Created
December 2, 2020 09:19
-
-
Save mobileappconsultant/bcfe01a98dd31c285b51379f339493f6 to your computer and use it in GitHub Desktop.
This is an MVI implementation that has a bug. Onclick in the from the MVIFragment isn't firing off any action.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
sealed class MoneyBoxIntent : MviIntent { | |
data class LoginIntent(val loginRequestBody: LoginRequestBody) : MoneyBoxIntent() | |
object GetAllInvestorProductsIntent : MoneyBoxIntent() | |
object MakeOneOffPaymentIntent : MoneyBoxIntent() | |
} | |
**************************************************************************************************************************************** | |
package com.android.moneybox.presentation | |
import androidx.lifecycle.ViewModel | |
import com.android.moneybox.domain.mvi.moneyboxactions.MoneyBoxAction | |
import com.android.moneybox.domain.mvi.moneyboxactions.MoneyBoxAction.* | |
import com.android.moneybox.domain.mvi.moneyboxresult.MoneyBoxActionResult | |
import com.android.moneybox.domain.mvi.moneyboxresult.MoneyBoxActionResult.LoginResult | |
import com.android.moneybox.domain.mvi.moneyboxresult.MoneyBoxProcessorWrapper | |
import com.android.moneybox.domain.mvi.moneyboxviewstates.AuthenticationViewState | |
import com.android.moneybox.domain.mvi.moneyintents.MoneyBoxIntent | |
import com.android.moneybox.domain.mvi.mvibase.MviViewModel | |
import io.reactivex.rxjava3.core.ObservableTransformer | |
import io.reactivex.rxjava3.functions.BiFunction | |
import javax.inject.Inject | |
class MoneyBoxMviViewModel @Inject constructor(private val moneyBoxProcessorWrapper: MoneyBoxProcessorWrapper) : | |
ViewModel(), MviViewModel<MoneyBoxIntent, AuthenticationViewState> { | |
private val loginIntentSubject = | |
io.reactivex.rxjava3.subjects.PublishSubject.create<MoneyBoxIntent>() | |
private val statesObservable: io.reactivex.rxjava3.core.Observable<AuthenticationViewState> = | |
compose() | |
private val intentFilter: ObservableTransformer<MoneyBoxIntent, MoneyBoxIntent> | |
get() = ObservableTransformer { intents -> | |
intents.publish { shared -> | |
io.reactivex.rxjava3.core.Observable.merge( | |
{ | |
shared.ofType(MoneyBoxIntent.LoginIntent::class.java).take(1) | |
} | |
) | |
} | |
} | |
private fun compose(): io.reactivex.rxjava3.core.Observable<AuthenticationViewState> { | |
return loginIntentSubject.compose(intentFilter) | |
.map(this::actionFromIntent) | |
.compose(moneyBoxProcessorWrapper.actionProcessor) | |
.scan(AuthenticationViewState.idle(), reducer) | |
.distinctUntilChanged().replay(1).autoConnect() | |
} | |
private fun actionFromIntent(intent: MoneyBoxIntent): MoneyBoxAction { | |
return when (intent) { | |
is MoneyBoxIntent.LoginIntent -> LoginAction(intent.loginRequestBody) | |
is MoneyBoxIntent.GetAllInvestorProductsIntent -> GetAllInvestorProductsAction | |
is MoneyBoxIntent.MakeOneOffPaymentIntent -> MakeOneOffPaymentAction | |
} | |
} | |
override fun states(): io.reactivex.rxjava3.core.Observable<AuthenticationViewState> = | |
statesObservable | |
override fun processIntents(intents: io.reactivex.rxjava3.core.Observable<MoneyBoxIntent>) { | |
intents.subscribe(loginIntentSubject) | |
} | |
companion object { | |
private val reducer = | |
BiFunction { previousState: AuthenticationViewState, result: MoneyBoxActionResult -> | |
when (result) { | |
is LoginResult -> { | |
when (result) { | |
is LoginResult.Loading -> { | |
previousState.copy(inProgress = true) | |
} | |
is LoginResult.Failure -> { | |
previousState.copy(inProgress = false, error = result.error) | |
} | |
is LoginResult.Success -> { | |
previousState.copy( | |
inProgress = false, error = null, | |
loginResponse = result.moneyBoxProcessorWrapper | |
) | |
} | |
} | |
} | |
is MoneyBoxActionResult.GetInvestorProdcutsResult -> { | |
when (result) { | |
is MoneyBoxActionResult.GetInvestorProdcutsResult.Loading -> { | |
previousState.copy(inProgress = true) | |
} | |
is MoneyBoxActionResult.GetInvestorProdcutsResult.Failure -> { | |
previousState.copy(inProgress = false, error = result.error) | |
} | |
is MoneyBoxActionResult.GetInvestorProdcutsResult.Success -> { | |
previousState.copy( | |
inProgress = false, error = null, | |
loginResponse = result.moneyBoxProcessorWrapper | |
) | |
} | |
} | |
} | |
is MoneyBoxActionResult.OneOfPaymentResult -> { | |
when (result) { | |
is MoneyBoxActionResult.OneOfPaymentResult.Loading -> { | |
previousState.copy(inProgress = true) | |
} | |
is MoneyBoxActionResult.OneOfPaymentResult.Failure -> { | |
previousState.copy(inProgress = false, error = result.error) | |
} | |
is MoneyBoxActionResult.OneOfPaymentResult.Success -> { | |
previousState.copy( | |
inProgress = false, error = null, | |
loginResponse = result.moneyBoxProcessorWrapper | |
) | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
**************************************************************************************************************************************** | |
package com.android.moneybox.domain.mvi.moneyboxresult | |
import com.android.moneybox.domain.SchedulerProvider | |
import com.android.moneybox.domain.model.LoginRequestBody | |
import com.android.moneybox.domain.model.MoneyBoxOneOffPaymentRequest | |
import com.android.moneybox.domain.mvi.moneyboxactions.MoneyBoxAction | |
import com.android.moneybox.domain.mvi.moneyboxactions.MoneyBoxAction.GetAllInvestorProductsAction | |
import com.android.moneybox.domain.mvi.moneyboxactions.MoneyBoxAction.MakeOneOffPaymentAction | |
import com.android.moneybox.domain.mvi.moneyboxresult.MoneyBoxActionResult.* | |
import com.android.moneybox.domain.repository.MoenyBoxApiRepository | |
import io.reactivex.rxjava3.core.ObservableTransformer | |
import io.reactivex.rxjava3.core.SingleSource | |
import javax.inject.Inject | |
class MoneyBoxProcessorWrapper @Inject constructor( | |
private val repository: MoenyBoxApiRepository, | |
private val appSchedulerProvider: SchedulerProvider | |
) { | |
var loginRequestBody: LoginRequestBody = | |
LoginRequestBody("jaeren+androidtest@moneyboxapp.com", "P455word12") | |
lateinit var makeOneOffPaymentRequest: MoneyBoxOneOffPaymentRequest | |
internal var actionProcessor = | |
ObservableTransformer<MoneyBoxAction, MoneyBoxActionResult> { actions -> | |
actions.publish { shared -> | |
io.reactivex.rxjava3.core.Observable.merge{ | |
shared.ofType(MoneyBoxAction.LoginAction::class.java) | |
.compose(loginProcessor) | |
shared.ofType(GetAllInvestorProductsAction::class.java) | |
.compose(investorProductProcessor) | |
shared.ofType(MakeOneOffPaymentAction::class.java) | |
.compose(oneOffPaymentProcessor) | |
} | |
} | |
} | |
val loginProcessor = | |
ObservableTransformer<MoneyBoxAction, MoneyBoxActionResult> { actions -> | |
actions.flatMap { | |
repository.login(loginRequestBody) | |
.map { loginResponse -> LoginResult.Success(loginResponse) } | |
.cast(LoginResult::class.java) | |
.onErrorReturn(LoginResult::Failure) | |
.subscribeOn(appSchedulerProvider.io()) | |
.observeOn(appSchedulerProvider.ui()) | |
.startWith(SingleSource { LoginResult.Loading }) | |
} | |
} | |
private val investorProductProcessor = | |
ObservableTransformer<GetAllInvestorProductsAction, GetInvestorProdcutsResult> { actions -> | |
actions.flatMap { | |
repository.getInvestorProducts() | |
.map { investorProducts -> GetInvestorProdcutsResult.Success(investorProducts) } | |
.cast(GetInvestorProdcutsResult::class.java) | |
.onErrorReturn(GetInvestorProdcutsResult::Failure) | |
.subscribeOn(appSchedulerProvider.io()) | |
.observeOn(appSchedulerProvider.ui()) | |
.startWith(SingleSource { GetInvestorProdcutsResult.Loading }) | |
} | |
} | |
private val oneOffPaymentProcessor = | |
ObservableTransformer<MakeOneOffPaymentAction, OneOfPaymentResult> { actions -> | |
actions.flatMap { | |
repository.makeOneOffPayment(makeOneOffPaymentRequest) | |
.map { oneOffPaymentResult -> OneOfPaymentResult.Success(oneOffPaymentResult) } | |
.cast(OneOfPaymentResult::class.java) | |
.onErrorReturn(OneOfPaymentResult::Failure) | |
.subscribeOn(appSchedulerProvider.io()) | |
.observeOn(appSchedulerProvider.ui()) | |
.startWith(SingleSource { OneOfPaymentResult.Loading }) | |
} | |
} | |
} | |
**************************************************************************************************************************************** | |
package com.android.moneybox.presentation | |
import androidx.lifecycle.ViewModel | |
import com.android.moneybox.domain.mvi.moneyboxactions.MoneyBoxAction | |
import com.android.moneybox.domain.mvi.moneyboxactions.MoneyBoxAction.* | |
import com.android.moneybox.domain.mvi.moneyboxresult.MoneyBoxActionResult | |
import com.android.moneybox.domain.mvi.moneyboxresult.MoneyBoxActionResult.LoginResult | |
import com.android.moneybox.domain.mvi.moneyboxresult.MoneyBoxProcessorWrapper | |
import com.android.moneybox.domain.mvi.moneyboxviewstates.AuthenticationViewState | |
import com.android.moneybox.domain.mvi.moneyintents.MoneyBoxIntent | |
import com.android.moneybox.domain.mvi.mvibase.MviViewModel | |
import io.reactivex.rxjava3.core.ObservableTransformer | |
import io.reactivex.rxjava3.functions.BiFunction | |
import javax.inject.Inject | |
class MoneyBoxMviViewModel @Inject constructor(private val moneyBoxProcessorWrapper: MoneyBoxProcessorWrapper) : | |
ViewModel(), MviViewModel<MoneyBoxIntent, AuthenticationViewState> { | |
private val loginIntentSubject = | |
io.reactivex.rxjava3.subjects.PublishSubject.create<MoneyBoxIntent>() | |
private val statesObservable: io.reactivex.rxjava3.core.Observable<AuthenticationViewState> = | |
compose() | |
private val intentFilter: ObservableTransformer<MoneyBoxIntent, MoneyBoxIntent> | |
get() = ObservableTransformer { intents -> | |
intents.publish { shared -> | |
io.reactivex.rxjava3.core.Observable.merge( | |
{ | |
shared.ofType(MoneyBoxIntent.LoginIntent::class.java).take(1) | |
} | |
) | |
} | |
} | |
private fun compose(): io.reactivex.rxjava3.core.Observable<AuthenticationViewState> { | |
return loginIntentSubject.compose(intentFilter) | |
.map(this::actionFromIntent) | |
.compose(moneyBoxProcessorWrapper.actionProcessor) | |
.scan(AuthenticationViewState.idle(), reducer) | |
.distinctUntilChanged().replay(1).autoConnect() | |
} | |
private fun actionFromIntent(intent: MoneyBoxIntent): MoneyBoxAction { | |
return when (intent) { | |
is MoneyBoxIntent.LoginIntent -> LoginAction(intent.loginRequestBody) | |
is MoneyBoxIntent.GetAllInvestorProductsIntent -> GetAllInvestorProductsAction | |
is MoneyBoxIntent.MakeOneOffPaymentIntent -> MakeOneOffPaymentAction | |
} | |
} | |
override fun states(): io.reactivex.rxjava3.core.Observable<AuthenticationViewState> = | |
statesObservable | |
override fun processIntents(intents: io.reactivex.rxjava3.core.Observable<MoneyBoxIntent>) { | |
intents.subscribe(loginIntentSubject) | |
} | |
companion object { | |
private val reducer = | |
BiFunction { previousState: AuthenticationViewState, result: MoneyBoxActionResult -> | |
when (result) { | |
is LoginResult -> { | |
when (result) { | |
is LoginResult.Loading -> { | |
previousState.copy(inProgress = true) | |
} | |
is LoginResult.Failure -> { | |
previousState.copy(inProgress = false, error = result.error) | |
} | |
is LoginResult.Success -> { | |
previousState.copy( | |
inProgress = false, error = null, | |
loginResponse = result.moneyBoxProcessorWrapper | |
) | |
} | |
} | |
} | |
is MoneyBoxActionResult.GetInvestorProdcutsResult -> { | |
when (result) { | |
is MoneyBoxActionResult.GetInvestorProdcutsResult.Loading -> { | |
previousState.copy(inProgress = true) | |
} | |
is MoneyBoxActionResult.GetInvestorProdcutsResult.Failure -> { | |
previousState.copy(inProgress = false, error = result.error) | |
} | |
is MoneyBoxActionResult.GetInvestorProdcutsResult.Success -> { | |
previousState.copy( | |
inProgress = false, error = null, | |
loginResponse = result.moneyBoxProcessorWrapper | |
) | |
} | |
} | |
} | |
is MoneyBoxActionResult.OneOfPaymentResult -> { | |
when (result) { | |
is MoneyBoxActionResult.OneOfPaymentResult.Loading -> { | |
previousState.copy(inProgress = true) | |
} | |
is MoneyBoxActionResult.OneOfPaymentResult.Failure -> { | |
previousState.copy(inProgress = false, error = result.error) | |
} | |
is MoneyBoxActionResult.OneOfPaymentResult.Success -> { | |
previousState.copy( | |
inProgress = false, error = null, | |
loginResponse = result.moneyBoxProcessorWrapper | |
) | |
} | |
} | |
} | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment