From 081347f31b4fcc919720a5e120b6025f09a6704a Mon Sep 17 00:00:00 2001 From: Ashin Walpola Date: Wed, 26 Aug 2026 17:12:46 +0200 Subject: [PATCH] Tapping the active bottom-nav tab returns to that tab's root screen Tapping Settings while on Settings > Connection appeared to do nothing. The tab navigated to its own route, but restoreState = true then restored that tab's saved back stack, putting the sub-screen straight back on top. The only way out was the back button or a back swipe. When the tap targets the tab already in use and the current destination is deeper inside it, pop back to the tab's own screen instead of navigating. Only entries above the tab root are removed, so Back and back-swipe behave exactly as before - both routes out of a sub-screen now work. The tab also stayed unhighlighted while any sub-screen was open, because selected compared the current route for equality with the tab's route. Ownership is now derived from the existing route naming convention, so settings/connection belongs to Settings and trip_review/{tripId} belongs to Trips. A new settings/* screen is picked up automatically; a sub-screen named outside its tab's prefix would need a line in ownsRoute. --- .../micr0bu/ui/navigation/AppNavigation.kt | 38 ++++++++++++++++--- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/hawhamburg/micr0bu/ui/navigation/AppNavigation.kt b/app/src/main/java/com/hawhamburg/micr0bu/ui/navigation/AppNavigation.kt index 8b0763f..e7cf0f4 100644 --- a/app/src/main/java/com/hawhamburg/micr0bu/ui/navigation/AppNavigation.kt +++ b/app/src/main/java/com/hawhamburg/micr0bu/ui/navigation/AppNavigation.kt @@ -63,6 +63,23 @@ private val bottomNavItems = listOf( Screen.Settings, ) +/** + * True if [route] is this tab's own screen or one of its sub-screens. + * + * The graph is flat, so ownership is derived from the route naming convention: every Settings + * sub-screen is "settings/...", and a trip review is "trip_review/{tripId}" belonging to Trips. + * Without this, a tab stops looking selected the moment you open anything inside it. + */ +private fun Screen.ownsRoute(route: String?): Boolean { + if (route == null) return false + if (route == this.route) return true + return when (this) { + Screen.Settings -> route.startsWith("settings/") + Screen.TripHistory -> route.startsWith("trip_review") + else -> false + } +} + @Composable fun BottomNavBar(navController: NavController) { val backStackEntry by navController.currentBackStackEntryAsState() @@ -70,13 +87,24 @@ fun BottomNavBar(navController: NavController) { NavigationBar { bottomNavItems.forEach { screen -> + val onThisTab = screen.ownsRoute(currentRoute) NavigationBarItem( - selected = currentRoute == screen.route, + selected = onThisTab, onClick = { - navController.navigate(screen.route) { - popUpTo(Screen.Dashboard.route) { saveState = true } - launchSingleTop = true - restoreState = true + if (onThisTab && currentRoute != screen.route) { + // Already inside this tab, just deeper in: pop back to the tab's own + // screen. Navigating instead would restoreState the saved back stack and + // land straight back on the sub-screen, which reads as the tap doing + // nothing - the reason Settings > Connection could not be left by tapping + // Settings. Leaves the rest of the stack intact, so Back still works + // exactly as before. + navController.popBackStack(screen.route, inclusive = false) + } else { + navController.navigate(screen.route) { + popUpTo(Screen.Dashboard.route) { saveState = true } + launchSingleTop = true + restoreState = true + } } }, icon = {