feat: Add vibration when timer completes, reduce loop frequency when app is in background
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" />
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||
<uses-permission android:name="android.permission.POST_PROMOTED_NOTIFICATIONS" />
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
|
||||
<application
|
||||
android:name=".TomatoApplication"
|
||||
|
||||
@@ -18,6 +18,10 @@ class MainActivity : ComponentActivity() {
|
||||
private val timerViewModel: TimerViewModel by viewModels(factoryProducer = { TimerViewModel.Factory })
|
||||
private val statsViewModel: StatsViewModel by viewModels(factoryProducer = { StatsViewModel.Factory })
|
||||
|
||||
private val appContainer by lazy {
|
||||
(application as TomatoApplication).container
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
enableEdgeToEdge()
|
||||
@@ -29,6 +33,18 @@ class MainActivity : ComponentActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
super.onStop()
|
||||
// Reduce the timer loop frequency when not visible to save battery power
|
||||
appContainer.appTimerRepository.timerFrequency = 1f
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
// Increase the timer loop frequency again when visible to make the progress smoother
|
||||
appContainer.appTimerRepository.timerFrequency = 10f
|
||||
}
|
||||
|
||||
companion object {
|
||||
val screens = listOf(
|
||||
NavItem(
|
||||
|
||||
@@ -16,6 +16,7 @@ interface TimerRepository {
|
||||
var shortBreakTime: Long
|
||||
var longBreakTime: Long
|
||||
var sessionLength: Int
|
||||
var timerFrequency: Float
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -26,4 +27,5 @@ class AppTimerRepository : TimerRepository {
|
||||
override var shortBreakTime = 5 * 60 * 1000L
|
||||
override var longBreakTime = 15 * 60 * 1000L
|
||||
override var sessionLength = 4
|
||||
override var timerFrequency: Float = 10f
|
||||
}
|
||||
@@ -7,6 +7,9 @@ import android.media.MediaPlayer
|
||||
import android.os.Build
|
||||
import android.os.IBinder
|
||||
import android.os.SystemClock
|
||||
import android.os.VibrationEffect
|
||||
import android.os.Vibrator
|
||||
import android.os.VibratorManager
|
||||
import android.provider.Settings
|
||||
import androidx.compose.material3.ColorScheme
|
||||
import androidx.compose.material3.lightColorScheme
|
||||
@@ -62,7 +65,23 @@ class TimerService : Service() {
|
||||
private val scope = CoroutineScope(Dispatchers.IO + job)
|
||||
private val skipScope = CoroutineScope(Dispatchers.IO + job)
|
||||
|
||||
private lateinit var alarm: MediaPlayer
|
||||
private val alarm by lazy {
|
||||
MediaPlayer.create(
|
||||
this,
|
||||
Settings.System.DEFAULT_ALARM_ALERT_URI ?: Settings.System.DEFAULT_RINGTONE_URI
|
||||
)
|
||||
}
|
||||
|
||||
private val vibrator by lazy {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
val vibratorManager =
|
||||
getSystemService(VIBRATOR_MANAGER_SERVICE) as VibratorManager
|
||||
vibratorManager.defaultVibrator
|
||||
} else {
|
||||
@Suppress("DEPRECATION")
|
||||
getSystemService(VIBRATOR_SERVICE) as Vibrator
|
||||
}
|
||||
}
|
||||
|
||||
private var cs: ColorScheme = lightColorScheme()
|
||||
|
||||
@@ -80,11 +99,6 @@ class TimerService : Service() {
|
||||
_time = appContainer.time
|
||||
|
||||
timerState = _timerState.asStateFlow()
|
||||
|
||||
alarm = MediaPlayer.create(
|
||||
this,
|
||||
Settings.System.DEFAULT_ALARM_ALERT_URI ?: Settings.System.DEFAULT_RINGTONE_URI
|
||||
)
|
||||
}
|
||||
|
||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
@@ -147,7 +161,8 @@ class TimerService : Service() {
|
||||
else -> timerRepository.longBreakTime - (SystemClock.elapsedRealtime() - startTime - pauseDuration).toInt()
|
||||
}
|
||||
|
||||
iterations = (iterations + 1) % 10
|
||||
iterations =
|
||||
(iterations + 1) % timerRepository.timerFrequency.toInt().coerceAtLeast(1)
|
||||
|
||||
if (iterations == 0) showTimerNotification(time.toInt())
|
||||
|
||||
@@ -165,7 +180,7 @@ class TimerService : Service() {
|
||||
}
|
||||
}
|
||||
|
||||
delay(100)
|
||||
delay((1000f / timerRepository.timerFrequency).toLong())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -254,7 +269,7 @@ class TimerService : Service() {
|
||||
)
|
||||
|
||||
if (complete) {
|
||||
alarm.start()
|
||||
startAlarm()
|
||||
_timerState.update { currentState ->
|
||||
currentState.copy(alarmRinging = true)
|
||||
}
|
||||
@@ -328,9 +343,25 @@ class TimerService : Service() {
|
||||
}
|
||||
}
|
||||
|
||||
fun startAlarm() {
|
||||
alarm.start()
|
||||
|
||||
if (!vibrator.hasVibrator()) {
|
||||
return
|
||||
}
|
||||
|
||||
val vibrationPattern = longArrayOf(0, 1000, 1000, 1000)
|
||||
val repeat = 2
|
||||
|
||||
val effect = VibrationEffect.createWaveform(vibrationPattern, repeat)
|
||||
vibrator.vibrate(effect)
|
||||
}
|
||||
|
||||
fun stopAlarm() {
|
||||
alarm.pause()
|
||||
alarm.seekTo(0)
|
||||
vibrator.cancel()
|
||||
|
||||
_timerState.update { currentState ->
|
||||
currentState.copy(alarmRinging = false)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user