Loading packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/dialog/SettingsAlertDialog.kt +78 −13 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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, Loading Loading @@ -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 } Loading @@ -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") }, ) } packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/dialog/SettingsAlertDialogWithIcon.kt +16 −40 Original line number Diff line number Diff line Loading @@ -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)?, ) { Loading @@ -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), ) Loading packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/dialog/SettingsAlterDialogContent.kt +38 −69 Original line number Diff line number Diff line Loading @@ -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)?, ) { Loading @@ -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() } } } }, ) } Loading @@ -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() } } Loading @@ -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 Loading @@ -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) ) { Loading @@ -177,7 +146,7 @@ internal fun SettingsAlertDialogContent( ProvideContentColorTextStyle( contentColor = MaterialTheme.colorScheme.primary, textStyle = MaterialTheme.typography.labelLarge, content = buttons content = buttons, ) } } Loading @@ -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>>() Loading @@ -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() { Loading @@ -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 Loading Loading @@ -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 } Loading @@ -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]) } } } Loading @@ -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. */ Loading @@ -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, ) } Loading
packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/dialog/SettingsAlertDialog.kt +78 −13 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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, Loading Loading @@ -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 } Loading @@ -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") }, ) }
packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/dialog/SettingsAlertDialogWithIcon.kt +16 −40 Original line number Diff line number Diff line Loading @@ -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)?, ) { Loading @@ -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), ) Loading
packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/dialog/SettingsAlterDialogContent.kt +38 −69 Original line number Diff line number Diff line Loading @@ -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)?, ) { Loading @@ -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() } } } }, ) } Loading @@ -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() } } Loading @@ -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 Loading @@ -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) ) { Loading @@ -177,7 +146,7 @@ internal fun SettingsAlertDialogContent( ProvideContentColorTextStyle( contentColor = MaterialTheme.colorScheme.primary, textStyle = MaterialTheme.typography.labelLarge, content = buttons content = buttons, ) } } Loading @@ -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>>() Loading @@ -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() { Loading @@ -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 Loading Loading @@ -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 } Loading @@ -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]) } } } Loading @@ -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. */ Loading @@ -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, ) }