diff --git a/app/src/main/java/org/nsh07/pomodoro/ui/timerScreen/AlarmDialog.kt b/app/src/main/java/org/nsh07/pomodoro/ui/timerScreen/AlarmDialog.kt
new file mode 100644
index 0000000..556e88d
--- /dev/null
+++ b/app/src/main/java/org/nsh07/pomodoro/ui/timerScreen/AlarmDialog.kt
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2025 Nishant Mishra
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package org.nsh07.pomodoro.ui.timerScreen
+
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.wrapContentHeight
+import androidx.compose.foundation.layout.wrapContentWidth
+import androidx.compose.material3.AlertDialogDefaults
+import androidx.compose.material3.BasicAlertDialog
+import androidx.compose.material3.Button
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.Icon
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.MaterialTheme.typography
+import androidx.compose.material3.Surface
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.unit.dp
+import org.nsh07.pomodoro.R
+
+@OptIn(ExperimentalMaterial3Api::class)
+@Composable
+fun AlarmDialog(
+ modifier: Modifier = Modifier,
+ stopAlarm: () -> Unit
+) {
+ BasicAlertDialog(
+ onDismissRequest = stopAlarm,
+ modifier = modifier
+ ) {
+ Surface(
+ modifier = Modifier
+ .wrapContentWidth()
+ .wrapContentHeight()
+ .clickable(onClick = stopAlarm),
+ shape = MaterialTheme.shapes.extraLarge,
+ tonalElevation = AlertDialogDefaults.TonalElevation,
+ ) {
+ Column(modifier = Modifier.padding(24.dp)) {
+ Icon(
+ painter = painterResource(R.drawable.alarm),
+ contentDescription = "Alarm",
+ modifier = Modifier.align(Alignment.CenterHorizontally)
+ )
+ Spacer(Modifier.height(16.dp))
+ Text(
+ text = "Stop Alarm?",
+ style = typography.headlineSmall,
+ modifier = Modifier.align(Alignment.CenterHorizontally)
+ )
+ Spacer(Modifier.height(16.dp))
+ Text(
+ text = "Current timer session is complete. Tap anywhere to stop the alarm."
+ )
+ Spacer(modifier = Modifier.height(24.dp))
+ Button(
+ onClick = stopAlarm,
+ modifier = Modifier.align(Alignment.End),
+ ) {
+ Text("Ok")
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/nsh07/pomodoro/ui/timerScreen/TimerScreen.kt b/app/src/main/java/org/nsh07/pomodoro/ui/timerScreen/TimerScreen.kt
index 4dbb7c8..a31724e 100644
--- a/app/src/main/java/org/nsh07/pomodoro/ui/timerScreen/TimerScreen.kt
+++ b/app/src/main/java/org/nsh07/pomodoro/ui/timerScreen/TimerScreen.kt
@@ -111,6 +111,9 @@ fun TimerScreen(
onResult = {}
)
+ if (timerState.alarmRinging)
+ AlarmDialog { onAction(TimerAction.StopAlarm) }
+
Column(modifier = modifier) {
TopAppBar(
title = {
diff --git a/app/src/main/java/org/nsh07/pomodoro/ui/timerScreen/viewModel/TimerAction.kt b/app/src/main/java/org/nsh07/pomodoro/ui/timerScreen/viewModel/TimerAction.kt
index 633c5cb..46df0d5 100644
--- a/app/src/main/java/org/nsh07/pomodoro/ui/timerScreen/viewModel/TimerAction.kt
+++ b/app/src/main/java/org/nsh07/pomodoro/ui/timerScreen/viewModel/TimerAction.kt
@@ -10,5 +10,6 @@ package org.nsh07.pomodoro.ui.timerScreen.viewModel
sealed interface TimerAction {
data object ResetTimer : TimerAction
data object SkipTimer : TimerAction
+ data object StopAlarm : TimerAction
data object ToggleTimer : TimerAction
}
\ No newline at end of file
diff --git a/app/src/main/java/org/nsh07/pomodoro/ui/timerScreen/viewModel/TimerState.kt b/app/src/main/java/org/nsh07/pomodoro/ui/timerScreen/viewModel/TimerState.kt
index 4a9c3d9..3a3cd3b 100644
--- a/app/src/main/java/org/nsh07/pomodoro/ui/timerScreen/viewModel/TimerState.kt
+++ b/app/src/main/java/org/nsh07/pomodoro/ui/timerScreen/viewModel/TimerState.kt
@@ -16,7 +16,8 @@ data class TimerState(
val nextTimeStr: String = "5:00",
val showBrandTitle: Boolean = true,
val currentFocusCount: Int = 1,
- val totalFocusCount: Int = 4
+ val totalFocusCount: Int = 4,
+ val alarmRinging: Boolean = false
)
enum class TimerMode {
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 8f7d025..80ed086 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
@@ -8,19 +8,23 @@
package org.nsh07.pomodoro.ui.timerScreen.viewModel
import android.annotation.SuppressLint
+import android.app.Application
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Intent
+import android.media.MediaPlayer
import android.os.SystemClock
+import android.provider.Settings
import androidx.compose.material3.ColorScheme
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.toArgb
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
-import androidx.lifecycle.ViewModel
+import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory.Companion.APPLICATION_KEY
+import androidx.lifecycle.application
import androidx.lifecycle.viewModelScope
import androidx.lifecycle.viewmodel.initializer
import androidx.lifecycle.viewmodel.viewModelFactory
@@ -46,12 +50,13 @@ import kotlin.text.Typography.middleDot
@OptIn(FlowPreview::class)
class TimerViewModel(
+ application: Application,
private val preferenceRepository: PreferenceRepository,
private val statRepository: StatRepository,
private val timerRepository: TimerRepository,
private val notificationBuilder: NotificationCompat.Builder,
private val notificationManager: NotificationManagerCompat
-) : ViewModel() {
+) : AndroidViewModel(application) {
private val _timerState = MutableStateFlow(
TimerState(
totalTime = timerRepository.focusTime,
@@ -73,6 +78,11 @@ class TimerViewModel(
private lateinit var cs: ColorScheme
+ private val alarm = MediaPlayer.create(
+ this.application,
+ Settings.System.DEFAULT_ALARM_ALERT_URI ?: Settings.System.DEFAULT_RINGTONE_URI
+ )
+
init {
viewModelScope.launch(Dispatchers.IO) {
timerRepository.focusTime =
@@ -126,6 +136,7 @@ class TimerViewModel(
when (action) {
TimerAction.ResetTimer -> resetTimer()
TimerAction.SkipTimer -> skipTimer()
+ TimerAction.StopAlarm -> stopAlarm()
TimerAction.ToggleTimer -> toggleTimer()
}
}
@@ -331,9 +342,24 @@ class TimerViewModel(
)
.setShowWhen(true)
.setWhen(System.currentTimeMillis() + remainingTime) // Sets the Live Activity/Now Bar chip time
- .setSilent(!complete)
+ .setSilent(true)
.build()
)
+
+ if (complete) {
+ alarm.start()
+ _timerState.update { currentState ->
+ currentState.copy(alarmRinging = true)
+ }
+ }
+ }
+
+ fun stopAlarm() {
+ alarm.pause()
+ alarm.seekTo(0)
+ _timerState.update { currentState ->
+ currentState.copy(alarmRinging = false)
+ }
}
companion object {
@@ -374,6 +400,7 @@ class TimerViewModel(
.setOngoing(true)
TimerViewModel(
+ application = application,
preferenceRepository = appPreferenceRepository,
statRepository = appStatRepository,
timerRepository = appTimerRepository,
diff --git a/app/src/main/res/drawable/alarm.xml b/app/src/main/res/drawable/alarm.xml
new file mode 100644
index 0000000..500f240
--- /dev/null
+++ b/app/src/main/res/drawable/alarm.xml
@@ -0,0 +1,16 @@
+
+
+
+
+