@@ -2,8 +2,10 @@ package com.hoc.flowmvi.ui.add
22
33import androidx.lifecycle.SavedStateHandle
44import androidx.lifecycle.viewModelScope
5+ import arrow.core.ValidatedNel
56import arrow.core.orNull
67import com.hoc.flowmvi.domain.model.User
8+ import com.hoc.flowmvi.domain.model.UserValidationError
79import com.hoc.flowmvi.domain.usecase.AddUserUseCase
810import com.hoc.flowmvi.mvi_base.AbstractMviViewModel
911import com.hoc081098.flowext.flatMapFirst
@@ -32,6 +34,8 @@ import kotlinx.coroutines.flow.take
3234import timber.log.Timber
3335import javax.inject.Inject
3436
37+ private typealias UserFormStateFlow = StateFlow <ValidatedNel <UserValidationError , User >? >
38+
3539@HiltViewModel
3640@ExperimentalCoroutinesApi
3741class AddVM @Inject constructor(
@@ -49,7 +53,7 @@ class AddVM @Inject constructor(
4953 Timber .tag(logTag).d(" [ADD_VM] initialVS: $initialVS " )
5054
5155 viewState = intentFlow
52- .toPartialStateChangesFlow (initialVS)
56+ .toPartialStateChangeFlow (initialVS)
5357 .log(" PartialStateChange" )
5458 .sendSingleEvent()
5559 .scan(initialVS) { state, change -> change.reduce(state) }
@@ -61,7 +65,7 @@ class AddVM @Inject constructor(
6165 private fun Flow<PartialStateChange>.sendSingleEvent (): Flow <PartialStateChange > {
6266 return onEach { change ->
6367 val event = when (change) {
64- is PartialStateChange .ErrorsChanged -> return @onEach
68+ is PartialStateChange .Errors -> return @onEach
6569 PartialStateChange .AddUser .Loading -> return @onEach
6670 is PartialStateChange .AddUser .AddUserSuccess -> SingleEvent .AddUserSuccess (change.user)
6771 is PartialStateChange .AddUser .AddUserFailure -> SingleEvent .AddUserFailure (
@@ -71,15 +75,15 @@ class AddVM @Inject constructor(
7175 PartialStateChange .FirstChange .EmailChangedFirstTime -> return @onEach
7276 PartialStateChange .FirstChange .FirstNameChangedFirstTime -> return @onEach
7377 PartialStateChange .FirstChange .LastNameChangedFirstTime -> return @onEach
74- is PartialStateChange .FormValueChange .EmailChanged -> return @onEach
75- is PartialStateChange .FormValueChange .FirstNameChanged -> return @onEach
76- is PartialStateChange .FormValueChange .LastNameChanged -> return @onEach
78+ is PartialStateChange .FormValue .EmailChanged -> return @onEach
79+ is PartialStateChange .FormValue .FirstNameChanged -> return @onEach
80+ is PartialStateChange .FormValue .LastNameChanged -> return @onEach
7781 }
7882 sendEvent(event)
7983 }
8084 }
8185
82- private fun SharedFlow<ViewIntent>.toPartialStateChangesFlow (initialVS : ViewState ): Flow <PartialStateChange > {
86+ private fun SharedFlow<ViewIntent>.toPartialStateChangeFlow (initialVS : ViewState ): Flow <PartialStateChange > {
8387 val emailFlow = filterIsInstance<ViewIntent .EmailChanged >()
8488 .map { it.email }
8589 .startWith(initialVS.email)
@@ -112,8 +116,41 @@ class AddVM @Inject constructor(
112116 )
113117 }.stateWithInitialNullWhileSubscribed()
114118
115- val addUserChanges = filterIsInstance<ViewIntent .Submit >()
116- .withLatestFrom(userFormFlow) { _, userForm -> userForm }
119+ val formValuesChangeFlow = merge(
120+ emailFlow.map { PartialStateChange .FormValue .EmailChanged (it) },
121+ firstNameFlow.map { PartialStateChange .FormValue .FirstNameChanged (it) },
122+ lastNameFlow.map { PartialStateChange .FormValue .LastNameChanged (it) },
123+ )
124+
125+ return merge(
126+ // form values change
127+ formValuesChangeFlow,
128+ // first change
129+ toFirstChangeFlow(),
130+ // errors change
131+ userFormFlow.toErrorsChangeFlow(),
132+ // add user change
133+ filterIsInstance<ViewIntent .Submit >()
134+ .toAddUserChangeFlow(userFormFlow),
135+ )
136+ }
137+
138+ // region Processors
139+ private fun SharedFlow<ViewIntent>.toFirstChangeFlow (): Flow <PartialStateChange .FirstChange > =
140+ merge(
141+ filterIsInstance<ViewIntent .EmailChanged >()
142+ .take(1 )
143+ .mapTo(PartialStateChange .FirstChange .EmailChangedFirstTime ),
144+ filterIsInstance<ViewIntent .FirstNameChanged >()
145+ .take(1 )
146+ .mapTo(PartialStateChange .FirstChange .FirstNameChangedFirstTime ),
147+ filterIsInstance<ViewIntent .LastNameChanged >()
148+ .take(1 )
149+ .mapTo(PartialStateChange .FirstChange .LastNameChangedFirstTime )
150+ )
151+
152+ private fun Flow<ViewIntent.Submit>.toAddUserChangeFlow (userFormFlow : UserFormStateFlow ): Flow <PartialStateChange .AddUser > =
153+ withLatestFrom(userFormFlow) { _, userForm -> userForm }
117154 .mapNotNull { it?.orNull() }
118155 .flatMapFirst { user ->
119156 flowFromSuspend { addUser(user) }
@@ -126,44 +163,15 @@ class AddVM @Inject constructor(
126163 .startWith(PartialStateChange .AddUser .Loading )
127164 }
128165
129- val firstChanges = firstChangesFlow()
130-
131- val formValuesChanges = merge(
132- emailFlow.map { PartialStateChange .FormValueChange .EmailChanged (it) },
133- firstNameFlow.map { PartialStateChange .FormValueChange .FirstNameChanged (it) },
134- lastNameFlow.map { PartialStateChange .FormValueChange .LastNameChanged (it) },
135- )
136-
137- val errorsChanges = userFormFlow.map { validated ->
138- PartialStateChange .ErrorsChanged (
166+ private fun UserFormStateFlow.toErrorsChangeFlow (): Flow <PartialStateChange .Errors > =
167+ map { validated ->
168+ PartialStateChange .Errors (
139169 validated?.fold(
140170 { it.toPersistentHashSet() },
141171 { persistentHashSetOf() }
142172 ) ? : persistentHashSetOf()
143173 )
144174 }
145-
146- return merge(
147- formValuesChanges,
148- errorsChanges,
149- addUserChanges,
150- firstChanges,
151- )
152- }
153-
154- // region Intent processors
155- private fun SharedFlow<ViewIntent>.firstChangesFlow () =
156- merge(
157- filterIsInstance<ViewIntent .EmailChanged >()
158- .take(1 )
159- .mapTo(PartialStateChange .FirstChange .EmailChangedFirstTime ),
160- filterIsInstance<ViewIntent .FirstNameChanged >()
161- .take(1 )
162- .mapTo(PartialStateChange .FirstChange .FirstNameChangedFirstTime ),
163- filterIsInstance<ViewIntent .LastNameChanged >()
164- .take(1 )
165- .mapTo(PartialStateChange .FirstChange .LastNameChangedFirstTime )
166- )
167175 // endregion
168176
169177 private companion object {
0 commit comments