From acd574b627ace1427007867a7355fac100849073 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABtan=20Muller?= Date: Fri, 26 Jul 2024 12:16:16 +0200 Subject: [PATCH] Align `AppSettingsView` design with the rest of the demo app --- .../demo/ui/settings/AppSettingsView.kt | 298 +++++++++--------- 1 file changed, 153 insertions(+), 145 deletions(-) diff --git a/pillarbox-demo/src/main/java/ch/srgssr/pillarbox/demo/ui/settings/AppSettingsView.kt b/pillarbox-demo/src/main/java/ch/srgssr/pillarbox/demo/ui/settings/AppSettingsView.kt index 08ffddef1..62ccf7af1 100644 --- a/pillarbox-demo/src/main/java/ch/srgssr/pillarbox/demo/ui/settings/AppSettingsView.kt +++ b/pillarbox-demo/src/main/java/ch/srgssr/pillarbox/demo/ui/settings/AppSettingsView.kt @@ -4,14 +4,14 @@ */ package ch.srgssr.pillarbox.demo.ui.settings +import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.core.animateFloatAsState import androidx.compose.foundation.clickable -import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.rememberScrollState @@ -26,6 +26,7 @@ import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Switch import androidx.compose.material3.Text +import androidx.compose.material3.minimumInteractiveComponentSize import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -37,8 +38,6 @@ import androidx.compose.ui.draw.rotate import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.DpOffset -import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.media3.common.MediaLibraryInfo import ch.srgssr.pillarbox.demo.BuildConfig @@ -46,6 +45,8 @@ import ch.srgssr.pillarbox.demo.R import ch.srgssr.pillarbox.demo.shared.ui.settings.AppSettings import ch.srgssr.pillarbox.demo.shared.ui.settings.AppSettingsRepository import ch.srgssr.pillarbox.demo.shared.ui.settings.AppSettingsViewModel +import ch.srgssr.pillarbox.demo.ui.components.DemoListHeaderView +import ch.srgssr.pillarbox.demo.ui.components.DemoListSectionView import ch.srgssr.pillarbox.demo.ui.theme.PillarboxTheme import ch.srgssr.pillarbox.demo.ui.theme.paddings @@ -53,167 +54,200 @@ import ch.srgssr.pillarbox.demo.ui.theme.paddings * App settings view * * @param settingsViewModel The [AppSettingsViewModel] + * @param modifier The [Modifier] to apply to the layout. */ @Composable -fun AppSettingsView(settingsViewModel: AppSettingsViewModel) { +fun AppSettingsView( + settingsViewModel: AppSettingsViewModel, + modifier: Modifier = Modifier, +) { val appSettings by settingsViewModel.currentAppSettings.collectAsStateWithLifecycle(AppSettings()) - val scrollState = rememberScrollState() + Column( - modifier = Modifier - .padding(MaterialTheme.paddings.small) - .verticalScroll(state = scrollState, enabled = true), - verticalArrangement = Arrangement.spacedBy(MaterialTheme.paddings.baseline) + modifier = modifier + .padding(horizontal = MaterialTheme.paddings.baseline) + .padding(bottom = MaterialTheme.paddings.baseline) + .verticalScroll(rememberScrollState()), ) { - MetricsOverlay( - modifier = Modifier.fillMaxWidth(), + MetricsOverlaySettings( appSettings = appSettings, setMetricsOverlayTextSize = settingsViewModel::setMetricsOverlayTextSize, setMetricsOverlayEnabled = settingsViewModel::setMetricsOverlayEnabled, - setMetricsOverlayTextColor = settingsViewModel::setMetricsOverlayTextColor + setMetricsOverlayTextColor = settingsViewModel::setMetricsOverlayTextColor, ) - SettingsDivider() - Text( - text = stringResource(R.string.settings_library_version), - style = MaterialTheme.typography.headlineMedium - ) - Column(verticalArrangement = Arrangement.spacedBy(MaterialTheme.paddings.small)) { - Text( - text = "Pillarbox: ${BuildConfig.VERSION_NAME}", - style = MaterialTheme.typography.bodySmall - ) - Text( - text = "Media3: ${MediaLibraryInfo.VERSION}", - style = MaterialTheme.typography.bodySmall - ) - } + + LibraryVersionSection() } } @Composable -private fun MetricsOverlay( +private fun MetricsOverlaySettings( appSettings: AppSettings, setMetricsOverlayEnabled: (Boolean) -> Unit, setMetricsOverlayTextColor: (AppSettings.TextColor) -> Unit, setMetricsOverlayTextSize: (AppSettings.TextSize) -> Unit, - modifier: Modifier = Modifier ) { - Column( - verticalArrangement = Arrangement.spacedBy(MaterialTheme.paddings.small) - ) { - Text(text = stringResource(R.string.setting_metrics_overlay), style = MaterialTheme.typography.headlineMedium) - Text( - style = MaterialTheme.typography.bodySmall, - text = stringResource(R.string.settings_enabled_overlay_description) + SettingSection(title = stringResource(R.string.setting_metrics_overlay)) { + TextLabel(text = stringResource(R.string.settings_enabled_overlay_description)) + + LabeledSwitch( + text = stringResource(R.string.settings_enabled_metrics_overlay), + checked = appSettings.metricsOverlayEnabled, + modifier = Modifier + .fillMaxWidth() + .padding(top = MaterialTheme.paddings.small), + onCheckedChange = setMetricsOverlayEnabled, ) - Row( - modifier = Modifier.fillMaxWidth(), - verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.SpaceBetween - ) { - Text( - text = stringResource(R.string.settings_enabled_metrics_overlay), - style = MaterialTheme.typography.bodyLarge - ) - Switch( - checked = appSettings.metricsOverlayEnabled, - onCheckedChange = setMetricsOverlayEnabled - ) - } - Row(modifier = modifier, horizontalArrangement = Arrangement.SpaceBetween) { - val selected = appSettings.metricsOverlayTextColor - val entries = AppSettings.TextColor.entries - val labels = remember(entries) { - entries.map { it.name } - } - Text(stringResource(R.string.settings_choose_text_color)) - DropDownSettings( - modifier = Modifier, - labels = labels, - selectedEntry = selected, - entries = entries, - onEntryClicked = setMetricsOverlayTextColor - ) - } + AnimatedVisibility(visible = appSettings.metricsOverlayEnabled) { + Column { + DropdownSetting( + text = stringResource(R.string.settings_choose_text_color), + entries = AppSettings.TextColor.entries, + selectedEntry = appSettings.metricsOverlayTextColor, + modifier = Modifier.fillMaxWidth(), + onEntrySelected = setMetricsOverlayTextColor, + ) - Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) { - val selected = appSettings.metricsOverlayTextSize - val entries = AppSettings.TextSize.entries - val labels = remember(entries) { - entries.map { it.name } + DropdownSetting( + text = stringResource(R.string.settings_choose_text_size), + entries = AppSettings.TextSize.entries, + selectedEntry = appSettings.metricsOverlayTextSize, + modifier = Modifier.fillMaxWidth(), + onEntrySelected = setMetricsOverlayTextSize, + ) } - Text(stringResource(R.string.settings_choose_text_size)) - DropDownSettings( - modifier = Modifier, - labels = labels, - selectedEntry = selected, - entries = entries, - onEntryClicked = setMetricsOverlayTextSize - ) } } } @Composable -private fun DropDownSettings( - selectedEntry: T, +private fun LibraryVersionSection() { + SettingSection(title = stringResource(R.string.settings_library_version)) { + TextLabel( + text = "Pillarbox: ${BuildConfig.VERSION_NAME}", + modifier = Modifier.padding(vertical = MaterialTheme.paddings.small), + ) + + HorizontalDivider() + + TextLabel( + text = "Media3: ${MediaLibraryInfo.VERSION}", + modifier = Modifier.padding(vertical = MaterialTheme.paddings.small), + ) + } +} + +@Composable +private fun SettingSection( + title: String, + content: @Composable ColumnScope.() -> Unit, +) { + DemoListHeaderView( + title = title, + modifier = Modifier.padding(start = MaterialTheme.paddings.baseline) + ) + + DemoListSectionView(content = content) +} + +@Composable +private fun TextLabel( + text: String, + modifier: Modifier = Modifier, +) { + Text( + text = text, + modifier = modifier.padding( + horizontal = MaterialTheme.paddings.baseline, + vertical = MaterialTheme.paddings.small + ), + style = MaterialTheme.typography.bodyMedium, + ) +} + +@Composable +private fun LabeledSwitch( + text: String, + checked: Boolean, + modifier: Modifier = Modifier, + onCheckedChange: (Boolean) -> Unit, +) { + Row( + modifier = modifier + .clickable { onCheckedChange(!checked) } + .minimumInteractiveComponentSize() + .padding(end = MaterialTheme.paddings.baseline), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically, + ) { + TextLabel(text = text) + + Switch( + checked = checked, + onCheckedChange = null, + ) + } +} + +@Composable +private fun DropdownSetting( + text: String, entries: List, - labels: List, - onEntryClicked: (T) -> Unit, + selectedEntry: T, modifier: Modifier = Modifier, + onEntrySelected: (entry: T) -> Unit, ) { - var showDropDownMenu by remember { mutableStateOf(false) } + var showDropdownMenu by remember { mutableStateOf(false) } + Box(modifier = modifier) { Row( modifier = Modifier - .clickable( - interactionSource = remember { MutableInteractionSource() }, - indication = null - ) { - showDropDownMenu = true - } - .padding( - start = MaterialTheme.paddings.baseline, - end = MaterialTheme.paddings.small - ), - verticalAlignment = Alignment.CenterVertically + .fillMaxWidth() + .clickable { showDropdownMenu = true } + .minimumInteractiveComponentSize() + .padding(end = MaterialTheme.paddings.baseline), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically, ) { - val iconRotation by animateFloatAsState( - targetValue = if (showDropDownMenu) -180f else 0f, - label = "icon_rotation_animation" - ) - Text(text = labels[entries.indexOf(selectedEntry)]) + TextLabel(text = text) - Icon( - imageVector = Icons.Default.ExpandMore, - contentDescription = null, - modifier = Modifier.rotate(iconRotation) - ) + Row( + verticalAlignment = Alignment.CenterVertically + ) { + val iconRotation by animateFloatAsState( + targetValue = if (showDropdownMenu) -180f else 0f, + label = "icon_rotation_animation" + ) + + Text(text = selectedEntry.toString()) + + Icon( + imageVector = Icons.Default.ExpandMore, + contentDescription = null, + modifier = Modifier.rotate(iconRotation), + ) + } } DropdownMenu( - expanded = showDropDownMenu, - onDismissRequest = { showDropDownMenu = false }, - offset = DpOffset( - x = 0.dp, - y = 0.dp, - ) + expanded = showDropdownMenu, + onDismissRequest = { showDropdownMenu = false }, ) { - entries.forEachIndexed { index, entry -> + entries.forEach { entry -> DropdownMenuItem( - text = { Text(text = labels[index]) }, + text = { Text(text = entry.toString()) }, onClick = { - onEntryClicked(entry) - showDropDownMenu = false + onEntrySelected(entry) + showDropdownMenu = false }, - trailingIcon = if (selectedEntry == entry) { - { + leadingIcon = { + AnimatedVisibility(entry == selectedEntry) { Icon( imageVector = Icons.Default.Check, - contentDescription = null + contentDescription = null, ) } - } else { - null } ) } @@ -221,15 +255,6 @@ private fun DropDownSettings( } } -@Composable -private fun SettingsDivider() { - HorizontalDivider( - modifier = Modifier.padding(vertical = MaterialTheme.paddings.baseline), - thickness = 1.dp, - color = MaterialTheme.colorScheme.secondary - ) -} - @Preview(showBackground = true) @Composable fun AppSettingsPreview() { @@ -238,20 +263,3 @@ fun AppSettingsPreview() { AppSettingsView(AppSettingsViewModel(appSettingsRepository)) } } - -@Preview(showBackground = true) -@Composable -fun DropDownMenu() { - PillarboxTheme { - Column(modifier = Modifier.fillMaxSize()) { - val entries = listOf("Value 1", "Value 2", "Value 3") - DropDownSettings( - modifier = Modifier, - selectedEntry = entries[0], - entries = entries, - labels = entries, - onEntryClicked = {} - ) - } - } -}