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