diff --git a/feature/settings/impl/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/settings/impl/SettingsDialog.kt b/feature/settings/impl/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/settings/impl/SettingsDialog.kt index b2758e286..3b6a328e5 100644 --- a/feature/settings/impl/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/settings/impl/SettingsDialog.kt +++ b/feature/settings/impl/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/settings/impl/SettingsDialog.kt @@ -34,19 +34,27 @@ import androidx.compose.foundation.layout.widthIn import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.selection.selectable import androidx.compose.foundation.selection.selectableGroup +import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.verticalScroll import androidx.compose.material3.AlertDialog +import androidx.compose.material3.Button import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.OutlinedButton import androidx.compose.material3.RadioButton +import androidx.compose.material3.SegmentedButton +import androidx.compose.material3.SegmentedButtonDefaults +import androidx.compose.material3.SingleChoiceSegmentedButtonRow import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalUriHandler +import androidx.compose.ui.platform.LocalWindowInfo import androidx.compose.ui.res.stringResource import androidx.compose.ui.semantics.Role import androidx.compose.ui.tooling.preview.Preview @@ -59,9 +67,6 @@ import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaTextB import com.google.samples.apps.nowinandroid.core.designsystem.theme.NiaTheme import com.google.samples.apps.nowinandroid.core.designsystem.theme.supportsDynamicTheming import com.google.samples.apps.nowinandroid.core.model.data.DarkThemeConfig -import com.google.samples.apps.nowinandroid.core.model.data.DarkThemeConfig.DARK -import com.google.samples.apps.nowinandroid.core.model.data.DarkThemeConfig.FOLLOW_SYSTEM -import com.google.samples.apps.nowinandroid.core.model.data.DarkThemeConfig.LIGHT import com.google.samples.apps.nowinandroid.core.model.data.ThemeBrand import com.google.samples.apps.nowinandroid.core.model.data.ThemeBrand.ANDROID import com.google.samples.apps.nowinandroid.core.model.data.ThemeBrand.DEFAULT @@ -70,6 +75,7 @@ import com.google.samples.apps.nowinandroid.feature.settings.impl.R.string import com.google.samples.apps.nowinandroid.feature.settings.impl.SettingsUiState.Loading import com.google.samples.apps.nowinandroid.feature.settings.impl.SettingsUiState.Success + @Composable fun SettingsDialog( onDismiss: () -> Unit, @@ -105,7 +111,7 @@ fun SettingsDialog( */ AlertDialog( properties = DialogProperties(usePlatformDefaultWidth = false), - modifier = Modifier.widthIn(max = configuration.screenWidthDp.dp - 80.dp), + modifier = Modifier.widthIn(max = LocalWindowInfo.current.containerSize.width.dp - 80.dp), onDismissRequest = { onDismiss() }, title = { Text( @@ -164,13 +170,14 @@ private fun ColumnScope.SettingsPanel( onChangeDarkThemeConfig: (darkThemeConfig: DarkThemeConfig) -> Unit, ) { SettingsDialogSectionTitle(text = stringResource(string.feature_settings_impl_theme)) - Column(Modifier.selectableGroup()) { - SettingsDialogThemeChooserRow( + Row(Modifier.selectableGroup()) { + SettingsDialogThemeRadioBtn( text = stringResource(string.feature_settings_impl_brand_default), selected = settings.brand == DEFAULT, onClick = { onChangeThemeBrand(DEFAULT) }, ) - SettingsDialogThemeChooserRow( + Spacer(Modifier.width(20.dp)) + SettingsDialogThemeRadioBtn( text = stringResource(string.feature_settings_impl_brand_android), selected = settings.brand == ANDROID, onClick = { onChangeThemeBrand(ANDROID) }, @@ -180,35 +187,38 @@ private fun ColumnScope.SettingsPanel( Column { SettingsDialogSectionTitle(text = stringResource(string.feature_settings_impl_dynamic_color_preference)) Column(Modifier.selectableGroup()) { - SettingsDialogThemeChooserRow( - text = stringResource(string.feature_settings_impl_dynamic_color_yes), - selected = settings.useDynamicColor, - onClick = { onChangeDynamicColorPreference(true) }, - ) - SettingsDialogThemeChooserRow( - text = stringResource(string.feature_settings_impl_dynamic_color_no), - selected = !settings.useDynamicColor, - onClick = { onChangeDynamicColorPreference(false) }, + + SettingsDialogThemeDynamicColorRow( + options = listOf( stringResource(string.feature_settings_impl_dynamic_color_yes), stringResource(string.feature_settings_impl_dynamic_color_no)), + selectedIndex = if (settings.useDynamicColor) 0 else 1, + onOptionSelected = { index -> + onChangeDynamicColorPreference(index == 0) + } ) } } } SettingsDialogSectionTitle(text = stringResource(string.feature_settings_impl_dark_mode_preference)) Column(Modifier.selectableGroup()) { - SettingsDialogThemeChooserRow( - text = stringResource(string.feature_settings_impl_dark_mode_config_system_default), - selected = settings.darkThemeConfig == FOLLOW_SYSTEM, - onClick = { onChangeDarkThemeConfig(FOLLOW_SYSTEM) }, - ) - SettingsDialogThemeChooserRow( - text = stringResource(string.feature_settings_impl_dark_mode_config_light), - selected = settings.darkThemeConfig == LIGHT, - onClick = { onChangeDarkThemeConfig(LIGHT) }, + val darkModeOptions = listOf( + stringResource(string.feature_settings_impl_dark_mode_config_system_default), + stringResource(string.feature_settings_impl_dark_mode_config_light), + stringResource(string.feature_settings_impl_dark_mode_config_dark) ) - SettingsDialogThemeChooserRow( - text = stringResource(string.feature_settings_impl_dark_mode_config_dark), - selected = settings.darkThemeConfig == DARK, - onClick = { onChangeDarkThemeConfig(DARK) }, + + SettingsDialogThemeDarkModeRow( + options = darkModeOptions, + selectedIndex = when(settings.darkThemeConfig) { + DarkThemeConfig.FOLLOW_SYSTEM -> 0 + DarkThemeConfig.LIGHT -> 1 + DarkThemeConfig.DARK -> 2 + }, + onOptionSelected = { index ->val newConfig = when (index) { + 0 -> DarkThemeConfig.FOLLOW_SYSTEM + 1 -> DarkThemeConfig.LIGHT + else -> DarkThemeConfig.DARK + } + onChangeDarkThemeConfig(newConfig)} ) } } @@ -223,20 +233,19 @@ private fun SettingsDialogSectionTitle(text: String) { } @Composable -fun SettingsDialogThemeChooserRow( +fun SettingsDialogThemeRadioBtn( text: String, selected: Boolean, onClick: () -> Unit, ) { Row( Modifier - .fillMaxWidth() .selectable( selected = selected, role = Role.RadioButton, onClick = onClick, ) - .padding(12.dp), + .padding(5.dp), verticalAlignment = Alignment.CenterVertically, ) { RadioButton( @@ -248,6 +257,73 @@ fun SettingsDialogThemeChooserRow( } } +@Composable +fun SettingsDialogThemeDynamicColorRow( options :List, + selectedIndex :Int, + onOptionSelected : (Int) -> Unit + ) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp), + horizontalArrangement = Arrangement.spacedBy(12.dp) + ) { + options.forEachIndexed { index, stringId -> + val isSelected = index == selectedIndex + + if (isSelected) { + Button( + onClick = { onOptionSelected(index) }, + modifier = Modifier.weight(1f), + shape = CircleShape + ) { + Spacer(Modifier.width(3.dp)) + Text(text = stringId) + } + } else { + OutlinedButton( + onClick = { onOptionSelected(index) }, + modifier = Modifier.weight(1f), + shape = CircleShape + ) { + Spacer(Modifier.width(3.dp)) + Text(text = stringId) } + } + } + } + } + +@Composable +fun SettingsDialogThemeDarkModeRow( + options: List, + selectedIndex: Int, + onOptionSelected: (Int) -> Unit +) { + SingleChoiceSegmentedButtonRow( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 1.dp) + ) { + options.forEachIndexed { index, stringId -> + val isSelected = index == selectedIndex + SegmentedButton( + shape = SegmentedButtonDefaults.itemShape(index = index, count = options.size), + onClick = { onOptionSelected(index) }, + selected = isSelected, + label = { + Text(text = stringId, maxLines = 1) + }, + colors = SegmentedButtonDefaults.colors( + activeContainerColor = MaterialTheme.colorScheme.primary , + activeContentColor = MaterialTheme.colorScheme.onPrimary, + inactiveContainerColor = Color.Transparent, + inactiveContentColor = MaterialTheme.colorScheme.onSurface + ), + icon = {} + ) } + } +} + @OptIn(ExperimentalLayoutApi::class) @Composable private fun LinksPanel() { @@ -294,7 +370,7 @@ private fun PreviewSettingsDialog() { settingsUiState = Success( UserEditableSettings( brand = DEFAULT, - darkThemeConfig = FOLLOW_SYSTEM, + darkThemeConfig = DarkThemeConfig.FOLLOW_SYSTEM, useDynamicColor = false, ), ), diff --git a/feature/settings/impl/src/main/res/values/strings.xml b/feature/settings/impl/src/main/res/values/strings.xml index 18e0dcf18..91228ebdc 100644 --- a/feature/settings/impl/src/main/res/values/strings.xml +++ b/feature/settings/impl/src/main/res/values/strings.xml @@ -27,7 +27,7 @@ Default Android Dark mode preference - System default + System Light Dark Use Dynamic Color diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index fbe070c1a..e8786d8b1 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -2,8 +2,8 @@ accompanist = "0.37.0" androidDesugarJdkLibs = "2.1.4" # AGP and tools should be updated together -androidGradlePlugin = "9.0.0" -androidTools = "32.0.0" +androidGradlePlugin = "9.0.1" +androidTools = "32.0.1" androidxActivity = "1.9.3" androidxAppCompat = "1.7.0" androidxBrowser = "1.8.0"