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