diff --git a/example/dependencies/dependencies.txt b/example/dependencies/dependencies.txt index a19c531f529..5f5e02888ac 100644 --- a/example/dependencies/dependencies.txt +++ b/example/dependencies/dependencies.txt @@ -994,15 +994,6 @@ | | | \--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 1.9.10 (*) | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:{require 1.6.4; reject _} -> 1.7.3 (*) | | \--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 1.9.10 (*) -| +--- com.airbnb.android:mavericks-compose:3.0.9 -| | +--- androidx.lifecycle:lifecycle-common-java8:{require 2.6.1; reject _} -> 2.7.0 (*) -| | +--- androidx.fragment:fragment:{require 1.5.2; reject _} -> 1.6.2 (*) -| | +--- androidx.appcompat:appcompat:{require 1.5.0; reject _} -> 1.6.1 (*) -| | +--- androidx.compose.foundation:foundation:{require 1.2.1; reject _} -> 1.5.4 (*) -| | +--- androidx.compose.ui:ui:{require 1.2.1; reject _} -> 1.5.4 (*) -| | +--- androidx.lifecycle:lifecycle-viewmodel-compose:{require 2.6.1; reject _} -> 2.7.0 (*) -| | +--- com.airbnb.android:mavericks:3.0.9 (*) -| | \--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 1.9.10 (*) | \--- org.jetbrains.kotlin:kotlin-parcelize-runtime:1.9.22 (*) +--- com.google.accompanist:accompanist-themeadapter-material:0.32.0 (*) +--- com.alipay.sdk:alipaysdk-android:15.8.12 diff --git a/financial-connections-example/dependencies/dependencies.txt b/financial-connections-example/dependencies/dependencies.txt index effcb618c42..6e97dab45b8 100644 --- a/financial-connections-example/dependencies/dependencies.txt +++ b/financial-connections-example/dependencies/dependencies.txt @@ -685,15 +685,6 @@ | | | \--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 1.9.10 (*) | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:{require 1.6.4; reject _} -> 1.7.3 (*) | | \--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 1.9.10 (*) -| +--- com.airbnb.android:mavericks-compose:3.0.9 -| | +--- androidx.lifecycle:lifecycle-common-java8:{require 2.6.1; reject _} -> 2.7.0 (*) -| | +--- androidx.fragment:fragment:{require 1.5.2; reject _} -> 1.6.2 (*) -| | +--- androidx.appcompat:appcompat:{require 1.5.0; reject _} -> 1.6.1 (*) -| | +--- androidx.compose.foundation:foundation:{require 1.2.1; reject _} -> 1.5.4 (*) -| | +--- androidx.compose.ui:ui:{require 1.2.1; reject _} -> 1.5.4 (*) -| | +--- androidx.lifecycle:lifecycle-viewmodel-compose:{require 2.6.1; reject _} -> 2.7.0 (*) -| | +--- com.airbnb.android:mavericks:3.0.9 (*) -| | \--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 1.9.10 (*) | \--- org.jetbrains.kotlin:kotlin-parcelize-runtime:1.9.22 (*) +--- project :payments-core | +--- project :stripe-core (*) diff --git a/financial-connections/build.gradle b/financial-connections/build.gradle index 0ba7b8db0ba..35da6c4834a 100644 --- a/financial-connections/build.gradle +++ b/financial-connections/build.gradle @@ -42,7 +42,6 @@ dependencies { implementation libs.kotlin.coroutinesAndroid implementation libs.kotlin.serialization implementation libs.mavericks - implementation libs.mavericksCompose debugImplementation libs.compose.uiTestManifest debugImplementation libs.compose.uiTooling @@ -64,7 +63,6 @@ dependencies { testImplementation testLibs.mockito.core testImplementation testLibs.mockito.inline testImplementation testLibs.mockito.kotlin - testImplementation testLibs.mavericks testImplementation testLibs.robolectric testImplementation testLibs.testParameterInjector testImplementation testLibs.turbine diff --git a/financial-connections/dependencies/dependencies.txt b/financial-connections/dependencies/dependencies.txt index 2527a93ce58..01b29065162 100644 --- a/financial-connections/dependencies/dependencies.txt +++ b/financial-connections/dependencies/dependencies.txt @@ -658,13 +658,4 @@ | | \--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 (*) | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:{require 1.6.4; reject _} -> 1.7.3 (*) | \--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 (*) -+--- com.airbnb.android:mavericks-compose:3.0.9 -| +--- androidx.lifecycle:lifecycle-common-java8:{require 2.6.1; reject _} -> 2.7.0 (*) -| +--- androidx.fragment:fragment:{require 1.5.2; reject _} -> 1.5.2 (*) -| +--- androidx.appcompat:appcompat:{require 1.5.0; reject _} -> 1.6.1 (*) -| +--- androidx.compose.foundation:foundation:{require 1.2.1; reject _} -> 1.5.4 (*) -| +--- androidx.compose.ui:ui:{require 1.2.1; reject _} -> 1.5.4 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:{require 2.6.1; reject _} -> 2.7.0 (*) -| +--- com.airbnb.android:mavericks:3.0.9 (*) -| \--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 (*) \--- org.jetbrains.kotlin:kotlin-parcelize-runtime:1.9.22 (*) \ No newline at end of file diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/FinancialConnectionsSheetState.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/FinancialConnectionsSheetState.kt index 6ec67c4a3bd..1bd27c66b67 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/FinancialConnectionsSheetState.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/FinancialConnectionsSheetState.kt @@ -2,7 +2,6 @@ package com.stripe.android.financialconnections import android.os.Bundle import androidx.annotation.StringRes -import com.airbnb.mvrx.MavericksState import com.stripe.android.financialconnections.launcher.FinancialConnectionsSheetActivityArgs import com.stripe.android.financialconnections.launcher.FinancialConnectionsSheetActivityResult import com.stripe.android.financialconnections.model.FinancialConnectionsSessionManifest @@ -17,7 +16,7 @@ internal data class FinancialConnectionsSheetState( val manifest: FinancialConnectionsSessionManifest?, val webAuthFlowStatus: AuthFlowStatus, val viewEffect: FinancialConnectionsSheetViewEffect? -) : MavericksState { +) { val sessionSecret: String get() = initialArgs.configuration.financialConnectionsSessionClientSecret diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/di/FinancialConnectionsSheetNativeModule.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/di/FinancialConnectionsSheetNativeModule.kt index 549abb755e0..5c6a97a0c71 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/di/FinancialConnectionsSheetNativeModule.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/di/FinancialConnectionsSheetNativeModule.kt @@ -3,11 +3,9 @@ package com.stripe.android.financialconnections.di import android.app.Application import com.stripe.android.core.ApiVersion import com.stripe.android.core.Logger -import com.stripe.android.core.injection.IOContext import com.stripe.android.core.networking.ApiRequest import com.stripe.android.core.networking.StripeNetworkClient import com.stripe.android.core.version.StripeSdkVersion -import com.stripe.android.financialconnections.analytics.FinancialConnectionsAnalyticsTracker import com.stripe.android.financialconnections.domain.HandleError import com.stripe.android.financialconnections.domain.RealHandleError import com.stripe.android.financialconnections.features.accountpicker.AccountPickerSubcomponent @@ -37,12 +35,9 @@ import com.stripe.android.uicore.image.StripeImageLoader import dagger.Binds import dagger.Module import dagger.Provides -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.SupervisorJob import java.util.Locale import javax.inject.Named import javax.inject.Singleton -import kotlin.coroutines.CoroutineContext @Module( subcomponents = [ @@ -162,13 +157,9 @@ internal interface FinancialConnectionsSheetNativeModule { @Singleton @Provides fun providesPartnerToCoreAuthsRepository( - logger: Logger, - @IOContext workContext: CoroutineContext, - analyticsTracker: FinancialConnectionsAnalyticsTracker + logger: Logger ) = CoreAuthorizationPendingNetworkingRepairRepository( - coroutineScope = CoroutineScope(SupervisorJob() + workContext), - logger = logger, - analyticsTracker = analyticsTracker + logger = logger ) @Provides diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/error/ErrorPreviewParameterProvider.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/error/ErrorPreviewParameterProvider.kt index 48a5f15f9be..cae4a302420 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/error/ErrorPreviewParameterProvider.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/error/ErrorPreviewParameterProvider.kt @@ -1,9 +1,9 @@ package com.stripe.android.financialconnections.features.error import androidx.compose.ui.tooling.preview.PreviewParameterProvider -import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.Success import com.stripe.android.core.exception.APIException +import com.stripe.android.financialconnections.core.Async.Loading +import com.stripe.android.financialconnections.core.Async.Success import com.stripe.android.financialconnections.exception.InstitutionPlannedDowntimeError import com.stripe.android.financialconnections.exception.InstitutionUnplannedDowntimeError import com.stripe.android.financialconnections.model.FinancialConnectionsInstitution diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/error/ErrorScreen.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/error/ErrorScreen.kt index 4172af0fba5..4131bfb5290 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/error/ErrorScreen.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/error/ErrorScreen.kt @@ -2,15 +2,16 @@ package com.stripe.android.financialconnections.features.error import androidx.activity.compose.BackHandler import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter -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.InstitutionPlannedDowntimeError import com.stripe.android.financialconnections.exception.InstitutionUnplannedDowntimeError import com.stripe.android.financialconnections.exception.PartnerAuthError @@ -26,12 +27,12 @@ import com.stripe.android.financialconnections.ui.components.FinancialConnection @Composable internal fun ErrorScreen() { - val viewModel: ErrorViewModel = mavericksViewModel() + val viewModel: ErrorViewModel = paneViewModel(ErrorViewModel.Companion::factory) val parentViewModel = parentViewModel() BackHandler(true) { } - val payload = viewModel.collectAsState { it.payload } + val state by viewModel.stateFlow.collectAsState() ErrorContent( - payload = payload.value, + payload = state.payload, onManualEntryClick = viewModel::onManualEntryClick, onSelectBankClick = viewModel::onSelectAnotherBank, onCloseFromErrorClick = parentViewModel::onCloseFromErrorClick diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/error/ErrorViewModel.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/error/ErrorViewModel.kt index a84e837f654..51e028ff8e6 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/error/ErrorViewModel.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/error/ErrorViewModel.kt @@ -1,14 +1,16 @@ package com.stripe.android.financialconnections.features.error -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.viewModelScope +import androidx.lifecycle.viewmodel.initializer +import androidx.lifecycle.viewmodel.viewModelFactory import com.stripe.android.core.Logger 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.GetManifest import com.stripe.android.financialconnections.domain.NativeAuthFlowCoordinator import com.stripe.android.financialconnections.domain.NativeAuthFlowCoordinator.Message @@ -17,7 +19,6 @@ import com.stripe.android.financialconnections.navigation.Destination import com.stripe.android.financialconnections.navigation.NavigationManager import com.stripe.android.financialconnections.navigation.PopUpToBehavior import com.stripe.android.financialconnections.repository.FinancialConnectionsErrorRepository -import com.stripe.android.financialconnections.ui.FinancialConnectionsSheetNativeActivity import kotlinx.coroutines.launch import javax.inject.Inject @@ -29,7 +30,7 @@ internal class ErrorViewModel @Inject constructor( private val eventTracker: FinancialConnectionsAnalyticsTracker, private val navigationManager: NavigationManager, private val logger: Logger -) : MavericksViewModel(initialState) { +) : FinancialConnectionsViewModel(initialState) { init { logErrors() @@ -83,7 +84,7 @@ internal class ErrorViewModel @Inject constructor( fun onSelectAnotherBank() = viewModelScope.launch { kotlin.runCatching { - val payload = requireNotNull(awaitState().payload()) + val payload = requireNotNull(stateFlow.value.payload()) if (payload.disableLinkMoreAccounts) { close(payload.error) } else { @@ -99,19 +100,17 @@ internal class ErrorViewModel @Inject constructor( super.onCleared() } - companion object : MavericksViewModelFactory { + companion object { - override fun create( - viewModelContext: ViewModelContext, - state: ErrorState - ): ErrorViewModel { - return viewModelContext.activity() - .viewModel - .activityRetainedComponent - .errorSubcomponent - .create(state) - .viewModel - } + fun factory(parentComponent: FinancialConnectionsSheetNativeComponent): ViewModelProvider.Factory = + viewModelFactory { + initializer { + parentComponent + .errorSubcomponent + .create(ErrorState()) + .viewModel + } + } internal val PANE = Pane.UNEXPECTED_ERROR } @@ -119,7 +118,7 @@ internal class ErrorViewModel @Inject constructor( internal data class ErrorState( val payload: Async = Uninitialized -) : MavericksState { +) { data class Payload( val error: Throwable, val disableLinkMoreAccounts: Boolean, diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/exit/ExitModal.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/exit/ExitModal.kt index 8862c8d17c0..7017055f218 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/exit/ExitModal.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/exit/ExitModal.kt @@ -7,6 +7,7 @@ import androidx.compose.foundation.layout.size import androidx.compose.material.Surface import androidx.compose.material.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource @@ -14,9 +15,8 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.navigation.NavBackStackEntry -import com.airbnb.mvrx.compose.collectAsState -import com.airbnb.mvrx.compose.mavericksViewModel import com.stripe.android.financialconnections.R +import com.stripe.android.financialconnections.core.paneViewModel import com.stripe.android.financialconnections.features.common.ShapedIcon import com.stripe.android.financialconnections.ui.TextResource import com.stripe.android.financialconnections.ui.components.FinancialConnectionsButton @@ -29,9 +29,11 @@ import com.stripe.android.financialconnections.ui.theme.Layout internal fun ExitModal( backStackEntry: NavBackStackEntry ) { - val viewModel: ExitViewModel = mavericksViewModel(argsFactory = { backStackEntry.arguments }) + val viewModel: ExitViewModel = paneViewModel { + ExitViewModel.factory(it, backStackEntry.arguments) + } - val state by viewModel.collectAsState() + val state by viewModel.stateFlow.collectAsState() state.payload()?.let { ExitModalContent( description = it.description, diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/exit/ExitViewModel.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/exit/ExitViewModel.kt index 37e98ec4c34..c6a6a21827c 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/exit/ExitViewModel.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/exit/ExitViewModel.kt @@ -1,16 +1,17 @@ package com.stripe.android.financialconnections.features.exit import android.os.Bundle -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.viewModelScope +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.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.GetManifest import com.stripe.android.financialconnections.domain.NativeAuthFlowCoordinator import com.stripe.android.financialconnections.domain.NativeAuthFlowCoordinator.Message @@ -18,7 +19,6 @@ import com.stripe.android.financialconnections.features.common.getBusinessName import com.stripe.android.financialconnections.model.FinancialConnectionsSessionManifest.Pane import com.stripe.android.financialconnections.navigation.Destination import com.stripe.android.financialconnections.navigation.NavigationManager -import com.stripe.android.financialconnections.ui.FinancialConnectionsSheetNativeActivity import com.stripe.android.financialconnections.ui.TextResource import kotlinx.coroutines.launch import javax.inject.Inject @@ -30,7 +30,7 @@ internal class ExitViewModel @Inject constructor( private val eventTracker: FinancialConnectionsAnalyticsTracker, private val navigationManager: NavigationManager, private val logger: Logger -) : MavericksViewModel(initialState) { +) : FinancialConnectionsViewModel(initialState) { init { logErrors() @@ -38,7 +38,7 @@ internal class ExitViewModel @Inject constructor( val manifest = kotlin.runCatching { getManifest() }.getOrNull() val businessName = manifest?.getBusinessName() val isNetworkingSignupPane = - manifest?.isNetworkingUserFlow == true && awaitState().referrer == Pane.NETWORKING_LINK_SIGNUP_PANE + manifest?.isNetworkingUserFlow == true && stateFlow.value.referrer == Pane.NETWORKING_LINK_SIGNUP_PANE val description = when { isNetworkingSignupPane -> when (businessName) { null -> TextResource.StringId(R.string.stripe_close_dialog_networking_desc_no_business) @@ -85,18 +85,15 @@ internal class ExitViewModel @Inject constructor( ) } - companion object : MavericksViewModelFactory { + companion object { - override fun create( - viewModelContext: ViewModelContext, - state: ExitState - ): ExitViewModel { - return viewModelContext.activity() - .viewModel - .activityRetainedComponent - .exitSubcomponent - .create(state) - .viewModel + fun factory(parentComponent: FinancialConnectionsSheetNativeComponent, arguments: Bundle?) = viewModelFactory { + initializer { + parentComponent + .exitSubcomponent + .create(ExitState(arguments)) + .viewModel + } } internal val PANE = Pane.EXIT @@ -107,7 +104,7 @@ internal data class ExitState( val referrer: Pane?, val payload: Async, val closing: Boolean -) : MavericksState { +) { data class Payload( val description: TextResource, ) diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/linkaccountpicker/LinkAccountPickerPreviewParameterProvider.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/linkaccountpicker/LinkAccountPickerPreviewParameterProvider.kt index 72d201d2f8f..4e54d9cb033 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/linkaccountpicker/LinkAccountPickerPreviewParameterProvider.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/linkaccountpicker/LinkAccountPickerPreviewParameterProvider.kt @@ -1,8 +1,8 @@ package com.stripe.android.financialconnections.features.linkaccountpicker import androidx.compose.ui.tooling.preview.PreviewParameterProvider -import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.Success +import com.stripe.android.financialconnections.core.Async.Loading +import com.stripe.android.financialconnections.core.Async.Success import com.stripe.android.financialconnections.features.common.MerchantDataAccessModel import com.stripe.android.financialconnections.model.AddNewAccount import com.stripe.android.financialconnections.model.Bullet diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/linkaccountpicker/LinkAccountPickerScreen.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/linkaccountpicker/LinkAccountPickerScreen.kt index e71952527ad..5f8f4c4a482 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/linkaccountpicker/LinkAccountPickerScreen.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/linkaccountpicker/LinkAccountPickerScreen.kt @@ -28,6 +28,7 @@ import androidx.compose.material.Text import androidx.compose.material.rememberModalBottomSheetState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment @@ -41,14 +42,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.features.common.AccountItem import com.stripe.android.financialconnections.features.common.DataAccessBottomSheetContent import com.stripe.android.financialconnections.features.common.LoadingShimmerEffect @@ -94,9 +94,9 @@ import kotlinx.coroutines.launch */ @Composable internal fun LinkAccountPickerScreen() { - val viewModel: LinkAccountPickerViewModel = mavericksViewModel() + val viewModel: LinkAccountPickerViewModel = paneViewModel { LinkAccountPickerViewModel.factory(it) } val parentViewModel = parentViewModel() - val state = viewModel.collectAsState() + val state = viewModel.stateFlow.collectAsState() BackHandler(enabled = true) {} val bottomSheetState = rememberModalBottomSheetState( diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/linkaccountpicker/LinkAccountPickerViewModel.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/linkaccountpicker/LinkAccountPickerViewModel.kt index 23d34ae0a2a..6ab2f792de5 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/linkaccountpicker/LinkAccountPickerViewModel.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/linkaccountpicker/LinkAccountPickerViewModel.kt @@ -1,11 +1,9 @@ package com.stripe.android.financialconnections.features.linkaccountpicker -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.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 @@ -15,6 +13,10 @@ 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.Uninitialized +import com.stripe.android.financialconnections.core.FinancialConnectionsViewModel +import com.stripe.android.financialconnections.di.FinancialConnectionsSheetNativeComponent import com.stripe.android.financialconnections.domain.FetchNetworkedAccounts import com.stripe.android.financialconnections.domain.GetCachedConsumerSession import com.stripe.android.financialconnections.domain.GetOrFetchSync @@ -34,7 +36,6 @@ import com.stripe.android.financialconnections.navigation.Destination import com.stripe.android.financialconnections.navigation.NavigationManager import com.stripe.android.financialconnections.navigation.destination import com.stripe.android.financialconnections.repository.CoreAuthorizationPendingNetworkingRepairRepository -import com.stripe.android.financialconnections.ui.FinancialConnectionsSheetNativeActivity import com.stripe.android.financialconnections.ui.HandleClickableUrl import kotlinx.coroutines.launch import java.util.Date @@ -53,7 +54,7 @@ internal class LinkAccountPickerViewModel @Inject constructor( private val getSync: GetOrFetchSync, private val navigationManager: NavigationManager, private val logger: Logger -) : MavericksViewModel(initialState) { +) : FinancialConnectionsViewModel(initialState) { init { observeAsyncs() @@ -141,12 +142,12 @@ internal class LinkAccountPickerViewModel @Inject constructor( fun onNewBankAccountClick() = viewModelScope.launch { eventTracker.track(Click("click.new_account", PANE)) - val nextPane = awaitState().payload()?.nextPaneOnNewAccount ?: Pane.INSTITUTION_PICKER + val nextPane = stateFlow.value.payload()?.nextPaneOnNewAccount ?: Pane.INSTITUTION_PICKER navigationManager.tryNavigateTo(nextPane.destination(referrer = PANE)) } fun onSelectAccountClick() = suspend { - val state = awaitState() + val state = stateFlow.value val payload = requireNotNull(state.payload()) val (account, _) = requireNotNull(payload.accounts.first { it.first.id == state.selectedAccountId }) @@ -200,23 +201,20 @@ internal class LinkAccountPickerViewModel @Inject constructor( setState { copy(viewEffect = null) } } - companion object : - MavericksViewModelFactory { + companion object { internal val PANE = Pane.LINK_ACCOUNT_PICKER - override fun create( - viewModelContext: ViewModelContext, - state: LinkAccountPickerState - ): LinkAccountPickerViewModel { - return viewModelContext.activity() - .viewModel - .activityRetainedComponent - .linkAccountPickerSubcomponent - .initialState(state) - .build() - .viewModel - } + fun factory(parentComponent: FinancialConnectionsSheetNativeComponent): ViewModelProvider.Factory = + viewModelFactory { + initializer { + parentComponent + .linkAccountPickerSubcomponent + .initialState(LinkAccountPickerState()) + .build() + .viewModel + } + } } } @@ -225,7 +223,7 @@ internal data class LinkAccountPickerState( val selectNetworkedAccountAsync: Async = Uninitialized, val selectedAccountId: String? = null, val viewEffect: ViewEffect? = null -) : MavericksState { +) { data class Payload( val title: String, diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/linkstepupverification/LinkStepUpVerificationPreviewParameterProvider.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/linkstepupverification/LinkStepUpVerificationPreviewParameterProvider.kt index fb2bb75c8d3..28b11c2f2f3 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/linkstepupverification/LinkStepUpVerificationPreviewParameterProvider.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/linkstepupverification/LinkStepUpVerificationPreviewParameterProvider.kt @@ -1,10 +1,10 @@ package com.stripe.android.financialconnections.features.linkstepupverification import androidx.compose.ui.tooling.preview.PreviewParameterProvider -import com.airbnb.mvrx.Fail -import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.Success -import com.airbnb.mvrx.Uninitialized +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.domain.ConfirmVerification import com.stripe.android.uicore.elements.IdentifierSpec import com.stripe.android.uicore.elements.OTPController diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/linkstepupverification/LinkStepUpVerificationScreen.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/linkstepupverification/LinkStepUpVerificationScreen.kt index b8c2d9298ed..6a04c242f84 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/linkstepupverification/LinkStepUpVerificationScreen.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/linkstepupverification/LinkStepUpVerificationScreen.kt @@ -14,6 +14,7 @@ import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -24,13 +25,12 @@ 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.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.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.domain.ConfirmVerification.OTPError import com.stripe.android.financialconnections.features.common.FullScreenGenericLoading import com.stripe.android.financialconnections.features.common.LoadingSpinner @@ -52,9 +52,11 @@ import com.stripe.android.financialconnections.ui.theme.LazyLayout @Composable internal fun LinkStepUpVerificationScreen() { - val viewModel: LinkStepUpVerificationViewModel = mavericksViewModel() + val viewModel: LinkStepUpVerificationViewModel = paneViewModel { + LinkStepUpVerificationViewModel.factory(it) + } val parentViewModel = parentViewModel() - val state = viewModel.collectAsState() + val state = viewModel.stateFlow.collectAsState() BackHandler(enabled = true) {} LinkStepUpVerificationContent( state = state.value, diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/linkstepupverification/LinkStepUpVerificationViewModel.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/linkstepupverification/LinkStepUpVerificationViewModel.kt index 64e308810be..206e691e6d2 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/linkstepupverification/LinkStepUpVerificationViewModel.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/linkstepupverification/LinkStepUpVerificationViewModel.kt @@ -1,14 +1,9 @@ package com.stripe.android.financialconnections.features.linkstepupverification -import com.airbnb.mvrx.Async -import com.airbnb.mvrx.Fail -import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.MavericksState -import com.airbnb.mvrx.MavericksViewModel -import com.airbnb.mvrx.MavericksViewModelFactory -import com.airbnb.mvrx.Success -import com.airbnb.mvrx.Uninitialized -import com.airbnb.mvrx.ViewModelContext +import androidx.lifecycle.ViewModelProvider.Factory +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.analytics.FinancialConnectionsAnalyticsEvent.VerificationStepUpError import com.stripe.android.financialconnections.analytics.FinancialConnectionsAnalyticsEvent.VerificationStepUpError.Error.ConsumerNotFoundError @@ -18,6 +13,13 @@ import com.stripe.android.financialconnections.analytics.FinancialConnectionsAna import com.stripe.android.financialconnections.analytics.FinancialConnectionsAnalyticsEvent.VerificationStepUpSuccess 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.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.FinancialConnectionsViewModel +import com.stripe.android.financialconnections.di.FinancialConnectionsSheetNativeComponent import com.stripe.android.financialconnections.domain.ConfirmVerification import com.stripe.android.financialconnections.domain.GetCachedAccounts import com.stripe.android.financialconnections.domain.GetManifest @@ -31,7 +33,6 @@ import com.stripe.android.financialconnections.model.FinancialConnectionsSession import com.stripe.android.financialconnections.navigation.Destination import com.stripe.android.financialconnections.navigation.Destination.InstitutionPicker import com.stripe.android.financialconnections.navigation.NavigationManager -import com.stripe.android.financialconnections.ui.FinancialConnectionsSheetNativeActivity import com.stripe.android.model.ConsumerSession import com.stripe.android.model.VerificationType import com.stripe.android.uicore.elements.IdentifierSpec @@ -55,7 +56,7 @@ internal class LinkStepUpVerificationViewModel @Inject constructor( private val updateCachedAccounts: UpdateCachedAccounts, private val navigationManager: NavigationManager, private val logger: Logger -) : MavericksViewModel(initialState) { +) : FinancialConnectionsViewModel(initialState) { init { logErrors() @@ -133,7 +134,7 @@ internal class LinkStepUpVerificationViewModel @Inject constructor( } private fun onOTPEntered(otp: String) = suspend { - val payload = requireNotNull(awaitState().payload()) + val payload = requireNotNull(stateFlow.value.payload()) // Confirm email. confirmVerification.email( consumerSessionClientSecret = payload.consumerSessionClientSecret, @@ -203,21 +204,18 @@ internal class LinkStepUpVerificationViewModel @Inject constructor( ) } - companion object : - MavericksViewModelFactory { - - override fun create( - viewModelContext: ViewModelContext, - state: LinkStepUpVerificationState - ): LinkStepUpVerificationViewModel { - return viewModelContext.activity() - .viewModel - .activityRetainedComponent - .linkStepUpVerificationSubcomponent - .initialState(state) - .build() - .viewModel - } + companion object { + + fun factory(parentComponent: FinancialConnectionsSheetNativeComponent): Factory = + viewModelFactory { + initializer { + parentComponent + .linkStepUpVerificationSubcomponent + .initialState(LinkStepUpVerificationState()) + .build() + .viewModel + } + } private const val CLICKABLE_TEXT_RESEND_CODE = "resend_code" internal val PANE = Pane.LINK_STEP_UP_VERIFICATION @@ -228,7 +226,7 @@ internal data class LinkStepUpVerificationState( val payload: Async = Uninitialized, val confirmVerification: Async = Uninitialized, val resendOtp: Async = Uninitialized, -) : MavericksState { +) { val submitLoading: Boolean get() = confirmVerification is Loading || resendOtp is Loading diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/manualentry/ManualEntryPreviewParameterProvider.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/manualentry/ManualEntryPreviewParameterProvider.kt index 54999334329..245d7ea518e 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/manualentry/ManualEntryPreviewParameterProvider.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/manualentry/ManualEntryPreviewParameterProvider.kt @@ -1,12 +1,12 @@ package com.stripe.android.financialconnections.features.manualentry import androidx.compose.ui.tooling.preview.PreviewParameterProvider -import com.airbnb.mvrx.Fail -import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.Success -import com.airbnb.mvrx.Uninitialized import com.stripe.android.core.exception.APIException import com.stripe.android.financialconnections.R +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.features.manualentry.ManualEntryPreviewParameterProvider.PreviewState internal class ManualEntryPreviewParameterProvider : PreviewParameterProvider { diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/manualentry/ManualEntryScreen.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/manualentry/ManualEntryScreen.kt index c9f093bc31e..b12a7a9abb2 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/manualentry/ManualEntryScreen.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/manualentry/ManualEntryScreen.kt @@ -24,15 +24,14 @@ import androidx.compose.ui.text.style.TextAlign 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.core.exception.StripeException 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.features.common.FullScreenGenericLoading import com.stripe.android.financialconnections.features.common.UnclassifiedErrorContent import com.stripe.android.financialconnections.features.manualentry.ManualEntryPreviewParameterProvider.PreviewState @@ -52,16 +51,18 @@ import com.stripe.android.financialconnections.ui.theme.Layout @Composable internal fun ManualEntryScreen() { - val viewModel: ManualEntryViewModel = mavericksViewModel() + val viewModel: ManualEntryViewModel = paneViewModel { + ManualEntryViewModel.factory(it) + } val parentViewModel = parentViewModel() - val state: ManualEntryState by viewModel.collectAsState() + val state: ManualEntryState by viewModel.stateFlow.collectAsState() val form by viewModel.form.collectAsState() ManualEntryContent( - routing = viewModel.routing ?: "", + routing = viewModel.routing, routingError = form.routingError, - account = viewModel.account ?: "", + account = viewModel.account, accountError = form.accountError, - accountConfirm = viewModel.accountConfirm ?: "", + accountConfirm = viewModel.accountConfirm, accountConfirmError = form.accountConfirmError, isValidForm = form.isValid, payload = state.payload, diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/manualentry/ManualEntryViewModel.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/manualentry/ManualEntryViewModel.kt index 1cb782327ad..a4e661653f6 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/manualentry/ManualEntryViewModel.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/manualentry/ManualEntryViewModel.kt @@ -4,17 +4,19 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.compose.runtime.snapshotFlow -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.viewModelScope +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.PaneLoaded 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.GetOrFetchSync import com.stripe.android.financialconnections.domain.NativeAuthFlowCoordinator import com.stripe.android.financialconnections.domain.NativeAuthFlowCoordinator.Message.Complete @@ -27,7 +29,6 @@ import com.stripe.android.financialconnections.model.PaymentAccountParams import com.stripe.android.financialconnections.navigation.Destination import com.stripe.android.financialconnections.navigation.NavigationManager import com.stripe.android.financialconnections.repository.SuccessContentRepository -import com.stripe.android.financialconnections.ui.FinancialConnectionsSheetNativeActivity import com.stripe.android.financialconnections.ui.TextResource import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow @@ -44,7 +45,7 @@ internal class ManualEntryViewModel @Inject constructor( private val getOrFetchSync: GetOrFetchSync, private val navigationManager: NavigationManager, private val logger: Logger -) : MavericksViewModel(initialState) { +) : FinancialConnectionsViewModel(initialState) { // Keep form fields outside of State for immediate updates. private var _routing: String? by mutableStateOf(null) @@ -158,21 +159,18 @@ internal class ManualEntryViewModel @Inject constructor( onSubmit() } - companion object : - MavericksViewModelFactory { - - override fun create( - viewModelContext: ViewModelContext, - state: ManualEntryState - ): ManualEntryViewModel { - return viewModelContext.activity() - .viewModel - .activityRetainedComponent - .manualEntryBuilder - .initialState(state) - .build() - .viewModel - } + companion object { + + fun factory(parentComponent: FinancialConnectionsSheetNativeComponent): ViewModelProvider.Factory = + viewModelFactory { + initializer { + parentComponent + .manualEntryBuilder + .initialState(ManualEntryState()) + .build() + .viewModel + } + } private val PANE = Pane.MANUAL_ENTRY } @@ -181,7 +179,7 @@ internal class ManualEntryViewModel @Inject constructor( internal data class ManualEntryState( val payload: Async = Uninitialized, val linkPaymentAccount: Async = Uninitialized -) : MavericksState { +) { data class Payload( val verifyWithMicrodeposits: Boolean, diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/networkinglinkloginwarmup/NetworkingLinkLoginWarmupPreviewParameterProvider.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/networkinglinkloginwarmup/NetworkingLinkLoginWarmupPreviewParameterProvider.kt index f5b2cc3c40d..35d195d4a16 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/networkinglinkloginwarmup/NetworkingLinkLoginWarmupPreviewParameterProvider.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/networkinglinkloginwarmup/NetworkingLinkLoginWarmupPreviewParameterProvider.kt @@ -1,10 +1,10 @@ package com.stripe.android.financialconnections.features.networkinglinkloginwarmup import androidx.compose.ui.tooling.preview.PreviewParameterProvider -import com.airbnb.mvrx.Fail -import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.Success -import com.airbnb.mvrx.Uninitialized +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 internal class NetworkingLinkLoginWarmupPreviewParameterProvider : PreviewParameterProvider { diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/networkinglinkloginwarmup/NetworkingLinkLoginWarmupScreen.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/networkinglinkloginwarmup/NetworkingLinkLoginWarmupScreen.kt index 51ad34ccf7a..012ead6045f 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/networkinglinkloginwarmup/NetworkingLinkLoginWarmupScreen.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/networkinglinkloginwarmup/NetworkingLinkLoginWarmupScreen.kt @@ -18,6 +18,7 @@ import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.ExperimentalComposeUiApi @@ -33,10 +34,9 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp import androidx.navigation.NavBackStackEntry -import com.airbnb.mvrx.Loading -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.Loading +import com.stripe.android.financialconnections.core.paneViewModel import com.stripe.android.financialconnections.features.common.ShapedIcon import com.stripe.android.financialconnections.ui.FinancialConnectionsPreview import com.stripe.android.financialconnections.ui.components.FinancialConnectionsButton @@ -50,10 +50,10 @@ import com.stripe.android.financialconnections.ui.theme.LinkColors internal fun NetworkingLinkLoginWarmupScreen( backStackEntry: NavBackStackEntry, ) { - val viewModel: NetworkingLinkLoginWarmupViewModel = mavericksViewModel( - argsFactory = { backStackEntry.arguments }, - ) - val state by viewModel.collectAsState() + val viewModel: NetworkingLinkLoginWarmupViewModel = paneViewModel { + NetworkingLinkLoginWarmupViewModel.factory(it, backStackEntry.arguments) + } + val state by viewModel.stateFlow.collectAsState() NetworkingLinkLoginWarmupContent( state = state, onSkipClicked = viewModel::onSkipClicked, diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/networkinglinkloginwarmup/NetworkingLinkLoginWarmupViewModel.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/networkinglinkloginwarmup/NetworkingLinkLoginWarmupViewModel.kt index 30be9b816aa..82da8bc4864 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/networkinglinkloginwarmup/NetworkingLinkLoginWarmupViewModel.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/networkinglinkloginwarmup/NetworkingLinkLoginWarmupViewModel.kt @@ -1,15 +1,17 @@ package com.stripe.android.financialconnections.features.networkinglinkloginwarmup import android.os.Bundle -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.Factory +import androidx.lifecycle.viewModelScope +import androidx.lifecycle.viewmodel.initializer +import androidx.lifecycle.viewmodel.viewModelFactory import com.stripe.android.financialconnections.analytics.FinancialConnectionsAnalyticsEvent.Click import com.stripe.android.financialconnections.analytics.FinancialConnectionsAnalyticsEvent.PaneLoaded import com.stripe.android.financialconnections.analytics.FinancialConnectionsAnalyticsTracker +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.DisableNetworking import com.stripe.android.financialconnections.domain.GetManifest import com.stripe.android.financialconnections.domain.HandleError @@ -21,7 +23,6 @@ import com.stripe.android.financialconnections.navigation.Destination import com.stripe.android.financialconnections.navigation.NavigationManager import com.stripe.android.financialconnections.navigation.PopUpToBehavior import com.stripe.android.financialconnections.navigation.destination -import com.stripe.android.financialconnections.ui.FinancialConnectionsSheetNativeActivity import kotlinx.coroutines.launch import javax.inject.Inject @@ -32,7 +33,7 @@ internal class NetworkingLinkLoginWarmupViewModel @Inject constructor( private val getManifest: GetManifest, private val disableNetworking: DisableNetworking, private val navigationManager: NavigationManager -) : MavericksViewModel(initialState) { +) : FinancialConnectionsViewModel(initialState) { init { logErrors() @@ -93,7 +94,7 @@ internal class NetworkingLinkLoginWarmupViewModel @Inject constructor( // Skipping disables networking, which means we don't want the user to navigate back to // the warm-up pane. Since the warmup pane is displayed as a bottom sheet, we need to // pop up all the way to the pane that opened it. - val referrer = awaitState().referrer + val referrer = stateFlow.value.referrer return if (referrer != null) { PopUpToBehavior.Route( @@ -106,23 +107,20 @@ internal class NetworkingLinkLoginWarmupViewModel @Inject constructor( } } - companion object : - MavericksViewModelFactory { + companion object { internal val PANE = Pane.NETWORKING_LINK_LOGIN_WARMUP - override fun create( - viewModelContext: ViewModelContext, - state: NetworkingLinkLoginWarmupState - ): NetworkingLinkLoginWarmupViewModel { - return viewModelContext.activity() - .viewModel - .activityRetainedComponent - .networkingLinkLoginWarmupSubcomponent - .initialState(state) - .build() - .viewModel - } + fun factory(parentComponent: FinancialConnectionsSheetNativeComponent, arguments: Bundle?): Factory = + viewModelFactory { + initializer { + parentComponent + .networkingLinkLoginWarmupSubcomponent + .initialState(NetworkingLinkLoginWarmupState(arguments)) + .build() + .viewModel + } + } } } @@ -130,9 +128,8 @@ internal data class NetworkingLinkLoginWarmupState( val referrer: Pane? = null, val payload: Async = Uninitialized, val disableNetworkingAsync: Async = Uninitialized, -) : MavericksState { +) { - @Suppress("unused") // used by mavericks to create initial state. constructor(args: Bundle?) : this( referrer = Destination.referrer(args), payload = Uninitialized, diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/networkinglinksignup/NetworkingLinkSignupPreviewParameterProvider.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/networkinglinksignup/NetworkingLinkSignupPreviewParameterProvider.kt index e40f4e89a7d..76f6b34895c 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/networkinglinksignup/NetworkingLinkSignupPreviewParameterProvider.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/networkinglinksignup/NetworkingLinkSignupPreviewParameterProvider.kt @@ -1,8 +1,8 @@ package com.stripe.android.financialconnections.features.networkinglinksignup import androidx.compose.ui.tooling.preview.PreviewParameterProvider -import com.airbnb.mvrx.Success -import com.airbnb.mvrx.Uninitialized +import com.stripe.android.financialconnections.core.Async.Success +import com.stripe.android.financialconnections.core.Async.Uninitialized import com.stripe.android.financialconnections.model.Bullet import com.stripe.android.financialconnections.model.NetworkingLinkSignupBody import com.stripe.android.financialconnections.model.NetworkingLinkSignupPane diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/networkinglinksignup/NetworkingLinkSignupScreen.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/networkinglinksignup/NetworkingLinkSignupScreen.kt index 6a15d17b500..488032e4682 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/networkinglinksignup/NetworkingLinkSignupScreen.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/networkinglinksignup/NetworkingLinkSignupScreen.kt @@ -22,6 +22,7 @@ import androidx.compose.material.Text import androidx.compose.material.rememberModalBottomSheetState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -42,13 +43,12 @@ import androidx.compose.ui.text.style.TextAlign 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.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.features.common.FullScreenGenericLoading import com.stripe.android.financialconnections.features.common.LegalDetailsBottomSheetContent import com.stripe.android.financialconnections.features.common.ListItem @@ -82,9 +82,9 @@ import kotlinx.coroutines.launch @Composable internal fun NetworkingLinkSignupScreen() { - val viewModel: NetworkingLinkSignupViewModel = mavericksViewModel() + val viewModel: NetworkingLinkSignupViewModel = paneViewModel(NetworkingLinkSignupViewModel.Companion::factory) val parentViewModel = parentViewModel() - val state = viewModel.collectAsState() + val state = viewModel.stateFlow.collectAsState() BackHandler(enabled = true) {} val uriHandler = LocalUriHandler.current val bottomSheetState: ModalBottomSheetState = rememberModalBottomSheetState( diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/networkinglinksignup/NetworkingLinkSignupViewModel.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/networkinglinksignup/NetworkingLinkSignupViewModel.kt index fa62f1bce9c..151ad1a601e 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/networkinglinksignup/NetworkingLinkSignupViewModel.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/networkinglinksignup/NetworkingLinkSignupViewModel.kt @@ -1,12 +1,10 @@ package com.stripe.android.financialconnections.features.networkinglinksignup import android.webkit.URLUtil -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.viewModelScope +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.Click @@ -15,6 +13,10 @@ import com.stripe.android.financialconnections.analytics.FinancialConnectionsAna import com.stripe.android.financialconnections.analytics.FinancialConnectionsAnalyticsEvent.PaneLoaded 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.GetManifest import com.stripe.android.financialconnections.domain.LookupAccount @@ -27,9 +29,7 @@ import com.stripe.android.financialconnections.model.FinancialConnectionsSession import com.stripe.android.financialconnections.model.FinancialConnectionsSessionManifest.Pane import com.stripe.android.financialconnections.model.NetworkingLinkSignupPane import com.stripe.android.financialconnections.navigation.Destination.NetworkingSaveToLinkVerification -import com.stripe.android.financialconnections.navigation.Destination.Success import com.stripe.android.financialconnections.navigation.NavigationManager -import com.stripe.android.financialconnections.ui.FinancialConnectionsSheetNativeActivity import com.stripe.android.financialconnections.utils.ConflatedJob import com.stripe.android.financialconnections.utils.UriUtils import com.stripe.android.financialconnections.utils.isCancellationError @@ -46,6 +46,7 @@ import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch import java.util.Date import javax.inject.Inject +import com.stripe.android.financialconnections.navigation.Destination.Success as SuccessDestination internal class NetworkingLinkSignupViewModel @Inject constructor( initialState: NetworkingLinkSignupState, @@ -58,7 +59,7 @@ internal class NetworkingLinkSignupViewModel @Inject constructor( private val sync: SynchronizeFinancialConnectionsSession, private val navigationManager: NavigationManager, private val logger: Logger -) : MavericksViewModel(initialState) { +) : FinancialConnectionsViewModel(initialState) { private var searchJob = ConflatedJob() @@ -114,7 +115,7 @@ internal class NetworkingLinkSignupViewModel @Inject constructor( onAsync( NetworkingLinkSignupState::saveAccountToLink, onSuccess = { - navigationManager.tryNavigateTo(Success(referrer = PANE)) + navigationManager.tryNavigateTo(SuccessDestination(referrer = PANE)) }, onFail = { error -> eventTracker.logError( @@ -123,7 +124,7 @@ internal class NetworkingLinkSignupViewModel @Inject constructor( logger = logger, pane = PANE ) - navigationManager.tryNavigateTo(Success(referrer = PANE)) + navigationManager.tryNavigateTo(SuccessDestination(referrer = PANE)) }, ) } @@ -185,7 +186,7 @@ internal class NetworkingLinkSignupViewModel @Inject constructor( fun onSkipClick() = viewModelScope.launch { eventTracker.track(Click(eventName = "click.not_now", pane = PANE)) - navigationManager.tryNavigateTo(Success(referrer = PANE)) + navigationManager.tryNavigateTo(SuccessDestination(referrer = PANE)) } fun onSaveAccount() { @@ -204,7 +205,7 @@ internal class NetworkingLinkSignupViewModel @Inject constructor( private fun saveNewAccount() { suspend { eventTracker.track(Click(eventName = "click.save_to_link", pane = PANE)) - val state = awaitState() + val state = stateFlow.value val selectedAccounts = getCachedAccounts() val phoneController = state.payload()!!.phoneController require(state.valid) { "Form invalid! ${state.validEmail} ${state.validPhone}" } @@ -230,7 +231,7 @@ internal class NetworkingLinkSignupViewModel @Inject constructor( if (URLUtil.isNetworkUrl(uri)) { setState { copy(viewEffect = OpenUrl(uri, date.time)) } } else { - val managedUri = NetworkingLinkSignupClickableText.values() + val managedUri = NetworkingLinkSignupClickableText.entries .firstOrNull { uriUtils.compareSchemeAuthorityAndPath(it.value, uri) } when (managedUri) { NetworkingLinkSignupClickableText.LEGAL_DETAILS -> { @@ -256,21 +257,18 @@ internal class NetworkingLinkSignupViewModel @Inject constructor( setState { copy(viewEffect = null) } } - companion object : - MavericksViewModelFactory { + companion object { - override fun create( - viewModelContext: ViewModelContext, - state: NetworkingLinkSignupState - ): NetworkingLinkSignupViewModel { - return viewModelContext.activity() - .viewModel - .activityRetainedComponent - .networkingLinkSignupSubcomponent - .initialState(state) - .build() - .viewModel - } + fun factory(parentComponent: FinancialConnectionsSheetNativeComponent): ViewModelProvider.Factory = + viewModelFactory { + initializer { + parentComponent + .networkingLinkSignupSubcomponent + .initialState(NetworkingLinkSignupState()) + .build() + .viewModel + } + } private const val SEARCH_DEBOUNCE_MS = 1000L private const val SEARCH_DEBOUNCE_FINISHED_EMAIL_MS = 300L @@ -285,7 +283,7 @@ internal data class NetworkingLinkSignupState( val saveAccountToLink: Async = Uninitialized, val lookupAccount: Async = Uninitialized, val viewEffect: ViewEffect? = null -) : MavericksState { +) { val showFullForm: Boolean get() = lookupAccount()?.let { !it.exists } ?: false diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/networkinglinkverification/NetworkingLinkVerificationPreviewParameterProvider.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/networkinglinkverification/NetworkingLinkVerificationPreviewParameterProvider.kt index 31360bf707c..933048eef09 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/networkinglinkverification/NetworkingLinkVerificationPreviewParameterProvider.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/networkinglinkverification/NetworkingLinkVerificationPreviewParameterProvider.kt @@ -1,10 +1,10 @@ package com.stripe.android.financialconnections.features.networkinglinkverification import androidx.compose.ui.tooling.preview.PreviewParameterProvider -import com.airbnb.mvrx.Fail -import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.Success -import com.airbnb.mvrx.Uninitialized +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.domain.ConfirmVerification import com.stripe.android.uicore.elements.IdentifierSpec import com.stripe.android.uicore.elements.OTPController diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/networkinglinkverification/NetworkingLinkVerificationScreen.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/networkinglinkverification/NetworkingLinkVerificationScreen.kt index cc83a54f60f..f25965f07a1 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/networkinglinkverification/NetworkingLinkVerificationScreen.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/networkinglinkverification/NetworkingLinkVerificationScreen.kt @@ -11,6 +11,7 @@ import androidx.compose.foundation.layout.size import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -21,14 +22,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.domain.ConfirmVerification.OTPError import com.stripe.android.financialconnections.features.common.FullScreenGenericLoading import com.stripe.android.financialconnections.features.common.LoadingSpinner @@ -45,9 +45,9 @@ import com.stripe.android.financialconnections.ui.theme.LazyLayout @Composable internal fun NetworkingLinkVerificationScreen() { - val viewModel: NetworkingLinkVerificationViewModel = mavericksViewModel() + val viewModel: NetworkingLinkVerificationViewModel = paneViewModel(NetworkingLinkVerificationViewModel::factory) val parentViewModel = parentViewModel() - val state = viewModel.collectAsState() + val state = viewModel.stateFlow.collectAsState() NetworkingLinkVerificationContent( state = state.value, onCloseClick = { parentViewModel.onCloseWithConfirmationClick(Pane.NETWORKING_LINK_VERIFICATION) }, diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/networkinglinkverification/NetworkingLinkVerificationViewModel.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/networkinglinkverification/NetworkingLinkVerificationViewModel.kt index e1b96ee38fb..315c0cb5a94 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/networkinglinkverification/NetworkingLinkVerificationViewModel.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/networkinglinkverification/NetworkingLinkVerificationViewModel.kt @@ -1,14 +1,9 @@ package com.stripe.android.financialconnections.features.networkinglinkverification -import com.airbnb.mvrx.Async -import com.airbnb.mvrx.Fail -import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.MavericksState -import com.airbnb.mvrx.MavericksViewModel -import com.airbnb.mvrx.MavericksViewModelFactory -import com.airbnb.mvrx.Success -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.analytics.FinancialConnectionsAnalyticsEvent.VerificationError import com.stripe.android.financialconnections.analytics.FinancialConnectionsAnalyticsEvent.VerificationError.Error.ConsumerNotFoundError @@ -18,6 +13,13 @@ import com.stripe.android.financialconnections.analytics.FinancialConnectionsAna import com.stripe.android.financialconnections.analytics.FinancialConnectionsAnalyticsEvent.VerificationSuccess 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.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.FinancialConnectionsViewModel +import com.stripe.android.financialconnections.di.FinancialConnectionsSheetNativeComponent import com.stripe.android.financialconnections.domain.ConfirmVerification import com.stripe.android.financialconnections.domain.GetManifest import com.stripe.android.financialconnections.domain.LookupConsumerAndStartVerification @@ -30,7 +32,6 @@ import com.stripe.android.financialconnections.navigation.Destination import com.stripe.android.financialconnections.navigation.Destination.InstitutionPicker 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.model.ConsumerSession import com.stripe.android.model.VerificationType import com.stripe.android.uicore.elements.IdentifierSpec @@ -50,7 +51,7 @@ internal class NetworkingLinkVerificationViewModel @Inject constructor( private val analyticsTracker: FinancialConnectionsAnalyticsTracker, private val lookupConsumerAndStartVerification: LookupConsumerAndStartVerification, private val logger: Logger -) : MavericksViewModel(initialState) { +) : FinancialConnectionsViewModel(initialState) { init { observeAsyncs() @@ -121,7 +122,7 @@ internal class NetworkingLinkVerificationViewModel @Inject constructor( } private fun onOTPEntered(otp: String) = suspend { - val payload = requireNotNull(awaitState().payload()) + val payload = requireNotNull(stateFlow.value.payload()) confirmVerification.sms( consumerSessionClientSecret = payload.consumerSessionClientSecret, verificationCode = otp @@ -150,21 +151,18 @@ internal class NetworkingLinkVerificationViewModel @Inject constructor( ) }.execute { copy(confirmVerification = it) } - companion object : - MavericksViewModelFactory { + companion object { - override fun create( - viewModelContext: ViewModelContext, - state: NetworkingLinkVerificationState - ): NetworkingLinkVerificationViewModel { - return viewModelContext.activity() - .viewModel - .activityRetainedComponent - .networkingLinkVerificationSubcomponent - .initialState(state) - .build() - .viewModel - } + fun factory(parentComponent: FinancialConnectionsSheetNativeComponent): ViewModelProvider.Factory = + viewModelFactory { + initializer { + parentComponent + .networkingLinkVerificationSubcomponent + .initialState(NetworkingLinkVerificationState()) + .build() + .viewModel + } + } internal val PANE = Pane.NETWORKING_LINK_VERIFICATION } @@ -173,7 +171,7 @@ internal class NetworkingLinkVerificationViewModel @Inject constructor( internal data class NetworkingLinkVerificationState( val payload: Async = Uninitialized, val confirmVerification: Async = Uninitialized -) : MavericksState { +) { data class Payload( val email: String, diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/networkingsavetolinkverification/NetworkingSaveToLinkVerificationPreviewParameterProvider.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/networkingsavetolinkverification/NetworkingSaveToLinkVerificationPreviewParameterProvider.kt index e7e9e059b06..1f1512d6d53 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/networkingsavetolinkverification/NetworkingSaveToLinkVerificationPreviewParameterProvider.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/networkingsavetolinkverification/NetworkingSaveToLinkVerificationPreviewParameterProvider.kt @@ -1,10 +1,10 @@ package com.stripe.android.financialconnections.features.networkingsavetolinkverification import androidx.compose.ui.tooling.preview.PreviewParameterProvider -import com.airbnb.mvrx.Fail -import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.Success -import com.airbnb.mvrx.Uninitialized +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.domain.ConfirmVerification import com.stripe.android.uicore.elements.IdentifierSpec import com.stripe.android.uicore.elements.OTPController diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/networkingsavetolinkverification/NetworkingSaveToLinkVerificationScreen.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/networkingsavetolinkverification/NetworkingSaveToLinkVerificationScreen.kt index 756fa62a4e5..ed0820704f7 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/networkingsavetolinkverification/NetworkingSaveToLinkVerificationScreen.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/networkingsavetolinkverification/NetworkingSaveToLinkVerificationScreen.kt @@ -13,6 +13,7 @@ import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -23,14 +24,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.domain.ConfirmVerification import com.stripe.android.financialconnections.features.common.FullScreenGenericLoading import com.stripe.android.financialconnections.features.common.LoadingSpinner @@ -49,9 +49,11 @@ import com.stripe.android.financialconnections.ui.theme.LazyLayout @Composable internal fun NetworkingSaveToLinkVerificationScreen() { - val viewModel: NetworkingSaveToLinkVerificationViewModel = mavericksViewModel() + val viewModel: NetworkingSaveToLinkVerificationViewModel = paneViewModel { + NetworkingSaveToLinkVerificationViewModel.factory(it) + } val parentViewModel = parentViewModel() - val state = viewModel.collectAsState() + val state = viewModel.stateFlow.collectAsState() NetworkingSaveToLinkVerificationContent( state = state.value, onCloseClick = { parentViewModel.onCloseWithConfirmationClick(PANE) }, diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/networkingsavetolinkverification/NetworkingSaveToLinkVerificationViewModel.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/networkingsavetolinkverification/NetworkingSaveToLinkVerificationViewModel.kt index 930e2e807ff..c6cf2fab426 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/networkingsavetolinkverification/NetworkingSaveToLinkVerificationViewModel.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/networkingsavetolinkverification/NetworkingSaveToLinkVerificationViewModel.kt @@ -1,11 +1,9 @@ package com.stripe.android.financialconnections.features.networkingsavetolinkverification -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.viewModelScope +import androidx.lifecycle.viewmodel.initializer +import androidx.lifecycle.viewmodel.viewModelFactory import com.stripe.android.core.Logger import com.stripe.android.financialconnections.analytics.FinancialConnectionsAnalyticsEvent.PaneLoaded import com.stripe.android.financialconnections.analytics.FinancialConnectionsAnalyticsEvent.VerificationError @@ -14,6 +12,10 @@ import com.stripe.android.financialconnections.analytics.FinancialConnectionsAna import com.stripe.android.financialconnections.analytics.FinancialConnectionsAnalyticsEvent.VerificationSuccess 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.ConfirmVerification import com.stripe.android.financialconnections.domain.ConfirmVerification.OTPError import com.stripe.android.financialconnections.domain.GetCachedAccounts @@ -23,9 +25,7 @@ import com.stripe.android.financialconnections.domain.MarkLinkVerified import com.stripe.android.financialconnections.domain.SaveAccountToLink import com.stripe.android.financialconnections.domain.StartVerification import com.stripe.android.financialconnections.model.FinancialConnectionsSessionManifest.Pane -import com.stripe.android.financialconnections.navigation.Destination.Success import com.stripe.android.financialconnections.navigation.NavigationManager -import com.stripe.android.financialconnections.ui.FinancialConnectionsSheetNativeActivity import com.stripe.android.uicore.elements.IdentifierSpec import com.stripe.android.uicore.elements.OTPController import com.stripe.android.uicore.elements.OTPElement @@ -33,6 +33,7 @@ import getRedactedPhoneNumber import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.launch import javax.inject.Inject +import com.stripe.android.financialconnections.navigation.Destination.Success as SuccessDestination internal class NetworkingSaveToLinkVerificationViewModel @Inject constructor( initialState: NetworkingSaveToLinkVerificationState, @@ -46,7 +47,7 @@ internal class NetworkingSaveToLinkVerificationViewModel @Inject constructor( private val saveAccountToLink: SaveAccountToLink, private val navigationManager: NavigationManager, private val logger: Logger -) : MavericksViewModel(initialState) { +) : FinancialConnectionsViewModel(initialState) { init { logErrors() @@ -93,7 +94,7 @@ internal class NetworkingSaveToLinkVerificationViewModel @Inject constructor( onAsync( NetworkingSaveToLinkVerificationState::confirmVerification, onSuccess = { - navigationManager.tryNavigateTo(Success(referrer = PANE)) + navigationManager.tryNavigateTo(SuccessDestination(referrer = PANE)) }, onFail = { error -> eventTracker.logError( @@ -103,14 +104,14 @@ internal class NetworkingSaveToLinkVerificationViewModel @Inject constructor( pane = PANE ) if (error !is OTPError) { - navigationManager.tryNavigateTo(Success(referrer = PANE)) + navigationManager.tryNavigateTo(SuccessDestination(referrer = PANE)) } }, ) } private fun onOTPEntered(otp: String) = suspend { - val payload = requireNotNull(awaitState().payload()) + val payload = requireNotNull(stateFlow.value.payload()) runCatching { confirmVerification.sms( @@ -133,33 +134,30 @@ internal class NetworkingSaveToLinkVerificationViewModel @Inject constructor( }.execute { copy(confirmVerification = it) } fun onSkipClick() { - navigationManager.tryNavigateTo(Success(referrer = PANE)) + navigationManager.tryNavigateTo(SuccessDestination(referrer = PANE)) } - companion object : - MavericksViewModelFactory { + companion object { internal val PANE = Pane.NETWORKING_SAVE_TO_LINK_VERIFICATION - override fun create( - viewModelContext: ViewModelContext, - state: NetworkingSaveToLinkVerificationState - ): NetworkingSaveToLinkVerificationViewModel { - return viewModelContext.activity() - .viewModel - .activityRetainedComponent - .networkingSaveToLinkVerificationSubcomponent - .initialState(state) - .build() - .viewModel - } + fun factory(parentComponent: FinancialConnectionsSheetNativeComponent): ViewModelProvider.Factory = + viewModelFactory { + initializer { + parentComponent + .networkingSaveToLinkVerificationSubcomponent + .initialState(NetworkingSaveToLinkVerificationState()) + .build() + .viewModel + } + } } } internal data class NetworkingSaveToLinkVerificationState( val payload: Async = Uninitialized, val confirmVerification: Async = Uninitialized -) : MavericksState { +) { data class Payload( val showNotNowButton: Boolean, diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/reset/ResetScreen.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/reset/ResetScreen.kt index aa47165a687..f3ab3a47c96 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/reset/ResetScreen.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/reset/ResetScreen.kt @@ -2,14 +2,15 @@ package com.stripe.android.financialconnections.features.reset import androidx.activity.compose.BackHandler import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue 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.features.common.FullScreenGenericLoading import com.stripe.android.financialconnections.features.common.UnclassifiedErrorContent import com.stripe.android.financialconnections.model.FinancialConnectionsSessionManifest.Pane @@ -20,12 +21,14 @@ import com.stripe.android.financialconnections.ui.components.FinancialConnection @Composable internal fun ResetScreen() { - val viewModel: ResetViewModel = mavericksViewModel() + val viewModel: ResetViewModel = paneViewModel { + ResetViewModel.factory(it) + } val parentViewModel = parentViewModel() - val payload = viewModel.collectAsState { it.payload } + val state by viewModel.stateFlow.collectAsState() BackHandler(enabled = true) {} ResetContent( - payload = payload.value, + payload = state.payload, onCloseClick = { parentViewModel.onCloseWithConfirmationClick(Pane.RESET) }, onCloseFromErrorClick = parentViewModel::onCloseFromErrorClick ) diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/reset/ResetViewModel.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/reset/ResetViewModel.kt index 6fda1929291..1a4bf7bdbb8 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/reset/ResetViewModel.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/reset/ResetViewModel.kt @@ -1,15 +1,16 @@ package com.stripe.android.financialconnections.features.reset -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.analytics.FinancialConnectionsAnalyticsEvent.PaneLoaded 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.LinkMoreAccounts import com.stripe.android.financialconnections.domain.NativeAuthFlowCoordinator import com.stripe.android.financialconnections.domain.NativeAuthFlowCoordinator.Message.ClearPartnerWebAuth @@ -17,7 +18,6 @@ import com.stripe.android.financialconnections.model.FinancialConnectionsSession import com.stripe.android.financialconnections.navigation.NavigationManager import com.stripe.android.financialconnections.navigation.PopUpToBehavior import com.stripe.android.financialconnections.navigation.destination -import com.stripe.android.financialconnections.ui.FinancialConnectionsSheetNativeActivity import javax.inject.Inject internal class ResetViewModel @Inject constructor( @@ -27,7 +27,7 @@ internal class ResetViewModel @Inject constructor( private val eventTracker: FinancialConnectionsAnalyticsTracker, private val navigationManager: NavigationManager, private val logger: Logger -) : MavericksViewModel(initialState) { +) : FinancialConnectionsViewModel(initialState) { init { logErrors() @@ -56,20 +56,18 @@ internal class ResetViewModel @Inject constructor( ) } - companion object : MavericksViewModelFactory { + companion object { - override fun create( - viewModelContext: ViewModelContext, - state: ResetState - ): ResetViewModel { - return viewModelContext.activity() - .viewModel - .activityRetainedComponent - .resetSubcomponent - .initialState(state) - .build() - .viewModel - } + fun factory(parentComponent: FinancialConnectionsSheetNativeComponent): ViewModelProvider.Factory = + viewModelFactory { + initializer { + parentComponent + .resetSubcomponent + .initialState(ResetState()) + .build() + .viewModel + } + } internal val PANE = Pane.RESET } @@ -77,4 +75,4 @@ internal class ResetViewModel @Inject constructor( internal data class ResetState( val payload: Async = Uninitialized -) : MavericksState +) diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/repository/CoreAuthorizationPendingNetworkingRepairRepository.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/repository/CoreAuthorizationPendingNetworkingRepairRepository.kt index 0cb2693fdf4..c406c40e527 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/repository/CoreAuthorizationPendingNetworkingRepairRepository.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/repository/CoreAuthorizationPendingNetworkingRepairRepository.kt @@ -1,49 +1,24 @@ package com.stripe.android.financialconnections.repository -import com.airbnb.mvrx.MavericksRepository import com.airbnb.mvrx.MavericksState -import com.stripe.android.core.BuildConfig import com.stripe.android.core.Logger -import com.stripe.android.financialconnections.analytics.FinancialConnectionsAnalyticsTracker -import com.stripe.android.financialconnections.analytics.logError -import com.stripe.android.financialconnections.model.FinancialConnectionsSessionManifest.Pane -import com.stripe.android.financialconnections.repository.CoreAuthorizationPendingNetworkingRepairRepository.State -import kotlinx.coroutines.CoroutineScope /** * Repository for storing the core authorization pending repair. * */ internal class CoreAuthorizationPendingNetworkingRepairRepository( - coroutineScope: CoroutineScope, - private val logger: Logger, - private val analyticsTracker: FinancialConnectionsAnalyticsTracker -) : MavericksRepository( - initialState = State(), - coroutineScope = coroutineScope, - performCorrectnessValidations = BuildConfig.DEBUG, + private val logger: Logger ) { - suspend fun get() = runCatching { - awaitState().coreAuthorization - }.onFailure { - analyticsTracker.logError( - "Failed to get core authorization", - logger = logger, - pane = Pane.UNEXPECTED_ERROR, - error = it - ) - }.getOrNull() + private var state: State = State() + + fun get() = state.coreAuthorization - fun set(coreAuthorization: String) = runCatching { + fun set(coreAuthorization: String) { logger.debug("core authorization set to $coreAuthorization") - setState { copy(coreAuthorization = coreAuthorization) } - }.onFailure { - analyticsTracker.logError( - "Failed to set core authorization", - logger = logger, - pane = Pane.UNEXPECTED_ERROR, - error = it + state = state.copy( + coreAuthorization = coreAuthorization ) } diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/utils/MavericksExtensions.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/utils/MavericksExtensions.kt index ed0c55c723c..ebf20bbf907 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/utils/MavericksExtensions.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/utils/MavericksExtensions.kt @@ -1,45 +1,14 @@ package com.stripe.android.financialconnections.utils import androidx.activity.ComponentActivity -import com.airbnb.mvrx.ActivityViewModelContext import com.airbnb.mvrx.Fail -import com.airbnb.mvrx.InternalMavericksApi import com.airbnb.mvrx.Loading import com.airbnb.mvrx.Mavericks -import com.airbnb.mvrx.MavericksState -import com.airbnb.mvrx.MavericksViewModel -import com.airbnb.mvrx.MavericksViewModelFactory -import com.airbnb.mvrx.MavericksViewModelProvider import com.stripe.android.core.exception.StripeException import com.stripe.android.financialconnections.core.Async import kotlinx.coroutines.CancellationException import kotlin.properties.ReadOnlyProperty -import kotlin.reflect.KClass import kotlin.reflect.KProperty -import com.airbnb.mvrx.Async as MvrxAsync - -/** - * Replicates [com.airbnb.mvrx.viewModel] delegate, but without using [com.airbnb.mvrx.lifecycleAwareLazy] - * to eagerly initialize the ViewModel in [ComponentActivity.onCreate]. - * - * Some [MavericksViewModelFactory] implementations assume args are correct to instantiate - * the viewModel, and the associated Dagger graph. - * - * This allows onCreate to check args and verify they're valid before accessing (and instantiating) - * the viewModel. - */ -@OptIn(InternalMavericksApi::class) -internal inline fun , reified S : MavericksState> T.viewModelLazy( - viewModelClass: KClass = VM::class, - crossinline keyFactory: () -> String = { viewModelClass.java.name } -): Lazy where T : ComponentActivity = lazy { - MavericksViewModelProvider.get( - viewModelClass = viewModelClass.java, - stateClass = S::class.java, - viewModelContext = ActivityViewModelContext(this, intent.extras?.get(Mavericks.KEY_ARG)), - key = keyFactory() - ) -} /** * Replicates [com.airbnb.mvrx.argsOrNull] for [ComponentActivity]. @@ -64,13 +33,6 @@ internal fun argsOrNull() = object : ReadOnlyProperty * Prevents [CancellationException] to map to [Fail] when coroutine being cancelled * due to search query changes. In these cases, re-map the [Async] instance to [Loading] */ -internal fun MvrxAsync<*>.isCancellationError(): Boolean = when { - this !is Fail -> false - error is CancellationException -> true - error is StripeException && error.cause is CancellationException -> true - else -> false -} - internal fun Async<*>.isCancellationError(): Boolean = when { this !is Async.Fail -> false error is CancellationException -> true diff --git a/financial-connections/src/test/java/com/stripe/android/financialconnections/CoroutineTestRule.kt b/financial-connections/src/test/java/com/stripe/android/financialconnections/CoroutineTestRule.kt index fdf557caa3f..4b8e785143b 100644 --- a/financial-connections/src/test/java/com/stripe/android/financialconnections/CoroutineTestRule.kt +++ b/financial-connections/src/test/java/com/stripe/android/financialconnections/CoroutineTestRule.kt @@ -3,6 +3,7 @@ package com.stripe.android.financialconnections import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.TestDispatcher +import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.resetMain import kotlinx.coroutines.test.setMain import org.junit.rules.TestWatcher @@ -10,7 +11,7 @@ import org.junit.runner.Description @ExperimentalCoroutinesApi class CoroutineTestRule( - private val testDispatcher: TestDispatcher, + private val testDispatcher: TestDispatcher = UnconfinedTestDispatcher(), ) : TestWatcher() { override fun starting(description: Description) { diff --git a/financial-connections/src/test/java/com/stripe/android/financialconnections/features/accountpicker/AccountPickerViewModelTest.kt b/financial-connections/src/test/java/com/stripe/android/financialconnections/features/accountpicker/AccountPickerViewModelTest.kt index ece09b1851f..49e8ece65e9 100644 --- a/financial-connections/src/test/java/com/stripe/android/financialconnections/features/accountpicker/AccountPickerViewModelTest.kt +++ b/financial-connections/src/test/java/com/stripe/android/financialconnections/features/accountpicker/AccountPickerViewModelTest.kt @@ -1,6 +1,5 @@ package com.stripe.android.financialconnections.features.accountpicker -import com.airbnb.mvrx.test.MavericksTestRule import com.google.common.truth.Truth.assertThat import com.stripe.android.core.Logger import com.stripe.android.financialconnections.ApiKeyFixtures.authorizationSession @@ -8,6 +7,7 @@ import com.stripe.android.financialconnections.ApiKeyFixtures.partnerAccount import com.stripe.android.financialconnections.ApiKeyFixtures.partnerAccountList import com.stripe.android.financialconnections.ApiKeyFixtures.sessionManifest import com.stripe.android.financialconnections.ApiKeyFixtures.syncResponse +import com.stripe.android.financialconnections.CoroutineTestRule import com.stripe.android.financialconnections.TestFinancialConnectionsAnalyticsTracker import com.stripe.android.financialconnections.core.withState import com.stripe.android.financialconnections.domain.GetOrFetchSync @@ -29,7 +29,7 @@ import kotlin.test.assertEquals internal class AccountPickerViewModelTest { @get:Rule - val mavericksTestRule = MavericksTestRule() + val testRule = CoroutineTestRule() private val pollAuthorizationSessionAccounts = mock() private val getSync = mock() diff --git a/financial-connections/src/test/java/com/stripe/android/financialconnections/features/linkaccountpicker/LinkAccountPickerViewModelTest.kt b/financial-connections/src/test/java/com/stripe/android/financialconnections/features/linkaccountpicker/LinkAccountPickerViewModelTest.kt index cb28ed3c8a1..a54c1047b9a 100644 --- a/financial-connections/src/test/java/com/stripe/android/financialconnections/features/linkaccountpicker/LinkAccountPickerViewModelTest.kt +++ b/financial-connections/src/test/java/com/stripe/android/financialconnections/features/linkaccountpicker/LinkAccountPickerViewModelTest.kt @@ -1,12 +1,12 @@ package com.stripe.android.financialconnections.features.linkaccountpicker -import com.airbnb.mvrx.test.MavericksTestRule import com.google.common.truth.Truth.assertThat import com.stripe.android.core.Logger import com.stripe.android.financialconnections.ApiKeyFixtures.consumerSession import com.stripe.android.financialconnections.ApiKeyFixtures.institution import com.stripe.android.financialconnections.ApiKeyFixtures.partnerAccount import com.stripe.android.financialconnections.ApiKeyFixtures.syncResponse +import com.stripe.android.financialconnections.CoroutineTestRule import com.stripe.android.financialconnections.TestFinancialConnectionsAnalyticsTracker import com.stripe.android.financialconnections.domain.FetchNetworkedAccounts import com.stripe.android.financialconnections.domain.GetCachedConsumerSession @@ -42,7 +42,7 @@ import org.mockito.kotlin.whenever class LinkAccountPickerViewModelTest { @get:Rule - val mavericksTestRule = MavericksTestRule() + val testRule = CoroutineTestRule() private val getSync = mock() private val navigationManager = TestNavigationManager() @@ -93,7 +93,7 @@ class LinkAccountPickerViewModelTest { val viewModel = buildViewModel(LinkAccountPickerState()) - assertThat(viewModel.awaitState().payload()!!.accounts) + assertThat(viewModel.stateFlow.value.payload()!!.accounts) .isEqualTo( listOf( partnerAccount().copy(id = "id1", _allowSelection = null) to diff --git a/financial-connections/src/test/java/com/stripe/android/financialconnections/features/linkstepupverification/LinkStepUpVerificationViewModelTest.kt b/financial-connections/src/test/java/com/stripe/android/financialconnections/features/linkstepupverification/LinkStepUpVerificationViewModelTest.kt index e80a1039808..607c171af72 100644 --- a/financial-connections/src/test/java/com/stripe/android/financialconnections/features/linkstepupverification/LinkStepUpVerificationViewModelTest.kt +++ b/financial-connections/src/test/java/com/stripe/android/financialconnections/features/linkstepupverification/LinkStepUpVerificationViewModelTest.kt @@ -1,13 +1,14 @@ package com.stripe.android.financialconnections.features.linkstepupverification -import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.test.MavericksTestRule +import app.cash.turbine.test import com.google.common.truth.Truth.assertThat import com.stripe.android.core.Logger import com.stripe.android.financialconnections.ApiKeyFixtures import com.stripe.android.financialconnections.ApiKeyFixtures.partnerAccount import com.stripe.android.financialconnections.ApiKeyFixtures.sessionManifest +import com.stripe.android.financialconnections.CoroutineTestRule import com.stripe.android.financialconnections.TestFinancialConnectionsAnalyticsTracker +import com.stripe.android.financialconnections.core.Async.Loading import com.stripe.android.financialconnections.domain.ConfirmVerification import com.stripe.android.financialconnections.domain.GetCachedAccounts import com.stripe.android.financialconnections.domain.GetManifest @@ -37,7 +38,7 @@ import org.mockito.kotlin.whenever @ExperimentalCoroutinesApi class LinkStepUpVerificationViewModelTest { @get:Rule - val mavericksTestRule = MavericksTestRule() + val testRule = CoroutineTestRule() private val getManifest = mock() private val navigationManager = TestNavigationManager() @@ -92,7 +93,7 @@ class LinkStepUpVerificationViewModelTest { onStartVerificationCaptor.firstValue() onVerificationStartedCaptor.firstValue(consumerSession) - val state = viewModel.awaitState() + val state = viewModel.stateFlow.value assertThat(state.payload()!!.consumerSessionClientSecret) .isEqualTo(consumerSession.clientSecret) @@ -103,39 +104,41 @@ class LinkStepUpVerificationViewModelTest { val email = "test@test.com" val onConsumerNotFoundCaptor = argumentCaptor Unit>() - whenever(getManifest()).thenReturn( - sessionManifest().copy(accountholderCustomerEmailAddress = email) - ) + whenever(getManifest()) + .thenReturn(sessionManifest().copy(accountholderCustomerEmailAddress = email)) - val viewModel = buildViewModel() + buildViewModel().stateFlow.test { + assertThat(awaitItem().payload).isInstanceOf(Loading::class.java) - assertThat(viewModel.awaitState().payload).isInstanceOf(Loading::class.java) + verify(lookupConsumerAndStartVerification).invoke( + email = eq(email), + businessName = anyOrNull(), + verificationType = eq(VerificationType.EMAIL), + onConsumerNotFound = onConsumerNotFoundCaptor.capture(), + onLookupError = any(), + onStartVerification = any(), + onVerificationStarted = any(), + onStartVerificationError = any() + ) - verify(lookupConsumerAndStartVerification).invoke( - email = eq(email), - businessName = anyOrNull(), - verificationType = eq(VerificationType.EMAIL), - onConsumerNotFound = onConsumerNotFoundCaptor.capture(), - onLookupError = any(), - onStartVerification = any(), - onVerificationStarted = any(), - onStartVerificationError = any() - ) + onConsumerNotFoundCaptor.firstValue() - onConsumerNotFoundCaptor.firstValue() + // we don't expect any state updates if the consumer is not found + expectNoEvents() - assertThat(viewModel.awaitState().payload).isInstanceOf(Loading::class.java) - navigationManager.assertNavigatedTo( - destination = Destination.InstitutionPicker, - pane = Pane.LINK_STEP_UP_VERIFICATION - ) - eventTracker.assertContainsEvent( - "linked_accounts.networking.verification.step_up.error", - mapOf( - "pane" to "networking_link_step_up_verification", - "error" to "ConsumerNotFoundError" + navigationManager.assertNavigatedTo( + destination = Destination.InstitutionPicker, + pane = Pane.LINK_STEP_UP_VERIFICATION ) - ) + + eventTracker.assertContainsEvent( + "linked_accounts.networking.verification.step_up.error", + mapOf( + "pane" to "networking_link_step_up_verification", + "error" to "ConsumerNotFoundError" + ) + ) + } } @Test @@ -173,7 +176,7 @@ class LinkStepUpVerificationViewModelTest { onStartVerificationCaptor.firstValue() onVerificationStartedCaptor.firstValue(consumerSession) - val otpController = viewModel.awaitState().payload()!!.otpElement.controller + val otpController = viewModel.stateFlow.value.payload()!!.otpElement.controller // enters valid OTP for (i in 0 until otpController.otpLength) { diff --git a/financial-connections/src/test/java/com/stripe/android/financialconnections/features/manualentry/ManualEntryViewModelTest.kt b/financial-connections/src/test/java/com/stripe/android/financialconnections/features/manualentry/ManualEntryViewModelTest.kt index ae58c50283f..af3d08488ec 100644 --- a/financial-connections/src/test/java/com/stripe/android/financialconnections/features/manualentry/ManualEntryViewModelTest.kt +++ b/financial-connections/src/test/java/com/stripe/android/financialconnections/features/manualentry/ManualEntryViewModelTest.kt @@ -1,14 +1,14 @@ package com.stripe.android.financialconnections.features.manualentry import app.cash.turbine.test -import com.airbnb.mvrx.Success -import com.airbnb.mvrx.test.MavericksTestRule -import com.airbnb.mvrx.withState import com.google.common.truth.Truth.assertThat import com.stripe.android.core.Logger import com.stripe.android.financialconnections.ApiKeyFixtures.sessionManifest import com.stripe.android.financialconnections.ApiKeyFixtures.syncResponse +import com.stripe.android.financialconnections.CoroutineTestRule import com.stripe.android.financialconnections.TestFinancialConnectionsAnalyticsTracker +import com.stripe.android.financialconnections.core.Async.Success +import com.stripe.android.financialconnections.core.withState import com.stripe.android.financialconnections.domain.GetOrFetchSync import com.stripe.android.financialconnections.domain.NativeAuthFlowCoordinator import com.stripe.android.financialconnections.domain.NativeAuthFlowCoordinator.Message.Complete @@ -18,6 +18,7 @@ import com.stripe.android.financialconnections.features.manualentry.ManualEntryS import com.stripe.android.financialconnections.mock.TestSuccessContentRepository import com.stripe.android.financialconnections.model.ManualEntryMode import com.stripe.android.financialconnections.utils.TestNavigationManager +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.test.runTest import org.junit.Rule @@ -26,9 +27,10 @@ import org.mockito.kotlin.mock import org.mockito.kotlin.whenever import kotlin.test.assertEquals +@ExperimentalCoroutinesApi class ManualEntryViewModelTest { @get:Rule - val mavericksTestRule = MavericksTestRule() + val testRule = CoroutineTestRule() private val getSync = mock() private val navigationManager = TestNavigationManager() diff --git a/financial-connections/src/test/java/com/stripe/android/financialconnections/features/networkinglinkloginwarmup/NetworkingLinkLoginWarmupViewModelTest.kt b/financial-connections/src/test/java/com/stripe/android/financialconnections/features/networkinglinkloginwarmup/NetworkingLinkLoginWarmupViewModelTest.kt index cfa88956807..df07bf53c38 100644 --- a/financial-connections/src/test/java/com/stripe/android/financialconnections/features/networkinglinkloginwarmup/NetworkingLinkLoginWarmupViewModelTest.kt +++ b/financial-connections/src/test/java/com/stripe/android/financialconnections/features/networkinglinkloginwarmup/NetworkingLinkLoginWarmupViewModelTest.kt @@ -1,7 +1,7 @@ package com.stripe.android.financialconnections.features.networkinglinkloginwarmup -import com.airbnb.mvrx.test.MavericksTestRule import com.stripe.android.financialconnections.ApiKeyFixtures +import com.stripe.android.financialconnections.CoroutineTestRule import com.stripe.android.financialconnections.TestFinancialConnectionsAnalyticsTracker import com.stripe.android.financialconnections.domain.DisableNetworking import com.stripe.android.financialconnections.domain.GetManifest @@ -11,6 +11,7 @@ import com.stripe.android.financialconnections.navigation.PopUpToBehavior import com.stripe.android.financialconnections.navigation.destination import com.stripe.android.financialconnections.utils.TestHandleError import com.stripe.android.financialconnections.utils.TestNavigationManager +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runTest import org.junit.Rule import org.junit.Test @@ -18,10 +19,11 @@ import org.mockito.kotlin.mock import org.mockito.kotlin.verify import org.mockito.kotlin.whenever +@ExperimentalCoroutinesApi class NetworkingLinkLoginWarmupViewModelTest { @get:Rule - val mavericksTestRule = MavericksTestRule() + val testRule = CoroutineTestRule() private val getManifest = mock() private val navigationManager = TestNavigationManager() diff --git a/financial-connections/src/test/java/com/stripe/android/financialconnections/features/networkinglinksignup/NetworkingLinkSignupViewModelTest.kt b/financial-connections/src/test/java/com/stripe/android/financialconnections/features/networkinglinksignup/NetworkingLinkSignupViewModelTest.kt index 26874861129..7137d1c547b 100644 --- a/financial-connections/src/test/java/com/stripe/android/financialconnections/features/networkinglinksignup/NetworkingLinkSignupViewModelTest.kt +++ b/financial-connections/src/test/java/com/stripe/android/financialconnections/features/networkinglinksignup/NetworkingLinkSignupViewModelTest.kt @@ -1,11 +1,11 @@ package com.stripe.android.financialconnections.features.networkinglinksignup import app.cash.turbine.test -import com.airbnb.mvrx.test.MavericksTestRule import com.google.common.truth.Truth.assertThat import com.stripe.android.core.Logger import com.stripe.android.financialconnections.ApiKeyFixtures import com.stripe.android.financialconnections.ApiKeyFixtures.syncResponse +import com.stripe.android.financialconnections.CoroutineTestRule import com.stripe.android.financialconnections.TestFinancialConnectionsAnalyticsTracker import com.stripe.android.financialconnections.domain.GetCachedAccounts import com.stripe.android.financialconnections.domain.GetManifest @@ -23,7 +23,6 @@ import com.stripe.android.financialconnections.utils.UriUtils import com.stripe.android.model.ConsumerSessionLookup import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.first -import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.runTest import org.junit.Rule import org.junit.Test @@ -36,10 +35,8 @@ import org.mockito.kotlin.whenever @OptIn(ExperimentalCoroutinesApi::class) class NetworkingLinkSignupViewModelTest { - private val testDispatcher = UnconfinedTestDispatcher() - @get:Rule - val mavericksTestRule = MavericksTestRule(testDispatcher = testDispatcher) + val testRule = CoroutineTestRule() private val getManifest = mock() private val eventTracker = TestFinancialConnectionsAnalyticsTracker() @@ -83,7 +80,7 @@ class NetworkingLinkSignupViewModelTest { whenever(lookupAccount(any())).thenReturn(ConsumerSessionLookup(exists = false)) val viewModel = buildViewModel(NetworkingLinkSignupState()) - val state = viewModel.awaitState() + val state = viewModel.stateFlow.value val payload = requireNotNull(state.payload()) assertThat(payload.emailController.fieldValue.first()).isEqualTo("test@test.com") } @@ -106,7 +103,7 @@ class NetworkingLinkSignupViewModelTest { val viewModel = buildViewModel(NetworkingLinkSignupState()) navigationManager.navigationFlow.test { - val state = viewModel.awaitState() + val state = viewModel.stateFlow.value val payload = requireNotNull(state.payload()) payload.emailController.onValueChange("email@email.com") @@ -138,7 +135,7 @@ class NetworkingLinkSignupViewModelTest { val viewModel = buildViewModel(NetworkingLinkSignupState()) navigationManager.navigationFlow.test { - val state = viewModel.awaitState() + val state = viewModel.stateFlow.value val payload = requireNotNull(state.payload()) payload.emailController.onValueChange("email@email.com") diff --git a/financial-connections/src/test/java/com/stripe/android/financialconnections/features/networkinglinkverification/NetworkingLinkVerificationViewModelTest.kt b/financial-connections/src/test/java/com/stripe/android/financialconnections/features/networkinglinkverification/NetworkingLinkVerificationViewModelTest.kt index 7a5d35a0088..e25635dd70f 100644 --- a/financial-connections/src/test/java/com/stripe/android/financialconnections/features/networkinglinkverification/NetworkingLinkVerificationViewModelTest.kt +++ b/financial-connections/src/test/java/com/stripe/android/financialconnections/features/networkinglinkverification/NetworkingLinkVerificationViewModelTest.kt @@ -1,13 +1,13 @@ package com.stripe.android.financialconnections.features.networkinglinkverification -import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.test.MavericksTestRule import com.google.common.truth.Truth.assertThat import com.stripe.android.core.Logger import com.stripe.android.core.exception.LocalStripeException import com.stripe.android.financialconnections.ApiKeyFixtures.consumerSession import com.stripe.android.financialconnections.ApiKeyFixtures.sessionManifest +import com.stripe.android.financialconnections.CoroutineTestRule import com.stripe.android.financialconnections.TestFinancialConnectionsAnalyticsTracker +import com.stripe.android.financialconnections.core.Async.Loading import com.stripe.android.financialconnections.domain.ConfirmVerification import com.stripe.android.financialconnections.domain.GetManifest import com.stripe.android.financialconnections.domain.LookupConsumerAndStartVerification @@ -34,7 +34,7 @@ import org.mockito.kotlin.whenever class NetworkingLinkVerificationViewModelTest { @get:Rule - val mavericksTestRule = MavericksTestRule() + val testRule = CoroutineTestRule() private val getManifest = mock() private val navigationManager = TestNavigationManager() @@ -69,7 +69,7 @@ class NetworkingLinkVerificationViewModelTest { val viewModel = buildViewModel() - assertThat(viewModel.awaitState().payload).isInstanceOf(Loading::class.java) + assertThat(viewModel.stateFlow.value.payload).isInstanceOf(Loading::class.java) verify(lookupConsumerAndStartVerification).invoke( email = eq(email), @@ -85,7 +85,7 @@ class NetworkingLinkVerificationViewModelTest { onStartVerificationCaptor.firstValue() onVerificationStartedCaptor.firstValue(consumerSession) - val state = viewModel.awaitState() + val state = viewModel.stateFlow.value assertThat(state.payload()!!.consumerSessionClientSecret) .isEqualTo(consumerSession.clientSecret) } @@ -101,7 +101,7 @@ class NetworkingLinkVerificationViewModelTest { val viewModel = buildViewModel() - assertThat(viewModel.awaitState().payload).isInstanceOf(Loading::class.java) + assertThat(viewModel.stateFlow.value.payload).isInstanceOf(Loading::class.java) verify(lookupConsumerAndStartVerification).invoke( email = eq(email), @@ -116,7 +116,7 @@ class NetworkingLinkVerificationViewModelTest { onConsumerNotFoundCaptor.firstValue() - assertThat(viewModel.awaitState().payload).isInstanceOf(Loading::class.java) + assertThat(viewModel.stateFlow.value.payload).isInstanceOf(Loading::class.java) navigationManager.assertNavigatedTo( destination = Destination.InstitutionPicker, pane = NETWORKING_LINK_VERIFICATION @@ -162,7 +162,7 @@ class NetworkingLinkVerificationViewModelTest { onStartVerificationCaptor.firstValue() onVerificationStartedCaptor.firstValue(consumerSession) - val otpController = viewModel.awaitState().payload()!!.otpElement.controller + val otpController = viewModel.stateFlow.value.payload()!!.otpElement.controller // enters valid OTP for (i in 0 until otpController.otpLength) { @@ -214,7 +214,7 @@ class NetworkingLinkVerificationViewModelTest { onStartVerificationCaptor.firstValue() onVerificationStartedCaptor.firstValue(consumerSession) - val otpController = viewModel.awaitState().payload()!!.otpElement.controller + val otpController = viewModel.stateFlow.value.payload()!!.otpElement.controller // enters valid OTP for (i in 0 until otpController.otpLength) { diff --git a/financial-connections/src/test/java/com/stripe/android/financialconnections/features/networkingsavetolinkverification/NetworkingSaveToLinkVerificationViewModelTest.kt b/financial-connections/src/test/java/com/stripe/android/financialconnections/features/networkingsavetolinkverification/NetworkingSaveToLinkVerificationViewModelTest.kt index bedcfda26db..15854211ce9 100644 --- a/financial-connections/src/test/java/com/stripe/android/financialconnections/features/networkingsavetolinkverification/NetworkingSaveToLinkVerificationViewModelTest.kt +++ b/financial-connections/src/test/java/com/stripe/android/financialconnections/features/networkingsavetolinkverification/NetworkingSaveToLinkVerificationViewModelTest.kt @@ -1,11 +1,11 @@ package com.stripe.android.financialconnections.features.networkingsavetolinkverification -import com.airbnb.mvrx.test.MavericksTestRule import com.google.common.truth.Truth.assertThat import com.stripe.android.core.Logger import com.stripe.android.financialconnections.ApiKeyFixtures.consumerSession import com.stripe.android.financialconnections.ApiKeyFixtures.partnerAccount import com.stripe.android.financialconnections.ApiKeyFixtures.sessionManifest +import com.stripe.android.financialconnections.CoroutineTestRule import com.stripe.android.financialconnections.TestFinancialConnectionsAnalyticsTracker import com.stripe.android.financialconnections.domain.ConfirmVerification import com.stripe.android.financialconnections.domain.GetCachedAccounts @@ -33,7 +33,7 @@ import org.mockito.kotlin.whenever class NetworkingSaveToLinkVerificationViewModelTest { @get:Rule - val mavericksTestRule = MavericksTestRule() + val testRule = CoroutineTestRule() private val navigationManager = TestNavigationManager() private val confirmVerification = mock() @@ -69,7 +69,7 @@ class NetworkingSaveToLinkVerificationViewModelTest { val viewModel = buildViewModel() - val state = viewModel.awaitState() + val state = viewModel.stateFlow.value verify(startVerification).sms(consumerSession.clientSecret) assertThat(state.payload()!!.consumerSessionClientSecret) .isEqualTo(consumerSession.clientSecret) @@ -88,14 +88,14 @@ class NetworkingSaveToLinkVerificationViewModelTest { val viewModel = buildViewModel() - val otpController = viewModel.awaitState().payload()!!.otpElement.controller + val otpController = viewModel.stateFlow.value.payload()!!.otpElement.controller // enters valid OTP for (i in 0 until otpController.otpLength) { otpController.onValueChanged(i, "1") } - val state = viewModel.awaitState() + val state = viewModel.stateFlow.value verify(saveAccountToLink).existing( eq(state.payload()!!.consumerSessionClientSecret), eq(listOf(selectedAccount.id)) @@ -128,14 +128,14 @@ class NetworkingSaveToLinkVerificationViewModelTest { val viewModel = buildViewModel() - val otpController = viewModel.awaitState().payload()!!.otpElement.controller + val otpController = viewModel.stateFlow.value.payload()!!.otpElement.controller // enters valid OTP for (i in 0 until otpController.otpLength) { otpController.onValueChanged(i, "1") } - val state = viewModel.awaitState() + val state = viewModel.stateFlow.value verify(saveAccountToLink).existing( eq(state.payload()!!.consumerSessionClientSecret), eq(listOf(selectedAccount.id)) diff --git a/financial-connections/src/test/java/com/stripe/android/financialconnections/features/partnerauth/PartnerAuthViewModelTest.kt b/financial-connections/src/test/java/com/stripe/android/financialconnections/features/partnerauth/PartnerAuthViewModelTest.kt index ec4e31078ca..cfcdc987839 100644 --- a/financial-connections/src/test/java/com/stripe/android/financialconnections/features/partnerauth/PartnerAuthViewModelTest.kt +++ b/financial-connections/src/test/java/com/stripe/android/financialconnections/features/partnerauth/PartnerAuthViewModelTest.kt @@ -1,6 +1,5 @@ package com.stripe.android.financialconnections.features.partnerauth -import com.airbnb.mvrx.test.MavericksTestRule import com.google.common.truth.Truth.assertThat import com.stripe.android.core.Logger import com.stripe.android.core.exception.APIException @@ -8,6 +7,7 @@ import com.stripe.android.financialconnections.ApiKeyFixtures.authorizationSessi import com.stripe.android.financialconnections.ApiKeyFixtures.institution import com.stripe.android.financialconnections.ApiKeyFixtures.sessionManifest import com.stripe.android.financialconnections.ApiKeyFixtures.syncResponse +import com.stripe.android.financialconnections.CoroutineTestRule import com.stripe.android.financialconnections.analytics.AuthSessionEvent import com.stripe.android.financialconnections.analytics.FinancialConnectionsAnalyticsTracker import com.stripe.android.financialconnections.domain.CancelAuthorizationSession @@ -25,7 +25,6 @@ import com.stripe.android.financialconnections.utils.TestHandleError import com.stripe.android.financialconnections.utils.TestNavigationManager import com.stripe.android.financialconnections.utils.UriUtils import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.runTest import org.junit.Rule import org.junit.Test @@ -36,12 +35,12 @@ import org.mockito.kotlin.verify import org.mockito.kotlin.verifyNoInteractions import org.mockito.kotlin.whenever -@OptIn(ExperimentalCoroutinesApi::class) @Suppress("MaxLineLength") +@ExperimentalCoroutinesApi internal class PartnerAuthViewModelTest { @get:Rule - val mavericksTestRule = MavericksTestRule(testDispatcher = UnconfinedTestDispatcher()) + val testRule = CoroutineTestRule() private val applicationId = "com.sample.applicationid" private val getSync = mock() diff --git a/financial-connections/src/test/java/com/stripe/android/financialconnections/features/success/SuccessViewModelTest.kt b/financial-connections/src/test/java/com/stripe/android/financialconnections/features/success/SuccessViewModelTest.kt index 20f257b85e0..82f54805f7f 100644 --- a/financial-connections/src/test/java/com/stripe/android/financialconnections/features/success/SuccessViewModelTest.kt +++ b/financial-connections/src/test/java/com/stripe/android/financialconnections/features/success/SuccessViewModelTest.kt @@ -1,10 +1,10 @@ package com.stripe.android.financialconnections.features.success import app.cash.turbine.test -import com.airbnb.mvrx.test.MavericksTestRule import com.google.common.truth.Truth.assertThat import com.stripe.android.core.Logger import com.stripe.android.financialconnections.ApiKeyFixtures +import com.stripe.android.financialconnections.CoroutineTestRule import com.stripe.android.financialconnections.TestFinancialConnectionsAnalyticsTracker import com.stripe.android.financialconnections.analytics.FinancialConnectionsAnalyticsEvent.PaneLoaded import com.stripe.android.financialconnections.domain.GetCachedAccounts @@ -15,7 +15,6 @@ import com.stripe.android.financialconnections.mock.TestSuccessContentRepository import com.stripe.android.financialconnections.model.FinancialConnectionsSessionManifest.Pane import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.MutableSharedFlow -import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.runTest import org.junit.Rule import org.junit.Test @@ -27,10 +26,8 @@ import kotlin.test.assertEquals @Suppress("MaxLineLength") internal class SuccessViewModelTest { - private val testDispatcher = UnconfinedTestDispatcher() - @get:Rule - val mavericksRule = MavericksTestRule(testDispatcher = testDispatcher) + val testRule = CoroutineTestRule() private val getManifest = mock() private val eventTracker = TestFinancialConnectionsAnalyticsTracker() diff --git a/paymentsheet-example/dependencies/dependencies.txt b/paymentsheet-example/dependencies/dependencies.txt index 32f683a3591..69cbcd62dd0 100644 --- a/paymentsheet-example/dependencies/dependencies.txt +++ b/paymentsheet-example/dependencies/dependencies.txt @@ -1123,15 +1123,6 @@ | | | \--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 1.9.10 (*) | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:{require 1.6.4; reject _} -> 1.7.3 (*) | | \--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 1.9.10 (*) -| +--- com.airbnb.android:mavericks-compose:3.0.9 -| | +--- androidx.lifecycle:lifecycle-common-java8:{require 2.6.1; reject _} -> 2.7.0 (*) -| | +--- androidx.fragment:fragment:{require 1.5.2; reject _} -> 1.6.2 (*) -| | +--- androidx.appcompat:appcompat:{require 1.5.0; reject _} -> 1.6.1 (*) -| | +--- androidx.compose.foundation:foundation:{require 1.2.1; reject _} -> 1.5.4 (*) -| | +--- androidx.compose.ui:ui:{require 1.2.1; reject _} -> 1.5.4 (*) -| | +--- androidx.lifecycle:lifecycle-viewmodel-compose:{require 2.6.1; reject _} -> 2.7.0 (*) -| | +--- com.airbnb.android:mavericks:3.0.9 (*) -| | \--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 1.9.10 (*) | \--- org.jetbrains.kotlin:kotlin-parcelize-runtime:1.9.22 (*) +--- androidx.activity:activity-ktx:1.8.2 (*) +--- androidx.appcompat:appcompat:1.6.1 (*)