Loading packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsDimension.kt +4 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import androidx.compose.ui.unit.dp object SettingsDimension { val paddingTiny = 2.dp val paddingExtraSmall = 4.dp val paddingExtraSmall1 = 6.dp val paddingSmall = if (isSpaExpressiveEnabled) 8.dp else 4.dp val paddingExtraSmall5 = 10.dp val paddingExtraSmall6 = 12.dp Loading Loading @@ -87,4 +88,7 @@ object SettingsDimension { val illustrationCornerRadius = 28.dp val preferenceMinHeight = 72.dp val spinnerOptionMinHeight = 48.dp val spinnerIconSize = 20.dp } packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsShape.kt +3 −1 Original line number Diff line number Diff line Loading @@ -24,7 +24,9 @@ object SettingsShape { val CornerMedium = RoundedCornerShape(12.dp) val categoryCorner = RoundedCornerShape(20.dp) val CornerMedium2 = RoundedCornerShape(20.dp) val CornerLarge = RoundedCornerShape(24.dp) val CornerExtraLarge = RoundedCornerShape(28.dp) } packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Category.kt +1 −1 Original line number Diff line number Diff line Loading @@ -85,7 +85,7 @@ fun Category(title: String? = null, content: @Composable ColumnScope.() -> Unit) } .then( if (isSpaExpressiveEnabled) Modifier.fillMaxWidth().clip(SettingsShape.categoryCorner) Modifier.fillMaxWidth().clip(SettingsShape.CornerMedium2) else Modifier ), verticalArrangement = Loading packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Spinner.kt +139 −60 Original line number Diff line number Diff line Loading @@ -19,9 +19,14 @@ package com.android.settingslib.spa.widget.ui import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.heightIn import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.selection.selectableGroup import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.Check import androidx.compose.material.icons.outlined.ExpandLess import androidx.compose.material.icons.outlined.ExpandMore import androidx.compose.material3.Button Loading @@ -38,20 +43,19 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.semantics.Role import androidx.compose.ui.semantics.role import androidx.compose.ui.semantics.semantics import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.android.settingslib.spa.framework.theme.SettingsDimension import com.android.settingslib.spa.framework.theme.SettingsShape import com.android.settingslib.spa.framework.theme.SettingsTheme import com.android.settingslib.spa.framework.theme.isSpaExpressiveEnabled data class SpinnerOption( val id: Int, val text: String, ) data class SpinnerOption(val id: Int, val text: String) @Composable fun Spinner(options: List<SpinnerOption>, selectedId: Int?, setId: (id: Int) -> Unit) { Loading @@ -62,23 +66,72 @@ fun Spinner(options: List<SpinnerOption>, selectedId: Int?, setId: (id: Int) -> var expanded by rememberSaveable { mutableStateOf(false) } Box( modifier = Modifier .padding( modifier = Modifier.padding( start = SettingsDimension.itemPaddingStart, top = SettingsDimension.itemPaddingAround, end = SettingsDimension.itemPaddingEnd, bottom = SettingsDimension.itemPaddingAround, ) .selectableGroup(), .selectableGroup() ) { val contentPadding = if (isSpaExpressiveEnabled) PaddingValues( if (isSpaExpressiveEnabled) { Button( modifier = Modifier.semantics { role = Role.DropdownList }, onClick = { expanded = true }, colors = ButtonDefaults.buttonColors( containerColor = MaterialTheme.colorScheme.secondaryContainer, contentColor = MaterialTheme.colorScheme.onSecondaryContainer, ), contentPadding = PaddingValues( horizontal = SettingsDimension.spinnerHorizontalPadding, vertical = SettingsDimension.spinnerVerticalPadding ) else PaddingValues(horizontal = SettingsDimension.itemPaddingEnd) vertical = SettingsDimension.spinnerVerticalPadding, ), ) { SpinnerText(options.find { it.id == selectedId }) ExpandIcon(expanded) } DropdownMenu( expanded = expanded, onDismissRequest = { expanded = false }, shape = SettingsShape.CornerLarge, modifier = Modifier.background(MaterialTheme.colorScheme.surfaceContainerLow) .padding(horizontal = SettingsDimension.paddingSmall), ) { for ((index, option) in options.withIndex()) { val selected = index + 1 == selectedId DropdownMenuItem( text = { SpinnerOptionText(option = option, selected) }, onClick = { expanded = false setId(option.id) }, contentPadding = PaddingValues( horizontal = SettingsDimension.paddingSmall, vertical = SettingsDimension.paddingExtraSmall1, ), modifier = Modifier.heightIn(min = SettingsDimension.spinnerOptionMinHeight) .then( if (selected) Modifier.clip(SettingsShape.CornerMedium2) .background(MaterialTheme.colorScheme.primaryContainer) else Modifier ), ) } } } else { val contentPadding = PaddingValues(horizontal = SettingsDimension.itemPaddingEnd) Button( modifier = Modifier.semantics { role = Role.DropdownList }, onClick = { expanded = true }, colors = ButtonDefaults.buttonColors( colors = ButtonDefaults.buttonColors( containerColor = MaterialTheme.colorScheme.primaryContainer, contentColor = MaterialTheme.colorScheme.onPrimaryContainer, ), Loading Loading @@ -111,11 +164,13 @@ fun Spinner(options: List<SpinnerOption>, selectedId: Int?, setId: (id: Int) -> } } } } @Composable internal fun ExpandIcon(expanded: Boolean) { Icon( imageVector = when { imageVector = when { expanded -> Icons.Outlined.ExpandLess else -> Icons.Outlined.ExpandMore }, Loading @@ -131,7 +186,8 @@ private fun SpinnerText( ) { Text( text = option?.text ?: "", modifier = modifier modifier = modifier .padding(end = SettingsDimension.itemPaddingEnd) .then( if (!isSpaExpressiveEnabled) Loading @@ -143,6 +199,29 @@ private fun SpinnerText( ) } @Composable private fun SpinnerOptionText(option: SpinnerOption?, selected: Boolean) { Row { if (selected) { Icon( imageVector = Icons.Outlined.Check, modifier = Modifier.size(SettingsDimension.spinnerIconSize), tint = MaterialTheme.colorScheme.onPrimaryContainer, contentDescription = null, ) Spacer(Modifier.padding(SettingsDimension.paddingSmall)) } Text( text = option?.text ?: "", modifier = Modifier.padding(end = SettingsDimension.itemPaddingEnd), color = if (selected) MaterialTheme.colorScheme.onPrimaryContainer else MaterialTheme.colorScheme.onSurface, style = MaterialTheme.typography.labelLarge, ) } } @Preview(showBackground = true) @Composable private fun SpinnerPreview() { Loading Loading
packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsDimension.kt +4 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import androidx.compose.ui.unit.dp object SettingsDimension { val paddingTiny = 2.dp val paddingExtraSmall = 4.dp val paddingExtraSmall1 = 6.dp val paddingSmall = if (isSpaExpressiveEnabled) 8.dp else 4.dp val paddingExtraSmall5 = 10.dp val paddingExtraSmall6 = 12.dp Loading Loading @@ -87,4 +88,7 @@ object SettingsDimension { val illustrationCornerRadius = 28.dp val preferenceMinHeight = 72.dp val spinnerOptionMinHeight = 48.dp val spinnerIconSize = 20.dp }
packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsShape.kt +3 −1 Original line number Diff line number Diff line Loading @@ -24,7 +24,9 @@ object SettingsShape { val CornerMedium = RoundedCornerShape(12.dp) val categoryCorner = RoundedCornerShape(20.dp) val CornerMedium2 = RoundedCornerShape(20.dp) val CornerLarge = RoundedCornerShape(24.dp) val CornerExtraLarge = RoundedCornerShape(28.dp) }
packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Category.kt +1 −1 Original line number Diff line number Diff line Loading @@ -85,7 +85,7 @@ fun Category(title: String? = null, content: @Composable ColumnScope.() -> Unit) } .then( if (isSpaExpressiveEnabled) Modifier.fillMaxWidth().clip(SettingsShape.categoryCorner) Modifier.fillMaxWidth().clip(SettingsShape.CornerMedium2) else Modifier ), verticalArrangement = Loading
packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Spinner.kt +139 −60 Original line number Diff line number Diff line Loading @@ -19,9 +19,14 @@ package com.android.settingslib.spa.widget.ui import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.heightIn import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.selection.selectableGroup import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.Check import androidx.compose.material.icons.outlined.ExpandLess import androidx.compose.material.icons.outlined.ExpandMore import androidx.compose.material3.Button Loading @@ -38,20 +43,19 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.semantics.Role import androidx.compose.ui.semantics.role import androidx.compose.ui.semantics.semantics import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.android.settingslib.spa.framework.theme.SettingsDimension import com.android.settingslib.spa.framework.theme.SettingsShape import com.android.settingslib.spa.framework.theme.SettingsTheme import com.android.settingslib.spa.framework.theme.isSpaExpressiveEnabled data class SpinnerOption( val id: Int, val text: String, ) data class SpinnerOption(val id: Int, val text: String) @Composable fun Spinner(options: List<SpinnerOption>, selectedId: Int?, setId: (id: Int) -> Unit) { Loading @@ -62,23 +66,72 @@ fun Spinner(options: List<SpinnerOption>, selectedId: Int?, setId: (id: Int) -> var expanded by rememberSaveable { mutableStateOf(false) } Box( modifier = Modifier .padding( modifier = Modifier.padding( start = SettingsDimension.itemPaddingStart, top = SettingsDimension.itemPaddingAround, end = SettingsDimension.itemPaddingEnd, bottom = SettingsDimension.itemPaddingAround, ) .selectableGroup(), .selectableGroup() ) { val contentPadding = if (isSpaExpressiveEnabled) PaddingValues( if (isSpaExpressiveEnabled) { Button( modifier = Modifier.semantics { role = Role.DropdownList }, onClick = { expanded = true }, colors = ButtonDefaults.buttonColors( containerColor = MaterialTheme.colorScheme.secondaryContainer, contentColor = MaterialTheme.colorScheme.onSecondaryContainer, ), contentPadding = PaddingValues( horizontal = SettingsDimension.spinnerHorizontalPadding, vertical = SettingsDimension.spinnerVerticalPadding ) else PaddingValues(horizontal = SettingsDimension.itemPaddingEnd) vertical = SettingsDimension.spinnerVerticalPadding, ), ) { SpinnerText(options.find { it.id == selectedId }) ExpandIcon(expanded) } DropdownMenu( expanded = expanded, onDismissRequest = { expanded = false }, shape = SettingsShape.CornerLarge, modifier = Modifier.background(MaterialTheme.colorScheme.surfaceContainerLow) .padding(horizontal = SettingsDimension.paddingSmall), ) { for ((index, option) in options.withIndex()) { val selected = index + 1 == selectedId DropdownMenuItem( text = { SpinnerOptionText(option = option, selected) }, onClick = { expanded = false setId(option.id) }, contentPadding = PaddingValues( horizontal = SettingsDimension.paddingSmall, vertical = SettingsDimension.paddingExtraSmall1, ), modifier = Modifier.heightIn(min = SettingsDimension.spinnerOptionMinHeight) .then( if (selected) Modifier.clip(SettingsShape.CornerMedium2) .background(MaterialTheme.colorScheme.primaryContainer) else Modifier ), ) } } } else { val contentPadding = PaddingValues(horizontal = SettingsDimension.itemPaddingEnd) Button( modifier = Modifier.semantics { role = Role.DropdownList }, onClick = { expanded = true }, colors = ButtonDefaults.buttonColors( colors = ButtonDefaults.buttonColors( containerColor = MaterialTheme.colorScheme.primaryContainer, contentColor = MaterialTheme.colorScheme.onPrimaryContainer, ), Loading Loading @@ -111,11 +164,13 @@ fun Spinner(options: List<SpinnerOption>, selectedId: Int?, setId: (id: Int) -> } } } } @Composable internal fun ExpandIcon(expanded: Boolean) { Icon( imageVector = when { imageVector = when { expanded -> Icons.Outlined.ExpandLess else -> Icons.Outlined.ExpandMore }, Loading @@ -131,7 +186,8 @@ private fun SpinnerText( ) { Text( text = option?.text ?: "", modifier = modifier modifier = modifier .padding(end = SettingsDimension.itemPaddingEnd) .then( if (!isSpaExpressiveEnabled) Loading @@ -143,6 +199,29 @@ private fun SpinnerText( ) } @Composable private fun SpinnerOptionText(option: SpinnerOption?, selected: Boolean) { Row { if (selected) { Icon( imageVector = Icons.Outlined.Check, modifier = Modifier.size(SettingsDimension.spinnerIconSize), tint = MaterialTheme.colorScheme.onPrimaryContainer, contentDescription = null, ) Spacer(Modifier.padding(SettingsDimension.paddingSmall)) } Text( text = option?.text ?: "", modifier = Modifier.padding(end = SettingsDimension.itemPaddingEnd), color = if (selected) MaterialTheme.colorScheme.onPrimaryContainer else MaterialTheme.colorScheme.onSurface, style = MaterialTheme.typography.labelLarge, ) } } @Preview(showBackground = true) @Composable private fun SpinnerPreview() { Loading