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

commonMain.pro.respawn.flowmvi.compose.dsl.SubscribeDsl.kt Maven / Gradle / Ivy

Go to download

A Kotlin Multiplatform MVI library based on coroutines with a powerful plugin system

There is a newer version: 3.0.0
Show newest version
@file:OptIn(DelicateStoreApi::class)

package pro.respawn.flowmvi.compose.dsl

import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.State
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberUpdatedState
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import pro.respawn.flowmvi.api.DelicateStoreApi
import pro.respawn.flowmvi.api.FlowMVIDSL
import pro.respawn.flowmvi.api.ImmutableStore
import pro.respawn.flowmvi.api.MVIAction
import pro.respawn.flowmvi.api.MVIIntent
import pro.respawn.flowmvi.api.MVIState
import pro.respawn.flowmvi.compose.api.SubscriberLifecycle
import pro.respawn.flowmvi.compose.api.SubscriptionMode
import pro.respawn.flowmvi.dsl.subscribe
import pro.respawn.flowmvi.util.immediateOrDefault

/**
 * A function to subscribe to the store that follows the system lifecycle.
 *
 * * This function will assign the store a new subscriber when invoked, then populate the returned [State] with new states.
 * * Provided [consume] parameter will be used to consume actions that come from the store.
 * * Store's subscribers will **not** wait until the store is launched when they subscribe to the store.
 *   Such subscribers will not receive state updates or actions. Don't forget to launch the store.
 *
 *  [lifecycle] is an instance of the lifecycle wrapper used to execute the subscription event.
 *  * The provided implementation must follow the contract outlined in [SubscriberLifecycle]. This instance can be
 *  provided automatically on Android, but must be implemented manually on other platforms for now.
 *  * If you have provided a lifecycle via [LocalSubscriberLifecycle], use [requireLifecycle].
 *  * If you don't want to provide a lifecycle, use [DefaultLifecycle] to fall back to a no-op implementation if needed
 *
 *
 * @param mode the subscription mode that should be reached in order to subscribe to the store. At specified moments
 * in the UI lifecycle (Activity, Composable, Window etc), the store will subscribe and unsubscribe from the store.
 * @param consume a lambda to consume actions with.
 * @return the [State] that contains the current state.
 * @see ImmutableStore.subscribe
 * @see subscribe
 */
@Suppress("ComposableParametersOrdering")
@Composable
@FlowMVIDSL
public fun  ImmutableStore.subscribe(
    lifecycle: SubscriberLifecycle,
    mode: SubscriptionMode = SubscriptionMode.Started,
    consume: suspend CoroutineScope.(action: A) -> Unit,
): State {
    val state = remember(this) { mutableStateOf(state) }
    val block by rememberUpdatedState(consume)
    LaunchedEffect(this@subscribe, mode, lifecycle) {
        withContext(Dispatchers.Main.immediateOrDefault) {
            lifecycle.repeatOnLifecycle(mode) {
                subscribe(
                    store = this@subscribe,
                    consume = { block(it) },
                    render = { state.value = it }
                ).join()
            }
        }
    }
    return state
}

/**
 * A function to subscribe to the store that follows the system lifecycle.
 *
 * * This function will assign the store a new subscriber when invoked, then populate the returned [State] with new states.
 * * Store's subscribers will **not** wait until the store is launched when they subscribe to the store.
 *   Such subscribers will not receive state updates or actions. Don't forget to launch the store.
 *
 *  [lifecycle] is an instance of the lifecycle wrapper used to execute the subscription event.
 *  * The provided implementation must follow the contract outlined in [SubscriberLifecycle]. This instance can be
 *  provided automatically on Android, but must be implemented manually on other platforms for now.
 *  * If you have provided a lifecycle via [LocalSubscriberLifecycle], use [requireLifecycle].
 *  * If you don't want to provide a lifecycle, use [DefaultLifecycle] to fall back to a no-op implementation if needed
 *
 *
 * @param mode the subscription mode that should be reached in order to subscribe to the store. At specified moments
 * in the UI lifecycle (Activity, Composable, Window etc), the store will subscribe and unsubscribe from the store.
 * @return the [State] that contains the current state.
 * @see ImmutableStore.subscribe
 * @see subscribe
 */
@Composable
@FlowMVIDSL
public fun  ImmutableStore.subscribe(
    lifecycle: SubscriberLifecycle,
    mode: SubscriptionMode = SubscriptionMode.Started,
): State {
    val state = remember(this) { mutableStateOf(state) }
    LaunchedEffect(this@subscribe, mode, lifecycle) {
        withContext(Dispatchers.Main.immediateOrDefault) {
            lifecycle.repeatOnLifecycle(mode) {
                subscribe(
                    store = this@subscribe,
                    render = { state.value = it }
                ).join()
            }
        }
    }
    return state
}