Skip to content

collectIn 🎉 #12

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

Merged
merged 3 commits into from
Mar 31, 2021
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
9 changes: 0 additions & 9 deletions .idea/codeStyles/Project.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion .idea/compiler.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions .idea/gradle.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions .idea/kotlinc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

35 changes: 35 additions & 0 deletions core/src/main/java/com/hoc/flowmvi/core/CollectIn.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.hoc.flowmvi.core

import android.util.Log
import androidx.fragment.app.Fragment
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.addRepeatingJob
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.collect
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext

inline fun <T> Flow<T>.collectIn(
owner: LifecycleOwner,
minActiveState: Lifecycle.State = Lifecycle.State.STARTED,
coroutineContext: CoroutineContext = EmptyCoroutineContext,
crossinline action: suspend (value: T) -> Unit,
): Job = owner.addRepeatingJob(state = minActiveState, coroutineContext = coroutineContext) {
Log.d("collectIn", "Start collecting...")
collect { action(it) }
}

@Suppress("unused")
inline fun <T> Flow<T>.collectIn(
fragment: Fragment,
minActiveState: Lifecycle.State = Lifecycle.State.STARTED,
coroutineContext: CoroutineContext = EmptyCoroutineContext,
crossinline action: suspend (value: T) -> Unit,
): Job = collectIn(
fragment.viewLifecycleOwner,
minActiveState = minActiveState,
coroutineContext = coroutineContext,
action = action,
)
11 changes: 3 additions & 8 deletions feature-add/src/main/java/com/hoc/flowmvi/ui/add/AddActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,11 @@ import android.util.Log
import android.view.MenuItem
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.isInvisible
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.flowWithLifecycle
import androidx.lifecycle.lifecycleScope
import androidx.transition.AutoTransition
import androidx.transition.TransitionManager
import com.hoc.flowmvi.core.clicks
import com.hoc.flowmvi.core.collectIn
import com.hoc.flowmvi.core.firstChange
import com.hoc.flowmvi.core.navigator.IntentProviders
import com.hoc.flowmvi.core.textChanges
Expand Down Expand Up @@ -53,15 +52,11 @@ class AddActivity : AppCompatActivity() {
private fun bindVM(addVM: AddVM) {
// observe view model
addVM.viewState
.onEach { render(it) }
.flowWithLifecycle(lifecycle, Lifecycle.State.STARTED)
.launchIn(lifecycleScope)
.collectIn(this) { render(it) }

// observe single event
addVM.singleEvent
.onEach { handleSingleEvent(it) }
.flowWithLifecycle(lifecycle, Lifecycle.State.STARTED)
.launchIn(lifecycleScope)
.collectIn(this) { handleSingleEvent(it) }

// pass view intent to view model
intents()
Expand Down
20 changes: 14 additions & 6 deletions feature-add/src/main/java/com/hoc/flowmvi/ui/add/AddVM.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filterIsInstance
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.map
Expand Down Expand Up @@ -47,9 +48,9 @@ internal class AddVM(

init {
val initialVS = ViewState.initial(
email = savedStateHandle.get<String?>("email"),
firstName = savedStateHandle.get<String?>("first_name"),
lastName = savedStateHandle.get<String?>("last_name"),
email = savedStateHandle.get<String?>(EMAIL_KEY),
firstName = savedStateHandle.get<String?>(FIRST_NAME_KEY),
lastName = savedStateHandle.get<String?>(LAST_NAME_KEY),
)
Log.d("###", "[ADD_VM] initialVS: $initialVS")

Expand Down Expand Up @@ -85,6 +86,7 @@ internal class AddVM(
private fun Flow<ViewIntent>.toPartialStateChangesFlow(): Flow<PartialStateChange> {
val emailErrors = filterIsInstance<ViewIntent.EmailChanged>()
.map { it.email }
.distinctUntilChanged()
.map { validateEmail(it) to it }
.shareIn(
scope = viewModelScope,
Expand All @@ -93,6 +95,7 @@ internal class AddVM(

val firstNameErrors = filterIsInstance<ViewIntent.FirstNameChanged>()
.map { it.firstName }
.distinctUntilChanged()
.map { validateFirstName(it) to it }
.shareIn(
scope = viewModelScope,
Expand All @@ -101,6 +104,7 @@ internal class AddVM(

val lastNameErrors = filterIsInstance<ViewIntent.LastNameChanged>()
.map { it.lastName }
.distinctUntilChanged()
.map { validateLastName(it) to it }
.shareIn(
scope = viewModelScope,
Expand Down Expand Up @@ -151,15 +155,15 @@ internal class AddVM(
val formValuesChanges = merge(
emailErrors
.map { it.second }
.onEach { savedStateHandle.set("email", it) }
.onEach { savedStateHandle.set(EMAIL_KEY, it) }
.map { PartialStateChange.FormValueChange.EmailChanged(it) },
firstNameErrors
.map { it.second }
.onEach { savedStateHandle.set("first_name", it) }
.onEach { savedStateHandle.set(FIRST_NAME_KEY, it) }
.map { PartialStateChange.FormValueChange.FirstNameChanged(it) },
lastNameErrors
.map { it.second }
.onEach { savedStateHandle.set("last_name", it) }
.onEach { savedStateHandle.set(LAST_NAME_KEY, it) }
.map { PartialStateChange.FormValueChange.LastNameChanged(it) },
)

Expand All @@ -178,6 +182,10 @@ internal class AddVM(
}

private companion object {
const val EMAIL_KEY = "email"
const val FIRST_NAME_KEY = "first_name"
const val LAST_NAME_KEY = "last_name"

const val MIN_LENGTH_FIRST_NAME = 3
const val MIN_LENGTH_LAST_NAME = 3

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,14 @@ import android.view.Menu
import android.view.MenuItem
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.isVisible
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.flowWithLifecycle
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.hoc.flowmvi.core.SwipeLeftToDeleteCallback
import com.hoc.flowmvi.core.clicks
import com.hoc.flowmvi.core.collectIn
import com.hoc.flowmvi.core.navigator.Navigator
import com.hoc.flowmvi.core.refreshes
import com.hoc.flowmvi.core.safeOffer
Expand Down Expand Up @@ -86,15 +85,11 @@ class MainActivity : AppCompatActivity() {
private fun bindVM(mainVM: MainVM) {
// observe view model
mainVM.viewState
.onEach { render(it) }
.flowWithLifecycle(lifecycle, Lifecycle.State.STARTED)
.launchIn(lifecycleScope)
.collectIn(this) { render(it) }

// observe single event
mainVM.singleEvent
.onEach { handleSingleEvent(it) }
.flowWithLifecycle(lifecycle, Lifecycle.State.STARTED)
.launchIn(lifecycleScope)
.collectIn(this) { handleSingleEvent(it) }

// pass view intent to view model
intents()
Expand Down