diff --git a/CHANGELOG.md b/CHANGELOG.md index 577c3a4328f..0d4c555406c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,8 +5,9 @@ * `Common`: * New extensions `Element#onVisibilityChanged`, `Element#onVisible` and `Element#onInvisible` * `Coroutines`: - * New extension `Element.visibilityFlow()` - + * New extension `Element.visibilityFlow()` +* `FSM`: + * Now it is possible to resolve conflicts on `startChain` ## 0.9.16 diff --git a/fsm/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/common/managers/DefaultStatesManager.kt b/fsm/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/common/managers/DefaultStatesManager.kt index 4c67a5fbd31..30b899da341 100644 --- a/fsm/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/common/managers/DefaultStatesManager.kt +++ b/fsm/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/common/managers/DefaultStatesManager.kt @@ -39,13 +39,14 @@ interface DefaultStatesManagerRepo { * @param repo This repo will be used as repository for storing states. All operations with this repo will happen BEFORE * any event will be sent to [onChainStateUpdated], [onStartChain] or [onEndChain]. By default, will be used * [InMemoryDefaultStatesManagerRepo] or you may create custom [DefaultStatesManagerRepo] and pass as [repo] parameter - * @param onContextsConflictResolver Receive old [State], new one and the state currently placed on new [State.context] + * @param onUpdateContextsConflictResolver Receive old [State], new one and the state currently placed on new [State.context] * key. In case when this callback will returns true, the state placed on [State.context] of new will be replaced by * new state by using [endChain] with that state */ open class DefaultStatesManager( protected val repo: DefaultStatesManagerRepo = InMemoryDefaultStatesManagerRepo(), - protected val onContextsConflictResolver: suspend (old: T, new: T, currentNew: T) -> Boolean = { _, _, _ -> true } + protected val onStartContextsConflictResolver: suspend (old: T, new: T) -> Boolean = { _, _ -> true }, + protected val onUpdateContextsConflictResolver: suspend (old: T, new: T, currentNew: T) -> Boolean = { _, _, _ -> true } ) : StatesManager { protected val _onChainStateUpdated = MutableSharedFlow>(0) override val onChainStateUpdated: Flow> = _onChainStateUpdated.asSharedFlow() @@ -56,6 +57,14 @@ open class DefaultStatesManager( protected val mapMutex = Mutex() + constructor( + repo: DefaultStatesManagerRepo, + onContextsConflictResolver: suspend (old: T, new: T, currentNew: T) -> Boolean + ) : this ( + repo, + onUpdateContextsConflictResolver = onContextsConflictResolver + ) + override suspend fun update(old: T, new: T) = mapMutex.withLock { val stateByOldContext: T? = repo.getContextState(old.context) when { @@ -67,7 +76,7 @@ open class DefaultStatesManager( } else -> { val stateOnNewOneContext = repo.getContextState(new.context) - if (stateOnNewOneContext == null || onContextsConflictResolver(old, new, stateOnNewOneContext)) { + if (stateOnNewOneContext == null || onUpdateContextsConflictResolver(old, new, stateOnNewOneContext)) { stateOnNewOneContext ?.let { endChainWithoutLock(it) } repo.removeState(old) repo.set(new) @@ -78,7 +87,11 @@ open class DefaultStatesManager( } override suspend fun startChain(state: T) = mapMutex.withLock { - if (!repo.contains(state.context)) { + val stateOnContext = repo.getContextState(state.context) + if (stateOnContext == null || onStartContextsConflictResolver(stateOnContext, state)) { + stateOnContext ?.let { + endChainWithoutLock(it) + } repo.set(state) _onStartChain.emit(state) } diff --git a/fsm/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/common/managers/InMemoryStatesManager.kt b/fsm/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/common/managers/InMemoryStatesManager.kt index 323e895b315..3cfe75323ad 100644 --- a/fsm/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/common/managers/InMemoryStatesManager.kt +++ b/fsm/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/common/managers/InMemoryStatesManager.kt @@ -12,5 +12,6 @@ import kotlinx.coroutines.flow.* */ @Deprecated("Use DefaultStatesManager instead", ReplaceWith("DefaultStatesManager")) fun InMemoryStatesManager( - onContextsConflictResolver: suspend (old: T, new: T, currentNew: T) -> Boolean = { _, _, _ -> true } -) = DefaultStatesManager(onContextsConflictResolver = onContextsConflictResolver) + onStartContextsConflictResolver: suspend (old: T, new: T) -> Boolean = { _, _ -> true }, + onUpdateContextsConflictResolver: suspend (old: T, new: T, currentNew: T) -> Boolean = { _, _, _ -> true } +) = DefaultStatesManager(onStartContextsConflictResolver = onStartContextsConflictResolver, onUpdateContextsConflictResolver = onUpdateContextsConflictResolver)