commonMain.dev.stateholder.StateHolder.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of core Show documentation
Show all versions of core Show documentation
A simple library for managing state in Kotlin Multiplatform projects, using Kotlin Coroutines and `StateFlow`.
package dev.stateholder
import dev.stateholder.internal.DefaultStateHolder
import kotlin.reflect.KProperty
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.StateFlow
/**
* A container for managing state.
*
* The [state] property is the only property that should be exposed to the UI level. All updating
* should be handled separately.
*
* Example usage:
*
*
*
* @param[State] The type of the state.
*/
public interface StateHolder {
/**
* The current state of type [State] exposed as a [StateFlow].
*/
public val state: StateFlow
/**
* Add a source of state from another [Flow].
*
* This is useful when you need to update the [state] based off of another [Flow]. The [flow]
* will be collected and [block] will be invoked in order to map the [T] value from [flow] to
* the [State] value.
*
* The collecting can be stopped by cancelling the returned [Job].
*
* @param[T] The type of the value from flow.
* @param[flow] The flow to collect from and update state with.
* @param[scope] The scope to use for collecting the flow.
* @param[block] The function to map the [T] value from [flow] to the [State] value.
* @return The [Job] of the collection.
*/
public fun addSource(
flow: Flow,
scope: CoroutineScope,
block: suspend (State, T) -> State,
): Job
/**
* Updates the MutableStateFlow.value atomically using the specified function of its value.
* function may be evaluated multiple times, if value is being concurrently updated.
*/
public fun update(block: (State) -> State)
/**
* Allows using delegation to access the [StateHolder.state] property.
*
* Example:
*
* ```
* val state: StateFlow by stateContainer
* ```
*/
public operator fun getValue(
stateOwner: StateOwner,
property: KProperty<*>,
): StateFlow = state
public companion object {
/**
* Create a [StateHolder] with the given [initialStateProvider].
*/
internal fun create(
initialStateProvider: StateProvider,
): StateHolder = DefaultStateHolder(initialStateProvider)
}
}
/**
* Create a [StateHolder] with the given [initialStateProvider].
*
* @see [StateHolder]
*/
public fun stateContainer(
initialStateProvider: StateProvider,
): StateHolder = StateHolder.create(initialStateProvider)
/**
* Create a [StateHolder] with the given [initialState].
*
* @see [StateHolder]
*/
public fun stateContainer(
initialState: State,
): StateHolder = StateHolder.create(provideState(initialState))
public fun Flow.collectToState(
container: StateHolder,
scope: CoroutineScope,
block: suspend (state: State, value: T) -> State,
): Job {
return container.addSource(this, scope, block)
}