Compare commits

...
2 Commits
Author SHA1 Message Date
Ashin Walpola 3da60d3a99 Ignore Office lock files
Word creates ~$<name>.docx beside a document while it is open and removes it on
close. docs/~$crOBU-User-Guide.docx was showing as untracked while the user guide
was being edited, which is exactly the kind of transient file a git add -A sweeps
in by accident.
2026-08-26 17:13:50 +02:00
Ashin Walpola 081347f31b 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.
2026-08-26 17:12:46 +02:00
2 changed files with 37 additions and 5 deletions
+4
View File
@@ -38,3 +38,7 @@ sdkconfig.old
# Third-party working copies kept beside the project, not part of it. The ASN.1 # Third-party working copies kept beside the project, not part of it. The ASN.1
# modules this project actually needs are vendored under asn1/ instead. # modules this project actually needs are vendored under asn1/ instead.
/C-ITS-Parser/ /C-ITS-Parser/
# Office lock files. Word/Excel create these beside a document while it is open
# and remove them on close, so they are transient and machine-local.
~$*
@@ -63,6 +63,23 @@ private val bottomNavItems = listOf(
Screen.Settings, 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 @Composable
fun BottomNavBar(navController: NavController) { fun BottomNavBar(navController: NavController) {
val backStackEntry by navController.currentBackStackEntryAsState() val backStackEntry by navController.currentBackStackEntryAsState()
@@ -70,13 +87,24 @@ fun BottomNavBar(navController: NavController) {
NavigationBar { NavigationBar {
bottomNavItems.forEach { screen -> bottomNavItems.forEach { screen ->
val onThisTab = screen.ownsRoute(currentRoute)
NavigationBarItem( NavigationBarItem(
selected = currentRoute == screen.route, selected = onThisTab,
onClick = { onClick = {
navController.navigate(screen.route) { if (onThisTab && currentRoute != screen.route) {
popUpTo(Screen.Dashboard.route) { saveState = true } // Already inside this tab, just deeper in: pop back to the tab's own
launchSingleTop = true // screen. Navigating instead would restoreState the saved back stack and
restoreState = true // 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 = { icon = {