From fe85bc30d44bbfcd0aa574a6f05527dfd1c3d5c6 Mon Sep 17 00:00:00 2001 From: Nishant Mishra Date: Mon, 8 Dec 2025 19:19:09 +0530 Subject: [PATCH] feat(settings): add settings option to auto start sessions #108 --- .../settingsScreen/screens/TimerSettings.kt | 32 +++++++++++++++---- .../viewModel/SettingsAction.kt | 1 + .../settingsScreen/viewModel/SettingsState.kt | 1 + .../viewModel/SettingsViewModel.kt | 22 ++++++++++++- app/src/main/res/drawable/autoplay.xml | 26 +++++++++++++++ app/src/main/res/values/strings.xml | 2 ++ 6 files changed, 76 insertions(+), 8 deletions(-) create mode 100644 app/src/main/res/drawable/autoplay.xml 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 4ea0853..d74f2aa 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 @@ -77,6 +77,7 @@ 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.platform.LocalInspectionMode import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.input.ImeAction @@ -118,17 +119,30 @@ fun TimerSettings( ) { val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior() val context = LocalContext.current + val inspectionMode = LocalInspectionMode.current val appName = stringResource(R.string.app_name) - val notificationManagerService = - remember { context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager } + val notificationManagerService = remember { + if (!inspectionMode) + context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + else + null + } val switchItems = remember( settingsState.dndEnabled, settingsState.aodEnabled, + settingsState.autostartNextSession, isPlus, serviceRunning ) { listOf( + SettingsSwitchItem( + checked = settingsState.autostartNextSession, + icon = R.drawable.autoplay, + label = R.string.auto_start_next_session, + description = R.string.auto_start_next_session_desc, + onClick = { onAction(SettingsAction.SaveAutostartNextSession(it)) } + ), SettingsSwitchItem( checked = settingsState.dndEnabled, enabled = !serviceRunning, @@ -136,7 +150,7 @@ fun TimerSettings( label = R.string.dnd, description = R.string.dnd_desc, onClick = { - if (it && !notificationManagerService.isNotificationPolicyAccessGranted()) { + if (it && notificationManagerService?.isNotificationPolicyAccessGranted() == false) { val intent = Intent(Settings.ACTION_NOTIFICATION_POLICY_ACCESS_SETTINGS) Toast.makeText( context, @@ -145,7 +159,7 @@ fun TimerSettings( ) .show() context.startActivity(intent) - } else if (!it && notificationManagerService.isNotificationPolicyAccessGranted()) { + } else if (!it && notificationManagerService?.isNotificationPolicyAccessGranted() == true) { notificationManagerService.setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_ALL) } onAction(SettingsAction.SaveDndEnabled(it)) @@ -314,7 +328,7 @@ fun TimerSettings( } item { Spacer(Modifier.height(12.dp)) } - itemsIndexed(if (isPlus) switchItems else switchItems.take(1)) { index, item -> + itemsIndexed(if (isPlus) switchItems else switchItems.take(2)) { index, item -> ListItem( leadingContent = { Icon( @@ -355,7 +369,11 @@ fun TimerSettings( switchItems.size - 1 -> bottomListItemShape else -> middleListItemShape } - else cardShape + else when (index) { + 0 -> topListItemShape + switchItems.size - 2 -> bottomListItemShape + else -> middleListItemShape + } ) ) } @@ -501,7 +519,7 @@ private fun TimerSettingsPreview() { ) TimerSettings( isPlus = false, - serviceRunning = true, + serviceRunning = false, settingsState = remember { SettingsState() }, contentPadding = PaddingValues(), focusTimeInputFieldState = focusTimeInputFieldState, diff --git a/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/viewModel/SettingsAction.kt b/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/viewModel/SettingsAction.kt index 9603809..34f244c 100644 --- a/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/viewModel/SettingsAction.kt +++ b/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/viewModel/SettingsAction.kt @@ -28,6 +28,7 @@ sealed interface SettingsAction { data class SaveDndEnabled(val enabled: Boolean) : SettingsAction data class SaveMediaVolumeForAlarm(val enabled: Boolean) : SettingsAction data class SaveSingleProgressBar(val enabled: Boolean) : SettingsAction + data class SaveAutostartNextSession(val enabled: Boolean) : SettingsAction data class SaveAlarmSound(val uri: Uri?) : SettingsAction data class SaveTheme(val theme: String) : SettingsAction data class SaveColorScheme(val color: Color) : SettingsAction diff --git a/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/viewModel/SettingsState.kt b/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/viewModel/SettingsState.kt index 1ca0165..c839866 100644 --- a/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/viewModel/SettingsState.kt +++ b/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/viewModel/SettingsState.kt @@ -33,6 +33,7 @@ data class SettingsState( val dndEnabled: Boolean = false, val mediaVolumeForAlarm: Boolean = false, val singleProgressBar: Boolean = false, + val autostartNextSession: Boolean = false, val focusTime: Long = 25 * 60 * 1000L, val shortBreakTime: Long = 5 * 60 * 1000L, 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 0be8e02..aac7009 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 @@ -114,6 +114,7 @@ class SettingsViewModel( is SettingsAction.SaveDndEnabled -> saveDndEnabled(action.enabled) is SettingsAction.SaveMediaVolumeForAlarm -> saveMediaVolumeForAlarm(action.enabled) is SettingsAction.SaveSingleProgressBar -> saveSingleProgressBar(action.enabled) + is SettingsAction.SaveAutostartNextSession -> saveAutostartNextSession(action.enabled) is SettingsAction.SaveColorScheme -> saveColorScheme(action.color) is SettingsAction.SaveTheme -> saveTheme(action.theme) is SettingsAction.SaveBlackTheme -> saveBlackTheme(action.enabled) @@ -289,6 +290,18 @@ class SettingsViewModel( } } + private fun saveAutostartNextSession(autostartNextSession: Boolean) { + viewModelScope.launch { + _settingsState.update { currentState -> + currentState.copy(autostartNextSession = autostartNextSession) + } + preferenceRepository.saveBooleanPreference( + "autostart_next_session", + autostartNextSession + ) + } + } + suspend fun reloadSettings() { var settingsState = _settingsState.value val focusTime = @@ -356,6 +369,12 @@ class SettingsViewModel( "single_progress_bar", settingsState.singleProgressBar ) + val autostartNextSession = + preferenceRepository.getBooleanPreference("autostart_next_session") + ?: preferenceRepository.saveBooleanPreference( + "autostart_next_session", + settingsState.autostartNextSession + ) _settingsState.update { currentState -> currentState.copy( @@ -372,7 +391,8 @@ class SettingsViewModel( vibrateEnabled = vibrateEnabled, dndEnabled = dndEnabled, mediaVolumeForAlarm = mediaVolumeForAlarm, - singleProgressBar = singleProgressBar + singleProgressBar = singleProgressBar, + autostartNextSession = autostartNextSession ) } diff --git a/app/src/main/res/drawable/autoplay.xml b/app/src/main/res/drawable/autoplay.xml new file mode 100644 index 0000000..c4920b6 --- /dev/null +++ b/app/src/main/res/drawable/autoplay.xml @@ -0,0 +1,26 @@ + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 0cd5947..0d2b3dd 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -107,4 +107,6 @@ Plays on headphones only. If headphones are disconnected, alarm plays through speaker at media volume. Session-only progress Show progress for the current session only in notifications, rather than the full sequence. + Start next session after stopping an alarm + Auto start next session \ No newline at end of file