feat(ui): add about screen list item in settings, remove card

Closes: #160
This commit is contained in:
Nishant Mishra
2025-12-01 10:51:07 +05:30
parent 6c32743d22
commit 9efc4f6467
9 changed files with 94 additions and 184 deletions

View File

@@ -45,18 +45,18 @@ val settingsScreens = listOf(
Screen.Settings.Timer, Screen.Settings.Timer,
R.drawable.timer_filled, R.drawable.timer_filled,
R.string.timer, R.string.timer,
listOf(R.string.durations, R.string.session_length, R.string.always_on_display) listOf(R.string.durations, R.string.dnd, R.string.always_on_display)
), ),
SettingsNavItem( SettingsNavItem(
Screen.Settings.Alarm, Screen.Settings.Alarm,
R.drawable.alarm, R.drawable.alarm,
R.string.alarm, R.string.alarm,
listOf(R.string.alarm_sound, R.string.alarm, R.string.vibrate) listOf(R.string.alarm_sound, R.string.sound, R.string.vibrate)
), ),
SettingsNavItem( SettingsNavItem(
Screen.Settings.Appearance, Screen.Settings.Appearance,
R.drawable.palette, R.drawable.palette,
R.string.appearance, R.string.appearance,
listOf(R.string.color_scheme, R.string.theme, R.string.black_theme) listOf(R.string.theme, R.string.color_scheme, R.string.black_theme)
) )
) )

View File

