Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 399f0d8e authored by Yuchen's avatar Yuchen Committed by Yuchen Sun
Browse files

[expressive design] Update AlertDialog layout.

Test: visual
Bug: 360916599
Flag: EXEMPT bug fix
Change-Id: I950c4164cb8f62aa598163d57e8ddc4710f2472b
parent 507aef74
Loading
Loading
Loading
Loading
+78 −13
Original line number Diff line number Diff line
@@ -17,11 +17,16 @@
package com.android.settingslib.spa.widget.dialog

import android.content.res.Configuration
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
@@ -32,9 +37,11 @@ import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.DialogProperties
import com.android.settingslib.spa.framework.theme.isSpaExpressiveEnabled

data class AlertDialogButton(
    val text: String,
@@ -85,24 +92,38 @@ private fun AlertDialogPresenter.SettingsAlertDialog(
    AlertDialog(
        onDismissRequest = ::close,
        modifier = Modifier.width(getDialogWidth()),
        confirmButton = { confirmButton?.let { Button(it) } },
        dismissButton = dismissButton?.let { { Button(it) } },
        title = title?.let { { Text(it) } },
        text = text?.let {
            {
                Column(Modifier.verticalScroll(rememberScrollState())) {
                    text()
                }
            }
        confirmButton = {
            confirmButton?.let { if (isSpaExpressiveEnabled) ConfirmButton(it) else Button(it) }
        },
        dismissButton =
            dismissButton?.let {
                { if (isSpaExpressiveEnabled) DismissButton(it) else Button(it) }
            },
        title = title?.let { { CenterRow { Text(it) } } },
        text =
            text?.let {
                { CenterRow { Column(Modifier.verticalScroll(rememberScrollState())) { text() } } }
            },
        properties = DialogProperties(usePlatformDefaultWidth = false),
    )
}

@Composable
internal fun CenterRow(content: @Composable (() -> Unit)) {
    if (isSpaExpressiveEnabled) {
        Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.Center) {
            content()
        }
    } else {
        content()
    }
}

@Composable
fun getDialogWidth(): Dp {
    val configuration = LocalConfiguration.current
    return configuration.screenWidthDp.dp * when (configuration.orientation) {
    return configuration.screenWidthDp.dp *
        when (configuration.orientation) {
            Configuration.ORIENTATION_LANDSCAPE -> 0.65f
            else -> 0.85f
        }
@@ -120,3 +141,47 @@ private fun AlertDialogPresenter.Button(button: AlertDialogButton) {
        Text(button.text)
    }
}

@Composable
private fun AlertDialogPresenter.DismissButton(button: AlertDialogButton) {
    OutlinedButton(
        onClick = {
            close()
            button.onClick()
        },
        enabled = button.enabled,
    ) {
        Text(button.text)
    }
}

@Composable
private fun AlertDialogPresenter.ConfirmButton(button: AlertDialogButton) {
    Button(
        onClick = {
            close()
            button.onClick()
        },
        enabled = button.enabled,
    ) {
        Text(button.text)
    }
}

@Preview
@Composable
private fun AlertDialogPreview() {
    val alertDialogPresenter = remember {
        object : AlertDialogPresenter {
            override fun open() {}

            override fun close() {}
        }
    }
    alertDialogPresenter.SettingsAlertDialog(
        confirmButton = AlertDialogButton("Ok"),
        dismissButton = AlertDialogButton("Cancel"),
        title = "Title",
        text = { Text("Text") },
    )
}
+16 −40
Original line number Diff line number Diff line
@@ -40,10 +40,7 @@ fun SettingsAlertDialogWithIcon(
    dismissButton: AlertDialogButton?,
    title: String?,
    icon: @Composable (() -> Unit)? = {
        Icon(
            Icons.Default.WarningAmber,
            contentDescription = null
        )
        Icon(Icons.Default.WarningAmber, contentDescription = null)
    },
    text: @Composable (() -> Unit)?,
) {
@@ -52,42 +49,21 @@ fun SettingsAlertDialogWithIcon(
        icon = icon,
        modifier = Modifier.width(getDialogWidth()),
        confirmButton = {
            confirmButton?.let {
                Button(
                    onClick = {
                        it.onClick()
            confirmButton?.let { Button(onClick = { it.onClick() }) { Text(it.text) } }
        },
                ) {
                    Text(it.text)
                }
            }
        },
        dismissButton = dismissButton?.let {
        dismissButton =
            dismissButton?.let { { OutlinedButton(onClick = { it.onClick() }) { Text(it.text) } } },
        title =
            title?.let {
                {
                OutlinedButton(
                    onClick = {
                        it.onClick()
                    },
                ) {
                    Text(it.text)
                    CenterRow {
                        Text(it, modifier = Modifier.fillMaxWidth(), textAlign = TextAlign.Center)
                    }
                }
            },
        title = title?.let {
            {
                Text(
                    it,
                    modifier = Modifier.fillMaxWidth(),
                    textAlign = TextAlign.Center
                )
            }
        },
        text = text?.let {
            {
                Column(Modifier.verticalScroll(rememberScrollState())) {
                    text()
                }
            }
        text =
            text?.let {
                { CenterRow { Column(Modifier.verticalScroll(rememberScrollState())) { text() } } }
            },
        properties = DialogProperties(usePlatformDefaultWidth = false),
    )
+38 −69
Original line number Diff line number Diff line
@@ -58,10 +58,7 @@ fun SettingsAlertDialogContent(
    dismissButton: AlertDialogButton?,
    title: String?,
    icon: @Composable (() -> Unit)? = {
        Icon(
            Icons.Default.WarningAmber,
            contentDescription = null
        )
        Icon(Icons.Default.WarningAmber, contentDescription = null)
    },
    text: @Composable (() -> Unit)?,
) {
@@ -69,41 +66,21 @@ fun SettingsAlertDialogContent(
        buttons = {
            AlertDialogFlowRow(
                mainAxisSpacing = ButtonsMainAxisSpacing,
                crossAxisSpacing = ButtonsCrossAxisSpacing
                crossAxisSpacing = ButtonsCrossAxisSpacing,
            ) {
                dismissButton?.let {
                    OutlinedButton(onClick = it.onClick) {
                        Text(it.text)
                    }
                }
                confirmButton?.let {
                    Button(
                        onClick = {
                            it.onClick()
                        },
                    ) {
                        Text(it.text)
                    }
                }
                dismissButton?.let { OutlinedButton(onClick = it.onClick) { Text(it.text) } }
                confirmButton?.let { Button(onClick = { it.onClick() }) { Text(it.text) } }
            }
        },
        icon = icon,
        modifier = Modifier.width(getDialogWidth()),
        title = title?.let {
            {
                Text(
                    it,
                    modifier = Modifier.fillMaxWidth(),
                    textAlign = TextAlign.Center
                )
            }
        title =
            title?.let {
                { Text(it, modifier = Modifier.fillMaxWidth(), textAlign = TextAlign.Center) }
            },
        text = text?.let {
            {
                Column(Modifier.verticalScroll(rememberScrollState())) {
                    text()
                }
            }
        text =
            text?.let {
                { CenterRow { Column(Modifier.verticalScroll(rememberScrollState())) { text() } } }
            },
    )
}
@@ -121,18 +98,12 @@ internal fun SettingsAlertDialogContent(
        shape = SettingsShape.CornerExtraLarge,
        color = MaterialTheme.colorScheme.surfaceContainerHigh,
    ) {
        Column(
            modifier = Modifier.padding(DialogPadding)
        ) {
        Column(modifier = Modifier.padding(DialogPadding)) {
            icon?.let {
                CompositionLocalProvider(
                    LocalContentColor provides AlertDialogDefaults.iconContentColor,
                ) {
                    Box(
                        Modifier
                            .padding(IconPadding)
                            .align(Alignment.CenterHorizontally)
                    LocalContentColor provides AlertDialogDefaults.iconContentColor
                ) {
                    Box(Modifier.padding(IconPadding).align(Alignment.CenterHorizontally)) {
                        icon()
                    }
                }
@@ -144,8 +115,7 @@ internal fun SettingsAlertDialogContent(
                ) {
                    Box(
                        // Align the title to the center when an icon is present.
                        Modifier
                            .padding(TitlePadding)
                        Modifier.padding(TitlePadding)
                            .align(
                                if (icon == null) {
                                    Alignment.Start
@@ -161,11 +131,10 @@ internal fun SettingsAlertDialogContent(
            text?.let {
                ProvideContentColorTextStyle(
                    contentColor = AlertDialogDefaults.textContentColor,
                    textStyle = MaterialTheme.typography.bodyMedium
                    textStyle = MaterialTheme.typography.bodyMedium,
                ) {
                    Box(
                        Modifier
                            .weight(weight = 1f, fill = false)
                        Modifier.weight(weight = 1f, fill = false)
                            .padding(TextPadding)
                            .align(Alignment.Start)
                    ) {
@@ -177,7 +146,7 @@ internal fun SettingsAlertDialogContent(
                ProvideContentColorTextStyle(
                    contentColor = MaterialTheme.colorScheme.primary,
                    textStyle = MaterialTheme.typography.labelLarge,
                    content = buttons
                    content = buttons,
                )
            }
        }
@@ -188,7 +157,7 @@ internal fun SettingsAlertDialogContent(
internal fun AlertDialogFlowRow(
    mainAxisSpacing: Dp,
    crossAxisSpacing: Dp,
    content: @Composable () -> Unit
    content: @Composable () -> Unit,
) {
    Layout(content) { measurables, constraints ->
        val sequences = mutableListOf<List<Placeable>>()
@@ -204,8 +173,9 @@ internal fun AlertDialogFlowRow(

        // Return whether the placeable can be added to the current sequence.
        fun canAddToCurrentSequence(placeable: Placeable) =
            currentSequence.isEmpty() || currentMainAxisSize + mainAxisSpacing.roundToPx() +
                placeable.width <= constraints.maxWidth
            currentSequence.isEmpty() ||
                currentMainAxisSize + mainAxisSpacing.roundToPx() + placeable.width <=
                    constraints.maxWidth

        // Store current sequence information and start a new sequence.
        fun startNewSequence() {
@@ -213,8 +183,7 @@ internal fun AlertDialogFlowRow(
                crossAxisSpace += crossAxisSpacing.roundToPx()
            }
            // Ensures that confirming actions appear above dismissive actions.
            @Suppress("ListIterator")
            sequences.add(0, currentSequence.toList())
            @Suppress("ListIterator") sequences.add(0, currentSequence.toList())
            crossAxisSizes += currentCrossAxisSize
            crossAxisPositions += crossAxisSpace

@@ -254,7 +223,8 @@ internal fun AlertDialogFlowRow(

        layout(layoutWidth, layoutHeight) {
            sequences.fastForEachIndexed { i, placeables ->
                val childrenMainAxisSizes = IntArray(placeables.size) { j ->
                val childrenMainAxisSizes =
                    IntArray(placeables.size) { j ->
                        placeables[j].width +
                            if (j < placeables.lastIndex) mainAxisSpacing.roundToPx() else 0
                    }
@@ -262,15 +232,14 @@ internal fun AlertDialogFlowRow(
                val mainAxisPositions = IntArray(childrenMainAxisSizes.size) { 0 }
                with(arrangement) {
                    arrange(
                        mainAxisLayoutSize, childrenMainAxisSizes,
                        layoutDirection, mainAxisPositions
                        mainAxisLayoutSize,
                        childrenMainAxisSizes,
                        layoutDirection,
                        mainAxisPositions,
                    )
                }
                placeables.fastForEachIndexed { j, placeable ->
                    placeable.place(
                        x = mainAxisPositions[j],
                        y = crossAxisPositions[i]
                    )
                    placeable.place(x = mainAxisPositions[j], y = crossAxisPositions[i])
                }
            }
        }
@@ -289,8 +258,8 @@ private val ButtonsCrossAxisSpacing = 12.dp
/**
 * ProvideContentColorTextStyle
 *
 * A convenience method to provide values to both LocalContentColor and LocalTextStyle in
 * one call. This is less expensive than nesting calls to CompositionLocalProvider.
 * A convenience method to provide values to both LocalContentColor and LocalTextStyle in one call.
 * This is less expensive than nesting calls to CompositionLocalProvider.
 *
 * Text styles will be merged with the current value of LocalTextStyle.
 */
@@ -298,12 +267,12 @@ private val ButtonsCrossAxisSpacing = 12.dp
private fun ProvideContentColorTextStyle(
    contentColor: Color,
    textStyle: TextStyle,
    content: @Composable () -> Unit
    content: @Composable () -> Unit,
) {
    val mergedStyle = LocalTextStyle.current.merge(textStyle)
    CompositionLocalProvider(
        LocalContentColor provides contentColor,
        LocalTextStyle provides mergedStyle,
        content = content
        content = content,
    )
}