fix: Improve TimerService code by using lazy init instead of lateinit var
This commit is contained in:
@@ -20,41 +20,35 @@ import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.nsh07.pomodoro.R
|
||||
import org.nsh07.pomodoro.TomatoApplication
|
||||
import org.nsh07.pomodoro.data.AppContainer
|
||||
import org.nsh07.pomodoro.data.StatRepository
|
||||
import org.nsh07.pomodoro.data.TimerRepository
|
||||
import org.nsh07.pomodoro.ui.timerScreen.viewModel.TimerMode
|
||||
import org.nsh07.pomodoro.ui.timerScreen.viewModel.TimerState
|
||||
import org.nsh07.pomodoro.utils.millisecondsToStr
|
||||
import kotlin.text.Typography.middleDot
|
||||
|
||||
class TimerService : Service() {
|
||||
private lateinit var appContainer: AppContainer
|
||||
|
||||
private lateinit var timerRepository: TimerRepository
|
||||
private lateinit var statRepository: StatRepository
|
||||
private lateinit var notificationManager: NotificationManagerCompat
|
||||
private lateinit var notificationBuilder: NotificationCompat.Builder
|
||||
private lateinit var _timerState: MutableStateFlow<TimerState>
|
||||
private lateinit var _time: MutableStateFlow<Long>
|
||||
|
||||
val timeStateFlow by lazy {
|
||||
_time.asStateFlow()
|
||||
private val appContainer by lazy {
|
||||
(application as TomatoApplication).container
|
||||
}
|
||||
|
||||
var time: Long
|
||||
private val timerRepository by lazy { appContainer.appTimerRepository }
|
||||
private val statRepository by lazy { appContainer.appStatRepository }
|
||||
private val notificationManager by lazy { NotificationManagerCompat.from(this) }
|
||||
private val notificationBuilder by lazy { appContainer.notificationBuilder }
|
||||
private val _timerState by lazy { appContainer.timerState }
|
||||
private val _time by lazy { appContainer.time }
|
||||
|
||||
private val timeStateFlow by lazy { _time.asStateFlow() }
|
||||
|
||||
private var time: Long
|
||||
get() = timeStateFlow.value
|
||||
set(value) = _time.update { value }
|
||||
|
||||
lateinit var timerState: StateFlow<TimerState>
|
||||
private val timerState by lazy { _timerState.asStateFlow() }
|
||||
|
||||
private var cycles = 0
|
||||
private var startTime = 0L
|
||||
@@ -67,19 +61,16 @@ class TimerService : Service() {
|
||||
|
||||
private val alarm by lazy {
|
||||
MediaPlayer.create(
|
||||
this,
|
||||
Settings.System.DEFAULT_ALARM_ALERT_URI ?: Settings.System.DEFAULT_RINGTONE_URI
|
||||
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
|
||||
val vibratorManager = getSystemService(VIBRATOR_MANAGER_SERVICE) as VibratorManager
|
||||
vibratorManager.defaultVibrator
|
||||
} else {
|
||||
@Suppress("DEPRECATION")
|
||||
getSystemService(VIBRATOR_SERVICE) as Vibrator
|
||||
@Suppress("DEPRECATION") getSystemService(VIBRATOR_SERVICE) as Vibrator
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,18 +80,6 @@ class TimerService : Service() {
|
||||
return null
|
||||
}
|
||||
|
||||
override fun onCreate() {
|
||||
appContainer = (application as TomatoApplication).container
|
||||
timerRepository = appContainer.appTimerRepository
|
||||
statRepository = appContainer.appStatRepository
|
||||
notificationManager = NotificationManagerCompat.from(this)
|
||||
notificationBuilder = appContainer.notificationBuilder
|
||||
_timerState = appContainer.timerState
|
||||
_time = appContainer.time
|
||||
|
||||
timerState = _timerState.asStateFlow()
|
||||
}
|
||||
|
||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
when (intent?.action) {
|
||||
Actions.TOGGLE.toString() -> {
|
||||
@@ -123,26 +102,18 @@ class TimerService : Service() {
|
||||
|
||||
private fun toggleTimer() {
|
||||
if (timerState.value.timerRunning) {
|
||||
notificationBuilder
|
||||
.clearActions()
|
||||
.addTimerActions(
|
||||
this,
|
||||
R.drawable.play,
|
||||
"Start"
|
||||
)
|
||||
notificationBuilder.clearActions().addTimerActions(
|
||||
this, R.drawable.play, "Start"
|
||||
)
|
||||
showTimerNotification(time.toInt(), paused = true)
|
||||
_timerState.update { currentState ->
|
||||
currentState.copy(timerRunning = false)
|
||||
}
|
||||
pauseTime = SystemClock.elapsedRealtime()
|
||||
} else {
|
||||
notificationBuilder
|
||||
.clearActions()
|
||||
.addTimerActions(
|
||||
this,
|
||||
R.drawable.pause,
|
||||
"Stop"
|
||||
)
|
||||
notificationBuilder.clearActions().addTimerActions(
|
||||
this, R.drawable.pause, "Stop"
|
||||
)
|
||||
_timerState.update { it.copy(timerRunning = true) }
|
||||
if (pauseTime != 0L) pauseDuration += SystemClock.elapsedRealtime() - pauseTime
|
||||
|
||||
@@ -214,59 +185,52 @@ class TimerService : Service() {
|
||||
else (remainingTime.toFloat() / 60000f).toInt()
|
||||
|
||||
notificationManager.notify(
|
||||
1,
|
||||
notificationBuilder
|
||||
.setContentTitle(
|
||||
if (!complete) {
|
||||
"$currentTimer $middleDot $remainingTimeString min remaining" + if (paused) " $middleDot Paused" else ""
|
||||
} else "$currentTimer $middleDot Completed"
|
||||
)
|
||||
.setContentText("Up next: $nextTimer (${timerState.value.nextTimeStr})")
|
||||
.setStyle(
|
||||
NotificationCompat.ProgressStyle().also {
|
||||
// Add all the Focus, Short break and long break intervals in order
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.BAKLAVA) {
|
||||
// Android 16 and later supports live updates
|
||||
// Set progress bar sections if on Baklava or later
|
||||
for (i in 0..<timerRepository.sessionLength * 2) {
|
||||
if (i % 2 == 0) it.addProgressSegment(
|
||||
NotificationCompat.ProgressStyle.Segment(
|
||||
timerRepository.focusTime.toInt()
|
||||
).setColor(cs.primary.toArgb())
|
||||
)
|
||||
else if (i != (timerRepository.sessionLength * 2 - 1)) it.addProgressSegment(
|
||||
NotificationCompat.ProgressStyle.Segment(
|
||||
timerRepository.shortBreakTime.toInt()
|
||||
).setColor(cs.tertiary.toArgb())
|
||||
)
|
||||
else it.addProgressSegment(
|
||||
NotificationCompat.ProgressStyle.Segment(
|
||||
timerRepository.longBreakTime.toInt()
|
||||
).setColor(cs.tertiary.toArgb())
|
||||
)
|
||||
}
|
||||
} else {
|
||||
it.addProgressSegment(
|
||||
1, notificationBuilder.setContentTitle(
|
||||
if (!complete) {
|
||||
"$currentTimer $middleDot $remainingTimeString min remaining" + if (paused) " $middleDot Paused" else ""
|
||||
} else "$currentTimer $middleDot Completed"
|
||||
).setContentText("Up next: $nextTimer (${timerState.value.nextTimeStr})")
|
||||
.setStyle(NotificationCompat.ProgressStyle().also {
|
||||
// Add all the Focus, Short break and long break intervals in order
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.BAKLAVA) {
|
||||
// Android 16 and later supports live updates
|
||||
// Set progress bar sections if on Baklava or later
|
||||
for (i in 0..<timerRepository.sessionLength * 2) {
|
||||
if (i % 2 == 0) it.addProgressSegment(
|
||||
NotificationCompat.ProgressStyle.Segment(
|
||||
when (timerState.value.timerMode) {
|
||||
TimerMode.FOCUS -> timerRepository.focusTime.toInt()
|
||||
TimerMode.SHORT_BREAK -> timerRepository.shortBreakTime.toInt()
|
||||
else -> timerRepository.longBreakTime.toInt()
|
||||
}
|
||||
)
|
||||
timerRepository.focusTime.toInt()
|
||||
).setColor(cs.primary.toArgb())
|
||||
)
|
||||
else if (i != (timerRepository.sessionLength * 2 - 1)) it.addProgressSegment(
|
||||
NotificationCompat.ProgressStyle.Segment(
|
||||
timerRepository.shortBreakTime.toInt()
|
||||
).setColor(cs.tertiary.toArgb())
|
||||
)
|
||||
else it.addProgressSegment(
|
||||
NotificationCompat.ProgressStyle.Segment(
|
||||
timerRepository.longBreakTime.toInt()
|
||||
).setColor(cs.tertiary.toArgb())
|
||||
)
|
||||
}
|
||||
}
|
||||
.setProgress( // Set the current progress by filling the previous intervals and part of the current interval
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.BAKLAVA) {
|
||||
(totalTime - remainingTime) + ((cycles + 1) / 2) * timerRepository.focusTime.toInt() + (cycles / 2) * timerRepository.shortBreakTime.toInt()
|
||||
} else (totalTime - remainingTime)
|
||||
} else {
|
||||
it.addProgressSegment(
|
||||
NotificationCompat.ProgressStyle.Segment(
|
||||
when (timerState.value.timerMode) {
|
||||
TimerMode.FOCUS -> timerRepository.focusTime.toInt()
|
||||
TimerMode.SHORT_BREAK -> timerRepository.shortBreakTime.toInt()
|
||||
else -> timerRepository.longBreakTime.toInt()
|
||||
}
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
.setProgress( // Set the current progress by filling the previous intervals and part of the current interval
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.BAKLAVA) {
|
||||
(totalTime - remainingTime) + ((cycles + 1) / 2) * timerRepository.focusTime.toInt() + (cycles / 2) * timerRepository.shortBreakTime.toInt()
|
||||
} else (totalTime - remainingTime)
|
||||
))
|
||||
.setWhen(System.currentTimeMillis() + remainingTime) // Sets the Live Activity/Now Bar chip time
|
||||
.setShortCriticalText(millisecondsToStr(time.coerceAtLeast(0)))
|
||||
.build()
|
||||
)
|
||||
.setShortCriticalText(millisecondsToStr(time.coerceAtLeast(0))).build())
|
||||
|
||||
if (complete) {
|
||||
startAlarm()
|
||||
@@ -376,9 +340,7 @@ class TimerService : Service() {
|
||||
TimerMode.FOCUS -> timerRepository.focusTime.toInt()
|
||||
TimerMode.SHORT_BREAK -> timerRepository.shortBreakTime.toInt()
|
||||
else -> timerRepository.longBreakTime.toInt()
|
||||
},
|
||||
paused = true,
|
||||
complete = false
|
||||
}, paused = true, complete = false
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user