fix(ux): keep Settings highlighted in bottom nav on drill-down sub-pages (issue #637) (#643)

* fix(ux): keep Settings highlighted in bottom nav on drill-down sub-pages (issue #637)

Map Settings drill-down destinations (SettingsConnection, SettingsAppearance, SettingsChat, SettingsNavBar, SettingsBehavior, SettingsAbout) back to SettingsScreen for bottom-nav selection only - navigation is unaffected.

- Add selectedBottomNavDestination() helper in Navigation.kt
- Extract bar-height logic into Modifier.bottomNavigationHeight() (ICON_AND_TEXT now uses heightIn(min=80.dp) so the standard bar can grow)
- BottomNavigationSelectionTest (JVM): selection mapping logic
- BottomNavigationLayoutTest (androidTest): per-mode bar height assertions

* docs(navigation): warn that new Settings sub-pages must be added to settingsDestinations

Addresses agy review (PR #643): documents the fragility of the hardcoded settingsDestinations set so future Settings drill-down screens don't silently drop the bottom-nav highlight. The sealed-class/marker-interface refactor was declined as scope creep (issue #637 explicitly scopes Settings-only; keys are flat data objects).

* fix: language selector

---------

Co-authored-by: M57 <Hy4ri@users.noreply.github.com>
This commit is contained in:
M57andM57 authored and GitHub committed 2026-07-20 18:26:05 +03:00
1 parent 367d6e22f5
commit e18b25d065
3 files changed
+154 -8

No files matched your search

@@ -0,0 +1,59 @@
package com.m57.hermescontrol
import androidx.navigation3.runtime.NavKey
import org.junit.Assert.assertEquals
import org.junit.Test
/**
* Verifies that the bottom-nav selection key maps Settings drill-down
* destinations back to [SettingsScreen] so the indicator stays highlighted,
* while every other screen is returned unchanged.
*/
class BottomNavigationSelectionTest {
@Test
fun `SettingsScreen selects itself`() {
assertEquals(SettingsScreen, selectedBottomNavDestination(SettingsScreen))
}
@Test
fun `every Settings drill-down maps back to SettingsScreen`() {
val drillDowns: List<NavKey> =
listOf(
SettingsConnection,
SettingsAppearance,
SettingsChat,
SettingsNavBar,
SettingsBehavior,
SettingsAbout,
)
for (destination in drillDowns) {
assertEquals(
"Expected $destination to map to SettingsScreen",
SettingsScreen,
selectedBottomNavDestination(destination),
)
}
}
@Test
fun `non-Settings screens are returned unchanged`() {
val others: List<NavKey> =
listOf(
ChatScreen,
CronJobsScreen,
WebhooksScreen,
GatewayScreen,
SkillsScreen,
LandingScreen,
AuthLoginScreen,
PairingCodeEntryScreen,
)
for (screen in others) {
assertEquals(
"Expected $screen to be returned unchanged",
screen,
selectedBottomNavDestination(screen),
)
}
}
}