@@ -34,6 +34,9 @@ sealed class Screen : NavKey {
@Serializable @Serializable
object Main : Settings() object Main : Settings()
@Serializable
object About : Settings()
@Serializable @Serializable
object Alarm : Settings() object Alarm : Settings()

View File

@@ -65,13 +65,14 @@ 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.entryProvider
import androidx.navigation3.ui.NavDisplay import androidx.navigation3.ui.NavDisplay
import org.nsh07.pomodoro.BuildConfig
import org.nsh07.pomodoro.R import org.nsh07.pomodoro.R
import org.nsh07.pomodoro.ui.Screen import org.nsh07.pomodoro.ui.Screen
import org.nsh07.pomodoro.ui.mergePaddingValues import org.nsh07.pomodoro.ui.mergePaddingValues
import org.nsh07.pomodoro.ui.settingsScreen.components.AboutCard
import org.nsh07.pomodoro.ui.settingsScreen.components.ClickableListItem import org.nsh07.pomodoro.ui.settingsScreen.components.ClickableListItem
import org.nsh07.pomodoro.ui.settingsScreen.components.LocaleBottomSheet import org.nsh07.pomodoro.ui.settingsScreen.components.LocaleBottomSheet
import org.nsh07.pomodoro.ui.settingsScreen.components.PlusPromo import org.nsh07.pomodoro.ui.settingsScreen.components.PlusPromo
import org.nsh07.pomodoro.ui.settingsScreen.screens.AboutScreen
import org.nsh07.pomodoro.ui.settingsScreen.screens.AlarmSettings import org.nsh07.pomodoro.ui.settingsScreen.screens.AlarmSettings
import org.nsh07.pomodoro.ui.settingsScreen.screens.AppearanceSettings import org.nsh07.pomodoro.ui.settingsScreen.screens.AppearanceSettings
import org.nsh07.pomodoro.ui.settingsScreen.screens.TimerSettings import org.nsh07.pomodoro.ui.settingsScreen.screens.TimerSettings
@@ -216,22 +217,33 @@ private fun SettingsScreen(
.fillMaxSize() .fillMaxSize()
.padding(horizontal = 16.dp) .padding(horizontal = 16.dp)
) { ) {
item { Spacer(Modifier.height(12.dp)) } item { Spacer(Modifier.height(14.dp)) }
if (!isPlus) item { item {
PlusPromo(isPlus, setShowPaywall) PlusPromo(isPlus, setShowPaywall)
Spacer(Modifier.height(14.dp))
} }
item { AboutCard(isPlus) } item {
ClickableListItem(
leadingContent = {
Icon(painterResource(R.drawable.info), null)
},
headlineContent = {
Text(stringResource(R.string.about))
},
supportingContent = {
Text(stringResource(R.string.app_name) + " ${BuildConfig.VERSION_NAME}")
},
trailingContent = {
Icon(painterResource(R.drawable.arrow_forward_big), null)
},
items = 2,
index = 1
) { backStack.add(Screen.Settings.About) }
}
item { Spacer(Modifier.height(12.dp)) } item { Spacer(Modifier.height(12.dp)) }
if (isPlus) item {
PlusPromo(isPlus, setShowPaywall)
Spacer(Modifier.height(14.dp))
}
itemsIndexed(settingsScreens) { index, item -> itemsIndexed(settingsScreens) { index, item ->
ClickableListItem( ClickableListItem(
leadingContent = { leadingContent = {
@@ -286,6 +298,14 @@ private fun SettingsScreen(
} }
} }
entry<Screen.Settings.About> {
AboutScreen(
contentPadding = contentPadding,
isPlus = isPlus,
onBack = backStack::removeLastOrNull
)
}
entry<Screen.Settings.Alarm> { entry<Screen.Settings.Alarm> {
AlarmSettings( AlarmSettings(
settingsState = settingsState, settingsState = settingsState,

View File

@@ -1,123 +0,0 @@
/*
* 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.settingsScreen.components
import android.widget.Toast
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.IconButtonDefaults
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.MaterialTheme.colorScheme
import androidx.compose.material3.MaterialTheme.shapes
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.res.painterResource
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.robotoFlexTopBar
// Taken from https://github.com/shub39/Grit/blob/master/app/src/main/java/com/shub39/grit/core/presentation/settings/ui/component/AboutApp.kt
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun AboutCard(
isPlus: Boolean,
modifier: Modifier = Modifier
) {
val uriHandler = LocalUriHandler.current
val context = LocalContext.current
Card(
modifier = modifier.fillMaxWidth(),
colors = CardDefaults.cardColors(
containerColor = colorScheme.primaryContainer,
contentColor = colorScheme.onPrimaryContainer
),
shape = shapes.extraLarge
) {
Row(
modifier = Modifier
.padding(16.dp)
.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
Column {
Text(
if (!isPlus) stringResource(R.string.app_name)
else stringResource(R.string.app_name_plus),
style = MaterialTheme.typography.titleLarge,
fontFamily = robotoFlexTopBar
)
Text(text = "${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE})")
}
Spacer(modifier = Modifier.weight(1f))
Row {
IconButton(
onClick = {
Toast.makeText(context, "Coming soon...", Toast.LENGTH_SHORT).show()
},
shapes = IconButtonDefaults.shapes()
) {
Icon(
painterResource(R.drawable.discord),
contentDescription = "Discord",
modifier = Modifier.size(24.dp)
)
}
IconButton(
onClick = { uriHandler.openUri("https://github.com/nsh07/Tomato") },
shapes = IconButtonDefaults.shapes()
) {
Icon(
painterResource(R.drawable.github),
contentDescription = "GitHub",
modifier = Modifier.size(24.dp)
)
}
}
}
FlowRow(
modifier = Modifier.padding(start = 16.dp, end = 16.dp, bottom = 16.dp),
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
// TopButton(buttonColors)
// BottomButton(buttonColors)
}
}
}

View File

@@ -32,7 +32,9 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import org.nsh07.pomodoro.R
@OptIn(ExperimentalMaterial3ExpressiveApi::class) @OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable @Composable
@@ -49,7 +51,7 @@ fun PlusDivider(
.background(colorScheme.surfaceContainer) .background(colorScheme.surfaceContainer)
.padding(horizontal = 8.dp) .padding(horizontal = 8.dp)
) { ) {
Text("Customize further with Tomato+", style = typography.titleSmall) Text(stringResource(R.string.tomato_plus_desc), style = typography.titleSmall)
} }
} }
} }

View File

@@ -17,27 +17,18 @@
package org.nsh07.pomodoro.ui.settingsScreen.components package org.nsh07.pomodoro.ui.settingsScreen.components
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.ListItemDefaults
import androidx.compose.material3.MaterialTheme.colorScheme import androidx.compose.material3.MaterialTheme.colorScheme
import androidx.compose.material3.MaterialTheme.typography
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
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.unit.dp import androidx.compose.ui.unit.dp
import org.nsh07.pomodoro.R import org.nsh07.pomodoro.R
import org.nsh07.pomodoro.ui.theme.AppFonts.robotoFlexTopBar import org.nsh07.pomodoro.ui.theme.CustomColors.listItemColors
@Composable @Composable
fun PlusPromo( fun PlusPromo(
@@ -45,38 +36,38 @@ fun PlusPromo(
setShowPaywall: (Boolean) -> Unit, setShowPaywall: (Boolean) -> Unit,
modifier: Modifier = Modifier modifier: Modifier = Modifier
) { ) {
val container = if (isPlus) colorScheme.surfaceBright else colorScheme.primary ClickableListItem(
val onContainer = if (isPlus) colorScheme.onSurface else colorScheme.onPrimary leadingContent = {
val onContainerVariant = if (isPlus) colorScheme.onSurfaceVariant else colorScheme.onPrimary Icon(
painterResource(R.drawable.tomato_logo_notification),
Row( null,
verticalAlignment = Alignment.CenterVertically, modifier = Modifier.size(24.dp)
)
},
headlineContent = {
Text(
if (!isPlus) stringResource(R.string.get_plus)
else stringResource(R.string.app_name_plus)
)
},
supportingContent = {
if (!isPlus) Text(stringResource(R.string.tomato_plus_desc))
},
trailingContent = {
Icon(
painterResource(R.drawable.arrow_forward_big),
null
)
},
colors = if (isPlus) listItemColors else ListItemDefaults.colors(
containerColor = colorScheme.primary,
leadingIconColor = colorScheme.onPrimary,
trailingIconColor = colorScheme.onPrimary,
supportingColor = colorScheme.onPrimary,
headlineColor = colorScheme.onPrimary
),
items = 2,
index = 0,
modifier = modifier modifier = modifier
.clip(CircleShape) ) { setShowPaywall(true) }
.clickable { setShowPaywall(true) }
.background(container)
.padding(16.dp)
) {
Icon(
painterResource(R.drawable.tomato_logo_notification),
null,
tint = onContainerVariant,
modifier = Modifier
.size(24.dp)
)
Spacer(Modifier.width(8.dp))
Text(
if (!isPlus) stringResource(R.string.get_plus)
else stringResource(R.string.app_name_plus),
style = typography.titleLarge,
fontFamily = robotoFlexTopBar,
color = onContainer
)
Spacer(Modifier.weight(1f))
Icon(
painterResource(R.drawable.arrow_forward_big),
null,
tint = onContainerVariant
)
}
} }

View File

@@ -80,7 +80,7 @@ fun AboutScreen(
onBack: () -> Unit, onBack: () -> Unit,
modifier: Modifier = Modifier modifier: Modifier = Modifier
) { ) {
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior() val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior()
val context = LocalContext.current val context = LocalContext.current
val uriHandler = LocalUriHandler.current val uriHandler = LocalUriHandler.current

View File

@@ -1,10 +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" <vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp" android:width="24dp"
android:height="24dp" android:height="24dp"
android:tint="#000000"
android:viewportWidth="960" android:viewportWidth="960"
android:viewportHeight="960"> android:viewportHeight="960">
<path <path
android:fillColor="@android:color/white" android:fillColor="#e3e3e3"
android:pathData="M480,680q17,0 28.5,-11.5T520,640v-160q0,-17 -11.5,-28.5T480,440q-17,0 -28.5,11.5T440,480v160q0,17 11.5,28.5T480,680ZM480,360q17,0 28.5,-11.5T520,320q0,-17 -11.5,-28.5T480,280q-17,0 -28.5,11.5T440,320q0,17 11.5,28.5T480,360ZM480,880q-83,0 -156,-31.5T197,763q-54,-54 -85.5,-127T80,480q0,-83 31.5,-156T197,197q54,-54 127,-85.5T480,80q83,0 156,31.5T763,197q54,54 85.5,127T880,480q0,83 -31.5,156T763,763q-54,54 -127,85.5T480,880Z" /> android:pathData="M480,680q17,0 28.5,-11.5T520,640v-160q0,-17 -11.5,-28.5T480,440q-17,0 -28.5,11.5T440,480v160q0,17 11.5,28.5T480,680ZM480,360q17,0 28.5,-11.5T520,320q0,-17 -11.5,-28.5T480,280q-17,0 -28.5,11.5T440,320q0,17 11.5,28.5T480,360ZM480,880q-83,0 -156,-31.5T197,763q-54,-54 -85.5,-127T80,480q0,-83 31.5,-156T197,197q54,-54 127,-85.5T480,80q83,0 156,31.5T763,197q54,54 85.5,127T880,480q0,83 -31.5,156T763,763q-54,54 -127,85.5T480,880Z" />
</vector> </vector>

View File

@@ -101,4 +101,5 @@
<string name="help_with_translation_desc">Translate Tomato into your language</string> <string name="help_with_translation_desc">Translate Tomato into your language</string>
<string name="rate_on_google_play_desc">Liked the app? Write a review!</string> <string name="rate_on_google_play_desc">Liked the app? Write a review!</string>
<string name="bmc_desc">Support me with a small donation</string> <string name="bmc_desc">Support me with a small donation</string>
<string name="tomato_plus_desc">Customize further with Tomato+</string>
</resources> </resources>