diff --git a/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/SettingsScreen.kt b/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/SettingsScreen.kt index 6420566..ca48eb2 100644 --- a/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/SettingsScreen.kt +++ b/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/SettingsScreen.kt @@ -61,6 +61,7 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource @@ -74,14 +75,17 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.viewmodel.compose.viewModel import org.nsh07.pomodoro.R import org.nsh07.pomodoro.service.TimerService +import org.nsh07.pomodoro.ui.settingsScreen.viewModel.PreferencesState import org.nsh07.pomodoro.ui.settingsScreen.viewModel.SettingsViewModel import org.nsh07.pomodoro.ui.theme.AppFonts.robotoFlexTopBar import org.nsh07.pomodoro.ui.theme.CustomColors.listItemColors import org.nsh07.pomodoro.ui.theme.CustomColors.topBarColors import org.nsh07.pomodoro.ui.theme.TomatoShapeDefaults.bottomListItemShape +import org.nsh07.pomodoro.ui.theme.TomatoShapeDefaults.cardShape import org.nsh07.pomodoro.ui.theme.TomatoShapeDefaults.middleListItemShape import org.nsh07.pomodoro.ui.theme.TomatoShapeDefaults.topListItemShape import org.nsh07.pomodoro.ui.theme.TomatoTheme +import org.nsh07.pomodoro.utils.toColor @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -104,6 +108,8 @@ fun SettingsScreenRoot( val vibrateEnabled by viewModel.vibrateEnabled.collectAsStateWithLifecycle(true) val alarmSound by viewModel.alarmSound.collectAsStateWithLifecycle(viewModel.currentAlarmSound) + val preferencesState by viewModel.preferencesState.collectAsStateWithLifecycle() + val sessionsSliderState = rememberSaveable( saver = SliderState.Saver( viewModel.sessionsSliderState.onValueChangeFinished, @@ -114,6 +120,7 @@ fun SettingsScreenRoot( } SettingsScreen( + preferencesState = preferencesState, focusTimeInputFieldState = focusTimeInputFieldState, shortBreakTimeInputFieldState = shortBreakTimeInputFieldState, longBreakTimeInputFieldState = longBreakTimeInputFieldState, @@ -123,6 +130,7 @@ fun SettingsScreenRoot( alarmSound = alarmSound, onAlarmEnabledChange = viewModel::saveAlarmEnabled, onVibrateEnabledChange = viewModel::saveVibrateEnabled, + onBlackThemeChange = {}, onAlarmSoundChanged = { viewModel.saveAlarmSound(it) Intent(context, TimerService::class.java).apply { @@ -137,6 +145,7 @@ fun SettingsScreenRoot( @OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class) @Composable private fun SettingsScreen( + preferencesState: PreferencesState, focusTimeInputFieldState: TextFieldState, shortBreakTimeInputFieldState: TextFieldState, longBreakTimeInputFieldState: TextFieldState, @@ -146,6 +155,7 @@ private fun SettingsScreen( alarmSound: String, onAlarmEnabledChange: (Boolean) -> Unit, onVibrateEnabledChange: (Boolean) -> Unit, + onBlackThemeChange: (Boolean) -> Unit, onAlarmSoundChanged: (Uri?) -> Unit, modifier: Modifier = Modifier ) { @@ -182,6 +192,13 @@ private fun SettingsScreen( val switchItems = remember(alarmEnabled, vibrateEnabled) { listOf( + SettingsSwitchItem( + checked = preferencesState.blackTheme, + icon = R.drawable.contrast, + label = "Black theme", + description = "Use a pure black dark theme", + onClick = onBlackThemeChange + ), SettingsSwitchItem( checked = alarmEnabled, icon = R.drawable.alarm_on, @@ -314,9 +331,101 @@ private fun SettingsScreen( } }, colors = listItemColors, - modifier = Modifier.clip(topListItemShape) + modifier = Modifier.clip(cardShape) ) } + + item { Spacer(Modifier.height(12.dp)) } + + item { + ListItem( + leadingContent = { + Icon( + painter = painterResource(R.drawable.palette), + contentDescription = null, + tint = colorScheme.primary + ) + }, + headlineContent = { Text("Color scheme") }, + supportingContent = { + Text( + if (preferencesState.colorScheme.toColor() == Color.White) "Dynamic" + else "Color" + ) + }, + colors = listItemColors, + modifier = Modifier + .clip(topListItemShape) + .clickable(onClick = {}) + ) + } + item { + ListItem( + leadingContent = { + Icon( + painter = painterResource( + when (preferencesState.theme) { + "dark" -> R.drawable.dark_mode + "light" -> R.drawable.light_mode + else -> R.drawable.brightness_auto + } + ), + contentDescription = null + ) + }, + headlineContent = { Text("Theme") }, + supportingContent = { + Text( + when (preferencesState.theme) { + "dark" -> "Dark" + "light" -> "Light" + else -> "System default" + } + ) + }, + colors = listItemColors, + modifier = Modifier + .clip(middleListItemShape) + .clickable(onClick = {}) + ) + } + item { + val item = switchItems[0] + ListItem( + leadingContent = { + Icon(painterResource(item.icon), contentDescription = null) + }, + headlineContent = { Text(item.label) }, + supportingContent = { Text(item.description) }, + trailingContent = { + Switch( + checked = item.checked, + onCheckedChange = { item.onClick(it) }, + thumbContent = { + if (item.checked) { + Icon( + painter = painterResource(R.drawable.check), + contentDescription = null, + modifier = Modifier.size(SwitchDefaults.IconSize), + ) + } else { + Icon( + painter = painterResource(R.drawable.clear), + contentDescription = null, + modifier = Modifier.size(SwitchDefaults.IconSize), + ) + } + }, + colors = switchColors + ) + }, + colors = listItemColors, + modifier = Modifier.clip(bottomListItemShape) + ) + } + + item { Spacer(Modifier.height(12.dp)) } + item { ListItem( leadingContent = { @@ -333,12 +442,11 @@ private fun SettingsScreen( }, colors = listItemColors, modifier = Modifier - .clip(bottomListItemShape) + .clip(topListItemShape) .clickable(onClick = { ringtonePickerLauncher.launch(intent) }) ) } - item { Spacer(Modifier.height(12.dp)) } - itemsIndexed(switchItems) { index, item -> + itemsIndexed(switchItems.drop(1)) { index, item -> ListItem( leadingContent = { Icon(painterResource(item.icon), contentDescription = null) @@ -371,8 +479,7 @@ private fun SettingsScreen( modifier = Modifier .clip( when (index) { - 0 -> topListItemShape - switchItems.lastIndex -> bottomListItemShape + switchItems.lastIndex - 1 -> bottomListItemShape else -> middleListItemShape } ) @@ -422,6 +529,7 @@ private fun SettingsScreen( fun SettingsScreenPreview() { TomatoTheme { SettingsScreen( + preferencesState = PreferencesState(), focusTimeInputFieldState = rememberTextFieldState((25 * 60 * 1000).toString()), shortBreakTimeInputFieldState = rememberTextFieldState((5 * 60 * 1000).toString()), longBreakTimeInputFieldState = rememberTextFieldState((15 * 60 * 1000).toString()), @@ -431,6 +539,7 @@ fun SettingsScreenPreview() { alarmSound = "null", onAlarmEnabledChange = {}, onVibrateEnabledChange = {}, + onBlackThemeChange = {}, onAlarmSoundChanged = {}, modifier = Modifier.fillMaxSize() ) diff --git a/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/viewModel/SettingsViewModel.kt b/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/viewModel/SettingsViewModel.kt index 25c66ac..5cab4c2 100644 --- a/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/viewModel/SettingsViewModel.kt +++ b/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/viewModel/SettingsViewModel.kt @@ -147,6 +147,33 @@ class SettingsViewModel( timerRepository.alarmSoundUri = uri } + fun saveColorScheme(colorScheme: Color) { + viewModelScope.launch { + preferenceRepository.saveStringPreference("color_scheme", colorScheme.toString()) + } + _preferencesState.update { currentState -> + currentState.copy(colorScheme = colorScheme.toString()) + } + } + + fun saveTheme(theme: String) { + viewModelScope.launch { + preferenceRepository.saveStringPreference("theme", theme) + } + _preferencesState.update { currentState -> + currentState.copy(theme = theme) + } + } + + fun saveBlackTheme(blackTheme: Boolean) { + viewModelScope.launch { + preferenceRepository.saveBooleanPreference("black_theme", blackTheme) + } + _preferencesState.update { currentState -> + currentState.copy(blackTheme = blackTheme) + } + } + companion object { val Factory: ViewModelProvider.Factory = viewModelFactory { initializer { diff --git a/app/src/main/res/drawable/brightness_auto.xml b/app/src/main/res/drawable/brightness_auto.xml new file mode 100644 index 0000000..4cf4213 --- /dev/null +++ b/app/src/main/res/drawable/brightness_auto.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/contrast.xml b/app/src/main/res/drawable/contrast.xml new file mode 100644 index 0000000..e25b8a8 --- /dev/null +++ b/app/src/main/res/drawable/contrast.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/dark_mode.xml b/app/src/main/res/drawable/dark_mode.xml new file mode 100644 index 0000000..74b86ba --- /dev/null +++ b/app/src/main/res/drawable/dark_mode.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/light_mode.xml b/app/src/main/res/drawable/light_mode.xml new file mode 100644 index 0000000..78dd9d6 --- /dev/null +++ b/app/src/main/res/drawable/light_mode.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/palette.xml b/app/src/main/res/drawable/palette.xml new file mode 100644 index 0000000..22a62f8 --- /dev/null +++ b/app/src/main/res/drawable/palette.xml @@ -0,0 +1,9 @@ + + +