Cancel and start a new timer on pause & resume

This commit is contained in:
Florian Renaud 2023-01-31 15:45:41 +01:00
parent bb8ebb73bf
commit b904548ba0
1 changed files with 10 additions and 12 deletions

View File

@ -19,31 +19,29 @@ package im.vector.lib.core.utils.timer
import im.vector.lib.core.utils.flow.tickerFlow import im.vector.lib.core.utils.flow.tickerFlow
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.cancel import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import java.util.concurrent.atomic.AtomicBoolean
import java.util.concurrent.atomic.AtomicLong import java.util.concurrent.atomic.AtomicLong
@OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class) @OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class)
class CountUpTimer(initialTime: Long = 0L, private val intervalInMs: Long = 1_000) { class CountUpTimer(initialTime: Long = 0L, private val intervalInMs: Long = 1_000) {
private val coroutineScope = CoroutineScope(Dispatchers.Main) private val coroutineScope = CoroutineScope(Dispatchers.Main)
private val resumed: AtomicBoolean = AtomicBoolean(false) private var counterJob: Job? = null
private val clock: Clock = DefaultClock() private val clock: Clock = DefaultClock()
private val lastTime: AtomicLong = AtomicLong() private val lastTime: AtomicLong = AtomicLong()
private val elapsedTime: AtomicLong = AtomicLong(initialTime) private val elapsedTime: AtomicLong = AtomicLong(initialTime)
init {
startCounter()
}
private fun startCounter() { private fun startCounter() {
tickerFlow(coroutineScope, intervalInMs) counterJob = tickerFlow(
.filter { resumed.get() } scope = coroutineScope,
delayMillis = intervalInMs,
initialDelayMillis = intervalInMs - (elapsedTime() % intervalInMs)
)
.map { elapsedTime() } .map { elapsedTime() }
.onEach { tickListener?.onTick(it) } .onEach { tickListener?.onTick(it) }
.launchIn(coroutineScope) .launchIn(coroutineScope)
@ -52,7 +50,7 @@ class CountUpTimer(initialTime: Long = 0L, private val intervalInMs: Long = 1_00
var tickListener: TickListener? = null var tickListener: TickListener? = null
fun elapsedTime(): Long { fun elapsedTime(): Long {
return if (resumed.get()) { return if (counterJob?.isActive == true) {
val now = clock.epochMillis() val now = clock.epochMillis()
elapsedTime.addAndGet(now - lastTime.getAndSet(now)) elapsedTime.addAndGet(now - lastTime.getAndSet(now))
} else { } else {
@ -62,12 +60,12 @@ class CountUpTimer(initialTime: Long = 0L, private val intervalInMs: Long = 1_00
fun pause() { fun pause() {
tickListener?.onTick(elapsedTime()) tickListener?.onTick(elapsedTime())
resumed.set(false) coroutineScope.cancel()
} }
fun resume() { fun resume() {
lastTime.set(clock.epochMillis()) lastTime.set(clock.epochMillis())
resumed.set(true) startCounter()
} }
fun stop() { fun stop() {