Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve pane transitions in bank auth flow #8682

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions financial-connections/api/financial-connections.api
Original file line number Diff line number Diff line change
Expand Up @@ -2053,13 +2053,13 @@ public final class com/stripe/android/financialconnections/ui/components/Composa
public static final field INSTANCE Lcom/stripe/android/financialconnections/ui/components/ComposableSingletons$TopAppBarKt;
public static field lambda-1 Lkotlin/jvm/functions/Function2;
public static field lambda-2 Lkotlin/jvm/functions/Function2;
public static field lambda-3 Lkotlin/jvm/functions/Function2;
public static field lambda-3 Lkotlin/jvm/functions/Function3;
public static field lambda-4 Lkotlin/jvm/functions/Function2;
public static field lambda-5 Lkotlin/jvm/functions/Function2;
public fun <init> ()V
public final fun getLambda-1$financial_connections_release ()Lkotlin/jvm/functions/Function2;
public final fun getLambda-2$financial_connections_release ()Lkotlin/jvm/functions/Function2;
public final fun getLambda-3$financial_connections_release ()Lkotlin/jvm/functions/Function2;
public final fun getLambda-3$financial_connections_release ()Lkotlin/jvm/functions/Function3;
public final fun getLambda-4$financial_connections_release ()Lkotlin/jvm/functions/Function2;
public final fun getLambda-5$financial_connections_release ()Lkotlin/jvm/functions/Function2;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,15 @@ import com.stripe.android.financialconnections.utils.error
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.parcelize.Parcelize
import java.util.Date
import javax.inject.Named
import com.stripe.android.financialconnections.features.partnerauth.SharedPartnerAuthState.AuthenticationStatus as Status

private val NavigationDelayMillis = 500L

