Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix AlertDialog dismiss on click to Dialog content. #359

Merged
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Copyright 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package androidx.compose.foundation.dialog

import androidx.compose.runtime.compositionLocalOf
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.graphics.Color

@ExperimentalComposeUiApi
data class DialogSettings(
val scrimColor:Color = Color.Black.copy(alpha = 0.32f)
)

@ExperimentalComposeUiApi
internal val LocalDialogSettings = compositionLocalOf<DialogSettings> {
DialogSettings()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*
* Copyright 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package androidx.compose.foundation.dialog

import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background
import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.onClick
import androidx.compose.runtime.Composable
import androidx.compose.runtime.InternalComposeApi
import androidx.compose.ui.Alignment
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.awt.awtEventOrNull
import androidx.compose.ui.input.key.KeyEventType
import androidx.compose.ui.input.key.type
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.IntRect
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.window.Popup
import androidx.compose.ui.window.PopupPositionProvider
import java.awt.event.KeyEvent

@InternalComposeApi
@OptIn(ExperimentalComposeUiApi::class, ExperimentalFoundationApi::class)
igordmn marked this conversation as resolved.
Show resolved Hide resolved
@Composable
fun PopupDialog(onDismissRequest: () -> Unit, content: @Composable () -> Unit) {
//TODO Change PopupDialog to LayerDialog (https://github.com/JetBrains/compose-jb/issues/933)
// Popups on the desktop are by default embedded in the component in which
// they are defined and aligned within its bounds. But Dialog needs
// to be aligned within the window, not the parent component, so we cannot use
// [alignment] property of [Popup] and have to use [Box] that fills all the
// available space. Also [Box] provides a dismiss request feature when clicked
// outside of the [AlertDialog] content.
Popup(
popupPositionProvider = object : PopupPositionProvider {
override fun calculatePosition(
anchorBounds: IntRect,
windowSize: IntSize,
layoutDirection: LayoutDirection,
popupContentSize: IntSize
): IntOffset = IntOffset.Zero
},
focusable = true,
onDismissRequest = onDismissRequest,
onKeyEvent = {
if (it.type == KeyEventType.KeyDown && it.awtEventOrNull?.keyCode == KeyEvent.VK_ESCAPE) {
onDismissRequest()
true
} else {
false
}
},
) {
Box(
modifier = Modifier
.fillMaxSize()
.background(LocalDialogSettings.current.scrimColor)
.pointerInput(onDismissRequest) {
detectTapGestures(onPress = { onDismissRequest() })
},
contentAlignment = Alignment.Center
) {
Box(Modifier.onClick {
igordmn marked this conversation as resolved.
Show resolved Hide resolved
// Workaround to disable clicks on Dialog background https://github.com/JetBrains/compose-jb/issues/2581
}) {
content()
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,37 +16,25 @@

package androidx.compose.material

import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.ui.window.Dialog as CoreDialog
import androidx.compose.foundation.dialog.PopupDialog
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.IntrinsicSize
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.window.WindowDraggableArea
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.runtime.InternalComposeApi
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.awt.awtEventOrNull
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.input.key.Key
import androidx.compose.ui.input.key.key
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.IntRect
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Popup
import androidx.compose.ui.window.PopupPositionProvider
import androidx.compose.ui.window.rememberDialogState
import java.awt.event.KeyEvent
import androidx.compose.ui.window.Dialog as CoreDialog
import androidx.compose.ui.input.key.KeyEventType
import androidx.compose.ui.input.key.type

/**
* Alert dialog is a Dialog which interrupts the user with urgent information, details or actions.
Expand Down Expand Up @@ -187,48 +175,15 @@ interface AlertDialogProvider {
*/
@ExperimentalMaterialApi
object PopupAlertDialogProvider : AlertDialogProvider {
@OptIn(InternalComposeApi::class)
@Composable
override fun AlertDialog(
onDismissRequest: () -> Unit,
content: @Composable () -> Unit
) {
// Popups on the desktop are by default embedded in the component in which
// they are defined and aligned within its bounds. But an [AlertDialog] needs
// to be aligned within the window, not the parent component, so we cannot use
// [alignment] property of [Popup] and have to use [Box] that fills all the
// available space. Also [Box] provides a dismiss request feature when clicked
// outside of the [AlertDialog] content.
Popup(
popupPositionProvider = object : PopupPositionProvider {
override fun calculatePosition(
anchorBounds: IntRect,
windowSize: IntSize,
layoutDirection: LayoutDirection,
popupContentSize: IntSize
): IntOffset = IntOffset.Zero
},
focusable = true,
onDismissRequest = onDismissRequest,
onKeyEvent = {
if (it.type == KeyEventType.KeyDown && it.awtEventOrNull?.keyCode == KeyEvent.VK_ESCAPE) {
onDismissRequest()
true
} else {
false
}
},
) {
Box(
modifier = Modifier
.fillMaxSize()
.pointerInput(onDismissRequest) {
detectTapGestures(onPress = { onDismissRequest() })
},
contentAlignment = Alignment.Center
) {
Surface(elevation = 24.dp) {
content()
}
PopupDialog(onDismissRequest = onDismissRequest) {
Surface(elevation = 24.dp) {
content()
}
}
}
Expand Down