From 9ec3e6851f246760ef62e22a907886aec2d41e2f Mon Sep 17 00:00:00 2001 From: Nishant Mishra Date: Sun, 9 Nov 2025 22:08:47 +0530 Subject: [PATCH 1/2] feat(settings): disable editing time when service is running, auto reload when navigating to timer screen --- .../nsh07/pomodoro/data/TimerRepository.kt | 5 ++- .../nsh07/pomodoro/service/TimerService.kt | 4 +- .../ui/settingsScreen/SettingsScreen.kt | 4 ++ .../ui/settingsScreen/SettingsSwitchItem.kt | 1 + .../components/MinuteInputField.kt | 4 +- .../settingsScreen/screens/TimerSettings.kt | 39 +++++++++++++++++-- .../viewModel/SettingsViewModel.kt | 5 ++- .../timerScreen/viewModel/TimerViewModel.kt | 2 +- 8 files changed, 52 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/org/nsh07/pomodoro/data/TimerRepository.kt b/app/src/main/java/org/nsh07/pomodoro/data/TimerRepository.kt index d7aea1a..89f27af 100644 --- a/app/src/main/java/org/nsh07/pomodoro/data/TimerRepository.kt +++ b/app/src/main/java/org/nsh07/pomodoro/data/TimerRepository.kt @@ -21,6 +21,7 @@ import android.net.Uri import android.provider.Settings import androidx.compose.material3.ColorScheme import androidx.compose.material3.lightColorScheme +import kotlinx.coroutines.flow.MutableStateFlow /** * Interface that holds the timer durations for each timer type. This repository maintains a single @@ -43,7 +44,7 @@ interface TimerRepository { var alarmSoundUri: Uri? - var serviceRunning: Boolean + var serviceRunning: MutableStateFlow } /** @@ -61,5 +62,5 @@ class AppTimerRepository : TimerRepository { override var colorScheme = lightColorScheme() override var alarmSoundUri: Uri? = Settings.System.DEFAULT_ALARM_ALERT_URI ?: Settings.System.DEFAULT_RINGTONE_URI - override var serviceRunning = false + override var serviceRunning = MutableStateFlow(false) } \ No newline at end of file diff --git a/app/src/main/java/org/nsh07/pomodoro/service/TimerService.kt b/app/src/main/java/org/nsh07/pomodoro/service/TimerService.kt index 01552a2..e87e2a7 100644 --- a/app/src/main/java/org/nsh07/pomodoro/service/TimerService.kt +++ b/app/src/main/java/org/nsh07/pomodoro/service/TimerService.kt @@ -98,12 +98,12 @@ class TimerService : Service() { override fun onCreate() { super.onCreate() - timerRepository.serviceRunning = true + timerRepository.serviceRunning.update { true } alarm = initializeMediaPlayer() } override fun onDestroy() { - timerRepository.serviceRunning = false + timerRepository.serviceRunning.update { false } runBlocking { job.cancel() saveTimeToDb() 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 f7c2c44..559142e 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 @@ -101,6 +101,7 @@ fun SettingsScreenRoot( val longBreakTimeInputFieldState = viewModel.longBreakTimeTextFieldState val isPlus by viewModel.isPlus.collectAsStateWithLifecycle() + val serviceRunning by viewModel.serviceRunning.collectAsStateWithLifecycle() val settingsState by viewModel.settingsState.collectAsStateWithLifecycle() @@ -115,6 +116,7 @@ fun SettingsScreenRoot( SettingsScreen( isPlus = isPlus, + serviceRunning = serviceRunning, settingsState = settingsState, backStack = backStack, focusTimeInputFieldState = focusTimeInputFieldState, @@ -132,6 +134,7 @@ fun SettingsScreenRoot( @Composable private fun SettingsScreen( isPlus: Boolean, + serviceRunning: Boolean, settingsState: SettingsState, backStack: SnapshotStateList, focusTimeInputFieldState: TextFieldState, @@ -292,6 +295,7 @@ private fun SettingsScreen( entry { TimerSettings( isPlus = isPlus, + serviceRunning = serviceRunning, settingsState = settingsState, focusTimeInputFieldState = focusTimeInputFieldState, shortBreakTimeInputFieldState = shortBreakTimeInputFieldState, diff --git a/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/SettingsSwitchItem.kt b/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/SettingsSwitchItem.kt index 75638e3..f16c2f4 100644 --- a/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/SettingsSwitchItem.kt +++ b/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/SettingsSwitchItem.kt @@ -22,6 +22,7 @@ import androidx.annotation.StringRes data class SettingsSwitchItem( val checked: Boolean, + val enabled: Boolean = true, @param:DrawableRes val icon: Int, @param:StringRes val label: Int, @param:StringRes val description: Int, diff --git a/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/components/MinuteInputField.kt b/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/components/MinuteInputField.kt index f5f0c23..f530eea 100644 --- a/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/components/MinuteInputField.kt +++ b/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/components/MinuteInputField.kt @@ -46,12 +46,14 @@ import org.nsh07.pomodoro.ui.theme.CustomColors.listItemColors @Composable fun MinuteInputField( state: TextFieldState, + enabled: Boolean, shape: Shape, modifier: Modifier = Modifier, imeAction: ImeAction = ImeAction.Next ) { BasicTextField( state = state, + enabled = enabled, lineLimits = TextFieldLineLimits.SingleLine, inputTransformation = MinutesInputTransformation, // outputTransformation = MinutesOutputTransformation, @@ -63,7 +65,7 @@ fun MinuteInputField( fontFamily = interClock, fontSize = 57.sp, letterSpacing = (-2).sp, - color = colorScheme.onSurfaceVariant, + color = if (enabled) colorScheme.onSurfaceVariant else colorScheme.outlineVariant, textAlign = TextAlign.Center ), cursorBrush = SolidColor(colorScheme.onSurface), diff --git a/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/screens/TimerSettings.kt b/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/screens/TimerSettings.kt index a7cb380..0d28931 100644 --- a/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/screens/TimerSettings.kt +++ b/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/screens/TimerSettings.kt @@ -50,6 +50,7 @@ import androidx.compose.material3.IconButton import androidx.compose.material3.IconButtonDefaults import androidx.compose.material3.LargeFlexibleTopAppBar import androidx.compose.material3.ListItem +import androidx.compose.material3.LocalContentColor import androidx.compose.material3.MaterialTheme.colorScheme import androidx.compose.material3.MaterialTheme.typography import androidx.compose.material3.Slider @@ -60,7 +61,8 @@ import androidx.compose.material3.Text import androidx.compose.material3.TopAppBarDefaults import androidx.compose.material3.rememberSliderState import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -76,6 +78,7 @@ 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.service.TimerService import org.nsh07.pomodoro.ui.settingsScreen.SettingsSwitchItem import org.nsh07.pomodoro.ui.settingsScreen.components.MinuteInputField import org.nsh07.pomodoro.ui.settingsScreen.components.PlusDivider @@ -95,6 +98,7 @@ import org.nsh07.pomodoro.ui.theme.TomatoShapeDefaults.topListItemShape @Composable fun TimerSettings( isPlus: Boolean, + serviceRunning: Boolean, settingsState: SettingsState, focusTimeInputFieldState: TextFieldState, shortBreakTimeInputFieldState: TextFieldState, @@ -111,14 +115,21 @@ fun TimerSettings( val notificationManagerService = remember { context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager } - LaunchedEffect(Unit) { - if (!notificationManagerService.isNotificationPolicyAccessGranted()) - onAction(SettingsAction.SaveDndEnabled(false)) + DisposableEffect(Unit) { + onDispose { + if (!serviceRunning) { + Intent(context, TimerService::class.java).also { + it.action = TimerService.Actions.RESET.toString() + context.startService(it) + } + } + } } val switchItems = listOf( SettingsSwitchItem( checked = settingsState.dndEnabled, + enabled = !serviceRunning, icon = R.drawable.dnd, label = R.string.dnd, description = R.string.dnd_desc, @@ -171,6 +182,20 @@ fun TimerSettings( .padding(horizontal = 16.dp) ) { item { + CompositionLocalProvider(LocalContentColor provides colorScheme.error) { + AnimatedVisibility(serviceRunning) { + Column { + Spacer(Modifier.height(8.dp)) + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(8.dp) + ) { + Icon(painterResource(R.drawable.info), null) + Text("Reset the timer to change settings") + } + } + } + } Spacer(Modifier.height(14.dp)) } item { @@ -190,6 +215,7 @@ fun TimerSettings( ) MinuteInputField( state = focusTimeInputFieldState, + enabled = !serviceRunning, shape = RoundedCornerShape( topStart = topListItemShape.topStart, bottomStart = topListItemShape.topStart, @@ -210,6 +236,7 @@ fun TimerSettings( ) MinuteInputField( state = shortBreakTimeInputFieldState, + enabled = !serviceRunning, shape = RoundedCornerShape(middleListItemShape.topStart), imeAction = ImeAction.Next ) @@ -225,6 +252,7 @@ fun TimerSettings( ) MinuteInputField( state = longBreakTimeInputFieldState, + enabled = !serviceRunning, shape = RoundedCornerShape( topStart = bottomListItemShape.topStart, bottomStart = bottomListItemShape.topStart, @@ -257,6 +285,7 @@ fun TimerSettings( ) Slider( state = sessionsSliderState, + enabled = !serviceRunning, modifier = Modifier.padding(vertical = 4.dp) ) } @@ -281,6 +310,7 @@ fun TimerSettings( trailingContent = { Switch( checked = item.checked, + enabled = item.enabled, onCheckedChange = { item.onClick(it) }, thumbContent = { if (item.checked) { @@ -405,6 +435,7 @@ private fun TimerSettingsPreview() { ) TimerSettings( isPlus = false, + serviceRunning = true, settingsState = remember { SettingsState() }, focusTimeInputFieldState = focusTimeInputFieldState, shortBreakTimeInputFieldState = shortBreakTimeInputFieldState, 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 d412bdd..a61146f 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 @@ -54,6 +54,7 @@ class SettingsViewModel( val backStack = mutableStateListOf(Screen.Settings.Main) val isPlus = billingManager.isPlus + val serviceRunning = timerRepository.serviceRunning.asStateFlow() private val _settingsState = MutableStateFlow(SettingsState()) val settingsState = _settingsState.asStateFlow() @@ -273,14 +274,14 @@ class SettingsViewModel( val Factory: ViewModelProvider.Factory = viewModelFactory { initializer { val application = (this[APPLICATION_KEY] as TomatoApplication) + val appBillingManager = application.container.billingManager val appPreferenceRepository = application.container.appPreferenceRepository val appTimerRepository = application.container.appTimerRepository - val appBillingManager = application.container.billingManager SettingsViewModel( billingManager = appBillingManager, preferenceRepository = appPreferenceRepository, - timerRepository = appTimerRepository, + timerRepository = appTimerRepository ) } } diff --git a/app/src/main/java/org/nsh07/pomodoro/ui/timerScreen/viewModel/TimerViewModel.kt b/app/src/main/java/org/nsh07/pomodoro/ui/timerScreen/viewModel/TimerViewModel.kt index 84c6ed4..6fefa40 100644 --- a/app/src/main/java/org/nsh07/pomodoro/ui/timerScreen/viewModel/TimerViewModel.kt +++ b/app/src/main/java/org/nsh07/pomodoro/ui/timerScreen/viewModel/TimerViewModel.kt @@ -70,7 +70,7 @@ class TimerViewModel( private var pauseDuration = 0L init { - if (!timerRepository.serviceRunning) + if (!timerRepository.serviceRunning.value) viewModelScope.launch(Dispatchers.IO) { timerRepository.focusTime = preferenceRepository.getIntPreference("focus_time")?.toLong() From 5cb864f084d9c1f3dce4e940eab1298325e2d527 Mon Sep 17 00:00:00 2001 From: Nishant Mishra Date: Sun, 9 Nov 2025 22:44:45 +0530 Subject: [PATCH 2/2] feat(settings): improve auto-reload behaviour --- .../org/nsh07/pomodoro/data/AppContainer.kt | 6 ++ .../nsh07/pomodoro/service/ServiceHelper.kt | 58 +++++++++++++++++++ .../java/org/nsh07/pomodoro/ui/AppScreen.kt | 30 +--------- .../settingsScreen/screens/TimerSettings.kt | 15 +---- .../viewModel/SettingsViewModel.kt | 39 ++++++++++++- .../timerScreen/viewModel/TimerViewModel.kt | 15 +++-- app/src/main/res/values/strings.xml | 1 + 7 files changed, 115 insertions(+), 49 deletions(-) create mode 100644 app/src/main/java/org/nsh07/pomodoro/service/ServiceHelper.kt diff --git a/app/src/main/java/org/nsh07/pomodoro/data/AppContainer.kt b/app/src/main/java/org/nsh07/pomodoro/data/AppContainer.kt index 3df1ce1..12186a6 100644 --- a/app/src/main/java/org/nsh07/pomodoro/data/AppContainer.kt +++ b/app/src/main/java/org/nsh07/pomodoro/data/AppContainer.kt @@ -29,6 +29,7 @@ import kotlinx.coroutines.flow.MutableStateFlow import org.nsh07.pomodoro.R import org.nsh07.pomodoro.billing.BillingManager import org.nsh07.pomodoro.billing.BillingManagerProvider +import org.nsh07.pomodoro.service.ServiceHelper import org.nsh07.pomodoro.service.addTimerActions import org.nsh07.pomodoro.ui.timerScreen.viewModel.TimerState import org.nsh07.pomodoro.utils.millisecondsToStr @@ -41,6 +42,7 @@ interface AppContainer { val notificationManager: NotificationManagerCompat val notificationManagerService: NotificationManager val notificationBuilder: NotificationCompat.Builder + val serviceHelper: ServiceHelper val timerState: MutableStateFlow val time: MutableStateFlow var activityTurnScreenOn: (Boolean) -> Unit @@ -87,6 +89,10 @@ class DefaultAppContainer(context: Context) : AppContainer { .setVisibility(VISIBILITY_PUBLIC) } + override val serviceHelper: ServiceHelper by lazy { + ServiceHelper(context) + } + override val timerState: MutableStateFlow by lazy { MutableStateFlow( TimerState( diff --git a/app/src/main/java/org/nsh07/pomodoro/service/ServiceHelper.kt b/app/src/main/java/org/nsh07/pomodoro/service/ServiceHelper.kt new file mode 100644 index 0000000..bb7bc89 --- /dev/null +++ b/app/src/main/java/org/nsh07/pomodoro/service/ServiceHelper.kt @@ -0,0 +1,58 @@ +/* + * 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.service + +import android.content.Context +import android.content.Intent +import org.nsh07.pomodoro.ui.timerScreen.viewModel.TimerAction + +/** + * Helper class that holds a reference to [Context] and helps call [Context.startService] in + * [androidx.lifecycle.ViewModel]s. This class must be managed by an [android.app.Application] class + * to scope it to the Activity's lifecycle and prevent leaks. + */ +class ServiceHelper(private val context: Context) { + fun startService(action: TimerAction) { + when (action) { + TimerAction.ResetTimer -> + Intent(context, TimerService::class.java).also { + it.action = TimerService.Actions.RESET.toString() + context.startService(it) + } + + is TimerAction.SkipTimer -> + Intent(context, TimerService::class.java).also { + it.action = TimerService.Actions.SKIP.toString() + context.startService(it) + } + + TimerAction.StopAlarm -> + Intent(context, TimerService::class.java).also { + it.action = + TimerService.Actions.STOP_ALARM.toString() + context.startService(it) + } + + TimerAction.ToggleTimer -> + Intent(context, TimerService::class.java).also { + it.action = TimerService.Actions.TOGGLE.toString() + context.startService(it) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/nsh07/pomodoro/ui/AppScreen.kt b/app/src/main/java/org/nsh07/pomodoro/ui/AppScreen.kt index e581922..a998da7 100644 --- a/app/src/main/java/org/nsh07/pomodoro/ui/AppScreen.kt +++ b/app/src/main/java/org/nsh07/pomodoro/ui/AppScreen.kt @@ -63,7 +63,6 @@ import org.nsh07.pomodoro.ui.settingsScreen.SettingsScreenRoot import org.nsh07.pomodoro.ui.statsScreen.StatsScreenRoot import org.nsh07.pomodoro.ui.timerScreen.AlarmDialog import org.nsh07.pomodoro.ui.timerScreen.TimerScreen -import org.nsh07.pomodoro.ui.timerScreen.viewModel.TimerAction import org.nsh07.pomodoro.ui.timerScreen.viewModel.TimerViewModel @OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class) @@ -163,34 +162,7 @@ fun AppScreen( timerState = uiState, isPlus = isPlus, progress = { progress }, - onAction = { action -> - when (action) { - TimerAction.ResetTimer -> - Intent(context, TimerService::class.java).also { - it.action = TimerService.Actions.RESET.toString() - context.startService(it) - } - - is TimerAction.SkipTimer -> - Intent(context, TimerService::class.java).also { - it.action = TimerService.Actions.SKIP.toString() - context.startService(it) - } - - TimerAction.StopAlarm -> - Intent(context, TimerService::class.java).also { - it.action = - TimerService.Actions.STOP_ALARM.toString() - context.startService(it) - } - - TimerAction.ToggleTimer -> - Intent(context, TimerService::class.java).also { - it.action = TimerService.Actions.TOGGLE.toString() - context.startService(it) - } - } - }, + onAction = timerViewModel::onAction, modifier = modifier .padding( start = contentPadding.calculateStartPadding(layoutDirection), diff --git a/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/screens/TimerSettings.kt b/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/screens/TimerSettings.kt index 0d28931..da31588 100644 --- a/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/screens/TimerSettings.kt +++ b/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/screens/TimerSettings.kt @@ -62,7 +62,6 @@ import androidx.compose.material3.TopAppBarDefaults import androidx.compose.material3.rememberSliderState import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider -import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -78,7 +77,6 @@ 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.service.TimerService import org.nsh07.pomodoro.ui.settingsScreen.SettingsSwitchItem import org.nsh07.pomodoro.ui.settingsScreen.components.MinuteInputField import org.nsh07.pomodoro.ui.settingsScreen.components.PlusDivider @@ -115,17 +113,6 @@ fun TimerSettings( val notificationManagerService = remember { context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager } - DisposableEffect(Unit) { - onDispose { - if (!serviceRunning) { - Intent(context, TimerService::class.java).also { - it.action = TimerService.Actions.RESET.toString() - context.startService(it) - } - } - } - } - val switchItems = listOf( SettingsSwitchItem( checked = settingsState.dndEnabled, @@ -191,7 +178,7 @@ fun TimerSettings( horizontalArrangement = Arrangement.spacedBy(8.dp) ) { Icon(painterResource(R.drawable.info), null) - Text("Reset the timer to change settings") + Text(stringResource(R.string.timer_settings_reset_info)) } } } 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 a61146f..896eb28 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 @@ -43,13 +43,21 @@ import org.nsh07.pomodoro.TomatoApplication import org.nsh07.pomodoro.billing.BillingManager import org.nsh07.pomodoro.data.AppPreferenceRepository import org.nsh07.pomodoro.data.TimerRepository +import org.nsh07.pomodoro.service.ServiceHelper import org.nsh07.pomodoro.ui.Screen +import org.nsh07.pomodoro.ui.timerScreen.viewModel.TimerAction +import org.nsh07.pomodoro.ui.timerScreen.viewModel.TimerMode +import org.nsh07.pomodoro.ui.timerScreen.viewModel.TimerState +import org.nsh07.pomodoro.utils.millisecondsToStr @OptIn(FlowPreview::class, ExperimentalMaterial3Api::class) class SettingsViewModel( private val billingManager: BillingManager, private val preferenceRepository: AppPreferenceRepository, + private val serviceHelper: ServiceHelper, + private val time: MutableStateFlow, private val timerRepository: TimerRepository, + private val timerState: MutableStateFlow ) : ViewModel() { val backStack = mutableStateListOf(Screen.Settings.Main) @@ -107,6 +115,7 @@ class SettingsViewModel( "session_length", sessionsSliderState.value.toInt() ) + refreshTimer() } } @@ -117,6 +126,7 @@ class SettingsViewModel( .collect { if (it.isNotEmpty()) { timerRepository.focusTime = it.toString().toLong() * 60 * 1000 + refreshTimer() preferenceRepository.saveIntPreference( "focus_time", timerRepository.focusTime.toInt() @@ -130,6 +140,7 @@ class SettingsViewModel( .collect { if (it.isNotEmpty()) { timerRepository.shortBreakTime = it.toString().toLong() * 60 * 1000 + refreshTimer() preferenceRepository.saveIntPreference( "short_break_time", timerRepository.shortBreakTime.toInt() @@ -143,6 +154,7 @@ class SettingsViewModel( .collect { if (it.isNotEmpty()) { timerRepository.longBreakTime = it.toString().toLong() * 60 * 1000 + refreshTimer() preferenceRepository.saveIntPreference( "long_break_time", timerRepository.longBreakTime.toInt() @@ -153,6 +165,7 @@ class SettingsViewModel( } fun cancelTextFieldFlowCollection() { + if (!serviceRunning.value) serviceHelper.startService(TimerAction.ResetTimer) focusFlowCollectionJob?.cancel() shortBreakFlowCollectionJob?.cancel() longBreakFlowCollectionJob?.cancel() @@ -270,6 +283,24 @@ class SettingsViewModel( } } + private fun refreshTimer() { + if (!serviceRunning.value) { + time.update { timerRepository.focusTime } + + timerState.update { currentState -> + currentState.copy( + timerMode = TimerMode.FOCUS, + timeStr = millisecondsToStr(time.value), + totalTime = time.value, + nextTimerMode = if (timerRepository.sessionLength > 1) TimerMode.SHORT_BREAK else TimerMode.LONG_BREAK, + nextTimeStr = millisecondsToStr(if (timerRepository.sessionLength > 1) timerRepository.shortBreakTime else timerRepository.longBreakTime), + currentFocusCount = 1, + totalFocusCount = timerRepository.sessionLength + ) + } + } + } + companion object { val Factory: ViewModelProvider.Factory = viewModelFactory { initializer { @@ -277,11 +308,17 @@ class SettingsViewModel( val appBillingManager = application.container.billingManager val appPreferenceRepository = application.container.appPreferenceRepository val appTimerRepository = application.container.appTimerRepository + val serviceHelper = application.container.serviceHelper + val time = application.container.time + val timerState = application.container.timerState SettingsViewModel( billingManager = appBillingManager, preferenceRepository = appPreferenceRepository, - timerRepository = appTimerRepository + serviceHelper = serviceHelper, + time = time, + timerRepository = appTimerRepository, + timerState = timerState ) } } diff --git a/app/src/main/java/org/nsh07/pomodoro/ui/timerScreen/viewModel/TimerViewModel.kt b/app/src/main/java/org/nsh07/pomodoro/ui/timerScreen/viewModel/TimerViewModel.kt index 6fefa40..318a862 100644 --- a/app/src/main/java/org/nsh07/pomodoro/ui/timerScreen/viewModel/TimerViewModel.kt +++ b/app/src/main/java/org/nsh07/pomodoro/ui/timerScreen/viewModel/TimerViewModel.kt @@ -17,10 +17,9 @@ package org.nsh07.pomodoro.ui.timerScreen.viewModel -import android.app.Application import android.provider.Settings import androidx.core.net.toUri -import androidx.lifecycle.AndroidViewModel +import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory.Companion.APPLICATION_KEY import androidx.lifecycle.viewModelScope @@ -42,19 +41,20 @@ import org.nsh07.pomodoro.data.PreferenceRepository import org.nsh07.pomodoro.data.Stat import org.nsh07.pomodoro.data.StatRepository import org.nsh07.pomodoro.data.TimerRepository +import org.nsh07.pomodoro.service.ServiceHelper import org.nsh07.pomodoro.utils.millisecondsToStr import java.time.LocalDate import java.time.temporal.ChronoUnit @OptIn(FlowPreview::class) class TimerViewModel( - application: Application, private val preferenceRepository: PreferenceRepository, + private val serviceHelper: ServiceHelper, private val statRepository: StatRepository, private val timerRepository: TimerRepository, private val _timerState: MutableStateFlow, private val _time: MutableStateFlow -) : AndroidViewModel(application) { +) : ViewModel() { val timerState: StateFlow = _timerState.asStateFlow() val time: StateFlow = _time.asStateFlow() @@ -155,6 +155,10 @@ class TimerViewModel( } } + fun onAction(action: TimerAction) { + serviceHelper.startService(action) + } + companion object { val Factory: ViewModelProvider.Factory = viewModelFactory { initializer { @@ -162,12 +166,13 @@ class TimerViewModel( val appPreferenceRepository = application.container.appPreferenceRepository val appStatRepository = application.container.appStatRepository val appTimerRepository = application.container.appTimerRepository + val serviceHelper = application.container.serviceHelper val timerState = application.container.timerState val time = application.container.time TimerViewModel( - application = application, preferenceRepository = appPreferenceRepository, + serviceHelper = serviceHelper, statRepository = appStatRepository, timerRepository = appTimerRepository, _timerState = timerState, diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 078f5d7..433cd72 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -93,4 +93,5 @@ BuyMeACoffee Selected Help with translation + Reset the timer to change settings \ No newline at end of file