feat(ui): implement navigation between settings pages

This commit is contained in:
Nishant Mishra
2025-10-22 20:25:40 +05:30
parent 612bc27859
commit cfb1a75d21
10 changed files with 319 additions and 88 deletions

View File

@@ -1,3 +1,20 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package org.nsh07.pomodoro package org.nsh07.pomodoro
import android.os.Bundle import android.os.Bundle
@@ -11,8 +28,6 @@ import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import org.nsh07.pomodoro.ui.AppScreen import org.nsh07.pomodoro.ui.AppScreen
import org.nsh07.pomodoro.ui.NavItem
import org.nsh07.pomodoro.ui.Screen
import org.nsh07.pomodoro.ui.settingsScreen.viewModel.SettingsViewModel import org.nsh07.pomodoro.ui.settingsScreen.viewModel.SettingsViewModel
import org.nsh07.pomodoro.ui.theme.TomatoTheme import org.nsh07.pomodoro.ui.theme.TomatoTheme
import org.nsh07.pomodoro.ui.timerScreen.viewModel.TimerViewModel import org.nsh07.pomodoro.ui.timerScreen.viewModel.TimerViewModel
@@ -70,27 +85,4 @@ class MainActivity : ComponentActivity() {
// Increase the timer loop frequency again when visible to make the progress smoother // Increase the timer loop frequency again when visible to make the progress smoother
appContainer.appTimerRepository.timerFrequency = 10f appContainer.appTimerRepository.timerFrequency = 10f
} }
companion object {
val screens = listOf(
NavItem(
Screen.Timer,
R.drawable.timer_outlined,
R.drawable.timer_filled,
R.string.timer
),
NavItem(
Screen.Stats,
R.drawable.monitoring,
R.drawable.monitoring_filled,
R.string.stats
),
NavItem(
Screen.Settings,
R.drawable.settings,
R.drawable.settings_filled,
R.string.settings
)
)
}
} }

View File

