diff --git a/.idea/compiler.xml b/.idea/compiler.xml index 7e7ee626..fb7f4a8a 100644 --- a/.idea/compiler.xml +++ b/.idea/compiler.xml @@ -1,6 +1,6 @@ - + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml index c22de178..686bec5b 100644 --- a/.idea/gradle.xml +++ b/.idea/gradle.xml @@ -4,7 +4,7 @@ \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index 076b3e47..22eff8b0 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -12,7 +12,7 @@ - + diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml new file mode 100644 index 00000000..797acea5 --- /dev/null +++ b/.idea/runConfigurations.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index d5c5e46e..5342c596 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -75,6 +75,7 @@ allprojects { google() mavenCentral() maven(url = "https://jitpack.io") + maven(url = "https://s01.oss.sonatype.org/content/repositories/snapshots/") } } diff --git a/buildSrc/src/main/kotlin/deps.kt b/buildSrc/src/main/kotlin/deps.kt index fc76321d..717f9976 100644 --- a/buildSrc/src/main/kotlin/deps.kt +++ b/buildSrc/src/main/kotlin/deps.kt @@ -62,6 +62,7 @@ object deps { const val coil = "io.coil-kt:coil:1.2.1" const val viewBindingDelegate = "com.github.hoc081098:ViewBindingDelegate:1.0.0" + const val flowExt = "io.github.hoc081098:FlowExt:0.0.7-SNAPSHOT" object test { const val junit = "junit:junit:4.13" diff --git a/core/src/main/java/com/hoc/flowmvi/core/FlowExt.kt b/core/src/main/java/com/hoc/flowmvi/core/FlowExt.kt deleted file mode 100644 index 9b639abe..00000000 --- a/core/src/main/java/com/hoc/flowmvi/core/FlowExt.kt +++ /dev/null @@ -1,115 +0,0 @@ -package com.hoc.flowmvi.core - -import kotlinx.coroutines.CancellationException -import kotlinx.coroutines.CoroutineStart -import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.cancel -import kotlinx.coroutines.coroutineScope -import kotlinx.coroutines.delay -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.asFlow -import kotlinx.coroutines.flow.catch -import kotlinx.coroutines.flow.channelFlow -import kotlinx.coroutines.flow.collect -import kotlinx.coroutines.flow.flow -import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.onEach -import kotlinx.coroutines.flow.take -import kotlinx.coroutines.launch -import java.util.concurrent.atomic.AtomicBoolean -import java.util.concurrent.atomic.AtomicReference - -@ExperimentalCoroutinesApi -fun Flow.takeUntil(notifier: Flow): Flow = channelFlow { - val outerScope = this - - launch { - try { - notifier.take(1).collect() - close() - } catch (e: CancellationException) { - outerScope.cancel(e) // cancel outer scope on cancellation exception, too - } - } - launch { - try { - collect { send(it) } - close() - } catch (e: CancellationException) { - outerScope.cancel(e) // cancel outer scope on cancellation exception, too - } - } -} - -@ExperimentalCoroutinesApi -fun Flow.flatMapFirst(transform: suspend (value: T) -> Flow): Flow = - map(transform).flattenFirst() - -@ExperimentalCoroutinesApi -fun Flow>.flattenFirst(): Flow = channelFlow { - val outerScope = this - val busy = AtomicBoolean(false) - - collect { inner -> - if (busy.compareAndSet(false, true)) { - outerScope.launch(start = CoroutineStart.UNDISPATCHED) { - try { - inner.collect { outerScope.send(it) } - busy.set(false) - } catch (e: CancellationException) { - // cancel outer scope on cancellation exception, too - outerScope.cancel(e) - } - } - } - } -} - -private object UNINITIALIZED - -fun Flow.withLatestFrom(other: Flow, transform: suspend (A, B) -> R): Flow { - return flow { - coroutineScope { - val latestB = AtomicReference(UNINITIALIZED) - val outerScope = this - - launch { - try { - other.collect { latestB.set(it) } - } catch (e: CancellationException) { - outerScope.cancel(e) // cancel outer scope on cancellation exception, too - } - } - - collect { a -> - val b = latestB.get() - if (b != UNINITIALIZED) { - @Suppress("UNCHECKED_CAST") - emit(transform(a, b as B)) - } - } - } - } -} - -@ExperimentalCoroutinesApi -suspend fun main() { - (1..2).asFlow() - .onEach { delay(50) } - .takeUntil(flow { delay(100000); emit(Unit) }) - .collect { println(">>>>> $it") } - - println("Done") - - (1..2000).asFlow() - .onEach { delay(50) } - .flatMapFirst { v -> - flow { - delay(500) - emit(v) - } - } - .onEach { println("[*] $it") } - .catch { println("Error $it") } - .collect() -} diff --git a/feature-add/build.gradle.kts b/feature-add/build.gradle.kts index 08ac6696..0dadf41f 100644 --- a/feature-add/build.gradle.kts +++ b/feature-add/build.gradle.kts @@ -50,5 +50,7 @@ dependencies { implementation(deps.coroutines.core) implementation(deps.koin.android) + implementation(deps.viewBindingDelegate) + implementation(deps.flowExt) } diff --git a/feature-add/src/main/java/com/hoc/flowmvi/ui/add/AddVM.kt b/feature-add/src/main/java/com/hoc/flowmvi/ui/add/AddVM.kt index c2a762da..f2ebc6b5 100644 --- a/feature-add/src/main/java/com/hoc/flowmvi/ui/add/AddVM.kt +++ b/feature-add/src/main/java/com/hoc/flowmvi/ui/add/AddVM.kt @@ -6,10 +6,10 @@ import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.hoc.flowmvi.core.Either -import com.hoc.flowmvi.core.flatMapFirst -import com.hoc.flowmvi.core.withLatestFrom import com.hoc.flowmvi.domain.entity.User import com.hoc.flowmvi.domain.usecase.AddUserUseCase +import com.hoc081098.flowext.flatMapFirst +import com.hoc081098.flowext.withLatestFrom import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.Flow diff --git a/feature-main/build.gradle.kts b/feature-main/build.gradle.kts index 90715ab6..420ab942 100644 --- a/feature-main/build.gradle.kts +++ b/feature-main/build.gradle.kts @@ -54,4 +54,5 @@ dependencies { implementation(deps.koin.android) implementation(deps.coil) implementation(deps.viewBindingDelegate) + implementation(deps.flowExt) } diff --git a/feature-main/src/main/java/com/hoc/flowmvi/ui/main/MainVM.kt b/feature-main/src/main/java/com/hoc/flowmvi/ui/main/MainVM.kt index 2b6a3e5c..09599d55 100644 --- a/feature-main/src/main/java/com/hoc/flowmvi/ui/main/MainVM.kt +++ b/feature-main/src/main/java/com/hoc/flowmvi/ui/main/MainVM.kt @@ -3,10 +3,10 @@ package com.hoc.flowmvi.ui.main import android.util.Log import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.hoc.flowmvi.core.flatMapFirst import com.hoc.flowmvi.domain.usecase.GetUsersUseCase import com.hoc.flowmvi.domain.usecase.RefreshGetUsersUseCase import com.hoc.flowmvi.domain.usecase.RemoveUserUseCase +import com.hoc081098.flowext.flatMapFirst import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.channels.Channel diff --git a/feature-search/build.gradle.kts b/feature-search/build.gradle.kts index 501782d8..11cf4165 100644 --- a/feature-search/build.gradle.kts +++ b/feature-search/build.gradle.kts @@ -55,4 +55,5 @@ dependencies { implementation(deps.koin.android) implementation(deps.coil) implementation(deps.viewBindingDelegate) + implementation(deps.flowExt) } diff --git a/feature-search/src/main/java/com/hoc/flowmvi/ui/search/SearchVM.kt b/feature-search/src/main/java/com/hoc/flowmvi/ui/search/SearchVM.kt index 7e0a76ea..c887301f 100644 --- a/feature-search/src/main/java/com/hoc/flowmvi/ui/search/SearchVM.kt +++ b/feature-search/src/main/java/com/hoc/flowmvi/ui/search/SearchVM.kt @@ -3,9 +3,9 @@ package com.hoc.flowmvi.ui.search import android.util.Log import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.hoc.flowmvi.core.flatMapFirst -import com.hoc.flowmvi.core.takeUntil import com.hoc.flowmvi.domain.usecase.SearchUsersUseCase +import com.hoc081098.flowext.flatMapFirst +import com.hoc081098.flowext.takeUntil import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.channels.Channel