From 2bfd615812a1809fa8641b710f539634333388c5 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Mon, 4 Dec 2023 15:01:42 +0600 Subject: [PATCH 1/4] start 0.20.18 --- CHANGELOG.md | 2 ++ gradle.properties | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e5f34040492..c676b569b69 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ # Changelog +## 0.20.18 + ## 0.20.17 * `Versions`: diff --git a/gradle.properties b/gradle.properties index 68aa34ac761..28a0c89171f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -15,5 +15,5 @@ crypto_js_version=4.1.1 # Project data group=dev.inmo -version=0.20.17 -android_code_version=223 +version=0.20.18 +android_code_version=224 From f3f9920bfb4aab8138230599b62cea27f1fd6d2f Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Mon, 4 Dec 2023 15:08:52 +0600 Subject: [PATCH 2/4] deprecate FlowState --- CHANGELOG.md | 4 ++++ .../dev/inmo/micro_utils/coroutines/compose/FlowState.kt | 1 + 2 files changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c676b569b69..6b2f1eb4d46 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## 0.20.18 +* `Coroutines`: + * `Compose`: + * Deprecate `FlowState` due to its complexity in fixes + ## 0.20.17 * `Versions`: diff --git a/coroutines/compose/src/commonMain/kotlin/dev/inmo/micro_utils/coroutines/compose/FlowState.kt b/coroutines/compose/src/commonMain/kotlin/dev/inmo/micro_utils/coroutines/compose/FlowState.kt index 487f1065564..99c8ae1b58f 100644 --- a/coroutines/compose/src/commonMain/kotlin/dev/inmo/micro_utils/coroutines/compose/FlowState.kt +++ b/coroutines/compose/src/commonMain/kotlin/dev/inmo/micro_utils/coroutines/compose/FlowState.kt @@ -12,6 +12,7 @@ import kotlinx.coroutines.Dispatchers * This type works like [MutableState], [kotlinx.coroutines.flow.StateFlow] and [kotlinx.coroutines.flow.MutableSharedFlow]. * Based on [SpecialMutableStateFlow] */ +@Deprecated("Will be removed soon") class FlowState( initial: T, internalScope: CoroutineScope = CoroutineScope(Dispatchers.Default) From 43e782ab6f31c3b0cf7b10374a3a72939164a9da Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Mon, 4 Dec 2023 15:37:02 +0600 Subject: [PATCH 3/4] SpecialMutableStateFlow : MutableStateFlow --- CHANGELOG.md | 1 + .../coroutines/compose/FlowState.kt | 7 +--- .../coroutines/SpecialMutableStateFlow.kt | 41 +++++++++++++++---- 3 files changed, 37 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b2f1eb4d46..8c30ac202c3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## 0.20.18 * `Coroutines`: + * `SpecialMutableStateFlow` now extends `MutableStateFlow` * `Compose`: * Deprecate `FlowState` due to its complexity in fixes diff --git a/coroutines/compose/src/commonMain/kotlin/dev/inmo/micro_utils/coroutines/compose/FlowState.kt b/coroutines/compose/src/commonMain/kotlin/dev/inmo/micro_utils/coroutines/compose/FlowState.kt index 99c8ae1b58f..c3729ac32cf 100644 --- a/coroutines/compose/src/commonMain/kotlin/dev/inmo/micro_utils/coroutines/compose/FlowState.kt +++ b/coroutines/compose/src/commonMain/kotlin/dev/inmo/micro_utils/coroutines/compose/FlowState.kt @@ -1,10 +1,7 @@ package dev.inmo.micro_utils.coroutines.compose import androidx.compose.runtime.MutableState -import androidx.compose.runtime.State -import androidx.compose.runtime.derivedStateOf import dev.inmo.micro_utils.coroutines.SpecialMutableStateFlow -import dev.inmo.micro_utils.coroutines.doInUI import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -26,9 +23,9 @@ class FlowState( tryEmit(value) } - override suspend fun onChange(value: T) { + override fun onChangeWithoutSync(value: T) { internalValue = value - super.onChange(value) + super.onChangeWithoutSync(value) } override fun component1(): T = value diff --git a/coroutines/src/commonMain/kotlin/dev/inmo/micro_utils/coroutines/SpecialMutableStateFlow.kt b/coroutines/src/commonMain/kotlin/dev/inmo/micro_utils/coroutines/SpecialMutableStateFlow.kt index e39d5cdaa48..c1ca2992ba9 100644 --- a/coroutines/src/commonMain/kotlin/dev/inmo/micro_utils/coroutines/SpecialMutableStateFlow.kt +++ b/coroutines/src/commonMain/kotlin/dev/inmo/micro_utils/coroutines/SpecialMutableStateFlow.kt @@ -3,10 +3,14 @@ package dev.inmo.micro_utils.coroutines import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.InternalCoroutinesApi import kotlinx.coroutines.channels.BufferOverflow import kotlinx.coroutines.flow.FlowCollector import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.internal.SynchronizedObject +import kotlinx.coroutines.internal.synchronized /** * Works like [StateFlow], but guarantee that latest value update will always be delivered to @@ -15,7 +19,9 @@ import kotlinx.coroutines.flow.StateFlow open class SpecialMutableStateFlow( initialValue: T, internalScope: CoroutineScope = CoroutineScope(Dispatchers.Default) -) : StateFlow, FlowCollector, MutableSharedFlow { +) : MutableStateFlow, FlowCollector, MutableSharedFlow { + @OptIn(InternalCoroutinesApi::class) + private val syncObject = SynchronizedObject() protected val internalSharedFlow: MutableSharedFlow = MutableSharedFlow( replay = 0, extraBufferCapacity = 2, @@ -28,16 +34,37 @@ open class SpecialMutableStateFlow( ) protected var _value: T = initialValue - override val value: T + @OptIn(InternalCoroutinesApi::class) + override var value: T get() = _value - protected open suspend fun onChange(value: T) { + set(value) { + doOnChangeAction(value) + } + + @OptIn(InternalCoroutinesApi::class) + override fun compareAndSet(expect: T, update: T): Boolean { + return synchronized(syncObject) { + if (expect == _value && update != _value) { + doOnChangeAction(update) + } + expect == _value + } + } + + protected open fun onChangeWithoutSync(value: T) { _value = value - publicSharedFlow.emit(value) + publicSharedFlow.tryEmit(value) + } + @OptIn(InternalCoroutinesApi::class) + protected open fun doOnChangeAction(value: T) { + synchronized(syncObject) { + if (_value != value) { + onChangeWithoutSync(value) + } + } } protected val job = internalSharedFlow.subscribe(internalScope) { - if (_value != it) { - onChange(it) - } + doOnChangeAction(it) } override val replayCache: List From f6d5035c1af2b768bfdf29e14e6c50abb8223607 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Mon, 4 Dec 2023 15:44:06 +0600 Subject: [PATCH 4/4] small refactor in SpecialMutableStateFlow --- .../coroutines/SpecialMutableStateFlow.kt | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/coroutines/src/commonMain/kotlin/dev/inmo/micro_utils/coroutines/SpecialMutableStateFlow.kt b/coroutines/src/commonMain/kotlin/dev/inmo/micro_utils/coroutines/SpecialMutableStateFlow.kt index c1ca2992ba9..ecc421aa5cb 100644 --- a/coroutines/src/commonMain/kotlin/dev/inmo/micro_utils/coroutines/SpecialMutableStateFlow.kt +++ b/coroutines/src/commonMain/kotlin/dev/inmo/micro_utils/coroutines/SpecialMutableStateFlow.kt @@ -34,12 +34,19 @@ open class SpecialMutableStateFlow( ) protected var _value: T = initialValue - @OptIn(InternalCoroutinesApi::class) override var value: T get() = _value set(value) { doOnChangeAction(value) } + protected val job = internalSharedFlow.subscribe(internalScope) { + doOnChangeAction(it) + } + + override val replayCache: List + get() = publicSharedFlow.replayCache + override val subscriptionCount: StateFlow + get() = publicSharedFlow.subscriptionCount @OptIn(InternalCoroutinesApi::class) override fun compareAndSet(expect: T, update: T): Boolean { @@ -63,14 +70,6 @@ open class SpecialMutableStateFlow( } } } - protected val job = internalSharedFlow.subscribe(internalScope) { - doOnChangeAction(it) - } - - override val replayCache: List - get() = publicSharedFlow.replayCache - override val subscriptionCount: StateFlow - get() = publicSharedFlow.subscriptionCount @ExperimentalCoroutinesApi override fun resetReplayCache() = publicSharedFlow.resetReplayCache()