refactor: remove bottom navigation bar (#665 #666 #667 #668) (#672)

* refactor(nav): remove bottom NavigationBar from Scaffold (#665)

* refactor(theme): remove BottomNavDisplayMode enum (#666)

* refactor(settings): remove nav bar customization page (#667)

* chore: clean up unused imports after bottom nav removal (#668)

* chore: remove dead bottom nav infrastructure after removal

- Remove SettingsNavBar NavKey (NavigationKeys.kt)
- Remove bottomNavItems field from ServerStoreState + migration code
- Remove _bottomNavItemsFlow, getBottomNavItems, setBottomNavItems from AuthManager
- Remove bottomNavItems handling from selfHealed() (ServerCollectionOps)
- Remove redundant bottomBar={} from Scaffold (Navigation.kt)
- Remove unused nav bar strings from values/strings.xml + values-ko/strings.xml
- Remove content_desc_move_up/down/remove_item strings
- Update SettingsViewModelTest.kt (drop stale getBottomNavItems mock)
- Update ServerStoreTest.kt (remove bottomNavItems assertions)

---------

Co-authored-by: M57 <Hy4ri@users.noreply.github.com>
This commit is contained in:
M57andM57 authored and GitHub committed 2026-07-22 10:14:50 +03:00
1 parent c43904b2b8
commit 0edb67338d
17 files changed
-580

No files matched your search

@@ -8,7 +8,6 @@ import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.consumeWindowInsets
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.navigationBars
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
@@ -22,9 +21,6 @@ import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ModalDrawerSheet
import androidx.compose.material3.ModalNavigationDrawer
import androidx.compose.material3.NavigationBar
import androidx.compose.material3.NavigationBarItem
import androidx.compose.material3.NavigationBarItemDefaults
import androidx.compose.material3.NavigationDrawerItem
import androidx.compose.material3.NavigationDrawerItemDefaults
import androidx.compose.material3.Scaffold
@@ -32,15 +28,12 @@ import androidx.compose.material3.Text
import androidx.compose.material3.rememberDrawerState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
@@ -52,7 +45,6 @@ import androidx.navigation3.ui.NavDisplay
import com.m57.hermescontrol.data.local.AuthManager
import com.m57.hermescontrol.data.ws.ConnectionStatus
import com.m57.hermescontrol.data.ws.HermesWsClient
import com.m57.hermescontrol.theme.BottomNavDisplayMode
import com.m57.hermescontrol.theme.LocalHermesStatusColors
import com.m57.hermescontrol.ui.common.DisableDrawerGestures
import com.m57.hermescontrol.ui.common.DrawerGestureController
@@ -62,46 +54,11 @@ import com.m57.hermescontrol.ui.settings.SettingsAppearancePage
import com.m57.hermescontrol.ui.settings.SettingsBehaviorPage
import com.m57.hermescontrol.ui.settings.SettingsChatPage
import com.m57.hermescontrol.ui.settings.SettingsConnectionPage
import com.m57.hermescontrol.ui.settings.SettingsNavBarPage
import com.m57.hermescontrol.ui.settings.SettingsViewModel
import kotlinx.coroutines.launch
import com.m57.hermescontrol.ui.authlogin.AuthLoginScreen as AuthLoginScreenContent
import com.m57.hermescontrol.ui.landing.LandingScreen as LandingScreenContent
// NOTE: if a new Settings drill-down screen is added, its NavKey MUST be added
// here too, or the bottom-nav Settings highlight will drop on that sub-page.
// (Keys are flat data objects, not a sealed hierarchy, so no type-based check
// is possible without a larger refactor — see issue #637.)
private val settingsDestinations: Set<NavKey> =
setOf(
SettingsScreen,
SettingsConnection,
SettingsAppearance,
SettingsChat,
SettingsNavBar,
SettingsBehavior,
SettingsAbout,
)
/**
* Keep Settings highlighted in the bottom nav while one of its drill-down
* sub-pages is visible. Navigation is unaffected — this only maps the
* *selection* key back to the Settings parent so the indicator doesn't drop.
*/
internal fun selectedBottomNavDestination(currentScreen: NavKey): NavKey =
if (currentScreen in settingsDestinations) SettingsScreen else currentScreen
/** Maps a compact bottom-nav display mode to its bar height. */
internal fun Modifier.bottomNavigationHeight(displayMode: BottomNavDisplayMode): Modifier =
when (displayMode) {
BottomNavDisplayMode.ICON_ONLY -> height(56.dp)
BottomNavDisplayMode.TEXT_ONLY -> height(44.dp)
BottomNavDisplayMode.ICON_AND_TEXT -> heightIn(min = 80.dp)
}
private fun resolveBottomNavItems(names: List<String>): List<ScreenDefinition> =
names.mapNotNull { name -> ScreenRegistry.ALL_SCREENS.firstOrNull { it.key::class.simpleName == name } }
private fun appEntryProvider(
sessionId: String?,
openDrawer: () -> Unit,
@@ -159,12 +116,6 @@ private fun appEntryProvider(
viewModel = viewModel { SettingsViewModel() },
)
}
entry<SettingsNavBar> {
SettingsNavBarPage(
onBack = { NavigationController.goBack() },
viewModel = viewModel { SettingsViewModel() },
)
}
entry<SettingsBehavior> {
SettingsBehaviorPage(
onBack = { NavigationController.goBack() },
@@ -189,7 +140,6 @@ fun MainNavigation(sessionId: String? = null) {
NavigationController.backStack = backStack
val currentScreen = backStack.lastOrNull() ?: startScreen
val selectedDestination = selectedBottomNavDestination(currentScreen)
val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed)
val scope = rememberCoroutineScope()
@@ -204,19 +154,6 @@ fun MainNavigation(sessionId: String? = null) {
DrawerGestureController(drawerState, scope)
}
val bottomNavItemsState by AuthManager.bottomNavItemsFlow.collectAsState()
val bottomNavDisplayMode by AuthManager.bottomNavDisplayModeFlow.collectAsState()
val bottomNavItems = resolveBottomNavItems(bottomNavItemsState)
val bottomNavKeys = remember(bottomNavItems) { bottomNavItems.mapTo(mutableSetOf()) { it.key } }
LaunchedEffect(bottomNavKeys) {
NavigationController.updatePrimaryScreens(bottomNavKeys)
}
val showBottomBar =
currentScreen != LandingScreen &&
currentScreen != AuthLoginScreen
val openDrawer: () -> Unit = { scope.launch { drawerState.open() } }
CompositionLocalProvider(LocalDrawerGestureController provides gestureController) {
@@ -312,60 +249,6 @@ fun MainNavigation(sessionId: String? = null) {
) {
Scaffold(
contentWindowInsets = WindowInsets.navigationBars,
bottomBar = {
if (showBottomBar) {
NavigationBar(
modifier = Modifier.bottomNavigationHeight(bottomNavDisplayMode),
) {
bottomNavItems.forEach { item ->
val showIcon =
bottomNavDisplayMode == BottomNavDisplayMode.ICON_AND_TEXT ||
bottomNavDisplayMode == BottomNavDisplayMode.ICON_ONLY
val showLabel =
bottomNavDisplayMode == BottomNavDisplayMode.ICON_AND_TEXT ||
bottomNavDisplayMode == BottomNavDisplayMode.TEXT_ONLY
val isSelected = selectedDestination == item.key
NavigationBarItem(
selected = isSelected,
onClick = { NavigationController.navigateTo(item.key) },
colors =
if (bottomNavDisplayMode == BottomNavDisplayMode.TEXT_ONLY) {
NavigationBarItemDefaults.colors(
indicatorColor = Color.Transparent,
)
} else {
NavigationBarItemDefaults.colors()
},
icon = {
if (showIcon) {
Icon(item.icon, contentDescription = stringResource(item.labelRes))
} else {
Text(
text = stringResource(item.labelRes),
style = MaterialTheme.typography.labelMedium,
fontWeight = if (isSelected) FontWeight.Bold else FontWeight.Normal,
)
}
},
label =
if (showLabel && showIcon) {
{ Text(stringResource(item.labelRes)) }
} else {
null
},
modifier =
Modifier.testTag(
"nav_${item.key::class.simpleName?.lowercase()?.removeSuffix(
"screen",
) ?: ""}",
),
)
}
}
}
},
) { paddingValues ->
NavDisplay(
backStack = backStack,