Skip to content

Commit

Permalink
[FC] Removes mavericks from repositories and more panes. (#8154)
Browse files Browse the repository at this point in the history
* Migrates more screens out of mavs.

* Migrates partner auth.

* Removes active auth session field.

* Updates tests.

* Updates attach payment viewmodel.

* PR feedback.

* Api dump.
  • Loading branch information
carlosmuvi-stripe authored Mar 26, 2024
1 parent 331f1e5 commit 6ca0025
Show file tree
Hide file tree
Showing 31 changed files with 280 additions and 326 deletions.
1 change: 1 addition & 0 deletions financial-connections/detekt-baseline.xml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
<ID>MaximumLineLength:com.stripe.android.financialconnections.presentation.FinancialConnectionsUrls.kt:41</ID>
<ID>MaximumLineLength:com.stripe.android.financialconnections.presentation.FinancialConnectionsUrls.kt:46</ID>
<ID>MaximumLineLength:com.stripe.android.financialconnections.presentation.FinancialConnectionsUrls.kt:9</ID>
<ID>NestedBlockDepth:AccountPickerViewModel.kt$AccountPickerViewModel$fun onAccountClicked(account: PartnerAccount)</ID>
<ID>NestedBlockDepth:InstitutionPickerScreen.kt$private fun LazyListScope.searchResults( isInputEmpty: Boolean, payload: Payload, selectedInstitutionId: String?, onInstitutionSelected: (FinancialConnectionsInstitution, Boolean) -> Unit, institutions: Async&lt;InstitutionResponse>, onManualEntryClick: () -> Unit, onSearchMoreClick: () -> Unit )</ID>
<ID>SwallowedException:PollAttachPaymentAccount.kt$PollAttachPaymentAccount$e: StripeException</ID>
<ID>SwallowedException:PollAuthorizationSessionAccounts.kt$PollAuthorizationSessionAccounts$e: StripeException</ID>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import androidx.lifecycle.viewModelScope
import com.stripe.android.financialconnections.core.Async.Fail
import com.stripe.android.financialconnections.core.Async.Loading
import com.stripe.android.financialconnections.core.Async.Success
import com.stripe.android.financialconnections.core.Async.Uninitialized
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
Expand All @@ -23,31 +24,30 @@ internal abstract class FinancialConnectionsViewModel<S>(
val stateFlow: StateFlow<S> = _stateFlow.asStateFlow()

protected open fun <T : Any?> (suspend () -> T).execute(
onSuccess: (T) -> Unit = {},
onFail: (Throwable) -> Unit = {},
reducer: S.(Async<T>) -> S
retainValue: KProperty1<S, Async<T>>? = null,
reducer: S.(Async<T>) -> S,
): Job {
return viewModelScope.launch {
setState { reducer(Loading) }
setState { reducer(Loading(value = retainValue?.get(this)?.invoke())) }
val result = runCatching { this@execute() }
// update state.
result.fold(
onSuccess = { data ->
setState { reducer(Success(data)) }
onSuccess(data)
},
onFailure = { throwable ->
setState { reducer(Fail(throwable)) }
onFail(throwable)
}
)
}
}

protected fun withState(action: (state: S) -> Unit) = stateFlow.value.let(action)

protected open fun <T> onAsync(
prop: KProperty1<S, Async<T>>,
onSuccess: (T) -> Unit = {},
onFail: (Throwable) -> Unit = {}
onSuccess: suspend (T) -> Unit = {},
onFail: suspend (Throwable) -> Unit = {}
) {
viewModelScope.launch {
stateFlow.map { prop.get(it) }
Expand All @@ -56,8 +56,8 @@ internal abstract class FinancialConnectionsViewModel<S>(
when (async) {
is Success -> onSuccess(async())
is Fail -> onFail(async.error)
Loading -> Unit
Async.Uninitialized -> Unit
is Loading -> Unit
Uninitialized -> Unit
}
}
}
Expand All @@ -70,7 +70,7 @@ internal sealed class Async<out T>(
private val value: T?
) {
data object Uninitialized : Async<Nothing>(value = null)
data object Loading : Async<Nothing>(value = null)
data class Loading<T>(val value: T? = null) : Async<T>(value = value)
data class Success<out T>(private val value: T) : Async<T>(value = value) {
override operator fun invoke(): T = value
}
Expand All @@ -79,3 +79,6 @@ internal sealed class Async<out T>(

open operator fun invoke(): T? = value
}

internal fun <A : FinancialConnectionsViewModel<B>, B, C> withState(viewModel: A, block: (B) -> C) =
block(viewModel.stateFlow.value)
Original file line number Diff line number Diff line change
Expand Up @@ -153,19 +153,11 @@ internal interface FinancialConnectionsSheetNativeModule {

@Singleton
@Provides
fun providesSaveToLinkWithStripeSucceededRepository(
@IOContext workContext: CoroutineContext
): SuccessContentRepository = SuccessContentRepositoryImpl(
CoroutineScope(SupervisorJob() + workContext)
)
fun providesSaveToLinkWithStripeSucceededRepository(): SuccessContentRepository = SuccessContentRepositoryImpl()

@Singleton
@Provides
fun providesFinancialConnectionsErrorRepository(
@IOContext workContext: CoroutineContext
) = FinancialConnectionsErrorRepository(
CoroutineScope(SupervisorJob() + workContext)
)
fun providesFinancialConnectionsErrorRepository() = FinancialConnectionsErrorRepository()

@Singleton
@Provides
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package com.stripe.android.financialconnections.features.accountpicker

import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import com.airbnb.mvrx.Fail
import com.airbnb.mvrx.Loading
import com.airbnb.mvrx.Success
import com.stripe.android.core.exception.APIException
import com.stripe.android.financialconnections.core.Async.Fail
import com.stripe.android.financialconnections.core.Async.Loading
import com.stripe.android.financialconnections.core.Async.Success
import com.stripe.android.financialconnections.exception.AccountNoneEligibleForPaymentMethodError
import com.stripe.android.financialconnections.features.accountpicker.AccountPickerState.SelectionMode
import com.stripe.android.financialconnections.features.common.MerchantDataAccessModel
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import androidx.compose.material.rememberModalBottomSheetState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.State
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
Expand All @@ -31,14 +32,13 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp
import com.airbnb.mvrx.Async
import com.airbnb.mvrx.Fail
import com.airbnb.mvrx.Loading
import com.airbnb.mvrx.Success
import com.airbnb.mvrx.Uninitialized
import com.airbnb.mvrx.compose.collectAsState
import com.airbnb.mvrx.compose.mavericksViewModel
import com.stripe.android.financialconnections.R
import com.stripe.android.financialconnections.core.Async
import com.stripe.android.financialconnections.core.Async.Fail
import com.stripe.android.financialconnections.core.Async.Loading
import com.stripe.android.financialconnections.core.Async.Success
import com.stripe.android.financialconnections.core.Async.Uninitialized
import com.stripe.android.financialconnections.core.paneViewModel
import com.stripe.android.financialconnections.exception.AccountLoadError
import com.stripe.android.financialconnections.exception.AccountNoneEligibleForPaymentMethodError
import com.stripe.android.financialconnections.features.accountpicker.AccountPickerClickableText.DATA
Expand Down Expand Up @@ -68,9 +68,9 @@ import kotlinx.coroutines.launch

@Composable
internal fun AccountPickerScreen() {
val viewModel: AccountPickerViewModel = mavericksViewModel()
val viewModel: AccountPickerViewModel = paneViewModel { AccountPickerViewModel.factory(it) }
val parentViewModel = parentViewModel()
val state: State<AccountPickerState> = viewModel.collectAsState()
val state: State<AccountPickerState> = viewModel.stateFlow.collectAsState()
BackHandler(true) {}

val bottomSheetState = rememberModalBottomSheetState(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
package com.stripe.android.financialconnections.features.accountpicker

import com.airbnb.mvrx.Async
import com.airbnb.mvrx.Loading
import com.airbnb.mvrx.MavericksState
import com.airbnb.mvrx.MavericksViewModel
import com.airbnb.mvrx.MavericksViewModelFactory
import com.airbnb.mvrx.Uninitialized
import com.airbnb.mvrx.ViewModelContext
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope
import androidx.lifecycle.viewmodel.initializer
import androidx.lifecycle.viewmodel.viewModelFactory
import com.stripe.android.core.Logger
import com.stripe.android.financialconnections.FinancialConnections
import com.stripe.android.financialconnections.analytics.FinancialConnectionsAnalyticsEvent.AccountSelected
Expand All @@ -19,6 +16,11 @@ import com.stripe.android.financialconnections.analytics.FinancialConnectionsAna
import com.stripe.android.financialconnections.analytics.FinancialConnectionsAnalyticsTracker
import com.stripe.android.financialconnections.analytics.FinancialConnectionsEvent.Name
import com.stripe.android.financialconnections.analytics.logError
import com.stripe.android.financialconnections.core.Async
import com.stripe.android.financialconnections.core.Async.Loading
import com.stripe.android.financialconnections.core.Async.Uninitialized
import com.stripe.android.financialconnections.core.FinancialConnectionsViewModel
import com.stripe.android.financialconnections.di.FinancialConnectionsSheetNativeComponent
import com.stripe.android.financialconnections.domain.GetOrFetchSync
import com.stripe.android.financialconnections.domain.PollAuthorizationSessionAccounts
import com.stripe.android.financialconnections.domain.SelectAccounts
Expand All @@ -35,7 +37,6 @@ import com.stripe.android.financialconnections.navigation.Destination.ManualEntr
import com.stripe.android.financialconnections.navigation.Destination.Reset
import com.stripe.android.financialconnections.navigation.NavigationManager
import com.stripe.android.financialconnections.navigation.destination
import com.stripe.android.financialconnections.ui.FinancialConnectionsSheetNativeActivity
import com.stripe.android.financialconnections.ui.HandleClickableUrl
import com.stripe.android.financialconnections.utils.measureTimeMillis
import kotlinx.coroutines.launch
Expand All @@ -51,7 +52,7 @@ internal class AccountPickerViewModel @Inject constructor(
private val handleClickableUrl: HandleClickableUrl,
private val logger: Logger,
private val pollAuthorizationSessionAccounts: PollAuthorizationSessionAccounts
) : MavericksViewModel<AccountPickerState>(initialState) {
) : FinancialConnectionsViewModel<AccountPickerState>(initialState) {

init {
logErrors()
Expand All @@ -61,7 +62,7 @@ internal class AccountPickerViewModel @Inject constructor(

private fun loadAccounts() {
suspend {
val state = awaitState()
val state = stateFlow.value
val sync = getOrFetchSync()
val dataAccessNotice = sync.text?.consent?.dataAccessNotice
val manifest = sync.manifest
Expand Down Expand Up @@ -308,21 +309,18 @@ internal class AccountPickerViewModel @Inject constructor(
setState { copy(viewEffect = null) }
}

companion object :
MavericksViewModelFactory<AccountPickerViewModel, AccountPickerState> {

override fun create(
viewModelContext: ViewModelContext,
state: AccountPickerState
): AccountPickerViewModel {
return viewModelContext.activity<FinancialConnectionsSheetNativeActivity>()
.viewModel
.activityRetainedComponent
.accountPickerBuilder
.initialState(state)
.build()
.viewModel
}
companion object {

fun factory(parentComponent: FinancialConnectionsSheetNativeComponent): ViewModelProvider.Factory =
viewModelFactory {
initializer {
parentComponent
.accountPickerBuilder
.initialState(AccountPickerState())
.build()
.viewModel
}
}

private val PANE = Pane.ACCOUNT_PICKER
}
Expand All @@ -334,7 +332,7 @@ internal data class AccountPickerState(
val selectAccounts: Async<PartnerAccountsList> = Uninitialized,
val selectedIds: Set<String> = emptySet(),
val viewEffect: ViewEffect? = null
) : MavericksState {
) {

val submitLoading: Boolean
get() = payload is Loading || selectAccounts is Loading
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ package com.stripe.android.financialconnections.features.attachpayment

import androidx.activity.compose.BackHandler
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.ui.tooling.preview.Preview
import com.airbnb.mvrx.Async
import com.airbnb.mvrx.Fail
import com.airbnb.mvrx.Loading
import com.airbnb.mvrx.Success
import com.airbnb.mvrx.Uninitialized
import com.airbnb.mvrx.compose.collectAsState
import com.airbnb.mvrx.compose.mavericksViewModel
import com.stripe.android.financialconnections.core.Async
import com.stripe.android.financialconnections.core.Async.Fail
import com.stripe.android.financialconnections.core.Async.Loading
import com.stripe.android.financialconnections.core.Async.Success
import com.stripe.android.financialconnections.core.Async.Uninitialized
import com.stripe.android.financialconnections.core.paneViewModel
import com.stripe.android.financialconnections.exception.AccountNumberRetrievalError
import com.stripe.android.financialconnections.features.common.AccountNumberRetrievalErrorContent
import com.stripe.android.financialconnections.features.common.FullScreenGenericLoading
Expand All @@ -23,9 +23,9 @@ import com.stripe.android.financialconnections.ui.components.FinancialConnection

@Composable
internal fun AttachPaymentScreen() {
val viewModel: AttachPaymentViewModel = mavericksViewModel()
val viewModel: AttachPaymentViewModel = paneViewModel { AttachPaymentViewModel.factory(it) }
val parentViewModel = parentViewModel()
val state = viewModel.collectAsState()
val state = viewModel.stateFlow.collectAsState()
BackHandler(enabled = true) {}
AttachPaymentContent(
attachPayment = state.value.linkPaymentAccount,
Expand Down Expand Up @@ -56,6 +56,7 @@ private fun AttachPaymentContent(
is Loading,
is Uninitialized,
is Success -> FullScreenGenericLoading()

is Fail -> ErrorContent(
error = attachPayment.error,
onSelectAnotherBank = onSelectAnotherBank,
Expand All @@ -79,6 +80,7 @@ private fun ErrorContent(
onSelectAnotherBank = onSelectAnotherBank,
onEnterDetailsManually = onEnterDetailsManually
)

else -> UnclassifiedErrorContent { onCloseFromErrorClick(error) }
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
package com.stripe.android.financialconnections.features.attachpayment

import com.airbnb.mvrx.Async
import com.airbnb.mvrx.MavericksState
import com.airbnb.mvrx.MavericksViewModel
import com.airbnb.mvrx.MavericksViewModelFactory
import com.airbnb.mvrx.Uninitialized
import com.airbnb.mvrx.ViewModelContext
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewmodel.initializer
import androidx.lifecycle.viewmodel.viewModelFactory
import com.stripe.android.core.Logger
import com.stripe.android.financialconnections.R
import com.stripe.android.financialconnections.analytics.FinancialConnectionsAnalyticsEvent.PollAttachPaymentsSucceeded
import com.stripe.android.financialconnections.analytics.FinancialConnectionsAnalyticsTracker
import com.stripe.android.financialconnections.analytics.logError
import com.stripe.android.financialconnections.core.Async
import com.stripe.android.financialconnections.core.Async.Uninitialized
import com.stripe.android.financialconnections.core.FinancialConnectionsViewModel
import com.stripe.android.financialconnections.di.FinancialConnectionsSheetNativeComponent
import com.stripe.android.financialconnections.domain.GetCachedAccounts
import com.stripe.android.financialconnections.domain.GetCachedConsumerSession
import com.stripe.android.financialconnections.domain.GetOrFetchSync
Expand All @@ -23,7 +24,6 @@ import com.stripe.android.financialconnections.navigation.Destination.Reset
import com.stripe.android.financialconnections.navigation.NavigationManager
import com.stripe.android.financialconnections.navigation.destination
import com.stripe.android.financialconnections.repository.SuccessContentRepository
import com.stripe.android.financialconnections.ui.FinancialConnectionsSheetNativeActivity
import com.stripe.android.financialconnections.ui.TextResource.PluralId
import com.stripe.android.financialconnections.utils.measureTimeMillis
import javax.inject.Inject
Expand All @@ -38,7 +38,7 @@ internal class AttachPaymentViewModel @Inject constructor(
private val getOrFetchSync: GetOrFetchSync,
private val getCachedConsumerSession: GetCachedConsumerSession,
private val logger: Logger
) : MavericksViewModel<AttachPaymentState>(initialState) {
) : FinancialConnectionsViewModel<AttachPaymentState>(initialState) {

init {
logErrors()
Expand Down Expand Up @@ -103,25 +103,23 @@ internal class AttachPaymentViewModel @Inject constructor(
fun onSelectAnotherBank() =
navigationManager.tryNavigateTo(Reset(referrer = PANE))

companion object : MavericksViewModelFactory<AttachPaymentViewModel, AttachPaymentState> {
companion object {

override fun create(
viewModelContext: ViewModelContext,
state: AttachPaymentState
): AttachPaymentViewModel {
return viewModelContext.activity<FinancialConnectionsSheetNativeActivity>()
.viewModel
.activityRetainedComponent
.attachPaymentSubcomponent
.initialState(state)
.build()
.viewModel
}
fun factory(parentComponent: FinancialConnectionsSheetNativeComponent): ViewModelProvider.Factory =
viewModelFactory {
initializer {
parentComponent
.attachPaymentSubcomponent
.initialState(AttachPaymentState())
.build()
.viewModel
}
}

private val PANE = Pane.ATTACH_LINKED_PAYMENT_ACCOUNT
}
}

internal data class AttachPaymentState(
val linkPaymentAccount: Async<LinkAccountSessionPaymentAccount> = Uninitialized
) : MavericksState
)
Loading

0 comments on commit 6ca0025

Please sign in to comment.