Skip to content

Commit

Permalink
Align AppSettingsView design with the rest of the demo app
Browse files Browse the repository at this point in the history
  • Loading branch information
MGaetan89 committed Jul 26, 2024
1 parent 75999e6 commit acd574b
Showing 1 changed file with 153 additions and 145 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -37,199 +38,223 @@ 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
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

/**
* 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 <T> 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 <T> DropdownSetting(
text: String,
entries: List<T>,
labels: List<String>,
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
}
)
}
}
}
}

@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() {
Expand All @@ -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 = {}
)
}
}
}

0 comments on commit acd574b

Please sign in to comment.