Add ability to edit timer durations

Changes are not yet applied to the preferences
This commit is contained in:
Nishant Mishra
2025-07-05 21:00:59 +05:30
parent 998a16ab4e
commit 67b1fa2ef9
3 changed files with 100 additions and 39 deletions

View File

@@ -153,6 +153,9 @@ fun AppScreen(
25 * 60 * 1000, 25 * 60 * 1000,
5 * 60 * 1000, 5 * 60 * 1000,
15 * 60 * 1000, 15 * 60 * 1000,
{},
{},
{},
modifier = modifier.padding( modifier = modifier.padding(
start = contentPadding.calculateStartPadding(layoutDirection), start = contentPadding.calculateStartPadding(layoutDirection),
end = contentPadding.calculateEndPadding(layoutDirection), end = contentPadding.calculateEndPadding(layoutDirection),

View File

@@ -0,0 +1,13 @@
package org.nsh07.pomodoro.ui.settingsScreen
import androidx.compose.foundation.text.input.InputTransformation
import androidx.compose.foundation.text.input.TextFieldBuffer
import androidx.core.text.isDigitsOnly
object MinutesInputTransformation : InputTransformation {
override fun TextFieldBuffer.transformInput() {
if (!this.asCharSequence().isDigitsOnly() || this.length > 2) {
revertAllChanges()
}
}
}

View File

@@ -1,5 +1,6 @@
package org.nsh07.pomodoro.ui.settingsScreen package org.nsh07.pomodoro.ui.settingsScreen
import androidx.compose.animation.animateColorAsState
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.horizontalScroll import androidx.compose.foundation.horizontalScroll
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
@@ -15,22 +16,27 @@ import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.BasicTextField
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.text.input.TextFieldLineLimits
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.LocalTextStyle import androidx.compose.material3.LocalTextStyle
import androidx.compose.material3.MaterialTheme.colorScheme import androidx.compose.material3.MaterialTheme.colorScheme
import androidx.compose.material3.MaterialTheme.motionScheme
import androidx.compose.material3.MaterialTheme.typography import androidx.compose.material3.MaterialTheme.typography
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
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.graphics.SolidColor
import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
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
@@ -46,9 +52,23 @@ fun SettingsScreen(
focusTime: Int, focusTime: Int,
shortBreakTime: Int, shortBreakTime: Int,
longBreakTime: Int, longBreakTime: Int,
updateFocusTime: (Int) -> Unit,
updateShortBreakTime: (Int) -> Unit,
updateLongBreakTime: (Int) -> Unit,
modifier: Modifier = Modifier modifier: Modifier = Modifier
) { ) {
val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior() val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior()
val focusTimeInputFieldState = rememberTextFieldState(
(focusTime / 60000).toString().padStart(2, '0')
)
val shortBreakTimeInputFieldState = rememberTextFieldState(
(shortBreakTime / 60000).toString().padStart(2, '0')
)
val longBreakTimeInputFieldState = rememberTextFieldState(
(longBreakTime / 60000).toString().padStart(2, '0')
)
Column(modifier.nestedScroll(scrollBehavior.nestedScrollConnection)) { Column(modifier.nestedScroll(scrollBehavior.nestedScrollConnection)) {
TopAppBar( TopAppBar(
title = { title = {
@@ -92,7 +112,14 @@ fun SettingsScreen(
Box( Box(
contentAlignment = Alignment.Center, contentAlignment = Alignment.Center,
modifier = Modifier modifier = Modifier
.clip( .size(112.dp, 100.dp)
.background(
animateColorAsState(
if (focusTimeInputFieldState.text.isNotEmpty())
colorScheme.surfaceContainer
else colorScheme.errorContainer,
motionScheme.defaultEffectsSpec()
).value,
RoundedCornerShape( RoundedCornerShape(
topStart = 16.dp, topStart = 16.dp,
bottomStart = 16.dp, bottomStart = 16.dp,
@@ -100,20 +127,21 @@ fun SettingsScreen(
bottomEnd = 4.dp bottomEnd = 4.dp
) )
) )
.size(112.dp, 100.dp)
.background(colorScheme.surfaceContainer)
) { ) {
Text( BasicTextField(
text = remember(focusTime) { (focusTime / 60000).toString() }, state = focusTimeInputFieldState,
style = TextStyle( lineLimits = TextFieldLineLimits.SingleLine,
inputTransformation = MinutesInputTransformation,
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.NumberPassword),
textStyle = TextStyle(
fontFamily = openRundeClock, fontFamily = openRundeClock,
fontWeight = FontWeight.Bold, fontWeight = FontWeight.Bold,
fontSize = 57.sp, fontSize = 57.sp,
letterSpacing = (-2).sp letterSpacing = (-2).sp,
color = colorScheme.onSurfaceVariant,
textAlign = TextAlign.Center
), ),
textAlign = TextAlign.Center, cursorBrush = SolidColor(colorScheme.onSurface)
maxLines = 1,
color = colorScheme.onSurfaceVariant
) )
} }
Text( Text(
@@ -128,23 +156,31 @@ fun SettingsScreen(
Box( Box(
contentAlignment = Alignment.Center, contentAlignment = Alignment.Center,
modifier = Modifier modifier = Modifier
.clip(RoundedCornerShape(4.dp))
.size(112.dp, 100.dp) .size(112.dp, 100.dp)
.background(colorScheme.surfaceContainer) .background(
animateColorAsState(
if (shortBreakTimeInputFieldState.text.isNotEmpty())
colorScheme.surfaceContainer
else colorScheme.errorContainer,
motionScheme.defaultEffectsSpec()
).value,
RoundedCornerShape(4.dp)
)
) { ) {
Text( BasicTextField(
text = remember(shortBreakTime) { state = shortBreakTimeInputFieldState,
(shortBreakTime / 60000).toString().padStart(2, '0') lineLimits = TextFieldLineLimits.SingleLine,
}, inputTransformation = MinutesInputTransformation,
style = TextStyle( keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.NumberPassword),
textStyle = TextStyle(
fontFamily = openRundeClock, fontFamily = openRundeClock,
fontWeight = FontWeight.Bold, fontWeight = FontWeight.Bold,
fontSize = 57.sp, fontSize = 57.sp,
letterSpacing = (-2).sp letterSpacing = (-2).sp,
color = colorScheme.onSurfaceVariant,
textAlign = TextAlign.Center
), ),
textAlign = TextAlign.Center, cursorBrush = SolidColor(colorScheme.onSurface)
maxLines = 1,
color = colorScheme.onSurfaceVariant
) )
} }
Text( Text(
@@ -159,30 +195,36 @@ fun SettingsScreen(
Box( Box(
contentAlignment = Alignment.Center, contentAlignment = Alignment.Center,
modifier = Modifier modifier = Modifier
.clip( .size(112.dp, 100.dp)
RoundedCornerShape( .background(
animateColorAsState(
if (longBreakTimeInputFieldState.text.isNotEmpty())
colorScheme.surfaceContainer
else colorScheme.errorContainer,
motionScheme.defaultEffectsSpec()
).value,
RoundedCornerShape(
topStart = 4.dp, topStart = 4.dp,
bottomStart = 4.dp, bottomStart = 4.dp,
topEnd = 16.dp, topEnd = 16.dp,
bottomEnd = 16.dp bottomEnd = 16.dp
) )
) )
.size(112.dp, 100.dp)
.background(colorScheme.surfaceContainer)
) { ) {
Text( BasicTextField(
text = remember(shortBreakTime) { state = longBreakTimeInputFieldState,
(longBreakTime / 60000).toString().padStart(2, '0') lineLimits = TextFieldLineLimits.SingleLine,
}, inputTransformation = MinutesInputTransformation,
style = TextStyle( keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.NumberPassword),
textStyle = TextStyle(
fontFamily = openRundeClock, fontFamily = openRundeClock,
fontWeight = FontWeight.Bold, fontWeight = FontWeight.Bold,
fontSize = 57.sp, fontSize = 57.sp,
letterSpacing = (-2).sp letterSpacing = (-2).sp,
color = colorScheme.onSurfaceVariant,
textAlign = TextAlign.Center
), ),
textAlign = TextAlign.Center, cursorBrush = SolidColor(colorScheme.onSurface)
maxLines = 1,
color = colorScheme.onSurfaceVariant
) )
} }
Text( Text(
@@ -206,9 +248,12 @@ fun SettingsScreen(
fun SettingsScreenPreview() { fun SettingsScreenPreview() {
TomatoTheme { TomatoTheme {
SettingsScreen( SettingsScreen(
focusTime = 88 * 60 * 1000, focusTime = 25 * 60 * 1000,
shortBreakTime = 88 * 60 * 1000, shortBreakTime = 5 * 60 * 1000,
longBreakTime = 88 * 60 * 1000, longBreakTime = 15 * 60 * 1000,
updateFocusTime = {},
updateShortBreakTime = {},
updateLongBreakTime = {},
modifier = Modifier.fillMaxSize() modifier = Modifier.fillMaxSize()
) )
} }