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

Alert dialog to match the maximum of the width of its content #433

Merged
merged 3 commits into from
Mar 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,17 @@ import androidx.compose.ui.window.rememberDialogState
import java.awt.event.KeyEvent
import androidx.compose.ui.window.Dialog as CoreDialog
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.input.key.KeyEventType
import androidx.compose.ui.input.key.type

/**
* The default padding for an [AlertDialog].
*/
private val AlertDialogPadding = PaddingValues(24.dp)

/**
* Alert dialog is a Dialog which interrupts the user with urgent information, details or actions.
*
Expand Down Expand Up @@ -92,6 +98,65 @@ fun AlertDialog(
backgroundColor: Color = MaterialTheme.colors.surface,
contentColor: Color = contentColorFor(backgroundColor),
dialogProvider: AlertDialogProvider = PopupAlertDialogProvider
) {
AlertDialog(
onDismissRequest = onDismissRequest,
confirmButton = confirmButton,
modifier = modifier,
dismissButton = dismissButton,
title = title,
text = text,
shape = shape,
backgroundColor = backgroundColor,
contentColor = contentColor,
dialogPadding = AlertDialogPadding,
dialogProvider = dialogProvider
)
}

/**
* Alert dialog is a Dialog which interrupts the user with urgent information, details or actions.
*
* The dialog will position its buttons based on the available space. By default it will try to
* place them horizontally next to each other and fallback to horizontal placement if not enough
* space is available. There is also another version of this composable that has a slot for buttons
* to provide custom buttons layout.
*
* Sample of dialog:
* @sample androidx.compose.material.samples.AlertDialogSample
*
* @param onDismissRequest Callback that will be called when the user closes the dialog.
* @param confirmButton A button which is meant to confirm a proposed action, thus resolving
* what triggered the dialog. The dialog does not set up any events for this button so they need
* to be set up by the caller.
* @param modifier Modifier to be applied to the layout of the dialog.
* @param dismissButton A button which is meant to dismiss the dialog. The dialog does not set up
* any events for this button so they need to be set up by the caller.
* @param title The title of the Dialog which should specify the purpose of the Dialog. The title
* is not mandatory, because there may be sufficient information inside the [text]. Provided text
* style will be [Typography.subtitle1].
* @param text The text which presents the details regarding the Dialog's purpose. Provided text
* style will be [Typography.body2].
* @param shape Defines the Dialog's shape
* @param backgroundColor The background color of the dialog.
* @param contentColor The preferred content color provided by this dialog to its children.
* @param dialogPadding The outer padding of the dialog.
* @param dialogProvider Defines how to create dialog in which will be placed AlertDialog's content.
*/
@Composable
@ExperimentalMaterialApi
fun AlertDialog(
onDismissRequest: () -> Unit,
confirmButton: @Composable () -> Unit,
modifier: Modifier = Modifier,
dismissButton: @Composable (() -> Unit)? = null,
title: @Composable (() -> Unit)? = null,
text: @Composable (() -> Unit)? = null,
shape: Shape = MaterialTheme.shapes.medium,
backgroundColor: Color = MaterialTheme.colors.surface,
contentColor: Color = contentColorFor(backgroundColor),
dialogPadding: PaddingValues = AlertDialogPadding,
dialogProvider: AlertDialogProvider = PopupAlertDialogProvider,
) {
AlertDialog(
onDismissRequest = onDismissRequest,
Expand All @@ -113,6 +178,54 @@ fun AlertDialog(
shape = shape,
backgroundColor = backgroundColor,
contentColor = contentColor,
dialogPadding = dialogPadding,
dialogProvider = dialogProvider
)
}

/**
* Alert dialog is a Dialog which interrupts the user with urgent information, details or actions.
*
* This function can be used to fully customize the button area, e.g. with:
*
* @sample androidx.compose.material.samples.CustomAlertDialogSample
*
* @param onDismissRequest Callback that will be called when the user closes the dialog.
* @param buttons Function that emits the layout with the buttons.
* @param modifier Modifier to be applied to the layout of the dialog.
* @param title The title of the Dialog which should specify the purpose of the Dialog. The title
* is not mandatory, because there may be sufficient information inside the [text]. Provided text
* style will be [Typography.subtitle1].
* @param text The text which presents the details regarding the Dialog's purpose. Provided text
* style will be [Typography.body2].
* @param shape Defines the Dialog's shape.
* @param backgroundColor The background color of the dialog.
* @param contentColor The preferred content color provided by this dialog to its children.
* @param dialogProvider Defines how to create dialog in which will be placed AlertDialog's content.
*/
@Composable
@ExperimentalMaterialApi
fun AlertDialog(
onDismissRequest: () -> Unit,
buttons: @Composable () -> Unit,
modifier: Modifier = Modifier,
title: (@Composable () -> Unit)? = null,
text: @Composable (() -> Unit)? = null,
shape: Shape = MaterialTheme.shapes.medium,
backgroundColor: Color = MaterialTheme.colors.surface,
contentColor: Color = contentColorFor(backgroundColor),
dialogProvider: AlertDialogProvider = PopupAlertDialogProvider
) {
AlertDialog(
onDismissRequest = onDismissRequest,
buttons = buttons,
modifier = modifier,
title = title,
text = text,
shape = shape,
backgroundColor = backgroundColor,
contentColor = contentColor,
dialogPadding = AlertDialogPadding,
dialogProvider = dialogProvider
)
}
Expand All @@ -135,6 +248,7 @@ fun AlertDialog(
* @param shape Defines the Dialog's shape.
* @param backgroundColor The background color of the dialog.
* @param contentColor The preferred content color provided by this dialog to its children.
* @param dialogPadding The outer padding of the dialog.
* @param dialogProvider Defines how to create dialog in which will be placed AlertDialog's content.
*/
@Composable
Expand All @@ -148,17 +262,18 @@ fun AlertDialog(
shape: Shape = MaterialTheme.shapes.medium,
backgroundColor: Color = MaterialTheme.colors.surface,
contentColor: Color = contentColorFor(backgroundColor),
dialogPadding: PaddingValues = AlertDialogPadding,
dialogProvider: AlertDialogProvider = PopupAlertDialogProvider
) {
with(dialogProvider) {
AlertDialog(
onDismissRequest = onDismissRequest,
shape = shape,
modifier = modifier,
modifier = modifier.padding(dialogPadding),
) { modifier ->
AlertDialogContent(
buttons = buttons,
modifier = modifier.width(IntrinsicSize.Min),
modifier = modifier.width(IntrinsicSize.Max),
igordmn marked this conversation as resolved.
Show resolved Hide resolved
title = title,
text = text,
shape = shape,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

package androidx.compose.material

import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.size
import androidx.compose.material.internal.keyEvent
import androidx.compose.runtime.CompositionLocalProvider
Expand All @@ -27,14 +27,25 @@ import androidx.compose.ui.graphics.toComposeImageBitmap
import androidx.compose.ui.graphics.toPixelMap
import androidx.compose.ui.input.key.Key
import androidx.compose.ui.input.key.KeyEventType
import androidx.compose.ui.layout.IntrinsicMeasurable
import androidx.compose.ui.layout.IntrinsicMeasureScope
import androidx.compose.ui.layout.Layout
import androidx.compose.ui.layout.Measurable
import androidx.compose.ui.layout.MeasurePolicy
import androidx.compose.ui.layout.MeasureResult
import androidx.compose.ui.layout.MeasureScope
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.layout.positionInRoot
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.renderComposeScene
import androidx.compose.ui.test.ExperimentalTestApi
import androidx.compose.ui.test.assertWidthIsEqualTo
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.performKeyPress
import androidx.compose.ui.test.runDesktopComposeUiTest
import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.dp
Expand Down Expand Up @@ -62,7 +73,7 @@ class DesktopAlertDialogTest {
@OptIn(ExperimentalMaterialApi::class)
AlertDialog(
onDismissRequest = {},
title = { Text("AlerDialog") },
title = { Text("AlertDialog") },
text = { Text("Apply?") },
confirmButton = { Button(onClick = {}) { Text("Apply") } },
modifier = Modifier.size(dialogSize.width.dp, dialogSize.height.dp)
Expand All @@ -86,7 +97,7 @@ class DesktopAlertDialogTest {
@OptIn(ExperimentalMaterialApi::class)
AlertDialog(
onDismissRequest = { dismissCount++ },
title = { Text("AlerDialog") },
title = { Text("AlertDialog") },
text = { Text("Apply?") },
confirmButton = { Button(onClick = {}) { Text("Apply") } },
modifier = Modifier.size(dialogSize.width.dp, dialogSize.height.dp)
Expand Down Expand Up @@ -119,14 +130,13 @@ class DesktopAlertDialogTest {
// background.
val screenshot = renderComposeScene(400, 400){
AlertDialog(
modifier = Modifier
.size(width = 400.dp, height = 100.dp)
.padding(horizontal = 150.dp),
modifier = Modifier.size(width = 400.dp, height = 100.dp),
onDismissRequest = {},
title = {},
text = {},
dismissButton = {},
confirmButton = {},
dialogPadding = PaddingValues(horizontal = 150.dp)
)
}

Expand All @@ -141,6 +151,43 @@ class DesktopAlertDialogTest {
assertNotEquals(nearRealEdgePixel, backgroundPixel)
}

@OptIn(ExperimentalTestApi::class, ExperimentalMaterialApi::class)
@Test
fun `alert dialog uses available width`() = runDesktopComposeUiTest(
width = 800,
height = 800
){
setContent {
AlertDialog(
onDismissRequest = {},
confirmButton = {},
text = {
Layout(
modifier = Modifier.testTag("text_content"),
measurePolicy = object: MeasurePolicy {
override fun MeasureScope.measure(
measurables: List<Measurable>,
constraints: Constraints
): MeasureResult {
val width = 200.coerceAtMost(constraints.maxWidth)
return layout(width, 200){}
}

override fun IntrinsicMeasureScope.minIntrinsicWidth(
measurables: List<IntrinsicMeasurable>,
height: Int
): Int {
return 100
}
}
)
}
)
}

onNodeWithTag("text_content").assertWidthIsEqualTo(200.dp)
}

private fun calculateCenterPosition(rootSize: IntSize, childSize: IntSize): Offset {
val x = (rootSize.width - childSize.width) / 2f
val y = (rootSize.height - childSize.height) / 2f
Expand Down