@@ -1,8 +1,18 @@
/* /*
* Copyright (c) 2025 Nishant Mishra * Copyright (c) 2025 Nishant Mishra
* *
* You should have received a copy of the GNU General Public License * This file is part of Tomato - a minimalist pomodoro timer for Android.
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
* 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 <https://www.gnu.org/licenses/>.
*/ */
package org.nsh07.pomodoro.ui package org.nsh07.pomodoro.ui
@@ -45,7 +55,6 @@ import androidx.navigation3.runtime.entryProvider
import androidx.navigation3.runtime.rememberNavBackStack import androidx.navigation3.runtime.rememberNavBackStack
import androidx.navigation3.ui.NavDisplay import androidx.navigation3.ui.NavDisplay
import androidx.window.core.layout.WindowSizeClass import androidx.window.core.layout.WindowSizeClass
import org.nsh07.pomodoro.MainActivity.Companion.screens
import org.nsh07.pomodoro.service.TimerService import org.nsh07.pomodoro.service.TimerService
import org.nsh07.pomodoro.ui.settingsScreen.SettingsScreenRoot import org.nsh07.pomodoro.ui.settingsScreen.SettingsScreenRoot
import org.nsh07.pomodoro.ui.statsScreen.StatsScreenRoot import org.nsh07.pomodoro.ui.statsScreen.StatsScreenRoot
@@ -100,7 +109,7 @@ fun AppScreen(
if (wide) ShortNavigationBarArrangement.Centered if (wide) ShortNavigationBarArrangement.Centered
else ShortNavigationBarArrangement.EqualWeight else ShortNavigationBarArrangement.EqualWeight
) { ) {
screens.forEach { mainScreens.forEach {
val selected = backStack.last() == it.route val selected = backStack.last() == it.route
ShortNavigationBarItem( ShortNavigationBarItem(
selected = selected, selected = selected,
@@ -131,7 +140,7 @@ fun AppScreen(
SharedTransitionLayout { SharedTransitionLayout {
NavDisplay( NavDisplay(
backStack = backStack, backStack = backStack,
onBack = { backStack.removeLastOrNull() }, onBack = backStack::removeLastOrNull,
transitionSpec = { transitionSpec = {
ContentTransform( ContentTransform(
fadeIn(motionScheme.defaultEffectsSpec()), fadeIn(motionScheme.defaultEffectsSpec()),
@@ -213,7 +222,7 @@ fun AppScreen(
) )
} }
entry<Screen.Settings> { entry<Screen.Settings.Main> {
SettingsScreenRoot( SettingsScreenRoot(
modifier = modifier.padding( modifier = modifier.padding(
start = contentPadding.calculateStartPadding(layoutDirection), start = contentPadding.calculateStartPadding(layoutDirection),

View File

@@ -0,0 +1,62 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package org.nsh07.pomodoro.ui
import org.nsh07.pomodoro.R
val mainScreens = listOf(
NavItem(
Screen.Timer,
R.drawable.timer_outlined,
R.drawable.timer_filled,
R.string.timer
),
NavItem(
Screen.Stats,
R.drawable.monitoring,
R.drawable.monitoring_filled,
R.string.stats
),
NavItem(
Screen.Settings.Main,
R.drawable.settings,
R.drawable.settings_filled,
R.string.settings
)
)
val settingsScreens = listOf(
SettingsNavItem(
Screen.Settings.Timer,
R.drawable.timer_filled,
R.string.timer,
listOf(R.string.durations, R.string.session_length, R.string.always_on_display)
),
SettingsNavItem(
Screen.Settings.Alarm,
R.drawable.alarm,
R.string.alarm,
listOf(R.string.alarm_sound, R.string.alarm, R.string.vibrate)
),
SettingsNavItem(
Screen.Settings.Appearance,
R.drawable.palette,
R.string.appearance,
listOf(R.string.color_scheme, R.string.theme, R.string.black_theme)
)
)

View File

@@ -1,3 +1,20 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package org.nsh07.pomodoro.ui package org.nsh07.pomodoro.ui
import androidx.annotation.DrawableRes import androidx.annotation.DrawableRes
@@ -13,7 +30,19 @@ sealed class Screen : NavKey {
object AOD : Screen() object AOD : Screen()
@Serializable @Serializable
object Settings : Screen() sealed class Settings : Screen() {
@Serializable
object Main : Settings()
@Serializable
object Alarm : Settings()
@Serializable
object Appearance : Settings()
@Serializable
object Timer : Settings()
}
@Serializable @Serializable
object Stats : Screen() object Stats : Screen()
@@ -24,4 +53,11 @@ data class NavItem(
@param:DrawableRes val unselectedIcon: Int, @param:DrawableRes val unselectedIcon: Int,
@param:DrawableRes val selectedIcon: Int, @param:DrawableRes val selectedIcon: Int,
@param:StringRes val label: Int @param:StringRes val label: Int
) )
data class SettingsNavItem(
val route: Screen.Settings,
@param:DrawableRes val icon: Int,
@param:StringRes val label: Int,
val innerSettings: List<Int>
)

View File

@@ -19,6 +19,11 @@ package org.nsh07.pomodoro.ui.settingsScreen
import android.content.Intent import android.content.Intent
import android.net.Uri import android.net.Uri
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.slideInHorizontally
import androidx.compose.animation.slideOutHorizontally
import androidx.compose.animation.togetherWith
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
@@ -27,10 +32,12 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.text.input.TextFieldState import androidx.compose.foundation.text.input.TextFieldState
import androidx.compose.foundation.text.input.rememberTextFieldState import androidx.compose.foundation.text.input.rememberTextFieldState
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.Icon
import androidx.compose.material3.LocalTextStyle import androidx.compose.material3.LocalTextStyle
import androidx.compose.material3.SliderState import androidx.compose.material3.SliderState
import androidx.compose.material3.Text import androidx.compose.material3.Text
@@ -40,24 +47,36 @@ import androidx.compose.material3.rememberSliderState
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Devices import androidx.compose.ui.tooling.preview.Devices
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation3.runtime.entryProvider
import androidx.navigation3.runtime.rememberNavBackStack
import androidx.navigation3.ui.NavDisplay
import org.nsh07.pomodoro.R import org.nsh07.pomodoro.R
import org.nsh07.pomodoro.service.TimerService import org.nsh07.pomodoro.service.TimerService
import org.nsh07.pomodoro.ui.ClickableListItem
import org.nsh07.pomodoro.ui.Screen
import org.nsh07.pomodoro.ui.settingsScreen.components.AboutCard import org.nsh07.pomodoro.ui.settingsScreen.components.AboutCard
import org.nsh07.pomodoro.ui.settingsScreen.screens.AlarmSettings
import org.nsh07.pomodoro.ui.settingsScreen.screens.AppearanceSettings
import org.nsh07.pomodoro.ui.settingsScreen.screens.TimerSettings
import org.nsh07.pomodoro.ui.settingsScreen.viewModel.PreferencesState import org.nsh07.pomodoro.ui.settingsScreen.viewModel.PreferencesState
import org.nsh07.pomodoro.ui.settingsScreen.viewModel.SettingsViewModel import org.nsh07.pomodoro.ui.settingsScreen.viewModel.SettingsViewModel
import org.nsh07.pomodoro.ui.settingsScreens
import org.nsh07.pomodoro.ui.theme.AppFonts.robotoFlexTopBar import org.nsh07.pomodoro.ui.theme.AppFonts.robotoFlexTopBar
import org.nsh07.pomodoro.ui.theme.CustomColors.topBarColors import org.nsh07.pomodoro.ui.theme.CustomColors.topBarColors
import org.nsh07.pomodoro.ui.theme.TomatoTheme import org.nsh07.pomodoro.ui.theme.TomatoTheme
@@ -147,44 +166,122 @@ private fun SettingsScreen(
onColorSchemeChange: (Color) -> Unit, onColorSchemeChange: (Color) -> Unit,
modifier: Modifier = Modifier modifier: Modifier = Modifier
) { ) {
val context = LocalContext.current
val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior() val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior()
val backStack = rememberNavBackStack(Screen.Settings.Main)
Column(modifier.nestedScroll(scrollBehavior.nestedScrollConnection)) { NavDisplay(
TopAppBar( backStack = backStack,
title = { onBack = backStack::removeLastOrNull,
Text( transitionSpec = {
stringResource(R.string.settings), (slideInHorizontally(initialOffsetX = { it }))
style = LocalTextStyle.current.copy( .togetherWith(slideOutHorizontally(targetOffsetX = { -it / 4 }) + fadeOut())
fontFamily = robotoFlexTopBar, },
fontSize = 32.sp, popTransitionSpec = {
lineHeight = 32.sp (slideInHorizontally(initialOffsetX = { -it / 4 }) + fadeIn())
.togetherWith(slideOutHorizontally(targetOffsetX = { it }))
},
predictivePopTransitionSpec = {
(slideInHorizontally(initialOffsetX = { -it / 4 }) + fadeIn())
.togetherWith(slideOutHorizontally(targetOffsetX = { it }))
},
entryProvider = entryProvider {
entry<Screen.Settings.Main> {
Column(modifier.nestedScroll(scrollBehavior.nestedScrollConnection)) {
TopAppBar(
title = {
Text(
stringResource(R.string.settings),
style = LocalTextStyle.current.copy(
fontFamily = robotoFlexTopBar,
fontSize = 32.sp,
lineHeight = 32.sp
)
)
},
subtitle = {},
colors = topBarColors,
titleHorizontalAlignment = Alignment.CenterHorizontally,
scrollBehavior = scrollBehavior
) )
LazyColumn(
verticalArrangement = Arrangement.spacedBy(2.dp),
modifier = Modifier
.background(topBarColors.containerColor)
.fillMaxSize()
.padding(horizontal = 16.dp)
) {
item { Spacer(Modifier.height(12.dp)) }
item { AboutCard() }
item { Spacer(Modifier.height(12.dp)) }
itemsIndexed(settingsScreens) { index, item ->
ClickableListItem(
leadingContent = {
Icon(painterResource(item.icon), null)
},
headlineContent = { Text(stringResource(item.label)) },
supportingContent = {
Text(
remember {
item.innerSettings.joinToString(", ") {
context.getString(it)
}
},
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
},
trailingContent = {
Icon(painterResource(R.drawable.arrow_forward_big), null)
},
items = settingsScreens.size,
index = index
) { backStack.add(item.route) }
}
item { Spacer(Modifier.height(12.dp)) }
}
}
}
entry<Screen.Settings.Alarm> {
AlarmSettings(
preferencesState = preferencesState,
alarmEnabled = alarmEnabled,
vibrateEnabled = vibrateEnabled,
alarmSound = alarmSound,
onAlarmEnabledChange = onAlarmEnabledChange,
onVibrateEnabledChange = onVibrateEnabledChange,
onAlarmSoundChanged = onAlarmSoundChanged,
onBack = backStack::removeLastOrNull
) )
}, }
subtitle = {}, entry<Screen.Settings.Appearance> {
colors = topBarColors, AppearanceSettings(
titleHorizontalAlignment = Alignment.CenterHorizontally, preferencesState = preferencesState,
scrollBehavior = scrollBehavior onBlackThemeChange = onBlackThemeChange,
) onThemeChange = onThemeChange,
onColorSchemeChange = onColorSchemeChange,
LazyColumn( onBack = backStack::removeLastOrNull
verticalArrangement = Arrangement.spacedBy(2.dp), )
modifier = Modifier }
.background(topBarColors.containerColor) entry<Screen.Settings.Timer> {
.fillMaxSize() TimerSettings(
.padding(horizontal = 16.dp) aodEnabled = preferencesState.aodEnabled,
) { focusTimeInputFieldState = focusTimeInputFieldState,
item { Spacer(Modifier.height(12.dp)) } shortBreakTimeInputFieldState = shortBreakTimeInputFieldState,
longBreakTimeInputFieldState = longBreakTimeInputFieldState,
item { AboutCard() } sessionsSliderState = sessionsSliderState,
onAodEnabledChange = onAodEnabledChange,
item { Spacer(Modifier.height(12.dp)) } onBack = backStack::removeLastOrNull
)
item {} }
item { Spacer(Modifier.height(12.dp)) }
} }
} )
} }
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)

View File

@@ -151,10 +151,10 @@ fun AlarmSettings(
Column(modifier.nestedScroll(scrollBehavior.nestedScrollConnection)) { Column(modifier.nestedScroll(scrollBehavior.nestedScrollConnection)) {
LargeFlexibleTopAppBar( LargeFlexibleTopAppBar(
title = { title = {
Text("Alarm", fontFamily = robotoFlexTopBar) Text(stringResource(R.string.alarm), fontFamily = robotoFlexTopBar)
}, },
subtitle = { subtitle = {
Text("Settings") Text(stringResource(R.string.settings))
}, },
navigationIcon = { navigationIcon = {
IconButton(onBack) { IconButton(onBack) {
@@ -241,12 +241,7 @@ fun AlarmSettings(
@Preview @Preview
@Composable @Composable
fun AlarmSettingsPreview() { fun AlarmSettingsPreview() {
val preferencesState = PreferencesState( val preferencesState = PreferencesState()
theme = "auto",
colorScheme = "White",
blackTheme = false,
aodEnabled = false
)
AlarmSettings( AlarmSettings(
preferencesState = preferencesState, preferencesState = preferencesState,
alarmEnabled = true, alarmEnabled = true,

View File

@@ -42,7 +42,6 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
@@ -70,8 +69,6 @@ fun AppearanceSettings(
onBack: () -> Unit, onBack: () -> Unit,
modifier: Modifier = Modifier modifier: Modifier = Modifier
) { ) {
val context = LocalContext.current
val themeMap: Map<String, Pair<Int, Int>> = remember { val themeMap: Map<String, Pair<Int, Int>> = remember {
mapOf( mapOf(
"auto" to Pair( "auto" to Pair(
@@ -82,23 +79,21 @@ fun AppearanceSettings(
"dark" to Pair(R.drawable.dark_mode, R.string.dark) "dark" to Pair(R.drawable.dark_mode, R.string.dark)
) )
} }
val reverseThemeMap: Map<String, String> = remember { val reverseThemeMap: Map<String, String> = mapOf(
mapOf( stringResource(R.string.system_default) to "auto",
context.getString(R.string.system_default) to "auto", stringResource(R.string.light) to "light",
context.getString(R.string.light) to "light", stringResource(R.string.dark) to "dark"
context.getString(R.string.dark) to "dark" )
)
}
val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior() val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior()
Column(modifier.nestedScroll(scrollBehavior.nestedScrollConnection)) { Column(modifier.nestedScroll(scrollBehavior.nestedScrollConnection)) {
LargeFlexibleTopAppBar( LargeFlexibleTopAppBar(
title = { title = {
Text("Appearance", fontFamily = robotoFlexTopBar) Text(stringResource(R.string.appearance), fontFamily = robotoFlexTopBar)
}, },
subtitle = { subtitle = {
Text("Settings") Text(stringResource(R.string.settings))
}, },
navigationIcon = { navigationIcon = {
IconButton(onBack) { IconButton(onBack) {

View File

@@ -93,10 +93,10 @@ fun TimerSettings(
Column(modifier.nestedScroll(scrollBehavior.nestedScrollConnection)) { Column(modifier.nestedScroll(scrollBehavior.nestedScrollConnection)) {
LargeFlexibleTopAppBar( LargeFlexibleTopAppBar(
title = { title = {
Text("Timer", fontFamily = robotoFlexTopBar) Text(stringResource(R.string.timer), fontFamily = robotoFlexTopBar)
}, },
subtitle = { subtitle = {
Text("Settings") Text(stringResource(R.string.settings))
}, },
navigationIcon = { navigationIcon = {
IconButton(onBack) { IconButton(onBack) {

View File

@@ -0,0 +1,26 @@
<!--
~ 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 <https://www.gnu.org/licenses/>.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:fillColor="#e3e3e3"
android:pathData="m321,880 l-71,-71 329,-329 -329,-329 71,-71 400,400L321,880Z" />
</vector>

View File

@@ -1,3 +1,20 @@
<!--
~ 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 <https://www.gnu.org/licenses/>.
-->
<resources> <resources>
<string name="alarm">Alarm</string> <string name="alarm">Alarm</string>
<string name="alarm_desc">Ring alarm when a timer completes</string> <string name="alarm_desc">Ring alarm when a timer completes</string>
@@ -59,4 +76,6 @@
<string name="vibrate">Vibrate</string> <string name="vibrate">Vibrate</string>
<string name="vibrate_desc">Vibrate when a timer completes</string> <string name="vibrate_desc">Vibrate when a timer completes</string>
<string name="weekly_productivity_analysis">Weekly productivity analysis</string> <string name="weekly_productivity_analysis">Weekly productivity analysis</string>
<string name="appearance">Appearance</string>
<string name="durations">Durations</string>
</resources> </resources>