mirror of
https://github.com/bitwarden/android.git
synced 2024-10-31 07:05:35 +03:00
BIT-985: Add initial transitions to the auth flow (#174)
This commit is contained in:
parent
e2e2c60759
commit
751b7ab2a8
7 changed files with 240 additions and 3 deletions
|
@ -4,6 +4,7 @@ import androidx.navigation.NavController
|
|||
import androidx.navigation.NavGraphBuilder
|
||||
import androidx.navigation.NavOptions
|
||||
import androidx.navigation.compose.composable
|
||||
import com.x8bit.bitwarden.ui.platform.theme.TransitionProviders
|
||||
|
||||
private const val CREATE_ACCOUNT_ROUTE = "create_account"
|
||||
|
||||
|
@ -21,7 +22,13 @@ fun NavGraphBuilder.createAccountDestinations(
|
|||
onNavigateBack: () -> Unit,
|
||||
onNavigateToLogin: (emailAddress: String, captchaToken: String) -> Unit,
|
||||
) {
|
||||
composable(route = CREATE_ACCOUNT_ROUTE) {
|
||||
composable(
|
||||
route = CREATE_ACCOUNT_ROUTE,
|
||||
enterTransition = TransitionProviders.Enter.slideUp,
|
||||
exitTransition = TransitionProviders.Exit.slideDown,
|
||||
popEnterTransition = TransitionProviders.Enter.slideUp,
|
||||
popExitTransition = TransitionProviders.Exit.slideDown,
|
||||
) {
|
||||
CreateAccountScreen(
|
||||
onNavigateBack = onNavigateBack,
|
||||
onNavigateToLogin = onNavigateToLogin,
|
||||
|
|
|
@ -4,6 +4,7 @@ import androidx.navigation.NavController
|
|||
import androidx.navigation.NavGraphBuilder
|
||||
import androidx.navigation.NavOptions
|
||||
import androidx.navigation.compose.composable
|
||||
import com.x8bit.bitwarden.ui.platform.theme.TransitionProviders
|
||||
|
||||
const val LANDING_ROUTE: String = "landing"
|
||||
|
||||
|
@ -21,7 +22,13 @@ fun NavGraphBuilder.landingDestinations(
|
|||
onNavigateToCreateAccount: () -> Unit,
|
||||
onNavigateToLogin: (emailAddress: String) -> Unit,
|
||||
) {
|
||||
composable(route = LANDING_ROUTE) {
|
||||
composable(
|
||||
route = LANDING_ROUTE,
|
||||
enterTransition = TransitionProviders.Enter.stay,
|
||||
exitTransition = TransitionProviders.Exit.stay,
|
||||
popEnterTransition = TransitionProviders.Enter.stay,
|
||||
popExitTransition = TransitionProviders.Exit.stay,
|
||||
) {
|
||||
LandingScreen(
|
||||
onNavigateToCreateAccount = onNavigateToCreateAccount,
|
||||
onNavigateToLogin = onNavigateToLogin,
|
||||
|
|
|
@ -7,6 +7,7 @@ import androidx.navigation.NavOptions
|
|||
import androidx.navigation.NavType
|
||||
import androidx.navigation.compose.composable
|
||||
import androidx.navigation.navArgument
|
||||
import com.x8bit.bitwarden.ui.platform.theme.TransitionProviders
|
||||
|
||||
private const val EMAIL_ADDRESS: String = "email_address"
|
||||
private const val CAPTCHA_TOKEN = "captcha_token"
|
||||
|
@ -51,6 +52,10 @@ fun NavGraphBuilder.loginDestinations(
|
|||
nullable = true
|
||||
},
|
||||
),
|
||||
enterTransition = TransitionProviders.Enter.slideUp,
|
||||
exitTransition = TransitionProviders.Exit.slideDown,
|
||||
popEnterTransition = TransitionProviders.Enter.slideUp,
|
||||
popExitTransition = TransitionProviders.Exit.slideDown,
|
||||
) {
|
||||
LoginScreen(
|
||||
onNavigateBack = onNavigateBack,
|
||||
|
|
|
@ -19,6 +19,7 @@ import com.x8bit.bitwarden.ui.platform.feature.splash.splashDestination
|
|||
import com.x8bit.bitwarden.ui.platform.feature.vaultunlocked.VAULT_UNLOCKED_GRAPH_ROUTE
|
||||
import com.x8bit.bitwarden.ui.platform.feature.vaultunlocked.navigateToVaultUnlockedGraph
|
||||
import com.x8bit.bitwarden.ui.platform.feature.vaultunlocked.vaultUnlockedGraph
|
||||
import com.x8bit.bitwarden.ui.platform.theme.RootTransitionProviders
|
||||
|
||||
/**
|
||||
* Controls root level [NavHost] for the app.
|
||||
|
@ -39,6 +40,10 @@ fun RootNavScreen(
|
|||
NavHost(
|
||||
navController = navController,
|
||||
startDestination = SPLASH_ROUTE,
|
||||
enterTransition = RootTransitionProviders.Enter.fadeIn,
|
||||
exitTransition = RootTransitionProviders.Exit.fadeOut,
|
||||
popEnterTransition = RootTransitionProviders.Enter.fadeIn,
|
||||
popExitTransition = RootTransitionProviders.Exit.fadeOut,
|
||||
) {
|
||||
splashDestination()
|
||||
authGraph(navController)
|
||||
|
|
|
@ -37,6 +37,7 @@ import com.x8bit.bitwarden.ui.platform.components.PlaceholderComposable
|
|||
import com.x8bit.bitwarden.ui.platform.feature.settings.SETTINGS_GRAPH_ROUTE
|
||||
import com.x8bit.bitwarden.ui.platform.feature.settings.navigateToSettingsGraph
|
||||
import com.x8bit.bitwarden.ui.platform.feature.settings.settingsGraph
|
||||
import com.x8bit.bitwarden.ui.platform.theme.RootTransitionProviders
|
||||
import com.x8bit.bitwarden.ui.tools.feature.generator.GENERATOR_ROUTE
|
||||
import com.x8bit.bitwarden.ui.tools.feature.generator.generatorDestination
|
||||
import com.x8bit.bitwarden.ui.tools.feature.generator.navigateToGenerator
|
||||
|
@ -175,6 +176,10 @@ private fun VaultUnlockedNavBarScaffold(
|
|||
modifier = Modifier
|
||||
.consumeWindowInsets(WindowInsets.navigationBars)
|
||||
.padding(innerPadding),
|
||||
enterTransition = RootTransitionProviders.Enter.fadeIn,
|
||||
exitTransition = RootTransitionProviders.Exit.fadeOut,
|
||||
popEnterTransition = RootTransitionProviders.Enter.fadeIn,
|
||||
popExitTransition = RootTransitionProviders.Exit.fadeOut,
|
||||
) {
|
||||
vaultDestination()
|
||||
sendDestination()
|
||||
|
|
|
@ -0,0 +1,208 @@
|
|||
package com.x8bit.bitwarden.ui.platform.theme
|
||||
|
||||
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.navigation.NavBackStackEntry
|
||||
import androidx.navigation.compose.NavHost
|
||||
|
||||
typealias EnterTransitionProvider =
|
||||
(@JvmSuppressWildcards AnimatedContentTransitionScope<NavBackStackEntry>.() -> EnterTransition?)
|
||||
|
||||
typealias ExitTransitionProvider =
|
||||
(@JvmSuppressWildcards AnimatedContentTransitionScope<NavBackStackEntry>.() -> ExitTransition?)
|
||||
|
||||
typealias NonNullEnterTransitionProvider =
|
||||
(@JvmSuppressWildcards AnimatedContentTransitionScope<NavBackStackEntry>.() -> EnterTransition)
|
||||
|
||||
typealias NonNullExitTransitionProvider =
|
||||
(@JvmSuppressWildcards AnimatedContentTransitionScope<NavBackStackEntry>.() -> ExitTransition)
|
||||
|
||||
/**
|
||||
* The default transition time (in milliseconds) for all transitions in the [TransitionProviders].
|
||||
*/
|
||||
const val DEFAULT_TRANSITION_TIME_MS: Int = 350
|
||||
|
||||
/**
|
||||
* Checks if the parent of the destination before and after the navigation is the same. This is
|
||||
* useful to ignore certain enter/exit transitions when navigating between distinct, nested flows.
|
||||
*/
|
||||
val AnimatedContentTransitionScope<NavBackStackEntry>.isSameGraphNavigation: Boolean
|
||||
get() = initialState.destination.parent == targetState.destination.parent
|
||||
|
||||
/**
|
||||
* Contains standard "transition providers" that may be used to specify the [EnterTransition] and
|
||||
* [ExitTransition] used when building a typical composable destination. These may return `null`
|
||||
* values in order to allow transitions between nested navigation graphs to be specified by
|
||||
* components higher up in the graph.
|
||||
*/
|
||||
object TransitionProviders {
|
||||
/**
|
||||
* The standard set of "enter" transition providers.
|
||||
*/
|
||||
object Enter {
|
||||
/**
|
||||
* Fades the new screen in.
|
||||
*
|
||||
* Note that this represents a `null` transition when navigating between different nested
|
||||
* navigation graphs.
|
||||
*/
|
||||
val fadeIn: EnterTransitionProvider = {
|
||||
RootTransitionProviders
|
||||
.Enter
|
||||
.fadeIn(this)
|
||||
.takeIf { isSameGraphNavigation }
|
||||
}
|
||||
|
||||
/**
|
||||
* Slides the new screen in from the bottom of the screen.
|
||||
*
|
||||
* Note that this represents a `null` transition when navigating between different nested
|
||||
* navigation graphs.
|
||||
*/
|
||||
val slideUp: EnterTransitionProvider = {
|
||||
RootTransitionProviders
|
||||
.Enter
|
||||
.slideUp(this)
|
||||
.takeIf { isSameGraphNavigation }
|
||||
}
|
||||
|
||||
/**
|
||||
* A "no-op" transition: this changes nothing about the screen but "lasts" as long as
|
||||
* other standard transitions in order to leave the screen in place such that it does not
|
||||
* immediately appear while the other screen transitions away.
|
||||
*
|
||||
* Note that this represents a `null` transition when navigating between different nested
|
||||
* navigation graphs.
|
||||
*/
|
||||
val stay: EnterTransitionProvider = {
|
||||
RootTransitionProviders
|
||||
.Enter
|
||||
.stay(this)
|
||||
.takeIf { isSameGraphNavigation }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The standard set of "exit" transition providers.
|
||||
*/
|
||||
object Exit {
|
||||
/**
|
||||
* Fades the current screen out.
|
||||
*
|
||||
* Note that this represents a `null` transition when navigating between different nested
|
||||
* navigation graphs.
|
||||
*/
|
||||
val fadeOut: ExitTransitionProvider = {
|
||||
RootTransitionProviders
|
||||
.Exit
|
||||
.fadeOut(this)
|
||||
.takeIf { isSameGraphNavigation }
|
||||
}
|
||||
|
||||
/**
|
||||
* Slides the current screen down to the bottom of the screen.
|
||||
*
|
||||
* Note that this represents a `null` transition when navigating between different nested
|
||||
* navigation graphs.
|
||||
*/
|
||||
val slideDown: ExitTransitionProvider = {
|
||||
RootTransitionProviders
|
||||
.Exit
|
||||
.slideDown(this)
|
||||
.takeIf { isSameGraphNavigation }
|
||||
}
|
||||
|
||||
/**
|
||||
* A "no-op" transition: this changes nothing about the screen but "lasts" as long as
|
||||
* other standard transitions in order to leave the screen in place such that it does not
|
||||
* immediately disappear while the other screen transitions into place.
|
||||
*
|
||||
* Note that this represents a `null` transition when navigating between different nested
|
||||
* navigation graphs.
|
||||
*/
|
||||
val stay: ExitTransitionProvider = {
|
||||
RootTransitionProviders
|
||||
.Exit
|
||||
.stay(this)
|
||||
.takeIf { isSameGraphNavigation }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Contains standard "transition providers" that may be used to specify the [EnterTransition] and
|
||||
* [ExitTransition] used when building a root [NavHost], which requires a non-null value.
|
||||
*/
|
||||
object RootTransitionProviders {
|
||||
/**
|
||||
* The standard set of "enter" transition providers.
|
||||
*/
|
||||
object Enter {
|
||||
/**
|
||||
* Fades the new screen in.
|
||||
*/
|
||||
val fadeIn: NonNullEnterTransitionProvider = {
|
||||
fadeIn(tween(DEFAULT_TRANSITION_TIME_MS))
|
||||
}
|
||||
|
||||
/**
|
||||
* Slides the new screen in from the bottom of the screen.
|
||||
*/
|
||||
val slideUp: NonNullEnterTransitionProvider = {
|
||||
slideIntoContainer(
|
||||
towards = AnimatedContentTransitionScope.SlideDirection.Up,
|
||||
animationSpec = tween(DEFAULT_TRANSITION_TIME_MS),
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A "no-op" transition: this changes nothing about the screen but "lasts" as long as
|
||||
* other standard transitions in order to leave the screen in place such that it does not
|
||||
* immediately appear while the other screen transitions away.
|
||||
*/
|
||||
val stay: NonNullEnterTransitionProvider = {
|
||||
fadeIn(
|
||||
animationSpec = tween(DEFAULT_TRANSITION_TIME_MS),
|
||||
initialAlpha = 1f,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The standard set of "exit" transition providers.
|
||||
*/
|
||||
object Exit {
|
||||
/**
|
||||
* Fades the current screen out.
|
||||
*/
|
||||
val fadeOut: NonNullExitTransitionProvider = {
|
||||
fadeOut(tween(DEFAULT_TRANSITION_TIME_MS))
|
||||
}
|
||||
|
||||
/**
|
||||
* Slides the current screen down to the bottom of the screen.
|
||||
*/
|
||||
val slideDown: NonNullExitTransitionProvider = {
|
||||
slideOutOfContainer(
|
||||
towards = AnimatedContentTransitionScope.SlideDirection.Down,
|
||||
animationSpec = tween(DEFAULT_TRANSITION_TIME_MS),
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A "no-op" transition: this changes nothing about the screen but "lasts" as long as
|
||||
* other standard transitions in order to leave the screen in place such that it does not
|
||||
* immediately disappear while the other screen transitions into place.
|
||||
*/
|
||||
val stay: NonNullExitTransitionProvider = {
|
||||
fadeOut(
|
||||
animationSpec = tween(DEFAULT_TRANSITION_TIME_MS),
|
||||
targetAlpha = 0f,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,7 +6,7 @@
|
|||
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||
<item name="android:textCursorDrawable">@null</item>
|
||||
<item name="android:windowActionBar">false</item>
|
||||
<item name="android:windowBackground">@null</item>
|
||||
<item name="android:windowBackground">@color/surface</item>
|
||||
<item name="android:windowNoTitle">true</item>
|
||||
<item name="android:windowActionModeOverlay">true</item>
|
||||
<item name="android:windowLayoutInDisplayCutoutMode">default</item>
|
||||
|
|
Loading…
Reference in a new issue