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 @@
+
+
+