diff --git a/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/AboutCard.kt b/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/AboutCard.kt index 96da61c..499b503 100644 --- a/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/AboutCard.kt +++ b/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/AboutCard.kt @@ -1,8 +1,18 @@ /* * Copyright (c) 2025 Nishant Mishra * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * This file is part of Tomato - a minimalist pomodoro timer for Android. + * + * Tomato is free software: you can redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * Tomato is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along with Tomato. + * If not, see . */ package org.nsh07.pomodoro.ui.settingsScreen @@ -36,7 +46,6 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import org.nsh07.pomodoro.BuildConfig import org.nsh07.pomodoro.R -import org.nsh07.pomodoro.ui.theme.AppFonts.robotoFlexHeadline import org.nsh07.pomodoro.ui.theme.AppFonts.robotoFlexTopBar // Taken from https://github.com/shub39/Grit/blob/master/app/src/main/java/com/shub39/grit/core/presentation/settings/ui/component/AboutApp.kt @@ -71,10 +80,7 @@ fun AboutCard(modifier: Modifier = Modifier) { style = MaterialTheme.typography.titleLarge, fontFamily = robotoFlexTopBar ) - Text( - text = "${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE})", - fontFamily = robotoFlexHeadline - ) + Text(text = "${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE})") } Spacer(modifier = Modifier.weight(1f)) diff --git a/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/AlarmSettings.kt b/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/AlarmSettings.kt new file mode 100644 index 0000000..659d75f --- /dev/null +++ b/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/AlarmSettings.kt @@ -0,0 +1,236 @@ +/* + * Copyright (c) 2025 Nishant Mishra + * + * This file is part of Tomato - a minimalist pomodoro timer for Android. + * + * Tomato is free software: you can redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * Tomato is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along with Tomato. + * If not, see . + */ + +package org.nsh07.pomodoro.ui.settingsScreen + +import android.app.Activity +import android.content.Intent +import android.media.RingtoneManager +import android.net.Uri +import android.os.Build +import androidx.activity.compose.rememberLauncherForActivityResult +import androidx.activity.result.contract.ActivityResultContracts +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.itemsIndexed +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.LargeFlexibleTopAppBar +import androidx.compose.material3.ListItem +import androidx.compose.material3.Switch +import androidx.compose.material3.SwitchDefaults +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +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.draw.clip +import androidx.compose.ui.input.nestedscroll.nestedScroll +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import androidx.core.net.toUri +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import org.nsh07.pomodoro.R +import org.nsh07.pomodoro.ui.settingsScreen.viewModel.PreferencesState +import org.nsh07.pomodoro.ui.theme.AppFonts.robotoFlexTopBar +import org.nsh07.pomodoro.ui.theme.CustomColors.listItemColors +import org.nsh07.pomodoro.ui.theme.CustomColors.switchColors +import org.nsh07.pomodoro.ui.theme.CustomColors.topBarColors +import org.nsh07.pomodoro.ui.theme.TomatoShapeDefaults.bottomListItemShape +import org.nsh07.pomodoro.ui.theme.TomatoShapeDefaults.middleListItemShape +import org.nsh07.pomodoro.ui.theme.TomatoShapeDefaults.topListItemShape + +@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class) +@Composable +fun AlarmSettings( + preferencesState: PreferencesState, + alarmEnabled: Boolean, + vibrateEnabled: Boolean, + alarmSound: String, + onAlarmEnabledChange: (Boolean) -> Unit, + onVibrateEnabledChange: (Boolean) -> Unit, + onAlarmSoundChanged: (Uri?) -> Unit, + onBack: () -> Unit, + modifier: Modifier = Modifier +) { + val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior() + val context = LocalContext.current + + var alarmName by remember { mutableStateOf("...") } + + LaunchedEffect(alarmSound) { + withContext(Dispatchers.IO) { + alarmName = + RingtoneManager.getRingtone(context, alarmSound.toUri())?.getTitle(context) ?: "" + } + } + + val ringtonePickerLauncher = rememberLauncherForActivityResult( + contract = ActivityResultContracts.StartActivityForResult() + ) { result -> + if (result.resultCode == Activity.RESULT_OK) { + val uri = + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + result.data?.getParcelableExtra( + RingtoneManager.EXTRA_RINGTONE_PICKED_URI, + Uri::class.java + ) + } else { + @Suppress("DEPRECATION") + result.data?.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI) + } + onAlarmSoundChanged(uri) + } + } + + val ringtonePickerIntent = remember(alarmSound) { + Intent(RingtoneManager.ACTION_RINGTONE_PICKER).apply { + putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, RingtoneManager.TYPE_ALARM) + putExtra(RingtoneManager.EXTRA_RINGTONE_TITLE, context.getString(R.string.alarm_sound)) + putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, alarmSound.toUri()) + } + } + + val switchItems = remember( + preferencesState.blackTheme, + preferencesState.aodEnabled, + alarmEnabled, + vibrateEnabled + ) { + listOf( + SettingsSwitchItem( + checked = alarmEnabled, + icon = R.drawable.alarm_on, + label = R.string.alarm, + description = R.string.alarm_desc, + onClick = onAlarmEnabledChange + ), + SettingsSwitchItem( + checked = vibrateEnabled, + icon = R.drawable.mobile_vibrate, + label = R.string.vibrate, + description = R.string.vibrate_desc, + onClick = onVibrateEnabledChange + ) + ) + } + + Column(modifier.nestedScroll(scrollBehavior.nestedScrollConnection)) { + LargeFlexibleTopAppBar( + title = { + Text("Alarm", fontFamily = robotoFlexTopBar) + }, + subtitle = { + Text("Settings") + }, + navigationIcon = { + IconButton(onBack) { + Icon( + painterResource(R.drawable.arrow_back), + null + ) + } + }, + colors = topBarColors, + scrollBehavior = scrollBehavior + ) + + LazyColumn( + verticalArrangement = Arrangement.spacedBy(2.dp), + modifier = Modifier + .background(topBarColors.containerColor) + .fillMaxSize() + .padding(horizontal = 16.dp) + ) { + item { + Spacer(Modifier.height(14.dp)) + } + + item { + ListItem( + leadingContent = { + Icon(painterResource(R.drawable.alarm), null) + }, + headlineContent = { Text(stringResource(R.string.alarm_sound)) }, + supportingContent = { Text(alarmName) }, + colors = listItemColors, + modifier = Modifier + .clip(topListItemShape) + .clickable(onClick = { ringtonePickerLauncher.launch(ringtonePickerIntent) }) + ) + } + itemsIndexed(switchItems) { index, item -> + ListItem( + leadingContent = { + Icon(painterResource(item.icon), contentDescription = null) + }, + headlineContent = { Text(stringResource(item.label)) }, + supportingContent = { Text(stringResource(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( + when (index) { + switchItems.lastIndex -> bottomListItemShape + else -> middleListItemShape + } + ) + ) + } + + item { Spacer(Modifier.height(12.dp)) } + } + } +} diff --git a/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/AppearanceSettings.kt b/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/AppearanceSettings.kt new file mode 100644 index 0000000..ca27045 --- /dev/null +++ b/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/AppearanceSettings.kt @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2025 Nishant Mishra + * + * This file is part of Tomato - a minimalist pomodoro timer for Android. + * + * Tomato is free software: you can redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * Tomato is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along with Tomato. + * If not, see . + */ + +package org.nsh07.pomodoro.ui.settingsScreen + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.LargeFlexibleTopAppBar +import androidx.compose.material3.ListItem +import androidx.compose.material3.Switch +import androidx.compose.material3.SwitchDefaults +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +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 +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import org.nsh07.pomodoro.R +import org.nsh07.pomodoro.ui.settingsScreen.viewModel.PreferencesState +import org.nsh07.pomodoro.ui.theme.AppFonts.robotoFlexTopBar +import org.nsh07.pomodoro.ui.theme.CustomColors.listItemColors +import org.nsh07.pomodoro.ui.theme.CustomColors.switchColors +import org.nsh07.pomodoro.ui.theme.CustomColors.topBarColors +import org.nsh07.pomodoro.ui.theme.TomatoShapeDefaults.bottomListItemShape +import org.nsh07.pomodoro.ui.theme.TomatoShapeDefaults.middleListItemShape +import org.nsh07.pomodoro.utils.toColor + +@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class) +@Composable +fun AppearanceSettings( + preferencesState: PreferencesState, + onBlackThemeChange: (Boolean) -> Unit, + onThemeChange: (String) -> Unit, + onColorSchemeChange: (Color) -> Unit, + onBack: () -> Unit, + modifier: Modifier = Modifier +) { + val context = LocalContext.current + + val themeMap: Map> = remember { + mapOf( + "auto" to Pair( + R.drawable.brightness_auto, + R.string.system_default + ), + "light" to Pair(R.drawable.light_mode, R.string.light), + "dark" to Pair(R.drawable.dark_mode, R.string.dark) + ) + } + val reverseThemeMap: Map = remember { + mapOf( + context.getString(R.string.system_default) to "auto", + context.getString(R.string.light) to "light", + context.getString(R.string.dark) to "dark" + ) + } + + val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior() + + Column(modifier.nestedScroll(scrollBehavior.nestedScrollConnection)) { + LargeFlexibleTopAppBar( + title = { + Text("Appearance", fontFamily = robotoFlexTopBar) + }, + subtitle = { + Text("Settings") + }, + navigationIcon = { + IconButton(onBack) { + Icon( + painterResource(R.drawable.arrow_back), + null + ) + } + }, + colors = topBarColors, + scrollBehavior = scrollBehavior + ) + + LazyColumn( + verticalArrangement = Arrangement.spacedBy(2.dp), + modifier = Modifier + .background(topBarColors.containerColor) + .fillMaxSize() + .padding(horizontal = 16.dp) + ) { + item { + Spacer(Modifier.height(14.dp)) + } + item { + ColorSchemePickerListItem( + color = preferencesState.colorScheme.toColor(), + items = 3, + index = 0, + onColorChange = onColorSchemeChange + ) + } + item { + ThemePickerListItem( + theme = preferencesState.theme, + themeMap = themeMap, + reverseThemeMap = reverseThemeMap, + onThemeChange = onThemeChange, + items = 3, + index = 1, + modifier = Modifier + .clip(middleListItemShape) + ) + } + item { + val item = SettingsSwitchItem( + checked = preferencesState.blackTheme, + icon = R.drawable.contrast, + label = R.string.black_theme, + description = R.string.black_theme_desc, + onClick = onBlackThemeChange + ) + ListItem( + leadingContent = { + Icon(painterResource(item.icon), contentDescription = null) + }, + headlineContent = { Text(stringResource(item.label)) }, + supportingContent = { Text(stringResource(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)) } + } + } +} + +@Preview +@Composable +fun AppearanceSettingsPreview() { + val preferencesState = PreferencesState() + AppearanceSettings( + preferencesState = preferencesState, + onBlackThemeChange = {}, + onThemeChange = {}, + onColorSchemeChange = {}, + onBack = {} + ) +} diff --git a/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/TimerSettings.kt b/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/TimerSettings.kt new file mode 100644 index 0000000..46354cd --- /dev/null +++ b/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/TimerSettings.kt @@ -0,0 +1,315 @@ +/* + * Copyright (c) 2025 Nishant Mishra + * + * This file is part of Tomato - a minimalist pomodoro timer for Android. + * + * Tomato is free software: you can redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * Tomato is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along with Tomato. + * If not, see . + */ + +package org.nsh07.pomodoro.ui.settingsScreen + +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.foundation.background +import androidx.compose.foundation.horizontalScroll +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.text.input.TextFieldState +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi +import androidx.compose.material3.FilledTonalIconToggleButton +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.IconButtonDefaults +import androidx.compose.material3.LargeFlexibleTopAppBar +import androidx.compose.material3.ListItem +import androidx.compose.material3.MaterialTheme.colorScheme +import androidx.compose.material3.MaterialTheme.typography +import androidx.compose.material3.Slider +import androidx.compose.material3.SliderState +import androidx.compose.material3.Switch +import androidx.compose.material3.SwitchDefaults +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBarDefaults +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.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.input.nestedscroll.nestedScroll +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.input.ImeAction +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import org.nsh07.pomodoro.R +import org.nsh07.pomodoro.ui.theme.AppFonts.robotoFlexTopBar +import org.nsh07.pomodoro.ui.theme.CustomColors.listItemColors +import org.nsh07.pomodoro.ui.theme.CustomColors.switchColors +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 + +@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class) +@Composable +fun TimerSettings( + aodEnabled: Boolean, + focusTimeInputFieldState: TextFieldState, + shortBreakTimeInputFieldState: TextFieldState, + longBreakTimeInputFieldState: TextFieldState, + sessionsSliderState: SliderState, + onAodEnabledChange: (Boolean) -> Unit, + onBack: () -> Unit, + modifier: Modifier = Modifier +) { + val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior() + + Column(modifier.nestedScroll(scrollBehavior.nestedScrollConnection)) { + LargeFlexibleTopAppBar( + title = { + Text("Timer", fontFamily = robotoFlexTopBar) + }, + subtitle = { + Text("Settings") + }, + navigationIcon = { + IconButton(onBack) { + Icon( + painterResource(R.drawable.arrow_back), + null + ) + } + }, + colors = topBarColors, + scrollBehavior = scrollBehavior + ) + + LazyColumn( + verticalArrangement = Arrangement.spacedBy(2.dp), + modifier = Modifier + .background(topBarColors.containerColor) + .fillMaxSize() + .padding(horizontal = 16.dp) + ) { + item { + Spacer(Modifier.height(14.dp)) + } + item { + Row( + horizontalArrangement = Arrangement.Center, + modifier = Modifier + .fillMaxWidth() + .horizontalScroll(rememberScrollState()) + ) { + Column( + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy(2.dp) + ) { + Text( + stringResource(R.string.focus), + style = typography.titleSmallEmphasized + ) + MinuteInputField( + state = focusTimeInputFieldState, + shape = RoundedCornerShape( + topStart = topListItemShape.topStart, + bottomStart = topListItemShape.topStart, + topEnd = topListItemShape.bottomStart, + bottomEnd = topListItemShape.bottomStart + ), + imeAction = ImeAction.Next + ) + } + Spacer(Modifier.width(2.dp)) + Column( + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy(2.dp) + ) { + Text( + stringResource(R.string.short_break), + style = typography.titleSmallEmphasized + ) + MinuteInputField( + state = shortBreakTimeInputFieldState, + shape = RoundedCornerShape(middleListItemShape.topStart), + imeAction = ImeAction.Next + ) + } + Spacer(Modifier.width(2.dp)) + Column( + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy(2.dp) + ) { + Text( + stringResource(R.string.long_break), + style = typography.titleSmallEmphasized + ) + MinuteInputField( + state = longBreakTimeInputFieldState, + shape = RoundedCornerShape( + topStart = bottomListItemShape.topStart, + bottomStart = bottomListItemShape.topStart, + topEnd = bottomListItemShape.bottomStart, + bottomEnd = bottomListItemShape.bottomStart + ), + imeAction = ImeAction.Done + ) + } + } + } + item { + Spacer(Modifier.height(12.dp)) + } + item { + ListItem( + leadingContent = { + Icon(painterResource(R.drawable.clocks), null) + }, + headlineContent = { + Text(stringResource(R.string.session_length)) + }, + supportingContent = { + Column { + Text( + stringResource( + R.string.session_length_desc, + sessionsSliderState.value.toInt() + ) + ) + Slider( + state = sessionsSliderState, + modifier = Modifier.padding(vertical = 4.dp) + ) + } + }, + colors = listItemColors, + modifier = Modifier.clip(cardShape) + ) + } + item { Spacer(Modifier.height(12.dp)) } + item { + val item = SettingsSwitchItem( + checked = aodEnabled, + icon = R.drawable.aod, + label = R.string.always_on_display, + description = R.string.always_on_display_desc, + onClick = onAodEnabledChange + ) + ListItem( + leadingContent = { + Icon( + painterResource(item.icon), + contentDescription = null, + modifier = Modifier.padding(top = 4.dp) + ) + }, + headlineContent = { Text(stringResource(item.label)) }, + supportingContent = { Text(stringResource(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(cardShape) + ) + } + + item { + var expanded by remember { mutableStateOf(false) } + Column( + horizontalAlignment = Alignment.End, + modifier = Modifier + .padding(vertical = 6.dp) + .fillMaxWidth() + ) { + FilledTonalIconToggleButton( + checked = expanded, + onCheckedChange = { expanded = it }, + shapes = IconButtonDefaults.toggleableShapes(), + modifier = Modifier.width(52.dp) + ) { + Icon( + painterResource(R.drawable.info), + null + ) + } + AnimatedVisibility(expanded) { + Text( + stringResource(R.string.pomodoro_info), + style = typography.bodyMedium, + color = colorScheme.onSurfaceVariant, + modifier = Modifier.padding(8.dp) + ) + } + } + } + + item { Spacer(Modifier.height(12.dp)) } + } + } +} + +@OptIn(ExperimentalMaterial3Api::class) +@Preview +@Composable +private fun TimerSettingsPreview() { + val focusTimeInputFieldState = TextFieldState("25") + val shortBreakTimeInputFieldState = TextFieldState("5") + val longBreakTimeInputFieldState = TextFieldState("15") + val sessionsSliderState = SliderState( + value = 4f, + valueRange = 1f..8f, + steps = 6 + ) + TimerSettings( + focusTimeInputFieldState = focusTimeInputFieldState, + shortBreakTimeInputFieldState = shortBreakTimeInputFieldState, + longBreakTimeInputFieldState = longBreakTimeInputFieldState, + sessionsSliderState = sessionsSliderState, + aodEnabled = true, + onBack = {}, + onAodEnabledChange = {} + ) +} \ No newline at end of file diff --git a/app/src/main/java/org/nsh07/pomodoro/ui/theme/Color.kt b/app/src/main/java/org/nsh07/pomodoro/ui/theme/Color.kt index 738f989..064d7d8 100644 --- a/app/src/main/java/org/nsh07/pomodoro/ui/theme/Color.kt +++ b/app/src/main/java/org/nsh07/pomodoro/ui/theme/Color.kt @@ -1,9 +1,28 @@ +/* + * Copyright (c) 2025 Nishant Mishra + * + * This file is part of Tomato - a minimalist pomodoro timer for Android. + * + * Tomato is free software: you can redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * Tomato is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along with Tomato. + * If not, see . + */ + package org.nsh07.pomodoro.ui.theme import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ListItemColors import androidx.compose.material3.ListItemDefaults import androidx.compose.material3.MaterialTheme.colorScheme +import androidx.compose.material3.SwitchColors +import androidx.compose.material3.SwitchDefaults import androidx.compose.material3.TopAppBarColors import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable @@ -41,4 +60,9 @@ object CustomColors { supportingColor = colorScheme.onSecondaryFixedVariant, trailingIconColor = colorScheme.onSecondaryFixedVariant ) + + val switchColors: SwitchColors + @Composable get() = SwitchDefaults.colors( + checkedIconColor = colorScheme.primary, + ) } \ No newline at end of file