Skip to content

Commit

Permalink
- remove PreInitEffect
Browse files Browse the repository at this point in the history
- refactor naming
- release 1.1.0
  • Loading branch information
pavelannin committed Jan 20, 2024
1 parent f1697ad commit 7cf7572
Show file tree
Hide file tree
Showing 19 changed files with 97 additions and 178 deletions.
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
# v1.1.0
## Core
- Renamed the `init` parameter to `start` from `StoreParams`
- Removed `PreInitEffect` from `StoreParams`
- Renamed `previous` to `savedState` from `Start`

## Decompose
- Renamed `KeemunComponentFeatureConnector` to `KeemunComponentConnector`

## SwiftUI
- Renamed `KeemunNativeFeatureConnector` to `KeemunNativeConnector`


# v1.0.1
- Optimization of swiftui connector dependencies

Expand Down
18 changes: 3 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,22 +138,11 @@ val effectHandler = EffectHandler<Effect, InternalMsg> { effect, dispatch ->
}
```

## PreInitEffect
`PreInitEffect` is the place where logic necessary for initializing the `Store` is executed. `PreInitEffect` returns a type that is later
used for initialization. In most scenarios, there is no need to use `PreInitEffect`.

**NOTE** `EffectHandler` is a suspend function that **blocks** the current thread.

```kotlin
val preInitEffect = PreInitEffect { fetchCachedCounter() }
```

## Init
`Init` is the place for initialization. Its method takes `previousState` (if the state is being persisted) and `deps` (optionally received
from `PreInitEffect`), and returns the initializing `state` and the initial set of side-effects.
`Init` is the place for initialization. Its method takes `previousState` (if the state is being persisted), and returns the initializing `state` and the initial set of side-effects.

```kotlin
val init = Init<CounterState, CounterEffect, Int> { previous, deps ->
val init = Init<CounterState, CounterEffect> { previous ->
val state = previous ?: CounterState(
syncCount = deps,
asyncCount = deps,
Expand All @@ -164,12 +153,11 @@ val init = Init<CounterState, CounterEffect, Int> { previous, deps ->
```

## StoreParams
`StoreParams` is a container that holds `PreInitEffect`, `Init`, `Update`, and `EffectHandler` in one place for creating a `Store`.
`StoreParams` is a container that holds `Init`, `Update`, and `EffectHandler` in one place for creating a `Store`.
`StoreParams` provides several convenient overridden functions for creating it with optional arguments.

```kotlin
val storeParams = StoreParams<State, Msg, Effect, Deps>(
preEffectInit = { },
init = { },
update = { },
effectHandler = { },
Expand Down
2 changes: 1 addition & 1 deletion connectors/decompose/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ mavenPublishing {
val artifactId = "keemun-decompose"
publishToMavenCentral(SonatypeHost.S01)
signAllPublications()
coordinates("io.github.pavelannin", artifactId, "1.0.1")
coordinates("io.github.pavelannin", artifactId, "1.1.0")
pom {
name.set(artifactId)
description.set("Keemun is a multiplatform Kotlin framework that provides a way to write shared code using The Elm Architecture pattern.")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,66 +19,66 @@ import kotlinx.serialization.serializer
*
* @see FeatureConnector
*/
interface KeemunComponentFeatureConnector<State : Any, Msg : Any> : ComponentContext, CoroutineScopeOwner, FeatureConnector<State, Msg>
interface KeemunComponentConnector<State : Any, Msg : Any> : ComponentContext, CoroutineScopeOwner, FeatureConnector<State, Msg>

/**
* Creates a [KeemunComponentFeatureConnector].
* Creates a [KeemunComponentConnector].
*
* @param componentContext The context for aggregating the creation of [KeemunComponentFeatureConnector].
* @param componentContext The context for aggregating the creation of [KeemunComponentConnector].
* @param storeCreator The function for creating the [Store].
* @param stateSerializer The serializer used for saving and restoring the state.
*
* @see KeemunComponentFeatureConnector
* @see KeemunComponentConnector
*/
fun <State : Any, Msg : Any> KeemunComponentFeatureConnector(
fun <State : Any, Msg : Any> KeemunComponentConnector(
componentContext: ComponentContext,
storeCreator: (previousState: State?, scope: CoroutineScope) -> Lazy<Store<State, Msg>>,
storeCreator: (savedState: State?, scope: CoroutineScope) -> Lazy<Store<State, Msg>>,
stateSerializer: KSerializer<State>,
): KeemunComponentFeatureConnector<State, Msg> = DefaultComponentFeatureConnector(
): KeemunComponentConnector<State, Msg> = DefaultComponentConnector(
componentContext = componentContext,
storeCreator = storeCreator,
stateSerializer = stateSerializer,
)

/**
* Creates a [KeemunComponentFeatureConnector].
* Creates a [KeemunComponentConnector].
*
* @param componentContext The context for aggregating the creation of [KeemunComponentFeatureConnector].
* @param componentContext The context for aggregating the creation of [KeemunComponentConnector].
* @param storeCreator The function for creating the [Store].
*
* @see KeemunComponentFeatureConnector
* @see KeemunComponentConnector
*/
@OptIn(InternalSerializationApi::class)
inline fun <reified State : Any, Msg : Any> KeemunComponentFeatureConnector(
inline fun <reified State : Any, Msg : Any> KeemunComponentConnector(
componentContext: ComponentContext,
noinline storeCreator: (previousState: State?, scope: CoroutineScope) -> Lazy<Store<State, Msg>>,
) = KeemunComponentFeatureConnector(
noinline storeCreator: (savedState: State?, scope: CoroutineScope) -> Lazy<Store<State, Msg>>,
) = KeemunComponentConnector(
componentContext = componentContext,
storeCreator = storeCreator,
stateSerializer = State::class.serializer(),
)

/**
* Creates a [KeemunComponentFeatureConnector].
* Creates a [KeemunComponentConnector].
*
* @param componentContext The context for aggregating the creation of [KeemunComponentFeatureConnector].
* @param componentContext The context for aggregating the creation of [KeemunComponentConnector].
* @param featureParams Parameters used for creation.
* @param stateSerializer The serializer used for saving and restoring the state.
*
* @see KeemunComponentFeatureConnector
* @see KeemunComponentConnector
*/
@OptIn(InternalSerializationApi::class)
inline fun <reified State : Any, Msg : Any, ViewState : Any, ExternalMsg : Msg> KeemunComponentFeatureConnector(
inline fun <reified State : Any, Msg : Any, ViewState : Any, ExternalMsg : Msg> KeemunComponentConnector(
componentContext: ComponentContext,
featureParams: FeatureParams<State, Msg, ViewState, ExternalMsg>,
stateSerializer: KSerializer<State> = State::class.serializer(),
): KeemunComponentFeatureConnector<ViewState, ExternalMsg> = object : KeemunComponentFeatureConnector<ViewState, ExternalMsg>,
): KeemunComponentConnector<ViewState, ExternalMsg> = object : KeemunComponentConnector<ViewState, ExternalMsg>,
ComponentContext by componentContext,
CoroutineScopeOwner by componentContext.CoroutineScopeOwner(),
Store<ViewState, ExternalMsg> by KeemunComponentFeatureConnector(
Store<ViewState, ExternalMsg> by KeemunComponentConnector(
componentContext = componentContext,
storeCreator = { previousState, scope ->
lazy { Store(previousState = previousState, params = featureParams.storeParams, coroutineScope = scope) }.let { lazyStore ->
storeCreator = { savedState, scope ->
lazy { Store(savedState = savedState, params = featureParams.storeParams, coroutineScope = scope) }.let { lazyStore ->
when (featureParams.startedOptions) {
FeatureStartedOptions.Eagerly -> lazyStore.apply { value }
FeatureStartedOptions.Lazily -> lazyStore
Expand All @@ -91,11 +91,11 @@ inline fun <reified State : Any, Msg : Any, ViewState : Any, ExternalMsg : Msg>
messageTransform = featureParams.externalMessageTransform,
){}

private class DefaultComponentFeatureConnector<State : Any, Msg : Any>(
private class DefaultComponentConnector<State : Any, Msg : Any>(
componentContext: ComponentContext,
storeCreator: (previousState: State?, scope: CoroutineScope) -> Lazy<Store<State, Msg>>,
storeCreator: (savedState: State?, scope: CoroutineScope) -> Lazy<Store<State, Msg>>,
stateSerializer: KSerializer<State>,
) : KeemunComponentFeatureConnector<State, Msg>,
) : KeemunComponentConnector<State, Msg>,
ComponentContext by componentContext,
CoroutineScopeOwner by componentContext.CoroutineScopeOwner(),
Store<State, Msg> {
Expand Down
2 changes: 1 addition & 1 deletion connectors/swift-ui/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ mavenPublishing {
val artifactId = "keemun-swiftui"
publishToMavenCentral(SonatypeHost.S01)
signAllPublications()
coordinates("io.github.pavelannin", artifactId, "1.0.1")
coordinates("io.github.pavelannin", artifactId, "1.1.0")
pom {
name.set(artifactId)
description.set("Keemun is a multiplatform Kotlin framework that provides a way to write shared code using The Elm Architecture pattern.")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import kotlinx.coroutines.withContext
*
* @see FeatureConnector
*/
class KeemunNativeFeatureConnector<State : Any, Msg : Any> (
class KeemunNativeConnector<State : Any, Msg : Any> (
storeCreator: (scope: CoroutineScope) -> Lazy<Store<State, Msg>>,
): FeatureConnector<State, Msg>, CoroutineScope by CoroutineScope(Dispatchers.Default) {
private val store by storeCreator(this)
Expand All @@ -44,18 +44,18 @@ class KeemunNativeFeatureConnector<State : Any, Msg : Any> (
}

/**
* Creates a [KeemunNativeFeatureConnector].
* Creates a [KeemunNativeConnector].
*
* @param featureParams Parameters used for creation.
*
* @see KeemunNativeFeatureConnector
* @see KeemunNativeConnector
*/
inline fun <reified State : Any, Msg : Any, ViewState : Any, ExternalMsg : Msg> KeemunNativeFeatureConnector(
inline fun <reified State : Any, Msg : Any, ViewState : Any, ExternalMsg : Msg> KeemunNativeConnector(
featureParams: FeatureParams<State, Msg, ViewState, ExternalMsg>,
) = KeemunNativeFeatureConnector(
): KeemunNativeConnector<ViewState, ExternalMsg> = KeemunNativeConnector(
storeCreator = { scope ->
lazy {
Store(previousState = null, params = featureParams.storeParams, coroutineScope = scope)
Store(savedState = null, params = featureParams.storeParams, coroutineScope = scope)
.transform(stateTransform = featureParams.viewStateTransform, messageTransform = featureParams.externalMessageTransform)
}.let { lazyStore ->
when (featureParams.startedOptions) {
Expand Down
2 changes: 1 addition & 1 deletion core/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ mavenPublishing {
val artifactId = "keemun-core"
publishToMavenCentral(SonatypeHost.S01)
signAllPublications()
coordinates("io.github.pavelannin", artifactId, "1.0.1")
coordinates("io.github.pavelannin", artifactId, "1.1.0")
pom {
name.set(artifactId)
description.set("Keemun is a multiplatform Kotlin framework that provides a way to write shared code using The Elm Architecture pattern.")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,10 @@ package io.github.pavelannin.keemun.core
import kotlinx.coroutines.CoroutineScope
import kotlin.native.HiddenFromObjC

/** Effect that will return the necessary dependencies to initialize the state. */
/** Returns default state and effects by previous state. */
@HiddenFromObjC
fun interface PreInitEffect<out Deps> {
suspend operator fun invoke(): Deps
}

/** Returns default state and effects by previous state and dependencies. */
@HiddenFromObjC
fun interface Init<State, out Effect, in Deps> {
operator fun invoke(previous: State?, deps: Deps): Pair<State, Set<Effect>>
fun interface Start<State, out Effect> {
operator fun invoke(savedState: State?): Pair<State, Set<Effect>>
}

/** Creates a next state and side-effects from a message and current state. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import kotlin.native.ObjCName
*/
@ObjCName(swiftName = "KeemunFeatureParams")
data class FeatureParams<State : Any, Msg : Any, ViewState : Any, ExternalMsg : Any>(
val storeParams: StoreParams<State, Msg, *, *>,
val storeParams: StoreParams<State, Msg, *>,
val viewStateTransform: StateTransform<State, ViewState>,
val externalMessageTransform: (ExternalMsg) -> Msg,
val startedOptions: FeatureStartedOptions,
Expand All @@ -31,10 +31,10 @@ data class FeatureParams<State : Any, Msg : Any, ViewState : Any, ExternalMsg :
/** @see FeatureParams */
@HiddenFromObjC
inline fun <State : Any, Msg : Any, ViewState : Any, ExternalMsg : Msg> FeatureParams(
storeParams: StoreParams<State, Msg, *, *>,
storeParams: StoreParams<State, Msg, *>,
viewStateTransform: StateTransform<State, ViewState>,
startedOptions: FeatureStartedOptions = FeatureStartedOptions.Lazily,
) = FeatureParams<State, Msg, ViewState, ExternalMsg>(
): FeatureParams<State, Msg, ViewState, ExternalMsg> = FeatureParams(
storeParams = storeParams,
viewStateTransform = viewStateTransform,
externalMessageTransform = { it },
Expand All @@ -44,10 +44,10 @@ inline fun <State : Any, Msg : Any, ViewState : Any, ExternalMsg : Msg> FeatureP
/** @see FeatureParams */
@HiddenFromObjC
inline fun <State : Any, Msg : Any, ExternalMsg : Any> FeatureParams(
storeParams: StoreParams<State, Msg, *, *>,
storeParams: StoreParams<State, Msg, *>,
noinline externalMessageTransform: (ExternalMsg) -> Msg,
startedOptions: FeatureStartedOptions = FeatureStartedOptions.Lazily,
) = FeatureParams<State, Msg, State, ExternalMsg>(
): FeatureParams<State, Msg, State, ExternalMsg> = FeatureParams(
storeParams = storeParams,
viewStateTransform = { it },
externalMessageTransform = externalMessageTransform,
Expand All @@ -57,9 +57,9 @@ inline fun <State : Any, Msg : Any, ExternalMsg : Any> FeatureParams(
/** @see FeatureParams */
@HiddenFromObjC
inline fun <State : Any, Msg : Any, ExternalMsg : Msg> FeatureParams(
storeParams: StoreParams<State, Msg, *, *>,
storeParams: StoreParams<State, Msg, *>,
startedOptions: FeatureStartedOptions = FeatureStartedOptions.Lazily,
) = FeatureParams<State, Msg, State, ExternalMsg>(
): FeatureParams<State, Msg, State, ExternalMsg> = FeatureParams(
storeParams = storeParams,
viewStateTransform = { it },
externalMessageTransform = { it },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.onSubscription
import kotlinx.coroutines.launch
import kotlinx.coroutines.plus
import kotlinx.coroutines.runBlocking
import kotlin.native.HiddenFromObjC
import kotlin.native.ObjCName

Expand All @@ -36,27 +35,27 @@ interface Store<out State : Any, in Msg : Any> {
/**
* Creates an implementation of [Store].
*
* @param previousState Previous state. Not null if the process was killed by the system and restored to its previous state.
* @param savedState Previous saved state. Not null if the process was killed by the system and restored to its previous state.
* @param params Parameters for creating [Store].
* @param coroutineScope The main scope on which all coroutines will be launched.
*
* @see Store
*/
@HiddenFromObjC
fun <State : Any, Msg : Any, Effect : Any, Deps : Any> Store(
previousState: State?,
params: StoreParams<State, Msg, Effect, Deps>,
fun <State : Any, Msg : Any, Effect : Any> Store(
savedState: State?,
params: StoreParams<State, Msg, Effect>,
coroutineScope: CoroutineScope,
): Store<State, Msg> = DefaultStore(
previousState = previousState,
savedState = savedState,
params = params,
coroutineScope = coroutineScope,
)

@HiddenFromObjC
private class DefaultStore<State : Any, in Msg : Any, in Effect : Any, in Deps : Any>(
previousState: State?,
private val params: StoreParams<State, Msg, Effect, Deps>,
private class DefaultStore<State : Any, in Msg : Any, in Effect : Any>(
savedState: State?,
private val params: StoreParams<State, Msg, Effect>,
coroutineScope: CoroutineScope,
) : Store<State, Msg> {
private val _state: MutableStateFlow<State>
Expand All @@ -66,7 +65,7 @@ private class DefaultStore<State : Any, in Msg : Any, in Effect : Any, in Deps :
override val scope: CoroutineScope = coroutineScope + Dispatchers.Default

init {
val (defaultState, startEffects) = runBlocking { params.init(previousState, params.preEffectInit()) }
val (defaultState, startEffects) = params.start(savedState)
_state = MutableStateFlow(value = defaultState)
scope.launch { observeMessages(scope = this, defaultState, startEffects) }
}
Expand Down
Loading

0 comments on commit 7cf7572

Please sign in to comment.