mirror of
https://github.com/bbara04/Purefin.git
synced 2026-07-24 03:36:51 +00:00
feat: enhance settings screen with dropdown and void setting options for improved user experience
This commit is contained in:
@@ -2,6 +2,7 @@ package hu.bbara.purefin.ui.screen.settings
|
|||||||
|
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
@@ -11,6 +12,8 @@ import androidx.compose.foundation.lazy.LazyColumn
|
|||||||
import androidx.compose.foundation.text.KeyboardOptions
|
import androidx.compose.foundation.text.KeyboardOptions
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.automirrored.outlined.ArrowBack
|
import androidx.compose.material.icons.automirrored.outlined.ArrowBack
|
||||||
|
import androidx.compose.material3.DropdownMenu
|
||||||
|
import androidx.compose.material3.DropdownMenuItem
|
||||||
import androidx.compose.material3.HorizontalDivider
|
import androidx.compose.material3.HorizontalDivider
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.IconButton
|
import androidx.compose.material3.IconButton
|
||||||
@@ -32,7 +35,13 @@ import androidx.compose.ui.text.input.KeyboardCapitalization
|
|||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.hilt.navigation.compose.hiltViewModel
|
import androidx.hilt.navigation.compose.hiltViewModel
|
||||||
import hu.bbara.purefin.core.feature.settings.SettingsViewModel
|
import hu.bbara.purefin.core.feature.settings.SettingsViewModel
|
||||||
|
import hu.bbara.purefin.core.settings.BooleanSetting
|
||||||
|
import hu.bbara.purefin.core.settings.DropdownSetting
|
||||||
|
import hu.bbara.purefin.core.settings.RangeSetting
|
||||||
|
import hu.bbara.purefin.core.settings.SettingOption
|
||||||
import hu.bbara.purefin.core.settings.SettingsOptions
|
import hu.bbara.purefin.core.settings.SettingsOptions
|
||||||
|
import hu.bbara.purefin.core.settings.StringSetting
|
||||||
|
import hu.bbara.purefin.core.settings.VoidSetting
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@@ -63,17 +72,39 @@ fun TvSettingsScreen(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SettingsOptions.groups.forEach { group ->
|
||||||
|
group.title?.let { title ->
|
||||||
item {
|
item {
|
||||||
Text(
|
Text(
|
||||||
text = "Playback",
|
text = title,
|
||||||
style = MaterialTheme.typography.titleMedium,
|
style = MaterialTheme.typography.titleMedium,
|
||||||
color = MaterialTheme.colorScheme.primary,
|
color = MaterialTheme.colorScheme.primary,
|
||||||
modifier = Modifier.padding(horizontal = 28.dp, vertical = 8.dp)
|
modifier = Modifier.padding(horizontal = 28.dp, vertical = 8.dp)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SettingsOptions.numberSettings.forEach { option ->
|
group.options.forEach { option ->
|
||||||
item(key = option.key) {
|
item(key = option.key) {
|
||||||
|
TvSettingOptionItem(
|
||||||
|
option = option,
|
||||||
|
viewModel = viewModel
|
||||||
|
)
|
||||||
|
HorizontalDivider()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun TvSettingOptionItem(
|
||||||
|
option: SettingOption<*>,
|
||||||
|
viewModel: SettingsViewModel
|
||||||
|
) {
|
||||||
|
when (option) {
|
||||||
|
is RangeSetting -> {
|
||||||
val value by viewModel.value(option).collectAsState(initial = option.defaultValue)
|
val value by viewModel.value(option).collectAsState(initial = option.defaultValue)
|
||||||
TvNumberSettingItem(
|
TvNumberSettingItem(
|
||||||
title = option.title,
|
title = option.title,
|
||||||
@@ -81,35 +112,54 @@ fun TvSettingsScreen(
|
|||||||
valueRange = option.valueRange,
|
valueRange = option.valueRange,
|
||||||
onValueChange = { viewModel.set(option, it) }
|
onValueChange = { viewModel.set(option, it) }
|
||||||
)
|
)
|
||||||
HorizontalDivider()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingsOptions.booleanSettings.forEach { option ->
|
is BooleanSetting -> {
|
||||||
item(key = option.key) {
|
|
||||||
val value by viewModel.value(option).collectAsState(initial = option.defaultValue)
|
val value by viewModel.value(option).collectAsState(initial = option.defaultValue)
|
||||||
TvBooleanSettingItem(
|
TvBooleanSettingItem(
|
||||||
title = option.title,
|
title = option.title,
|
||||||
value = value,
|
value = value,
|
||||||
onValueChange = { viewModel.set(option, it) }
|
onValueChange = { viewModel.set(option, it) }
|
||||||
)
|
)
|
||||||
HorizontalDivider()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingsOptions.stringSettings.forEach { option ->
|
is StringSetting -> {
|
||||||
item(key = option.key) {
|
|
||||||
val value by viewModel.value(option).collectAsState(initial = option.defaultValue)
|
val value by viewModel.value(option).collectAsState(initial = option.defaultValue)
|
||||||
TvStringSettingItem(
|
TvStringSettingItem(
|
||||||
title = option.title,
|
title = option.title,
|
||||||
value = value,
|
value = value,
|
||||||
onValueChange = { viewModel.set(option, it) }
|
onValueChange = { viewModel.set(option, it) }
|
||||||
)
|
)
|
||||||
HorizontalDivider()
|
}
|
||||||
}
|
|
||||||
|
is VoidSetting -> {
|
||||||
|
TvVoidSettingItem(
|
||||||
|
title = option.title,
|
||||||
|
onClick = {}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
is DropdownSetting<*> -> {
|
||||||
|
TvDropdownSettingOptionItem(
|
||||||
|
option = option,
|
||||||
|
viewModel = viewModel
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun <T> TvDropdownSettingOptionItem(
|
||||||
|
option: DropdownSetting<T>,
|
||||||
|
viewModel: SettingsViewModel
|
||||||
|
) {
|
||||||
|
val value by viewModel.value(option).collectAsState(initial = option.defaultValue)
|
||||||
|
TvDropdownSettingItem(
|
||||||
|
title = option.title,
|
||||||
|
value = value,
|
||||||
|
options = option.options,
|
||||||
|
onValueChange = { viewModel.set(option, it) }
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@@ -131,6 +181,72 @@ private fun TvSettingsTopBar(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun TvVoidSettingItem(
|
||||||
|
title: String,
|
||||||
|
onClick: () -> Unit,
|
||||||
|
modifier: Modifier = Modifier
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
modifier = modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.clickable(onClick = onClick)
|
||||||
|
.padding(horizontal = 28.dp, vertical = 16.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = title,
|
||||||
|
style = MaterialTheme.typography.bodyLarge
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun <T> TvDropdownSettingItem(
|
||||||
|
title: String,
|
||||||
|
value: T,
|
||||||
|
options: List<T>,
|
||||||
|
onValueChange: (T) -> Unit,
|
||||||
|
modifier: Modifier = Modifier
|
||||||
|
) {
|
||||||
|
var expanded by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
|
Box(modifier = modifier.fillMaxWidth()) {
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.clickable { expanded = true }
|
||||||
|
.padding(horizontal = 28.dp, vertical = 16.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = title,
|
||||||
|
style = MaterialTheme.typography.bodyLarge
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = value.toString(),
|
||||||
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
|
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||||
|
)
|
||||||
|
}
|
||||||
|
DropdownMenu(
|
||||||
|
expanded = expanded,
|
||||||
|
onDismissRequest = { expanded = false }
|
||||||
|
) {
|
||||||
|
options.forEach { option ->
|
||||||
|
DropdownMenuItem(
|
||||||
|
text = { Text(option.toString()) },
|
||||||
|
onClick = {
|
||||||
|
expanded = false
|
||||||
|
onValueChange(option)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun TvNumberSettingItem(
|
private fun TvNumberSettingItem(
|
||||||
title: String,
|
title: String,
|
||||||
|
|||||||
@@ -17,12 +17,20 @@ import androidx.compose.ui.Modifier
|
|||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.hilt.navigation.compose.hiltViewModel
|
import androidx.hilt.navigation.compose.hiltViewModel
|
||||||
import hu.bbara.purefin.core.feature.settings.SettingsViewModel
|
import hu.bbara.purefin.core.feature.settings.SettingsViewModel
|
||||||
|
import hu.bbara.purefin.core.settings.BooleanSetting
|
||||||
|
import hu.bbara.purefin.core.settings.DropdownSetting
|
||||||
|
import hu.bbara.purefin.core.settings.RangeSetting
|
||||||
|
import hu.bbara.purefin.core.settings.SettingOption
|
||||||
import hu.bbara.purefin.core.settings.SettingsOptions
|
import hu.bbara.purefin.core.settings.SettingsOptions
|
||||||
|
import hu.bbara.purefin.core.settings.StringSetting
|
||||||
|
import hu.bbara.purefin.core.settings.VoidSetting
|
||||||
import hu.bbara.purefin.ui.screen.home.components.DefaultTopBar
|
import hu.bbara.purefin.ui.screen.home.components.DefaultTopBar
|
||||||
import hu.bbara.purefin.ui.screen.home.components.DefaultTopBarIconButton
|
import hu.bbara.purefin.ui.screen.home.components.DefaultTopBarIconButton
|
||||||
import hu.bbara.purefin.ui.screen.settings.components.BooleanSettingItem
|
import hu.bbara.purefin.ui.screen.settings.components.BooleanSettingItem
|
||||||
import hu.bbara.purefin.ui.screen.settings.components.NumberSettingItem
|
import hu.bbara.purefin.ui.screen.settings.components.DropdownSettingItem
|
||||||
|
import hu.bbara.purefin.ui.screen.settings.components.RangeSettingItem
|
||||||
import hu.bbara.purefin.ui.screen.settings.components.StringSettingItem
|
import hu.bbara.purefin.ui.screen.settings.components.StringSettingItem
|
||||||
|
import hu.bbara.purefin.ui.screen.settings.components.VoidSettingItem
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun SettingsScreen(
|
fun SettingsScreen(
|
||||||
@@ -51,53 +59,94 @@ fun SettingsScreen(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SettingsOptions.groups.forEach { group ->
|
||||||
|
group.title?.let { title ->
|
||||||
item {
|
item {
|
||||||
Text(
|
Text(
|
||||||
text = "Playback",
|
text = title,
|
||||||
style = MaterialTheme.typography.titleMedium,
|
style = MaterialTheme.typography.titleMedium,
|
||||||
color = MaterialTheme.colorScheme.primary,
|
color = MaterialTheme.colorScheme.primary,
|
||||||
modifier = Modifier.padding(horizontal = 24.dp, vertical = 8.dp)
|
modifier = Modifier.padding(horizontal = 24.dp, vertical = 8.dp)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SettingsOptions.numberSettings.forEach { option ->
|
group.options.forEach { option ->
|
||||||
item(key = option.key) {
|
item(key = option.key) {
|
||||||
|
SettingOptionItem(
|
||||||
|
option = option,
|
||||||
|
viewModel = viewModel
|
||||||
|
)
|
||||||
|
HorizontalDivider()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun SettingOptionItem(
|
||||||
|
option: SettingOption<*>,
|
||||||
|
viewModel: SettingsViewModel
|
||||||
|
) {
|
||||||
|
when (option) {
|
||||||
|
is RangeSetting -> {
|
||||||
val value by viewModel.value(option).collectAsState(initial = option.defaultValue)
|
val value by viewModel.value(option).collectAsState(initial = option.defaultValue)
|
||||||
NumberSettingItem(
|
RangeSettingItem(
|
||||||
title = option.title,
|
title = option.title,
|
||||||
value = value,
|
value = value,
|
||||||
valueRange = option.valueRange,
|
valueRange = option.valueRange,
|
||||||
onValueChange = { viewModel.set(option, it) }
|
onValueChange = { viewModel.set(option, it) }
|
||||||
)
|
)
|
||||||
HorizontalDivider()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingsOptions.booleanSettings.forEach { option ->
|
is BooleanSetting -> {
|
||||||
item(key = option.key) {
|
|
||||||
val value by viewModel.value(option).collectAsState(initial = option.defaultValue)
|
val value by viewModel.value(option).collectAsState(initial = option.defaultValue)
|
||||||
BooleanSettingItem(
|
BooleanSettingItem(
|
||||||
title = option.title,
|
title = option.title,
|
||||||
value = value,
|
value = value,
|
||||||
onValueChange = { viewModel.set(option, it) }
|
onValueChange = { viewModel.set(option, it) }
|
||||||
)
|
)
|
||||||
HorizontalDivider()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingsOptions.stringSettings.forEach { option ->
|
is StringSetting -> {
|
||||||
item(key = option.key) {
|
|
||||||
val value by viewModel.value(option).collectAsState(initial = option.defaultValue)
|
val value by viewModel.value(option).collectAsState(initial = option.defaultValue)
|
||||||
StringSettingItem(
|
StringSettingItem(
|
||||||
title = option.title,
|
title = option.title,
|
||||||
value = value,
|
value = value,
|
||||||
onValueChange = { viewModel.set(option, it) }
|
onValueChange = { viewModel.set(option, it) }
|
||||||
)
|
)
|
||||||
HorizontalDivider()
|
}
|
||||||
}
|
|
||||||
|
is VoidSetting -> {
|
||||||
|
VoidSettingItem(
|
||||||
|
title = option.title,
|
||||||
|
onClick = {}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
is DropdownSetting<*> -> {
|
||||||
|
DropdownSettingOptionItem(
|
||||||
|
option = option,
|
||||||
|
viewModel = viewModel
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun <T> DropdownSettingOptionItem(
|
||||||
|
option: DropdownSetting<T>,
|
||||||
|
viewModel: SettingsViewModel
|
||||||
|
) {
|
||||||
|
val value by viewModel.value(option).collectAsState(initial = option.defaultValue)
|
||||||
|
DropdownSettingItem(
|
||||||
|
title = option.title,
|
||||||
|
value = value,
|
||||||
|
options = option.options,
|
||||||
|
onValueChange = { viewModel.set(option, it) }
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
|||||||
@@ -0,0 +1,65 @@
|
|||||||
|
package hu.bbara.purefin.ui.screen.settings.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.material3.DropdownMenuItem
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.ExposedDropdownMenuBox
|
||||||
|
import androidx.compose.material3.ExposedDropdownMenuDefaults
|
||||||
|
import androidx.compose.material3.OutlinedTextField
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
@Composable
|
||||||
|
fun <T> DropdownSettingItem(
|
||||||
|
title: String,
|
||||||
|
value: T,
|
||||||
|
options: List<T>,
|
||||||
|
onValueChange: (T) -> Unit,
|
||||||
|
modifier: Modifier = Modifier.Companion
|
||||||
|
) {
|
||||||
|
var expanded by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
|
ExposedDropdownMenuBox(
|
||||||
|
expanded = expanded,
|
||||||
|
onExpandedChange = { expanded = it },
|
||||||
|
modifier = modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(horizontal = 24.dp, vertical = 16.dp)
|
||||||
|
) {
|
||||||
|
OutlinedTextField(
|
||||||
|
value = value.toString(),
|
||||||
|
onValueChange = {},
|
||||||
|
readOnly = true,
|
||||||
|
label = { Text(title) },
|
||||||
|
singleLine = true,
|
||||||
|
trailingIcon = {
|
||||||
|
ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded)
|
||||||
|
},
|
||||||
|
modifier = Modifier
|
||||||
|
.menuAnchor()
|
||||||
|
.fillMaxWidth()
|
||||||
|
)
|
||||||
|
ExposedDropdownMenu(
|
||||||
|
expanded = expanded,
|
||||||
|
onDismissRequest = { expanded = false }
|
||||||
|
) {
|
||||||
|
options.forEach { option ->
|
||||||
|
DropdownMenuItem(
|
||||||
|
text = { Text(option.toString()) },
|
||||||
|
onClick = {
|
||||||
|
expanded = false
|
||||||
|
onValueChange(option)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,7 +17,7 @@ import androidx.compose.ui.unit.dp
|
|||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun NumberSettingItem(
|
fun RangeSettingItem(
|
||||||
title: String,
|
title: String,
|
||||||
value: Double,
|
value: Double,
|
||||||
valueRange: ClosedFloatingPointRange<Double>,
|
valueRange: ClosedFloatingPointRange<Double>,
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package hu.bbara.purefin.ui.screen.settings.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.material3.ListItem
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun VoidSettingItem(
|
||||||
|
title: String,
|
||||||
|
onClick: () -> Unit,
|
||||||
|
modifier: Modifier = Modifier.Companion
|
||||||
|
) {
|
||||||
|
ListItem(
|
||||||
|
headlineContent = {
|
||||||
|
Text(
|
||||||
|
text = title,
|
||||||
|
style = MaterialTheme.typography.bodyLarge
|
||||||
|
)
|
||||||
|
},
|
||||||
|
modifier = modifier.clickable(onClick = onClick)
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -5,7 +5,8 @@ import androidx.lifecycle.viewModelScope
|
|||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import hu.bbara.purefin.core.navigation.NavigationManager
|
import hu.bbara.purefin.core.navigation.NavigationManager
|
||||||
import hu.bbara.purefin.core.settings.BooleanSetting
|
import hu.bbara.purefin.core.settings.BooleanSetting
|
||||||
import hu.bbara.purefin.core.settings.NumberSetting
|
import hu.bbara.purefin.core.settings.DropdownSetting
|
||||||
|
import hu.bbara.purefin.core.settings.RangeSetting
|
||||||
import hu.bbara.purefin.core.settings.SettingsRepository
|
import hu.bbara.purefin.core.settings.SettingsRepository
|
||||||
import hu.bbara.purefin.core.settings.StringSetting
|
import hu.bbara.purefin.core.settings.StringSetting
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@@ -17,13 +18,15 @@ class SettingsViewModel @Inject constructor(
|
|||||||
private val navigationManager: NavigationManager,
|
private val navigationManager: NavigationManager,
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
|
|
||||||
fun value(option: NumberSetting) = settingsRepository.value(option)
|
fun value(option: RangeSetting) = settingsRepository.value(option)
|
||||||
|
|
||||||
fun value(option: BooleanSetting) = settingsRepository.value(option)
|
fun value(option: BooleanSetting) = settingsRepository.value(option)
|
||||||
|
|
||||||
fun value(option: StringSetting) = settingsRepository.value(option)
|
fun value(option: StringSetting) = settingsRepository.value(option)
|
||||||
|
|
||||||
fun set(option: NumberSetting, value: Double) {
|
fun <T> value(option: DropdownSetting<T>) = settingsRepository.value(option)
|
||||||
|
|
||||||
|
fun set(option: RangeSetting, value: Double) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
settingsRepository.set(option, value)
|
settingsRepository.set(option, value)
|
||||||
}
|
}
|
||||||
@@ -41,6 +44,12 @@ class SettingsViewModel @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun <T> set(option: DropdownSetting<T>, value: T) {
|
||||||
|
viewModelScope.launch {
|
||||||
|
settingsRepository.set(option, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun onBack() {
|
fun onBack() {
|
||||||
navigationManager.pop()
|
navigationManager.pop()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ sealed interface SettingOption<T> {
|
|||||||
val defaultValue: T
|
val defaultValue: T
|
||||||
}
|
}
|
||||||
|
|
||||||
data class NumberSetting(
|
data class RangeSetting(
|
||||||
override val key: String,
|
override val key: String,
|
||||||
override val title: String,
|
override val title: String,
|
||||||
override val defaultValue: Double,
|
override val defaultValue: Double,
|
||||||
@@ -25,8 +25,26 @@ data class StringSetting(
|
|||||||
override val defaultValue: String
|
override val defaultValue: String
|
||||||
) : SettingOption<String>
|
) : SettingOption<String>
|
||||||
|
|
||||||
|
data class VoidSetting(
|
||||||
|
override val key: String,
|
||||||
|
override val title: String,
|
||||||
|
override val defaultValue: Unit = Unit
|
||||||
|
) : SettingOption<Unit>
|
||||||
|
|
||||||
|
data class DropdownSetting<T>(
|
||||||
|
override val key: String,
|
||||||
|
override val title: String,
|
||||||
|
override val defaultValue: T,
|
||||||
|
val options: List<T>
|
||||||
|
): SettingOption<T>
|
||||||
|
|
||||||
|
data class SettingGroup(
|
||||||
|
val title: String?,
|
||||||
|
val options: List<SettingOption<*>>
|
||||||
|
)
|
||||||
|
|
||||||
object SettingsOptions {
|
object SettingsOptions {
|
||||||
val defaultPlaybackSpeed = NumberSetting(
|
val defaultPlaybackSpeed = RangeSetting(
|
||||||
key = "default_playback_speed",
|
key = "default_playback_speed",
|
||||||
title = "Default playback speed",
|
title = "Default playback speed",
|
||||||
defaultValue = 1.0,
|
defaultValue = 1.0,
|
||||||
@@ -45,7 +63,28 @@ object SettingsOptions {
|
|||||||
defaultValue = "English"
|
defaultValue = "English"
|
||||||
)
|
)
|
||||||
|
|
||||||
val numberSettings = listOf(defaultPlaybackSpeed)
|
val resetPlaybackSettings = VoidSetting(
|
||||||
val booleanSettings = listOf(confirmMobileDataPlayback)
|
key = "reset_playback_settings",
|
||||||
val stringSettings = listOf(preferredAudioLanguage)
|
title = "Reset playback settings"
|
||||||
|
)
|
||||||
|
|
||||||
|
val streamingQuality = DropdownSetting(
|
||||||
|
key = "streaming_quality",
|
||||||
|
title = "Streaming quality",
|
||||||
|
defaultValue = "Auto",
|
||||||
|
options = listOf("Auto", "Low", "Medium", "High")
|
||||||
|
)
|
||||||
|
|
||||||
|
val groups = listOf(
|
||||||
|
SettingGroup(
|
||||||
|
title = "Playback",
|
||||||
|
options = listOf(
|
||||||
|
defaultPlaybackSpeed,
|
||||||
|
confirmMobileDataPlayback,
|
||||||
|
preferredAudioLanguage,
|
||||||
|
resetPlaybackSettings,
|
||||||
|
streamingQuality
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,15 +6,19 @@ import kotlinx.coroutines.flow.Flow
|
|||||||
interface SettingsRepository {
|
interface SettingsRepository {
|
||||||
val settings: Flow<Settings>
|
val settings: Flow<Settings>
|
||||||
|
|
||||||
fun value(option: NumberSetting): Flow<Double>
|
fun value(option: RangeSetting): Flow<Double>
|
||||||
|
|
||||||
fun value(option: BooleanSetting): Flow<Boolean>
|
fun value(option: BooleanSetting): Flow<Boolean>
|
||||||
|
|
||||||
fun value(option: StringSetting): Flow<String>
|
fun value(option: StringSetting): Flow<String>
|
||||||
|
|
||||||
suspend fun set(option: NumberSetting, value: Double)
|
fun <T> value(option: DropdownSetting<T>): Flow<T>
|
||||||
|
|
||||||
|
suspend fun set(option: RangeSetting, value: Double)
|
||||||
|
|
||||||
suspend fun set(option: BooleanSetting, value: Boolean)
|
suspend fun set(option: BooleanSetting, value: Boolean)
|
||||||
|
|
||||||
suspend fun set(option: StringSetting, value: String)
|
suspend fun set(option: StringSetting, value: String)
|
||||||
|
|
||||||
|
suspend fun <T> set(option: DropdownSetting<T>, value: T)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,8 @@ package hu.bbara.purefin.data.settings
|
|||||||
|
|
||||||
import androidx.datastore.core.DataStore
|
import androidx.datastore.core.DataStore
|
||||||
import hu.bbara.purefin.core.settings.BooleanSetting
|
import hu.bbara.purefin.core.settings.BooleanSetting
|
||||||
import hu.bbara.purefin.core.settings.NumberSetting
|
import hu.bbara.purefin.core.settings.DropdownSetting
|
||||||
|
import hu.bbara.purefin.core.settings.RangeSetting
|
||||||
import hu.bbara.purefin.core.settings.SettingsRepository
|
import hu.bbara.purefin.core.settings.SettingsRepository
|
||||||
import hu.bbara.purefin.core.settings.StringSetting
|
import hu.bbara.purefin.core.settings.StringSetting
|
||||||
import hu.bbara.purefin.model.Settings
|
import hu.bbara.purefin.model.Settings
|
||||||
@@ -17,7 +18,7 @@ class SettingsRepositoryImpl @Inject constructor(
|
|||||||
|
|
||||||
override val settings: Flow<Settings> = settingsDataStore.data
|
override val settings: Flow<Settings> = settingsDataStore.data
|
||||||
|
|
||||||
override fun value(option: NumberSetting): Flow<Double> {
|
override fun value(option: RangeSetting): Flow<Double> {
|
||||||
return settings
|
return settings
|
||||||
.map { it.numberSettings[option.key] ?: option.defaultValue }
|
.map { it.numberSettings[option.key] ?: option.defaultValue }
|
||||||
.distinctUntilChanged()
|
.distinctUntilChanged()
|
||||||
@@ -35,7 +36,16 @@ class SettingsRepositoryImpl @Inject constructor(
|
|||||||
.distinctUntilChanged()
|
.distinctUntilChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun set(option: NumberSetting, value: Double) {
|
override fun <T> value(option: DropdownSetting<T>): Flow<T> {
|
||||||
|
return settings
|
||||||
|
.map { settings ->
|
||||||
|
val storedValue = settings.stringSettings[option.key]
|
||||||
|
option.options.firstOrNull { it.toString() == storedValue } ?: option.defaultValue
|
||||||
|
}
|
||||||
|
.distinctUntilChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun set(option: RangeSetting, value: Double) {
|
||||||
settingsDataStore.updateData { current ->
|
settingsDataStore.updateData { current ->
|
||||||
current.copy(
|
current.copy(
|
||||||
numberSettings = current.numberSettings + (option.key to value)
|
numberSettings = current.numberSettings + (option.key to value)
|
||||||
@@ -58,4 +68,12 @@ class SettingsRepositoryImpl @Inject constructor(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun <T> set(option: DropdownSetting<T>, value: T) {
|
||||||
|
settingsDataStore.updateData { current ->
|
||||||
|
current.copy(
|
||||||
|
stringSettings = current.stringSettings + (option.key to value.toString())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user