All Downloads are FREE. Search and download functionalities are using the official Maven repository.

main.net.asere.omni.mvi.SaveableStateContainer.kt Maven / Gradle / Ivy

Go to download

Omni MVI Android is a Omni MVI interface that allows developers listen to Omni MVI exposed states as composables

There is a newer version: 1.7.5
Show newest version
package net.asere.omni.mvi

import androidx.lifecycle.SavedStateHandle
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.receiveAsFlow
import net.asere.omni.core.EmptyCoroutineExceptionHandler
import net.asere.omni.core.ExecutableContainer
import kotlin.coroutines.EmptyCoroutineContext

private const val HANDLE_KEY = "omni_state"

/**
 * This container behaves just like a normal StateContainer but it will
 * store states to the SavedStateHandle
 *
 * @param initialState Initial state to start the container
 * @param savedStateHandle SavedStateHandle used to store the state
 * @param coroutineScope Coroutine scope in which intents will be executed
 * @param coroutineExceptionHandler Handler to deal with exceptions
 */
class SaveableStateContainer internal constructor(
    override val initialState: State,
    private val savedStateHandle: SavedStateHandle,
    override val coroutineScope: CoroutineScope,
    override val coroutineExceptionHandler: CoroutineExceptionHandler,
) : ExecutableContainer(
    coroutineScope = coroutineScope,
    coroutineExceptionHandler = coroutineExceptionHandler
), StateContainer {

    override val state = savedStateHandle.getStateFlow(HANDLE_KEY, initialState)

    private val _effect = Channel(capacity = Channel.UNLIMITED)
    override val effect = _effect.receiveAsFlow()

    override fun update(function: State.() -> State) {
        val currentState: State = savedStateHandle[HANDLE_KEY] ?: initialState
        savedStateHandle[HANDLE_KEY] = currentState.function()
    }

    override fun post(effect: Effect) {
        _effect.trySend(effect)
    }
}

/**
 * Use this top level extension to build a SaveableStateContainer
 *
 * @param initialState Initial state to start the container
 * @param savedStateHandle SavedStateHandle used to store the state
 * @param coroutineScope Coroutine scope in which intents will be executed, defaulted to CoroutineScope(EmptyCoroutineContext)
 * @param coroutineExceptionHandler Handler to deal with exceptions, defaulted to EmptyCoroutineExceptionHandler
 */
fun 
        StateContainerHost.saveableStateContainer(
    initialState: State,
    savedStateHandle: SavedStateHandle,
    coroutineScope: CoroutineScope = CoroutineScope(EmptyCoroutineContext),
    coroutineExceptionHandler: CoroutineExceptionHandler = EmptyCoroutineExceptionHandler
) = SaveableStateContainer(
    initialState = initialState,
    savedStateHandle = savedStateHandle,
    coroutineScope = coroutineScope,
    coroutineExceptionHandler = coroutineExceptionHandler
).decorate { DelegatorContainer(it) }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy