From 8669051c84b0b8f2a1b237759eb720366b319f54 Mon Sep 17 00:00:00 2001 From: "Carlos M." Date: Tue, 19 Mar 2024 12:12:38 -0700 Subject: [PATCH 01/28] Removes mackericks references on Consent screen. --- .../financialconnections/core/Compose.kt | 26 ++++ .../core/FinancialConnectionsViewModel.kt | 49 +++++++ .../ConsentPreviewParameterProvider.kt | 26 ++-- .../features/consent/ConsentScreen.kt | 60 +++++---- .../features/consent/ConsentState.kt | 11 +- .../features/consent/ConsentViewModel.kt | 126 ++++++++++-------- 6 files changed, 195 insertions(+), 103 deletions(-) create mode 100644 financial-connections/src/main/java/com/stripe/android/financialconnections/core/Compose.kt create mode 100644 financial-connections/src/main/java/com/stripe/android/financialconnections/core/FinancialConnectionsViewModel.kt diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/core/Compose.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/core/Compose.kt new file mode 100644 index 00000000000..62221bc1cee --- /dev/null +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/core/Compose.kt @@ -0,0 +1,26 @@ +package com.stripe.android.financialconnections.core + +import android.content.Context +import android.content.ContextWrapper +import androidx.activity.ComponentActivity +import com.stripe.android.financialconnections.presentation.FinancialConnectionsSheetNativeViewModel +import com.stripe.android.financialconnections.ui.FinancialConnectionsSheetNativeActivity + +internal fun Context.activityViewModel() : FinancialConnectionsSheetNativeViewModel { + val activity = extractActivityFromContext(this) as FinancialConnectionsSheetNativeActivity + return activity.viewModel +} +private fun extractActivityFromContext(context: Context): ComponentActivity? { + var currentContext = context + if (currentContext is ComponentActivity) { + return currentContext + } else { + while (currentContext is ContextWrapper) { + if (currentContext is ComponentActivity) { + return currentContext + } + currentContext = currentContext.baseContext + } + } + return null +} \ No newline at end of file diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/core/FinancialConnectionsViewModel.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/core/FinancialConnectionsViewModel.kt new file mode 100644 index 00000000000..b9718590856 --- /dev/null +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/core/FinancialConnectionsViewModel.kt @@ -0,0 +1,49 @@ +package com.stripe.android.financialconnections.core + +import android.content.Context +import android.content.ContextWrapper +import androidx.activity.ComponentActivity +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.stripe.android.financialconnections.presentation.FinancialConnectionsSheetNativeViewModel +import com.stripe.android.financialconnections.ui.FinancialConnectionsSheetNativeActivity +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.launch + +abstract class FinancialConnectionsViewModel( + initialState: S +) : ViewModel() { + + val stateFlow: MutableStateFlow = MutableStateFlow(initialState) +} + +data class Result( + val loading: Boolean = false, + val data: T? = null, + val error: Throwable? = null +) { + operator fun invoke(): T? = data +} + + +fun FinancialConnectionsViewModel<*>.executeAsync( + block: suspend () -> T, + updateAsync: (Result) -> Unit, + onSuccess: (T) -> Unit = {}, + onFail: (Throwable) -> Unit = {} +) { + updateAsync(Result(loading = true)) + viewModelScope.launch { + val result = runCatching { block() } + updateAsync( + Result( + loading = false, + data = result.getOrNull(), + error = result.exceptionOrNull() + ) + ) + result + .onSuccess { onSuccess(it) } + .onFailure { onFail(it) } + } +} \ No newline at end of file diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentPreviewParameterProvider.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentPreviewParameterProvider.kt index 1e4de0c3b73..56ebbbc7239 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentPreviewParameterProvider.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentPreviewParameterProvider.kt @@ -3,7 +3,7 @@ package com.stripe.android.financialconnections.features.consent import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.material.ModalBottomSheetValue import androidx.compose.ui.tooling.preview.PreviewParameterProvider -import com.airbnb.mvrx.Success +import com.stripe.android.financialconnections.core.Result import com.stripe.android.financialconnections.model.Bullet import com.stripe.android.financialconnections.model.ConnectedAccessNotice import com.stripe.android.financialconnections.model.ConsentPane @@ -32,8 +32,8 @@ internal class ConsentPreviewParameterProvider : private fun withPlatformLogos() = ConsentState( - consent = Success( - ConsentState.Payload( + consent = Result( + data = ConsentState.Payload( consent = sampleConsent().copy(belowCta = null), merchantLogos = listOf( "www.logo1.com", @@ -46,8 +46,8 @@ internal class ConsentPreviewParameterProvider : private fun withConnectedAccountLogos() = ConsentState( - consent = Success( - ConsentState.Payload( + consent = Result( + data = ConsentState.Payload( consent = sampleConsent().copy(belowCta = null), merchantLogos = listOf( "www.logo1.com", @@ -60,8 +60,8 @@ internal class ConsentPreviewParameterProvider : ) private fun manualEntryPlusMicrodeposits() = ConsentState( - consent = Success( - ConsentState.Payload( + consent = Result( + data = ConsentState.Payload( consent = sampleConsent(), merchantLogos = listOf( "www.logo1.com", @@ -74,8 +74,8 @@ internal class ConsentPreviewParameterProvider : private fun withDataBottomSheet() = ConsentState( currentBottomSheet = ConsentState.BottomSheetContent.DATA, - consent = Success( - ConsentState.Payload( + consent = Result( + data = ConsentState.Payload( consent = sampleConsent().copy( dataAccessNotice = sampleConsent().dataAccessNotice.copy( connectedAccountNotice = null @@ -92,8 +92,8 @@ internal class ConsentPreviewParameterProvider : private fun withDataBottomSheetAndConnectedAccount() = ConsentState( currentBottomSheet = ConsentState.BottomSheetContent.DATA, - consent = Success( - ConsentState.Payload( + consent = Result( + data = ConsentState.Payload( consent = sampleConsent(), merchantLogos = listOf( "www.logo1.com", @@ -106,8 +106,8 @@ internal class ConsentPreviewParameterProvider : private fun withLegalDetailsBottomSheet() = ConsentState( currentBottomSheet = ConsentState.BottomSheetContent.LEGAL, - consent = Success( - ConsentState.Payload( + consent = Result( + data = ConsentState.Payload( consent = sampleConsent().copy(belowCta = null), merchantLogos = listOf( "www.logo1.com", diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentScreen.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentScreen.kt index 0fa834e059a..8b58d242876 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentScreen.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentScreen.kt @@ -17,11 +17,13 @@ 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 import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalUriHandler import androidx.compose.ui.platform.testTag import androidx.compose.ui.semantics.semantics @@ -30,13 +32,9 @@ 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 androidx.lifecycle.viewmodel.compose.viewModel +import com.stripe.android.financialconnections.core.Result +import com.stripe.android.financialconnections.core.activityViewModel import com.stripe.android.financialconnections.features.common.DataAccessBottomSheetContent import com.stripe.android.financialconnections.features.common.LegalDetailsBottomSheetContent import com.stripe.android.financialconnections.features.common.ListItem @@ -45,6 +43,7 @@ import com.stripe.android.financialconnections.features.consent.ConsentState.Vie import com.stripe.android.financialconnections.features.consent.ConsentState.ViewEffect.OpenUrl import com.stripe.android.financialconnections.features.consent.ui.ConsentLogoHeader import com.stripe.android.financialconnections.model.ConsentPane +import com.stripe.android.financialconnections.model.FinancialConnectionsSessionManifest import com.stripe.android.financialconnections.model.FinancialConnectionsSessionManifest.Pane import com.stripe.android.financialconnections.presentation.parentViewModel import com.stripe.android.financialconnections.ui.FinancialConnectionsPreview @@ -67,9 +66,11 @@ import kotlinx.coroutines.launch @Composable internal fun ConsentScreen() { // update step state when manifest changes - val viewModel: ConsentViewModel = mavericksViewModel() + val viewModel: ConsentViewModel = viewModel( + factory = ConsentViewModel.factory(parentViewModel = LocalContext.current.activityViewModel()) + ) val parentViewModel = parentViewModel() - val state = viewModel.collectAsState() + val state = viewModel.stateFlow.collectAsState() val uriHandler = LocalUriHandler.current val scope = rememberCoroutineScope() @@ -113,20 +114,27 @@ private fun ConsentContent( onCloseClick: () -> Unit, onCloseFromErrorClick: (Throwable) -> Unit ) { - when (val consent = state.consent) { - Uninitialized, is Loading -> ConsentLoadingContent() - is Success -> LoadedContent( - payload = consent(), - bottomSheetMode = state.currentBottomSheet, - acceptConsent = state.acceptConsent, - bottomSheetState = bottomSheetState, - onClickableTextClick = onClickableTextClick, - onCloseClick = onCloseClick, - onConfirmModalClick = onConfirmModalClick, - onContinueClick = onContinueClick - ) + when { + state.consent.loading -> { + ConsentLoadingContent() + } + + state.consent.error != null -> { + UnclassifiedErrorContent { onCloseFromErrorClick(state.consent.error) } + } - is Fail -> UnclassifiedErrorContent { onCloseFromErrorClick(consent.error) } + state.consent() != null -> { + LoadedContent( + payload = state.consent()!!, + bottomSheetState = bottomSheetState, + acceptConsent = state.acceptConsent, + bottomSheetMode = state.currentBottomSheet, + onClickableTextClick = onClickableTextClick, + onContinueClick = onContinueClick, + onCloseClick = onCloseClick, + onConfirmModalClick = onConfirmModalClick + ) + } } } @@ -147,7 +155,7 @@ private fun ConsentLoadingContent() { @Composable private fun ConsentMainContent( payload: ConsentState.Payload, - acceptConsent: Async, + acceptConsent: Result, onClickableTextClick: (String) -> Unit, onContinueClick: () -> Unit, onCloseClick: () -> Unit @@ -230,7 +238,7 @@ private fun LazyListScope.consentBody( private fun LoadedContent( payload: ConsentState.Payload, bottomSheetState: ModalBottomSheetState, - acceptConsent: Async, + acceptConsent: Result, onContinueClick: () -> Unit, onCloseClick: () -> Unit, onClickableTextClick: (String) -> Unit, @@ -271,7 +279,7 @@ private fun LoadedContent( @OptIn(ExperimentalComposeUiApi::class) @Composable private fun ConsentFooter( - acceptConsent: Async, + acceptConsent: Result, consent: ConsentPane, onClickableTextClick: (String) -> Unit, onContinueClick: () -> Unit, @@ -294,7 +302,7 @@ private fun ConsentFooter( ) Spacer(modifier = Modifier.size(16.dp)) FinancialConnectionsButton( - loading = acceptConsent is Loading, + loading = acceptConsent.loading, onClick = onContinueClick, modifier = Modifier .semantics { testTagsAsResourceId = true } diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentState.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentState.kt index de5ec0d693a..bb232b56740 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentState.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentState.kt @@ -1,17 +1,16 @@ package com.stripe.android.financialconnections.features.consent -import com.airbnb.mvrx.Async -import com.airbnb.mvrx.MavericksState -import com.airbnb.mvrx.Uninitialized +import com.stripe.android.financialconnections.core.Result import com.stripe.android.financialconnections.model.ConsentPane +import com.stripe.android.financialconnections.model.FinancialConnectionsSessionManifest internal data class ConsentState( - val consent: Async = Uninitialized, + val consent: Result = Result(), val merchantLogos: List = emptyList(), val currentBottomSheet: BottomSheetContent = BottomSheetContent.DATA, - val acceptConsent: Async = Uninitialized, + val acceptConsent: Result = Result(), val viewEffect: ViewEffect? = null -) : MavericksState { +) { data class Payload( val consent: ConsentPane, diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentViewModel.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentViewModel.kt index 1eac34eb74f..61a457839a0 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentViewModel.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentViewModel.kt @@ -1,8 +1,9 @@ package com.stripe.android.financialconnections.features.consent -import com.airbnb.mvrx.MavericksViewModel -import com.airbnb.mvrx.MavericksViewModelFactory -import com.airbnb.mvrx.ViewModelContext +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.viewModelScope +import androidx.lifecycle.viewmodel.CreationExtras import com.stripe.android.core.Logger import com.stripe.android.financialconnections.FinancialConnections import com.stripe.android.financialconnections.analytics.FinancialConnectionsAnalyticsEvent.ConsentAgree @@ -10,21 +11,23 @@ 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.FinancialConnectionsViewModel +import com.stripe.android.financialconnections.core.executeAsync import com.stripe.android.financialconnections.domain.AcceptConsent import com.stripe.android.financialconnections.domain.GetOrFetchSync import com.stripe.android.financialconnections.features.consent.ConsentState.BottomSheetContent import com.stripe.android.financialconnections.features.consent.ConsentState.ViewEffect import com.stripe.android.financialconnections.features.consent.ConsentState.ViewEffect.OpenUrl -import com.stripe.android.financialconnections.model.FinancialConnectionsSessionManifest 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.navigation.destination -import com.stripe.android.financialconnections.ui.FinancialConnectionsSheetNativeActivity +import com.stripe.android.financialconnections.presentation.FinancialConnectionsSheetNativeViewModel import com.stripe.android.financialconnections.ui.HandleClickableUrl import com.stripe.android.financialconnections.utils.Experiment.CONNECTIONS_CONSENT_COMBINED_LOGO import com.stripe.android.financialconnections.utils.experimentAssignment import com.stripe.android.financialconnections.utils.trackExposure +import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import java.util.Date import javax.inject.Inject @@ -37,47 +40,50 @@ internal class ConsentViewModel @Inject constructor( private val eventTracker: FinancialConnectionsAnalyticsTracker, private val handleClickableUrl: HandleClickableUrl, private val logger: Logger -) : MavericksViewModel(initialState) { +) : FinancialConnectionsViewModel(initialState) { init { - logErrors() - suspend { - val sync = getOrFetchSync() - val manifest = sync.manifest - val shouldShowMerchantLogos: Boolean = manifest - .experimentAssignment(CONNECTIONS_CONSENT_COMBINED_LOGO) == "treatment" - eventTracker.trackExposure(CONNECTIONS_CONSENT_COMBINED_LOGO, manifest) - ConsentState.Payload( - consent = sync.text!!.consent!!, - shouldShowMerchantLogos = shouldShowMerchantLogos, - merchantLogos = sync.visual.merchantLogos - ) - }.execute { copy(consent = it) } - } - - private fun logErrors() { - onAsync( - ConsentState::consent, - onSuccess = { eventTracker.track(PaneLoaded(Pane.CONSENT)) }, - onFail = { logger.error("Error retrieving consent content", it) } + executeAsync( + block = { + val sync = getOrFetchSync() + val manifest = sync.manifest + val shouldShowMerchantLogos: Boolean = manifest + .experimentAssignment(CONNECTIONS_CONSENT_COMBINED_LOGO) == "treatment" + eventTracker.trackExposure(CONNECTIONS_CONSENT_COMBINED_LOGO, manifest) + ConsentState.Payload( + consent = sync.text!!.consent!!, + shouldShowMerchantLogos = shouldShowMerchantLogos, + merchantLogos = sync.visual.merchantLogos + ) + }, + updateAsync = { stateFlow.update { state -> state.copy(consent = it) } }, + onFail = { logger.error("Error retrieving consent content", it) }, + onSuccess = { eventTracker.track(PaneLoaded(Pane.CONSENT)) } ) - onAsync(ConsentState::acceptConsent, onFail = { - eventTracker.logError( - extraMessage = "Error accepting consent", - error = it, - logger = logger, - pane = Pane.CONSENT - ) - }) } fun onContinueClick() { - suspend { - eventTracker.track(ConsentAgree) - FinancialConnections.emitEvent(Name.CONSENT_ACQUIRED) - val updatedManifest: FinancialConnectionsSessionManifest = acceptConsent() - navigationManager.tryNavigateTo(updatedManifest.nextPane.destination(referrer = Pane.CONSENT)) - }.execute { copy(acceptConsent = it) } + executeAsync( + block = { + eventTracker.track(ConsentAgree) + FinancialConnections.emitEvent(Name.CONSENT_ACQUIRED) + acceptConsent() + }, + updateAsync = { + stateFlow.update { state -> state.copy(acceptConsent = it) } + }, + onFail = { + eventTracker.logError( + extraMessage = "Error accepting consent", + error = it, + logger = logger, + pane = Pane.CONSENT + ) + }, + onSuccess = { manifest -> + navigationManager.tryNavigateTo(manifest.nextPane.destination(referrer = Pane.CONSENT)) + } + ) } fun onClickableTextClick(uri: String) = viewModelScope.launch { @@ -85,12 +91,12 @@ internal class ConsentViewModel @Inject constructor( handleClickableUrl( currentPane = Pane.CONSENT, uri = uri, - onNetworkUrlClicked = { setState { copy(viewEffect = OpenUrl(uri, date.time)) } }, + onNetworkUrlClicked = { stateFlow.update { it.copy(viewEffect = OpenUrl(uri, date.time)) } }, knownDeeplinkActions = mapOf( // Clicked on the "Data Access" link -> Open the Data Access bottom sheet ConsentClickableText.DATA.value to { - setState { - copy( + stateFlow.update { + it.copy( currentBottomSheet = BottomSheetContent.DATA, viewEffect = ViewEffect.OpenBottomSheet(date.time) ) @@ -98,8 +104,8 @@ internal class ConsentViewModel @Inject constructor( }, // Clicked on the "Legal details" link -> Open the Legal Details bottom sheet ConsentClickableText.LEGAL_DETAILS.value to { - setState { - copy( + stateFlow.update { + it.copy( viewEffect = ViewEffect.OpenBottomSheet(date.time), currentBottomSheet = BottomSheetContent.LEGAL ) @@ -114,22 +120,26 @@ internal class ConsentViewModel @Inject constructor( } fun onViewEffectLaunched() { - setState { copy(viewEffect = null) } + stateFlow.update { it.copy(viewEffect = null) } } - companion object : MavericksViewModelFactory { + companion object { - override fun create( - viewModelContext: ViewModelContext, - state: ConsentState - ): ConsentViewModel { - return viewModelContext.activity() - .viewModel - .activityRetainedComponent - .consentBuilder - .initialState(state) - .build() - .viewModel + fun factory(parentViewModel: FinancialConnectionsSheetNativeViewModel): ViewModelProvider.Factory { + return object : ViewModelProvider.Factory { + override fun create( + modelClass: Class, + extras: CreationExtras + ): T { + return parentViewModel + .activityRetainedComponent + .consentBuilder + .initialState(ConsentState()) + .build() + .viewModel as T + } + } } + } } From be1f31f10269cf55f7f3130e20cb5bbb805d92d7 Mon Sep 17 00:00:00 2001 From: "Carlos M." Date: Tue, 19 Mar 2024 12:15:05 -0700 Subject: [PATCH 02/28] Updates files. --- .../core/{Compose.kt => compose.kt} | 0 ...{FinancialConnectionsViewModel.kt => viewmodel.kt} | 11 +++-------- 2 files changed, 3 insertions(+), 8 deletions(-) rename financial-connections/src/main/java/com/stripe/android/financialconnections/core/{Compose.kt => compose.kt} (100%) rename financial-connections/src/main/java/com/stripe/android/financialconnections/core/{FinancialConnectionsViewModel.kt => viewmodel.kt} (70%) diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/core/Compose.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/core/compose.kt similarity index 100% rename from financial-connections/src/main/java/com/stripe/android/financialconnections/core/Compose.kt rename to financial-connections/src/main/java/com/stripe/android/financialconnections/core/compose.kt diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/core/FinancialConnectionsViewModel.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/core/viewmodel.kt similarity index 70% rename from financial-connections/src/main/java/com/stripe/android/financialconnections/core/FinancialConnectionsViewModel.kt rename to financial-connections/src/main/java/com/stripe/android/financialconnections/core/viewmodel.kt index b9718590856..7eab3a3802c 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/core/FinancialConnectionsViewModel.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/core/viewmodel.kt @@ -1,23 +1,18 @@ package com.stripe.android.financialconnections.core -import android.content.Context -import android.content.ContextWrapper -import androidx.activity.ComponentActivity import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.stripe.android.financialconnections.presentation.FinancialConnectionsSheetNativeViewModel -import com.stripe.android.financialconnections.ui.FinancialConnectionsSheetNativeActivity import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.launch -abstract class FinancialConnectionsViewModel( +internal abstract class FinancialConnectionsViewModel( initialState: S ) : ViewModel() { val stateFlow: MutableStateFlow = MutableStateFlow(initialState) } -data class Result( +internal data class Result( val loading: Boolean = false, val data: T? = null, val error: Throwable? = null @@ -26,7 +21,7 @@ data class Result( } -fun FinancialConnectionsViewModel<*>.executeAsync( +internal fun FinancialConnectionsViewModel<*>.executeAsync( block: suspend () -> T, updateAsync: (Result) -> Unit, onSuccess: (T) -> Unit = {}, From 897109c0d3341c92df61fab8810bccecd12f0928 Mon Sep 17 00:00:00 2001 From: "Carlos M." Date: Tue, 19 Mar 2024 12:23:50 -0700 Subject: [PATCH 03/28] Uses viewmodel factory builder. --- .../features/consent/ConsentViewModel.kt | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentViewModel.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentViewModel.kt index 61a457839a0..e2aad2e3d04 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentViewModel.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentViewModel.kt @@ -1,9 +1,9 @@ package com.stripe.android.financialconnections.features.consent -import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.viewModelScope -import androidx.lifecycle.viewmodel.CreationExtras +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.ConsentAgree @@ -125,21 +125,16 @@ internal class ConsentViewModel @Inject constructor( companion object { - fun factory(parentViewModel: FinancialConnectionsSheetNativeViewModel): ViewModelProvider.Factory { - return object : ViewModelProvider.Factory { - override fun create( - modelClass: Class, - extras: CreationExtras - ): T { - return parentViewModel + fun factory(parentViewModel: FinancialConnectionsSheetNativeViewModel): ViewModelProvider.Factory = + viewModelFactory { + initializer { + parentViewModel .activityRetainedComponent .consentBuilder .initialState(ConsentState()) .build() - .viewModel as T + .viewModel } } - } - } } From 2f309d65384f3adabc4e8b2afa1c6f32cbe01421 Mon Sep 17 00:00:00 2001 From: "Carlos M." Date: Tue, 19 Mar 2024 12:26:17 -0700 Subject: [PATCH 04/28] Updates functions. --- .../android/financialconnections/core/viewmodel.kt | 8 ++++---- .../features/consent/ConsentViewModel.kt | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/core/viewmodel.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/core/viewmodel.kt index 7eab3a3802c..d6f856badcb 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/core/viewmodel.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/core/viewmodel.kt @@ -21,16 +21,16 @@ internal data class Result( } -internal fun FinancialConnectionsViewModel<*>.executeAsync( +internal fun FinancialConnectionsViewModel<*>.execute( block: suspend () -> T, - updateAsync: (Result) -> Unit, + onResultUpdated: (Result) -> Unit, onSuccess: (T) -> Unit = {}, onFail: (Throwable) -> Unit = {} ) { - updateAsync(Result(loading = true)) + onResultUpdated(Result(loading = true)) viewModelScope.launch { val result = runCatching { block() } - updateAsync( + onResultUpdated( Result( loading = false, data = result.getOrNull(), diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentViewModel.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentViewModel.kt index e2aad2e3d04..8b77ad91298 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentViewModel.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentViewModel.kt @@ -12,7 +12,7 @@ import com.stripe.android.financialconnections.analytics.FinancialConnectionsAna import com.stripe.android.financialconnections.analytics.FinancialConnectionsEvent.Name import com.stripe.android.financialconnections.analytics.logError import com.stripe.android.financialconnections.core.FinancialConnectionsViewModel -import com.stripe.android.financialconnections.core.executeAsync +import com.stripe.android.financialconnections.core.execute import com.stripe.android.financialconnections.domain.AcceptConsent import com.stripe.android.financialconnections.domain.GetOrFetchSync import com.stripe.android.financialconnections.features.consent.ConsentState.BottomSheetContent @@ -43,7 +43,7 @@ internal class ConsentViewModel @Inject constructor( ) : FinancialConnectionsViewModel(initialState) { init { - executeAsync( + execute( block = { val sync = getOrFetchSync() val manifest = sync.manifest @@ -56,20 +56,20 @@ internal class ConsentViewModel @Inject constructor( merchantLogos = sync.visual.merchantLogos ) }, - updateAsync = { stateFlow.update { state -> state.copy(consent = it) } }, + onResultUpdated = { stateFlow.update { state -> state.copy(consent = it) } }, onFail = { logger.error("Error retrieving consent content", it) }, onSuccess = { eventTracker.track(PaneLoaded(Pane.CONSENT)) } ) } fun onContinueClick() { - executeAsync( + execute( block = { eventTracker.track(ConsentAgree) FinancialConnections.emitEvent(Name.CONSENT_ACQUIRED) acceptConsent() }, - updateAsync = { + onResultUpdated = { stateFlow.update { state -> state.copy(acceptConsent = it) } }, onFail = { From deecbdb189c7db5f710c3013c0948602ad9fc128 Mon Sep 17 00:00:00 2001 From: "Carlos M." Date: Tue, 19 Mar 2024 14:30:29 -0700 Subject: [PATCH 05/28] Updates execute. --- .../financialconnections/core/compose.kt | 4 +- .../financialconnections/core/viewmodel.kt | 45 +++++++------ .../features/consent/ConsentViewModel.kt | 66 +++++++++---------- 3 files changed, 56 insertions(+), 59 deletions(-) diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/core/compose.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/core/compose.kt index 62221bc1cee..1e7bc7ad2e2 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/core/compose.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/core/compose.kt @@ -6,7 +6,7 @@ import androidx.activity.ComponentActivity import com.stripe.android.financialconnections.presentation.FinancialConnectionsSheetNativeViewModel import com.stripe.android.financialconnections.ui.FinancialConnectionsSheetNativeActivity -internal fun Context.activityViewModel() : FinancialConnectionsSheetNativeViewModel { +internal fun Context.activityViewModel(): FinancialConnectionsSheetNativeViewModel { val activity = extractActivityFromContext(this) as FinancialConnectionsSheetNativeActivity return activity.viewModel } @@ -23,4 +23,4 @@ private fun extractActivityFromContext(context: Context): ComponentActivity? { } } return null -} \ No newline at end of file +} diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/core/viewmodel.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/core/viewmodel.kt index d6f856badcb..a8a1c32594d 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/core/viewmodel.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/core/viewmodel.kt @@ -2,7 +2,9 @@ package com.stripe.android.financialconnections.core import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import kotlinx.coroutines.Job import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch internal abstract class FinancialConnectionsViewModel( @@ -10,6 +12,26 @@ internal abstract class FinancialConnectionsViewModel( ) : ViewModel() { val stateFlow: MutableStateFlow = MutableStateFlow(initialState) + + protected open fun (suspend () -> T).execute( + reducer: S.(Result) -> S, + onSuccess: (T) -> Unit = {}, + onFail: (Throwable) -> Unit = {} + ): Job { + return viewModelScope.launch { + stateFlow.update { state -> state.reducer(Result(loading = true)) } + val result = kotlin.runCatching { this@execute() } + stateFlow.update { state -> + state.reducer( + Result( + loading = false, + data = result.getOrNull(), + error = result.exceptionOrNull() + ) + ) + } + } + } } internal data class Result( @@ -19,26 +41,3 @@ internal data class Result( ) { operator fun invoke(): T? = data } - - -internal fun FinancialConnectionsViewModel<*>.execute( - block: suspend () -> T, - onResultUpdated: (Result) -> Unit, - onSuccess: (T) -> Unit = {}, - onFail: (Throwable) -> Unit = {} -) { - onResultUpdated(Result(loading = true)) - viewModelScope.launch { - val result = runCatching { block() } - onResultUpdated( - Result( - loading = false, - data = result.getOrNull(), - error = result.exceptionOrNull() - ) - ) - result - .onSuccess { onSuccess(it) } - .onFailure { onFail(it) } - } -} \ No newline at end of file diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentViewModel.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentViewModel.kt index 8b77ad91298..91905c3b199 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentViewModel.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentViewModel.kt @@ -12,7 +12,6 @@ import com.stripe.android.financialconnections.analytics.FinancialConnectionsAna import com.stripe.android.financialconnections.analytics.FinancialConnectionsEvent.Name import com.stripe.android.financialconnections.analytics.logError import com.stripe.android.financialconnections.core.FinancialConnectionsViewModel -import com.stripe.android.financialconnections.core.execute import com.stripe.android.financialconnections.domain.AcceptConsent import com.stripe.android.financialconnections.domain.GetOrFetchSync import com.stripe.android.financialconnections.features.consent.ConsentState.BottomSheetContent @@ -43,49 +42,48 @@ internal class ConsentViewModel @Inject constructor( ) : FinancialConnectionsViewModel(initialState) { init { - execute( - block = { - val sync = getOrFetchSync() - val manifest = sync.manifest - val shouldShowMerchantLogos: Boolean = manifest - .experimentAssignment(CONNECTIONS_CONSENT_COMBINED_LOGO) == "treatment" - eventTracker.trackExposure(CONNECTIONS_CONSENT_COMBINED_LOGO, manifest) - ConsentState.Payload( - consent = sync.text!!.consent!!, - shouldShowMerchantLogos = shouldShowMerchantLogos, - merchantLogos = sync.visual.merchantLogos - ) - }, - onResultUpdated = { stateFlow.update { state -> state.copy(consent = it) } }, - onFail = { logger.error("Error retrieving consent content", it) }, - onSuccess = { eventTracker.track(PaneLoaded(Pane.CONSENT)) } - ) - } - - fun onContinueClick() { - execute( - block = { - eventTracker.track(ConsentAgree) - FinancialConnections.emitEvent(Name.CONSENT_ACQUIRED) - acceptConsent() - }, - onResultUpdated = { - stateFlow.update { state -> state.copy(acceptConsent = it) } - }, + suspend { + val sync = getOrFetchSync() + val manifest = sync.manifest + val shouldShowMerchantLogos: Boolean = manifest + .experimentAssignment(CONNECTIONS_CONSENT_COMBINED_LOGO) == "treatment" + eventTracker.trackExposure(CONNECTIONS_CONSENT_COMBINED_LOGO, manifest) + ConsentState.Payload( + consent = sync.text!!.consent!!, + shouldShowMerchantLogos = shouldShowMerchantLogos, + merchantLogos = sync.visual.merchantLogos + ) + }.execute( + reducer = { copy(consent = it) }, + onSuccess = { eventTracker.track(PaneLoaded(Pane.CONSENT)) }, onFail = { eventTracker.logError( - extraMessage = "Error accepting consent", + extraMessage = "Error retrieving consent content", error = it, logger = logger, pane = Pane.CONSENT ) }, - onSuccess = { manifest -> - navigationManager.tryNavigateTo(manifest.nextPane.destination(referrer = Pane.CONSENT)) - } ) } + fun onContinueClick() = suspend { + eventTracker.track(ConsentAgree) + FinancialConnections.emitEvent(Name.CONSENT_ACQUIRED) + acceptConsent() + }.execute( + reducer = { copy(acceptConsent = it) }, + onSuccess = { navigationManager.tryNavigateTo(it.nextPane.destination(referrer = Pane.CONSENT)) }, + onFail = { + eventTracker.logError( + extraMessage = "Error accepting consent", + error = it, + logger = logger, + pane = Pane.CONSENT + ) + }, + ) + fun onClickableTextClick(uri: String) = viewModelScope.launch { val date = Date() handleClickableUrl( From d2f6bf4dcec520f67b058cf775c10147274773b9 Mon Sep 17 00:00:00 2001 From: "Carlos M." Date: Tue, 19 Mar 2024 14:41:34 -0700 Subject: [PATCH 06/28] Updates compose util. --- ...ewmodel.kt => FinancialConnectionsViewModel.kt} | 0 .../android/financialconnections/core/compose.kt | 14 +++++++++++--- .../features/consent/ConsentScreen.kt | 8 +++----- 3 files changed, 14 insertions(+), 8 deletions(-) rename financial-connections/src/main/java/com/stripe/android/financialconnections/core/{viewmodel.kt => FinancialConnectionsViewModel.kt} (100%) diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/core/viewmodel.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/core/FinancialConnectionsViewModel.kt similarity index 100% rename from financial-connections/src/main/java/com/stripe/android/financialconnections/core/viewmodel.kt rename to financial-connections/src/main/java/com/stripe/android/financialconnections/core/FinancialConnectionsViewModel.kt diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/core/compose.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/core/compose.kt index 1e7bc7ad2e2..816742d13cb 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/core/compose.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/core/compose.kt @@ -3,13 +3,21 @@ package com.stripe.android.financialconnections.core import android.content.Context import android.content.ContextWrapper import androidx.activity.ComponentActivity +import androidx.compose.runtime.Composable +import androidx.compose.ui.platform.LocalContext +import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.viewmodel.compose.viewModel import com.stripe.android.financialconnections.presentation.FinancialConnectionsSheetNativeViewModel import com.stripe.android.financialconnections.ui.FinancialConnectionsSheetNativeActivity -internal fun Context.activityViewModel(): FinancialConnectionsSheetNativeViewModel { - val activity = extractActivityFromContext(this) as FinancialConnectionsSheetNativeActivity - return activity.viewModel +@Composable +internal inline fun , S> rememberPaneViewModel( + factory: (FinancialConnectionsSheetNativeViewModel) -> ViewModelProvider.Factory +): T { + val parentActivity = extractActivityFromContext(LocalContext.current) as FinancialConnectionsSheetNativeActivity + return viewModel(factory = factory(parentActivity.viewModel)) } + private fun extractActivityFromContext(context: Context): ComponentActivity? { var currentContext = context if (currentContext is ComponentActivity) { diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentScreen.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentScreen.kt index 8b58d242876..65993e513ed 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentScreen.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentScreen.kt @@ -23,7 +23,6 @@ import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalUriHandler import androidx.compose.ui.platform.testTag import androidx.compose.ui.semantics.semantics @@ -32,9 +31,8 @@ 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 androidx.lifecycle.viewmodel.compose.viewModel import com.stripe.android.financialconnections.core.Result -import com.stripe.android.financialconnections.core.activityViewModel +import com.stripe.android.financialconnections.core.rememberPaneViewModel import com.stripe.android.financialconnections.features.common.DataAccessBottomSheetContent import com.stripe.android.financialconnections.features.common.LegalDetailsBottomSheetContent import com.stripe.android.financialconnections.features.common.ListItem @@ -66,8 +64,8 @@ import kotlinx.coroutines.launch @Composable internal fun ConsentScreen() { // update step state when manifest changes - val viewModel: ConsentViewModel = viewModel( - factory = ConsentViewModel.factory(parentViewModel = LocalContext.current.activityViewModel()) + val viewModel: ConsentViewModel = rememberPaneViewModel( + factory = { ConsentViewModel.factory(it) } ) val parentViewModel = parentViewModel() val state = viewModel.stateFlow.collectAsState() From a825667f2f34bc1c8fbaccf2ef7397a33ccf4133 Mon Sep 17 00:00:00 2001 From: "Carlos M." Date: Tue, 19 Mar 2024 14:43:19 -0700 Subject: [PATCH 07/28] Adds missing side effects. --- .../core/{compose.kt => ComposeUtils.kt} | 0 .../core/FinancialConnectionsViewModel.kt | 5 +++++ 2 files changed, 5 insertions(+) rename financial-connections/src/main/java/com/stripe/android/financialconnections/core/{compose.kt => ComposeUtils.kt} (100%) diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/core/compose.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/core/ComposeUtils.kt similarity index 100% rename from financial-connections/src/main/java/com/stripe/android/financialconnections/core/compose.kt rename to financial-connections/src/main/java/com/stripe/android/financialconnections/core/ComposeUtils.kt diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/core/FinancialConnectionsViewModel.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/core/FinancialConnectionsViewModel.kt index a8a1c32594d..58d45377ad3 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/core/FinancialConnectionsViewModel.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/core/FinancialConnectionsViewModel.kt @@ -21,6 +21,7 @@ internal abstract class FinancialConnectionsViewModel( return viewModelScope.launch { stateFlow.update { state -> state.reducer(Result(loading = true)) } val result = kotlin.runCatching { this@execute() } + // update state. stateFlow.update { state -> state.reducer( Result( @@ -30,6 +31,10 @@ internal abstract class FinancialConnectionsViewModel( ) ) } + // trigger side effects. + result + .onSuccess(onSuccess) + .onFailure(onFail) } } } From 7bd7df50720ecf99f50120b8f6d039291a39367b Mon Sep 17 00:00:00 2001 From: "Carlos M." Date: Tue, 19 Mar 2024 14:45:41 -0700 Subject: [PATCH 08/28] Simplifies code. --- .../financialconnections/features/consent/ConsentScreen.kt | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentScreen.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentScreen.kt index 65993e513ed..5aca56e2300 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentScreen.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentScreen.kt @@ -63,10 +63,7 @@ import kotlinx.coroutines.launch @ExperimentalMaterialApi @Composable internal fun ConsentScreen() { - // update step state when manifest changes - val viewModel: ConsentViewModel = rememberPaneViewModel( - factory = { ConsentViewModel.factory(it) } - ) + val viewModel: ConsentViewModel = rememberPaneViewModel { ConsentViewModel.factory(it) } val parentViewModel = parentViewModel() val state = viewModel.stateFlow.collectAsState() From 01dff6051ce7351a26ff5d8a699222ecc94f867d Mon Sep 17 00:00:00 2001 From: "Carlos M." Date: Tue, 19 Mar 2024 14:46:21 -0700 Subject: [PATCH 09/28] Renames viewmodel. --- .../stripe/android/financialconnections/core/ComposeUtils.kt | 2 +- .../{FinancialConnectionsViewModel.kt => PaneViewModel.kt} | 2 +- .../financialconnections/features/consent/ConsentViewModel.kt | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) rename financial-connections/src/main/java/com/stripe/android/financialconnections/core/{FinancialConnectionsViewModel.kt => PaneViewModel.kt} (96%) diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/core/ComposeUtils.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/core/ComposeUtils.kt index 816742d13cb..f1592e4b9db 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/core/ComposeUtils.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/core/ComposeUtils.kt @@ -11,7 +11,7 @@ import com.stripe.android.financialconnections.presentation.FinancialConnections import com.stripe.android.financialconnections.ui.FinancialConnectionsSheetNativeActivity @Composable -internal inline fun , S> rememberPaneViewModel( +internal inline fun , S> rememberPaneViewModel( factory: (FinancialConnectionsSheetNativeViewModel) -> ViewModelProvider.Factory ): T { val parentActivity = extractActivityFromContext(LocalContext.current) as FinancialConnectionsSheetNativeActivity diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/core/FinancialConnectionsViewModel.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/core/PaneViewModel.kt similarity index 96% rename from financial-connections/src/main/java/com/stripe/android/financialconnections/core/FinancialConnectionsViewModel.kt rename to financial-connections/src/main/java/com/stripe/android/financialconnections/core/PaneViewModel.kt index 58d45377ad3..f266edd0874 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/core/FinancialConnectionsViewModel.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/core/PaneViewModel.kt @@ -7,7 +7,7 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch -internal abstract class FinancialConnectionsViewModel( +internal abstract class PaneViewModel( initialState: S ) : ViewModel() { diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentViewModel.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentViewModel.kt index 91905c3b199..8f3ada8db13 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentViewModel.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentViewModel.kt @@ -11,7 +11,7 @@ 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.FinancialConnectionsViewModel +import com.stripe.android.financialconnections.core.PaneViewModel import com.stripe.android.financialconnections.domain.AcceptConsent import com.stripe.android.financialconnections.domain.GetOrFetchSync import com.stripe.android.financialconnections.features.consent.ConsentState.BottomSheetContent @@ -39,7 +39,7 @@ internal class ConsentViewModel @Inject constructor( private val eventTracker: FinancialConnectionsAnalyticsTracker, private val handleClickableUrl: HandleClickableUrl, private val logger: Logger -) : FinancialConnectionsViewModel(initialState) { +) : PaneViewModel(initialState) { init { suspend { From a10a111c22709a7c15ce1302bd134c8213d8aa05 Mon Sep 17 00:00:00 2001 From: "Carlos M." Date: Tue, 19 Mar 2024 14:58:19 -0700 Subject: [PATCH 10/28] Updates async. --- .../core/PaneViewModel.kt | 38 +++++++++---------- .../ConsentPreviewParameterProvider.kt | 24 ++++++------ .../features/consent/ConsentScreen.kt | 14 +++---- .../features/consent/ConsentState.kt | 4 +- 4 files changed, 40 insertions(+), 40 deletions(-) diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/core/PaneViewModel.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/core/PaneViewModel.kt index f266edd0874..d8ce5180c64 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/core/PaneViewModel.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/core/PaneViewModel.kt @@ -19,30 +19,30 @@ internal abstract class PaneViewModel( onFail: (Throwable) -> Unit = {} ): Job { return viewModelScope.launch { - stateFlow.update { state -> state.reducer(Result(loading = true)) } + stateFlow.update { state -> state.reducer(Result.Loading) } val result = kotlin.runCatching { this@execute() } // update state. - stateFlow.update { state -> - state.reducer( - Result( - loading = false, - data = result.getOrNull(), - error = result.exceptionOrNull() - ) - ) - } - // trigger side effects. - result - .onSuccess(onSuccess) - .onFailure(onFail) + result.fold( + onSuccess = { data -> + stateFlow.update { state -> state.reducer(Result.Success(data)) } + onSuccess(data) + }, + onFailure = { throwable -> + stateFlow.update { state -> state.reducer(Result.Error(throwable)) } + onFail(throwable) + } + ) } } } -internal data class Result( - val loading: Boolean = false, - val data: T? = null, - val error: Throwable? = null +internal sealed class Result( + private val value: T? ) { - operator fun invoke(): T? = data + data object Uninitialized : Result(value = null) + data object Loading : Result(value = null) + data class Success(val value: T) : Result(value = value) + data class Error(val throwable: Throwable) : Result(value = null) + + open operator fun invoke(): T? = value } diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentPreviewParameterProvider.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentPreviewParameterProvider.kt index 56ebbbc7239..251a400eb42 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentPreviewParameterProvider.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentPreviewParameterProvider.kt @@ -32,8 +32,8 @@ internal class ConsentPreviewParameterProvider : private fun withPlatformLogos() = ConsentState( - consent = Result( - data = ConsentState.Payload( + consent = Result.Success( + ConsentState.Payload( consent = sampleConsent().copy(belowCta = null), merchantLogos = listOf( "www.logo1.com", @@ -46,8 +46,8 @@ internal class ConsentPreviewParameterProvider : private fun withConnectedAccountLogos() = ConsentState( - consent = Result( - data = ConsentState.Payload( + consent = Result.Success( + ConsentState.Payload( consent = sampleConsent().copy(belowCta = null), merchantLogos = listOf( "www.logo1.com", @@ -60,8 +60,8 @@ internal class ConsentPreviewParameterProvider : ) private fun manualEntryPlusMicrodeposits() = ConsentState( - consent = Result( - data = ConsentState.Payload( + consent = Result.Success( + ConsentState.Payload( consent = sampleConsent(), merchantLogos = listOf( "www.logo1.com", @@ -74,8 +74,8 @@ internal class ConsentPreviewParameterProvider : private fun withDataBottomSheet() = ConsentState( currentBottomSheet = ConsentState.BottomSheetContent.DATA, - consent = Result( - data = ConsentState.Payload( + consent = Result.Success( + ConsentState.Payload( consent = sampleConsent().copy( dataAccessNotice = sampleConsent().dataAccessNotice.copy( connectedAccountNotice = null @@ -92,8 +92,8 @@ internal class ConsentPreviewParameterProvider : private fun withDataBottomSheetAndConnectedAccount() = ConsentState( currentBottomSheet = ConsentState.BottomSheetContent.DATA, - consent = Result( - data = ConsentState.Payload( + consent = Result.Success( + ConsentState.Payload( consent = sampleConsent(), merchantLogos = listOf( "www.logo1.com", @@ -106,8 +106,8 @@ internal class ConsentPreviewParameterProvider : private fun withLegalDetailsBottomSheet() = ConsentState( currentBottomSheet = ConsentState.BottomSheetContent.LEGAL, - consent = Result( - data = ConsentState.Payload( + consent = Result.Success( + ConsentState.Payload( consent = sampleConsent().copy(belowCta = null), merchantLogos = listOf( "www.logo1.com", diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentScreen.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentScreen.kt index 5aca56e2300..7b6e277bade 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentScreen.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentScreen.kt @@ -109,18 +109,18 @@ private fun ConsentContent( onCloseClick: () -> Unit, onCloseFromErrorClick: (Throwable) -> Unit ) { - when { - state.consent.loading -> { + when (val result = state.consent) { + Result.Uninitialized, Result.Loading -> { ConsentLoadingContent() } - state.consent.error != null -> { - UnclassifiedErrorContent { onCloseFromErrorClick(state.consent.error) } + is Result.Error -> { + UnclassifiedErrorContent { onCloseFromErrorClick(result.throwable) } } - state.consent() != null -> { + is Result.Success -> { LoadedContent( - payload = state.consent()!!, + payload = result.value, bottomSheetState = bottomSheetState, acceptConsent = state.acceptConsent, bottomSheetMode = state.currentBottomSheet, @@ -297,7 +297,7 @@ private fun ConsentFooter( ) Spacer(modifier = Modifier.size(16.dp)) FinancialConnectionsButton( - loading = acceptConsent.loading, + loading = acceptConsent is Result.Loading, onClick = onContinueClick, modifier = Modifier .semantics { testTagsAsResourceId = true } diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentState.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentState.kt index bb232b56740..ea061b56347 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentState.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentState.kt @@ -5,10 +5,10 @@ import com.stripe.android.financialconnections.model.ConsentPane import com.stripe.android.financialconnections.model.FinancialConnectionsSessionManifest internal data class ConsentState( - val consent: Result = Result(), + val consent: Result = Result.Uninitialized, val merchantLogos: List = emptyList(), val currentBottomSheet: BottomSheetContent = BottomSheetContent.DATA, - val acceptConsent: Result = Result(), + val acceptConsent: Result = Result.Uninitialized, val viewEffect: ViewEffect? = null ) { From 420fbe74add5904ab8b333bb1034c96606ddda34 Mon Sep 17 00:00:00 2001 From: "Carlos M." Date: Tue, 19 Mar 2024 15:29:20 -0700 Subject: [PATCH 11/28] Removes mavericks from institution picker. --- .../core/PaneViewModel.kt | 8 +- .../features/consent/ConsentScreen.kt | 2 +- ...stitutionPickerPreviewParameterProvider.kt | 18 +-- .../InstitutionPickerScreen.kt | 29 ++--- .../InstitutionPickerViewModel.kt | 123 ++++++++---------- .../utils/MavericksExtensions.kt | 8 ++ .../{LogErrorTest.kt => LogFailTest.kt} | 2 +- ...appingTest.kt => StripeFailMappingTest.kt} | 2 +- ...eporterTest.kt => RealFailReporterTest.kt} | 2 +- ...essageTest.kt => StripeFailMessageTest.kt} | 2 +- ...otTest.kt => FailMessageScreenshotTest.kt} | 2 +- 11 files changed, 99 insertions(+), 99 deletions(-) rename financial-connections/src/test/java/com/stripe/android/financialconnections/analytics/{LogErrorTest.kt => LogFailTest.kt} (99%) rename payments-core/src/test/java/com/stripe/android/{StripeErrorMappingTest.kt => StripeFailMappingTest.kt} (98%) rename payments-core/src/test/java/com/stripe/android/payments/core/analytics/{RealErrorReporterTest.kt => RealFailReporterTest.kt} (98%) rename paymentsheet/src/test/java/com/stripe/android/common/exception/{StripeErrorMessageTest.kt => StripeFailMessageTest.kt} (98%) rename paymentsheet/src/test/java/com/stripe/android/paymentsheet/ui/{ErrorMessageScreenshotTest.kt => FailMessageScreenshotTest.kt} (94%) diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/core/PaneViewModel.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/core/PaneViewModel.kt index d8ce5180c64..9c848b4acff 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/core/PaneViewModel.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/core/PaneViewModel.kt @@ -28,7 +28,7 @@ internal abstract class PaneViewModel( onSuccess(data) }, onFailure = { throwable -> - stateFlow.update { state -> state.reducer(Result.Error(throwable)) } + stateFlow.update { state -> state.reducer(Result.Fail(throwable)) } onFail(throwable) } ) @@ -41,8 +41,10 @@ internal sealed class Result( ) { data object Uninitialized : Result(value = null) data object Loading : Result(value = null) - data class Success(val value: T) : Result(value = value) - data class Error(val throwable: Throwable) : Result(value = null) + data class Success(val value: T) : Result(value = value) { + override operator fun invoke(): T = value + } + data class Fail(val throwable: Throwable) : Result(value = null) open operator fun invoke(): T? = value } diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentScreen.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentScreen.kt index 7b6e277bade..3624246e4f8 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentScreen.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentScreen.kt @@ -114,7 +114,7 @@ private fun ConsentContent( ConsentLoadingContent() } - is Result.Error -> { + is Result.Fail -> { UnclassifiedErrorContent { onCloseFromErrorClick(result.throwable) } } diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/institutionpicker/InstitutionPickerPreviewParameterProvider.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/institutionpicker/InstitutionPickerPreviewParameterProvider.kt index 04cbaa75798..d29575f1b2c 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/institutionpicker/InstitutionPickerPreviewParameterProvider.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/institutionpicker/InstitutionPickerPreviewParameterProvider.kt @@ -1,10 +1,10 @@ package com.stripe.android.financialconnections.features.institutionpicker 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.Result.Fail +import com.stripe.android.financialconnections.core.Result.Loading +import com.stripe.android.financialconnections.core.Result.Success +import com.stripe.android.financialconnections.core.Result.Uninitialized import com.stripe.android.financialconnections.model.FinancialConnectionsInstitution import com.stripe.android.financialconnections.model.InstitutionResponse @@ -28,7 +28,7 @@ internal class InstitutionPickerPreviewParameterProvider : private fun initialLoading() = InstitutionPreviewState( state = InstitutionPickerState( previewText = null, - payload = Loading(), + payload = Loading, searchInstitutions = Uninitialized, ), initialScroll = 0 @@ -47,7 +47,7 @@ internal class InstitutionPickerPreviewParameterProvider : state = InstitutionPickerState( previewText = "Some query", payload = Success(payload()), - searchInstitutions = Loading(), + searchInstitutions = Loading, ), initialScroll = 0 ) @@ -102,7 +102,7 @@ internal class InstitutionPickerPreviewParameterProvider : state = InstitutionPickerState( previewText = "Some query", payload = Success(payload(manualEntry = true)), - searchInstitutions = Fail(java.lang.Exception("Something went wrong")), + searchInstitutions = Fail(Exception("Something went wrong")), ), initialScroll = 0 ) @@ -111,7 +111,7 @@ internal class InstitutionPickerPreviewParameterProvider : state = InstitutionPickerState( previewText = "Some query", payload = Success(payload(manualEntry = false)), - searchInstitutions = Fail(java.lang.Exception("Something went wrong")), + searchInstitutions = Fail(Exception("Something went wrong")), ), initialScroll = 0 ) @@ -122,7 +122,7 @@ internal class InstitutionPickerPreviewParameterProvider : payload = Success(payload()), searchInstitutions = Success(institutionResponse(FEW_INSTITUTIONS)), selectedInstitutionId = "2", - createSessionForInstitution = Loading(), + createSessionForInstitution = Loading, ), initialScroll = 0 ) diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/institutionpicker/InstitutionPickerScreen.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/institutionpicker/InstitutionPickerScreen.kt index ac6f7e816e1..5fc02f8f8c2 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/institutionpicker/InstitutionPickerScreen.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/institutionpicker/InstitutionPickerScreen.kt @@ -32,6 +32,7 @@ import androidx.compose.material.icons.filled.Clear import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider 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 @@ -58,14 +59,13 @@ import androidx.compose.ui.text.style.TextOverflow 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.Result +import com.stripe.android.financialconnections.core.Result.Fail +import com.stripe.android.financialconnections.core.Result.Loading +import com.stripe.android.financialconnections.core.Result.Success +import com.stripe.android.financialconnections.core.Result.Uninitialized +import com.stripe.android.financialconnections.core.rememberPaneViewModel import com.stripe.android.financialconnections.features.common.FullScreenGenericLoading import com.stripe.android.financialconnections.features.common.InstitutionIcon import com.stripe.android.financialconnections.features.common.LoadingShimmerEffect @@ -91,9 +91,9 @@ import kotlinx.coroutines.launch @Composable internal fun InstitutionPickerScreen() { - val viewModel: InstitutionPickerViewModel = mavericksViewModel() + val viewModel: InstitutionPickerViewModel = rememberPaneViewModel { InstitutionPickerViewModel.factory(it) } val parentViewModel = parentViewModel() - val state: InstitutionPickerState by viewModel.collectAsState() + val state: InstitutionPickerState by viewModel.stateFlow.collectAsState() val listState = rememberLazyListState() InstitutionPickerContent( @@ -114,8 +114,8 @@ internal fun InstitutionPickerScreen() { @Composable private fun InstitutionPickerContent( listState: LazyListState, - payload: Async, - institutions: Async, + payload: Result, + institutions: Result, previewText: String?, selectedInstitutionId: String?, onQueryChanged: (String) -> Unit, @@ -135,7 +135,6 @@ private fun InstitutionPickerContent( is Uninitialized, is Loading, is Fail -> FullScreenGenericLoading() - is Success -> LoadedContent( listState = listState, previewText = previewText, @@ -143,7 +142,7 @@ private fun InstitutionPickerContent( onQueryChanged = onQueryChanged, institutions = institutions, onInstitutionSelected = onInstitutionSelected, - payload = payload(), + payload = payload.value, onManualEntryClick = onManualEntryClick, onScrollChanged = onScrollChanged ) @@ -158,7 +157,7 @@ private fun LoadedContent( previewText: String?, selectedInstitutionId: String?, onQueryChanged: (String) -> Unit, - institutions: Async, + institutions: Result, onInstitutionSelected: (FinancialConnectionsInstitution, Boolean) -> Unit, payload: Payload, onManualEntryClick: () -> Unit, @@ -226,7 +225,7 @@ private fun LazyListScope.searchResults( payload: Payload, selectedInstitutionId: String?, onInstitutionSelected: (FinancialConnectionsInstitution, Boolean) -> Unit, - institutions: Async, + institutions: Result, onManualEntryClick: () -> Unit, onSearchMoreClick: () -> Unit ) { diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/institutionpicker/InstitutionPickerViewModel.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/institutionpicker/InstitutionPickerViewModel.kt index 36ab15ff383..c798087fdb8 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/institutionpicker/InstitutionPickerViewModel.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/institutionpicker/InstitutionPickerViewModel.kt @@ -1,12 +1,9 @@ package com.stripe.android.financialconnections.features.institutionpicker -import com.airbnb.mvrx.Async -import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.MavericksState -import com.airbnb.mvrx.MavericksViewModel -import com.airbnb.mvrx.MavericksViewModelFactory -import com.airbnb.mvrx.Uninitialized -import com.airbnb.mvrx.ViewModelContext +import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.viewModelScope +import androidx.lifecycle.viewmodel.initializer +import androidx.lifecycle.viewmodel.viewModelFactory import com.stripe.android.core.Logger import com.stripe.android.financialconnections.FinancialConnections import com.stripe.android.financialconnections.FinancialConnectionsSheet @@ -19,6 +16,10 @@ import com.stripe.android.financialconnections.analytics.FinancialConnectionsAna import com.stripe.android.financialconnections.analytics.FinancialConnectionsEvent.Metadata import com.stripe.android.financialconnections.analytics.FinancialConnectionsEvent.Name import com.stripe.android.financialconnections.analytics.logError +import com.stripe.android.financialconnections.core.PaneViewModel +import com.stripe.android.financialconnections.core.Result +import com.stripe.android.financialconnections.core.Result.Loading +import com.stripe.android.financialconnections.core.Result.Uninitialized import com.stripe.android.financialconnections.domain.FeaturedInstitutions import com.stripe.android.financialconnections.domain.GetOrFetchSync import com.stripe.android.financialconnections.domain.HandleError @@ -34,7 +35,7 @@ import com.stripe.android.financialconnections.navigation.Destination.ManualEntr import com.stripe.android.financialconnections.navigation.Destination.PartnerAuth import com.stripe.android.financialconnections.navigation.Destination.PartnerAuthDrawer import com.stripe.android.financialconnections.navigation.NavigationManager -import com.stripe.android.financialconnections.ui.FinancialConnectionsSheetNativeActivity +import com.stripe.android.financialconnections.presentation.FinancialConnectionsSheetNativeViewModel import com.stripe.android.financialconnections.utils.ConflatedJob import com.stripe.android.financialconnections.utils.isCancellationError import com.stripe.android.financialconnections.utils.measureTimeMillis @@ -54,12 +55,11 @@ internal class InstitutionPickerViewModel @Inject constructor( private val updateLocalManifest: UpdateLocalManifest, private val logger: Logger, initialState: InstitutionPickerState -) : MavericksViewModel(initialState) { +) : PaneViewModel(initialState) { private var searchJob = ConflatedJob() init { - logErrors() suspend { val manifest = getOrFetchSync().manifest val (featuredInstitutions: InstitutionResponse, duration: Long) = runCatching { @@ -87,12 +87,8 @@ internal class InstitutionPickerViewModel @Inject constructor( featuredInstitutions = featuredInstitutions, searchDisabled = manifest.institutionSearchDisabled, ) - }.execute { copy(payload = it) } - } - - private fun logErrors() { - onAsync( - InstitutionPickerState::payload, + }.execute( + reducer = { result -> copy(payload = result) }, onSuccess = { payload -> eventTracker.track(PaneLoaded(PANE)) eventTracker.track( @@ -112,28 +108,6 @@ internal class InstitutionPickerViewModel @Inject constructor( ) } ) - onAsync( - InstitutionPickerState::searchInstitutions, - onFail = { - handleError( - extraMessage = "Error searching institutions", - error = it, - pane = PANE, - displayErrorScreen = false // don't show error screen for search errors. - ) - } - ) - onAsync( - InstitutionPickerState::createSessionForInstitution, - onFail = { - handleError( - extraMessage = "Error selecting or creating session for institution", - error = it, - pane = PANE, - displayErrorScreen = true - ) - } - ) } fun onQueryChanged(query: String) { @@ -162,9 +136,17 @@ internal class InstitutionPickerViewModel @Inject constructor( showManualEntry = false ) } - }.execute { - copy(searchInstitutions = if (it.isCancellationError()) Loading() else it) - } + }.execute( + reducer = { copy(searchInstitutions = if (it.isCancellationError()) Loading else it) }, + onFail = { + handleError( + extraMessage = "Error searching institutions", + error = it, + pane = PANE, + displayErrorScreen = false // don't show error screen for search errors. + ) + } + ) } fun onInstitutionSelected(institution: FinancialConnectionsInstitution, fromFeatured: Boolean) { @@ -190,12 +172,22 @@ internal class InstitutionPickerViewModel @Inject constructor( // navigate to next step val authSession = postAuthorizationSession(institution, getOrFetchSync()) navigateToPartnerAuth(authSession) - }.execute { async -> - copy( - selectedInstitutionId = institution.id.takeIf { async is Loading }, - createSessionForInstitution = async - ) - } + }.execute( + reducer = { result -> + copy( + selectedInstitutionId = institution.id.takeIf { result is Loading }, + createSessionForInstitution = result + ) + }, + onFail = { + handleError( + extraMessage = "Error selecting or creating session for institution", + error = it, + pane = PANE, + displayErrorScreen = true + ) + } + ) } /** @@ -226,7 +218,7 @@ internal class InstitutionPickerViewModel @Inject constructor( eventTracker.track( SearchScroll( pane = PANE, - institutionIds = awaitState().searchInstitutions() + institutionIds = stateFlow.value.searchInstitutions() ?.data ?.map { it.id } ?.toSet() ?: emptySet(), @@ -235,23 +227,22 @@ internal class InstitutionPickerViewModel @Inject constructor( } } - companion object : - MavericksViewModelFactory { + companion object { + fun factory(parentViewModel: FinancialConnectionsSheetNativeViewModel): ViewModelProvider.Factory = + viewModelFactory { + initializer { + parentViewModel + .activityRetainedComponent + .institutionPickerBuilder + .initialState(InstitutionPickerState()) + .build() + .viewModel + } + } private const val SEARCH_DEBOUNCE_MS = 300L private val PANE = Pane.INSTITUTION_PICKER - override fun create( - viewModelContext: ViewModelContext, - state: InstitutionPickerState - ): InstitutionPickerViewModel { - return viewModelContext.activity() - .viewModel - .activityRetainedComponent - .institutionPickerBuilder - .initialState(state) - .build() - .viewModel - } + } } @@ -259,10 +250,10 @@ internal data class InstitutionPickerState( // This is just used to provide a text in Compose previews val previewText: String? = null, val selectedInstitutionId: String? = null, - val payload: Async = Uninitialized, - val searchInstitutions: Async = Uninitialized, - val createSessionForInstitution: Async = Uninitialized -) : MavericksState { + val payload: Result = Uninitialized, + val searchInstitutions: Result = Uninitialized, + val createSessionForInstitution: Result = Uninitialized +) { data class Payload( val featuredInstitutions: InstitutionResponse, 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 b70d767e08c..a27e8835925 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 @@ -12,6 +12,7 @@ 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.Result import kotlinx.coroutines.CancellationException import kotlin.properties.ReadOnlyProperty import kotlin.reflect.KClass @@ -69,3 +70,10 @@ internal fun Async<*>.isCancellationError(): Boolean = when { error is StripeException && error.cause is CancellationException -> true else -> false } + +internal fun Result<*>.isCancellationError(): Boolean = when { + this !is Result.Fail -> false + throwable is CancellationException -> true + throwable is StripeException && throwable.cause is CancellationException -> true + else -> false +} diff --git a/financial-connections/src/test/java/com/stripe/android/financialconnections/analytics/LogErrorTest.kt b/financial-connections/src/test/java/com/stripe/android/financialconnections/analytics/LogFailTest.kt similarity index 99% rename from financial-connections/src/test/java/com/stripe/android/financialconnections/analytics/LogErrorTest.kt rename to financial-connections/src/test/java/com/stripe/android/financialconnections/analytics/LogFailTest.kt index a22fcfb56d8..8b0058d8b8e 100644 --- a/financial-connections/src/test/java/com/stripe/android/financialconnections/analytics/LogErrorTest.kt +++ b/financial-connections/src/test/java/com/stripe/android/financialconnections/analytics/LogFailTest.kt @@ -21,7 +21,7 @@ import org.mockito.kotlin.verify import kotlin.test.Test @OptIn(ExperimentalCoroutinesApi::class) -class LogErrorTest { +class LogFailTest { private val liveEvents = mutableListOf() diff --git a/payments-core/src/test/java/com/stripe/android/StripeErrorMappingTest.kt b/payments-core/src/test/java/com/stripe/android/StripeFailMappingTest.kt similarity index 98% rename from payments-core/src/test/java/com/stripe/android/StripeErrorMappingTest.kt rename to payments-core/src/test/java/com/stripe/android/StripeFailMappingTest.kt index 4395930cc13..7f5f760324f 100644 --- a/payments-core/src/test/java/com/stripe/android/StripeErrorMappingTest.kt +++ b/payments-core/src/test/java/com/stripe/android/StripeFailMappingTest.kt @@ -11,7 +11,7 @@ import org.robolectric.RobolectricTestRunner import java.util.Locale @RunWith(RobolectricTestRunner::class) -class StripeErrorMappingTest { +class StripeFailMappingTest { private val context: Context = ApplicationProvider.getApplicationContext() diff --git a/payments-core/src/test/java/com/stripe/android/payments/core/analytics/RealErrorReporterTest.kt b/payments-core/src/test/java/com/stripe/android/payments/core/analytics/RealFailReporterTest.kt similarity index 98% rename from payments-core/src/test/java/com/stripe/android/payments/core/analytics/RealErrorReporterTest.kt rename to payments-core/src/test/java/com/stripe/android/payments/core/analytics/RealFailReporterTest.kt index 4c591c031c0..cf1dd555f9d 100644 --- a/payments-core/src/test/java/com/stripe/android/payments/core/analytics/RealErrorReporterTest.kt +++ b/payments-core/src/test/java/com/stripe/android/payments/core/analytics/RealFailReporterTest.kt @@ -14,7 +14,7 @@ import org.junit.runner.RunWith import org.robolectric.RobolectricTestRunner @RunWith(RobolectricTestRunner::class) -class RealErrorReporterTest { +class RealFailReporterTest { val analyticsRequestExecutor = FakeAnalyticsRequestExecutor() private val application = ApplicationProvider.getApplicationContext() private val analyticsRequestFactory = AnalyticsRequestFactory( diff --git a/paymentsheet/src/test/java/com/stripe/android/common/exception/StripeErrorMessageTest.kt b/paymentsheet/src/test/java/com/stripe/android/common/exception/StripeFailMessageTest.kt similarity index 98% rename from paymentsheet/src/test/java/com/stripe/android/common/exception/StripeErrorMessageTest.kt rename to paymentsheet/src/test/java/com/stripe/android/common/exception/StripeFailMessageTest.kt index 36afa27f616..0d9dcdba878 100644 --- a/paymentsheet/src/test/java/com/stripe/android/common/exception/StripeErrorMessageTest.kt +++ b/paymentsheet/src/test/java/com/stripe/android/common/exception/StripeFailMessageTest.kt @@ -18,7 +18,7 @@ import org.robolectric.RobolectricTestRunner import java.io.IOException @RunWith(RobolectricTestRunner::class) -internal class StripeErrorMessageTest { +internal class StripeFailMessageTest { private val application = ApplicationProvider.getApplicationContext() diff --git a/paymentsheet/src/test/java/com/stripe/android/paymentsheet/ui/ErrorMessageScreenshotTest.kt b/paymentsheet/src/test/java/com/stripe/android/paymentsheet/ui/FailMessageScreenshotTest.kt similarity index 94% rename from paymentsheet/src/test/java/com/stripe/android/paymentsheet/ui/ErrorMessageScreenshotTest.kt rename to paymentsheet/src/test/java/com/stripe/android/paymentsheet/ui/FailMessageScreenshotTest.kt index fe19a3c8a0a..0ab4f76dc3c 100644 --- a/paymentsheet/src/test/java/com/stripe/android/paymentsheet/ui/ErrorMessageScreenshotTest.kt +++ b/paymentsheet/src/test/java/com/stripe/android/paymentsheet/ui/FailMessageScreenshotTest.kt @@ -7,7 +7,7 @@ import com.stripe.android.utils.screenshots.SystemAppearance import org.junit.Rule import org.junit.Test -class ErrorMessageScreenshotTest { +class FailMessageScreenshotTest { @get:Rule val paparazziRule = PaparazziRule( From bddfb55e286f7f8a57cd3d0961ab8a192483a52c Mon Sep 17 00:00:00 2001 From: "Carlos M." Date: Tue, 19 Mar 2024 15:32:54 -0700 Subject: [PATCH 12/28] Reverts rename. --- .../financialconnections/core/PaneViewModel.kt | 4 ++-- .../features/consent/ConsentScreen.kt | 12 ++++++++---- .../InstitutionPickerPreviewParameterProvider.kt | 6 +++--- .../institutionpicker/InstitutionPickerScreen.kt | 6 +++--- .../utils/MavericksExtensions.kt | 2 +- .../analytics/{LogFailTest.kt => LogErrorTest.kt} | 2 +- ...eFailMappingTest.kt => StripeErrorMappingTest.kt} | 2 +- ...lFailReporterTest.kt => RealErrorReporterTest.kt} | 2 +- ...eFailMessageTest.kt => StripeErrorMessageTest.kt} | 2 +- ...reenshotTest.kt => ErrorMessageScreenshotTest.kt} | 2 +- 10 files changed, 22 insertions(+), 18 deletions(-) rename financial-connections/src/test/java/com/stripe/android/financialconnections/analytics/{LogFailTest.kt => LogErrorTest.kt} (99%) rename payments-core/src/test/java/com/stripe/android/{StripeFailMappingTest.kt => StripeErrorMappingTest.kt} (98%) rename payments-core/src/test/java/com/stripe/android/payments/core/analytics/{RealFailReporterTest.kt => RealErrorReporterTest.kt} (98%) rename paymentsheet/src/test/java/com/stripe/android/common/exception/{StripeFailMessageTest.kt => StripeErrorMessageTest.kt} (98%) rename paymentsheet/src/test/java/com/stripe/android/paymentsheet/ui/{FailMessageScreenshotTest.kt => ErrorMessageScreenshotTest.kt} (94%) diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/core/PaneViewModel.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/core/PaneViewModel.kt index 9c848b4acff..7d16edac55d 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/core/PaneViewModel.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/core/PaneViewModel.kt @@ -28,7 +28,7 @@ internal abstract class PaneViewModel( onSuccess(data) }, onFailure = { throwable -> - stateFlow.update { state -> state.reducer(Result.Fail(throwable)) } + stateFlow.update { state -> state.reducer(Result.Error(throwable)) } onFail(throwable) } ) @@ -44,7 +44,7 @@ internal sealed class Result( data class Success(val value: T) : Result(value = value) { override operator fun invoke(): T = value } - data class Fail(val throwable: Throwable) : Result(value = null) + data class Error(val throwable: Throwable) : Result(value = null) open operator fun invoke(): T? = value } diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentScreen.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentScreen.kt index 3624246e4f8..a6e232f18aa 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentScreen.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentScreen.kt @@ -32,6 +32,10 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp import com.stripe.android.financialconnections.core.Result +import com.stripe.android.financialconnections.core.Result.Error +import com.stripe.android.financialconnections.core.Result.Loading +import com.stripe.android.financialconnections.core.Result.Success +import com.stripe.android.financialconnections.core.Result.Uninitialized import com.stripe.android.financialconnections.core.rememberPaneViewModel import com.stripe.android.financialconnections.features.common.DataAccessBottomSheetContent import com.stripe.android.financialconnections.features.common.LegalDetailsBottomSheetContent @@ -110,15 +114,15 @@ private fun ConsentContent( onCloseFromErrorClick: (Throwable) -> Unit ) { when (val result = state.consent) { - Result.Uninitialized, Result.Loading -> { + Uninitialized, Loading -> { ConsentLoadingContent() } - is Result.Fail -> { + is Error -> { UnclassifiedErrorContent { onCloseFromErrorClick(result.throwable) } } - is Result.Success -> { + is Success -> { LoadedContent( payload = result.value, bottomSheetState = bottomSheetState, @@ -297,7 +301,7 @@ private fun ConsentFooter( ) Spacer(modifier = Modifier.size(16.dp)) FinancialConnectionsButton( - loading = acceptConsent is Result.Loading, + loading = acceptConsent is Loading, onClick = onContinueClick, modifier = Modifier .semantics { testTagsAsResourceId = true } diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/institutionpicker/InstitutionPickerPreviewParameterProvider.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/institutionpicker/InstitutionPickerPreviewParameterProvider.kt index d29575f1b2c..31043ba0a06 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/institutionpicker/InstitutionPickerPreviewParameterProvider.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/institutionpicker/InstitutionPickerPreviewParameterProvider.kt @@ -1,7 +1,7 @@ package com.stripe.android.financialconnections.features.institutionpicker import androidx.compose.ui.tooling.preview.PreviewParameterProvider -import com.stripe.android.financialconnections.core.Result.Fail +import com.stripe.android.financialconnections.core.Result.Error import com.stripe.android.financialconnections.core.Result.Loading import com.stripe.android.financialconnections.core.Result.Success import com.stripe.android.financialconnections.core.Result.Uninitialized @@ -102,7 +102,7 @@ internal class InstitutionPickerPreviewParameterProvider : state = InstitutionPickerState( previewText = "Some query", payload = Success(payload(manualEntry = true)), - searchInstitutions = Fail(Exception("Something went wrong")), + searchInstitutions = Error(Exception("Something went wrong")), ), initialScroll = 0 ) @@ -111,7 +111,7 @@ internal class InstitutionPickerPreviewParameterProvider : state = InstitutionPickerState( previewText = "Some query", payload = Success(payload(manualEntry = false)), - searchInstitutions = Fail(Exception("Something went wrong")), + searchInstitutions = Error(Exception("Something went wrong")), ), initialScroll = 0 ) diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/institutionpicker/InstitutionPickerScreen.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/institutionpicker/InstitutionPickerScreen.kt index 5fc02f8f8c2..8d66a5908de 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/institutionpicker/InstitutionPickerScreen.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/institutionpicker/InstitutionPickerScreen.kt @@ -61,7 +61,7 @@ import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp import com.stripe.android.financialconnections.R import com.stripe.android.financialconnections.core.Result -import com.stripe.android.financialconnections.core.Result.Fail +import com.stripe.android.financialconnections.core.Result.Error import com.stripe.android.financialconnections.core.Result.Loading import com.stripe.android.financialconnections.core.Result.Success import com.stripe.android.financialconnections.core.Result.Uninitialized @@ -134,7 +134,7 @@ private fun InstitutionPickerContent( when (payload) { is Uninitialized, is Loading, - is Fail -> FullScreenGenericLoading() + is Error -> FullScreenGenericLoading() is Success -> LoadedContent( listState = listState, previewText = previewText, @@ -257,7 +257,7 @@ private fun LazyListScope.searchResults( else -> when (institutions) { // Load failure: Display error message. - is Fail -> item { + is Error -> item { NoResultsTile( modifier = Modifier.padding(8.dp), showManualEntry = payload.featuredInstitutions.showManualEntry, 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 a27e8835925..124a9ac7983 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 @@ -72,7 +72,7 @@ internal fun Async<*>.isCancellationError(): Boolean = when { } internal fun Result<*>.isCancellationError(): Boolean = when { - this !is Result.Fail -> false + this !is Result.Error -> false throwable is CancellationException -> true throwable is StripeException && throwable.cause is CancellationException -> true else -> false diff --git a/financial-connections/src/test/java/com/stripe/android/financialconnections/analytics/LogFailTest.kt b/financial-connections/src/test/java/com/stripe/android/financialconnections/analytics/LogErrorTest.kt similarity index 99% rename from financial-connections/src/test/java/com/stripe/android/financialconnections/analytics/LogFailTest.kt rename to financial-connections/src/test/java/com/stripe/android/financialconnections/analytics/LogErrorTest.kt index 8b0058d8b8e..a22fcfb56d8 100644 --- a/financial-connections/src/test/java/com/stripe/android/financialconnections/analytics/LogFailTest.kt +++ b/financial-connections/src/test/java/com/stripe/android/financialconnections/analytics/LogErrorTest.kt @@ -21,7 +21,7 @@ import org.mockito.kotlin.verify import kotlin.test.Test @OptIn(ExperimentalCoroutinesApi::class) -class LogFailTest { +class LogErrorTest { private val liveEvents = mutableListOf() diff --git a/payments-core/src/test/java/com/stripe/android/StripeFailMappingTest.kt b/payments-core/src/test/java/com/stripe/android/StripeErrorMappingTest.kt similarity index 98% rename from payments-core/src/test/java/com/stripe/android/StripeFailMappingTest.kt rename to payments-core/src/test/java/com/stripe/android/StripeErrorMappingTest.kt index 7f5f760324f..4395930cc13 100644 --- a/payments-core/src/test/java/com/stripe/android/StripeFailMappingTest.kt +++ b/payments-core/src/test/java/com/stripe/android/StripeErrorMappingTest.kt @@ -11,7 +11,7 @@ import org.robolectric.RobolectricTestRunner import java.util.Locale @RunWith(RobolectricTestRunner::class) -class StripeFailMappingTest { +class StripeErrorMappingTest { private val context: Context = ApplicationProvider.getApplicationContext() diff --git a/payments-core/src/test/java/com/stripe/android/payments/core/analytics/RealFailReporterTest.kt b/payments-core/src/test/java/com/stripe/android/payments/core/analytics/RealErrorReporterTest.kt similarity index 98% rename from payments-core/src/test/java/com/stripe/android/payments/core/analytics/RealFailReporterTest.kt rename to payments-core/src/test/java/com/stripe/android/payments/core/analytics/RealErrorReporterTest.kt index cf1dd555f9d..4c591c031c0 100644 --- a/payments-core/src/test/java/com/stripe/android/payments/core/analytics/RealFailReporterTest.kt +++ b/payments-core/src/test/java/com/stripe/android/payments/core/analytics/RealErrorReporterTest.kt @@ -14,7 +14,7 @@ import org.junit.runner.RunWith import org.robolectric.RobolectricTestRunner @RunWith(RobolectricTestRunner::class) -class RealFailReporterTest { +class RealErrorReporterTest { val analyticsRequestExecutor = FakeAnalyticsRequestExecutor() private val application = ApplicationProvider.getApplicationContext() private val analyticsRequestFactory = AnalyticsRequestFactory( diff --git a/paymentsheet/src/test/java/com/stripe/android/common/exception/StripeFailMessageTest.kt b/paymentsheet/src/test/java/com/stripe/android/common/exception/StripeErrorMessageTest.kt similarity index 98% rename from paymentsheet/src/test/java/com/stripe/android/common/exception/StripeFailMessageTest.kt rename to paymentsheet/src/test/java/com/stripe/android/common/exception/StripeErrorMessageTest.kt index 0d9dcdba878..36afa27f616 100644 --- a/paymentsheet/src/test/java/com/stripe/android/common/exception/StripeFailMessageTest.kt +++ b/paymentsheet/src/test/java/com/stripe/android/common/exception/StripeErrorMessageTest.kt @@ -18,7 +18,7 @@ import org.robolectric.RobolectricTestRunner import java.io.IOException @RunWith(RobolectricTestRunner::class) -internal class StripeFailMessageTest { +internal class StripeErrorMessageTest { private val application = ApplicationProvider.getApplicationContext() diff --git a/paymentsheet/src/test/java/com/stripe/android/paymentsheet/ui/FailMessageScreenshotTest.kt b/paymentsheet/src/test/java/com/stripe/android/paymentsheet/ui/ErrorMessageScreenshotTest.kt similarity index 94% rename from paymentsheet/src/test/java/com/stripe/android/paymentsheet/ui/FailMessageScreenshotTest.kt rename to paymentsheet/src/test/java/com/stripe/android/paymentsheet/ui/ErrorMessageScreenshotTest.kt index 0ab4f76dc3c..fe19a3c8a0a 100644 --- a/paymentsheet/src/test/java/com/stripe/android/paymentsheet/ui/FailMessageScreenshotTest.kt +++ b/paymentsheet/src/test/java/com/stripe/android/paymentsheet/ui/ErrorMessageScreenshotTest.kt @@ -7,7 +7,7 @@ import com.stripe.android.utils.screenshots.SystemAppearance import org.junit.Rule import org.junit.Test -class FailMessageScreenshotTest { +class ErrorMessageScreenshotTest { @get:Rule val paparazziRule = PaparazziRule( From d0ce301d4d350ab8ccc55bb24e57cc32c6bb56f9 Mon Sep 17 00:00:00 2001 From: "Carlos M." Date: Tue, 19 Mar 2024 15:34:56 -0700 Subject: [PATCH 13/28] Updates baseline. --- financial-connections/detekt-baseline.xml | 4 ++-- .../features/institutionpicker/InstitutionPickerViewModel.kt | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/financial-connections/detekt-baseline.xml b/financial-connections/detekt-baseline.xml index b8b46c731ae..c7b6d72b239 100644 --- a/financial-connections/detekt-baseline.xml +++ b/financial-connections/detekt-baseline.xml @@ -5,7 +5,7 @@ ConstructorParameterNaming:FinancialConnectionsAuthorizationSession.kt$FinancialConnectionsAuthorizationSession$@SerialName(value = "is_oauth") private val _isOAuth: Boolean? = false ConstructorParameterNaming:PartnerAccountsList.kt$PartnerAccount$@SerialName(value = "allow_selection") private val _allowSelection: Boolean? = null LongMethod:AccountItem.kt$@Composable @Preview internal fun AccountItemPreview() - LongMethod:InstitutionPickerScreen.kt$private fun LazyListScope.searchResults( isInputEmpty: Boolean, payload: Payload, selectedInstitutionId: String?, onInstitutionSelected: (FinancialConnectionsInstitution, Boolean) -> Unit, institutions: Async<InstitutionResponse>, onManualEntryClick: () -> Unit, onSearchMoreClick: () -> Unit ) + LongMethod:InstitutionPickerScreen.kt$private fun LazyListScope.searchResults( isInputEmpty: Boolean, payload: Payload, selectedInstitutionId: String?, onInstitutionSelected: (FinancialConnectionsInstitution, Boolean) -> Unit, institutions: Result<InstitutionResponse>, onManualEntryClick: () -> Unit, onSearchMoreClick: () -> Unit ) LongMethod:LinkAccountPickerPreviewParameterProvider.kt$LinkAccountPickerPreviewParameterProvider$private fun partnerAccountList() MagicNumber:AccountPickerScreen.kt$3 MagicNumber:ConsentLogoHeader.kt$3 @@ -30,7 +30,7 @@ MaximumLineLength:com.stripe.android.financialconnections.presentation.FinancialConnectionsUrls.kt:41 MaximumLineLength:com.stripe.android.financialconnections.presentation.FinancialConnectionsUrls.kt:46 MaximumLineLength:com.stripe.android.financialconnections.presentation.FinancialConnectionsUrls.kt:9 - NestedBlockDepth:InstitutionPickerScreen.kt$private fun LazyListScope.searchResults( isInputEmpty: Boolean, payload: Payload, selectedInstitutionId: String?, onInstitutionSelected: (FinancialConnectionsInstitution, Boolean) -> Unit, institutions: Async<InstitutionResponse>, onManualEntryClick: () -> Unit, onSearchMoreClick: () -> Unit ) + NestedBlockDepth:InstitutionPickerScreen.kt$private fun LazyListScope.searchResults( isInputEmpty: Boolean, payload: Payload, selectedInstitutionId: String?, onInstitutionSelected: (FinancialConnectionsInstitution, Boolean) -> Unit, institutions: Result<InstitutionResponse>, onManualEntryClick: () -> Unit, onSearchMoreClick: () -> Unit ) SwallowedException:PollAttachPaymentAccount.kt$PollAttachPaymentAccount$e: StripeException SwallowedException:PollAuthorizationSessionAccounts.kt$PollAuthorizationSessionAccounts$e: StripeException SwallowedException:PostAuthorizationSession.kt$PostAuthorizationSession$e: StripeException diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/institutionpicker/InstitutionPickerViewModel.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/institutionpicker/InstitutionPickerViewModel.kt index c798087fdb8..26b905c9c61 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/institutionpicker/InstitutionPickerViewModel.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/institutionpicker/InstitutionPickerViewModel.kt @@ -242,7 +242,6 @@ internal class InstitutionPickerViewModel @Inject constructor( private const val SEARCH_DEBOUNCE_MS = 300L private val PANE = Pane.INSTITUTION_PICKER - } } From 32203df937384a2801abf61067b50d1aee717d74 Mon Sep 17 00:00:00 2001 From: "Carlos M." Date: Wed, 20 Mar 2024 11:36:41 -0700 Subject: [PATCH 14/28] Adds setState and persists state. --- financial-connections/detekt-baseline.xml | 2 +- .../financialconnections/core/ComposeUtils.kt | 40 ++++++- ...el.kt => FinancialConnectionsViewModel.kt} | 12 +- ...inancialConnectionsSheetNativeComponent.kt | 6 + .../features/common/SharedPartnerAuth.kt | 5 +- .../features/consent/ConsentScreen.kt | 4 +- .../features/consent/ConsentViewModel.kt | 24 ++-- .../InstitutionPickerScreen.kt | 4 +- .../InstitutionPickerViewModel.kt | 11 +- ...inancialConnectionsSheetNativeViewModel.kt | 103 ++++++++++++------ ...FinancialConnectionsSheetNativeActivity.kt | 67 ++++++------ 11 files changed, 177 insertions(+), 101 deletions(-) rename financial-connections/src/main/java/com/stripe/android/financialconnections/core/{PaneViewModel.kt => FinancialConnectionsViewModel.kt} (80%) diff --git a/financial-connections/detekt-baseline.xml b/financial-connections/detekt-baseline.xml index c7b6d72b239..e603a24b609 100644 --- a/financial-connections/detekt-baseline.xml +++ b/financial-connections/detekt-baseline.xml @@ -36,6 +36,6 @@ SwallowedException:PostAuthorizationSession.kt$PostAuthorizationSession$e: StripeException TooManyFunctions:FinancialConnectionsManifestRepository.kt$FinancialConnectionsManifestRepository TooManyFunctions:FinancialConnectionsManifestRepository.kt$FinancialConnectionsManifestRepositoryImpl : FinancialConnectionsManifestRepository - TooManyFunctions:FinancialConnectionsSheetNativeViewModel.kt$FinancialConnectionsSheetNativeViewModel : MavericksViewModel + TooManyFunctions:FinancialConnectionsSheetNativeViewModel.kt$FinancialConnectionsSheetNativeViewModel : FinancialConnectionsViewModel diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/core/ComposeUtils.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/core/ComposeUtils.kt index f1592e4b9db..57718fab463 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/core/ComposeUtils.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/core/ComposeUtils.kt @@ -1,21 +1,34 @@ package com.stripe.android.financialconnections.core +import android.annotation.SuppressLint import android.content.Context import android.content.ContextWrapper import androidx.activity.ComponentActivity import androidx.compose.runtime.Composable +import androidx.compose.runtime.State +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.remember import androidx.compose.ui.platform.LocalContext import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.viewmodel.compose.viewModel -import com.stripe.android.financialconnections.presentation.FinancialConnectionsSheetNativeViewModel +import com.stripe.android.financialconnections.di.FinancialConnectionsSheetNativeComponent import com.stripe.android.financialconnections.ui.FinancialConnectionsSheetNativeActivity +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.map +import kotlin.reflect.KProperty1 +/** + * Retrieves or builds a ViewModel instance, providing the [FinancialConnectionsSheetNativeComponent] (activity + * retained component) to the factory to facilitate its creation via dependency injection. + */ @Composable -internal inline fun , S> rememberPaneViewModel( - factory: (FinancialConnectionsSheetNativeViewModel) -> ViewModelProvider.Factory -): T { - val parentActivity = extractActivityFromContext(LocalContext.current) as FinancialConnectionsSheetNativeActivity - return viewModel(factory = factory(parentActivity.viewModel)) +internal inline fun , S> paneViewModel( + factory: (FinancialConnectionsSheetNativeComponent) -> ViewModelProvider.Factory +): T { return viewModel(factory = factory(parentActivity().viewModel.activityRetainedComponent)) } + +@Composable +internal fun parentActivity(): FinancialConnectionsSheetNativeActivity { + return extractActivityFromContext(LocalContext.current) as FinancialConnectionsSheetNativeActivity } private fun extractActivityFromContext(context: Context): ComponentActivity? { @@ -32,3 +45,18 @@ private fun extractActivityFromContext(context: Context): ComponentActivity? { } return null } + +/** + * Creates a Compose State variable that will only update when the value of this property changes. + * Prefer this to subscribing to entire state classes which will trigger a recomposition whenever + * any state variable changes. + * + * If you find yourself subscribing to many state properties in a single composable, + * consider breaking it up into smaller ones. + */ +@SuppressLint("StateFlowValueCalledInComposition") +@Composable +fun , S, A> VM.collectAsState(prop1: KProperty1): State { + val mappedFlow = remember(prop1) { stateFlow.map { prop1.get(it) }.distinctUntilChanged() } + return mappedFlow.collectAsState(initial = prop1.get(stateFlow.value)) +} diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/core/PaneViewModel.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/core/FinancialConnectionsViewModel.kt similarity index 80% rename from financial-connections/src/main/java/com/stripe/android/financialconnections/core/PaneViewModel.kt rename to financial-connections/src/main/java/com/stripe/android/financialconnections/core/FinancialConnectionsViewModel.kt index 7d16edac55d..9e5fd28eca4 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/core/PaneViewModel.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/core/FinancialConnectionsViewModel.kt @@ -7,7 +7,7 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch -internal abstract class PaneViewModel( +internal abstract class FinancialConnectionsViewModel( initialState: S ) : ViewModel() { @@ -19,21 +19,25 @@ internal abstract class PaneViewModel( onFail: (Throwable) -> Unit = {} ): Job { return viewModelScope.launch { - stateFlow.update { state -> state.reducer(Result.Loading) } + setState { reducer(Result.Loading) } val result = kotlin.runCatching { this@execute() } // update state. result.fold( onSuccess = { data -> - stateFlow.update { state -> state.reducer(Result.Success(data)) } + setState { reducer(Result.Success(data)) } onSuccess(data) }, onFailure = { throwable -> - stateFlow.update { state -> state.reducer(Result.Error(throwable)) } + setState { reducer(Result.Error(throwable)) } onFail(throwable) } ) } } + + protected fun setState(reducer: S.() -> S) { + stateFlow.update { state -> state.reducer() } + } } internal sealed class Result( diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/di/FinancialConnectionsSheetNativeComponent.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/di/FinancialConnectionsSheetNativeComponent.kt index a4292f0278b..1bc155e6d70 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/di/FinancialConnectionsSheetNativeComponent.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/di/FinancialConnectionsSheetNativeComponent.kt @@ -1,6 +1,7 @@ package com.stripe.android.financialconnections.di import android.app.Application +import androidx.lifecycle.SavedStateHandle import com.stripe.android.core.injection.CoreCommonModule import com.stripe.android.core.injection.CoroutineContextModule import com.stripe.android.financialconnections.FinancialConnectionsSheet @@ -73,6 +74,11 @@ internal interface FinancialConnectionsSheetNativeComponent { @Named(INITIAL_SYNC_RESPONSE) initialSyncResponse: SynchronizeSessionResponse? ): Builder + @BindsInstance + fun savedStateHandle( + savedStateHandle: SavedStateHandle + ): Builder + @BindsInstance fun application(application: Application): Builder diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/common/SharedPartnerAuth.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/common/SharedPartnerAuth.kt index 203e0b14371..f4515fd247f 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/common/SharedPartnerAuth.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/common/SharedPartnerAuth.kt @@ -46,8 +46,8 @@ 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.stripe.android.financialconnections.R +import com.stripe.android.financialconnections.core.collectAsState import com.stripe.android.financialconnections.features.partnerauth.PartnerAuthPreviewParameterProvider import com.stripe.android.financialconnections.features.partnerauth.SharedPartnerAuthState import com.stripe.android.financialconnections.features.partnerauth.SharedPartnerAuthState.AuthenticationStatus @@ -55,6 +55,7 @@ import com.stripe.android.financialconnections.features.partnerauth.SharedPartne import com.stripe.android.financialconnections.features.partnerauth.SharedPartnerAuthState.ViewEffect import com.stripe.android.financialconnections.model.Entry import com.stripe.android.financialconnections.model.OauthPrepane +import com.stripe.android.financialconnections.presentation.FinancialConnectionsSheetNativeState import com.stripe.android.financialconnections.presentation.WebAuthFlowState import com.stripe.android.financialconnections.presentation.parentViewModel import com.stripe.android.financialconnections.ui.FinancialConnectionsPreview @@ -83,7 +84,7 @@ internal fun SharedPartnerAuth( ) { val viewModel = parentViewModel() - val webAuthFlow = viewModel.collectAsState { it.webAuthFlow } + val webAuthFlow = viewModel.collectAsState(FinancialConnectionsSheetNativeState::webAuthFlow) val uriHandler = LocalUriHandler.current val bottomSheetState = rememberModalBottomSheetState( diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentScreen.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentScreen.kt index a6e232f18aa..ed558b8c029 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentScreen.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentScreen.kt @@ -36,7 +36,7 @@ import com.stripe.android.financialconnections.core.Result.Error import com.stripe.android.financialconnections.core.Result.Loading import com.stripe.android.financialconnections.core.Result.Success import com.stripe.android.financialconnections.core.Result.Uninitialized -import com.stripe.android.financialconnections.core.rememberPaneViewModel +import com.stripe.android.financialconnections.core.paneViewModel import com.stripe.android.financialconnections.features.common.DataAccessBottomSheetContent import com.stripe.android.financialconnections.features.common.LegalDetailsBottomSheetContent import com.stripe.android.financialconnections.features.common.ListItem @@ -67,7 +67,7 @@ import kotlinx.coroutines.launch @ExperimentalMaterialApi @Composable internal fun ConsentScreen() { - val viewModel: ConsentViewModel = rememberPaneViewModel { ConsentViewModel.factory(it) } + val viewModel: ConsentViewModel = paneViewModel { ConsentViewModel.factory(it) } val parentViewModel = parentViewModel() val state = viewModel.stateFlow.collectAsState() diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentViewModel.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentViewModel.kt index 8f3ada8db13..9867a03357d 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentViewModel.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentViewModel.kt @@ -11,7 +11,8 @@ 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.PaneViewModel +import com.stripe.android.financialconnections.core.FinancialConnectionsViewModel +import com.stripe.android.financialconnections.di.FinancialConnectionsSheetNativeComponent import com.stripe.android.financialconnections.domain.AcceptConsent import com.stripe.android.financialconnections.domain.GetOrFetchSync import com.stripe.android.financialconnections.features.consent.ConsentState.BottomSheetContent @@ -21,12 +22,10 @@ import com.stripe.android.financialconnections.model.FinancialConnectionsSession 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.presentation.FinancialConnectionsSheetNativeViewModel import com.stripe.android.financialconnections.ui.HandleClickableUrl import com.stripe.android.financialconnections.utils.Experiment.CONNECTIONS_CONSENT_COMBINED_LOGO import com.stripe.android.financialconnections.utils.experimentAssignment import com.stripe.android.financialconnections.utils.trackExposure -import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import java.util.Date import javax.inject.Inject @@ -39,7 +38,7 @@ internal class ConsentViewModel @Inject constructor( private val eventTracker: FinancialConnectionsAnalyticsTracker, private val handleClickableUrl: HandleClickableUrl, private val logger: Logger -) : PaneViewModel(initialState) { +) : FinancialConnectionsViewModel(initialState) { init { suspend { @@ -89,12 +88,12 @@ internal class ConsentViewModel @Inject constructor( handleClickableUrl( currentPane = Pane.CONSENT, uri = uri, - onNetworkUrlClicked = { stateFlow.update { it.copy(viewEffect = OpenUrl(uri, date.time)) } }, + onNetworkUrlClicked = { setState { copy(viewEffect = OpenUrl(uri, date.time)) } }, knownDeeplinkActions = mapOf( // Clicked on the "Data Access" link -> Open the Data Access bottom sheet ConsentClickableText.DATA.value to { - stateFlow.update { - it.copy( + setState { + copy( currentBottomSheet = BottomSheetContent.DATA, viewEffect = ViewEffect.OpenBottomSheet(date.time) ) @@ -102,8 +101,8 @@ internal class ConsentViewModel @Inject constructor( }, // Clicked on the "Legal details" link -> Open the Legal Details bottom sheet ConsentClickableText.LEGAL_DETAILS.value to { - stateFlow.update { - it.copy( + setState { + copy( viewEffect = ViewEffect.OpenBottomSheet(date.time), currentBottomSheet = BottomSheetContent.LEGAL ) @@ -118,16 +117,15 @@ internal class ConsentViewModel @Inject constructor( } fun onViewEffectLaunched() { - stateFlow.update { it.copy(viewEffect = null) } + setState { copy(viewEffect = null) } } companion object { - fun factory(parentViewModel: FinancialConnectionsSheetNativeViewModel): ViewModelProvider.Factory = + fun factory(parentComponent: FinancialConnectionsSheetNativeComponent): ViewModelProvider.Factory = viewModelFactory { initializer { - parentViewModel - .activityRetainedComponent + parentComponent .consentBuilder .initialState(ConsentState()) .build() diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/institutionpicker/InstitutionPickerScreen.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/institutionpicker/InstitutionPickerScreen.kt index 8d66a5908de..4f5e54707e8 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/institutionpicker/InstitutionPickerScreen.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/institutionpicker/InstitutionPickerScreen.kt @@ -65,7 +65,7 @@ import com.stripe.android.financialconnections.core.Result.Error import com.stripe.android.financialconnections.core.Result.Loading import com.stripe.android.financialconnections.core.Result.Success import com.stripe.android.financialconnections.core.Result.Uninitialized -import com.stripe.android.financialconnections.core.rememberPaneViewModel +import com.stripe.android.financialconnections.core.paneViewModel import com.stripe.android.financialconnections.features.common.FullScreenGenericLoading import com.stripe.android.financialconnections.features.common.InstitutionIcon import com.stripe.android.financialconnections.features.common.LoadingShimmerEffect @@ -91,7 +91,7 @@ import kotlinx.coroutines.launch @Composable internal fun InstitutionPickerScreen() { - val viewModel: InstitutionPickerViewModel = rememberPaneViewModel { InstitutionPickerViewModel.factory(it) } + val viewModel: InstitutionPickerViewModel = paneViewModel { InstitutionPickerViewModel.factory(it) } val parentViewModel = parentViewModel() val state: InstitutionPickerState by viewModel.stateFlow.collectAsState() val listState = rememberLazyListState() diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/institutionpicker/InstitutionPickerViewModel.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/institutionpicker/InstitutionPickerViewModel.kt index 26b905c9c61..40f3d609cf4 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/institutionpicker/InstitutionPickerViewModel.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/institutionpicker/InstitutionPickerViewModel.kt @@ -16,10 +16,11 @@ import com.stripe.android.financialconnections.analytics.FinancialConnectionsAna import com.stripe.android.financialconnections.analytics.FinancialConnectionsEvent.Metadata import com.stripe.android.financialconnections.analytics.FinancialConnectionsEvent.Name import com.stripe.android.financialconnections.analytics.logError -import com.stripe.android.financialconnections.core.PaneViewModel +import com.stripe.android.financialconnections.core.FinancialConnectionsViewModel import com.stripe.android.financialconnections.core.Result import com.stripe.android.financialconnections.core.Result.Loading import com.stripe.android.financialconnections.core.Result.Uninitialized +import com.stripe.android.financialconnections.di.FinancialConnectionsSheetNativeComponent import com.stripe.android.financialconnections.domain.FeaturedInstitutions import com.stripe.android.financialconnections.domain.GetOrFetchSync import com.stripe.android.financialconnections.domain.HandleError @@ -35,7 +36,6 @@ import com.stripe.android.financialconnections.navigation.Destination.ManualEntr import com.stripe.android.financialconnections.navigation.Destination.PartnerAuth import com.stripe.android.financialconnections.navigation.Destination.PartnerAuthDrawer import com.stripe.android.financialconnections.navigation.NavigationManager -import com.stripe.android.financialconnections.presentation.FinancialConnectionsSheetNativeViewModel import com.stripe.android.financialconnections.utils.ConflatedJob import com.stripe.android.financialconnections.utils.isCancellationError import com.stripe.android.financialconnections.utils.measureTimeMillis @@ -55,7 +55,7 @@ internal class InstitutionPickerViewModel @Inject constructor( private val updateLocalManifest: UpdateLocalManifest, private val logger: Logger, initialState: InstitutionPickerState -) : PaneViewModel(initialState) { +) : FinancialConnectionsViewModel(initialState) { private var searchJob = ConflatedJob() @@ -228,11 +228,10 @@ internal class InstitutionPickerViewModel @Inject constructor( } companion object { - fun factory(parentViewModel: FinancialConnectionsSheetNativeViewModel): ViewModelProvider.Factory = + fun factory(parentComponent: FinancialConnectionsSheetNativeComponent): ViewModelProvider.Factory = viewModelFactory { initializer { - parentViewModel - .activityRetainedComponent + parentComponent .institutionPickerBuilder .initialState(InstitutionPickerState()) .build() diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/presentation/FinancialConnectionsSheetNativeViewModel.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/presentation/FinancialConnectionsSheetNativeViewModel.kt index c0890eb9d99..c5f2787e1bc 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/presentation/FinancialConnectionsSheetNativeViewModel.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/presentation/FinancialConnectionsSheetNativeViewModel.kt @@ -1,16 +1,20 @@ package com.stripe.android.financialconnections.presentation +import android.app.Application import android.content.Intent +import android.os.Bundle import android.os.Parcelable import androidx.compose.runtime.Composable +import androidx.lifecycle.SavedStateHandle +import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory.Companion.APPLICATION_KEY +import androidx.lifecycle.createSavedStateHandle +import androidx.lifecycle.viewModelScope +import androidx.lifecycle.viewmodel.initializer +import androidx.lifecycle.viewmodel.viewModelFactory import androidx.navigation.NavDestination import androidx.navigation.compose.NavHost -import com.airbnb.mvrx.MavericksState -import com.airbnb.mvrx.MavericksViewModel -import com.airbnb.mvrx.MavericksViewModelFactory -import com.airbnb.mvrx.PersistState -import com.airbnb.mvrx.ViewModelContext -import com.airbnb.mvrx.compose.mavericksActivityViewModel +import com.airbnb.mvrx.Mavericks import com.stripe.android.core.Logger import com.stripe.android.financialconnections.FinancialConnections import com.stripe.android.financialconnections.FinancialConnectionsSheet @@ -22,6 +26,8 @@ import com.stripe.android.financialconnections.analytics.FinancialConnectionsAna import com.stripe.android.financialconnections.analytics.FinancialConnectionsAnalyticsTracker import com.stripe.android.financialconnections.analytics.FinancialConnectionsEvent.Metadata import com.stripe.android.financialconnections.analytics.FinancialConnectionsEvent.Name +import com.stripe.android.financialconnections.core.FinancialConnectionsViewModel +import com.stripe.android.financialconnections.core.parentActivity import com.stripe.android.financialconnections.di.APPLICATION_ID import com.stripe.android.financialconnections.di.DaggerFinancialConnectionsSheetNativeComponent import com.stripe.android.financialconnections.di.FinancialConnectionsSheetNativeComponent @@ -45,6 +51,9 @@ import com.stripe.android.financialconnections.model.FinancialConnectionsSession import com.stripe.android.financialconnections.navigation.Destination import com.stripe.android.financialconnections.navigation.NavigationManager import com.stripe.android.financialconnections.navigation.pane +import com.stripe.android.financialconnections.presentation.FinancialConnectionsSheetNativeState.Companion.KEY_FIRST_INIT +import com.stripe.android.financialconnections.presentation.FinancialConnectionsSheetNativeState.Companion.KEY_SAVED_STATE +import com.stripe.android.financialconnections.presentation.FinancialConnectionsSheetNativeState.Companion.KEY_WEB_AUTH_FLOW import com.stripe.android.financialconnections.presentation.FinancialConnectionsSheetNativeViewEffect.Finish import com.stripe.android.financialconnections.presentation.FinancialConnectionsSheetNativeViewEffect.OpenUrl import com.stripe.android.financialconnections.utils.UriUtils @@ -61,6 +70,7 @@ internal class FinancialConnectionsSheetNativeViewModel @Inject constructor( * No other dependencies should be exposed from the viewModel */ val activityRetainedComponent: FinancialConnectionsSheetNativeComponent, + savedStateHandle: SavedStateHandle, private val nativeAuthFlowCoordinator: NativeAuthFlowCoordinator, private val uriUtils: UriUtils, private val completeFinancialConnectionsSession: CompleteFinancialConnectionsSession, @@ -69,12 +79,13 @@ internal class FinancialConnectionsSheetNativeViewModel @Inject constructor( private val navigationManager: NavigationManager, @Named(APPLICATION_ID) private val applicationId: String, initialState: FinancialConnectionsSheetNativeState -) : MavericksViewModel(initialState) { +) : FinancialConnectionsViewModel(initialState) { private val mutex = Mutex() val navigationFlow = navigationManager.navigationFlow init { + savedStateHandle.registerSavedStateProvider() setState { copy(firstInit = false) } viewModelScope.launch { nativeAuthFlowCoordinator().collect { message -> @@ -95,6 +106,16 @@ internal class FinancialConnectionsSheetNativeViewModel @Inject constructor( } } + private fun SavedStateHandle.registerSavedStateProvider() { + setSavedStateProvider(KEY_SAVED_STATE) { + val state = stateFlow.value + Bundle().apply { + putParcelable(KEY_WEB_AUTH_FLOW, state.webAuthFlow) + putBoolean(KEY_FIRST_INIT, state.firstInit) + } + } + } + /** * When authorization flow finishes, it will redirect to a URL scheme stripe-auth://link-accounts * captured by [com.stripe.android.financialconnections.FinancialConnectionsSheetRedirectActivity] @@ -161,7 +182,7 @@ internal class FinancialConnectionsSheetNativeViewModel @Inject constructor( */ fun onResume() = viewModelScope.launch { mutex.withLock { - val state = awaitState() + val state = stateFlow.value if (state.webAuthFlow is WebAuthFlowState.InProgress) { setState { copy(webAuthFlow = WebAuthFlowState.Canceled(url = null)) } } @@ -227,7 +248,7 @@ internal class FinancialConnectionsSheetNativeViewModel @Inject constructor( ) = viewModelScope.launch { mutex.withLock { // prevents multiple complete triggers. - if (awaitState().completed) return@launch + if (stateFlow.value.completed) return@launch setState { copy(completed = true) } runCatching { val session = completeFinancialConnectionsSession(earlyTerminationCause?.value) @@ -321,8 +342,7 @@ internal class FinancialConnectionsSheetNativeViewModel @Inject constructor( } } - companion object : - MavericksViewModelFactory { + companion object { private fun baseUrl(applicationId: String) = "stripe://auth-redirect/$applicationId" @@ -333,30 +353,38 @@ internal class FinancialConnectionsSheetNativeViewModel @Inject constructor( private const val STATUS_SUCCESS = "success" private const val STATUS_FAILURE = "failure" - override fun create( - viewModelContext: ViewModelContext, - state: FinancialConnectionsSheetNativeState - ): FinancialConnectionsSheetNativeViewModel { - val args = viewModelContext.args() - return DaggerFinancialConnectionsSheetNativeComponent - .builder() - .initialSyncResponse(args.initialSyncResponse.takeIf { state.firstInit }) - .application(viewModelContext.app()) - .configuration(state.configuration) - .initialState(state) - .build() - .viewModel + val Factory: ViewModelProvider.Factory = viewModelFactory { + initializer { + val savedStateHandle: SavedStateHandle = createSavedStateHandle() + val app = this[APPLICATION_KEY] as Application + // Arguments passed to the activity + val args: FinancialConnectionsSheetNativeActivityArgs = + requireNotNull(savedStateHandle[Mavericks.KEY_ARG]) + // If the ViewModel is recreated, it will be provided with the saved state. + val savedState = savedStateHandle.get(KEY_SAVED_STATE) + val state = FinancialConnectionsSheetNativeState( + args = args, + savedState = savedState + ) + DaggerFinancialConnectionsSheetNativeComponent + .builder() + .initialSyncResponse(args.initialSyncResponse.takeIf { state.firstInit }) + .application(app) + .configuration(state.configuration) + .savedStateHandle(savedStateHandle) + .initialState(state) + .build() + .viewModel + } } } } internal data class FinancialConnectionsSheetNativeState( - @PersistState val webAuthFlow: WebAuthFlowState, /** * Tracks whether this state was recreated from a process kill. */ - @PersistState val firstInit: Boolean, val configuration: FinancialConnectionsSheet.Configuration, val reducedBranding: Boolean, @@ -364,22 +392,30 @@ internal data class FinancialConnectionsSheetNativeState( val viewEffect: FinancialConnectionsSheetNativeViewEffect?, val completed: Boolean, val initialPane: Pane -) : MavericksState { +) { /** - * Used by Mavericks to build initial state based on args. + * Used to build initial state based on args. */ - @Suppress("Unused") - constructor(args: FinancialConnectionsSheetNativeActivityArgs) : this( - webAuthFlow = WebAuthFlowState.Uninitialized, + constructor( + args: FinancialConnectionsSheetNativeActivityArgs, + savedState: Bundle? + ) : this( + webAuthFlow = savedState?.getParcelable(KEY_WEB_AUTH_FLOW) ?: WebAuthFlowState.Uninitialized, reducedBranding = args.initialSyncResponse.visual.reducedBranding, testMode = args.initialSyncResponse.manifest.livemode.not(), - firstInit = true, + firstInit = savedState?.getBoolean(KEY_FIRST_INIT, true) ?: true, completed = false, initialPane = args.initialSyncResponse.manifest.nextPane, configuration = args.configuration, viewEffect = null ) + + companion object { + const val KEY_SAVED_STATE = "FinancialConnectionsSheetNativeState" + const val KEY_WEB_AUTH_FLOW = "webAuthFlow" + const val KEY_FIRST_INIT = "firstInit" + } } /** @@ -430,8 +466,7 @@ internal sealed class WebAuthFlowState : Parcelable { } @Composable -internal fun parentViewModel(): FinancialConnectionsSheetNativeViewModel = - mavericksActivityViewModel() +internal fun parentViewModel(): FinancialConnectionsSheetNativeViewModel = parentActivity().viewModel internal sealed interface FinancialConnectionsSheetNativeViewEffect { /** diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/ui/FinancialConnectionsSheetNativeActivity.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/ui/FinancialConnectionsSheetNativeActivity.kt index fcb1e7e02fb..1838b990b07 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/ui/FinancialConnectionsSheetNativeActivity.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/ui/FinancialConnectionsSheetNativeActivity.kt @@ -7,6 +7,7 @@ import android.os.Bundle import androidx.activity.addCallback import androidx.activity.compose.BackHandler import androidx.activity.compose.setContent +import androidx.activity.viewModels import androidx.appcompat.app.AppCompatActivity import androidx.compose.material.ModalBottomSheetValue import androidx.compose.material.rememberModalBottomSheetState @@ -14,6 +15,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.runtime.staticCompositionLocalOf @@ -21,14 +23,14 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalLifecycleOwner import androidx.compose.ui.platform.LocalUriHandler import androidx.lifecycle.DefaultLifecycleObserver +import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.repeatOnLifecycle import androidx.navigation.NavHostController import androidx.navigation.NavOptionsBuilder import androidx.navigation.compose.NavHost import androidx.navigation.compose.rememberNavController -import com.airbnb.mvrx.MavericksView -import com.airbnb.mvrx.compose.collectAsState -import com.airbnb.mvrx.withState import com.stripe.android.core.Logger import com.stripe.android.financialconnections.browser.BrowserManager import com.stripe.android.financialconnections.launcher.FinancialConnectionsSheetNativeActivityArgs @@ -49,18 +51,22 @@ import com.stripe.android.financialconnections.ui.theme.FinancialConnectionsThem import com.stripe.android.financialconnections.utils.KeyboardController import com.stripe.android.financialconnections.utils.argsOrNull import com.stripe.android.financialconnections.utils.rememberKeyboardController -import com.stripe.android.financialconnections.utils.viewModelLazy import com.stripe.android.uicore.image.StripeImageLoader import kotlinx.coroutines.flow.SharedFlow +import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.launch import javax.inject.Inject -internal class FinancialConnectionsSheetNativeActivity : AppCompatActivity(), MavericksView { +internal class FinancialConnectionsSheetNativeActivity : AppCompatActivity() { val args by argsOrNull() - val viewModel: FinancialConnectionsSheetNativeViewModel by viewModelLazy() + val viewModel: FinancialConnectionsSheetNativeViewModel by viewModels( + factoryProducer = { FinancialConnectionsSheetNativeViewModel.Factory } + ) @Inject lateinit var logger: Logger @@ -77,44 +83,43 @@ internal class FinancialConnectionsSheetNativeActivity : AppCompatActivity(), Ma finish() } else { viewModel.activityRetainedComponent.inject(this) - viewModel.onEach { postInvalidate() } onBackPressedDispatcher.addCallback { viewModel.onBackPressed() } + observeViewEffects() setContent { FinancialConnectionsTheme { - val firstPane by viewModel.collectAsState { it.initialPane } - val reducedBranding by viewModel.collectAsState { it.reducedBranding } - val testMode by viewModel.collectAsState { it.testMode } + val state by viewModel.stateFlow.collectAsState() NavHost( - initialPane = firstPane, - testMode = testMode, - reducedBranding = reducedBranding + initialPane = state.initialPane, + testMode = state.testMode, + reducedBranding = state.reducedBranding ) } } } } - /** - * handle state changes here. - */ - override fun invalidate() { - withState(viewModel) { state -> - state.viewEffect?.let { viewEffect -> - when (viewEffect) { - is OpenUrl -> startActivity( - browserManager.createBrowserIntentForUrl(uri = Uri.parse(viewEffect.url)) - ) - - is Finish -> { - setResult( - Activity.RESULT_OK, - Intent().putExtra(EXTRA_RESULT, viewEffect.result) + private fun observeViewEffects() = lifecycleScope.launch { + repeatOnLifecycle(Lifecycle.State.STARTED) { + viewModel.stateFlow + .map { it.viewEffect } + .distinctUntilChanged() + .collect { viewEffect -> + if (viewEffect == null) return@collect + when (viewEffect) { + is OpenUrl -> startActivity( + browserManager.createBrowserIntentForUrl(uri = Uri.parse(viewEffect.url)) ) - finish() + + is Finish -> { + setResult( + Activity.RESULT_OK, + Intent().putExtra(EXTRA_RESULT, viewEffect.result) + ) + finish() + } } + viewModel.onViewEffectLaunched() } - viewModel.onViewEffectLaunched() - } } } From dc1e4e596a8a3a691694696691516255274e506e Mon Sep 17 00:00:00 2001 From: "Carlos M." Date: Wed, 20 Mar 2024 11:57:46 -0700 Subject: [PATCH 15/28] Renames result error to fail. --- .../financialconnections/core/ComposeUtils.kt | 3 ++ .../core/FinancialConnectionsViewModel.kt | 11 ++++--- .../features/consent/ConsentScreen.kt | 32 ++++++++----------- ...stitutionPickerPreviewParameterProvider.kt | 6 ++-- .../InstitutionPickerScreen.kt | 6 ++-- .../utils/MavericksExtensions.kt | 6 ++-- 6 files changed, 32 insertions(+), 32 deletions(-) diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/core/ComposeUtils.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/core/ComposeUtils.kt index 57718fab463..d9b84cac350 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/core/ComposeUtils.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/core/ComposeUtils.kt @@ -26,6 +26,9 @@ internal inline fun , S> paneViewMo factory: (FinancialConnectionsSheetNativeComponent) -> ViewModelProvider.Factory ): T { return viewModel(factory = factory(parentActivity().viewModel.activityRetainedComponent)) } +/** + * Retrieves the parent [FinancialConnectionsSheetNativeActivity] from the current Compose context. + */ @Composable internal fun parentActivity(): FinancialConnectionsSheetNativeActivity { return extractActivityFromContext(LocalContext.current) as FinancialConnectionsSheetNativeActivity diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/core/FinancialConnectionsViewModel.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/core/FinancialConnectionsViewModel.kt index 9e5fd28eca4..b0cc7aea918 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/core/FinancialConnectionsViewModel.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/core/FinancialConnectionsViewModel.kt @@ -2,6 +2,9 @@ package com.stripe.android.financialconnections.core import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.stripe.android.financialconnections.core.Result.Fail +import com.stripe.android.financialconnections.core.Result.Loading +import com.stripe.android.financialconnections.core.Result.Success import kotlinx.coroutines.Job import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.update @@ -19,16 +22,16 @@ internal abstract class FinancialConnectionsViewModel( onFail: (Throwable) -> Unit = {} ): Job { return viewModelScope.launch { - setState { reducer(Result.Loading) } + setState { reducer(Loading) } val result = kotlin.runCatching { this@execute() } // update state. result.fold( onSuccess = { data -> - setState { reducer(Result.Success(data)) } + setState { reducer(Success(data)) } onSuccess(data) }, onFailure = { throwable -> - setState { reducer(Result.Error(throwable)) } + setState { reducer(Fail(throwable)) } onFail(throwable) } ) @@ -48,7 +51,7 @@ internal sealed class Result( data class Success(val value: T) : Result(value = value) { override operator fun invoke(): T = value } - data class Error(val throwable: Throwable) : Result(value = null) + data class Fail(val error: Throwable) : Result(value = null) open operator fun invoke(): T? = value } diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentScreen.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentScreen.kt index ed558b8c029..c906e561f11 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentScreen.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentScreen.kt @@ -32,7 +32,7 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp import com.stripe.android.financialconnections.core.Result -import com.stripe.android.financialconnections.core.Result.Error +import com.stripe.android.financialconnections.core.Result.Fail import com.stripe.android.financialconnections.core.Result.Loading import com.stripe.android.financialconnections.core.Result.Success import com.stripe.android.financialconnections.core.Result.Uninitialized @@ -114,26 +114,20 @@ private fun ConsentContent( onCloseFromErrorClick: (Throwable) -> Unit ) { when (val result = state.consent) { - Uninitialized, Loading -> { - ConsentLoadingContent() - } + Uninitialized, Loading -> ConsentLoadingContent() - is Error -> { - UnclassifiedErrorContent { onCloseFromErrorClick(result.throwable) } - } + is Success -> LoadedContent( + payload = result.value, + bottomSheetState = bottomSheetState, + acceptConsent = state.acceptConsent, + bottomSheetMode = state.currentBottomSheet, + onClickableTextClick = onClickableTextClick, + onContinueClick = onContinueClick, + onCloseClick = onCloseClick, + onConfirmModalClick = onConfirmModalClick + ) - is Success -> { - LoadedContent( - payload = result.value, - bottomSheetState = bottomSheetState, - acceptConsent = state.acceptConsent, - bottomSheetMode = state.currentBottomSheet, - onClickableTextClick = onClickableTextClick, - onContinueClick = onContinueClick, - onCloseClick = onCloseClick, - onConfirmModalClick = onConfirmModalClick - ) - } + is Fail -> UnclassifiedErrorContent { onCloseFromErrorClick(result.error) } } } diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/institutionpicker/InstitutionPickerPreviewParameterProvider.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/institutionpicker/InstitutionPickerPreviewParameterProvider.kt index 31043ba0a06..d29575f1b2c 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/institutionpicker/InstitutionPickerPreviewParameterProvider.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/institutionpicker/InstitutionPickerPreviewParameterProvider.kt @@ -1,7 +1,7 @@ package com.stripe.android.financialconnections.features.institutionpicker import androidx.compose.ui.tooling.preview.PreviewParameterProvider -import com.stripe.android.financialconnections.core.Result.Error +import com.stripe.android.financialconnections.core.Result.Fail import com.stripe.android.financialconnections.core.Result.Loading import com.stripe.android.financialconnections.core.Result.Success import com.stripe.android.financialconnections.core.Result.Uninitialized @@ -102,7 +102,7 @@ internal class InstitutionPickerPreviewParameterProvider : state = InstitutionPickerState( previewText = "Some query", payload = Success(payload(manualEntry = true)), - searchInstitutions = Error(Exception("Something went wrong")), + searchInstitutions = Fail(Exception("Something went wrong")), ), initialScroll = 0 ) @@ -111,7 +111,7 @@ internal class InstitutionPickerPreviewParameterProvider : state = InstitutionPickerState( previewText = "Some query", payload = Success(payload(manualEntry = false)), - searchInstitutions = Error(Exception("Something went wrong")), + searchInstitutions = Fail(Exception("Something went wrong")), ), initialScroll = 0 ) diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/institutionpicker/InstitutionPickerScreen.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/institutionpicker/InstitutionPickerScreen.kt index 4f5e54707e8..d9d9008a55d 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/institutionpicker/InstitutionPickerScreen.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/institutionpicker/InstitutionPickerScreen.kt @@ -61,7 +61,7 @@ import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp import com.stripe.android.financialconnections.R import com.stripe.android.financialconnections.core.Result -import com.stripe.android.financialconnections.core.Result.Error +import com.stripe.android.financialconnections.core.Result.Fail import com.stripe.android.financialconnections.core.Result.Loading import com.stripe.android.financialconnections.core.Result.Success import com.stripe.android.financialconnections.core.Result.Uninitialized @@ -134,7 +134,7 @@ private fun InstitutionPickerContent( when (payload) { is Uninitialized, is Loading, - is Error -> FullScreenGenericLoading() + is Fail -> FullScreenGenericLoading() is Success -> LoadedContent( listState = listState, previewText = previewText, @@ -257,7 +257,7 @@ private fun LazyListScope.searchResults( else -> when (institutions) { // Load failure: Display error message. - is Error -> item { + is Fail -> item { NoResultsTile( modifier = Modifier.padding(8.dp), showManualEntry = payload.featuredInstitutions.showManualEntry, 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 124a9ac7983..125d7cfccb3 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 @@ -72,8 +72,8 @@ internal fun Async<*>.isCancellationError(): Boolean = when { } internal fun Result<*>.isCancellationError(): Boolean = when { - this !is Result.Error -> false - throwable is CancellationException -> true - throwable is StripeException && throwable.cause is CancellationException -> true + this !is Result.Fail -> false + error is CancellationException -> true + error is StripeException && error.cause is CancellationException -> true else -> false } From cfff17fd6f9e894ec213bb9e393388d74645ee52 Mon Sep 17 00:00:00 2001 From: "Carlos M." Date: Wed, 20 Mar 2024 13:55:23 -0700 Subject: [PATCH 16/28] Migrates Initial activity out of mavericks. --- .../FinancialConnectionsSheetActivity.kt | 87 ++++++----- .../FinancialConnectionsSheetState.kt | 27 +++- .../FinancialConnectionsSheetViewModel.kt | 137 ++++++++++-------- .../di/FinancialConnectionsSheetComponent.kt | 4 + .../ConsentPreviewParameterProvider.kt | 14 +- 5 files changed, 160 insertions(+), 109 deletions(-) diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/FinancialConnectionsSheetActivity.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/FinancialConnectionsSheetActivity.kt index fe3376f566f..18b9083f5f4 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/FinancialConnectionsSheetActivity.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/FinancialConnectionsSheetActivity.kt @@ -7,6 +7,7 @@ import android.widget.Toast import androidx.activity.addCallback import androidx.activity.compose.setContent import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult +import androidx.activity.viewModels import androidx.appcompat.app.AppCompatActivity import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize @@ -15,9 +16,10 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.repeatOnLifecycle import com.airbnb.mvrx.Mavericks -import com.airbnb.mvrx.MavericksView -import com.airbnb.mvrx.withState import com.stripe.android.financialconnections.FinancialConnectionsSheetViewEffect.FinishWithResult import com.stripe.android.financialconnections.FinancialConnectionsSheetViewEffect.OpenAuthFlowWithUrl import com.stripe.android.financialconnections.FinancialConnectionsSheetViewEffect.OpenNativeAuthFlow @@ -29,11 +31,15 @@ import com.stripe.android.financialconnections.launcher.FinancialConnectionsShee import com.stripe.android.financialconnections.ui.FinancialConnectionsSheetNativeActivity import com.stripe.android.financialconnections.ui.theme.FinancialConnectionsTheme import com.stripe.android.financialconnections.utils.argsOrNull -import com.stripe.android.financialconnections.utils.viewModelLazy +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.launch -internal class FinancialConnectionsSheetActivity : AppCompatActivity(), MavericksView { +internal class FinancialConnectionsSheetActivity : AppCompatActivity() { - val viewModel: FinancialConnectionsSheetViewModel by viewModelLazy() + val viewModel: FinancialConnectionsSheetViewModel by viewModels( + factoryProducer = { FinancialConnectionsSheetViewModel.Factory } + ) val args by argsOrNull() @@ -52,7 +58,7 @@ internal class FinancialConnectionsSheetActivity : AppCompatActivity(), Maverick if (args == null) { finish() } else { - viewModel.onEach { postInvalidate() } + observeViewEffects() browserManager = BrowserManager(application) if (savedInstanceState != null) viewModel.onActivityRecreated() } @@ -91,42 +97,53 @@ internal class FinancialConnectionsSheetActivity : AppCompatActivity(), Maverick /** * handle state changes here. */ - override fun invalidate() { - withState(viewModel) { state -> - state.viewEffect?.let { viewEffect -> - when (viewEffect) { - is OpenAuthFlowWithUrl -> startBrowserForResult.launch( - browserManager.createBrowserIntentForUrl( - uri = Uri.parse(viewEffect.url) + + private fun observeViewEffects() = lifecycleScope.launch { + repeatOnLifecycle(Lifecycle.State.STARTED) { + viewModel.stateFlow + .map { it.viewEffect } + .distinctUntilChanged() + .collect { viewEffect -> + if (viewEffect == null) return@collect + when (viewEffect) { + is OpenAuthFlowWithUrl -> startBrowserForResult.launch( + browserManager.createBrowserIntentForUrl( + uri = Uri.parse(viewEffect.url) + ) ) - ) - is FinishWithResult -> { - viewEffect.finishToast?.let { - Toast.makeText(this, it, Toast.LENGTH_LONG).show() + is FinishWithResult -> { + viewEffect.finishToast?.let { + Toast.makeText( + this@FinancialConnectionsSheetActivity, it, Toast.LENGTH_LONG + ).show() + } + finishWithResult(viewEffect.result) } - finishWithResult(viewEffect.result) + + is OpenNativeAuthFlow -> openNativeAuthFlow(viewEffect) } + viewModel.onViewEffectLaunched() + } + } + } - is OpenNativeAuthFlow -> startNativeAuthFlowForResult.launch( - Intent( - this, - FinancialConnectionsSheetNativeActivity::class.java - ).also { - it.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION) - it.putExtra( - Mavericks.KEY_ARG, - FinancialConnectionsSheetNativeActivityArgs( - initialSyncResponse = viewEffect.initialSyncResponse, - configuration = viewEffect.configuration - ) - ) - } + private fun openNativeAuthFlow(viewEffect: OpenNativeAuthFlow) { + startNativeAuthFlowForResult.launch( + Intent( + this@FinancialConnectionsSheetActivity, + FinancialConnectionsSheetNativeActivity::class.java + ).also { + it.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION) + it.putExtra( + Mavericks.KEY_ARG, + FinancialConnectionsSheetNativeActivityArgs( + initialSyncResponse = viewEffect.initialSyncResponse, + configuration = viewEffect.configuration ) - } - viewModel.onViewEffectLaunched() + ) } - } + ) } private fun finishWithResult(result: FinancialConnectionsSheetActivityResult) { 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 50886478de1..2a76dd1a79d 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 @@ -1,5 +1,6 @@ package com.stripe.android.financialconnections +import android.os.Bundle import androidx.annotation.StringRes import com.airbnb.mvrx.MavericksState import com.airbnb.mvrx.PersistState @@ -13,7 +14,7 @@ import com.stripe.android.financialconnections.model.SynchronizeSessionResponse */ internal data class FinancialConnectionsSheetState( val initialArgs: FinancialConnectionsSheetActivityArgs, - val activityRecreated: Boolean = false, + val activityRecreated: Boolean, @PersistState val manifest: FinancialConnectionsSessionManifest? = null, @PersistState val webAuthFlowStatus: AuthFlowStatus = AuthFlowStatus.NONE, val viewEffect: FinancialConnectionsSheetViewEffect? = null @@ -22,6 +23,19 @@ internal data class FinancialConnectionsSheetState( val sessionSecret: String get() = initialArgs.configuration.financialConnectionsSessionClientSecret + /** + * Constructor used to build the initial state. + */ + constructor(args: FinancialConnectionsSheetActivityArgs, savedState: Bundle?) : this( + initialArgs = args, + activityRecreated = false, + manifest = savedState?.getParcelable(KEY_MANIFEST), + webAuthFlowStatus = savedState?.getSerializable(KEY_WEB_AUTH_FLOW_STATUS) + as? AuthFlowStatus + ?: AuthFlowStatus.NONE, + viewEffect = null + ) + enum class AuthFlowStatus { /** * AuthFlow is happening outside of the SDK (app2app, web browser, etc). @@ -47,12 +61,11 @@ internal data class FinancialConnectionsSheetState( NONE } - /** - * Constructor used by Mavericks to build the initial state. - */ - constructor(args: FinancialConnectionsSheetActivityArgs) : this( - initialArgs = args - ) + companion object { + const val KEY_SAVED_STATE = "financial_connections_sheet_state" + const val KEY_MANIFEST = "financial_connections_sheet_manifest" + const val KEY_WEB_AUTH_FLOW_STATUS = "financial_connections_sheet_web_auth_flow_status" + } } /** diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/FinancialConnectionsSheetViewModel.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/FinancialConnectionsSheetViewModel.kt index c661f97c982..295f8df1de8 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/FinancialConnectionsSheetViewModel.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/FinancialConnectionsSheetViewModel.kt @@ -1,13 +1,19 @@ package com.stripe.android.financialconnections import android.app.Activity +import android.app.Application import android.content.Intent import android.net.Uri +import android.os.Bundle import androidx.activity.result.ActivityResult import androidx.annotation.StringRes -import com.airbnb.mvrx.MavericksViewModel -import com.airbnb.mvrx.MavericksViewModelFactory -import com.airbnb.mvrx.ViewModelContext +import androidx.lifecycle.SavedStateHandle +import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.createSavedStateHandle +import androidx.lifecycle.viewModelScope +import androidx.lifecycle.viewmodel.initializer +import androidx.lifecycle.viewmodel.viewModelFactory +import com.airbnb.mvrx.Mavericks import com.stripe.android.core.Logger import com.stripe.android.financialconnections.FinancialConnectionsSheetState.AuthFlowStatus import com.stripe.android.financialconnections.FinancialConnectionsSheetViewEffect.FinishWithResult @@ -20,6 +26,7 @@ import com.stripe.android.financialconnections.analytics.FinancialConnectionsEve import com.stripe.android.financialconnections.analytics.FinancialConnectionsEventReporter import com.stripe.android.financialconnections.analytics.logError import com.stripe.android.financialconnections.browser.BrowserManager +import com.stripe.android.financialconnections.core.FinancialConnectionsViewModel import com.stripe.android.financialconnections.di.APPLICATION_ID import com.stripe.android.financialconnections.di.DaggerFinancialConnectionsSheetComponent import com.stripe.android.financialconnections.domain.FetchFinancialConnectionsSession @@ -29,6 +36,7 @@ import com.stripe.android.financialconnections.domain.SynchronizeFinancialConnec import com.stripe.android.financialconnections.exception.AppInitializationError import com.stripe.android.financialconnections.exception.CustomManualEntryRequiredError import com.stripe.android.financialconnections.features.manualentry.isCustomManualEntryError +import com.stripe.android.financialconnections.launcher.FinancialConnectionsSheetActivityArgs import com.stripe.android.financialconnections.launcher.FinancialConnectionsSheetActivityArgs.ForData import com.stripe.android.financialconnections.launcher.FinancialConnectionsSheetActivityArgs.ForLink import com.stripe.android.financialconnections.launcher.FinancialConnectionsSheetActivityArgs.ForToken @@ -50,6 +58,7 @@ import javax.inject.Named internal class FinancialConnectionsSheetViewModel @Inject constructor( @Named(APPLICATION_ID) private val applicationId: String, + savedStateHandle: SavedStateHandle, private val synchronizeFinancialConnectionsSession: SynchronizeFinancialConnectionsSession, private val fetchFinancialConnectionsSession: FetchFinancialConnectionsSession, private val fetchFinancialConnectionsSessionForToken: FetchFinancialConnectionsSessionForToken, @@ -59,11 +68,12 @@ internal class FinancialConnectionsSheetViewModel @Inject constructor( private val analyticsTracker: FinancialConnectionsAnalyticsTracker, private val nativeRouter: NativeAuthFlowRouter, initialState: FinancialConnectionsSheetState -) : MavericksViewModel(initialState) { +) : FinancialConnectionsViewModel(initialState) { private val mutex = Mutex() init { + savedStateHandle.registerSavedStateProvider() if (initialState.initialArgs.isValid()) { eventReporter.onPresented(initialState.initialArgs.configuration) // avoid re-fetching manifest if already exists (this will happen on process recreations) @@ -76,20 +86,27 @@ internal class FinancialConnectionsSheetViewModel @Inject constructor( } } + private fun SavedStateHandle.registerSavedStateProvider() = + setSavedStateProvider(FinancialConnectionsSheetState.KEY_SAVED_STATE) { + val state = stateFlow.value + Bundle().apply { + putParcelable(FinancialConnectionsSheetState.KEY_MANIFEST, state.manifest) + putSerializable(FinancialConnectionsSheetState.KEY_WEB_AUTH_FLOW_STATUS, state.webAuthFlowStatus) + } + } + /** * Fetches the [FinancialConnectionsSessionManifest] from the Stripe API to get the hosted auth flow URL * as well as the success and cancel callback URLs to verify. */ private fun fetchManifest() { - withState { state -> - viewModelScope.launch { - kotlin.runCatching { - synchronizeFinancialConnectionsSession() - }.onFailure { - finishWithResult(state, Failed(it)) - }.onSuccess { - openAuthFlow(it) - } + viewModelScope.launch { + kotlin.runCatching { + synchronizeFinancialConnectionsSession() + }.onFailure { + finishWithResult(stateFlow.value, Failed(it)) + }.onSuccess { + openAuthFlow(it) } } } @@ -108,12 +125,10 @@ internal class FinancialConnectionsSheetViewModel @Inject constructor( val nativeAuthFlowEnabled = nativeRouter.nativeAuthFlowEnabled(sync.manifest) viewModelScope.launch { nativeRouter.logExposure(sync.manifest) } if (sync.manifest.hostedAuthUrl == null) { - withState { - finishWithResult( - state = it, - result = Failed(IllegalArgumentException("hostedAuthUrl is required!")) - ) - } + finishWithResult( + state = stateFlow.value, + result = Failed(IllegalArgumentException("hostedAuthUrl is required!")) + ) } else { FinancialConnections.emitEvent(name = Name.OPEN) if (nativeAuthFlowEnabled) { @@ -138,19 +153,17 @@ internal class FinancialConnectionsSheetViewModel @Inject constructor( } private fun logNoBrowserAvailableAndFinish() { - withState { state -> - val error = AppInitializationError("No Web browser available to launch AuthFlow") - analyticsTracker.logError( - "error Launching the Auth Flow", - logger = logger, - pane = Pane.UNEXPECTED_ERROR, - error = error - ) - finishWithResult( - state = state, - result = Failed(error) - ) - } + val error = AppInitializationError("No Web browser available to launch AuthFlow") + analyticsTracker.logError( + "error Launching the Auth Flow", + logger = logger, + pane = Pane.UNEXPECTED_ERROR, + error = error + ) + finishWithResult( + state = stateFlow.value, + result = Failed(error) + ) } /** @@ -187,7 +200,7 @@ internal class FinancialConnectionsSheetViewModel @Inject constructor( internal fun onResume() { viewModelScope.launch { mutex.withLock { - val state = awaitState() + val state = stateFlow.value if (state.activityRecreated.not()) { when (state.webAuthFlowStatus) { AuthFlowStatus.ON_EXTERNAL_ACTIVITY -> finishWithResult( @@ -216,7 +229,7 @@ internal class FinancialConnectionsSheetViewModel @Inject constructor( internal fun onBrowserActivityResult() { viewModelScope.launch { mutex.withLock { - val state = awaitState() + val state = stateFlow.value if (state.activityRecreated) { when (state.webAuthFlowStatus) { AuthFlowStatus.ON_EXTERNAL_ACTIVITY -> finishWithResult( @@ -241,9 +254,9 @@ internal class FinancialConnectionsSheetViewModel @Inject constructor( val result: FinancialConnectionsSheetActivityResult? = activityResult.data ?.parcelable(FinancialConnectionsSheetNativeActivity.EXTRA_RESULT) if (activityResult.resultCode == Activity.RESULT_OK && result != null) { - withState { finishWithResult(it, result, fromNative = true) } + finishWithResult(stateFlow.value, result, fromNative = true) } else { - withState { finishWithResult(it, Canceled, fromNative = true) } + finishWithResult(stateFlow.value, Canceled, fromNative = true) } } @@ -264,7 +277,7 @@ internal class FinancialConnectionsSheetViewModel @Inject constructor( result = Completed(financialConnectionsSession = it) ) }.onFailure { error -> - withState { finishWithResult(it, Failed(error)) } + finishWithResult(stateFlow.value, Failed(error)) } } } @@ -286,7 +299,7 @@ internal class FinancialConnectionsSheetViewModel @Inject constructor( result = Completed(financialConnectionsSession = las, token = token) ) }.onFailure { error -> - withState { finishWithResult(it, Failed(error)) } + finishWithResult(stateFlow.value, Failed(error)) } } } @@ -311,7 +324,7 @@ internal class FinancialConnectionsSheetViewModel @Inject constructor( } ) }.onFailure { error -> - withState { finishWithResult(it, Failed(error)) } + finishWithResult(stateFlow.value, Failed(error)) } } } @@ -328,7 +341,7 @@ internal class FinancialConnectionsSheetViewModel @Inject constructor( viewModelScope.launch { mutex.withLock { val receivedUrl: Uri? = intent?.data?.toString()?.toUriOrNull() - val state = awaitState() + val state = stateFlow.value when { // stripe-auth://native-redirect receivedUrl?.host == "native-redirect" -> @@ -423,15 +436,13 @@ internal class FinancialConnectionsSheetViewModel @Inject constructor( kotlin.runCatching { requireNotNull(url.getQueryParameter(QUERY_PARAM_LINKED_ACCOUNT)) }.onSuccess { linkedAccountId -> - withState { - finishWithResult( - state = it, - result = Completed(linkedAccountId = linkedAccountId) - ) - } + finishWithResult( + state = stateFlow.value, + result = Completed(linkedAccountId = linkedAccountId) + ) }.onFailure { error -> logger.error("Could not retrieve linked account from success url", error) - withState { state -> finishWithResult(state, Failed(error)) } + finishWithResult(stateFlow.value, Failed(error)) } } @@ -465,19 +476,25 @@ internal class FinancialConnectionsSheetViewModel @Inject constructor( setState { copy(viewEffect = FinishWithResult(result, finishMessage)) } } - companion object : - MavericksViewModelFactory { - - override fun create( - viewModelContext: ViewModelContext, - state: FinancialConnectionsSheetState - ): FinancialConnectionsSheetViewModel { - return DaggerFinancialConnectionsSheetComponent - .builder() - .application(viewModelContext.app()) - .initialState(state) - .configuration(state.initialArgs.configuration) - .build().viewModel + companion object { + + val Factory = viewModelFactory { + initializer { + val savedStateHandle: SavedStateHandle = createSavedStateHandle() + // If the ViewModel is recreated, it will be provided with the saved state. + val savedState = savedStateHandle.get(FinancialConnectionsSheetState.KEY_SAVED_STATE) + val app = this[ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY] as Application + // Arguments passed to the activity + val args: FinancialConnectionsSheetActivityArgs = requireNotNull(savedStateHandle[Mavericks.KEY_ARG]) + val state = FinancialConnectionsSheetState(args, savedState) + DaggerFinancialConnectionsSheetComponent + .builder() + .application(app) + .savedStateHandle(savedStateHandle) + .initialState(state) + .configuration(state.initialArgs.configuration) + .build().viewModel + } } internal const val MAX_ACCOUNTS = 100 diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/di/FinancialConnectionsSheetComponent.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/di/FinancialConnectionsSheetComponent.kt index c62cf42b946..0ba94d9ba49 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/di/FinancialConnectionsSheetComponent.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/di/FinancialConnectionsSheetComponent.kt @@ -1,6 +1,7 @@ package com.stripe.android.financialconnections.di import android.app.Application +import androidx.lifecycle.SavedStateHandle import com.stripe.android.core.injection.CoreCommonModule import com.stripe.android.core.injection.CoroutineContextModule import com.stripe.android.financialconnections.FinancialConnectionsSheet @@ -27,6 +28,9 @@ internal interface FinancialConnectionsSheetComponent { @BindsInstance fun application(application: Application): Builder + @BindsInstance + fun savedStateHandle(savedStateHandle: SavedStateHandle): Builder + @BindsInstance fun initialState(initialState: FinancialConnectionsSheetState): Builder diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentPreviewParameterProvider.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentPreviewParameterProvider.kt index 251a400eb42..eebf7129600 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentPreviewParameterProvider.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentPreviewParameterProvider.kt @@ -3,7 +3,7 @@ package com.stripe.android.financialconnections.features.consent import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.material.ModalBottomSheetValue import androidx.compose.ui.tooling.preview.PreviewParameterProvider -import com.stripe.android.financialconnections.core.Result +import com.stripe.android.financialconnections.core.Result.Success import com.stripe.android.financialconnections.model.Bullet import com.stripe.android.financialconnections.model.ConnectedAccessNotice import com.stripe.android.financialconnections.model.ConsentPane @@ -32,7 +32,7 @@ internal class ConsentPreviewParameterProvider : private fun withPlatformLogos() = ConsentState( - consent = Result.Success( + consent = Success( ConsentState.Payload( consent = sampleConsent().copy(belowCta = null), merchantLogos = listOf( @@ -46,7 +46,7 @@ internal class ConsentPreviewParameterProvider : private fun withConnectedAccountLogos() = ConsentState( - consent = Result.Success( + consent = Success( ConsentState.Payload( consent = sampleConsent().copy(belowCta = null), merchantLogos = listOf( @@ -60,7 +60,7 @@ internal class ConsentPreviewParameterProvider : ) private fun manualEntryPlusMicrodeposits() = ConsentState( - consent = Result.Success( + consent = Success( ConsentState.Payload( consent = sampleConsent(), merchantLogos = listOf( @@ -74,7 +74,7 @@ internal class ConsentPreviewParameterProvider : private fun withDataBottomSheet() = ConsentState( currentBottomSheet = ConsentState.BottomSheetContent.DATA, - consent = Result.Success( + consent = Success( ConsentState.Payload( consent = sampleConsent().copy( dataAccessNotice = sampleConsent().dataAccessNotice.copy( @@ -92,7 +92,7 @@ internal class ConsentPreviewParameterProvider : private fun withDataBottomSheetAndConnectedAccount() = ConsentState( currentBottomSheet = ConsentState.BottomSheetContent.DATA, - consent = Result.Success( + consent = Success( ConsentState.Payload( consent = sampleConsent(), merchantLogos = listOf( @@ -106,7 +106,7 @@ internal class ConsentPreviewParameterProvider : private fun withLegalDetailsBottomSheet() = ConsentState( currentBottomSheet = ConsentState.BottomSheetContent.LEGAL, - consent = Result.Success( + consent = Success( ConsentState.Payload( consent = sampleConsent().copy(belowCta = null), merchantLogos = listOf( From bc737a8743f6d4754e5a41ee1514c8bbe489e3c8 Mon Sep 17 00:00:00 2001 From: "Carlos M." Date: Wed, 20 Mar 2024 14:00:35 -0700 Subject: [PATCH 17/28] Removes persist state. --- .../financialconnections/FinancialConnectionsSheetState.kt | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) 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 2a76dd1a79d..6ec67c4a3bd 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 @@ -3,7 +3,6 @@ package com.stripe.android.financialconnections import android.os.Bundle import androidx.annotation.StringRes import com.airbnb.mvrx.MavericksState -import com.airbnb.mvrx.PersistState import com.stripe.android.financialconnections.launcher.FinancialConnectionsSheetActivityArgs import com.stripe.android.financialconnections.launcher.FinancialConnectionsSheetActivityResult import com.stripe.android.financialconnections.model.FinancialConnectionsSessionManifest @@ -15,9 +14,9 @@ import com.stripe.android.financialconnections.model.SynchronizeSessionResponse internal data class FinancialConnectionsSheetState( val initialArgs: FinancialConnectionsSheetActivityArgs, val activityRecreated: Boolean, - @PersistState val manifest: FinancialConnectionsSessionManifest? = null, - @PersistState val webAuthFlowStatus: AuthFlowStatus = AuthFlowStatus.NONE, - val viewEffect: FinancialConnectionsSheetViewEffect? = null + val manifest: FinancialConnectionsSessionManifest?, + val webAuthFlowStatus: AuthFlowStatus, + val viewEffect: FinancialConnectionsSheetViewEffect? ) : MavericksState { val sessionSecret: String From ce3643e3e5d17caa39598c90eafa66e501f3ea5f Mon Sep 17 00:00:00 2001 From: "Carlos M." Date: Wed, 20 Mar 2024 14:21:17 -0700 Subject: [PATCH 18/28] Updates tests. --- .../FinancialConnectionsSheetActivity.kt | 6 ++- .../financialconnections/CoroutineTestRule.kt | 25 ++++++++++++ .../FinancialConnectionsSheetViewModelTest.kt | 39 ++++++++++--------- .../InstitutionPickerViewModelTest.kt | 25 ++++++------ ...inancialConnectionsSheetNativeStateTest.kt | 6 ++- ...cialConnectionsSheetNativeViewModelTest.kt | 35 +++++++++-------- 6 files changed, 84 insertions(+), 52 deletions(-) create mode 100644 financial-connections/src/test/java/com/stripe/android/financialconnections/CoroutineTestRule.kt diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/FinancialConnectionsSheetActivity.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/FinancialConnectionsSheetActivity.kt index 18b9083f5f4..a2da71d0b30 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/FinancialConnectionsSheetActivity.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/FinancialConnectionsSheetActivity.kt @@ -113,9 +113,11 @@ internal class FinancialConnectionsSheetActivity : AppCompatActivity() { ) is FinishWithResult -> { - viewEffect.finishToast?.let { + viewEffect.finishToast?.let { resId -> Toast.makeText( - this@FinancialConnectionsSheetActivity, it, Toast.LENGTH_LONG + this@FinancialConnectionsSheetActivity, + resId, + Toast.LENGTH_LONG ).show() } finishWithResult(viewEffect.result) 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 new file mode 100644 index 00000000000..fdf557caa3f --- /dev/null +++ b/financial-connections/src/test/java/com/stripe/android/financialconnections/CoroutineTestRule.kt @@ -0,0 +1,25 @@ +package com.stripe.android.financialconnections + +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.TestDispatcher +import kotlinx.coroutines.test.resetMain +import kotlinx.coroutines.test.setMain +import org.junit.rules.TestWatcher +import org.junit.runner.Description + +@ExperimentalCoroutinesApi +class CoroutineTestRule( + private val testDispatcher: TestDispatcher, +) : TestWatcher() { + + override fun starting(description: Description) { + super.starting(description) + Dispatchers.setMain(testDispatcher) + } + + override fun finished(description: Description) { + Dispatchers.resetMain() + super.finished(description) + } +} diff --git a/financial-connections/src/test/java/com/stripe/android/financialconnections/FinancialConnectionsSheetViewModelTest.kt b/financial-connections/src/test/java/com/stripe/android/financialconnections/FinancialConnectionsSheetViewModelTest.kt index 9206bbc1a30..811e24970dc 100644 --- a/financial-connections/src/test/java/com/stripe/android/financialconnections/FinancialConnectionsSheetViewModelTest.kt +++ b/financial-connections/src/test/java/com/stripe/android/financialconnections/FinancialConnectionsSheetViewModelTest.kt @@ -2,9 +2,8 @@ package com.stripe.android.financialconnections import android.content.Intent import android.net.Uri +import androidx.lifecycle.SavedStateHandle import androidx.test.ext.junit.runners.AndroidJUnit4 -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.core.exception.APIException @@ -34,6 +33,7 @@ import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.runTest import org.junit.Rule import org.junit.Test +import org.junit.rules.TestRule import org.junit.runner.RunWith import org.mockito.kotlin.any import org.mockito.kotlin.eq @@ -47,7 +47,7 @@ import org.mockito.kotlin.whenever class FinancialConnectionsSheetViewModelTest { @get:Rule - val mavericksRule = MavericksTestRule(testDispatcher = UnconfinedTestDispatcher()) + val rule: TestRule = CoroutineTestRule(UnconfinedTestDispatcher()) private val eventReporter = mock() private val configuration = FinancialConnectionsSheet.Configuration( @@ -65,7 +65,8 @@ class FinancialConnectionsSheetViewModelTest { private val synchronizeFinancialConnectionsSession = mock() private val defaultInitialState = FinancialConnectionsSheetState( - FinancialConnectionsSheetActivityArgs.ForData(configuration) + args = FinancialConnectionsSheetActivityArgs.ForData(configuration), + savedState = null ) @Test @@ -105,7 +106,7 @@ class FinancialConnectionsSheetViewModelTest { val viewModel = createViewModel(defaultInitialState) // Then - withState(viewModel) { + viewModel.stateFlow.value.let { assertThat(it.webAuthFlowStatus).isEqualTo(AuthFlowStatus.NONE) require(it.viewEffect is FinishWithResult) require(it.viewEffect.result is Failed) @@ -160,7 +161,7 @@ class FinancialConnectionsSheetViewModelTest { ) // Then - withState(viewModel) { + viewModel.stateFlow.value.let { assertThat(it.webAuthFlowStatus).isEqualTo(AuthFlowStatus.NONE) val viewEffect = it.viewEffect as FinishWithResult assertThat(viewEffect.result).isEqualTo( @@ -188,7 +189,7 @@ class FinancialConnectionsSheetViewModelTest { ) // Then - withState(viewModel) { + viewModel.stateFlow.value.let { val viewEffect = it.viewEffect as FinishWithResult assertThat(viewEffect.result).isInstanceOf(Failed::class.java) } @@ -232,8 +233,7 @@ class FinancialConnectionsSheetViewModelTest { // end auth flow viewModel.handleOnNewIntent(cancelIntent()) - // Then - withState(viewModel) { + viewModel.stateFlow.value.let { assertThat(it.webAuthFlowStatus).isEqualTo(AuthFlowStatus.NONE) assertThat(it.viewEffect).isEqualTo(FinishWithResult(Canceled)) } @@ -260,7 +260,7 @@ class FinancialConnectionsSheetViewModelTest { viewModel.handleOnNewIntent(cancelIntent()) // Then - withState(viewModel) { + viewModel.stateFlow.value.let { require(it.viewEffect is FinishWithResult) require(it.viewEffect.result is Failed) assertThat(it.viewEffect.result.error).isInstanceOf(CustomManualEntryRequiredError::class.java) @@ -281,7 +281,7 @@ class FinancialConnectionsSheetViewModelTest { viewModel.handleOnNewIntent(errorIntent) // Then - withState(viewModel) { + viewModel.stateFlow.value.let { assertThat(it.webAuthFlowStatus).isEqualTo(AuthFlowStatus.NONE) val viewEffect = it.viewEffect as FinishWithResult assertThat(viewEffect.result).isInstanceOf(Failed::class.java) @@ -304,7 +304,7 @@ class FinancialConnectionsSheetViewModelTest { viewModel.handleOnNewIntent(successIntent()) // Then - withState(viewModel) { + viewModel.stateFlow.value.let { assertThat(it.webAuthFlowStatus).isEqualTo(AuthFlowStatus.NONE) val viewEffect = it.viewEffect as FinishWithResult assertThat(viewEffect.result).isEqualTo( @@ -331,7 +331,7 @@ class FinancialConnectionsSheetViewModelTest { viewModel.handleOnNewIntent(Intent().apply { data = Uri.parse(nativeRedirectUrl) }) // Then - withState(viewModel) { + viewModel.stateFlow.value.let { assertThat(it.webAuthFlowStatus).isEqualTo(AuthFlowStatus.INTERMEDIATE_DEEPLINK) val viewEffect = it.viewEffect as OpenAuthFlowWithUrl assertThat(viewEffect.url).isEqualTo(aggregatorUrl) @@ -357,7 +357,7 @@ class FinancialConnectionsSheetViewModelTest { viewModel.handleOnNewIntent(Intent().apply { data = Uri.parse(returnUrl) }) // Then - withState(viewModel) { + viewModel.stateFlow.value.let { assertThat(it.webAuthFlowStatus).isEqualTo(AuthFlowStatus.INTERMEDIATE_DEEPLINK) val viewEffect = it.viewEffect as OpenAuthFlowWithUrl assertThat(viewEffect.url).isEqualTo( @@ -381,7 +381,7 @@ class FinancialConnectionsSheetViewModelTest { viewModel.handleOnNewIntent(successIntent()) // Then - withState(viewModel) { + viewModel.stateFlow.value.let { assertThat(it.webAuthFlowStatus).isEqualTo(AuthFlowStatus.NONE) val viewEffect = it.viewEffect as FinishWithResult assertThat(viewEffect.result).isEqualTo(Failed(apiException)) @@ -402,7 +402,7 @@ class FinancialConnectionsSheetViewModelTest { // Then // Then - withState(viewModel) { + viewModel.stateFlow.value.let { assertThat(it.webAuthFlowStatus).isEqualTo(AuthFlowStatus.NONE) val viewEffect = it.viewEffect as FinishWithResult assertThat(viewEffect.result).isEqualTo(Failed(APIException())) @@ -429,7 +429,7 @@ class FinancialConnectionsSheetViewModelTest { viewModel.onResume() // Then - withState(viewModel) { + viewModel.stateFlow.value.let { assertThat(it.webAuthFlowStatus).isEqualTo(AuthFlowStatus.ON_EXTERNAL_ACTIVITY) val viewEffect = it.viewEffect as FinishWithResult assertThat(viewEffect.result).isEqualTo(Canceled) @@ -456,7 +456,7 @@ class FinancialConnectionsSheetViewModelTest { viewModel.onBrowserActivityResult() // Then - withState(viewModel) { + viewModel.stateFlow.value.let { assertThat(it.webAuthFlowStatus).isEqualTo(AuthFlowStatus.ON_EXTERNAL_ACTIVITY) val viewEffect = it.viewEffect as FinishWithResult assertThat(viewEffect.result).isEqualTo(Canceled) @@ -476,7 +476,7 @@ class FinancialConnectionsSheetViewModelTest { val viewModel = createViewModel(defaultInitialState) // Then - withState(viewModel) { assertThat(it.manifest).isEqualTo(syncResponse.manifest) } + assertThat(viewModel.stateFlow.value.manifest).isEqualTo(syncResponse.manifest) } } @@ -517,6 +517,7 @@ class FinancialConnectionsSheetViewModelTest { nativeRouter = mock(), analyticsTracker = analyticsTracker, browserManager = browserManager, + savedStateHandle = SavedStateHandle(), logger = Logger.noop() ) } diff --git a/financial-connections/src/test/java/com/stripe/android/financialconnections/features/institutionpicker/InstitutionPickerViewModelTest.kt b/financial-connections/src/test/java/com/stripe/android/financialconnections/features/institutionpicker/InstitutionPickerViewModelTest.kt index 475f85539ee..fa8de8eb624 100644 --- a/financial-connections/src/test/java/com/stripe/android/financialconnections/features/institutionpicker/InstitutionPickerViewModelTest.kt +++ b/financial-connections/src/test/java/com/stripe/android/financialconnections/features/institutionpicker/InstitutionPickerViewModelTest.kt @@ -1,12 +1,11 @@ package com.stripe.android.financialconnections.features.institutionpicker -import com.airbnb.mvrx.Uninitialized -import com.airbnb.mvrx.test.MavericksTestRule -import com.airbnb.mvrx.withState import com.stripe.android.core.Logger import com.stripe.android.financialconnections.ApiKeyFixtures +import com.stripe.android.financialconnections.CoroutineTestRule import com.stripe.android.financialconnections.FinancialConnectionsSheet import com.stripe.android.financialconnections.TestFinancialConnectionsAnalyticsTracker +import com.stripe.android.financialconnections.core.Result import com.stripe.android.financialconnections.domain.FeaturedInstitutions import com.stripe.android.financialconnections.domain.GetOrFetchSync import com.stripe.android.financialconnections.domain.PostAuthorizationSession @@ -22,10 +21,12 @@ 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.UnconfinedTestDispatcher import kotlinx.coroutines.test.advanceUntilIdle import kotlinx.coroutines.test.runTest import org.junit.Rule import org.junit.Test +import org.junit.rules.TestRule import org.mockito.kotlin.any import org.mockito.kotlin.mock import org.mockito.kotlin.verifyNoInteractions @@ -38,7 +39,7 @@ import kotlin.test.assertTrue internal class InstitutionPickerViewModelTest { @get:Rule - val mavericksTestRule = MavericksTestRule() + val rule: TestRule = CoroutineTestRule(UnconfinedTestDispatcher()) private val searchInstitutions = mock() private val featuredInstitutions = mock() @@ -92,9 +93,9 @@ internal class InstitutionPickerViewModelTest { val viewModel = buildViewModel(InstitutionPickerState()) - withState(viewModel) { state -> + viewModel.stateFlow.value.let { state -> assertEquals(state.payload()!!.featuredInstitutions, institutionResponse) - assertIs(state.searchInstitutions) + assertIs(state.searchInstitutions) } } @@ -108,10 +109,8 @@ internal class InstitutionPickerViewModelTest { val viewModel = buildViewModel(InstitutionPickerState()) - withState(viewModel) { state -> - // payload with empty list - assertTrue(state.payload()!!.featuredInstitutions.data.isEmpty()) - } + // payload with empty list + assertTrue(viewModel.stateFlow.value.payload()!!.featuredInstitutions.data.isEmpty()) } @Test @@ -121,7 +120,7 @@ internal class InstitutionPickerViewModelTest { val viewModel = buildViewModel(InstitutionPickerState()) - withState(viewModel) { state -> + viewModel.stateFlow.value.let { state -> assertTrue(state.payload() == null) handleError.assertError( error = error, @@ -170,7 +169,7 @@ internal class InstitutionPickerViewModelTest { viewModel.onQueryChanged(query) advanceUntilIdle() - withState(viewModel) { state -> + viewModel.stateFlow.value.let { state -> assertEquals(state.payload()!!.featuredInstitutions, featuredResults) assertEquals(state.searchInstitutions()!!, searchResults) eventTracker.assertContainsEvent( @@ -193,7 +192,7 @@ internal class InstitutionPickerViewModelTest { viewModel.onQueryChanged(query) advanceUntilIdle() - withState(viewModel) { state -> + viewModel.stateFlow.value.let { state -> verifyNoInteractions(searchInstitutions) assertTrue(eventTracker.sentEvents.none { it.eventName == "linked_accounts.search.succeeded" }) assertEquals(state.searchInstitutions()!!.data, emptyList()) diff --git a/financial-connections/src/test/java/com/stripe/android/financialconnections/presentation/FinancialConnectionsSheetNativeStateTest.kt b/financial-connections/src/test/java/com/stripe/android/financialconnections/presentation/FinancialConnectionsSheetNativeStateTest.kt index 166f1c60cb2..af092b6a84a 100644 --- a/financial-connections/src/test/java/com/stripe/android/financialconnections/presentation/FinancialConnectionsSheetNativeStateTest.kt +++ b/financial-connections/src/test/java/com/stripe/android/financialconnections/presentation/FinancialConnectionsSheetNativeStateTest.kt @@ -24,7 +24,8 @@ internal class FinancialConnectionsSheetNativeStateTest { reducedManualEntryProminenceInErrors = false, merchantLogos = emptyList() ) - ) + ), + savedState = null ).reducedBranding, ).isTrue() } @@ -39,7 +40,8 @@ internal class FinancialConnectionsSheetNativeStateTest { reducedManualEntryProminenceInErrors = false, merchantLogos = emptyList() ) - ) + ), + savedState = null ).reducedBranding, ).isFalse() } diff --git a/financial-connections/src/test/java/com/stripe/android/financialconnections/presentation/FinancialConnectionsSheetNativeViewModelTest.kt b/financial-connections/src/test/java/com/stripe/android/financialconnections/presentation/FinancialConnectionsSheetNativeViewModelTest.kt index cb64b9551f3..209703dfe22 100644 --- a/financial-connections/src/test/java/com/stripe/android/financialconnections/presentation/FinancialConnectionsSheetNativeViewModelTest.kt +++ b/financial-connections/src/test/java/com/stripe/android/financialconnections/presentation/FinancialConnectionsSheetNativeViewModelTest.kt @@ -2,13 +2,13 @@ package com.stripe.android.financialconnections.presentation import android.content.Intent import android.net.Uri +import androidx.lifecycle.SavedStateHandle import androidx.test.ext.junit.runners.AndroidJUnit4 -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 import com.stripe.android.financialconnections.ApiKeyFixtures.financialConnectionsSessionNoAccounts +import com.stripe.android.financialconnections.CoroutineTestRule import com.stripe.android.financialconnections.FinancialConnections import com.stripe.android.financialconnections.FinancialConnectionsSheet import com.stripe.android.financialconnections.analytics.FinancialConnectionsEvent @@ -38,6 +38,7 @@ import org.junit.After import org.junit.Before import org.junit.Rule import org.junit.Test +import org.junit.rules.TestRule import org.junit.runner.RunWith import org.mockito.kotlin.any import org.mockito.kotlin.anyOrNull @@ -50,7 +51,7 @@ import kotlin.test.assertIs internal class FinancialConnectionsSheetNativeViewModelTest { @get:Rule - val mavericksTestRule = MavericksTestRule(testDispatcher = UnconfinedTestDispatcher()) + val rule: TestRule = CoroutineTestRule(UnconfinedTestDispatcher()) private val nativeAuthFlowCoordinator = mock() private val completeFinancialConnectionsSession = mock() @@ -87,7 +88,7 @@ internal class FinancialConnectionsSheetNativeViewModelTest { messagesFlow.emit(Complete(EarlyTerminationCause.USER_INITIATED_WITH_CUSTOM_MANUAL_ENTRY)) - withState(viewModel) { + viewModel.stateFlow.value.let { require(it.viewEffect is Finish) require(it.viewEffect.result is Failed) assertThat(it.viewEffect.result.error).isInstanceOf(CustomManualEntryRequiredError::class.java) @@ -107,7 +108,7 @@ internal class FinancialConnectionsSheetNativeViewModelTest { messagesFlow.emit(Complete(null)) - withState(viewModel) { + viewModel.stateFlow.value.let { require(it.viewEffect is Finish) require(it.viewEffect.result is Completed) } @@ -133,7 +134,7 @@ internal class FinancialConnectionsSheetNativeViewModelTest { messagesFlow.emit(Complete(null)) - withState(viewModel) { + viewModel.stateFlow.value.let { require(it.viewEffect is Finish) require(it.viewEffect.result is Canceled) } @@ -165,7 +166,7 @@ internal class FinancialConnectionsSheetNativeViewModelTest { messagesFlow.emit(Complete(null)) - withState(viewModel) { + viewModel.stateFlow.value.let { require(it.viewEffect is Finish) require(it.viewEffect.result is Failed) } @@ -186,7 +187,7 @@ internal class FinancialConnectionsSheetNativeViewModelTest { val intent = intent("stripe://auth-redirect/$applicationId?status=success") viewModel.handleOnNewIntent(intent) - withState(viewModel) { + viewModel.stateFlow.value.let { assertThat(it.webAuthFlow).isEqualTo(WebAuthFlowState.Success(intent.data!!.toString())) } } @@ -201,7 +202,7 @@ internal class FinancialConnectionsSheetNativeViewModelTest { ) viewModel.handleOnNewIntent(intent) - withState(viewModel) { + viewModel.stateFlow.value.let { val webAuthFlow = it.webAuthFlow assertIs(webAuthFlow) assertThat(webAuthFlow.reason).isEqualTo(errorReason) @@ -217,7 +218,7 @@ internal class FinancialConnectionsSheetNativeViewModelTest { ) viewModel.handleOnNewIntent(intent) - withState(viewModel) { + viewModel.stateFlow.value.let { val webAuthFlow = it.webAuthFlow assertIs(webAuthFlow) } @@ -232,7 +233,7 @@ internal class FinancialConnectionsSheetNativeViewModelTest { ) viewModel.handleOnNewIntent(intent) - withState(viewModel) { + viewModel.stateFlow.value.let { val webAuthFlow = it.webAuthFlow assertIs(webAuthFlow) } @@ -245,7 +246,7 @@ internal class FinancialConnectionsSheetNativeViewModelTest { val intent = intent("stripe://auth-redirect/$applicationId?status=unknown") viewModel.handleOnNewIntent(intent) - withState(viewModel) { + viewModel.stateFlow.value.let { val webAuthFlow = it.webAuthFlow assertIs(webAuthFlow) } @@ -258,7 +259,7 @@ internal class FinancialConnectionsSheetNativeViewModelTest { val intent = intent("stripe://auth-redirect/$applicationId?status=cancel") viewModel.handleOnNewIntent(intent) - withState(viewModel) { + viewModel.stateFlow.value.let { val webAuthFlow = it.webAuthFlow assertIs(webAuthFlow) } @@ -271,7 +272,7 @@ internal class FinancialConnectionsSheetNativeViewModelTest { val intent = intent("stripe://auth-redirect/other-app-id?code=success") viewModel.handleOnNewIntent(intent) - withState(viewModel) { + viewModel.stateFlow.value.let { val webAuthFlow = it.webAuthFlow assertIs(webAuthFlow) } @@ -286,10 +287,11 @@ internal class FinancialConnectionsSheetNativeViewModelTest { private fun createViewModel( initialState: FinancialConnectionsSheetNativeState = FinancialConnectionsSheetNativeState( - FinancialConnectionsSheetNativeActivityArgs( + args = FinancialConnectionsSheetNativeActivityArgs( configuration = configuration, initialSyncResponse = ApiKeyFixtures.syncResponse(), - ) + ), + savedState = null ) ) = FinancialConnectionsSheetNativeViewModel( eventTracker = mock(), @@ -300,6 +302,7 @@ internal class FinancialConnectionsSheetNativeViewModelTest { nativeAuthFlowCoordinator = nativeAuthFlowCoordinator, logger = mock(), navigationManager = TestNavigationManager(), + savedStateHandle = SavedStateHandle(), initialState = initialState ) } From f1d8ca2f6c952445c5bf11ea92e4e2257f1c6e19 Mon Sep 17 00:00:00 2001 From: "Carlos M." Date: Thu, 21 Mar 2024 11:12:53 -0700 Subject: [PATCH 19/28] Regenerates API. --- .../core/{ComposeUtils.kt => ComposeExtensions.kt} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename financial-connections/src/main/java/com/stripe/android/financialconnections/core/{ComposeUtils.kt => ComposeExtensions.kt} (95%) diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/core/ComposeUtils.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/core/ComposeExtensions.kt similarity index 95% rename from financial-connections/src/main/java/com/stripe/android/financialconnections/core/ComposeUtils.kt rename to financial-connections/src/main/java/com/stripe/android/financialconnections/core/ComposeExtensions.kt index d9b84cac350..020e8080f50 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/core/ComposeUtils.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/core/ComposeExtensions.kt @@ -59,7 +59,7 @@ private fun extractActivityFromContext(context: Context): ComponentActivity? { */ @SuppressLint("StateFlowValueCalledInComposition") @Composable -fun , S, A> VM.collectAsState(prop1: KProperty1): State { +internal fun , S, A> VM.collectAsState(prop1: KProperty1): State { val mappedFlow = remember(prop1) { stateFlow.map { prop1.get(it) }.distinctUntilChanged() } return mappedFlow.collectAsState(initial = prop1.get(stateFlow.value)) } From 35bcd359db00518ccd50fb04d6b5471f7403c5d4 Mon Sep 17 00:00:00 2001 From: "Carlos M." Date: Thu, 21 Mar 2024 16:35:06 -0700 Subject: [PATCH 20/28] filterNotNull. --- .../financialconnections/FinancialConnectionsSheetActivity.kt | 3 ++- .../ui/FinancialConnectionsSheetNativeActivity.kt | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/FinancialConnectionsSheetActivity.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/FinancialConnectionsSheetActivity.kt index a2da71d0b30..11946f3bf9b 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/FinancialConnectionsSheetActivity.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/FinancialConnectionsSheetActivity.kt @@ -32,6 +32,7 @@ import com.stripe.android.financialconnections.ui.FinancialConnectionsSheetNativ import com.stripe.android.financialconnections.ui.theme.FinancialConnectionsTheme import com.stripe.android.financialconnections.utils.argsOrNull import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch @@ -103,8 +104,8 @@ internal class FinancialConnectionsSheetActivity : AppCompatActivity() { viewModel.stateFlow .map { it.viewEffect } .distinctUntilChanged() + .filterNotNull() .collect { viewEffect -> - if (viewEffect == null) return@collect when (viewEffect) { is OpenAuthFlowWithUrl -> startBrowserForResult.launch( browserManager.createBrowserIntentForUrl( diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/ui/FinancialConnectionsSheetNativeActivity.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/ui/FinancialConnectionsSheetNativeActivity.kt index 1838b990b07..a42b67bd838 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/ui/FinancialConnectionsSheetNativeActivity.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/ui/FinancialConnectionsSheetNativeActivity.kt @@ -54,6 +54,7 @@ import com.stripe.android.financialconnections.utils.rememberKeyboardController import com.stripe.android.uicore.image.StripeImageLoader import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach @@ -103,8 +104,8 @@ internal class FinancialConnectionsSheetNativeActivity : AppCompatActivity() { viewModel.stateFlow .map { it.viewEffect } .distinctUntilChanged() + .filterNotNull() .collect { viewEffect -> - if (viewEffect == null) return@collect when (viewEffect) { is OpenUrl -> startActivity( browserManager.createBrowserIntentForUrl(uri = Uri.parse(viewEffect.url)) From 0f39b41568b34605bc8c295238425a6d3011e72a Mon Sep 17 00:00:00 2001 From: "Carlos M." Date: Thu, 21 Mar 2024 16:40:02 -0700 Subject: [PATCH 21/28] Nits. --- .../core/ComposeExtensions.kt | 23 +++---------------- .../core/FinancialConnectionsViewModel.kt | 9 ++++---- .../stripe/android/core/utils/ContextUtils.kt | 17 ++++++++++++++ 3 files changed, 25 insertions(+), 24 deletions(-) diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/core/ComposeExtensions.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/core/ComposeExtensions.kt index 020e8080f50..5303a158636 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/core/ComposeExtensions.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/core/ComposeExtensions.kt @@ -1,9 +1,6 @@ package com.stripe.android.financialconnections.core import android.annotation.SuppressLint -import android.content.Context -import android.content.ContextWrapper -import androidx.activity.ComponentActivity import androidx.compose.runtime.Composable import androidx.compose.runtime.State import androidx.compose.runtime.collectAsState @@ -11,6 +8,7 @@ import androidx.compose.runtime.remember import androidx.compose.ui.platform.LocalContext import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.viewmodel.compose.viewModel +import com.stripe.android.core.utils.ContextUtils.extractActivityFromContext import com.stripe.android.financialconnections.di.FinancialConnectionsSheetNativeComponent import com.stripe.android.financialconnections.ui.FinancialConnectionsSheetNativeActivity import kotlinx.coroutines.flow.distinctUntilChanged @@ -34,21 +32,6 @@ internal fun parentActivity(): FinancialConnectionsSheetNativeActivity { return extractActivityFromContext(LocalContext.current) as FinancialConnectionsSheetNativeActivity } -private fun extractActivityFromContext(context: Context): ComponentActivity? { - var currentContext = context - if (currentContext is ComponentActivity) { - return currentContext - } else { - while (currentContext is ContextWrapper) { - if (currentContext is ComponentActivity) { - return currentContext - } - currentContext = currentContext.baseContext - } - } - return null -} - /** * Creates a Compose State variable that will only update when the value of this property changes. * Prefer this to subscribing to entire state classes which will trigger a recomposition whenever @@ -57,9 +40,9 @@ private fun extractActivityFromContext(context: Context): ComponentActivity? { * If you find yourself subscribing to many state properties in a single composable, * consider breaking it up into smaller ones. */ -@SuppressLint("StateFlowValueCalledInComposition") @Composable internal fun , S, A> VM.collectAsState(prop1: KProperty1): State { val mappedFlow = remember(prop1) { stateFlow.map { prop1.get(it) }.distinctUntilChanged() } - return mappedFlow.collectAsState(initial = prop1.get(stateFlow.value)) + val initialValue = remember { stateFlow.value } + return mappedFlow.collectAsState(initial = prop1.get(initialValue)) } diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/core/FinancialConnectionsViewModel.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/core/FinancialConnectionsViewModel.kt index b0cc7aea918..a95d8d7e7b0 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/core/FinancialConnectionsViewModel.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/core/FinancialConnectionsViewModel.kt @@ -7,6 +7,7 @@ import com.stripe.android.financialconnections.core.Result.Loading import com.stripe.android.financialconnections.core.Result.Success import kotlinx.coroutines.Job import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch @@ -14,7 +15,9 @@ internal abstract class FinancialConnectionsViewModel( initialState: S ) : ViewModel() { - val stateFlow: MutableStateFlow = MutableStateFlow(initialState) + private val _stateFlow: MutableStateFlow = MutableStateFlow(initialState) + val stateFlow: StateFlow = _stateFlow + protected open fun (suspend () -> T).execute( reducer: S.(Result) -> S, @@ -38,9 +41,7 @@ internal abstract class FinancialConnectionsViewModel( } } - protected fun setState(reducer: S.() -> S) { - stateFlow.update { state -> state.reducer() } - } + protected fun setState(reducer: S.() -> S) = _stateFlow.update(reducer) } internal sealed class Result( diff --git a/stripe-core/src/main/java/com/stripe/android/core/utils/ContextUtils.kt b/stripe-core/src/main/java/com/stripe/android/core/utils/ContextUtils.kt index aebd8533925..17f2933ddec 100644 --- a/stripe-core/src/main/java/com/stripe/android/core/utils/ContextUtils.kt +++ b/stripe-core/src/main/java/com/stripe/android/core/utils/ContextUtils.kt @@ -1,8 +1,10 @@ package com.stripe.android.core.utils import android.content.Context +import android.content.ContextWrapper import android.content.pm.PackageInfo import androidx.annotation.RestrictTo +import androidx.core.app.ComponentActivity @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) object ContextUtils { @@ -11,4 +13,19 @@ object ContextUtils { get() = runCatching { packageManager.getPackageInfo(packageName, 0) }.getOrNull() + + fun extractActivityFromContext(context: Context): ComponentActivity? { + var currentContext = context + if (currentContext is ComponentActivity) { + return currentContext + } else { + while (currentContext is ContextWrapper) { + if (currentContext is ComponentActivity) { + return currentContext + } + currentContext = currentContext.baseContext + } + } + return null + } } From 59a645cff11752674ca3a11cfe949db1744a7000 Mon Sep 17 00:00:00 2001 From: "Carlos M." Date: Thu, 21 Mar 2024 16:45:31 -0700 Subject: [PATCH 22/28] Updates async. --- financial-connections/detekt-baseline.xml | 4 ++-- .../core/ComposeExtensions.kt | 1 - .../core/FinancialConnectionsViewModel.kt | 19 +++++++++---------- .../ConsentPreviewParameterProvider.kt | 2 +- .../features/consent/ConsentScreen.kt | 16 ++++++++-------- .../features/consent/ConsentState.kt | 6 +++--- ...stitutionPickerPreviewParameterProvider.kt | 8 ++++---- .../InstitutionPickerScreen.kt | 18 +++++++++--------- .../InstitutionPickerViewModel.kt | 12 ++++++------ .../utils/MavericksExtensions.kt | 10 +++++----- .../InstitutionPickerViewModelTest.kt | 4 ++-- ...PayResultTest.kt => GooglePayAsyncTest.kt} | 2 +- 12 files changed, 50 insertions(+), 52 deletions(-) rename payments-core/src/test/java/com/stripe/android/model/{GooglePayResultTest.kt => GooglePayAsyncTest.kt} (98%) diff --git a/financial-connections/detekt-baseline.xml b/financial-connections/detekt-baseline.xml index e603a24b609..099fdef0d71 100644 --- a/financial-connections/detekt-baseline.xml +++ b/financial-connections/detekt-baseline.xml @@ -5,7 +5,7 @@ ConstructorParameterNaming:FinancialConnectionsAuthorizationSession.kt$FinancialConnectionsAuthorizationSession$@SerialName(value = "is_oauth") private val _isOAuth: Boolean? = false ConstructorParameterNaming:PartnerAccountsList.kt$PartnerAccount$@SerialName(value = "allow_selection") private val _allowSelection: Boolean? = null LongMethod:AccountItem.kt$@Composable @Preview internal fun AccountItemPreview() - LongMethod:InstitutionPickerScreen.kt$private fun LazyListScope.searchResults( isInputEmpty: Boolean, payload: Payload, selectedInstitutionId: String?, onInstitutionSelected: (FinancialConnectionsInstitution, Boolean) -> Unit, institutions: Result<InstitutionResponse>, onManualEntryClick: () -> Unit, onSearchMoreClick: () -> Unit ) + LongMethod:InstitutionPickerScreen.kt$private fun LazyListScope.searchResults( isInputEmpty: Boolean, payload: Payload, selectedInstitutionId: String?, onInstitutionSelected: (FinancialConnectionsInstitution, Boolean) -> Unit, institutions: Async<InstitutionResponse>, onManualEntryClick: () -> Unit, onSearchMoreClick: () -> Unit ) LongMethod:LinkAccountPickerPreviewParameterProvider.kt$LinkAccountPickerPreviewParameterProvider$private fun partnerAccountList() MagicNumber:AccountPickerScreen.kt$3 MagicNumber:ConsentLogoHeader.kt$3 @@ -30,7 +30,7 @@ MaximumLineLength:com.stripe.android.financialconnections.presentation.FinancialConnectionsUrls.kt:41 MaximumLineLength:com.stripe.android.financialconnections.presentation.FinancialConnectionsUrls.kt:46 MaximumLineLength:com.stripe.android.financialconnections.presentation.FinancialConnectionsUrls.kt:9 - NestedBlockDepth:InstitutionPickerScreen.kt$private fun LazyListScope.searchResults( isInputEmpty: Boolean, payload: Payload, selectedInstitutionId: String?, onInstitutionSelected: (FinancialConnectionsInstitution, Boolean) -> Unit, institutions: Result<InstitutionResponse>, onManualEntryClick: () -> Unit, onSearchMoreClick: () -> Unit ) + NestedBlockDepth:InstitutionPickerScreen.kt$private fun LazyListScope.searchResults( isInputEmpty: Boolean, payload: Payload, selectedInstitutionId: String?, onInstitutionSelected: (FinancialConnectionsInstitution, Boolean) -> Unit, institutions: Async<InstitutionResponse>, onManualEntryClick: () -> Unit, onSearchMoreClick: () -> Unit ) SwallowedException:PollAttachPaymentAccount.kt$PollAttachPaymentAccount$e: StripeException SwallowedException:PollAuthorizationSessionAccounts.kt$PollAuthorizationSessionAccounts$e: StripeException SwallowedException:PostAuthorizationSession.kt$PostAuthorizationSession$e: StripeException diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/core/ComposeExtensions.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/core/ComposeExtensions.kt index 5303a158636..b53f9c7b838 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/core/ComposeExtensions.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/core/ComposeExtensions.kt @@ -1,6 +1,5 @@ package com.stripe.android.financialconnections.core -import android.annotation.SuppressLint import androidx.compose.runtime.Composable import androidx.compose.runtime.State import androidx.compose.runtime.collectAsState diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/core/FinancialConnectionsViewModel.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/core/FinancialConnectionsViewModel.kt index a95d8d7e7b0..fda205b5144 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/core/FinancialConnectionsViewModel.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/core/FinancialConnectionsViewModel.kt @@ -2,9 +2,9 @@ package com.stripe.android.financialconnections.core import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.stripe.android.financialconnections.core.Result.Fail -import com.stripe.android.financialconnections.core.Result.Loading -import com.stripe.android.financialconnections.core.Result.Success +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 kotlinx.coroutines.Job import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow @@ -18,9 +18,8 @@ internal abstract class FinancialConnectionsViewModel( private val _stateFlow: MutableStateFlow = MutableStateFlow(initialState) val stateFlow: StateFlow = _stateFlow - protected open fun (suspend () -> T).execute( - reducer: S.(Result) -> S, + reducer: S.(Async) -> S, onSuccess: (T) -> Unit = {}, onFail: (Throwable) -> Unit = {} ): Job { @@ -44,15 +43,15 @@ internal abstract class FinancialConnectionsViewModel( protected fun setState(reducer: S.() -> S) = _stateFlow.update(reducer) } -internal sealed class Result( +internal sealed class Async( private val value: T? ) { - data object Uninitialized : Result(value = null) - data object Loading : Result(value = null) - data class Success(val value: T) : Result(value = value) { + data object Uninitialized : Async(value = null) + data object Loading : Async(value = null) + data class Success(private val value: T) : Async(value = value) { override operator fun invoke(): T = value } - data class Fail(val error: Throwable) : Result(value = null) + data class Fail(val error: Throwable) : Async(value = null) open operator fun invoke(): T? = value } diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentPreviewParameterProvider.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentPreviewParameterProvider.kt index eebf7129600..a95fa1ae314 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentPreviewParameterProvider.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentPreviewParameterProvider.kt @@ -3,7 +3,7 @@ package com.stripe.android.financialconnections.features.consent import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.material.ModalBottomSheetValue import androidx.compose.ui.tooling.preview.PreviewParameterProvider -import com.stripe.android.financialconnections.core.Result.Success +import com.stripe.android.financialconnections.core.Async.Success import com.stripe.android.financialconnections.model.Bullet import com.stripe.android.financialconnections.model.ConnectedAccessNotice import com.stripe.android.financialconnections.model.ConsentPane diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentScreen.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentScreen.kt index c906e561f11..256235b7d4c 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentScreen.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentScreen.kt @@ -31,11 +31,11 @@ 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.stripe.android.financialconnections.core.Result -import com.stripe.android.financialconnections.core.Result.Fail -import com.stripe.android.financialconnections.core.Result.Loading -import com.stripe.android.financialconnections.core.Result.Success -import com.stripe.android.financialconnections.core.Result.Uninitialized +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.DataAccessBottomSheetContent import com.stripe.android.financialconnections.features.common.LegalDetailsBottomSheetContent @@ -148,7 +148,7 @@ private fun ConsentLoadingContent() { @Composable private fun ConsentMainContent( payload: ConsentState.Payload, - acceptConsent: Result, + acceptConsent: Async, onClickableTextClick: (String) -> Unit, onContinueClick: () -> Unit, onCloseClick: () -> Unit @@ -231,7 +231,7 @@ private fun LazyListScope.consentBody( private fun LoadedContent( payload: ConsentState.Payload, bottomSheetState: ModalBottomSheetState, - acceptConsent: Result, + acceptConsent: Async, onContinueClick: () -> Unit, onCloseClick: () -> Unit, onClickableTextClick: (String) -> Unit, @@ -272,7 +272,7 @@ private fun LoadedContent( @OptIn(ExperimentalComposeUiApi::class) @Composable private fun ConsentFooter( - acceptConsent: Result, + acceptConsent: Async, consent: ConsentPane, onClickableTextClick: (String) -> Unit, onContinueClick: () -> Unit, diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentState.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentState.kt index ea061b56347..b2eb24f1718 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentState.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentState.kt @@ -1,14 +1,14 @@ package com.stripe.android.financialconnections.features.consent -import com.stripe.android.financialconnections.core.Result +import com.stripe.android.financialconnections.core.Async import com.stripe.android.financialconnections.model.ConsentPane import com.stripe.android.financialconnections.model.FinancialConnectionsSessionManifest internal data class ConsentState( - val consent: Result = Result.Uninitialized, + val consent: Async = Async.Uninitialized, val merchantLogos: List = emptyList(), val currentBottomSheet: BottomSheetContent = BottomSheetContent.DATA, - val acceptConsent: Result = Result.Uninitialized, + val acceptConsent: Async = Async.Uninitialized, val viewEffect: ViewEffect? = null ) { diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/institutionpicker/InstitutionPickerPreviewParameterProvider.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/institutionpicker/InstitutionPickerPreviewParameterProvider.kt index d29575f1b2c..6dcddd6ba62 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/institutionpicker/InstitutionPickerPreviewParameterProvider.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/institutionpicker/InstitutionPickerPreviewParameterProvider.kt @@ -1,10 +1,10 @@ package com.stripe.android.financialconnections.features.institutionpicker import androidx.compose.ui.tooling.preview.PreviewParameterProvider -import com.stripe.android.financialconnections.core.Result.Fail -import com.stripe.android.financialconnections.core.Result.Loading -import com.stripe.android.financialconnections.core.Result.Success -import com.stripe.android.financialconnections.core.Result.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.model.FinancialConnectionsInstitution import com.stripe.android.financialconnections.model.InstitutionResponse diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/institutionpicker/InstitutionPickerScreen.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/institutionpicker/InstitutionPickerScreen.kt index d9d9008a55d..ff304c70b88 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/institutionpicker/InstitutionPickerScreen.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/institutionpicker/InstitutionPickerScreen.kt @@ -60,11 +60,11 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp import com.stripe.android.financialconnections.R -import com.stripe.android.financialconnections.core.Result -import com.stripe.android.financialconnections.core.Result.Fail -import com.stripe.android.financialconnections.core.Result.Loading -import com.stripe.android.financialconnections.core.Result.Success -import com.stripe.android.financialconnections.core.Result.Uninitialized +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.InstitutionIcon @@ -114,8 +114,8 @@ internal fun InstitutionPickerScreen() { @Composable private fun InstitutionPickerContent( listState: LazyListState, - payload: Result, - institutions: Result, + payload: Async, + institutions: Async, previewText: String?, selectedInstitutionId: String?, onQueryChanged: (String) -> Unit, @@ -157,7 +157,7 @@ private fun LoadedContent( previewText: String?, selectedInstitutionId: String?, onQueryChanged: (String) -> Unit, - institutions: Result, + institutions: Async, onInstitutionSelected: (FinancialConnectionsInstitution, Boolean) -> Unit, payload: Payload, onManualEntryClick: () -> Unit, @@ -225,7 +225,7 @@ private fun LazyListScope.searchResults( payload: Payload, selectedInstitutionId: String?, onInstitutionSelected: (FinancialConnectionsInstitution, Boolean) -> Unit, - institutions: Result, + institutions: Async, onManualEntryClick: () -> Unit, onSearchMoreClick: () -> Unit ) { diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/institutionpicker/InstitutionPickerViewModel.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/institutionpicker/InstitutionPickerViewModel.kt index 40f3d609cf4..d8b3804aee3 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/institutionpicker/InstitutionPickerViewModel.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/institutionpicker/InstitutionPickerViewModel.kt @@ -16,10 +16,10 @@ import com.stripe.android.financialconnections.analytics.FinancialConnectionsAna import com.stripe.android.financialconnections.analytics.FinancialConnectionsEvent.Metadata import com.stripe.android.financialconnections.analytics.FinancialConnectionsEvent.Name import com.stripe.android.financialconnections.analytics.logError +import com.stripe.android.financialconnections.core.Async +import com.stripe.android.financialconnections.core.Async.Loading +import com.stripe.android.financialconnections.core.Async.Uninitialized import com.stripe.android.financialconnections.core.FinancialConnectionsViewModel -import com.stripe.android.financialconnections.core.Result -import com.stripe.android.financialconnections.core.Result.Loading -import com.stripe.android.financialconnections.core.Result.Uninitialized import com.stripe.android.financialconnections.di.FinancialConnectionsSheetNativeComponent import com.stripe.android.financialconnections.domain.FeaturedInstitutions import com.stripe.android.financialconnections.domain.GetOrFetchSync @@ -248,9 +248,9 @@ internal data class InstitutionPickerState( // This is just used to provide a text in Compose previews val previewText: String? = null, val selectedInstitutionId: String? = null, - val payload: Result = Uninitialized, - val searchInstitutions: Result = Uninitialized, - val createSessionForInstitution: Result = Uninitialized + val payload: Async = Uninitialized, + val searchInstitutions: Async = Uninitialized, + val createSessionForInstitution: Async = Uninitialized ) { data class Payload( 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 125d7cfccb3..ed0c55c723c 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 @@ -2,7 +2,6 @@ package com.stripe.android.financialconnections.utils import androidx.activity.ComponentActivity import com.airbnb.mvrx.ActivityViewModelContext -import com.airbnb.mvrx.Async import com.airbnb.mvrx.Fail import com.airbnb.mvrx.InternalMavericksApi import com.airbnb.mvrx.Loading @@ -12,11 +11,12 @@ 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.Result +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] @@ -64,15 +64,15 @@ 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 Async<*>.isCancellationError(): Boolean = when { +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 Result<*>.isCancellationError(): Boolean = when { - this !is Result.Fail -> false +internal fun Async<*>.isCancellationError(): Boolean = when { + this !is Async.Fail -> false error is CancellationException -> true error is StripeException && error.cause is CancellationException -> true else -> false diff --git a/financial-connections/src/test/java/com/stripe/android/financialconnections/features/institutionpicker/InstitutionPickerViewModelTest.kt b/financial-connections/src/test/java/com/stripe/android/financialconnections/features/institutionpicker/InstitutionPickerViewModelTest.kt index fa8de8eb624..057f6709f84 100644 --- a/financial-connections/src/test/java/com/stripe/android/financialconnections/features/institutionpicker/InstitutionPickerViewModelTest.kt +++ b/financial-connections/src/test/java/com/stripe/android/financialconnections/features/institutionpicker/InstitutionPickerViewModelTest.kt @@ -5,7 +5,7 @@ import com.stripe.android.financialconnections.ApiKeyFixtures import com.stripe.android.financialconnections.CoroutineTestRule import com.stripe.android.financialconnections.FinancialConnectionsSheet import com.stripe.android.financialconnections.TestFinancialConnectionsAnalyticsTracker -import com.stripe.android.financialconnections.core.Result +import com.stripe.android.financialconnections.core.Async import com.stripe.android.financialconnections.domain.FeaturedInstitutions import com.stripe.android.financialconnections.domain.GetOrFetchSync import com.stripe.android.financialconnections.domain.PostAuthorizationSession @@ -95,7 +95,7 @@ internal class InstitutionPickerViewModelTest { viewModel.stateFlow.value.let { state -> assertEquals(state.payload()!!.featuredInstitutions, institutionResponse) - assertIs(state.searchInstitutions) + assertIs(state.searchInstitutions) } } diff --git a/payments-core/src/test/java/com/stripe/android/model/GooglePayResultTest.kt b/payments-core/src/test/java/com/stripe/android/model/GooglePayAsyncTest.kt similarity index 98% rename from payments-core/src/test/java/com/stripe/android/model/GooglePayResultTest.kt rename to payments-core/src/test/java/com/stripe/android/model/GooglePayAsyncTest.kt index a893f9c399b..7187e2dd324 100644 --- a/payments-core/src/test/java/com/stripe/android/model/GooglePayResultTest.kt +++ b/payments-core/src/test/java/com/stripe/android/model/GooglePayAsyncTest.kt @@ -5,7 +5,7 @@ import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertNull -class GooglePayResultTest { +class GooglePayAsyncTest { @Test fun fromJson_withFullBillingAddress() { From 85bc66b883f6ce0492b1e1a92267636dd445df52 Mon Sep 17 00:00:00 2001 From: "Carlos M." Date: Thu, 21 Mar 2024 16:50:16 -0700 Subject: [PATCH 23/28] use suspend block. --- .../features/consent/ConsentViewModel.kt | 34 ++++++++++--------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentViewModel.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentViewModel.kt index 9867a03357d..580caef0d46 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentViewModel.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentViewModel.kt @@ -66,22 +66,24 @@ internal class ConsentViewModel @Inject constructor( ) } - fun onContinueClick() = suspend { - eventTracker.track(ConsentAgree) - FinancialConnections.emitEvent(Name.CONSENT_ACQUIRED) - acceptConsent() - }.execute( - reducer = { copy(acceptConsent = it) }, - onSuccess = { navigationManager.tryNavigateTo(it.nextPane.destination(referrer = Pane.CONSENT)) }, - onFail = { - eventTracker.logError( - extraMessage = "Error accepting consent", - error = it, - logger = logger, - pane = Pane.CONSENT - ) - }, - ) + fun onContinueClick() { + suspend { + eventTracker.track(ConsentAgree) + FinancialConnections.emitEvent(Name.CONSENT_ACQUIRED) + acceptConsent() + }.execute( + reducer = { copy(acceptConsent = it) }, + onSuccess = { navigationManager.tryNavigateTo(it.nextPane.destination(referrer = Pane.CONSENT)) }, + onFail = { + eventTracker.logError( + extraMessage = "Error accepting consent", + error = it, + logger = logger, + pane = Pane.CONSENT + ) + }, + ) + } fun onClickableTextClick(uri: String) = viewModelScope.launch { val date = Date() From a019f4a37e4451fce1df80ff8872dcd7db1b0982 Mon Sep 17 00:00:00 2001 From: Carlos M <99293320+carlosmuvi-stripe@users.noreply.github.com> Date: Thu, 21 Mar 2024 16:52:52 -0700 Subject: [PATCH 24/28] Update financial-connections/src/main/java/com/stripe/android/financialconnections/core/FinancialConnectionsViewModel.kt Co-authored-by: Till Hellmund --- .../financialconnections/core/FinancialConnectionsViewModel.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/core/FinancialConnectionsViewModel.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/core/FinancialConnectionsViewModel.kt index fda205b5144..be645c419fd 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/core/FinancialConnectionsViewModel.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/core/FinancialConnectionsViewModel.kt @@ -25,7 +25,7 @@ internal abstract class FinancialConnectionsViewModel( ): Job { return viewModelScope.launch { setState { reducer(Loading) } - val result = kotlin.runCatching { this@execute() } + val result = runCatching { this@execute() } // update state. result.fold( onSuccess = { data -> From eb82caf56103d442972e37aae0e983da3bc2907a Mon Sep 17 00:00:00 2001 From: "Carlos M." Date: Thu, 21 Mar 2024 17:54:52 -0700 Subject: [PATCH 25/28] Tries onAsync. --- .../core/FinancialConnectionsViewModel.kt | 27 +++++++- .../features/consent/ConsentScreen.kt | 2 +- .../features/consent/ConsentViewModel.kt | 44 ++++++------ .../InstitutionPickerScreen.kt | 2 +- .../InstitutionPickerViewModel.kt | 67 +++++++++++-------- 5 files changed, 86 insertions(+), 56 deletions(-) diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/core/FinancialConnectionsViewModel.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/core/FinancialConnectionsViewModel.kt index be645c419fd..205f10fb6a3 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/core/FinancialConnectionsViewModel.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/core/FinancialConnectionsViewModel.kt @@ -8,8 +8,11 @@ import com.stripe.android.financialconnections.core.Async.Success import kotlinx.coroutines.Job import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch +import kotlin.reflect.KProperty1 internal abstract class FinancialConnectionsViewModel( initialState: S @@ -19,9 +22,9 @@ internal abstract class FinancialConnectionsViewModel( val stateFlow: StateFlow = _stateFlow protected open fun (suspend () -> T).execute( - reducer: S.(Async) -> S, onSuccess: (T) -> Unit = {}, - onFail: (Throwable) -> Unit = {} + onFail: (Throwable) -> Unit = {}, + reducer: S.(Async) -> S ): Job { return viewModelScope.launch { setState { reducer(Loading) } @@ -40,6 +43,25 @@ internal abstract class FinancialConnectionsViewModel( } } + protected open fun onAsync( + prop: KProperty1>, + onSuccess: (T) -> Unit = {}, + onFail: (Throwable) -> Unit = {} + ) { + viewModelScope.launch { + stateFlow.map { prop.get(it) } + .distinctUntilChanged() + .collect { async -> + when (async) { + is Success -> onSuccess(async()) + is Fail -> onFail(async.error) + Loading -> Unit + Async.Uninitialized -> Unit + } + } + } + } + protected fun setState(reducer: S.() -> S) = _stateFlow.update(reducer) } @@ -51,6 +73,7 @@ internal sealed class Async( data class Success(private val value: T) : Async(value = value) { override operator fun invoke(): T = value } + data class Fail(val error: Throwable) : Async(value = null) open operator fun invoke(): T? = value diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentScreen.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentScreen.kt index 256235b7d4c..0177617881c 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentScreen.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentScreen.kt @@ -117,7 +117,7 @@ private fun ConsentContent( Uninitialized, Loading -> ConsentLoadingContent() is Success -> LoadedContent( - payload = result.value, + payload = result(), bottomSheetState = bottomSheetState, acceptConsent = state.acceptConsent, bottomSheetMode = state.currentBottomSheet, diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentViewModel.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentViewModel.kt index 580caef0d46..4e5bd773a09 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentViewModel.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/consent/ConsentViewModel.kt @@ -18,6 +18,7 @@ import com.stripe.android.financialconnections.domain.GetOrFetchSync import com.stripe.android.financialconnections.features.consent.ConsentState.BottomSheetContent import com.stripe.android.financialconnections.features.consent.ConsentState.ViewEffect import com.stripe.android.financialconnections.features.consent.ConsentState.ViewEffect.OpenUrl +import com.stripe.android.financialconnections.model.FinancialConnectionsSessionManifest import com.stripe.android.financialconnections.model.FinancialConnectionsSessionManifest.Pane import com.stripe.android.financialconnections.navigation.Destination import com.stripe.android.financialconnections.navigation.NavigationManager @@ -41,6 +42,7 @@ internal class ConsentViewModel @Inject constructor( ) : FinancialConnectionsViewModel(initialState) { init { + logErrors() suspend { val sync = getOrFetchSync() val manifest = sync.manifest @@ -52,37 +54,33 @@ internal class ConsentViewModel @Inject constructor( shouldShowMerchantLogos = shouldShowMerchantLogos, merchantLogos = sync.visual.merchantLogos ) - }.execute( - reducer = { copy(consent = it) }, + }.execute { copy(consent = it) } + } + + private fun logErrors() { + onAsync( + ConsentState::consent, onSuccess = { eventTracker.track(PaneLoaded(Pane.CONSENT)) }, - onFail = { - eventTracker.logError( - extraMessage = "Error retrieving consent content", - error = it, - logger = logger, - pane = Pane.CONSENT - ) - }, + onFail = { logger.error("Error retrieving consent content", it) } ) + onAsync(ConsentState::acceptConsent, onFail = { + eventTracker.logError( + extraMessage = "Error accepting consent", + error = it, + logger = logger, + pane = Pane.CONSENT + ) + }) } fun onContinueClick() { suspend { eventTracker.track(ConsentAgree) FinancialConnections.emitEvent(Name.CONSENT_ACQUIRED) - acceptConsent() - }.execute( - reducer = { copy(acceptConsent = it) }, - onSuccess = { navigationManager.tryNavigateTo(it.nextPane.destination(referrer = Pane.CONSENT)) }, - onFail = { - eventTracker.logError( - extraMessage = "Error accepting consent", - error = it, - logger = logger, - pane = Pane.CONSENT - ) - }, - ) + val updatedManifest: FinancialConnectionsSessionManifest = acceptConsent() + navigationManager.tryNavigateTo(updatedManifest.nextPane.destination(referrer = Pane.CONSENT)) + updatedManifest + }.execute { copy(acceptConsent = it) } } fun onClickableTextClick(uri: String) = viewModelScope.launch { diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/institutionpicker/InstitutionPickerScreen.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/institutionpicker/InstitutionPickerScreen.kt index ff304c70b88..90f74f83554 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/institutionpicker/InstitutionPickerScreen.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/institutionpicker/InstitutionPickerScreen.kt @@ -142,7 +142,7 @@ private fun InstitutionPickerContent( onQueryChanged = onQueryChanged, institutions = institutions, onInstitutionSelected = onInstitutionSelected, - payload = payload.value, + payload = payload(), onManualEntryClick = onManualEntryClick, onScrollChanged = onScrollChanged ) diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/institutionpicker/InstitutionPickerViewModel.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/institutionpicker/InstitutionPickerViewModel.kt index d8b3804aee3..ad61a1e4ae6 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/features/institutionpicker/InstitutionPickerViewModel.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/features/institutionpicker/InstitutionPickerViewModel.kt @@ -60,6 +60,7 @@ internal class InstitutionPickerViewModel @Inject constructor( private var searchJob = ConflatedJob() init { + logErrors() suspend { val manifest = getOrFetchSync().manifest val (featuredInstitutions: InstitutionResponse, duration: Long) = runCatching { @@ -87,8 +88,12 @@ internal class InstitutionPickerViewModel @Inject constructor( featuredInstitutions = featuredInstitutions, searchDisabled = manifest.institutionSearchDisabled, ) - }.execute( - reducer = { result -> copy(payload = result) }, + }.execute { copy(payload = it) } + } + + private fun logErrors() { + onAsync( + InstitutionPickerState::payload, onSuccess = { payload -> eventTracker.track(PaneLoaded(PANE)) eventTracker.track( @@ -108,6 +113,28 @@ internal class InstitutionPickerViewModel @Inject constructor( ) } ) + onAsync( + InstitutionPickerState::searchInstitutions, + onFail = { + handleError( + extraMessage = "Error searching institutions", + error = it, + pane = PANE, + displayErrorScreen = false // don't show error screen for search errors. + ) + } + ) + onAsync( + InstitutionPickerState::createSessionForInstitution, + onFail = { + handleError( + extraMessage = "Error selecting or creating session for institution", + error = it, + pane = PANE, + displayErrorScreen = true + ) + } + ) } fun onQueryChanged(query: String) { @@ -136,17 +163,9 @@ internal class InstitutionPickerViewModel @Inject constructor( showManualEntry = false ) } - }.execute( - reducer = { copy(searchInstitutions = if (it.isCancellationError()) Loading else it) }, - onFail = { - handleError( - extraMessage = "Error searching institutions", - error = it, - pane = PANE, - displayErrorScreen = false // don't show error screen for search errors. - ) - } - ) + }.execute { + copy(searchInstitutions = if (it.isCancellationError()) Loading else it) + } } fun onInstitutionSelected(institution: FinancialConnectionsInstitution, fromFeatured: Boolean) { @@ -172,22 +191,12 @@ internal class InstitutionPickerViewModel @Inject constructor( // navigate to next step val authSession = postAuthorizationSession(institution, getOrFetchSync()) navigateToPartnerAuth(authSession) - }.execute( - reducer = { result -> - copy( - selectedInstitutionId = institution.id.takeIf { result is Loading }, - createSessionForInstitution = result - ) - }, - onFail = { - handleError( - extraMessage = "Error selecting or creating session for institution", - error = it, - pane = PANE, - displayErrorScreen = true - ) - } - ) + }.execute { async -> + copy( + selectedInstitutionId = institution.id.takeIf { async is Loading }, + createSessionForInstitution = async + ) + } } /** From 0d0c270ae0f8c9b7a64de725a9348c56ab448cb9 Mon Sep 17 00:00:00 2001 From: "Carlos M." Date: Fri, 22 Mar 2024 11:11:18 -0700 Subject: [PATCH 26/28] Moves activity to stripe ui core. --- .../core/ComposeExtensions.kt | 4 +-- .../stripe/android/core/utils/ContextUtils.kt | 17 ------------- stripe-ui-core/build.gradle | 1 + .../uicore/utils/ActivityExtensions.kt | 25 +++++++++++++++++++ 4 files changed, 28 insertions(+), 19 deletions(-) create mode 100644 stripe-ui-core/src/main/java/com/stripe/android/uicore/utils/ActivityExtensions.kt diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/core/ComposeExtensions.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/core/ComposeExtensions.kt index b53f9c7b838..9d158e31d0f 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/core/ComposeExtensions.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/core/ComposeExtensions.kt @@ -7,9 +7,9 @@ import androidx.compose.runtime.remember import androidx.compose.ui.platform.LocalContext import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.viewmodel.compose.viewModel -import com.stripe.android.core.utils.ContextUtils.extractActivityFromContext import com.stripe.android.financialconnections.di.FinancialConnectionsSheetNativeComponent import com.stripe.android.financialconnections.ui.FinancialConnectionsSheetNativeActivity +import com.stripe.android.uicore.utils.extractActivity import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.map import kotlin.reflect.KProperty1 @@ -28,7 +28,7 @@ internal inline fun , S> paneViewMo */ @Composable internal fun parentActivity(): FinancialConnectionsSheetNativeActivity { - return extractActivityFromContext(LocalContext.current) as FinancialConnectionsSheetNativeActivity + return LocalContext.current.extractActivity() as FinancialConnectionsSheetNativeActivity } /** diff --git a/stripe-core/src/main/java/com/stripe/android/core/utils/ContextUtils.kt b/stripe-core/src/main/java/com/stripe/android/core/utils/ContextUtils.kt index 17f2933ddec..aebd8533925 100644 --- a/stripe-core/src/main/java/com/stripe/android/core/utils/ContextUtils.kt +++ b/stripe-core/src/main/java/com/stripe/android/core/utils/ContextUtils.kt @@ -1,10 +1,8 @@ package com.stripe.android.core.utils import android.content.Context -import android.content.ContextWrapper import android.content.pm.PackageInfo import androidx.annotation.RestrictTo -import androidx.core.app.ComponentActivity @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) object ContextUtils { @@ -13,19 +11,4 @@ object ContextUtils { get() = runCatching { packageManager.getPackageInfo(packageName, 0) }.getOrNull() - - fun extractActivityFromContext(context: Context): ComponentActivity? { - var currentContext = context - if (currentContext is ComponentActivity) { - return currentContext - } else { - while (currentContext is ContextWrapper) { - if (currentContext is ComponentActivity) { - return currentContext - } - currentContext = currentContext.baseContext - } - } - return null - } } diff --git a/stripe-ui-core/build.gradle b/stripe-ui-core/build.gradle index 5e863d7f012..149f137c8d9 100644 --- a/stripe-ui-core/build.gradle +++ b/stripe-ui-core/build.gradle @@ -34,6 +34,7 @@ android { dependencies { implementation project(":stripe-core") + implementation libs.androidx.activity implementation libs.androidx.annotation implementation libs.androidx.coreKtx implementation libs.compose.foundation diff --git a/stripe-ui-core/src/main/java/com/stripe/android/uicore/utils/ActivityExtensions.kt b/stripe-ui-core/src/main/java/com/stripe/android/uicore/utils/ActivityExtensions.kt new file mode 100644 index 00000000000..5e4f09194d8 --- /dev/null +++ b/stripe-ui-core/src/main/java/com/stripe/android/uicore/utils/ActivityExtensions.kt @@ -0,0 +1,25 @@ +package com.stripe.android.uicore.utils + +import android.content.Context +import android.content.ContextWrapper +import androidx.activity.ComponentActivity +import androidx.annotation.RestrictTo + +/** + * Extracts the [ComponentActivity] from the given [Context]. + */ +@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) +fun Context.extractActivity(): ComponentActivity? { + var currentContext = this + if (currentContext is ComponentActivity) { + return currentContext + } else { + while (currentContext is ContextWrapper) { + if (currentContext is ComponentActivity) { + return currentContext + } + currentContext = currentContext.baseContext + } + } + return null +} From d060b53aa904eb0e6f82aabcbad3e4d1fc3ea4f9 Mon Sep 17 00:00:00 2001 From: "Carlos M." Date: Fri, 22 Mar 2024 14:10:13 -0700 Subject: [PATCH 27/28] PR feedback. --- .../financialconnections/core/FinancialConnectionsViewModel.kt | 3 ++- .../model/{GooglePayAsyncTest.kt => GooglePayResultTest.kt} | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) rename payments-core/src/test/java/com/stripe/android/model/{GooglePayAsyncTest.kt => GooglePayResultTest.kt} (98%) diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/core/FinancialConnectionsViewModel.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/core/FinancialConnectionsViewModel.kt index 205f10fb6a3..604fcfa4912 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/core/FinancialConnectionsViewModel.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/core/FinancialConnectionsViewModel.kt @@ -8,6 +8,7 @@ import com.stripe.android.financialconnections.core.Async.Success import kotlinx.coroutines.Job import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.update @@ -19,7 +20,7 @@ internal abstract class FinancialConnectionsViewModel( ) : ViewModel() { private val _stateFlow: MutableStateFlow = MutableStateFlow(initialState) - val stateFlow: StateFlow = _stateFlow + val stateFlow: StateFlow = _stateFlow.asStateFlow() protected open fun (suspend () -> T).execute( onSuccess: (T) -> Unit = {}, diff --git a/payments-core/src/test/java/com/stripe/android/model/GooglePayAsyncTest.kt b/payments-core/src/test/java/com/stripe/android/model/GooglePayResultTest.kt similarity index 98% rename from payments-core/src/test/java/com/stripe/android/model/GooglePayAsyncTest.kt rename to payments-core/src/test/java/com/stripe/android/model/GooglePayResultTest.kt index 7187e2dd324..a893f9c399b 100644 --- a/payments-core/src/test/java/com/stripe/android/model/GooglePayAsyncTest.kt +++ b/payments-core/src/test/java/com/stripe/android/model/GooglePayResultTest.kt @@ -5,7 +5,7 @@ import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertNull -class GooglePayAsyncTest { +class GooglePayResultTest { @Test fun fromJson_withFullBillingAddress() { From 1e1d5e74f7141975186f026b8f182c9c03dfd38a Mon Sep 17 00:00:00 2001 From: "Carlos M." Date: Fri, 22 Mar 2024 16:34:51 -0700 Subject: [PATCH 28/28] Regenerates deps. --- example/dependencies/dependencies.txt | 57 +++--- .../dependencies/dependencies.txt | 171 +++++++++--------- .../dependencies/dependencies.txt | 165 ++++++++--------- identity/dependencies/dependencies.txt | 57 +++--- link/dependencies/dependencies.txt | 57 +++--- network-testing/dependencies/dependencies.txt | 53 +++--- .../dependencies/dependencies.txt | 57 +++--- .../dependencies/dependencies.txt | 53 +++--- payments-core/dependencies/dependencies.txt | 53 +++--- .../dependencies/dependencies.txt | 53 +++--- payments/dependencies/dependencies.txt | 57 +++--- .../dependencies/dependencies.txt | 57 +++--- paymentsheet/dependencies/dependencies.txt | 57 +++--- stripe-test-e2e/dependencies/dependencies.txt | 57 +++--- stripe-ui-core/dependencies/dependencies.txt | 167 ++++++++--------- wechatpay/dependencies/dependencies.txt | 53 +++--- 16 files changed, 620 insertions(+), 604 deletions(-) diff --git a/example/dependencies/dependencies.txt b/example/dependencies/dependencies.txt index cc4818ccde8..a19c531f529 100644 --- a/example/dependencies/dependencies.txt +++ b/example/dependencies/dependencies.txt @@ -336,6 +336,34 @@ | | +--- project :stripe-ui-core | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.9.22 (*) | | | +--- project :stripe-core (*) +| | | +--- androidx.activity:activity-ktx:1.8.2 +| | | | +--- androidx.activity:activity:1.8.2 (*) +| | | | +--- androidx.core:core-ktx:1.9.0 -> 1.12.0 (*) +| | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.6.1 -> 2.7.0 +| | | | | +--- androidx.annotation:annotation:1.0.0 -> 1.7.1 (*) +| | | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (*) +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) +| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1 -> 1.7.3 (*) +| | | | | +--- androidx.lifecycle:lifecycle-livedata:2.7.0 (c) +| | | | | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.7.0 (c) +| | | | | +--- androidx.lifecycle:lifecycle-livedata-ktx:2.7.0 (c) +| | | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (c) +| | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.7.0 (c) +| | | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0 (c) +| | | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.7.0 (c) +| | | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.7.0 (c) +| | | | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.7.0 (c) +| | | | | +--- androidx.lifecycle:lifecycle-common-java8:2.7.0 (c) +| | | | | +--- androidx.lifecycle:lifecycle-common:2.7.0 (c) +| | | | | \--- androidx.lifecycle:lifecycle-process:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1 -> 2.7.0 (*) +| | | | +--- androidx.savedstate:savedstate-ktx:1.2.1 +| | | | | +--- androidx.savedstate:savedstate:1.2.1 (*) +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.10 -> 1.9.22 (*) +| | | | | \--- androidx.savedstate:savedstate:1.2.1 (c) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) +| | | | +--- androidx.activity:activity:1.8.2 (c) +| | | | \--- androidx.activity:activity-compose:1.8.2 (c) | | | +--- androidx.annotation:annotation:1.7.1 (*) | | | +--- androidx.core:core-ktx:1.12.0 (*) | | | +--- androidx.compose.foundation:foundation:1.5.4 @@ -358,34 +386,7 @@ | | | | | | | \--- androidx.compose.runtime:runtime-saveable:1.5.4 (c) | | | | | | +--- androidx.compose.ui:ui:1.5.4 | | | | | | | \--- androidx.compose.ui:ui-android:1.5.4 -| | | | | | | +--- androidx.activity:activity-ktx:1.7.0 -> 1.8.2 -| | | | | | | | +--- androidx.activity:activity:1.8.2 (*) -| | | | | | | | +--- androidx.core:core-ktx:1.9.0 -> 1.12.0 (*) -| | | | | | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.6.1 -> 2.7.0 -| | | | | | | | | +--- androidx.annotation:annotation:1.0.0 -> 1.7.1 (*) -| | | | | | | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (*) -| | | | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) -| | | | | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1 -> 1.7.3 (*) -| | | | | | | | | +--- androidx.lifecycle:lifecycle-livedata:2.7.0 (c) -| | | | | | | | | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.7.0 (c) -| | | | | | | | | +--- androidx.lifecycle:lifecycle-livedata-ktx:2.7.0 (c) -| | | | | | | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (c) -| | | | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.7.0 (c) -| | | | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0 (c) -| | | | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.7.0 (c) -| | | | | | | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.7.0 (c) -| | | | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.7.0 (c) -| | | | | | | | | +--- androidx.lifecycle:lifecycle-common-java8:2.7.0 (c) -| | | | | | | | | +--- androidx.lifecycle:lifecycle-common:2.7.0 (c) -| | | | | | | | | \--- androidx.lifecycle:lifecycle-process:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1 -> 2.7.0 (*) -| | | | | | | | +--- androidx.savedstate:savedstate-ktx:1.2.1 -| | | | | | | | | +--- androidx.savedstate:savedstate:1.2.1 (*) -| | | | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.10 -> 1.9.22 (*) -| | | | | | | | | \--- androidx.savedstate:savedstate:1.2.1 (c) -| | | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) -| | | | | | | | +--- androidx.activity:activity:1.8.2 (c) -| | | | | | | | \--- androidx.activity:activity-compose:1.8.2 (c) +| | | | | | | +--- androidx.activity:activity-ktx:1.7.0 -> 1.8.2 (*) | | | | | | | +--- androidx.annotation:annotation:1.5.0 -> 1.7.1 (*) | | | | | | | +--- androidx.autofill:autofill:1.0.0 | | | | | | | | \--- androidx.core:core:1.1.0 -> 1.12.0 (*) diff --git a/financial-connections-example/dependencies/dependencies.txt b/financial-connections-example/dependencies/dependencies.txt index e5d57aba731..effcb618c42 100644 --- a/financial-connections-example/dependencies/dependencies.txt +++ b/financial-connections-example/dependencies/dependencies.txt @@ -145,12 +145,92 @@ | +--- project :stripe-ui-core | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.9.22 (*) | | +--- project :stripe-core (*) -| | +--- androidx.annotation:annotation:1.7.1 (*) -| | +--- androidx.core:core-ktx:1.12.0 -| | | +--- androidx.annotation:annotation:1.1.0 -> 1.7.1 (*) -| | | +--- androidx.core:core:1.12.0 (*) +| | +--- androidx.activity:activity-ktx:1.8.2 +| | | +--- androidx.activity:activity:1.8.2 +| | | | +--- androidx.annotation:annotation:1.1.0 -> 1.7.1 (*) +| | | | +--- androidx.collection:collection:1.0.0 -> 1.1.0 (*) +| | | | +--- androidx.core:core:1.8.0 -> 1.12.0 (*) +| | | | +--- androidx.lifecycle:lifecycle-runtime:2.6.1 -> 2.7.0 (*) +| | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.6.1 -> 2.7.0 (*) +| | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.6.1 -> 2.7.0 +| | | | | +--- androidx.annotation:annotation:1.0.0 -> 1.7.1 (*) +| | | | | +--- androidx.core:core-ktx:1.2.0 -> 1.12.0 +| | | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.7.1 (*) +| | | | | | +--- androidx.core:core:1.12.0 (*) +| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) +| | | | | | \--- androidx.core:core:1.12.0 (c) +| | | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.7.0 +| | | | | | +--- androidx.arch.core:core-common:2.2.0 (*) +| | | | | | +--- androidx.arch.core:core-runtime:2.2.0 (*) +| | | | | | +--- androidx.lifecycle:lifecycle-common:2.7.0 (*) +| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) +| | | | | | +--- androidx.lifecycle:lifecycle-common:2.7.0 (c) +| | | | | | +--- androidx.lifecycle:lifecycle-common-java8:2.7.0 (c) +| | | | | | +--- androidx.lifecycle:lifecycle-livedata:2.7.0 (c) +| | | | | | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.7.0 (c) +| | | | | | +--- androidx.lifecycle:lifecycle-livedata-ktx:2.7.0 (c) +| | | | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (c) +| | | | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.7.0 (c) +| | | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.7.0 (c) +| | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.7.0 (c) +| | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0 (c) +| | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.7.0 (c) +| | | | | | \--- androidx.lifecycle:lifecycle-process:2.7.0 (c) +| | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.7.0 (*) +| | | | | +--- androidx.savedstate:savedstate:1.2.1 +| | | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.7.1 (*) +| | | | | | +--- androidx.arch.core:core-common:2.1.0 -> 2.2.0 (*) +| | | | | | +--- androidx.lifecycle:lifecycle-common:2.6.1 -> 2.7.0 (*) +| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.10 -> 1.9.22 (*) +| | | | | | \--- androidx.savedstate:savedstate-ktx:1.2.1 (c) +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) +| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1 -> 1.7.3 (*) +| | | | | +--- androidx.lifecycle:lifecycle-livedata:2.7.0 (c) +| | | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.7.0 (c) +| | | | | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.7.0 (c) +| | | | | +--- androidx.lifecycle:lifecycle-livedata-ktx:2.7.0 (c) +| | | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (c) +| | | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.7.0 (c) +| | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.7.0 (c) +| | | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0 (c) +| | | | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.7.0 (c) +| | | | | +--- androidx.lifecycle:lifecycle-common-java8:2.7.0 (c) +| | | | | +--- androidx.lifecycle:lifecycle-common:2.7.0 (c) +| | | | | \--- androidx.lifecycle:lifecycle-process:2.7.0 (c) +| | | | +--- androidx.profileinstaller:profileinstaller:1.3.0 (*) +| | | | +--- androidx.savedstate:savedstate:1.2.1 (*) +| | | | +--- androidx.tracing:tracing:1.0.0 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) +| | | | +--- androidx.activity:activity-compose:1.8.2 (c) +| | | | \--- androidx.activity:activity-ktx:1.8.2 (c) +| | | +--- androidx.core:core-ktx:1.9.0 -> 1.12.0 (*) +| | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.6.1 -> 2.7.0 +| | | | +--- androidx.annotation:annotation:1.0.0 -> 1.7.1 (*) +| | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) +| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1 -> 1.7.3 (*) +| | | | +--- androidx.lifecycle:lifecycle-livedata-ktx:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-livedata:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-common-java8:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-common:2.7.0 (c) +| | | | \--- androidx.lifecycle:lifecycle-process:2.7.0 (c) +| | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1 -> 2.7.0 (*) +| | | +--- androidx.savedstate:savedstate-ktx:1.2.1 +| | | | +--- androidx.savedstate:savedstate:1.2.1 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.10 -> 1.9.22 (*) +| | | | \--- androidx.savedstate:savedstate:1.2.1 (c) | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) -| | | \--- androidx.core:core:1.12.0 (c) +| | | +--- androidx.activity:activity:1.8.2 (c) +| | | \--- androidx.activity:activity-compose:1.8.2 (c) +| | +--- androidx.annotation:annotation:1.7.1 (*) +| | +--- androidx.core:core-ktx:1.12.0 (*) | | +--- androidx.compose.foundation:foundation:1.5.4 | | | \--- androidx.compose.foundation:foundation-android:1.5.4 | | | +--- androidx.annotation:annotation:1.1.0 -> 1.7.1 (*) @@ -171,86 +251,7 @@ | | | | | | \--- androidx.compose.runtime:runtime-saveable:1.5.4 (c) | | | | | +--- androidx.compose.ui:ui:1.5.4 | | | | | | \--- androidx.compose.ui:ui-android:1.5.4 -| | | | | | +--- androidx.activity:activity-ktx:1.7.0 -> 1.8.2 -| | | | | | | +--- androidx.activity:activity:1.8.2 -| | | | | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.7.1 (*) -| | | | | | | | +--- androidx.collection:collection:1.0.0 -> 1.1.0 (*) -| | | | | | | | +--- androidx.core:core:1.8.0 -> 1.12.0 (*) -| | | | | | | | +--- androidx.lifecycle:lifecycle-runtime:2.6.1 -> 2.7.0 (*) -| | | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.6.1 -> 2.7.0 (*) -| | | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.6.1 -> 2.7.0 -| | | | | | | | | +--- androidx.annotation:annotation:1.0.0 -> 1.7.1 (*) -| | | | | | | | | +--- androidx.core:core-ktx:1.2.0 -> 1.12.0 (*) -| | | | | | | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.7.0 -| | | | | | | | | | +--- androidx.arch.core:core-common:2.2.0 (*) -| | | | | | | | | | +--- androidx.arch.core:core-runtime:2.2.0 (*) -| | | | | | | | | | +--- androidx.lifecycle:lifecycle-common:2.7.0 (*) -| | | | | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) -| | | | | | | | | | +--- androidx.lifecycle:lifecycle-common:2.7.0 (c) -| | | | | | | | | | +--- androidx.lifecycle:lifecycle-common-java8:2.7.0 (c) -| | | | | | | | | | +--- androidx.lifecycle:lifecycle-livedata:2.7.0 (c) -| | | | | | | | | | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.7.0 (c) -| | | | | | | | | | +--- androidx.lifecycle:lifecycle-livedata-ktx:2.7.0 (c) -| | | | | | | | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (c) -| | | | | | | | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.7.0 (c) -| | | | | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.7.0 (c) -| | | | | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.7.0 (c) -| | | | | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0 (c) -| | | | | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.7.0 (c) -| | | | | | | | | | \--- androidx.lifecycle:lifecycle-process:2.7.0 (c) -| | | | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.7.0 (*) -| | | | | | | | | +--- androidx.savedstate:savedstate:1.2.1 -| | | | | | | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.7.1 (*) -| | | | | | | | | | +--- androidx.arch.core:core-common:2.1.0 -> 2.2.0 (*) -| | | | | | | | | | +--- androidx.lifecycle:lifecycle-common:2.6.1 -> 2.7.0 (*) -| | | | | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.10 -> 1.9.22 (*) -| | | | | | | | | | \--- androidx.savedstate:savedstate-ktx:1.2.1 (c) -| | | | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) -| | | | | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1 -> 1.7.3 (*) -| | | | | | | | | +--- androidx.lifecycle:lifecycle-livedata:2.7.0 (c) -| | | | | | | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.7.0 (c) -| | | | | | | | | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.7.0 (c) -| | | | | | | | | +--- androidx.lifecycle:lifecycle-livedata-ktx:2.7.0 (c) -| | | | | | | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (c) -| | | | | | | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.7.0 (c) -| | | | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.7.0 (c) -| | | | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0 (c) -| | | | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.7.0 (c) -| | | | | | | | | +--- androidx.lifecycle:lifecycle-common-java8:2.7.0 (c) -| | | | | | | | | +--- androidx.lifecycle:lifecycle-common:2.7.0 (c) -| | | | | | | | | \--- androidx.lifecycle:lifecycle-process:2.7.0 (c) -| | | | | | | | +--- androidx.profileinstaller:profileinstaller:1.3.0 (*) -| | | | | | | | +--- androidx.savedstate:savedstate:1.2.1 (*) -| | | | | | | | +--- androidx.tracing:tracing:1.0.0 (*) -| | | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) -| | | | | | | | +--- androidx.activity:activity-compose:1.8.2 (c) -| | | | | | | | \--- androidx.activity:activity-ktx:1.8.2 (c) -| | | | | | | +--- androidx.core:core-ktx:1.9.0 -> 1.12.0 (*) -| | | | | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.6.1 -> 2.7.0 -| | | | | | | | +--- androidx.annotation:annotation:1.0.0 -> 1.7.1 (*) -| | | | | | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (*) -| | | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) -| | | | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1 -> 1.7.3 (*) -| | | | | | | | +--- androidx.lifecycle:lifecycle-livedata-ktx:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-livedata:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-common-java8:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-common:2.7.0 (c) -| | | | | | | | \--- androidx.lifecycle:lifecycle-process:2.7.0 (c) -| | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1 -> 2.7.0 (*) -| | | | | | | +--- androidx.savedstate:savedstate-ktx:1.2.1 -| | | | | | | | +--- androidx.savedstate:savedstate:1.2.1 (*) -| | | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.10 -> 1.9.22 (*) -| | | | | | | | \--- androidx.savedstate:savedstate:1.2.1 (c) -| | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) -| | | | | | | +--- androidx.activity:activity:1.8.2 (c) -| | | | | | | \--- androidx.activity:activity-compose:1.8.2 (c) +| | | | | | +--- androidx.activity:activity-ktx:1.7.0 -> 1.8.2 (*) | | | | | | +--- androidx.annotation:annotation:1.5.0 -> 1.7.1 (*) | | | | | | +--- androidx.autofill:autofill:1.0.0 | | | | | | | \--- androidx.core:core:1.1.0 -> 1.12.0 (*) diff --git a/financial-connections/dependencies/dependencies.txt b/financial-connections/dependencies/dependencies.txt index 84fbb58eae3..2527a93ce58 100644 --- a/financial-connections/dependencies/dependencies.txt +++ b/financial-connections/dependencies/dependencies.txt @@ -138,12 +138,89 @@ +--- project :stripe-ui-core | +--- org.jetbrains.kotlin:kotlin-stdlib:1.9.22 (*) | +--- project :stripe-core (*) -| +--- androidx.annotation:annotation:1.7.1 (*) -| +--- androidx.core:core-ktx:1.12.0 -| | +--- androidx.annotation:annotation:1.1.0 -> 1.7.1 (*) -| | +--- androidx.core:core:1.12.0 (*) +| +--- androidx.activity:activity-ktx:1.8.2 +| | +--- androidx.activity:activity:1.8.2 +| | | +--- androidx.annotation:annotation:1.1.0 -> 1.7.1 (*) +| | | +--- androidx.collection:collection:1.0.0 -> 1.1.0 (*) +| | | +--- androidx.core:core:1.8.0 -> 1.12.0 (*) +| | | +--- androidx.lifecycle:lifecycle-runtime:2.6.1 -> 2.7.0 (*) +| | | +--- androidx.lifecycle:lifecycle-viewmodel:2.6.1 -> 2.7.0 (*) +| | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.6.1 -> 2.7.0 +| | | | +--- androidx.annotation:annotation:1.0.0 -> 1.7.1 (*) +| | | | +--- androidx.core:core-ktx:1.2.0 -> 1.12.0 +| | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.7.1 (*) +| | | | | +--- androidx.core:core:1.12.0 (*) +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) +| | | | | \--- androidx.core:core:1.12.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.7.0 +| | | | | +--- androidx.arch.core:core-common:2.2.0 (*) +| | | | | +--- androidx.arch.core:core-runtime:2.2.0 (*) +| | | | | +--- androidx.lifecycle:lifecycle-common:2.7.0 (*) +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) +| | | | | +--- androidx.lifecycle:lifecycle-common:2.7.0 (c) +| | | | | +--- androidx.lifecycle:lifecycle-common-java8:2.7.0 (c) +| | | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (c) +| | | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.7.0 (c) +| | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.7.0 (c) +| | | | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.7.0 (c) +| | | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0 (c) +| | | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.7.0 (c) +| | | | | +--- androidx.lifecycle:lifecycle-process:2.7.0 (c) +| | | | | +--- androidx.lifecycle:lifecycle-livedata:2.7.0 (c) +| | | | | \--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.7.0 (*) +| | | | +--- androidx.savedstate:savedstate:1.2.1 +| | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.7.1 (*) +| | | | | +--- androidx.arch.core:core-common:2.1.0 -> 2.2.0 (*) +| | | | | +--- androidx.lifecycle:lifecycle-common:2.6.1 -> 2.7.0 (*) +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.10 -> 1.9.22 (*) +| | | | | \--- androidx.savedstate:savedstate-ktx:1.2.1 (c) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) +| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1 -> 1.7.3 (*) +| | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-common-java8:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-common:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-process:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-livedata:2.7.0 (c) +| | | | \--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.7.0 (c) +| | | +--- androidx.profileinstaller:profileinstaller:1.3.0 (*) +| | | +--- androidx.savedstate:savedstate:1.2.1 (*) +| | | +--- androidx.tracing:tracing:1.0.0 (*) +| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) +| | | +--- androidx.activity:activity-compose:1.8.2 (c) +| | | \--- androidx.activity:activity-ktx:1.8.2 (c) +| | +--- androidx.core:core-ktx:1.9.0 -> 1.12.0 (*) +| | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.6.1 -> 2.7.0 +| | | +--- androidx.annotation:annotation:1.0.0 -> 1.7.1 (*) +| | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (*) +| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) +| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1 -> 1.7.3 (*) +| | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (c) +| | | +--- androidx.lifecycle:lifecycle-viewmodel:2.7.0 (c) +| | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0 (c) +| | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.7.0 (c) +| | | +--- androidx.lifecycle:lifecycle-livedata-core:2.7.0 (c) +| | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.7.0 (c) +| | | +--- androidx.lifecycle:lifecycle-common-java8:2.7.0 (c) +| | | +--- androidx.lifecycle:lifecycle-common:2.7.0 (c) +| | | +--- androidx.lifecycle:lifecycle-process:2.7.0 (c) +| | | +--- androidx.lifecycle:lifecycle-livedata:2.7.0 (c) +| | | \--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.7.0 (c) +| | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1 -> 2.7.0 (*) +| | +--- androidx.savedstate:savedstate-ktx:1.2.1 +| | | +--- androidx.savedstate:savedstate:1.2.1 (*) +| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.10 -> 1.9.22 (*) +| | | \--- androidx.savedstate:savedstate:1.2.1 (c) | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) -| | \--- androidx.core:core:1.12.0 (c) +| | +--- androidx.activity:activity:1.8.2 (c) +| | \--- androidx.activity:activity-compose:1.8.2 (c) +| +--- androidx.annotation:annotation:1.7.1 (*) +| +--- androidx.core:core-ktx:1.12.0 (*) | +--- androidx.compose.foundation:foundation:1.5.4 | | \--- androidx.compose.foundation:foundation-android:1.5.4 | | +--- androidx.annotation:annotation:1.1.0 -> 1.7.1 (*) @@ -163,83 +240,7 @@ | | | | | \--- androidx.compose.runtime:runtime-saveable:1.5.4 (c) | | | | +--- androidx.compose.ui:ui:1.5.4 | | | | | \--- androidx.compose.ui:ui-android:1.5.4 -| | | | | +--- androidx.activity:activity-ktx:1.7.0 -> 1.8.2 -| | | | | | +--- androidx.activity:activity:1.8.2 -| | | | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.7.1 (*) -| | | | | | | +--- androidx.collection:collection:1.0.0 -> 1.1.0 (*) -| | | | | | | +--- androidx.core:core:1.8.0 -> 1.12.0 (*) -| | | | | | | +--- androidx.lifecycle:lifecycle-runtime:2.6.1 -> 2.7.0 (*) -| | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.6.1 -> 2.7.0 (*) -| | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.6.1 -> 2.7.0 -| | | | | | | | +--- androidx.annotation:annotation:1.0.0 -> 1.7.1 (*) -| | | | | | | | +--- androidx.core:core-ktx:1.2.0 -> 1.12.0 (*) -| | | | | | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.7.0 -| | | | | | | | | +--- androidx.arch.core:core-common:2.2.0 (*) -| | | | | | | | | +--- androidx.arch.core:core-runtime:2.2.0 (*) -| | | | | | | | | +--- androidx.lifecycle:lifecycle-common:2.7.0 (*) -| | | | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) -| | | | | | | | | +--- androidx.lifecycle:lifecycle-common:2.7.0 (c) -| | | | | | | | | +--- androidx.lifecycle:lifecycle-common-java8:2.7.0 (c) -| | | | | | | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (c) -| | | | | | | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.7.0 (c) -| | | | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.7.0 (c) -| | | | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.7.0 (c) -| | | | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0 (c) -| | | | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.7.0 (c) -| | | | | | | | | +--- androidx.lifecycle:lifecycle-process:2.7.0 (c) -| | | | | | | | | +--- androidx.lifecycle:lifecycle-livedata:2.7.0 (c) -| | | | | | | | | \--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.7.0 (*) -| | | | | | | | +--- androidx.savedstate:savedstate:1.2.1 -| | | | | | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.7.1 (*) -| | | | | | | | | +--- androidx.arch.core:core-common:2.1.0 -> 2.2.0 (*) -| | | | | | | | | +--- androidx.lifecycle:lifecycle-common:2.6.1 -> 2.7.0 (*) -| | | | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.10 -> 1.9.22 (*) -| | | | | | | | | \--- androidx.savedstate:savedstate-ktx:1.2.1 (c) -| | | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) -| | | | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1 -> 1.7.3 (*) -| | | | | | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-common-java8:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-common:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-process:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-livedata:2.7.0 (c) -| | | | | | | | \--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.7.0 (c) -| | | | | | | +--- androidx.profileinstaller:profileinstaller:1.3.0 (*) -| | | | | | | +--- androidx.savedstate:savedstate:1.2.1 (*) -| | | | | | | +--- androidx.tracing:tracing:1.0.0 (*) -| | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) -| | | | | | | +--- androidx.activity:activity-compose:1.8.2 (c) -| | | | | | | \--- androidx.activity:activity-ktx:1.8.2 (c) -| | | | | | +--- androidx.core:core-ktx:1.9.0 -> 1.12.0 (*) -| | | | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.6.1 -> 2.7.0 -| | | | | | | +--- androidx.annotation:annotation:1.0.0 -> 1.7.1 (*) -| | | | | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (*) -| | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) -| | | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1 -> 1.7.3 (*) -| | | | | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (c) -| | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.7.0 (c) -| | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0 (c) -| | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.7.0 (c) -| | | | | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.7.0 (c) -| | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.7.0 (c) -| | | | | | | +--- androidx.lifecycle:lifecycle-common-java8:2.7.0 (c) -| | | | | | | +--- androidx.lifecycle:lifecycle-common:2.7.0 (c) -| | | | | | | +--- androidx.lifecycle:lifecycle-process:2.7.0 (c) -| | | | | | | +--- androidx.lifecycle:lifecycle-livedata:2.7.0 (c) -| | | | | | | \--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.7.0 (c) -| | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1 -> 2.7.0 (*) -| | | | | | +--- androidx.savedstate:savedstate-ktx:1.2.1 -| | | | | | | +--- androidx.savedstate:savedstate:1.2.1 (*) -| | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.10 -> 1.9.22 (*) -| | | | | | | \--- androidx.savedstate:savedstate:1.2.1 (c) -| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) -| | | | | | +--- androidx.activity:activity:1.8.2 (c) -| | | | | | \--- androidx.activity:activity-compose:1.8.2 (c) +| | | | | +--- androidx.activity:activity-ktx:1.7.0 -> 1.8.2 (*) | | | | | +--- androidx.annotation:annotation:1.5.0 -> 1.7.1 (*) | | | | | +--- androidx.autofill:autofill:1.0.0 | | | | | | \--- androidx.core:core:1.1.0 -> 1.12.0 (*) diff --git a/identity/dependencies/dependencies.txt b/identity/dependencies/dependencies.txt index 188f606d752..e11c19e1994 100644 --- a/identity/dependencies/dependencies.txt +++ b/identity/dependencies/dependencies.txt @@ -392,6 +392,34 @@ +--- project :stripe-ui-core | +--- org.jetbrains.kotlin:kotlin-stdlib:1.9.22 (*) | +--- project :stripe-core (*) +| +--- androidx.activity:activity-ktx:1.8.2 +| | +--- androidx.activity:activity:1.8.2 (*) +| | +--- androidx.core:core-ktx:1.9.0 -> 1.12.0 (*) +| | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.6.1 -> 2.7.0 +| | | +--- androidx.annotation:annotation:1.0.0 -> 1.7.1 (*) +| | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (*) +| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) +| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1 -> 1.7.3 (*) +| | | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.7.0 (c) +| | | +--- androidx.lifecycle:lifecycle-livedata-ktx:2.7.0 (c) +| | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (c) +| | | +--- androidx.lifecycle:lifecycle-viewmodel:2.7.0 (c) +| | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.7.0 (c) +| | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0 (c) +| | | +--- androidx.lifecycle:lifecycle-livedata:2.7.0 (c) +| | | +--- androidx.lifecycle:lifecycle-common-java8:2.7.0 (c) +| | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.7.0 (c) +| | | +--- androidx.lifecycle:lifecycle-common:2.7.0 (c) +| | | +--- androidx.lifecycle:lifecycle-livedata-core:2.7.0 (c) +| | | \--- androidx.lifecycle:lifecycle-process:2.7.0 (c) +| | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1 -> 2.7.0 (*) +| | +--- androidx.savedstate:savedstate-ktx:1.2.1 +| | | +--- androidx.savedstate:savedstate:1.2.1 (*) +| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.10 -> 1.9.22 (*) +| | | \--- androidx.savedstate:savedstate:1.2.1 (c) +| | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) +| | +--- androidx.activity:activity:1.8.2 (c) +| | \--- androidx.activity:activity-compose:1.8.2 (c) | +--- androidx.annotation:annotation:1.7.1 (*) | +--- androidx.core:core-ktx:1.12.0 (*) | +--- androidx.compose.foundation:foundation:1.5.4 @@ -414,34 +442,7 @@ | | | | | \--- androidx.compose.runtime:runtime-saveable:1.5.4 (c) | | | | +--- androidx.compose.ui:ui:1.5.4 | | | | | \--- androidx.compose.ui:ui-android:1.5.4 -| | | | | +--- androidx.activity:activity-ktx:1.7.0 -> 1.8.2 -| | | | | | +--- androidx.activity:activity:1.8.2 (*) -| | | | | | +--- androidx.core:core-ktx:1.9.0 -> 1.12.0 (*) -| | | | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.6.1 -> 2.7.0 -| | | | | | | +--- androidx.annotation:annotation:1.0.0 -> 1.7.1 (*) -| | | | | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (*) -| | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) -| | | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1 -> 1.7.3 (*) -| | | | | | | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.7.0 (c) -| | | | | | | +--- androidx.lifecycle:lifecycle-livedata-ktx:2.7.0 (c) -| | | | | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (c) -| | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.7.0 (c) -| | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.7.0 (c) -| | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0 (c) -| | | | | | | +--- androidx.lifecycle:lifecycle-livedata:2.7.0 (c) -| | | | | | | +--- androidx.lifecycle:lifecycle-common-java8:2.7.0 (c) -| | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.7.0 (c) -| | | | | | | +--- androidx.lifecycle:lifecycle-common:2.7.0 (c) -| | | | | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.7.0 (c) -| | | | | | | \--- androidx.lifecycle:lifecycle-process:2.7.0 (c) -| | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1 -> 2.7.0 (*) -| | | | | | +--- androidx.savedstate:savedstate-ktx:1.2.1 -| | | | | | | +--- androidx.savedstate:savedstate:1.2.1 (*) -| | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.10 -> 1.9.22 (*) -| | | | | | | \--- androidx.savedstate:savedstate:1.2.1 (c) -| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) -| | | | | | +--- androidx.activity:activity:1.8.2 (c) -| | | | | | \--- androidx.activity:activity-compose:1.8.2 (c) +| | | | | +--- androidx.activity:activity-ktx:1.7.0 -> 1.8.2 (*) | | | | | +--- androidx.annotation:annotation:1.5.0 -> 1.7.1 (*) | | | | | +--- androidx.autofill:autofill:1.0.0 | | | | | | \--- androidx.core:core:1.1.0 -> 1.12.0 (*) diff --git a/link/dependencies/dependencies.txt b/link/dependencies/dependencies.txt index 2c36466f4f0..21622d211d3 100644 --- a/link/dependencies/dependencies.txt +++ b/link/dependencies/dependencies.txt @@ -334,6 +334,34 @@ | +--- project :stripe-ui-core | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.9.22 (*) | | +--- project :stripe-core (*) +| | +--- androidx.activity:activity-ktx:1.8.2 +| | | +--- androidx.activity:activity:1.8.2 (*) +| | | +--- androidx.core:core-ktx:1.9.0 -> 1.12.0 (*) +| | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.6.1 -> 2.7.0 +| | | | +--- androidx.annotation:annotation:1.0.0 -> 1.7.1 (*) +| | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) +| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1 -> 1.7.3 (*) +| | | | +--- androidx.lifecycle:lifecycle-common:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-common-java8:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-livedata:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-livedata-ktx:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.7.0 (c) +| | | | \--- androidx.lifecycle:lifecycle-process:2.7.0 (c) +| | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1 -> 2.7.0 (*) +| | | +--- androidx.savedstate:savedstate-ktx:1.2.1 +| | | | +--- androidx.savedstate:savedstate:1.2.1 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.10 -> 1.9.22 (*) +| | | | \--- androidx.savedstate:savedstate:1.2.1 (c) +| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) +| | | +--- androidx.activity:activity:1.8.2 (c) +| | | \--- androidx.activity:activity-compose:1.8.2 (c) | | +--- androidx.annotation:annotation:1.7.1 (*) | | +--- androidx.core:core-ktx:1.12.0 (*) | | +--- androidx.compose.foundation:foundation:1.5.4 @@ -356,34 +384,7 @@ | | | | | | \--- androidx.compose.runtime:runtime-saveable:1.5.4 (c) | | | | | +--- androidx.compose.ui:ui:1.5.4 | | | | | | \--- androidx.compose.ui:ui-android:1.5.4 -| | | | | | +--- androidx.activity:activity-ktx:1.7.0 -> 1.8.2 -| | | | | | | +--- androidx.activity:activity:1.8.2 (*) -| | | | | | | +--- androidx.core:core-ktx:1.9.0 -> 1.12.0 (*) -| | | | | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.6.1 -> 2.7.0 -| | | | | | | | +--- androidx.annotation:annotation:1.0.0 -> 1.7.1 (*) -| | | | | | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (*) -| | | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) -| | | | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1 -> 1.7.3 (*) -| | | | | | | | +--- androidx.lifecycle:lifecycle-common:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-common-java8:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-livedata:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-livedata-ktx:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.7.0 (c) -| | | | | | | | \--- androidx.lifecycle:lifecycle-process:2.7.0 (c) -| | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1 -> 2.7.0 (*) -| | | | | | | +--- androidx.savedstate:savedstate-ktx:1.2.1 -| | | | | | | | +--- androidx.savedstate:savedstate:1.2.1 (*) -| | | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.10 -> 1.9.22 (*) -| | | | | | | | \--- androidx.savedstate:savedstate:1.2.1 (c) -| | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) -| | | | | | | +--- androidx.activity:activity:1.8.2 (c) -| | | | | | | \--- androidx.activity:activity-compose:1.8.2 (c) +| | | | | | +--- androidx.activity:activity-ktx:1.7.0 -> 1.8.2 (*) | | | | | | +--- androidx.annotation:annotation:1.5.0 -> 1.7.1 (*) | | | | | | +--- androidx.autofill:autofill:1.0.0 | | | | | | | \--- androidx.core:core:1.1.0 -> 1.12.0 (*) diff --git a/network-testing/dependencies/dependencies.txt b/network-testing/dependencies/dependencies.txt index 07f55395351..16fa69fc2c1 100644 --- a/network-testing/dependencies/dependencies.txt +++ b/network-testing/dependencies/dependencies.txt @@ -325,6 +325,32 @@ | +--- project :stripe-ui-core | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.9.22 (*) | | +--- project :stripe-core (*) +| | +--- androidx.activity:activity-ktx:1.8.2 +| | | +--- androidx.activity:activity:1.8.2 (*) +| | | +--- androidx.core:core-ktx:1.9.0 -> 1.12.0 (*) +| | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.6.1 -> 2.7.0 +| | | | +--- androidx.annotation:annotation:1.0.0 -> 1.7.1 (*) +| | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) +| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1 -> 1.7.3 (*) +| | | | +--- androidx.lifecycle:lifecycle-common:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-livedata-ktx:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-livedata:2.7.0 (c) +| | | | \--- androidx.lifecycle:lifecycle-process:2.7.0 (c) +| | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1 -> 2.7.0 (*) +| | | +--- androidx.savedstate:savedstate-ktx:1.2.1 +| | | | +--- androidx.savedstate:savedstate:1.2.1 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.10 -> 1.9.22 (*) +| | | | \--- androidx.savedstate:savedstate:1.2.1 (c) +| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) +| | | +--- androidx.activity:activity:1.8.2 (c) +| | | \--- androidx.activity:activity-compose:1.8.2 (c) | | +--- androidx.annotation:annotation:1.7.1 (*) | | +--- androidx.core:core-ktx:1.12.0 (*) | | +--- androidx.compose.foundation:foundation:1.5.4 @@ -346,32 +372,7 @@ | | | | | | \--- androidx.compose.runtime:runtime-saveable:1.5.4 (c) | | | | | +--- androidx.compose.ui:ui:1.5.4 | | | | | | \--- androidx.compose.ui:ui-android:1.5.4 -| | | | | | +--- androidx.activity:activity-ktx:1.7.0 -> 1.8.2 -| | | | | | | +--- androidx.activity:activity:1.8.2 (*) -| | | | | | | +--- androidx.core:core-ktx:1.9.0 -> 1.12.0 (*) -| | | | | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.6.1 -> 2.7.0 -| | | | | | | | +--- androidx.annotation:annotation:1.0.0 -> 1.7.1 (*) -| | | | | | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (*) -| | | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) -| | | | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1 -> 1.7.3 (*) -| | | | | | | | +--- androidx.lifecycle:lifecycle-common:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-livedata-ktx:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-livedata:2.7.0 (c) -| | | | | | | | \--- androidx.lifecycle:lifecycle-process:2.7.0 (c) -| | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1 -> 2.7.0 (*) -| | | | | | | +--- androidx.savedstate:savedstate-ktx:1.2.1 -| | | | | | | | +--- androidx.savedstate:savedstate:1.2.1 (*) -| | | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.10 -> 1.9.22 (*) -| | | | | | | | \--- androidx.savedstate:savedstate:1.2.1 (c) -| | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) -| | | | | | | +--- androidx.activity:activity:1.8.2 (c) -| | | | | | | \--- androidx.activity:activity-compose:1.8.2 (c) +| | | | | | +--- androidx.activity:activity-ktx:1.7.0 -> 1.8.2 (*) | | | | | | +--- androidx.annotation:annotation:1.5.0 -> 1.7.1 (*) | | | | | | +--- androidx.autofill:autofill:1.0.0 | | | | | | | \--- androidx.core:core:1.1.0 -> 1.12.0 (*) diff --git a/payment-method-messaging/dependencies/dependencies.txt b/payment-method-messaging/dependencies/dependencies.txt index d53e39db39d..f132887ec20 100644 --- a/payment-method-messaging/dependencies/dependencies.txt +++ b/payment-method-messaging/dependencies/dependencies.txt @@ -335,6 +335,34 @@ | +--- project :stripe-ui-core | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.9.22 (*) | | +--- project :stripe-core (*) +| | +--- androidx.activity:activity-ktx:1.8.2 +| | | +--- androidx.activity:activity:1.8.2 (*) +| | | +--- androidx.core:core-ktx:1.9.0 -> 1.12.0 (*) +| | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.6.1 -> 2.7.0 +| | | | +--- androidx.annotation:annotation:1.0.0 -> 1.7.1 (*) +| | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) +| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1 -> 1.7.3 (*) +| | | | +--- androidx.lifecycle:lifecycle-common-java8:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-livedata-ktx:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-common:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-livedata:2.7.0 (c) +| | | | \--- androidx.lifecycle:lifecycle-process:2.7.0 (c) +| | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1 -> 2.7.0 (*) +| | | +--- androidx.savedstate:savedstate-ktx:1.2.1 +| | | | +--- androidx.savedstate:savedstate:1.2.1 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.10 -> 1.9.22 (*) +| | | | \--- androidx.savedstate:savedstate:1.2.1 (c) +| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) +| | | +--- androidx.activity:activity:1.8.2 (c) +| | | \--- androidx.activity:activity-compose:1.8.2 (c) | | +--- androidx.annotation:annotation:1.7.1 (*) | | +--- androidx.core:core-ktx:1.12.0 (*) | | +--- androidx.compose.foundation:foundation:1.5.4 @@ -356,34 +384,7 @@ | | | | | | \--- androidx.compose.runtime:runtime-saveable:1.5.4 (c) | | | | | +--- androidx.compose.ui:ui:1.5.4 | | | | | | \--- androidx.compose.ui:ui-android:1.5.4 -| | | | | | +--- androidx.activity:activity-ktx:1.7.0 -> 1.8.2 -| | | | | | | +--- androidx.activity:activity:1.8.2 (*) -| | | | | | | +--- androidx.core:core-ktx:1.9.0 -> 1.12.0 (*) -| | | | | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.6.1 -> 2.7.0 -| | | | | | | | +--- androidx.annotation:annotation:1.0.0 -> 1.7.1 (*) -| | | | | | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (*) -| | | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) -| | | | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1 -> 1.7.3 (*) -| | | | | | | | +--- androidx.lifecycle:lifecycle-common-java8:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-livedata-ktx:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-common:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-livedata:2.7.0 (c) -| | | | | | | | \--- androidx.lifecycle:lifecycle-process:2.7.0 (c) -| | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1 -> 2.7.0 (*) -| | | | | | | +--- androidx.savedstate:savedstate-ktx:1.2.1 -| | | | | | | | +--- androidx.savedstate:savedstate:1.2.1 (*) -| | | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.10 -> 1.9.22 (*) -| | | | | | | | \--- androidx.savedstate:savedstate:1.2.1 (c) -| | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) -| | | | | | | +--- androidx.activity:activity:1.8.2 (c) -| | | | | | | \--- androidx.activity:activity-compose:1.8.2 (c) +| | | | | | +--- androidx.activity:activity-ktx:1.7.0 -> 1.8.2 (*) | | | | | | +--- androidx.annotation:annotation:1.5.0 -> 1.7.1 (*) | | | | | | +--- androidx.autofill:autofill:1.0.0 | | | | | | | \--- androidx.core:core:1.1.0 -> 1.12.0 (*) diff --git a/payments-core-testing/dependencies/dependencies.txt b/payments-core-testing/dependencies/dependencies.txt index 793f278ae50..bd97f4aee9a 100644 --- a/payments-core-testing/dependencies/dependencies.txt +++ b/payments-core-testing/dependencies/dependencies.txt @@ -317,6 +317,32 @@ | +--- project :stripe-ui-core | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.9.22 (*) | | +--- project :stripe-core (*) +| | +--- androidx.activity:activity-ktx:1.8.2 +| | | +--- androidx.activity:activity:1.8.2 (*) +| | | +--- androidx.core:core-ktx:1.9.0 -> 1.12.0 (*) +| | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.6.1 -> 2.7.0 +| | | | +--- androidx.annotation:annotation:1.0.0 -> 1.7.1 (*) +| | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) +| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1 -> 1.7.3 (*) +| | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-livedata-ktx:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-common:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-livedata:2.7.0 (c) +| | | | \--- androidx.lifecycle:lifecycle-process:2.7.0 (c) +| | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1 -> 2.7.0 (*) +| | | +--- androidx.savedstate:savedstate-ktx:1.2.1 +| | | | +--- androidx.savedstate:savedstate:1.2.1 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.10 -> 1.9.22 (*) +| | | | \--- androidx.savedstate:savedstate:1.2.1 (c) +| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) +| | | +--- androidx.activity:activity:1.8.2 (c) +| | | \--- androidx.activity:activity-compose:1.8.2 (c) | | +--- androidx.annotation:annotation:1.7.1 (*) | | +--- androidx.core:core-ktx:1.12.0 (*) | | +--- androidx.compose.foundation:foundation:1.5.4 @@ -338,32 +364,7 @@ | | | | | | \--- androidx.compose.runtime:runtime-saveable:1.5.4 (c) | | | | | +--- androidx.compose.ui:ui:1.5.4 | | | | | | \--- androidx.compose.ui:ui-android:1.5.4 -| | | | | | +--- androidx.activity:activity-ktx:1.7.0 -> 1.8.2 -| | | | | | | +--- androidx.activity:activity:1.8.2 (*) -| | | | | | | +--- androidx.core:core-ktx:1.9.0 -> 1.12.0 (*) -| | | | | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.6.1 -> 2.7.0 -| | | | | | | | +--- androidx.annotation:annotation:1.0.0 -> 1.7.1 (*) -| | | | | | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (*) -| | | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) -| | | | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1 -> 1.7.3 (*) -| | | | | | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-livedata-ktx:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-common:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-livedata:2.7.0 (c) -| | | | | | | | \--- androidx.lifecycle:lifecycle-process:2.7.0 (c) -| | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1 -> 2.7.0 (*) -| | | | | | | +--- androidx.savedstate:savedstate-ktx:1.2.1 -| | | | | | | | +--- androidx.savedstate:savedstate:1.2.1 (*) -| | | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.10 -> 1.9.22 (*) -| | | | | | | | \--- androidx.savedstate:savedstate:1.2.1 (c) -| | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) -| | | | | | | +--- androidx.activity:activity:1.8.2 (c) -| | | | | | | \--- androidx.activity:activity-compose:1.8.2 (c) +| | | | | | +--- androidx.activity:activity-ktx:1.7.0 -> 1.8.2 (*) | | | | | | +--- androidx.annotation:annotation:1.5.0 -> 1.7.1 (*) | | | | | | +--- androidx.autofill:autofill:1.0.0 | | | | | | | \--- androidx.core:core:1.1.0 -> 1.12.0 (*) diff --git a/payments-core/dependencies/dependencies.txt b/payments-core/dependencies/dependencies.txt index adcd1cecd8a..9f3056c50cc 100644 --- a/payments-core/dependencies/dependencies.txt +++ b/payments-core/dependencies/dependencies.txt @@ -313,6 +313,32 @@ +--- project :stripe-ui-core | +--- org.jetbrains.kotlin:kotlin-stdlib:1.9.22 (*) | +--- project :stripe-core (*) +| +--- androidx.activity:activity-ktx:1.8.2 +| | +--- androidx.activity:activity:1.8.2 (*) +| | +--- androidx.core:core-ktx:1.9.0 -> 1.12.0 (*) +| | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.6.1 -> 2.7.0 +| | | +--- androidx.annotation:annotation:1.0.0 -> 1.7.1 (*) +| | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (*) +| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) +| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1 -> 1.7.3 (*) +| | | +--- androidx.lifecycle:lifecycle-common:2.7.0 (c) +| | | +--- androidx.lifecycle:lifecycle-livedata-core:2.7.0 (c) +| | | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.7.0 (c) +| | | +--- androidx.lifecycle:lifecycle-livedata-ktx:2.7.0 (c) +| | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (c) +| | | +--- androidx.lifecycle:lifecycle-viewmodel:2.7.0 (c) +| | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0 (c) +| | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.7.0 (c) +| | | +--- androidx.lifecycle:lifecycle-livedata:2.7.0 (c) +| | | \--- androidx.lifecycle:lifecycle-process:2.7.0 (c) +| | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1 -> 2.7.0 (*) +| | +--- androidx.savedstate:savedstate-ktx:1.2.1 +| | | +--- androidx.savedstate:savedstate:1.2.1 (*) +| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.10 -> 1.9.22 (*) +| | | \--- androidx.savedstate:savedstate:1.2.1 (c) +| | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) +| | +--- androidx.activity:activity:1.8.2 (c) +| | \--- androidx.activity:activity-compose:1.8.2 (c) | +--- androidx.annotation:annotation:1.7.1 (*) | +--- androidx.core:core-ktx:1.12.0 (*) | +--- androidx.compose.foundation:foundation:1.5.4 @@ -334,32 +360,7 @@ | | | | | \--- androidx.compose.runtime:runtime-saveable:1.5.4 (c) | | | | +--- androidx.compose.ui:ui:1.5.4 | | | | | \--- androidx.compose.ui:ui-android:1.5.4 -| | | | | +--- androidx.activity:activity-ktx:1.7.0 -> 1.8.2 -| | | | | | +--- androidx.activity:activity:1.8.2 (*) -| | | | | | +--- androidx.core:core-ktx:1.9.0 -> 1.12.0 (*) -| | | | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.6.1 -> 2.7.0 -| | | | | | | +--- androidx.annotation:annotation:1.0.0 -> 1.7.1 (*) -| | | | | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (*) -| | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) -| | | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1 -> 1.7.3 (*) -| | | | | | | +--- androidx.lifecycle:lifecycle-common:2.7.0 (c) -| | | | | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.7.0 (c) -| | | | | | | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.7.0 (c) -| | | | | | | +--- androidx.lifecycle:lifecycle-livedata-ktx:2.7.0 (c) -| | | | | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (c) -| | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.7.0 (c) -| | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0 (c) -| | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.7.0 (c) -| | | | | | | +--- androidx.lifecycle:lifecycle-livedata:2.7.0 (c) -| | | | | | | \--- androidx.lifecycle:lifecycle-process:2.7.0 (c) -| | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1 -> 2.7.0 (*) -| | | | | | +--- androidx.savedstate:savedstate-ktx:1.2.1 -| | | | | | | +--- androidx.savedstate:savedstate:1.2.1 (*) -| | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.10 -> 1.9.22 (*) -| | | | | | | \--- androidx.savedstate:savedstate:1.2.1 (c) -| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) -| | | | | | +--- androidx.activity:activity:1.8.2 (c) -| | | | | | \--- androidx.activity:activity-compose:1.8.2 (c) +| | | | | +--- androidx.activity:activity-ktx:1.7.0 -> 1.8.2 (*) | | | | | +--- androidx.annotation:annotation:1.5.0 -> 1.7.1 (*) | | | | | +--- androidx.autofill:autofill:1.0.0 | | | | | | \--- androidx.core:core:1.1.0 -> 1.12.0 (*) diff --git a/payments-ui-core/dependencies/dependencies.txt b/payments-ui-core/dependencies/dependencies.txt index cbfd74e9d39..47037bdf288 100644 --- a/payments-ui-core/dependencies/dependencies.txt +++ b/payments-ui-core/dependencies/dependencies.txt @@ -318,6 +318,32 @@ | +--- project :stripe-ui-core | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.9.22 (*) | | +--- project :stripe-core (*) +| | +--- androidx.activity:activity-ktx:1.8.2 +| | | +--- androidx.activity:activity:1.8.2 (*) +| | | +--- androidx.core:core-ktx:1.9.0 -> 1.12.0 (*) +| | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.6.1 -> 2.7.0 +| | | | +--- androidx.annotation:annotation:1.0.0 -> 1.7.1 (*) +| | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) +| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1 -> 1.7.3 (*) +| | | | +--- androidx.lifecycle:lifecycle-common:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-livedata-ktx:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-livedata:2.7.0 (c) +| | | | \--- androidx.lifecycle:lifecycle-process:2.7.0 (c) +| | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1 -> 2.7.0 (*) +| | | +--- androidx.savedstate:savedstate-ktx:1.2.1 +| | | | +--- androidx.savedstate:savedstate:1.2.1 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.10 -> 1.9.22 (*) +| | | | \--- androidx.savedstate:savedstate:1.2.1 (c) +| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) +| | | +--- androidx.activity:activity:1.8.2 (c) +| | | \--- androidx.activity:activity-compose:1.8.2 (c) | | +--- androidx.annotation:annotation:1.7.1 (*) | | +--- androidx.core:core-ktx:1.12.0 (*) | | +--- androidx.compose.foundation:foundation:1.5.4 @@ -339,32 +365,7 @@ | | | | | | \--- androidx.compose.runtime:runtime-saveable:1.5.4 (c) | | | | | +--- androidx.compose.ui:ui:1.5.4 | | | | | | \--- androidx.compose.ui:ui-android:1.5.4 -| | | | | | +--- androidx.activity:activity-ktx:1.7.0 -> 1.8.2 -| | | | | | | +--- androidx.activity:activity:1.8.2 (*) -| | | | | | | +--- androidx.core:core-ktx:1.9.0 -> 1.12.0 (*) -| | | | | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.6.1 -> 2.7.0 -| | | | | | | | +--- androidx.annotation:annotation:1.0.0 -> 1.7.1 (*) -| | | | | | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (*) -| | | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) -| | | | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1 -> 1.7.3 (*) -| | | | | | | | +--- androidx.lifecycle:lifecycle-common:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-livedata-ktx:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-livedata:2.7.0 (c) -| | | | | | | | \--- androidx.lifecycle:lifecycle-process:2.7.0 (c) -| | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1 -> 2.7.0 (*) -| | | | | | | +--- androidx.savedstate:savedstate-ktx:1.2.1 -| | | | | | | | +--- androidx.savedstate:savedstate:1.2.1 (*) -| | | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.10 -> 1.9.22 (*) -| | | | | | | | \--- androidx.savedstate:savedstate:1.2.1 (c) -| | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) -| | | | | | | +--- androidx.activity:activity:1.8.2 (c) -| | | | | | | \--- androidx.activity:activity-compose:1.8.2 (c) +| | | | | | +--- androidx.activity:activity-ktx:1.7.0 -> 1.8.2 (*) | | | | | | +--- androidx.annotation:annotation:1.5.0 -> 1.7.1 (*) | | | | | | +--- androidx.autofill:autofill:1.0.0 | | | | | | | \--- androidx.core:core:1.1.0 -> 1.12.0 (*) diff --git a/payments/dependencies/dependencies.txt b/payments/dependencies/dependencies.txt index 020fbccb9fa..fac48acd931 100644 --- a/payments/dependencies/dependencies.txt +++ b/payments/dependencies/dependencies.txt @@ -333,6 +333,34 @@ | +--- project :stripe-ui-core | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.9.22 (*) | | +--- project :stripe-core (*) +| | +--- androidx.activity:activity-ktx:1.8.2 +| | | +--- androidx.activity:activity:1.8.2 (*) +| | | +--- androidx.core:core-ktx:1.9.0 -> 1.12.0 (*) +| | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.6.1 -> 2.7.0 +| | | | +--- androidx.annotation:annotation:1.0.0 -> 1.7.1 (*) +| | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) +| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1 -> 1.7.3 (*) +| | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-livedata-ktx:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-common:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-livedata:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-common-java8:2.7.0 (c) +| | | | \--- androidx.lifecycle:lifecycle-process:2.7.0 (c) +| | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1 -> 2.7.0 (*) +| | | +--- androidx.savedstate:savedstate-ktx:1.2.1 +| | | | +--- androidx.savedstate:savedstate:1.2.1 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.10 -> 1.9.22 (*) +| | | | \--- androidx.savedstate:savedstate:1.2.1 (c) +| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) +| | | +--- androidx.activity:activity:1.8.2 (c) +| | | \--- androidx.activity:activity-compose:1.8.2 (c) | | +--- androidx.annotation:annotation:1.7.1 (*) | | +--- androidx.core:core-ktx:1.12.0 (*) | | +--- androidx.compose.foundation:foundation:1.5.4 @@ -355,34 +383,7 @@ | | | | | | \--- androidx.compose.runtime:runtime-saveable:1.5.4 (c) | | | | | +--- androidx.compose.ui:ui:1.5.4 | | | | | | \--- androidx.compose.ui:ui-android:1.5.4 -| | | | | | +--- androidx.activity:activity-ktx:1.7.0 -> 1.8.2 -| | | | | | | +--- androidx.activity:activity:1.8.2 (*) -| | | | | | | +--- androidx.core:core-ktx:1.9.0 -> 1.12.0 (*) -| | | | | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.6.1 -> 2.7.0 -| | | | | | | | +--- androidx.annotation:annotation:1.0.0 -> 1.7.1 (*) -| | | | | | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (*) -| | | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) -| | | | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1 -> 1.7.3 (*) -| | | | | | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-livedata-ktx:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-common:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-livedata:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-common-java8:2.7.0 (c) -| | | | | | | | \--- androidx.lifecycle:lifecycle-process:2.7.0 (c) -| | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1 -> 2.7.0 (*) -| | | | | | | +--- androidx.savedstate:savedstate-ktx:1.2.1 -| | | | | | | | +--- androidx.savedstate:savedstate:1.2.1 (*) -| | | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.10 -> 1.9.22 (*) -| | | | | | | | \--- androidx.savedstate:savedstate:1.2.1 (c) -| | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) -| | | | | | | +--- androidx.activity:activity:1.8.2 (c) -| | | | | | | \--- androidx.activity:activity-compose:1.8.2 (c) +| | | | | | +--- androidx.activity:activity-ktx:1.7.0 -> 1.8.2 (*) | | | | | | +--- androidx.annotation:annotation:1.5.0 -> 1.7.1 (*) | | | | | | +--- androidx.autofill:autofill:1.0.0 | | | | | | | \--- androidx.core:core:1.1.0 -> 1.12.0 (*) diff --git a/paymentsheet-example/dependencies/dependencies.txt b/paymentsheet-example/dependencies/dependencies.txt index 420660e0c34..32f683a3591 100644 --- a/paymentsheet-example/dependencies/dependencies.txt +++ b/paymentsheet-example/dependencies/dependencies.txt @@ -336,6 +336,34 @@ | | +--- project :stripe-ui-core | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.9.22 (*) | | | +--- project :stripe-core (*) +| | | +--- androidx.activity:activity-ktx:1.8.2 +| | | | +--- androidx.activity:activity:1.8.2 (*) +| | | | +--- androidx.core:core-ktx:1.9.0 -> 1.12.0 (*) +| | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.6.1 -> 2.7.0 +| | | | | +--- androidx.annotation:annotation:1.0.0 -> 1.7.1 (*) +| | | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (*) +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) +| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1 -> 1.7.3 (*) +| | | | | +--- androidx.lifecycle:lifecycle-common-java8:2.7.0 (c) +| | | | | +--- androidx.lifecycle:lifecycle-livedata:2.7.0 (c) +| | | | | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.7.0 (c) +| | | | | +--- androidx.lifecycle:lifecycle-livedata-ktx:2.7.0 (c) +| | | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (c) +| | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.7.0 (c) +| | | | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.7.0 (c) +| | | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0 (c) +| | | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.7.0 (c) +| | | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.7.0 (c) +| | | | | +--- androidx.lifecycle:lifecycle-common:2.7.0 (c) +| | | | | \--- androidx.lifecycle:lifecycle-process:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1 -> 2.7.0 (*) +| | | | +--- androidx.savedstate:savedstate-ktx:1.2.1 +| | | | | +--- androidx.savedstate:savedstate:1.2.1 (*) +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.10 -> 1.9.22 (*) +| | | | | \--- androidx.savedstate:savedstate:1.2.1 (c) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) +| | | | +--- androidx.activity:activity:1.8.2 (c) +| | | | \--- androidx.activity:activity-compose:1.8.2 (c) | | | +--- androidx.annotation:annotation:1.7.1 (*) | | | +--- androidx.core:core-ktx:1.12.0 (*) | | | +--- androidx.compose.foundation:foundation:1.5.4 @@ -358,34 +386,7 @@ | | | | | | | \--- androidx.compose.runtime:runtime-saveable:1.5.4 (c) | | | | | | +--- androidx.compose.ui:ui:1.5.4 | | | | | | | \--- androidx.compose.ui:ui-android:1.5.4 -| | | | | | | +--- androidx.activity:activity-ktx:1.7.0 -> 1.8.2 -| | | | | | | | +--- androidx.activity:activity:1.8.2 (*) -| | | | | | | | +--- androidx.core:core-ktx:1.9.0 -> 1.12.0 (*) -| | | | | | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.6.1 -> 2.7.0 -| | | | | | | | | +--- androidx.annotation:annotation:1.0.0 -> 1.7.1 (*) -| | | | | | | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (*) -| | | | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) -| | | | | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1 -> 1.7.3 (*) -| | | | | | | | | +--- androidx.lifecycle:lifecycle-common-java8:2.7.0 (c) -| | | | | | | | | +--- androidx.lifecycle:lifecycle-livedata:2.7.0 (c) -| | | | | | | | | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.7.0 (c) -| | | | | | | | | +--- androidx.lifecycle:lifecycle-livedata-ktx:2.7.0 (c) -| | | | | | | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (c) -| | | | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.7.0 (c) -| | | | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.7.0 (c) -| | | | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0 (c) -| | | | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.7.0 (c) -| | | | | | | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.7.0 (c) -| | | | | | | | | +--- androidx.lifecycle:lifecycle-common:2.7.0 (c) -| | | | | | | | | \--- androidx.lifecycle:lifecycle-process:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1 -> 2.7.0 (*) -| | | | | | | | +--- androidx.savedstate:savedstate-ktx:1.2.1 -| | | | | | | | | +--- androidx.savedstate:savedstate:1.2.1 (*) -| | | | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.10 -> 1.9.22 (*) -| | | | | | | | | \--- androidx.savedstate:savedstate:1.2.1 (c) -| | | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) -| | | | | | | | +--- androidx.activity:activity:1.8.2 (c) -| | | | | | | | \--- androidx.activity:activity-compose:1.8.2 (c) +| | | | | | | +--- androidx.activity:activity-ktx:1.7.0 -> 1.8.2 (*) | | | | | | | +--- androidx.annotation:annotation:1.5.0 -> 1.7.1 (*) | | | | | | | +--- androidx.autofill:autofill:1.0.0 | | | | | | | | \--- androidx.core:core:1.1.0 -> 1.12.0 (*) diff --git a/paymentsheet/dependencies/dependencies.txt b/paymentsheet/dependencies/dependencies.txt index d37b2c5ac70..00b5f215929 100644 --- a/paymentsheet/dependencies/dependencies.txt +++ b/paymentsheet/dependencies/dependencies.txt @@ -333,6 +333,34 @@ | +--- project :stripe-ui-core | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.9.22 (*) | | +--- project :stripe-core (*) +| | +--- androidx.activity:activity-ktx:1.8.2 +| | | +--- androidx.activity:activity:1.8.2 (*) +| | | +--- androidx.core:core-ktx:1.9.0 -> 1.12.0 (*) +| | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.6.1 -> 2.7.0 +| | | | +--- androidx.annotation:annotation:1.0.0 -> 1.7.1 (*) +| | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) +| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1 -> 1.7.3 (*) +| | | | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-livedata-ktx:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-livedata:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-common:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-common-java8:2.7.0 (c) +| | | | \--- androidx.lifecycle:lifecycle-process:2.7.0 (c) +| | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1 -> 2.7.0 (*) +| | | +--- androidx.savedstate:savedstate-ktx:1.2.1 +| | | | +--- androidx.savedstate:savedstate:1.2.1 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.10 -> 1.9.22 (*) +| | | | \--- androidx.savedstate:savedstate:1.2.1 (c) +| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) +| | | +--- androidx.activity:activity:1.8.2 (c) +| | | \--- androidx.activity:activity-compose:1.8.2 (c) | | +--- androidx.annotation:annotation:1.7.1 (*) | | +--- androidx.core:core-ktx:1.12.0 (*) | | +--- androidx.compose.foundation:foundation:1.5.4 @@ -355,34 +383,7 @@ | | | | | | \--- androidx.compose.runtime:runtime-saveable:1.5.4 (c) | | | | | +--- androidx.compose.ui:ui:1.5.4 | | | | | | \--- androidx.compose.ui:ui-android:1.5.4 -| | | | | | +--- androidx.activity:activity-ktx:1.7.0 -> 1.8.2 -| | | | | | | +--- androidx.activity:activity:1.8.2 (*) -| | | | | | | +--- androidx.core:core-ktx:1.9.0 -> 1.12.0 (*) -| | | | | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.6.1 -> 2.7.0 -| | | | | | | | +--- androidx.annotation:annotation:1.0.0 -> 1.7.1 (*) -| | | | | | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (*) -| | | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) -| | | | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1 -> 1.7.3 (*) -| | | | | | | | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-livedata-ktx:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-livedata:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-common:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-common-java8:2.7.0 (c) -| | | | | | | | \--- androidx.lifecycle:lifecycle-process:2.7.0 (c) -| | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1 -> 2.7.0 (*) -| | | | | | | +--- androidx.savedstate:savedstate-ktx:1.2.1 -| | | | | | | | +--- androidx.savedstate:savedstate:1.2.1 (*) -| | | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.10 -> 1.9.22 (*) -| | | | | | | | \--- androidx.savedstate:savedstate:1.2.1 (c) -| | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) -| | | | | | | +--- androidx.activity:activity:1.8.2 (c) -| | | | | | | \--- androidx.activity:activity-compose:1.8.2 (c) +| | | | | | +--- androidx.activity:activity-ktx:1.7.0 -> 1.8.2 (*) | | | | | | +--- androidx.annotation:annotation:1.5.0 -> 1.7.1 (*) | | | | | | +--- androidx.autofill:autofill:1.0.0 | | | | | | | \--- androidx.core:core:1.1.0 -> 1.12.0 (*) diff --git a/stripe-test-e2e/dependencies/dependencies.txt b/stripe-test-e2e/dependencies/dependencies.txt index e8b7c01325b..f88fd5447de 100644 --- a/stripe-test-e2e/dependencies/dependencies.txt +++ b/stripe-test-e2e/dependencies/dependencies.txt @@ -335,6 +335,34 @@ | +--- project :stripe-ui-core | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.9.22 (*) | | +--- project :stripe-core (*) + | | +--- androidx.activity:activity-ktx:1.8.2 + | | | +--- androidx.activity:activity:1.8.2 (*) + | | | +--- androidx.core:core-ktx:1.9.0 -> 1.12.0 (*) + | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.6.1 -> 2.7.0 + | | | | +--- androidx.annotation:annotation:1.0.0 -> 1.7.1 (*) + | | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (*) + | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) + | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1 -> 1.7.3 (*) + | | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.7.0 (c) + | | | | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.7.0 (c) + | | | | +--- androidx.lifecycle:lifecycle-livedata-ktx:2.7.0 (c) + | | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (c) + | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.7.0 (c) + | | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0 (c) + | | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.7.0 (c) + | | | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.7.0 (c) + | | | | +--- androidx.lifecycle:lifecycle-common:2.7.0 (c) + | | | | +--- androidx.lifecycle:lifecycle-livedata:2.7.0 (c) + | | | | +--- androidx.lifecycle:lifecycle-common-java8:2.7.0 (c) + | | | | \--- androidx.lifecycle:lifecycle-process:2.7.0 (c) + | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1 -> 2.7.0 (*) + | | | +--- androidx.savedstate:savedstate-ktx:1.2.1 + | | | | +--- androidx.savedstate:savedstate:1.2.1 (*) + | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.10 -> 1.9.22 (*) + | | | | \--- androidx.savedstate:savedstate:1.2.1 (c) + | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) + | | | +--- androidx.activity:activity:1.8.2 (c) + | | | \--- androidx.activity:activity-compose:1.8.2 (c) | | +--- androidx.annotation:annotation:1.7.1 (*) | | +--- androidx.core:core-ktx:1.12.0 (*) | | +--- androidx.compose.foundation:foundation:1.5.4 @@ -357,34 +385,7 @@ | | | | | | \--- androidx.compose.runtime:runtime-saveable:1.5.4 (c) | | | | | +--- androidx.compose.ui:ui:1.5.4 | | | | | | \--- androidx.compose.ui:ui-android:1.5.4 - | | | | | | +--- androidx.activity:activity-ktx:1.7.0 -> 1.8.2 - | | | | | | | +--- androidx.activity:activity:1.8.2 (*) - | | | | | | | +--- androidx.core:core-ktx:1.9.0 -> 1.12.0 (*) - | | | | | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.6.1 -> 2.7.0 - | | | | | | | | +--- androidx.annotation:annotation:1.0.0 -> 1.7.1 (*) - | | | | | | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (*) - | | | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) - | | | | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1 -> 1.7.3 (*) - | | | | | | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.7.0 (c) - | | | | | | | | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.7.0 (c) - | | | | | | | | +--- androidx.lifecycle:lifecycle-livedata-ktx:2.7.0 (c) - | | | | | | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (c) - | | | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.7.0 (c) - | | | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0 (c) - | | | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.7.0 (c) - | | | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.7.0 (c) - | | | | | | | | +--- androidx.lifecycle:lifecycle-common:2.7.0 (c) - | | | | | | | | +--- androidx.lifecycle:lifecycle-livedata:2.7.0 (c) - | | | | | | | | +--- androidx.lifecycle:lifecycle-common-java8:2.7.0 (c) - | | | | | | | | \--- androidx.lifecycle:lifecycle-process:2.7.0 (c) - | | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1 -> 2.7.0 (*) - | | | | | | | +--- androidx.savedstate:savedstate-ktx:1.2.1 - | | | | | | | | +--- androidx.savedstate:savedstate:1.2.1 (*) - | | | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.10 -> 1.9.22 (*) - | | | | | | | | \--- androidx.savedstate:savedstate:1.2.1 (c) - | | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) - | | | | | | | +--- androidx.activity:activity:1.8.2 (c) - | | | | | | | \--- androidx.activity:activity-compose:1.8.2 (c) + | | | | | | +--- androidx.activity:activity-ktx:1.7.0 -> 1.8.2 (*) | | | | | | +--- androidx.annotation:annotation:1.5.0 -> 1.7.1 (*) | | | | | | +--- androidx.autofill:autofill:1.0.0 | | | | | | | \--- androidx.core:core:1.1.0 -> 1.12.0 (*) diff --git a/stripe-ui-core/dependencies/dependencies.txt b/stripe-ui-core/dependencies/dependencies.txt index 27921d72ec0..2372c12f8fd 100644 --- a/stripe-ui-core/dependencies/dependencies.txt +++ b/stripe-ui-core/dependencies/dependencies.txt @@ -47,13 +47,13 @@ | | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.7.3 (*) | | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.20 (*) | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1 -> 1.7.3 (*) +| | | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.7.0 (c) | | | | | +--- androidx.lifecycle:lifecycle-process:2.7.0 (c) | | | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (c) | | | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.7.0 (c) | | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.7.0 (c) | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0 (c) -| | | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.7.0 (c) -| | | | | \--- androidx.lifecycle:lifecycle-livedata-core:2.7.0 (c) +| | | | | \--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.7.0 (c) | | | | +--- androidx.profileinstaller:profileinstaller:1.3.0 | | | | | +--- androidx.annotation:annotation:1.2.0 -> 1.7.1 (*) | | | | | +--- androidx.concurrent:concurrent-futures:1.1.0 (*) @@ -64,12 +64,12 @@ | | | | | \--- com.google.guava:listenablefuture:1.0 | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) | | | | +--- androidx.lifecycle:lifecycle-common:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.7.0 (c) | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.7.0 (c) | | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0 (c) -| | | | +--- androidx.lifecycle:lifecycle-process:2.7.0 (c) -| | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.7.0 (c) | | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.7.0 (c) -| | | | \--- androidx.lifecycle:lifecycle-livedata-core:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.7.0 (c) +| | | | \--- androidx.lifecycle:lifecycle-process:2.7.0 (c) | | | +--- androidx.versionedparcelable:versionedparcelable:1.1.1 | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.7.1 (*) | | | | \--- androidx.collection:collection:1.0.0 -> 1.1.0 (*) @@ -101,31 +101,94 @@ | | | +--- androidx.annotation:annotation:1.1.0 -> 1.7.1 (*) | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (c) -| | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0 (c) -| | | +--- androidx.lifecycle:lifecycle-common:2.7.0 (c) -| | | +--- androidx.lifecycle:lifecycle-process:2.7.0 (c) | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.7.0 (c) +| | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0 (c) | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.7.0 (c) -| | | \--- androidx.lifecycle:lifecycle-livedata-core:2.7.0 (c) +| | | +--- androidx.lifecycle:lifecycle-common:2.7.0 (c) +| | | +--- androidx.lifecycle:lifecycle-livedata-core:2.7.0 (c) +| | | \--- androidx.lifecycle:lifecycle-process:2.7.0 (c) | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1 -> 1.7.3 (*) +| | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.7.0 (c) | | +--- androidx.lifecycle:lifecycle-viewmodel:2.7.0 (c) | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (c) -| | +--- androidx.lifecycle:lifecycle-common:2.7.0 (c) -| | +--- androidx.lifecycle:lifecycle-process:2.7.0 (c) -| | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.7.0 (c) | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.7.0 (c) -| | \--- androidx.lifecycle:lifecycle-livedata-core:2.7.0 (c) +| | +--- androidx.lifecycle:lifecycle-common:2.7.0 (c) +| | +--- androidx.lifecycle:lifecycle-livedata-core:2.7.0 (c) +| | \--- androidx.lifecycle:lifecycle-process:2.7.0 (c) | \--- org.jetbrains.kotlin:kotlin-parcelize-runtime:1.9.22 | +--- org.jetbrains.kotlin:kotlin-stdlib:1.9.22 (*) | \--- org.jetbrains.kotlin:kotlin-android-extensions-runtime:1.9.22 | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.22 (*) -+--- androidx.annotation:annotation:1.7.1 (*) -+--- androidx.core:core-ktx:1.12.0 -| +--- androidx.annotation:annotation:1.1.0 -> 1.7.1 (*) -| +--- androidx.core:core:1.12.0 (*) ++--- androidx.activity:activity-ktx:1.8.2 +| +--- androidx.activity:activity:1.8.2 +| | +--- androidx.annotation:annotation:1.1.0 -> 1.7.1 (*) +| | +--- androidx.collection:collection:1.0.0 -> 1.1.0 (*) +| | +--- androidx.core:core:1.8.0 -> 1.12.0 (*) +| | +--- androidx.lifecycle:lifecycle-runtime:2.6.1 -> 2.7.0 (*) +| | +--- androidx.lifecycle:lifecycle-viewmodel:2.6.1 -> 2.7.0 (*) +| | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.6.1 -> 2.7.0 +| | | +--- androidx.annotation:annotation:1.0.0 -> 1.7.1 (*) +| | | +--- androidx.core:core-ktx:1.2.0 -> 1.12.0 +| | | | +--- androidx.annotation:annotation:1.1.0 -> 1.7.1 (*) +| | | | +--- androidx.core:core:1.12.0 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) +| | | | \--- androidx.core:core:1.12.0 (c) +| | | +--- androidx.lifecycle:lifecycle-livedata-core:2.7.0 +| | | | +--- androidx.arch.core:core-common:2.2.0 (*) +| | | | +--- androidx.arch.core:core-runtime:2.2.0 (*) +| | | | +--- androidx.lifecycle:lifecycle-common:2.7.0 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) +| | | | +--- androidx.lifecycle:lifecycle-common:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-process:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0 (c) +| | | | \--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.7.0 (c) +| | | +--- androidx.lifecycle:lifecycle-viewmodel:2.7.0 (*) +| | | +--- androidx.savedstate:savedstate:1.2.1 +| | | | +--- androidx.annotation:annotation:1.1.0 -> 1.7.1 (*) +| | | | +--- androidx.arch.core:core-common:2.1.0 -> 2.2.0 (*) +| | | | +--- androidx.lifecycle:lifecycle-common:2.6.1 -> 2.7.0 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.10 -> 1.9.22 (*) +| | | | \--- androidx.savedstate:savedstate-ktx:1.2.1 (c) +| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) +| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1 -> 1.7.3 (*) +| | | +--- androidx.lifecycle:lifecycle-common:2.7.0 (c) +| | | +--- androidx.lifecycle:lifecycle-livedata-core:2.7.0 (c) +| | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (c) +| | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.7.0 (c) +| | | +--- androidx.lifecycle:lifecycle-viewmodel:2.7.0 (c) +| | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0 (c) +| | | \--- androidx.lifecycle:lifecycle-process:2.7.0 (c) +| | +--- androidx.profileinstaller:profileinstaller:1.3.0 (*) +| | +--- androidx.savedstate:savedstate:1.2.1 (*) +| | +--- androidx.tracing:tracing:1.0.0 (*) +| | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) +| | \--- androidx.activity:activity-ktx:1.8.2 (c) +| +--- androidx.core:core-ktx:1.9.0 -> 1.12.0 (*) +| +--- androidx.lifecycle:lifecycle-runtime-ktx:2.6.1 -> 2.7.0 +| | +--- androidx.annotation:annotation:1.0.0 -> 1.7.1 (*) +| | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (*) +| | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) +| | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1 -> 1.7.3 (*) +| | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (c) +| | +--- androidx.lifecycle:lifecycle-viewmodel:2.7.0 (c) +| | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0 (c) +| | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.7.0 (c) +| | +--- androidx.lifecycle:lifecycle-common:2.7.0 (c) +| | +--- androidx.lifecycle:lifecycle-livedata-core:2.7.0 (c) +| | \--- androidx.lifecycle:lifecycle-process:2.7.0 (c) +| +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1 -> 2.7.0 (*) +| +--- androidx.savedstate:savedstate-ktx:1.2.1 +| | +--- androidx.savedstate:savedstate:1.2.1 (*) +| | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.10 -> 1.9.22 (*) +| | \--- androidx.savedstate:savedstate:1.2.1 (c) | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) -| \--- androidx.core:core:1.12.0 (c) +| \--- androidx.activity:activity:1.8.2 (c) ++--- androidx.annotation:annotation:1.7.1 (*) ++--- androidx.core:core-ktx:1.12.0 (*) +--- androidx.compose.foundation:foundation:1.5.4 | \--- androidx.compose.foundation:foundation-android:1.5.4 | +--- androidx.annotation:annotation:1.1.0 -> 1.7.1 (*) @@ -144,69 +207,7 @@ | | | | \--- androidx.compose.runtime:runtime-saveable:1.5.4 (c) | | | +--- androidx.compose.ui:ui:1.5.4 | | | | \--- androidx.compose.ui:ui-android:1.5.4 -| | | | +--- androidx.activity:activity-ktx:1.7.0 -| | | | | +--- androidx.activity:activity:1.7.0 -| | | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.7.1 (*) -| | | | | | +--- androidx.collection:collection:1.0.0 -> 1.1.0 (*) -| | | | | | +--- androidx.core:core:1.8.0 -> 1.12.0 (*) -| | | | | | +--- androidx.lifecycle:lifecycle-runtime:2.6.1 -> 2.7.0 (*) -| | | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.6.1 -> 2.7.0 (*) -| | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.6.1 -> 2.7.0 -| | | | | | | +--- androidx.annotation:annotation:1.0.0 -> 1.7.1 (*) -| | | | | | | +--- androidx.core:core-ktx:1.2.0 -> 1.12.0 (*) -| | | | | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.7.0 -| | | | | | | | +--- androidx.arch.core:core-common:2.2.0 (*) -| | | | | | | | +--- androidx.arch.core:core-runtime:2.2.0 (*) -| | | | | | | | +--- androidx.lifecycle:lifecycle-common:2.7.0 (*) -| | | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) -| | | | | | | | +--- androidx.lifecycle:lifecycle-common:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-process:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0 (c) -| | | | | | | | \--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.7.0 (c) -| | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.7.0 (*) -| | | | | | | +--- androidx.savedstate:savedstate:1.2.1 -| | | | | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.7.1 (*) -| | | | | | | | +--- androidx.arch.core:core-common:2.1.0 -> 2.2.0 (*) -| | | | | | | | +--- androidx.lifecycle:lifecycle-common:2.6.1 -> 2.7.0 (*) -| | | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.10 -> 1.9.22 (*) -| | | | | | | | \--- androidx.savedstate:savedstate-ktx:1.2.1 (c) -| | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) -| | | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1 -> 1.7.3 (*) -| | | | | | | +--- androidx.lifecycle:lifecycle-common:2.7.0 (c) -| | | | | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.7.0 (c) -| | | | | | | +--- androidx.lifecycle:lifecycle-process:2.7.0 (c) -| | | | | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (c) -| | | | | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.7.0 (c) -| | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.7.0 (c) -| | | | | | | \--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0 (c) -| | | | | | +--- androidx.profileinstaller:profileinstaller:1.3.0 (*) -| | | | | | +--- androidx.savedstate:savedstate:1.2.1 (*) -| | | | | | +--- androidx.tracing:tracing:1.0.0 (*) -| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.10 -> 1.9.22 (*) -| | | | | | \--- androidx.activity:activity-ktx:1.7.0 (c) -| | | | | +--- androidx.core:core-ktx:1.1.0 -> 1.12.0 (*) -| | | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.6.1 -> 2.7.0 -| | | | | | +--- androidx.annotation:annotation:1.0.0 -> 1.7.1 (*) -| | | | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (*) -| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) -| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1 -> 1.7.3 (*) -| | | | | | +--- androidx.lifecycle:lifecycle-common:2.7.0 (c) -| | | | | | +--- androidx.lifecycle:lifecycle-process:2.7.0 (c) -| | | | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (c) -| | | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.7.0 (c) -| | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0 (c) -| | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.7.0 (c) -| | | | | | \--- androidx.lifecycle:lifecycle-livedata-core:2.7.0 (c) -| | | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1 -> 2.7.0 (*) -| | | | | +--- androidx.savedstate:savedstate-ktx:1.2.1 -| | | | | | +--- androidx.savedstate:savedstate:1.2.1 (*) -| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.10 -> 1.9.22 (*) -| | | | | | \--- androidx.savedstate:savedstate:1.2.1 (c) -| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.10 -> 1.9.22 (*) -| | | | | \--- androidx.activity:activity:1.7.0 (c) +| | | | +--- androidx.activity:activity-ktx:1.7.0 -> 1.8.2 (*) | | | | +--- androidx.annotation:annotation:1.5.0 -> 1.7.1 (*) | | | | +--- androidx.autofill:autofill:1.0.0 | | | | | \--- androidx.core:core:1.1.0 -> 1.12.0 (*) @@ -282,12 +283,12 @@ | | | | | | | +--- androidx.startup:startup-runtime:1.1.1 (*) | | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) | | | | | | | +--- androidx.lifecycle:lifecycle-common:2.7.0 (c) +| | | | | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.7.0 (c) | | | | | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (c) | | | | | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.7.0 (c) | | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.7.0 (c) | | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0 (c) -| | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.7.0 (c) -| | | | | | | \--- androidx.lifecycle:lifecycle-livedata-core:2.7.0 (c) +| | | | | | | \--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.7.0 (c) | | | | | | \--- androidx.startup:startup-runtime:1.0.0 -> 1.1.1 (*) | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.21 -> 1.9.22 (*) | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4 -> 1.7.3 (*) diff --git a/wechatpay/dependencies/dependencies.txt b/wechatpay/dependencies/dependencies.txt index 615ceeb1a6b..79fdd538c5f 100644 --- a/wechatpay/dependencies/dependencies.txt +++ b/wechatpay/dependencies/dependencies.txt @@ -315,6 +315,32 @@ | +--- project :stripe-ui-core | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.9.22 (*) | | +--- project :stripe-core (*) +| | +--- androidx.activity:activity-ktx:1.8.2 +| | | +--- androidx.activity:activity:1.8.2 (*) +| | | +--- androidx.core:core-ktx:1.9.0 -> 1.12.0 (*) +| | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.6.1 -> 2.7.0 +| | | | +--- androidx.annotation:annotation:1.0.0 -> 1.7.1 (*) +| | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) +| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1 -> 1.7.3 (*) +| | | | +--- androidx.lifecycle:lifecycle-common:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-livedata-ktx:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.7.0 (c) +| | | | +--- androidx.lifecycle:lifecycle-livedata:2.7.0 (c) +| | | | \--- androidx.lifecycle:lifecycle-process:2.7.0 (c) +| | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1 -> 2.7.0 (*) +| | | +--- androidx.savedstate:savedstate-ktx:1.2.1 +| | | | +--- androidx.savedstate:savedstate:1.2.1 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.10 -> 1.9.22 (*) +| | | | \--- androidx.savedstate:savedstate:1.2.1 (c) +| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) +| | | +--- androidx.activity:activity:1.8.2 (c) +| | | \--- androidx.activity:activity-compose:1.8.2 (c) | | +--- androidx.annotation:annotation:1.7.1 (*) | | +--- androidx.core:core-ktx:1.12.0 (*) | | +--- androidx.compose.foundation:foundation:1.5.4 @@ -336,32 +362,7 @@ | | | | | | \--- androidx.compose.runtime:runtime-saveable:1.5.4 (c) | | | | | +--- androidx.compose.ui:ui:1.5.4 | | | | | | \--- androidx.compose.ui:ui-android:1.5.4 -| | | | | | +--- androidx.activity:activity-ktx:1.7.0 -> 1.8.2 -| | | | | | | +--- androidx.activity:activity:1.8.2 (*) -| | | | | | | +--- androidx.core:core-ktx:1.9.0 -> 1.12.0 (*) -| | | | | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.6.1 -> 2.7.0 -| | | | | | | | +--- androidx.annotation:annotation:1.0.0 -> 1.7.1 (*) -| | | | | | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (*) -| | | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) -| | | | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1 -> 1.7.3 (*) -| | | | | | | | +--- androidx.lifecycle:lifecycle-common:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-livedata-ktx:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.7.0 (c) -| | | | | | | | +--- androidx.lifecycle:lifecycle-livedata:2.7.0 (c) -| | | | | | | | \--- androidx.lifecycle:lifecycle-process:2.7.0 (c) -| | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1 -> 2.7.0 (*) -| | | | | | | +--- androidx.savedstate:savedstate-ktx:1.2.1 -| | | | | | | | +--- androidx.savedstate:savedstate:1.2.1 (*) -| | | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.10 -> 1.9.22 (*) -| | | | | | | | \--- androidx.savedstate:savedstate:1.2.1 (c) -| | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 1.9.22 (*) -| | | | | | | +--- androidx.activity:activity:1.8.2 (c) -| | | | | | | \--- androidx.activity:activity-compose:1.8.2 (c) +| | | | | | +--- androidx.activity:activity-ktx:1.7.0 -> 1.8.2 (*) | | | | | | +--- androidx.annotation:annotation:1.5.0 -> 1.7.1 (*) | | | | | | +--- androidx.autofill:autofill:1.0.0 | | | | | | | \--- androidx.core:core:1.1.0 -> 1.12.0 (*)