diff --git a/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/auth/unlock/UnlockNavigation.kt b/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/auth/unlock/UnlockNavigation.kt index dceddeb0fb..79c8b62d4d 100644 --- a/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/auth/unlock/UnlockNavigation.kt +++ b/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/auth/unlock/UnlockNavigation.kt @@ -4,8 +4,13 @@ import androidx.navigation.NavController import androidx.navigation.NavGraphBuilder import androidx.navigation.NavOptions import androidx.navigation.compose.composable +import kotlinx.serialization.Serializable -const val UNLOCK_ROUTE: String = "unlock" +/** + * The type-safe route for the unlock screen. + */ +@Serializable +data object UnlockRoute /** * Navigate to the unlock screen. @@ -13,7 +18,7 @@ const val UNLOCK_ROUTE: String = "unlock" fun NavController.navigateToUnlock( navOptions: NavOptions? = null, ) { - navigate(route = UNLOCK_ROUTE, navOptions = navOptions) + navigate(route = UnlockRoute, navOptions = navOptions) } /** @@ -22,7 +27,7 @@ fun NavController.navigateToUnlock( fun NavGraphBuilder.unlockDestination( onUnlocked: () -> Unit, ) { - composable(route = UNLOCK_ROUTE) { + composable { UnlockScreen(onUnlocked = onUnlocked) } } diff --git a/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/authenticator/feature/authenticator/AuthenticatorNavigation.kt b/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/authenticator/feature/authenticator/AuthenticatorNavigation.kt index 683b6de821..bcaeb4e017 100644 --- a/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/authenticator/feature/authenticator/AuthenticatorNavigation.kt +++ b/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/authenticator/feature/authenticator/AuthenticatorNavigation.kt @@ -7,21 +7,26 @@ import androidx.navigation.navigation import com.bitwarden.authenticator.ui.authenticator.feature.edititem.navigateToEditItem import com.bitwarden.authenticator.ui.authenticator.feature.itemlisting.itemListingGraph import com.bitwarden.authenticator.ui.authenticator.feature.manualcodeentry.navigateToManualCodeEntryScreen -import com.bitwarden.authenticator.ui.authenticator.feature.navbar.AUTHENTICATOR_NAV_BAR_ROUTE +import com.bitwarden.authenticator.ui.authenticator.feature.navbar.AuthenticatorNavbarRoute import com.bitwarden.authenticator.ui.authenticator.feature.navbar.authenticatorNavBarDestination import com.bitwarden.authenticator.ui.authenticator.feature.qrcodescan.navigateToQrCodeScanScreen import com.bitwarden.authenticator.ui.authenticator.feature.search.navigateToSearch import com.bitwarden.authenticator.ui.platform.feature.settings.export.navigateToExport import com.bitwarden.authenticator.ui.platform.feature.settings.importing.navigateToImporting import com.bitwarden.authenticator.ui.platform.feature.tutorial.navigateToSettingsTutorial +import kotlinx.serialization.Serializable -const val AUTHENTICATOR_GRAPH_ROUTE = "authenticator_graph" +/** + * The type-safe route for the authenticator graph. + */ +@Serializable +data object AuthenticatorGraphRoute /** * Navigate to the authenticator graph */ fun NavController.navigateToAuthenticatorGraph(navOptions: NavOptions? = null) { - navigate(AUTHENTICATOR_NAV_BAR_ROUTE, navOptions) + navigate(route = AuthenticatorNavbarRoute, navOptions = navOptions) } /** @@ -31,9 +36,8 @@ fun NavGraphBuilder.authenticatorGraph( navController: NavController, onNavigateBack: () -> Unit, ) { - navigation( - startDestination = AUTHENTICATOR_NAV_BAR_ROUTE, - route = AUTHENTICATOR_GRAPH_ROUTE, + navigation( + startDestination = AuthenticatorNavbarRoute, ) { authenticatorNavBarDestination( onNavigateBack = onNavigateBack, diff --git a/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/authenticator/feature/edititem/EditItemNavigation.kt b/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/authenticator/feature/edititem/EditItemNavigation.kt index f2512b1ffd..8be06ced00 100644 --- a/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/authenticator/feature/edititem/EditItemNavigation.kt +++ b/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/authenticator/feature/edititem/EditItemNavigation.kt @@ -4,23 +4,31 @@ import androidx.lifecycle.SavedStateHandle import androidx.navigation.NavController import androidx.navigation.NavGraphBuilder import androidx.navigation.NavOptions -import androidx.navigation.NavType -import androidx.navigation.navArgument -import com.bitwarden.authenticator.ui.platform.base.util.composableWithPushTransitions +import androidx.navigation.toRoute +import com.bitwarden.ui.platform.base.util.composableWithPushTransitions +import kotlinx.serialization.Serializable -private const val EDIT_ITEM_PREFIX = "edit_item" -private const val EDIT_ITEM_ITEM_ID = "item_id" -private const val EDIT_ITEM_ROUTE = "$EDIT_ITEM_PREFIX/{$EDIT_ITEM_ITEM_ID}" +/** + * The type-safe route for the edit item screen. + */ +@Serializable +data class EditItemRoute( + val itemId: String, +) /** * Class to retrieve authenticator item arguments from the [SavedStateHandle]. * * @property itemId ID of the item to be edited. */ -data class EditItemArgs(val itemId: String) { - constructor(savedStateHandle: SavedStateHandle) : this( - checkNotNull(savedStateHandle[EDIT_ITEM_ITEM_ID]) as String, - ) +data class EditItemArgs(val itemId: String) + +/** + * Constructs a [EditItemArgs] from the [SavedStateHandle] and internal route data. + */ +fun SavedStateHandle.toEditItemArgs(): EditItemArgs { + val route = this.toRoute() + return EditItemArgs(itemId = route.itemId) } /** @@ -29,12 +37,7 @@ data class EditItemArgs(val itemId: String) { fun NavGraphBuilder.editItemDestination( onNavigateBack: () -> Unit = { }, ) { - composableWithPushTransitions( - route = EDIT_ITEM_ROUTE, - arguments = listOf( - navArgument(EDIT_ITEM_ITEM_ID) { type = NavType.StringType }, - ), - ) { + composableWithPushTransitions { EditItemScreen( onNavigateBack = onNavigateBack, ) @@ -49,7 +52,7 @@ fun NavController.navigateToEditItem( navOptions: NavOptions? = null, ) { navigate( - route = "$EDIT_ITEM_PREFIX/$itemId", + route = EditItemRoute(itemId = itemId), navOptions = navOptions, ) } diff --git a/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/authenticator/feature/edititem/EditItemScreen.kt b/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/authenticator/feature/edititem/EditItemScreen.kt index 79fdff8a75..7f13b06fbb 100644 --- a/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/authenticator/feature/edititem/EditItemScreen.kt +++ b/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/authenticator/feature/edititem/EditItemScreen.kt @@ -64,8 +64,8 @@ import com.bitwarden.authenticator.ui.platform.components.model.IconData import com.bitwarden.authenticator.ui.platform.components.scaffold.BitwardenScaffold import com.bitwarden.authenticator.ui.platform.components.stepper.BitwardenStepper import com.bitwarden.authenticator.ui.platform.components.toggle.BitwardenSwitch -import com.bitwarden.authenticator.ui.platform.theme.DEFAULT_FADE_TRANSITION_TIME_MS -import com.bitwarden.authenticator.ui.platform.theme.DEFAULT_STAY_TRANSITION_TIME_MS +import com.bitwarden.ui.platform.theme.DEFAULT_FADE_TRANSITION_TIME_MS +import com.bitwarden.ui.platform.theme.DEFAULT_STAY_TRANSITION_TIME_MS import kotlinx.collections.immutable.toImmutableList /** diff --git a/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/authenticator/feature/edititem/EditItemViewModel.kt b/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/authenticator/feature/edititem/EditItemViewModel.kt index ba76e45b13..29957a562d 100644 --- a/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/authenticator/feature/edititem/EditItemViewModel.kt +++ b/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/authenticator/feature/edititem/EditItemViewModel.kt @@ -42,7 +42,7 @@ class EditItemViewModel @Inject constructor( savedStateHandle: SavedStateHandle, ) : BaseViewModel( initialState = savedStateHandle[KEY_STATE] ?: EditItemState( - itemId = EditItemArgs(savedStateHandle).itemId, + itemId = savedStateHandle.toEditItemArgs().itemId, viewState = EditItemState.ViewState.Loading, dialog = null, ), diff --git a/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/authenticator/feature/itemlisting/ItemListingGraphNavigation.kt b/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/authenticator/feature/itemlisting/ItemListingGraphNavigation.kt index be8e0767c2..119679c67a 100644 --- a/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/authenticator/feature/itemlisting/ItemListingGraphNavigation.kt +++ b/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/authenticator/feature/itemlisting/ItemListingGraphNavigation.kt @@ -11,8 +11,13 @@ import com.bitwarden.authenticator.ui.authenticator.feature.qrcodescan.navigateT import com.bitwarden.authenticator.ui.authenticator.feature.qrcodescan.qrCodeScanDestination import com.bitwarden.authenticator.ui.authenticator.feature.search.itemSearchDestination import com.bitwarden.authenticator.ui.platform.feature.settings.settingsGraph +import kotlinx.serialization.Serializable -const val ITEM_LISTING_GRAPH_ROUTE = "item_listing_graph" +/** + * The type-safe route for the item listing graph. + */ +@Serializable +data object ItemListingGraphRoute /** * Add the item listing graph to the nav graph. @@ -29,9 +34,8 @@ fun NavGraphBuilder.itemListingGraph( navigateToImport: () -> Unit, navigateToTutorial: () -> Unit, ) { - navigation( - route = ITEM_LISTING_GRAPH_ROUTE, - startDestination = ITEM_LIST_ROUTE, + navigation( + startDestination = ItemListingRoute, ) { itemListingDestination( onNavigateBack = navigateBack, @@ -76,7 +80,7 @@ fun NavController.navigateToItemListGraph( navOptions: NavOptions? = null, ) { navigate( - route = ITEM_LISTING_GRAPH_ROUTE, + route = ItemListingGraphRoute, navOptions = navOptions, ) } diff --git a/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/authenticator/feature/itemlisting/ItemListingNavigation.kt b/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/authenticator/feature/itemlisting/ItemListingNavigation.kt index 95d34b29cb..a10a6172cd 100644 --- a/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/authenticator/feature/itemlisting/ItemListingNavigation.kt +++ b/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/authenticator/feature/itemlisting/ItemListingNavigation.kt @@ -1,9 +1,14 @@ package com.bitwarden.authenticator.ui.authenticator.feature.itemlisting import androidx.navigation.NavGraphBuilder -import com.bitwarden.authenticator.ui.platform.base.util.composableWithPushTransitions +import com.bitwarden.ui.platform.base.util.composableWithPushTransitions +import kotlinx.serialization.Serializable -const val ITEM_LIST_ROUTE = "item_list" +/** + * The type-safe route for the item listing screen. + */ +@Serializable +data object ItemListingRoute /** * Add the item listing screen to the nav graph. @@ -15,9 +20,7 @@ fun NavGraphBuilder.itemListingDestination( onNavigateToManualKeyEntry: () -> Unit = { }, onNavigateToEditItemScreen: (id: String) -> Unit = { }, ) { - composableWithPushTransitions( - route = ITEM_LIST_ROUTE, - ) { + composableWithPushTransitions { ItemListingScreen( onNavigateBack = onNavigateBack, onNavigateToSearch = onNavigateToSearch, diff --git a/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/authenticator/feature/manualcodeentry/ManualCodeEntryNavigation.kt b/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/authenticator/feature/manualcodeentry/ManualCodeEntryNavigation.kt index 97bdd4121c..0545018d9e 100644 --- a/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/authenticator/feature/manualcodeentry/ManualCodeEntryNavigation.kt +++ b/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/authenticator/feature/manualcodeentry/ManualCodeEntryNavigation.kt @@ -3,9 +3,14 @@ package com.bitwarden.authenticator.ui.authenticator.feature.manualcodeentry import androidx.navigation.NavController import androidx.navigation.NavGraphBuilder import androidx.navigation.NavOptions -import com.bitwarden.authenticator.ui.platform.base.util.composableWithSlideTransitions +import com.bitwarden.ui.platform.base.util.composableWithSlideTransitions +import kotlinx.serialization.Serializable -private const val MANUAL_CODE_ENTRY_ROUTE: String = "manual_code_entry" +/** + * The type-safe route for the manual code entry screen. + */ +@Serializable +data object ManualCodeEntryRoute /** * Add the manual code entry screen to the nav graph. @@ -14,9 +19,7 @@ fun NavGraphBuilder.manualCodeEntryDestination( onNavigateBack: () -> Unit, onNavigateToQrCodeScreen: () -> Unit, ) { - composableWithSlideTransitions( - route = MANUAL_CODE_ENTRY_ROUTE, - ) { + composableWithSlideTransitions { ManualCodeEntryScreen( onNavigateBack = onNavigateBack, onNavigateToQrCodeScreen = onNavigateToQrCodeScreen, @@ -30,5 +33,5 @@ fun NavGraphBuilder.manualCodeEntryDestination( fun NavController.navigateToManualCodeEntryScreen( navOptions: NavOptions? = null, ) { - this.navigate(MANUAL_CODE_ENTRY_ROUTE, navOptions) + this.navigate(route = ManualCodeEntryRoute, navOptions = navOptions) } diff --git a/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/authenticator/feature/navbar/AuthenticatorNavBarNavigation.kt b/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/authenticator/feature/navbar/AuthenticatorNavBarNavigation.kt index 4cd01caba0..dee1010cc8 100644 --- a/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/authenticator/feature/navbar/AuthenticatorNavBarNavigation.kt +++ b/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/authenticator/feature/navbar/AuthenticatorNavBarNavigation.kt @@ -1,9 +1,14 @@ package com.bitwarden.authenticator.ui.authenticator.feature.navbar import androidx.navigation.NavGraphBuilder -import com.bitwarden.authenticator.ui.platform.base.util.composableWithStayTransitions +import com.bitwarden.ui.platform.base.util.composableWithStayTransitions +import kotlinx.serialization.Serializable -const val AUTHENTICATOR_NAV_BAR_ROUTE: String = "AuthenticatorNavBarRoute" +/** + * The type-safe route for the authenticator navbar screen. + */ +@Serializable +data object AuthenticatorNavbarRoute /** * Add the authenticator nav bar to the nav graph. @@ -19,9 +24,7 @@ fun NavGraphBuilder.authenticatorNavBarDestination( onNavigateToImport: () -> Unit, onNavigateToTutorial: () -> Unit, ) { - composableWithStayTransitions( - route = AUTHENTICATOR_NAV_BAR_ROUTE, - ) { + composableWithStayTransitions { AuthenticatorNavBarScreen( onNavigateBack = onNavigateBack, onNavigateToSearch = onNavigateToSearch, diff --git a/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/authenticator/feature/navbar/AuthenticatorNavBarScreen.kt b/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/authenticator/feature/navbar/AuthenticatorNavBarScreen.kt index ba16fc7da1..3403cc76ed 100644 --- a/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/authenticator/feature/navbar/AuthenticatorNavBarScreen.kt +++ b/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/authenticator/feature/navbar/AuthenticatorNavBarScreen.kt @@ -43,8 +43,8 @@ import androidx.navigation.compose.currentBackStackEntryAsState import androidx.navigation.compose.rememberNavController import androidx.navigation.navOptions import com.bitwarden.authenticator.R -import com.bitwarden.authenticator.ui.authenticator.feature.itemlisting.ITEM_LISTING_GRAPH_ROUTE -import com.bitwarden.authenticator.ui.authenticator.feature.itemlisting.ITEM_LIST_ROUTE +import com.bitwarden.authenticator.ui.authenticator.feature.itemlisting.ItemListingGraphRoute +import com.bitwarden.authenticator.ui.authenticator.feature.itemlisting.ItemListingRoute import com.bitwarden.authenticator.ui.authenticator.feature.itemlisting.itemListingGraph import com.bitwarden.authenticator.ui.authenticator.feature.itemlisting.navigateToItemListGraph import com.bitwarden.authenticator.ui.platform.base.util.EventsEffect @@ -52,9 +52,10 @@ import com.bitwarden.authenticator.ui.platform.base.util.max import com.bitwarden.authenticator.ui.platform.base.util.toDp import com.bitwarden.authenticator.ui.platform.components.scaffold.BitwardenScaffold import com.bitwarden.authenticator.ui.platform.components.scrim.BitwardenAnimatedScrim -import com.bitwarden.authenticator.ui.platform.feature.settings.SETTINGS_GRAPH_ROUTE +import com.bitwarden.authenticator.ui.platform.feature.settings.SettingsGraphRoute import com.bitwarden.authenticator.ui.platform.feature.settings.navigateToSettingsGraph -import com.bitwarden.authenticator.ui.platform.theme.RootTransitionProviders +import com.bitwarden.ui.platform.theme.RootTransitionProviders +import com.bitwarden.ui.platform.util.toObjectNavigationRoute import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.parcelize.Parcelize @@ -161,7 +162,7 @@ private fun AuthenticatorNavBarScaffold( ) { innerPadding -> NavHost( navController = navController, - startDestination = ITEM_LISTING_GRAPH_ROUTE, + startDestination = ItemListingGraphRoute, modifier = Modifier .consumeWindowInsets(WindowInsets.navigationBars) .consumeWindowInsets(WindowInsets.ime) @@ -309,7 +310,7 @@ private sealed class AuthenticatorNavBarTab : Parcelable { override val iconRes get() = R.drawable.ic_verification_codes override val labelRes get() = R.string.verification_codes override val contentDescriptionRes get() = R.string.verification_codes - override val route get() = ITEM_LIST_ROUTE + override val route get() = ItemListingRoute.toObjectNavigationRoute() override val testTag get() = "VerificationCodesTab" } @@ -322,9 +323,7 @@ private sealed class AuthenticatorNavBarTab : Parcelable { override val iconRes get() = R.drawable.ic_settings override val labelRes get() = R.string.settings override val contentDescriptionRes get() = R.string.settings - - // TODO: Replace with constant when settings screen is complete. - override val route get() = SETTINGS_GRAPH_ROUTE + override val route get() = SettingsGraphRoute.toObjectNavigationRoute() override val testTag get() = "SettingsTab" } } diff --git a/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/authenticator/feature/qrcodescan/QrCodeScanNavigation.kt b/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/authenticator/feature/qrcodescan/QrCodeScanNavigation.kt index f84f1be77f..4ca3a332e9 100644 --- a/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/authenticator/feature/qrcodescan/QrCodeScanNavigation.kt +++ b/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/authenticator/feature/qrcodescan/QrCodeScanNavigation.kt @@ -3,9 +3,14 @@ package com.bitwarden.authenticator.ui.authenticator.feature.qrcodescan import androidx.navigation.NavController import androidx.navigation.NavGraphBuilder import androidx.navigation.NavOptions -import com.bitwarden.authenticator.ui.platform.base.util.composableWithSlideTransitions +import com.bitwarden.ui.platform.base.util.composableWithSlideTransitions +import kotlinx.serialization.Serializable -private const val QR_CODE_SCAN_ROUTE: String = "qr_code_scan" +/** + * The type-safe route for the QR code scan screen. + */ +@Serializable +data object QrCodeScanRoute /** * Add the QR code scan screen to the nav graph. @@ -14,9 +19,7 @@ fun NavGraphBuilder.qrCodeScanDestination( onNavigateBack: () -> Unit, onNavigateToManualCodeEntryScreen: () -> Unit, ) { - composableWithSlideTransitions( - route = QR_CODE_SCAN_ROUTE, - ) { + composableWithSlideTransitions { QrCodeScanScreen( onNavigateToManualCodeEntryScreen = onNavigateToManualCodeEntryScreen, onNavigateBack = onNavigateBack, @@ -30,5 +33,5 @@ fun NavGraphBuilder.qrCodeScanDestination( fun NavController.navigateToQrCodeScanScreen( navOptions: NavOptions? = null, ) { - this.navigate(QR_CODE_SCAN_ROUTE, navOptions) + this.navigate(route = QrCodeScanRoute, navOptions = navOptions) } diff --git a/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/authenticator/feature/search/ItemSearchNavigation.kt b/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/authenticator/feature/search/ItemSearchNavigation.kt index 929c9b3d10..6bb71bc0a0 100644 --- a/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/authenticator/feature/search/ItemSearchNavigation.kt +++ b/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/authenticator/feature/search/ItemSearchNavigation.kt @@ -2,9 +2,14 @@ package com.bitwarden.authenticator.ui.authenticator.feature.search import androidx.navigation.NavController import androidx.navigation.NavGraphBuilder -import com.bitwarden.authenticator.ui.platform.base.util.composableWithSlideTransitions +import com.bitwarden.ui.platform.base.util.composableWithSlideTransitions +import kotlinx.serialization.Serializable -const val ITEM_SEARCH_ROUTE = "item_search" +/** + * The type-safe route for the item search screen. + */ +@Serializable +data object ItemSearchRoute /** * Add item search destination to the nav graph. @@ -12,9 +17,7 @@ const val ITEM_SEARCH_ROUTE = "item_search" fun NavGraphBuilder.itemSearchDestination( onNavigateBack: () -> Unit, ) { - composableWithSlideTransitions( - route = ITEM_SEARCH_ROUTE, - ) { + composableWithSlideTransitions { ItemSearchScreen( onNavigateBack = onNavigateBack, ) @@ -25,5 +28,5 @@ fun NavGraphBuilder.itemSearchDestination( * Navigate to the item search screen. */ fun NavController.navigateToSearch() { - navigate(route = ITEM_SEARCH_ROUTE) + navigate(route = ItemSearchRoute) } diff --git a/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/platform/base/util/NavGraphBuilderExtensions.kt b/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/platform/base/util/NavGraphBuilderExtensions.kt deleted file mode 100644 index b9ba7cafdb..0000000000 --- a/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/platform/base/util/NavGraphBuilderExtensions.kt +++ /dev/null @@ -1,98 +0,0 @@ -package com.bitwarden.authenticator.ui.platform.base.util - -import androidx.compose.animation.AnimatedContentScope -import androidx.compose.runtime.Composable -import androidx.navigation.NamedNavArgument -import androidx.navigation.NavBackStackEntry -import androidx.navigation.NavDeepLink -import androidx.navigation.NavGraphBuilder -import androidx.navigation.compose.composable -import com.bitwarden.authenticator.ui.platform.theme.TransitionProviders - -/** - * A wrapper around [NavGraphBuilder.composable] that supplies slide up/down transitions. - */ -fun NavGraphBuilder.composableWithSlideTransitions( - route: String, - arguments: List = emptyList(), - deepLinks: List = emptyList(), - content: @Composable AnimatedContentScope.(NavBackStackEntry) -> Unit, -) { - this.composable( - route = route, - arguments = arguments, - deepLinks = deepLinks, - enterTransition = TransitionProviders.Enter.slideUp, - exitTransition = TransitionProviders.Exit.stay, - popEnterTransition = TransitionProviders.Enter.stay, - popExitTransition = TransitionProviders.Exit.slideDown, - content = content, - ) -} - -/** - * A wrapper around [NavGraphBuilder.composable] that supplies "stay" transitions. - */ -fun NavGraphBuilder.composableWithStayTransitions( - route: String, - arguments: List = emptyList(), - deepLinks: List = emptyList(), - content: @Composable AnimatedContentScope.(NavBackStackEntry) -> Unit, -) { - this.composable( - route = route, - arguments = arguments, - deepLinks = deepLinks, - enterTransition = TransitionProviders.Enter.stay, - exitTransition = TransitionProviders.Exit.stay, - popEnterTransition = TransitionProviders.Enter.stay, - popExitTransition = TransitionProviders.Exit.stay, - content = content, - ) -} - -/** - * A wrapper around [NavGraphBuilder.composable] that supplies push transitions. - * - * This is suitable for screens deeper within a hierarchy that uses push transitions; the root - * screen of such a hierarchy should use [composableWithRootPushTransitions]. - */ -fun NavGraphBuilder.composableWithPushTransitions( - route: String, - arguments: List = emptyList(), - deepLinks: List = emptyList(), - content: @Composable AnimatedContentScope.(NavBackStackEntry) -> Unit, -) { - this.composable( - route = route, - arguments = arguments, - deepLinks = deepLinks, - enterTransition = TransitionProviders.Enter.pushLeft, - exitTransition = TransitionProviders.Exit.stay, - popEnterTransition = TransitionProviders.Enter.stay, - popExitTransition = TransitionProviders.Exit.pushRight, - content = content, - ) -} - -/** - * A wrapper around [NavGraphBuilder.composable] that supplies push transitions to the root screen - * in a nested graph that uses push transitions. - */ -fun NavGraphBuilder.composableWithRootPushTransitions( - route: String, - arguments: List = emptyList(), - deepLinks: List = emptyList(), - content: @Composable AnimatedContentScope.(NavBackStackEntry) -> Unit, -) { - this.composable( - route = route, - arguments = arguments, - deepLinks = deepLinks, - enterTransition = TransitionProviders.Enter.stay, - exitTransition = TransitionProviders.Exit.pushLeft, - popEnterTransition = TransitionProviders.Enter.pushRight, - popExitTransition = TransitionProviders.Exit.fadeOut, - content = content, - ) -} diff --git a/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/platform/feature/debugmenu/DebugMenuNavigation.kt b/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/platform/feature/debugmenu/DebugMenuNavigation.kt index 85f3303ae4..cb1376f5e8 100644 --- a/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/platform/feature/debugmenu/DebugMenuNavigation.kt +++ b/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/platform/feature/debugmenu/DebugMenuNavigation.kt @@ -2,15 +2,20 @@ package com.bitwarden.authenticator.ui.platform.feature.debugmenu import androidx.navigation.NavController import androidx.navigation.NavGraphBuilder -import com.bitwarden.authenticator.ui.platform.base.util.composableWithPushTransitions +import com.bitwarden.ui.platform.base.util.composableWithPushTransitions +import kotlinx.serialization.Serializable -private const val DEBUG_MENU = "debug_menu" +/** + * The type-safe route for the debug screen. + */ +@Serializable +data object DebugRoute /** * Navigate to the setup unlock screen. */ fun NavController.navigateToDebugMenuScreen() { - this.navigate(DEBUG_MENU) { + this.navigate(route = DebugRoute) { launchSingleTop = true } } @@ -21,9 +26,7 @@ fun NavController.navigateToDebugMenuScreen() { fun NavGraphBuilder.setupDebugMenuDestination( onNavigateBack: () -> Unit, ) { - composableWithPushTransitions( - route = DEBUG_MENU, - ) { + composableWithPushTransitions { DebugMenuScreen(onNavigateBack = onNavigateBack) } } diff --git a/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/platform/feature/rootnav/RootNavScreen.kt b/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/platform/feature/rootnav/RootNavScreen.kt index 4949a9f0ac..d672388e2e 100644 --- a/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/platform/feature/rootnav/RootNavScreen.kt +++ b/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/platform/feature/rootnav/RootNavScreen.kt @@ -13,22 +13,23 @@ import androidx.navigation.NavHostController import androidx.navigation.compose.NavHost import androidx.navigation.compose.rememberNavController import androidx.navigation.navOptions -import com.bitwarden.authenticator.ui.auth.unlock.UNLOCK_ROUTE +import com.bitwarden.authenticator.ui.auth.unlock.UnlockRoute import com.bitwarden.authenticator.ui.auth.unlock.navigateToUnlock import com.bitwarden.authenticator.ui.auth.unlock.unlockDestination -import com.bitwarden.authenticator.ui.authenticator.feature.authenticator.AUTHENTICATOR_GRAPH_ROUTE +import com.bitwarden.authenticator.ui.authenticator.feature.authenticator.AuthenticatorGraphRoute import com.bitwarden.authenticator.ui.authenticator.feature.authenticator.authenticatorGraph import com.bitwarden.authenticator.ui.authenticator.feature.authenticator.navigateToAuthenticatorGraph import com.bitwarden.authenticator.ui.platform.feature.debugmenu.setupDebugMenuDestination -import com.bitwarden.authenticator.ui.platform.feature.splash.SPLASH_ROUTE +import com.bitwarden.authenticator.ui.platform.feature.splash.SplashRoute import com.bitwarden.authenticator.ui.platform.feature.splash.navigateToSplash import com.bitwarden.authenticator.ui.platform.feature.splash.splashDestination -import com.bitwarden.authenticator.ui.platform.feature.tutorial.TUTORIAL_ROUTE +import com.bitwarden.authenticator.ui.platform.feature.tutorial.TutorialRoute import com.bitwarden.authenticator.ui.platform.feature.tutorial.navigateToTutorial import com.bitwarden.authenticator.ui.platform.feature.tutorial.tutorialDestination -import com.bitwarden.authenticator.ui.platform.theme.NonNullEnterTransitionProvider -import com.bitwarden.authenticator.ui.platform.theme.NonNullExitTransitionProvider -import com.bitwarden.authenticator.ui.platform.theme.RootTransitionProviders +import com.bitwarden.ui.platform.theme.NonNullEnterTransitionProvider +import com.bitwarden.ui.platform.theme.NonNullExitTransitionProvider +import com.bitwarden.ui.platform.theme.RootTransitionProviders +import com.bitwarden.ui.platform.util.toObjectNavigationRoute import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import java.util.concurrent.atomic.AtomicReference @@ -64,7 +65,7 @@ fun RootNavScreen( NavHost( navController = navController, - startDestination = SPLASH_ROUTE, + startDestination = SplashRoute, enterTransition = { toEnterTransition()(this) }, exitTransition = { toExitTransition()(this) }, popEnterTransition = { toEnterTransition()(this) }, @@ -93,10 +94,10 @@ fun RootNavScreen( } val targetRoute = when (state.navState) { - RootNavState.NavState.Splash -> SPLASH_ROUTE - RootNavState.NavState.Locked -> UNLOCK_ROUTE - RootNavState.NavState.Tutorial -> TUTORIAL_ROUTE - RootNavState.NavState.Unlocked -> AUTHENTICATOR_GRAPH_ROUTE + RootNavState.NavState.Splash -> SplashRoute + RootNavState.NavState.Locked -> UnlockRoute + RootNavState.NavState.Tutorial -> TutorialRoute + RootNavState.NavState.Unlocked -> AuthenticatorGraphRoute } val currentRoute = navController.currentDestination?.rootLevelRoute() @@ -104,7 +105,9 @@ fun RootNavScreen( // death. In this case, the NavHost already restores state, so we don't have to navigate. // However, if the route is correct but the underlying state is different, we should still // proceed in order to get a fresh version of that route. - if (currentRoute == targetRoute && previousStateReference.get() == state) { + if (currentRoute == targetRoute.toObjectNavigationRoute() && + previousStateReference.get() == state + ) { previousStateReference.set(state) return } @@ -167,7 +170,7 @@ private fun AnimatedContentTransitionScope.toEnterTransition( when (targetState.destination.rootLevelRoute()) { else -> when (initialState.destination.rootLevelRoute()) { // Disable transitions when coming from the splash screen - SPLASH_ROUTE -> RootTransitionProviders.Enter.none + SplashRoute.toObjectNavigationRoute() -> RootTransitionProviders.Enter.none else -> RootTransitionProviders.Enter.fadeIn } } @@ -179,7 +182,7 @@ private fun AnimatedContentTransitionScope.toEnterTransition( private fun AnimatedContentTransitionScope.toExitTransition(): NonNullExitTransitionProvider = when (initialState.destination.rootLevelRoute()) { // Disable transitions when coming from the splash screen - SPLASH_ROUTE -> RootTransitionProviders.Exit.none + SplashRoute.toObjectNavigationRoute() -> RootTransitionProviders.Exit.none else -> when (targetState.destination.rootLevelRoute()) { else -> RootTransitionProviders.Exit.fadeOut } diff --git a/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/platform/feature/settings/SettingsNavigation.kt b/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/platform/feature/settings/SettingsNavigation.kt index ad796c81d3..f28b5df78c 100644 --- a/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/platform/feature/settings/SettingsNavigation.kt +++ b/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/platform/feature/settings/SettingsNavigation.kt @@ -4,13 +4,23 @@ import androidx.navigation.NavController import androidx.navigation.NavGraphBuilder import androidx.navigation.NavOptions import androidx.navigation.navigation -import com.bitwarden.authenticator.ui.platform.base.util.composableWithRootPushTransitions import com.bitwarden.authenticator.ui.platform.feature.settings.export.exportDestination import com.bitwarden.authenticator.ui.platform.feature.settings.importing.importingDestination import com.bitwarden.authenticator.ui.platform.feature.tutorial.tutorialSettingsDestination +import com.bitwarden.ui.platform.base.util.composableWithRootPushTransitions +import kotlinx.serialization.Serializable -const val SETTINGS_GRAPH_ROUTE = "settings_graph" -private const val SETTINGS_ROUTE = "settings" +/** + * The type-safe route for the settings graph. + */ +@Serializable +data object SettingsGraphRoute + +/** + * The type-safe route for the settings screen. + */ +@Serializable +data object SettingsRoute /** * Add settings graph to the nav graph. @@ -21,13 +31,10 @@ fun NavGraphBuilder.settingsGraph( onNavigateToImport: () -> Unit, onNavigateToTutorial: () -> Unit, ) { - navigation( - startDestination = SETTINGS_ROUTE, - route = SETTINGS_GRAPH_ROUTE, + navigation( + startDestination = SettingsRoute, ) { - composableWithRootPushTransitions( - route = SETTINGS_ROUTE, - ) { + composableWithRootPushTransitions { SettingsScreen( onNavigateToTutorial = onNavigateToTutorial, onNavigateToExport = onNavigateToExport, @@ -50,5 +57,5 @@ fun NavGraphBuilder.settingsGraph( * Navigate to the settings screen. */ fun NavController.navigateToSettingsGraph(navOptions: NavOptions? = null) { - navigate(SETTINGS_GRAPH_ROUTE, navOptions) + navigate(route = SettingsGraphRoute, navOptions = navOptions) } diff --git a/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/platform/feature/settings/export/ExportNavigation.kt b/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/platform/feature/settings/export/ExportNavigation.kt index cd8c18adba..135ed566e3 100644 --- a/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/platform/feature/settings/export/ExportNavigation.kt +++ b/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/platform/feature/settings/export/ExportNavigation.kt @@ -3,12 +3,14 @@ package com.bitwarden.authenticator.ui.platform.feature.settings.export import androidx.navigation.NavController import androidx.navigation.NavGraphBuilder import androidx.navigation.NavOptions -import com.bitwarden.authenticator.ui.platform.base.util.composableWithSlideTransitions +import com.bitwarden.ui.platform.base.util.composableWithSlideTransitions +import kotlinx.serialization.Serializable /** - * Route for the export data screen. + * The type-safe route for the export screen. */ -const val EXPORT_ROUTE = "export" +@Serializable +data object ExportRoute /** * Add the export data destination to the nav graph. @@ -16,7 +18,7 @@ const val EXPORT_ROUTE = "export" fun NavGraphBuilder.exportDestination( onNavigateBack: () -> Unit, ) { - composableWithSlideTransitions(EXPORT_ROUTE) { + composableWithSlideTransitions { ExportScreen( onNavigateBack = onNavigateBack, ) @@ -27,5 +29,5 @@ fun NavGraphBuilder.exportDestination( * Navigate to the export data screen. */ fun NavController.navigateToExport(navOptions: NavOptions? = null) { - navigate(EXPORT_ROUTE, navOptions) + navigate(route = ExportRoute, navOptions = navOptions) } diff --git a/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/platform/feature/settings/importing/ImportingNavigation.kt b/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/platform/feature/settings/importing/ImportingNavigation.kt index 3f8e109a21..3694d7a0c1 100644 --- a/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/platform/feature/settings/importing/ImportingNavigation.kt +++ b/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/platform/feature/settings/importing/ImportingNavigation.kt @@ -3,9 +3,14 @@ package com.bitwarden.authenticator.ui.platform.feature.settings.importing import androidx.navigation.NavController import androidx.navigation.NavGraphBuilder import androidx.navigation.NavOptions -import com.bitwarden.authenticator.ui.platform.base.util.composableWithSlideTransitions +import com.bitwarden.ui.platform.base.util.composableWithSlideTransitions +import kotlinx.serialization.Serializable -const val IMPORT_ROUTE = "importing" +/** + * The type-safe route for the import screen. + */ +@Serializable +data object ImportRoute /** * Add the import screen to the nav graph. @@ -13,7 +18,7 @@ const val IMPORT_ROUTE = "importing" fun NavGraphBuilder.importingDestination( onNavigateBack: () -> Unit, ) { - composableWithSlideTransitions(IMPORT_ROUTE) { + composableWithSlideTransitions { ImportingScreen( onNavigateBack = onNavigateBack, ) @@ -24,5 +29,5 @@ fun NavGraphBuilder.importingDestination( * Navigate to the Import destination. */ fun NavController.navigateToImporting(navOptions: NavOptions? = null) { - navigate(IMPORT_ROUTE, navOptions) + navigate(route = ImportRoute, navOptions = navOptions) } diff --git a/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/platform/feature/splash/SplashNavigation.kt b/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/platform/feature/splash/SplashNavigation.kt index bbca8c418d..70ec1cad34 100644 --- a/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/platform/feature/splash/SplashNavigation.kt +++ b/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/platform/feature/splash/SplashNavigation.kt @@ -4,14 +4,19 @@ import androidx.navigation.NavController import androidx.navigation.NavGraphBuilder import androidx.navigation.NavOptions import androidx.navigation.compose.composable +import kotlinx.serialization.Serializable -const val SPLASH_ROUTE: String = "splash" +/** + * The type-safe route for the splash screen. + */ +@Serializable +data object SplashRoute /** * Add splash destinations to the nav graph. */ fun NavGraphBuilder.splashDestination() { - composable(SPLASH_ROUTE) { SplashScreen() } + composable { SplashScreen() } } /** @@ -20,5 +25,5 @@ fun NavGraphBuilder.splashDestination() { fun NavController.navigateToSplash( navOptions: NavOptions? = null, ) { - navigate(SPLASH_ROUTE, navOptions) + navigate(route = SplashRoute, navOptions = navOptions) } diff --git a/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/platform/feature/tutorial/TutorialNavigation.kt b/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/platform/feature/tutorial/TutorialNavigation.kt index 60b914abcd..1c121fc8d4 100644 --- a/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/platform/feature/tutorial/TutorialNavigation.kt +++ b/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/platform/feature/tutorial/TutorialNavigation.kt @@ -4,15 +4,25 @@ import androidx.navigation.NavController import androidx.navigation.NavGraphBuilder import androidx.navigation.NavOptions import androidx.navigation.compose.composable +import kotlinx.serialization.Serializable -const val TUTORIAL_ROUTE = "tutorial" -const val SETTINGS_TUTORIAL_ROUTE = "settings/tutorial" +/** + * The type-safe route for the tutorial screen. + */ +@Serializable +data object TutorialRoute + +/** + * The type-safe route for the settings tutorial screen. + */ +@Serializable +data object SettingsTutorialRoute /** * Add the top level Tutorial screen to the nav graph. */ fun NavGraphBuilder.tutorialDestination(onTutorialFinished: () -> Unit) { - composable(TUTORIAL_ROUTE) { + composable { TutorialScreen( onTutorialFinished = onTutorialFinished, ) @@ -23,7 +33,7 @@ fun NavGraphBuilder.tutorialDestination(onTutorialFinished: () -> Unit) { * Add the Settings Tutorial screen to the nav graph. */ fun NavGraphBuilder.tutorialSettingsDestination(onTutorialFinished: () -> Unit) { - composable(SETTINGS_TUTORIAL_ROUTE) { + composable { TutorialScreen( onTutorialFinished = onTutorialFinished, ) @@ -34,12 +44,12 @@ fun NavGraphBuilder.tutorialSettingsDestination(onTutorialFinished: () -> Unit) * Navigate to the top level Tutorial screen. */ fun NavController.navigateToTutorial(navOptions: NavOptions? = null) { - navigate(route = TUTORIAL_ROUTE, navOptions = navOptions) + navigate(route = TutorialRoute, navOptions = navOptions) } /** * Navigate to the Tutorial screen within Settings. */ fun NavController.navigateToSettingsTutorial(navOptions: NavOptions? = null) { - navigate(route = SETTINGS_TUTORIAL_ROUTE, navOptions) + navigate(route = SettingsTutorialRoute, navOptions = navOptions) } diff --git a/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/platform/theme/Transition.kt b/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/platform/theme/Transition.kt deleted file mode 100644 index 3419100727..0000000000 --- a/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/platform/theme/Transition.kt +++ /dev/null @@ -1,371 +0,0 @@ -package com.bitwarden.authenticator.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.compose.animation.slideInHorizontally -import androidx.compose.animation.slideOutHorizontally -import androidx.navigation.NavBackStackEntry -import androidx.navigation.compose.NavHost -import com.bitwarden.authenticator.ui.platform.theme.RootTransitionProviders.Exit.stay - -typealias EnterTransitionProvider = - (@JvmSuppressWildcards AnimatedContentTransitionScope.() -> EnterTransition?) - -typealias ExitTransitionProvider = - (@JvmSuppressWildcards AnimatedContentTransitionScope.() -> ExitTransition?) - -typealias NonNullEnterTransitionProvider = - (@JvmSuppressWildcards AnimatedContentTransitionScope.() -> EnterTransition) - -typealias NonNullExitTransitionProvider = - (@JvmSuppressWildcards AnimatedContentTransitionScope.() -> ExitTransition) - -/** - * The default transition time (in milliseconds) for all fade transitions in the - * [TransitionProviders]. - */ -const val DEFAULT_FADE_TRANSITION_TIME_MS: Int = 300 - -/** - * The default transition time (in milliseconds) for all slide transitions in the - * [TransitionProviders]. - */ -const val DEFAULT_SLIDE_TRANSITION_TIME_MS: Int = 450 - -/** - * The default transition time (in milliseconds) for all slide transitions in the - * [TransitionProviders]. - */ -const val DEFAULT_PUSH_TRANSITION_TIME_MS: Int = 350 - -/** - * The default transition time (in milliseconds) for all "stay"/no-op transitions in the - * [TransitionProviders]. - * - * This should be at least as large as any other transition that might also be happening during a - * navigation. - */ -val DEFAULT_STAY_TRANSITION_TIME_MS: Int = - maxOf( - DEFAULT_FADE_TRANSITION_TIME_MS, - DEFAULT_SLIDE_TRANSITION_TIME_MS, - DEFAULT_PUSH_TRANSITION_TIME_MS, - ) - -/** - * 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.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 left of the screen. - */ - val pushLeft: EnterTransitionProvider = { - RootTransitionProviders - .Enter - .pushLeft(this) - .takeIf { isSameGraphNavigation } - } - - /** - * Slides the new screen in from the right of the screen. - */ - val pushRight: EnterTransitionProvider = { - RootTransitionProviders - .Enter - .pushRight(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 out to the left of the screen. - */ - val pushLeft: ExitTransitionProvider = { - RootTransitionProviders - .Exit - .pushLeft(this) - .takeIf { isSameGraphNavigation } - } - - /** - * Slides the current screen out to the right of the screen. - */ - val pushRight: ExitTransitionProvider = { - RootTransitionProviders - .Exit - .pushRight(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_FADE_TRANSITION_TIME_MS)) - } - - /** - * There is no transition for the entering screen. - */ - val none: NonNullEnterTransitionProvider = { - EnterTransition.None - } - - /** - * Slides the new screen in from the left of the screen. - */ - val pushLeft: NonNullEnterTransitionProvider = { - val totalTransitionDurationMs = DEFAULT_PUSH_TRANSITION_TIME_MS - slideInHorizontally( - animationSpec = tween(durationMillis = totalTransitionDurationMs), - initialOffsetX = { fullWidth -> fullWidth / 2 }, - ) + fadeIn( - animationSpec = tween( - durationMillis = totalTransitionDurationMs / 2, - delayMillis = totalTransitionDurationMs / 2, - ), - ) - } - - /** - * Slides the new screen in from the right of the screen. - */ - val pushRight: NonNullEnterTransitionProvider = { - val totalTransitionDurationMs = DEFAULT_PUSH_TRANSITION_TIME_MS - slideInHorizontally( - animationSpec = tween(durationMillis = totalTransitionDurationMs), - initialOffsetX = { fullWidth -> -fullWidth / 2 }, - ) + fadeIn( - animationSpec = tween( - durationMillis = totalTransitionDurationMs / 2, - delayMillis = totalTransitionDurationMs / 2, - ), - ) - } - - /** - * Slides the new screen in from the bottom of the screen. - */ - val slideUp: NonNullEnterTransitionProvider = { - slideIntoContainer( - towards = AnimatedContentTransitionScope.SlideDirection.Up, - animationSpec = tween(DEFAULT_SLIDE_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_STAY_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_FADE_TRANSITION_TIME_MS)) - } - - /** - * There is no transition for the exiting screen. - * - * Unlike the [stay] transition, this will immediately remove the outgoing screen even if - * there is an ongoing enter transition happening for the new screen. - */ - val none: NonNullExitTransitionProvider = { - ExitTransition.None - } - - /** - * Slides the current screen out to the left of the screen. - */ - @Suppress("MagicNumber") - val pushLeft: NonNullExitTransitionProvider = { - val totalTransitionDurationMs = DEFAULT_PUSH_TRANSITION_TIME_MS - val delayMs = totalTransitionDurationMs / 7 - val slideWithoutDelayMs = totalTransitionDurationMs - delayMs - slideOutHorizontally( - animationSpec = tween( - durationMillis = slideWithoutDelayMs, - delayMillis = delayMs, - ), - targetOffsetX = { fullWidth -> -fullWidth / 2 }, - ) + fadeOut( - animationSpec = tween( - durationMillis = totalTransitionDurationMs / 2, - delayMillis = delayMs, - ), - ) - } - - /** - * Slides the current screen out to the right of the screen. - */ - @Suppress("MagicNumber") - val pushRight: NonNullExitTransitionProvider = { - val totalTransitionDurationMs = DEFAULT_PUSH_TRANSITION_TIME_MS - val delayMs = totalTransitionDurationMs / 7 - val slideWithoutDelayMs = totalTransitionDurationMs - delayMs - slideOutHorizontally( - animationSpec = tween( - durationMillis = slideWithoutDelayMs, - delayMillis = delayMs, - ), - targetOffsetX = { fullWidth -> fullWidth / 2 }, - ) + fadeOut( - animationSpec = tween( - durationMillis = totalTransitionDurationMs / 2, - delayMillis = delayMs, - ), - ) - } - - /** - * Slides the current screen down to the bottom of the screen. - */ - val slideDown: NonNullExitTransitionProvider = { - slideOutOfContainer( - towards = AnimatedContentTransitionScope.SlideDirection.Down, - animationSpec = tween(DEFAULT_SLIDE_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_STAY_TRANSITION_TIME_MS), - targetAlpha = 0.99f, - ) - } - } -}