Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replaced Cancelable with AutoCloseable #9

Merged
merged 1 commit into from
Feb 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,16 @@ import androidx.lifecycle.ViewModelStoreOwner
import com.arkivanov.essenty.instancekeeper.InstanceKeeper
import com.arkivanov.essenty.instancekeeper.getOrCreate
import com.arkivanov.essenty.instancekeeper.instanceKeeper
import kotlinx.coroutines.flow.StateFlow
import io.github.ikarenkov.kombucha.Cancelable
import io.github.ikarenkov.kombucha.store.Store
import kotlinx.coroutines.flow.StateFlow

/**
* This interface provides Ui related part of TEA for compose.
* @param UiMsg - messages that can be dispatched to store
* @param Model - model of screen that can be observed
* @param UiEff - single event effects that can be consumed by compose screen (WIP)
*/
interface ComposeKombucha<UiMsg : Any, Model : Any, UiEff : Any> : Cancelable {
interface ComposeKombucha<UiMsg : Any, Model : Any, UiEff : Any> : AutoCloseable {

fun accept(msg: UiMsg)

Expand All @@ -32,8 +31,8 @@ open class ComposeKombuchaImpl<Msg : Any, UiMsg : Msg, Model : Any, Eff : Any, U
store.accept(msg)
}

override fun cancel() {
store.cancel()
override fun close() {
store.close()
}

}
Expand All @@ -42,7 +41,7 @@ class ComposeKombuchaInstance<UiMsg : Any, Model : Any, UiEff : Any>(
composeKombucha: ComposeKombucha<UiMsg, Model, UiEff>
) : ComposeKombucha<UiMsg, Model, UiEff> by composeKombucha, InstanceKeeper.Instance {
override fun onDestroy() {
cancel()
close()
}
}

Expand Down

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ abstract class AggregatorStore<Msg : Any, State : Any, Eff : Any>(
coroutineExceptionHandler: CoroutineExceptionHandler = DefaultStoreCoroutineExceptionHandler()
) : this(StoreScope(name, coroutineExceptionHandler))

override fun cancel() {
override fun close() {
coroutineScope.cancel()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,10 @@ class TwoStoreAggregatorStore<
}
}

override fun cancel() {
super.cancel()
store1.cancel()
store2.cancel()
override fun close() {
super.close()
store1.close()
store2.close()
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ open class CoroutinesStore<Msg : Any, State : Any, Eff : Any>(

override fun accept(msg: Msg) {
if (!isActive) {
error("Trying to call accept in canceled store with name \"$name\".")
error("Trying to call accept in closed store with name \"$name\".")
}
coroutinesScope.launch {
val storeUpdate = stateUpdateMutex.withLock {
Expand Down Expand Up @@ -90,7 +90,7 @@ open class CoroutinesStore<Msg : Any, State : Any, Eff : Any>(
}
}

override fun cancel() {
override fun close() {
coroutinesScope.cancel()
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
package io.github.ikarenkov.kombucha.store

import io.github.ikarenkov.kombucha.Cancelable
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.StateFlow

/**
* The base component of library that hold state and converst incoming [Msg] to a new [State] and [Eff].
* Take a look and the main implementation: [CoroutinesStore]
*/
interface Store<Msg : Any, State : Any, Eff : Any> : Cancelable {
@OptIn(ExperimentalStdlibApi::class)
interface Store<Msg : Any, State : Any, Eff : Any> : AutoCloseable {

/**
* Represent current state of this store. Can be modified only through [accept].
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFails

class CoroutinesStoreCancellationTest {
class CoroutinesStoreCloseTest {

@Test
@JsName("test1")
fun `When accept on canceled store - Then crush`() {
val store = NoOpTestStore()
store.accept(Any())
store.cancel()
store.close()
assertFails {
store.accept(Any())
}
Expand All @@ -22,7 +22,7 @@ class CoroutinesStoreCancellationTest {
@JsName("test2")
fun `When canceled - Then isActive false`() {
val store = NoOpTestStore()
store.cancel()
store.close()
assertEquals(false, store.isActive)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ private class StoreInstance<out T : Store<*, *, *>>(
) : InstanceKeeper.Instance {

override fun onDestroy() {
store.cancel()
store.close()
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,14 @@ import kotlinx.coroutines.isActive
* Wrapper for store, that allows handle basic UI scenarios:
* 1. Convert models to Ui Models
* 2. Cache ui effects when there is no subscribers and emit cached effects with a first subscription
* @param cancelOriginalStoreOnCancel shows if we need to call [Store.cancel] on the [store] when this store is canceling.
* @param propagateCloseToOriginal shows if we need to call [Store.close] on the [store] when this store is closed.
*/
class UiStore<UiMsg : Any, UiState : Any, UiEff : Any, Msg : Any, State : Any, Eff : Any>(
private val store: Store<Msg, State, Eff>,
private val uiMsgToMsgConverter: (UiMsg) -> Msg,
private val uiStateConverter: (State) -> UiState,
private val uiEffConverter: (Eff) -> UiEff?,
private val cancelOriginalStoreOnCancel: Boolean = true,
private val propagateCloseToOriginal: Boolean = true,
coroutineExceptionHandler: CoroutineExceptionHandler = DefaultStoreCoroutineExceptionHandler(),
uiDispatcher: CoroutineDispatcher = Dispatchers.Main,
cacheUiEffects: Boolean = true,
Expand Down Expand Up @@ -64,10 +64,10 @@ class UiStore<UiMsg : Any, UiState : Any, UiEff : Any, Msg : Any, State : Any, E
store.accept(uiMsgToMsgConverter(msg))
}

override fun cancel() {
override fun close() {
coroutineScope.cancel()
if (cancelOriginalStoreOnCancel) {
store.cancel()
if (propagateCloseToOriginal) {
store.close()
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@ class UiStoreBuilder<Msg : Any, State : Any, Eff : Any>(
uiStateConverter: (State) -> UiState,
uiEffConverter: (Eff) -> UiEff?,
cacheUiEffects: Boolean = true,
cancelOriginalStoreOnCancel: Boolean = true,
propagateCloseToOriginal: Boolean = true,
uiDispatcher: CoroutineDispatcher = Dispatchers.Main,
): UiStore<UiMsg, UiState, UiEff, Msg, State, Eff> = UiStore(
store = store,
uiMsgToMsgConverter = uiMsgToMsgConverter,
uiStateConverter = uiStateConverter,
uiEffConverter = uiEffConverter,
cancelOriginalStoreOnCancel = cancelOriginalStoreOnCancel,
propagateCloseToOriginal = propagateCloseToOriginal,
cacheUiEffects = cacheUiEffects,
uiDispatcher = uiDispatcher
)
Expand All @@ -34,7 +34,7 @@ class UiStoreBuilder<Msg : Any, State : Any, Eff : Any>(
*/
inline fun <UiMsg : Msg, UiState : Any, reified UiEff : Eff> using(
cacheUiEffects: Boolean = true,
cancelOriginalStoreOnCancel: Boolean = true,
propagateCloseToOriginal: Boolean = true,
uiDispatcher: CoroutineDispatcher = Dispatchers.Main,
noinline uiStateConverter: (State) -> UiState,
): UiStore<UiMsg, UiState, UiEff, Msg, State, Eff> = UiStore(
Expand All @@ -43,7 +43,7 @@ class UiStoreBuilder<Msg : Any, State : Any, Eff : Any>(
uiStateConverter = uiStateConverter,
uiEffConverter = { it as? UiEff },
uiDispatcher = uiDispatcher,
cancelOriginalStoreOnCancel = cancelOriginalStoreOnCancel,
propagateCloseToOriginal = propagateCloseToOriginal,
cacheUiEffects = cacheUiEffects
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,30 +12,30 @@ class UiStoreTest {

@Test
@JsName("test1")
fun `When cancel original is false - original is not canceled`() {
fun `When close original is false - original is not closed`() {
val store = DummyStore()
val uiStore = store.uiBuilder()
.using<Any, Any, Any>(
cancelOriginalStoreOnCancel = false,
propagateCloseToOriginal = false,
uiDispatcher = StandardTestDispatcher()
) { it }

uiStore.cancel()
uiStore.close()

assertTrue(store.isActive)
}

@Test
@JsName("test2")
fun `When cancel original is true - original is canceled`() {
fun `When close original is true - original is closed`() {
val store = DummyStore()
val uiStore = store.uiBuilder()
.using<Any, Any, Any>(
cancelOriginalStoreOnCancel = true,
propagateCloseToOriginal = true,
uiDispatcher = StandardTestDispatcher()
) { it }

uiStore.cancel()
uiStore.close()

assertFalse(store.isActive)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class ModoKombuchaScreenModel<UiMsg : Any, UiState : Any, UiEff : Any>(
) : ScreenModel {

override fun onDispose() {
store.cancel()
store.close()
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ internal class CounterScreenModel(
val state = store.state

override fun onDispose() {
store.cancel()
store.close()
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ internal class AnimesScreenModel(
val store = animesStoreAgregatorFactory.createStore()

override fun onDispose() {
store.cancel()
store.close()
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,10 @@ internal class AnimesAggregatorStore(
}
}

override fun cancel() {
super.cancel()
paginationStore.cancel()
animesStore.cancel()
override fun close() {
super.close()
paginationStore.close()
animesStore.close()
}

data class State(
Expand Down