diff --git a/shared/arkitekt-decompose/src/commonMain/kotlin/app/futured/arkitekt/decompose/coroutines/ValueStateFlow.kt b/shared/arkitekt-decompose/src/commonMain/kotlin/app/futured/arkitekt/decompose/coroutines/ValueStateFlow.kt new file mode 100644 index 0000000..18b1db8 --- /dev/null +++ b/shared/arkitekt-decompose/src/commonMain/kotlin/app/futured/arkitekt/decompose/coroutines/ValueStateFlow.kt @@ -0,0 +1,33 @@ +package app.futured.arkitekt.decompose.coroutines + +import com.arkivanov.decompose.value.Value +import kotlinx.coroutines.flow.FlowCollector +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow + +/** + * A [StateFlow] implementation that wraps a Decompose Value. + * + * @param T The type of the value. + * @property decomposeValue The Decompose Value to be wrapped. + */ +internal class ValueStateFlow( + private val decomposeValue: Value, +) : StateFlow { + + override val value: T + get() = decomposeValue.value + + override val replayCache: List = listOf(value) + + override suspend fun collect(collector: FlowCollector): Nothing { + val relay = MutableStateFlow(decomposeValue.value) + val cancellation = decomposeValue.subscribe { value -> relay.value = value } + + try { + relay.collect(collector) + } finally { + cancellation.cancel() + } + } +} diff --git a/shared/arkitekt-decompose/src/commonMain/kotlin/app/futured/arkitekt/decompose/ext/DecomposeValueExt.kt b/shared/arkitekt-decompose/src/commonMain/kotlin/app/futured/arkitekt/decompose/ext/DecomposeValueExt.kt index 99863fa..62f5722 100644 --- a/shared/arkitekt-decompose/src/commonMain/kotlin/app/futured/arkitekt/decompose/ext/DecomposeValueExt.kt +++ b/shared/arkitekt-decompose/src/commonMain/kotlin/app/futured/arkitekt/decompose/ext/DecomposeValueExt.kt @@ -1,43 +1,13 @@ package app.futured.arkitekt.decompose.ext +import app.futured.arkitekt.decompose.coroutines.ValueStateFlow import com.arkivanov.decompose.value.Value -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.channels.awaitClose -import kotlinx.coroutines.channels.trySendBlocking -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.callbackFlow -import kotlinx.coroutines.flow.stateIn - -/** - * Converts this Decompose [Value] to Kotlin [Flow]. - * - * @param T The type of the value. - * @return A [Flow] emitting the values of the Decompose [Value]. - */ -fun Value.asFlow(): Flow = callbackFlow { - val cancellation = subscribe { value -> - trySendBlocking(value) - } - - awaitClose { - cancellation.cancel() - } -} /** * Converts this Decompose [Value] to Kotlin [StateFlow]. * * @param T The type of the value. - * @param coroutineScope The [CoroutineScope] in which the [StateFlow] is active. - * @return A [StateFlow] emitting the values of the [Value]. + * @return A [StateFlow] emitting the values of this [Value]. */ -fun Value.asStateFlow( - coroutineScope: CoroutineScope, -): StateFlow = asFlow() - .stateIn( - scope = coroutineScope, - started = SharingStarted.Lazily, - initialValue = value, - ) +fun Value.asStateFlow(): StateFlow = ValueStateFlow(decomposeValue = this) diff --git a/shared/feature/src/commonMain/kotlin/app/futured/kmptemplate/feature/navigation/home/HomeNavHostComponent.kt b/shared/feature/src/commonMain/kotlin/app/futured/kmptemplate/feature/navigation/home/HomeNavHostComponent.kt index 3c90d58..5521d39 100644 --- a/shared/feature/src/commonMain/kotlin/app/futured/kmptemplate/feature/navigation/home/HomeNavHostComponent.kt +++ b/shared/feature/src/commonMain/kotlin/app/futured/kmptemplate/feature/navigation/home/HomeNavHostComponent.kt @@ -73,5 +73,5 @@ internal class HomeNavHostComponent( ) } }, - ).asStateFlow(componentCoroutineScope) + ).asStateFlow() } diff --git a/shared/feature/src/commonMain/kotlin/app/futured/kmptemplate/feature/navigation/profile/ProfileNavHostComponent.kt b/shared/feature/src/commonMain/kotlin/app/futured/kmptemplate/feature/navigation/profile/ProfileNavHostComponent.kt index 38ebf53..f5d760c 100644 --- a/shared/feature/src/commonMain/kotlin/app/futured/kmptemplate/feature/navigation/profile/ProfileNavHostComponent.kt +++ b/shared/feature/src/commonMain/kotlin/app/futured/kmptemplate/feature/navigation/profile/ProfileNavHostComponent.kt @@ -41,7 +41,7 @@ internal class ProfileNavHostComponent( ) } }, - ).asStateFlow(componentCoroutineScope) + ).asStateFlow() override val actions: ProfileNavHost.Actions = object : ProfileNavHost.Actions { override fun pop() = stackNavigator.pop() diff --git a/shared/feature/src/commonMain/kotlin/app/futured/kmptemplate/feature/navigation/root/RootNavHostComponent.kt b/shared/feature/src/commonMain/kotlin/app/futured/kmptemplate/feature/navigation/root/RootNavHostComponent.kt index 4a2fcff..861e7d9 100644 --- a/shared/feature/src/commonMain/kotlin/app/futured/kmptemplate/feature/navigation/root/RootNavHostComponent.kt +++ b/shared/feature/src/commonMain/kotlin/app/futured/kmptemplate/feature/navigation/root/RootNavHostComponent.kt @@ -61,7 +61,7 @@ internal class RootNavHostComponent( ) } }, - ).asStateFlow(coroutineScope = componentCoroutineScope) + ).asStateFlow() init { doOnCreate { diff --git a/shared/feature/src/commonMain/kotlin/app/futured/kmptemplate/feature/navigation/signedIn/SignedInNavHostComponent.kt b/shared/feature/src/commonMain/kotlin/app/futured/kmptemplate/feature/navigation/signedIn/SignedInNavHostComponent.kt index 8e14e83..fd0a98e 100644 --- a/shared/feature/src/commonMain/kotlin/app/futured/kmptemplate/feature/navigation/signedIn/SignedInNavHostComponent.kt +++ b/shared/feature/src/commonMain/kotlin/app/futured/kmptemplate/feature/navigation/signedIn/SignedInNavHostComponent.kt @@ -54,7 +54,7 @@ internal class SignedInNavHostComponent( ) } }, - ).asStateFlow(componentCoroutineScope) + ).asStateFlow() override val viewState: StateFlow = componentState.combine(stack) { state, stack -> state.copy( diff --git a/shared/feature/src/commonMain/kotlin/app/futured/kmptemplate/feature/ui/secondScreen/SecondComponent.kt b/shared/feature/src/commonMain/kotlin/app/futured/kmptemplate/feature/ui/secondScreen/SecondComponent.kt index 1d8ba0f..970d067 100644 --- a/shared/feature/src/commonMain/kotlin/app/futured/kmptemplate/feature/ui/secondScreen/SecondComponent.kt +++ b/shared/feature/src/commonMain/kotlin/app/futured/kmptemplate/feature/ui/secondScreen/SecondComponent.kt @@ -22,9 +22,9 @@ internal class SecondComponent( @InjectedParam componentContext: AppComponentContext, @InjectedParam override val navigation: SecondScreenNavigation, ) : ScreenComponent( - componentContext = componentContext, - defaultState = SecondViewState, - ), + componentContext = componentContext, + defaultState = SecondViewState, +), SecondScreen { override val viewState: StateFlow = componentState @@ -55,7 +55,7 @@ internal class SecondComponent( ) } }, - ).asStateFlow(componentCoroutineScope) + ).asStateFlow() override val actions: SecondScreen.Actions = object : SecondScreen.Actions { override fun onBack() = navigation.pop()