@@ -14,6 +14,7 @@ import androidx.compose.animation.Crossfade
1414import androidx.compose.animation.EnterTransition
1515import androidx.compose.animation.ExitTransition
1616import androidx.compose.animation.core.tween
17+ import androidx.compose.animation.core.FastOutSlowInEasing
1718import androidx.compose.animation.fadeIn
1819import androidx.compose.animation.fadeOut
1920import androidx.compose.animation.scaleOut
@@ -187,60 +188,92 @@ class MainActivity : AppCompatActivity() {
187188 val bottomBarRoutes = remember {
188189 BottomBarDestination .entries.map { it.direction.route }.toSet()
189190 }
191+ val bottomBarRouteIndex = remember {
192+ BottomBarDestination .entries
193+ .mapIndexed { index, destination -> destination.direction.route to index }
194+ .toMap()
195+ }
190196 val state by APApplication .apStateLiveData.observeAsState(APApplication .State .UNKNOWN_STATE )
191197 val kPatchReady = state != APApplication .State .UNKNOWN_STATE
192198 val aPatchReady = state == APApplication .State .ANDROIDPATCH_INSTALLED
193199 val visibleDestinations = remember(state) {
194200 BottomBarDestination .entries.filter { destination ->
195201 ! (destination.kPatchRequired && ! kPatchReady) && ! (destination.aPatchRequired && ! aPatchReady)
196- }.toSet()
202+ }
197203 }
198204
199- val defaultTransitions = object : NavHostAnimatedDestinationStyle () {
200- override val enterTransition: AnimatedContentTransitionScope <NavBackStackEntry >.() -> EnterTransition =
201- {
202- // If the target is a detail page (not a bottom navigation page), slide in from the right
203- if (targetState.destination.route !in bottomBarRoutes) {
204- slideInHorizontally(initialOffsetX = { it })
205- } else {
206- // Otherwise (switching between bottom navigation pages), use fade in
207- fadeIn(animationSpec = tween(340 ))
205+ val defaultTransitions = remember(bottomBarRoutes, bottomBarRouteIndex) {
206+ object : NavHostAnimatedDestinationStyle () {
207+ override val enterTransition: AnimatedContentTransitionScope <NavBackStackEntry >.() -> EnterTransition =
208+ {
209+ val fromIndex = bottomBarRouteIndex[initialState.destination.route]
210+ val toIndex = bottomBarRouteIndex[targetState.destination.route]
211+ if (fromIndex != null && toIndex != null ) {
212+ val slideFrom = if (toIndex > fromIndex) { { width: Int -> width / 3 } } else { { width: Int -> - width / 3 } }
213+ slideInHorizontally(
214+ initialOffsetX = slideFrom,
215+ animationSpec = tween(durationMillis = 300 , easing = FastOutSlowInEasing )
216+ ) + fadeIn(animationSpec = tween(durationMillis = 240 , easing = FastOutSlowInEasing ))
217+ } else if (targetState.destination.route !in bottomBarRoutes) {
218+ slideInHorizontally(
219+ initialOffsetX = { it / 2 },
220+ animationSpec = tween(durationMillis = 320 , easing = FastOutSlowInEasing )
221+ ) + fadeIn(animationSpec = tween(durationMillis = 260 , easing = FastOutSlowInEasing ))
222+ } else {
223+ fadeIn(animationSpec = tween(220 , easing = FastOutSlowInEasing ))
224+ }
208225 }
209- }
210226
211- override val exitTransition: AnimatedContentTransitionScope <NavBackStackEntry >.() -> ExitTransition =
212- {
213- // If navigating from the home page (bottom navigation page) to a detail page, slide out to the left
214- if (initialState.destination.route in bottomBarRoutes && targetState.destination.route !in bottomBarRoutes) {
215- slideOutHorizontally(targetOffsetX = { - it / 4 }) + fadeOut()
216- } else {
217- // Otherwise (switching between bottom navigation pages), use fade out
218- fadeOut(animationSpec = tween(340 ))
227+ override val exitTransition: AnimatedContentTransitionScope <NavBackStackEntry >.() -> ExitTransition =
228+ {
229+ val fromIndex = bottomBarRouteIndex[initialState.destination.route]
230+ val toIndex = bottomBarRouteIndex[targetState.destination.route]
231+ if (fromIndex != null && toIndex != null ) {
232+ val slideTo = if (toIndex > fromIndex) { { width: Int -> - width / 6 } } else { { width: Int -> width / 6 } }
233+ slideOutHorizontally(
234+ targetOffsetX = slideTo,
235+ animationSpec = tween(durationMillis = 300 , easing = FastOutSlowInEasing )
236+ ) + fadeOut(animationSpec = tween(durationMillis = 210 , easing = FastOutSlowInEasing ))
237+ } else if (initialState.destination.route in bottomBarRoutes && targetState.destination.route !in bottomBarRoutes) {
238+ slideOutHorizontally(
239+ targetOffsetX = { - it / 6 },
240+ animationSpec = tween(durationMillis = 300 , easing = FastOutSlowInEasing )
241+ ) + fadeOut(
242+ animationSpec = tween(durationMillis = 220 , easing = FastOutSlowInEasing )
243+ )
244+ } else {
245+ fadeOut(animationSpec = tween(durationMillis = 220 , easing = FastOutSlowInEasing ))
246+ }
219247 }
220- }
221248
222- override val popEnterTransition: AnimatedContentTransitionScope <NavBackStackEntry >.() -> EnterTransition =
223- {
224- // If returning to the home page (bottom navigation page), slide in from the left
225- if (targetState.destination.route in bottomBarRoutes) {
226- slideInHorizontally(initialOffsetX = { - it / 4 }) + fadeIn()
227- } else {
228- // Otherwise (e.g., returning between multiple detail pages), use default fade in
229- fadeIn(animationSpec = tween(340 ))
249+ override val popEnterTransition: AnimatedContentTransitionScope <NavBackStackEntry >.() -> EnterTransition =
250+ {
251+ if (targetState.destination.route in bottomBarRoutes) {
252+ slideInHorizontally(
253+ initialOffsetX = { - it / 6 },
254+ animationSpec = tween(durationMillis = 300 , easing = FastOutSlowInEasing )
255+ ) + fadeIn(
256+ animationSpec = tween(durationMillis = 240 , easing = FastOutSlowInEasing )
257+ )
258+ } else {
259+ fadeIn(animationSpec = tween(durationMillis = 220 , easing = FastOutSlowInEasing ))
260+ }
230261 }
231- }
232262
233- override val popExitTransition: AnimatedContentTransitionScope <NavBackStackEntry >.() -> ExitTransition =
234- {
235- // If returning from a detail page (not a bottom navigation page), scale down and fade out
236- if (initialState.destination.route !in bottomBarRoutes) {
237- scaleOut(targetScale = 0.9f ) + fadeOut()
238- } else {
239- // Otherwise, use default fade out
240- fadeOut(animationSpec = tween(340 ))
263+ override val popExitTransition: AnimatedContentTransitionScope <NavBackStackEntry >.() -> ExitTransition =
264+ {
265+ if (initialState.destination.route !in bottomBarRoutes) {
266+ scaleOut(
267+ targetScale = 0.96f ,
268+ animationSpec = tween(durationMillis = 260 , easing = FastOutSlowInEasing )
269+ ) + fadeOut(animationSpec = tween(durationMillis = 220 , easing = FastOutSlowInEasing ))
270+ } else {
271+ fadeOut(animationSpec = tween(durationMillis = 180 , easing = FastOutSlowInEasing ))
272+ }
241273 }
242- }
274+ }
243275 }
276+ val navHostEngine = rememberNavHostEngine(navHostContentAlignment = Alignment .TopCenter )
244277
245278 ShortcutIntentHandler (currentIntent = currentIntent, navigator = navigator)
246279
@@ -362,7 +395,7 @@ class MainActivity : AppCompatActivity() {
362395 DestinationsNavHost (
363396 navGraph = NavGraphs .root,
364397 navController = navController,
365- engine = rememberNavHostEngine(navHostContentAlignment = Alignment . TopCenter ) ,
398+ engine = navHostEngine ,
366399 defaultTransitions = defaultTransitions
367400 )
368401 }
@@ -377,7 +410,7 @@ class MainActivity : AppCompatActivity() {
377410 DestinationsNavHost (
378411 navGraph = NavGraphs .root,
379412 navController = navController,
380- engine = rememberNavHostEngine(navHostContentAlignment = Alignment . TopCenter ) ,
413+ engine = navHostEngine ,
381414 defaultTransitions = defaultTransitions
382415 )
383416 }
@@ -440,7 +473,7 @@ private fun ShortcutIntentHandler(
440473
441474
442475@Composable
443- private fun BottomBar (navController : NavHostController , visibleDestinations : Set <BottomBarDestination >) {
476+ private fun BottomBar (navController : NavHostController , visibleDestinations : List <BottomBarDestination >) {
444477 val navigator = navController.rememberDestinationsNavigator()
445478 val background = rememberBackgroundConfig()
446479
@@ -460,6 +493,7 @@ private fun BottomBar(navController: NavHostController, visibleDestinations: Set
460493 onClick = {
461494 if (isCurrentDestOnBackStack) {
462495 navigator.popBackStack(destination.direction, false )
496+ return @NavigationBarItem
463497 }
464498 navigator.navigate(destination.direction) {
465499 popUpTo(NavGraphs .root) {
@@ -492,7 +526,7 @@ private fun BottomBar(navController: NavHostController, visibleDestinations: Set
492526}
493527
494528@Composable
495- private fun SideBar (navController : NavHostController , modifier : Modifier = Modifier , visibleDestinations : Set <BottomBarDestination >) {
529+ private fun SideBar (navController : NavHostController , modifier : Modifier = Modifier , visibleDestinations : List <BottomBarDestination >) {
496530 val navigator = navController.rememberDestinationsNavigator()
497531
498532 Crossfade (
@@ -514,6 +548,7 @@ private fun SideBar(navController: NavHostController, modifier: Modifier = Modif
514548 onClick = {
515549 if (isCurrentDestOnBackStack) {
516550 navigator.popBackStack(destination.direction, false )
551+ return @NavigationRailItem
517552 }
518553 navigator.navigate(destination.direction) {
519554 popUpTo(NavGraphs .root) {
0 commit comments