59 lines
1.7 KiB
Kotlin
59 lines
1.7 KiB
Kotlin
package cash.z.ecc.android.sdk.demoapp.ui.common
|
|
|
|
import kotlinx.coroutines.Deferred
|
|
import kotlinx.coroutines.Dispatchers
|
|
import kotlinx.coroutines.async
|
|
import kotlinx.coroutines.coroutineScope
|
|
import kotlinx.coroutines.delay
|
|
import kotlinx.coroutines.flow.Flow
|
|
import kotlinx.coroutines.flow.flow
|
|
import kotlinx.coroutines.sync.Mutex
|
|
import kotlinx.coroutines.sync.withLock
|
|
import kotlinx.coroutines.withContext
|
|
import kotlin.time.Duration
|
|
import kotlin.time.ExperimentalTime
|
|
import kotlin.time.TimeSource
|
|
|
|
@OptIn(ExperimentalTime::class)
|
|
fun <T> Flow<T>.throttle(
|
|
duration: Duration,
|
|
timeSource: TimeSource = TimeSource.Monotonic
|
|
): Flow<T> = flow {
|
|
coroutineScope {
|
|
val context = coroutineContext
|
|
val mutex = Mutex()
|
|
|
|
var timeMark = timeSource.markNow()
|
|
var delayEmit: Deferred<Unit>? = null
|
|
var firstValue = true
|
|
var valueToEmit: T
|
|
collect { value ->
|
|
if (firstValue) {
|
|
firstValue = false
|
|
emit(value)
|
|
timeMark = timeSource.markNow()
|
|
return@collect
|
|
}
|
|
delayEmit?.cancel()
|
|
valueToEmit = value
|
|
|
|
if (timeMark.elapsedNow() >= duration) {
|
|
mutex.withLock {
|
|
emit(valueToEmit)
|
|
timeMark = timeSource.markNow()
|
|
}
|
|
} else {
|
|
delayEmit = async(Dispatchers.Default) {
|
|
mutex.withLock {
|
|
delay(duration)
|
|
withContext(context) {
|
|
emit(valueToEmit)
|
|
}
|
|
timeMark = timeSource.markNow()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|