zcash-android-wallet-sdk/demo-app/src/main/java/cash/z/ecc/android/sdk/demoapp/ui/common/FlowExt.kt

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()
}
}
}
}
}
}