From f10df4813f23f631df0e3b709c31335f6fb0806c Mon Sep 17 00:00:00 2001 From: Tretzi Date: Sat, 4 Apr 2026 08:01:01 -0500 Subject: [PATCH] Auto commit Sat Apr 4 08:01:01 AM CDT 2026 --- .../java/com/mindmachine/mvp/MainActivity.kt | 56 ++++++++++++++++++- .../mvp/session/ActiveSessionUi.kt | 7 +++ .../mindmachine/mvp/ActiveSessionUiTest.kt | 13 +++++ 3 files changed, 74 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/mindmachine/mvp/MainActivity.kt b/app/src/main/java/com/mindmachine/mvp/MainActivity.kt index fac951b..f8ff7be 100644 --- a/app/src/main/java/com/mindmachine/mvp/MainActivity.kt +++ b/app/src/main/java/com/mindmachine/mvp/MainActivity.kt @@ -104,6 +104,7 @@ import com.mindmachine.mvp.session.flashIntervalMsToSeconds import com.mindmachine.mvp.session.flashIntervalSecondsToMs import com.mindmachine.mvp.session.formatDuration import com.mindmachine.mvp.session.sessionProgressFraction +import com.mindmachine.mvp.session.shouldRequireStopConfirmation import com.mindmachine.mvp.session.shouldShowActiveControlsByDefault import com.mindmachine.mvp.session.shouldUseImmersiveFullscreen import kotlinx.coroutines.delay @@ -113,6 +114,11 @@ import java.util.Locale private const val SESSION_ENTRY_HOME = "home" private const val SESSION_ENTRY_SETUP = "setup" +private enum class StopConfirmationAction { + BACK, + STOP_BUTTON, +} + private val MindMachineColors = darkColorScheme( primary = Color(0xFF8AB4FF), onPrimary = Color(0xFF001B3D), @@ -483,8 +489,14 @@ fun ActiveSessionScreen(vm: MainViewModel, onFinish: () -> Unit, onBackToEntry: val ui by vm.ui.collectAsStateWithLifecycle() if (ui.runtimeState == RuntimeState.COMPLETED) onFinish() + var stopConfirmationAction by remember { mutableStateOf(null) } + BackHandler { - onBackToEntry() + if (shouldRequireStopConfirmation(ui.runtimeState)) { + stopConfirmationAction = StopConfirmationAction.BACK + } else { + onBackToEntry() + } } val isVisualMode = true @@ -633,7 +645,17 @@ fun ActiveSessionScreen(vm: MainViewModel, onFinish: () -> Unit, onBackToEntry: } else { Button(onClick = { vm.resume() }, modifier = Modifier.fillMaxWidth()) { Text("Resume") } } - OutlinedButton(onClick = { vm.stop(); onFinish() }, modifier = Modifier.fillMaxWidth()) { Text("Stop") } + OutlinedButton( + onClick = { + if (shouldRequireStopConfirmation(ui.runtimeState)) { + stopConfirmationAction = StopConfirmationAction.STOP_BUTTON + } else { + vm.stop() + onFinish() + } + }, + modifier = Modifier.fillMaxWidth() + ) { Text("Stop") } if (ui.interruptionReason != null) { Text(ui.interruptionReason!!, color = Color.White) if (ui.runtimeState == RuntimeState.INTERRUPTED) { @@ -645,6 +667,36 @@ fun ActiveSessionScreen(vm: MainViewModel, onFinish: () -> Unit, onBackToEntry: } } } + + if (stopConfirmationAction != null) { + AlertDialog( + onDismissRequest = { stopConfirmationAction = null }, + title = { Text("End session?") }, + text = { Text("Your current session will stop and return to the previous screen.") }, + confirmButton = { + TextButton( + onClick = { + when (stopConfirmationAction) { + StopConfirmationAction.BACK -> onBackToEntry() + StopConfirmationAction.STOP_BUTTON -> { + vm.stop() + onFinish() + } + null -> Unit + } + stopConfirmationAction = null + } + ) { + Text("End session", color = Color(0xFFFF5252)) + } + }, + dismissButton = { + TextButton(onClick = { stopConfirmationAction = null }) { + Text("Keep running") + } + } + ) + } } @Composable diff --git a/app/src/main/java/com/mindmachine/mvp/session/ActiveSessionUi.kt b/app/src/main/java/com/mindmachine/mvp/session/ActiveSessionUi.kt index a39e9a1..c035300 100644 --- a/app/src/main/java/com/mindmachine/mvp/session/ActiveSessionUi.kt +++ b/app/src/main/java/com/mindmachine/mvp/session/ActiveSessionUi.kt @@ -11,3 +11,10 @@ fun sessionProgressFraction(durationSec: Int, remainingSec: Int): Float { val elapsed = (total - remainingSec).coerceIn(0, total) return elapsed.toFloat() / total.toFloat() } + +fun shouldRequireStopConfirmation(runtimeState: RuntimeState): Boolean { + return runtimeState == RuntimeState.COUNTDOWN || + runtimeState == RuntimeState.RUNNING || + runtimeState == RuntimeState.PAUSED || + runtimeState == RuntimeState.INTERRUPTED +} diff --git a/app/src/test/java/com/mindmachine/mvp/ActiveSessionUiTest.kt b/app/src/test/java/com/mindmachine/mvp/ActiveSessionUiTest.kt index 2ed908a..8f1f33e 100644 --- a/app/src/test/java/com/mindmachine/mvp/ActiveSessionUiTest.kt +++ b/app/src/test/java/com/mindmachine/mvp/ActiveSessionUiTest.kt @@ -2,6 +2,7 @@ package com.mindmachine.mvp import com.mindmachine.mvp.domain.RuntimeState import com.mindmachine.mvp.session.sessionProgressFraction +import com.mindmachine.mvp.session.shouldRequireStopConfirmation import com.mindmachine.mvp.session.shouldRevealSystemBarsOnTap import com.mindmachine.mvp.session.shouldShowActiveControlsByDefault import com.mindmachine.mvp.session.shouldUseImmersiveFullscreen @@ -53,4 +54,16 @@ class ActiveSessionUiTest { assertTrue(sessionProgressFraction(durationSec = 600, remainingSec = 800) == 0f) assertTrue(sessionProgressFraction(durationSec = 600, remainingSec = -10) == 1f) } + + @Test + fun stop_confirmation_is_required_only_while_session_is_active_or_paused() { + assertTrue(shouldRequireStopConfirmation(RuntimeState.COUNTDOWN)) + assertTrue(shouldRequireStopConfirmation(RuntimeState.RUNNING)) + assertTrue(shouldRequireStopConfirmation(RuntimeState.PAUSED)) + assertTrue(shouldRequireStopConfirmation(RuntimeState.INTERRUPTED)) + + assertFalse(shouldRequireStopConfirmation(RuntimeState.IDLE)) + assertFalse(shouldRequireStopConfirmation(RuntimeState.COMPLETED)) + assertFalse(shouldRequireStopConfirmation(RuntimeState.STOPPED)) + } }