commonMain.org.brightify.hyperdrive.property.impl.AsyncBindingObservableProperty.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of runtime Show documentation
Show all versions of runtime Show documentation
Hyperdrive implementation that's needed for observations and such
package org.brightify.hyperdrive.property.impl
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.collectLatest
import org.brightify.hyperdrive.CancellationToken
import org.brightify.hyperdrive.Lifecycle
import org.brightify.hyperdrive.property.MutableObservableProperty
import org.brightify.hyperdrive.property.ObservableProperty
import org.brightify.hyperdrive.property.defaultEqualityPolicy
import org.brightify.hyperdrive.util.AsyncQueue
internal class AsyncBindingObservableProperty(
initialValue: T,
private val boundFlow: Flow,
lifecycle: Lifecycle,
private val equalityPolicy: ObservableProperty.EqualityPolicy = defaultEqualityPolicy(),
overflowPolicy: AsyncQueue.OverflowPolicy = AsyncQueue.OverflowPolicy.Conflate,
private val readMapping: (U) -> T,
asyncSetter: suspend (T) -> Unit,
): MutableObservableProperty {
private var valueStorage: T = initialValue
override var value: T
get() = valueStorage
set(newValue) {
if (equalityPolicy.isEqual(value, newValue)) { return }
listeners.runNotifyingListeners(newValue) {
valueStorage = it
queue.push(it)
}
}
private val listeners = ValueChangeListenerHandler(this)
private val queue = AsyncQueue(action = asyncSetter, overflowPolicy = overflowPolicy, lifecycle = lifecycle)
init {
lifecycle.whileAttached {
// TODO: We want to ignore changes we made. Equality policy should be enough, but we better do it smarter.
boundFlow
.collectLatest { newValue ->
queue.awaitIdle()
val mappedNewValue = readMapping(newValue)
if (equalityPolicy.isEqual(value, mappedNewValue)) { return@collectLatest }
listeners.runNotifyingListeners(mappedNewValue) {
valueStorage = it
}
}
}
}
override fun addListener(listener: ObservableProperty.Listener): CancellationToken = listeners.addListener(listener)
override fun removeListener(listener: ObservableProperty.Listener) = listeners.removeListener(listener)
}