internal class PartnerAuthViewModel @AssistedInject constructor(
private val completeAuthorizationSession: CompleteAuthorizationSession,
private val createAuthorizationSession: PostAuthorizationSession,
Expand Down Expand Up @@ -410,6 +413,7 @@ internal class PartnerAuthViewModel @AssistedInject constructor(
AccountPicker(referrer = PANE)
}
FinancialConnections.emitEvent(Name.INSTITUTION_AUTHORIZED)
delay(NavigationDelayMillis)
navigationManager.tryNavigateTo(nextPane)
}.onFailure {
eventTracker.logError(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ internal sealed class Destination(
val closeWithoutConfirmation: Boolean,
val logPaneLaunched: Boolean,
extraArgs: List<NamedNavArgument> = emptyList(),
val fadeOnlyTransition: Boolean,
protected val composable: @Composable (NavBackStackEntry) -> Unit
) {

Expand Down Expand Up @@ -95,62 +96,71 @@ internal sealed class Destination(
route = Pane.INSTITUTION_PICKER.value,
closeWithoutConfirmation = false,
logPaneLaunched = true,
fadeOnlyTransition = false,
composable = { InstitutionPickerScreen(it) },
)

data object Consent : Destination(
route = Pane.CONSENT.value,
closeWithoutConfirmation = true,
logPaneLaunched = true,
fadeOnlyTransition = false,
composable = { ConsentScreen() }
)

data object PartnerAuthDrawer : Destination(
route = Pane.PARTNER_AUTH_DRAWER.value,
closeWithoutConfirmation = false,
logPaneLaunched = true,
fadeOnlyTransition = false,
composable = { PartnerAuthScreen(inModal = true) }
)

data object PartnerAuth : Destination(
route = Pane.PARTNER_AUTH.value,
closeWithoutConfirmation = false,
logPaneLaunched = true,
fadeOnlyTransition = false,
composable = { PartnerAuthScreen(inModal = false) }
)

data object AccountPicker : Destination(
route = Pane.ACCOUNT_PICKER.value,
closeWithoutConfirmation = false,
logPaneLaunched = true,
fadeOnlyTransition = false,
composable = { AccountPickerScreen() }
)

data object Success : Destination(
route = Pane.SUCCESS.value,
closeWithoutConfirmation = true,
logPaneLaunched = true,
fadeOnlyTransition = false,
composable = { SuccessScreen() }
)

data object ManualEntry : Destination(
route = Pane.MANUAL_ENTRY.value,
closeWithoutConfirmation = false,
logPaneLaunched = true,
fadeOnlyTransition = false,
composable = { ManualEntryScreen() }
)

data object AttachLinkedPaymentAccount : Destination(
route = Pane.ATTACH_LINKED_PAYMENT_ACCOUNT.value,
closeWithoutConfirmation = false,
logPaneLaunched = true,
fadeOnlyTransition = true,
composable = { AttachPaymentScreen() }
)

data object NetworkingLinkSignup : Destination(
route = Pane.NETWORKING_LINK_SIGNUP_PANE.value,
closeWithoutConfirmation = false,
logPaneLaunched = true,
fadeOnlyTransition = false,
composable = { NetworkingLinkSignupScreen() }
)

Expand All @@ -164,83 +174,95 @@ internal sealed class Destination(
),
closeWithoutConfirmation = false,
logPaneLaunched = true,
fadeOnlyTransition = false,
composable = { NetworkingLinkLoginWarmupScreen(it) }
)

data object NetworkingLinkVerification : Destination(
route = Pane.NETWORKING_LINK_VERIFICATION.value,
closeWithoutConfirmation = false,
logPaneLaunched = true,
fadeOnlyTransition = false,
composable = { NetworkingLinkVerificationScreen() }
)

data object NetworkingSaveToLinkVerification : Destination(
route = Pane.NETWORKING_SAVE_TO_LINK_VERIFICATION.value,
closeWithoutConfirmation = false,
logPaneLaunched = true,
fadeOnlyTransition = false,
composable = { NetworkingSaveToLinkVerificationScreen() }
)

data object LinkAccountPicker : Destination(
route = Pane.LINK_ACCOUNT_PICKER.value,
closeWithoutConfirmation = false,
logPaneLaunched = true,
fadeOnlyTransition = false,
composable = { LinkAccountPickerScreen() },
)

data object LinkStepUpVerification : Destination(
route = Pane.LINK_STEP_UP_VERIFICATION.value,
closeWithoutConfirmation = false,
logPaneLaunched = true,
fadeOnlyTransition = false,
composable = { LinkStepUpVerificationScreen() }
)

data object Reset : Destination(
route = Pane.RESET.value,
closeWithoutConfirmation = false,
logPaneLaunched = true,
fadeOnlyTransition = false,
composable = { ResetScreen() }
)

data object Exit : Destination(
route = Pane.EXIT.value,
closeWithoutConfirmation = false,
logPaneLaunched = false,
fadeOnlyTransition = false,
composable = { ExitModal(it) }
)

data object Notice : Destination(
route = Pane.NOTICE.value,
closeWithoutConfirmation = false,
logPaneLaunched = false,
fadeOnlyTransition = false,
composable = { NoticeSheet(it) },
)

data object AccountUpdateRequired : Destination(
route = Pane.ACCOUNT_UPDATE_REQUIRED.value,
closeWithoutConfirmation = false,
logPaneLaunched = false,
fadeOnlyTransition = false,
composable = { AccountUpdateRequiredModal(it) },
)

data object Error : Destination(
route = Pane.UNEXPECTED_ERROR.value,
closeWithoutConfirmation = false,
logPaneLaunched = false,
fadeOnlyTransition = false,
composable = { ErrorScreen() }
)

data object BankAuthRepair : Destination(
route = Pane.BANK_AUTH_REPAIR.value,
closeWithoutConfirmation = false,
logPaneLaunched = true,
fadeOnlyTransition = false,
composable = { BankAuthRepairScreen() }
)

data object ManualEntrySuccess : Destination(
route = Pane.MANUAL_ENTRY_SUCCESS.value,
closeWithoutConfirmation = true,
logPaneLaunched = true,
fadeOnlyTransition = false,
composable = { ManualEntrySuccessScreen() }
)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.stripe.android.financialconnections.navigation

import androidx.navigation.NavBackStackEntry
import androidx.navigation.NavDestination
import com.stripe.android.financialconnections.model.FinancialConnectionsSessionManifest.Pane

Expand Down Expand Up @@ -37,3 +38,9 @@ internal val NavDestination.pane: Pane
.firstOrNull { (_, destination) -> destination.fullRoute == route }
?.key
?: throw IllegalArgumentException("No corresponding destination for $this")

internal val NavBackStackEntry.pane: Pane
get() = paneToDestination.entries
.firstOrNull { (_, destination) -> destination.fullRoute == this.destination.route }
?.key
?: throw IllegalArgumentException("No corresponding destination for $this")
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,10 @@ internal class FinancialConnectionsSheetNativeActivity : AppCompatActivity() {
NavHost(
navController = navController,
startDestination = initialDestination.fullRoute,
enterTransition = enterTransition(),
exitTransition = pauseTransition(),
popEnterTransition = resumeTransition(),
popExitTransition = exitTransition(),
) {
composable(Destination.Consent)
composable(Destination.ManualEntry)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package com.stripe.android.financialconnections.ui

import androidx.compose.animation.AnimatedContentTransitionScope
import androidx.compose.animation.EnterTransition
import androidx.compose.animation.ExitTransition
import androidx.compose.animation.core.tween
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.slideInHorizontally
import androidx.compose.animation.slideOutHorizontally
import androidx.navigation.NavBackStackEntry
import com.stripe.android.financialconnections.navigation.destination
import com.stripe.android.financialconnections.navigation.pane

private const val TransitionDurationMillis = 300

private val FADE_IN_TRANSITION = fadeIn(
animationSpec = tween(TransitionDurationMillis)
)

private val FADE_OUT_TRANSITION = fadeOut(
animationSpec = tween(TransitionDurationMillis)
)

internal fun enterTransition(): AnimatedContentTransitionScope<NavBackStackEntry>.() -> EnterTransition {
return {
if (initialState.pane.destination.fadeOnlyTransition) {
FADE_IN_TRANSITION
} else {
FADE_IN_TRANSITION + slideInHorizontally(
animationSpec = tween(TransitionDurationMillis),
initialOffsetX = { fullWidth ->
fullWidth / 2
},
)
}
}
}

internal fun resumeTransition(): AnimatedContentTransitionScope<NavBackStackEntry>.() -> EnterTransition {
return {
if (initialState.pane.destination.fadeOnlyTransition) {
FADE_IN_TRANSITION
} else {
FADE_IN_TRANSITION + slideInHorizontally(
animationSpec = tween(TransitionDurationMillis),
initialOffsetX = { fullWidth ->
-fullWidth / 2
},
)
}
}
}

internal fun pauseTransition(): AnimatedContentTransitionScope<NavBackStackEntry>.() -> ExitTransition {
return {
if (initialState.pane.destination.fadeOnlyTransition) {
FADE_OUT_TRANSITION
} else {
FADE_OUT_TRANSITION + slideOutHorizontally(
animationSpec = tween(TransitionDurationMillis),
targetOffsetX = { fullWidth ->
-fullWidth / 2
},
)
}
}
}

internal fun exitTransition(): AnimatedContentTransitionScope<NavBackStackEntry>.() -> ExitTransition {
return {
if (initialState.pane.destination.fadeOnlyTransition) {
FADE_OUT_TRANSITION
} else {
FADE_OUT_TRANSITION + slideOutHorizontally(
animationSpec = tween(TransitionDurationMillis),
targetOffsetX = { fullWidth ->
fullWidth / 2
},
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@ package com.stripe.android.financialconnections.ui.components

import androidx.activity.OnBackPressedDispatcher
import androidx.activity.compose.LocalOnBackPressedDispatcherOwner
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.animateDpAsState
import androidx.compose.animation.core.tween
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
Expand Down Expand Up @@ -188,13 +192,18 @@ private fun Title(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
if (hideStripeLogo.not()) {
AnimatedVisibility(
visible = !hideStripeLogo,
enter = fadeIn(animationSpec = tween()),
exit = fadeOut(animationSpec = tween()),
) {
Image(
modifier = Modifier.size(width = LOGO_WIDTH, height = LOGO_HEIGHT),
painter = painterResource(id = theme.icon),
contentDescription = null // decorative element
)
}

// show a test mode pill if in test mode
if (testmode) {
Text(
Expand Down
Loading