Move SettingsNavigation back to :app module (#3604)

This commit is contained in:
Phil Oliver 2025-11-03 19:31:24 -05:00 committed by GitHub
parent e147025528
commit e9bc9c9b15
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 72 additions and 39 deletions

View file

@ -27,7 +27,7 @@ import androidx.navigation.navigation
import com.geeksville.mesh.ui.sharing.ChannelScreen
import org.meshtastic.core.navigation.ChannelsRoutes
import org.meshtastic.core.navigation.DEEP_LINK_BASE_URI
import org.meshtastic.feature.settings.navigation.ConfigRoute
import org.meshtastic.core.navigation.SettingsRoutes
import org.meshtastic.feature.settings.radio.channel.ChannelConfigScreen
import org.meshtastic.feature.settings.radio.component.LoRaConfigScreen
@ -44,19 +44,13 @@ fun NavGraphBuilder.channelsGraph(navController: NavHostController) {
onNavigateUp = { navController.navigateUp() },
)
}
configRoutes(navController)
}
}
private fun NavGraphBuilder.configRoutes(navController: NavHostController) {
ConfigRoute.entries.forEach { configRoute ->
composable(configRoute.route::class) { backStackEntry ->
val parentEntry = remember(backStackEntry) { navController.getBackStackEntry(ChannelsRoutes.ChannelsGraph) }
when (configRoute) {
ConfigRoute.CHANNELS -> ChannelConfigScreen(hiltViewModel(parentEntry), navController::popBackStack)
ConfigRoute.LORA -> LoRaConfigScreen(hiltViewModel(parentEntry), navController::popBackStack)
else -> Unit // Should not happen if ConfigRoute enum is exhaustive for this context
}
navController.configComposable<SettingsRoutes.ChannelConfig, ChannelsRoutes.ChannelsGraph> {
ChannelConfigScreen(viewModel = it, onBack = navController::popBackStack)
}
navController.configComposable<SettingsRoutes.LoRa, ChannelsRoutes.ChannelsGraph> {
LoRaConfigScreen(viewModel = it, onBack = navController::popBackStack)
}
}
}

View file

@ -29,7 +29,6 @@ import org.meshtastic.core.navigation.ConnectionsRoutes
import org.meshtastic.core.navigation.DEEP_LINK_BASE_URI
import org.meshtastic.core.navigation.NodesRoutes
import org.meshtastic.core.navigation.SettingsRoutes
import org.meshtastic.feature.settings.radio.RadioConfigViewModel
import org.meshtastic.feature.settings.radio.component.LoRaConfigScreen
/** Navigation graph for for the top level ConnectionsScreen - [ConnectionsRoutes.Connections]. */
@ -55,14 +54,9 @@ fun NavGraphBuilder.connectionsGraph(navController: NavHostController) {
onConfigNavigate = { route -> navController.navigate(route) },
)
}
configRoutes(navController)
}
}
private fun NavGraphBuilder.configRoutes(navController: NavHostController) {
composable<SettingsRoutes.LoRa> { backStackEntry ->
val parentEntry =
remember(backStackEntry) { navController.getBackStackEntry(ConnectionsRoutes.ConnectionsGraph) }
LoRaConfigScreen(viewModel = hiltViewModel<RadioConfigViewModel>(parentEntry), navController::popBackStack)
navController.configComposable<SettingsRoutes.LoRa, ConnectionsRoutes.ConnectionsGraph> {
LoRaConfigScreen(viewModel = it, onBack = navController::popBackStack)
}
}
}

View file

@ -0,0 +1,195 @@
/*
* Copyright (c) 2025 Meshtastic LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
@file:Suppress("Wrapping", "SpacingAroundColon")
package com.geeksville.mesh.navigation
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.navigation.NavGraphBuilder
import androidx.navigation.NavHostController
import androidx.navigation.compose.composable
import androidx.navigation.navDeepLink
import androidx.navigation.navigation
import org.meshtastic.core.navigation.DEEP_LINK_BASE_URI
import org.meshtastic.core.navigation.Graph
import org.meshtastic.core.navigation.NodesRoutes
import org.meshtastic.core.navigation.Route
import org.meshtastic.core.navigation.SettingsRoutes
import org.meshtastic.feature.settings.SettingsScreen
import org.meshtastic.feature.settings.debugging.DebugScreen
import org.meshtastic.feature.settings.navigation.ConfigRoute
import org.meshtastic.feature.settings.navigation.ModuleRoute
import org.meshtastic.feature.settings.radio.CleanNodeDatabaseScreen
import org.meshtastic.feature.settings.radio.RadioConfigViewModel
import org.meshtastic.feature.settings.radio.channel.ChannelConfigScreen
import org.meshtastic.feature.settings.radio.component.AmbientLightingConfigScreen
import org.meshtastic.feature.settings.radio.component.AudioConfigScreen
import org.meshtastic.feature.settings.radio.component.BluetoothConfigScreen
import org.meshtastic.feature.settings.radio.component.CannedMessageConfigScreen
import org.meshtastic.feature.settings.radio.component.DetectionSensorConfigScreen
import org.meshtastic.feature.settings.radio.component.DeviceConfigScreen
import org.meshtastic.feature.settings.radio.component.DisplayConfigScreen
import org.meshtastic.feature.settings.radio.component.ExternalNotificationConfigScreen
import org.meshtastic.feature.settings.radio.component.LoRaConfigScreen
import org.meshtastic.feature.settings.radio.component.MQTTConfigScreen
import org.meshtastic.feature.settings.radio.component.NeighborInfoConfigScreen
import org.meshtastic.feature.settings.radio.component.NetworkConfigScreen
import org.meshtastic.feature.settings.radio.component.PaxcounterConfigScreen
import org.meshtastic.feature.settings.radio.component.PositionConfigScreen
import org.meshtastic.feature.settings.radio.component.PowerConfigScreen
import org.meshtastic.feature.settings.radio.component.RangeTestConfigScreen
import org.meshtastic.feature.settings.radio.component.RemoteHardwareConfigScreen
import org.meshtastic.feature.settings.radio.component.SecurityConfigScreen
import org.meshtastic.feature.settings.radio.component.SerialConfigScreen
import org.meshtastic.feature.settings.radio.component.StoreForwardConfigScreen
import org.meshtastic.feature.settings.radio.component.TelemetryConfigScreen
import org.meshtastic.feature.settings.radio.component.UserConfigScreen
import kotlin.reflect.KClass
@Suppress("LongMethod")
fun NavGraphBuilder.settingsGraph(navController: NavHostController) {
navigation<SettingsRoutes.SettingsGraph>(startDestination = SettingsRoutes.Settings()) {
composable<SettingsRoutes.Settings>(
deepLinks = listOf(navDeepLink<SettingsRoutes.Settings>(basePath = "$DEEP_LINK_BASE_URI/settings")),
) { backStackEntry ->
val parentEntry =
remember(backStackEntry) { navController.getBackStackEntry(SettingsRoutes.SettingsGraph::class) }
SettingsScreen(
viewModel = hiltViewModel(parentEntry),
onClickNodeChip = {
navController.navigate(NodesRoutes.NodeDetailGraph(it)) {
launchSingleTop = true
restoreState = true
}
},
) {
navController.navigate(it) { popUpTo(SettingsRoutes.Settings()) { inclusive = false } }
}
}
composable<SettingsRoutes.CleanNodeDb>(
deepLinks =
listOf(
navDeepLink<SettingsRoutes.CleanNodeDb>(
basePath = "$DEEP_LINK_BASE_URI/settings/radio/clean_node_db",
),
),
) {
CleanNodeDatabaseScreen()
}
ConfigRoute.entries.forEach { entry ->
navController.configComposable(
route = entry.route::class,
parentGraphRoute = SettingsRoutes.SettingsGraph::class,
) { viewModel ->
when (entry) {
ConfigRoute.USER -> UserConfigScreen(viewModel, onBack = navController::popBackStack)
ConfigRoute.CHANNELS -> ChannelConfigScreen(viewModel, onBack = navController::popBackStack)
ConfigRoute.DEVICE -> DeviceConfigScreen(viewModel, onBack = navController::popBackStack)
ConfigRoute.POSITION -> PositionConfigScreen(viewModel, onBack = navController::popBackStack)
ConfigRoute.POWER -> PowerConfigScreen(viewModel, onBack = navController::popBackStack)
ConfigRoute.NETWORK -> NetworkConfigScreen(viewModel, onBack = navController::popBackStack)
ConfigRoute.DISPLAY -> DisplayConfigScreen(viewModel, onBack = navController::popBackStack)
ConfigRoute.LORA -> LoRaConfigScreen(viewModel, onBack = navController::popBackStack)
ConfigRoute.BLUETOOTH -> BluetoothConfigScreen(viewModel, onBack = navController::popBackStack)
ConfigRoute.SECURITY -> SecurityConfigScreen(viewModel, onBack = navController::popBackStack)
}
}
}
ModuleRoute.entries.forEach { entry ->
navController.configComposable(
route = entry.route::class,
parentGraphRoute = SettingsRoutes.SettingsGraph::class,
) { viewModel ->
when (entry) {
ModuleRoute.MQTT -> MQTTConfigScreen(viewModel, onBack = navController::popBackStack)
ModuleRoute.SERIAL -> SerialConfigScreen(viewModel, onBack = navController::popBackStack)
ModuleRoute.EXT_NOTIFICATION ->
ExternalNotificationConfigScreen(viewModel, onBack = navController::popBackStack)
ModuleRoute.STORE_FORWARD ->
StoreForwardConfigScreen(viewModel, onBack = navController::popBackStack)
ModuleRoute.RANGE_TEST -> RangeTestConfigScreen(viewModel, onBack = navController::popBackStack)
ModuleRoute.TELEMETRY -> TelemetryConfigScreen(viewModel, onBack = navController::popBackStack)
ModuleRoute.CANNED_MESSAGE ->
CannedMessageConfigScreen(viewModel, onBack = navController::popBackStack)
ModuleRoute.AUDIO -> AudioConfigScreen(viewModel, onBack = navController::popBackStack)
ModuleRoute.REMOTE_HARDWARE ->
RemoteHardwareConfigScreen(viewModel, onBack = navController::popBackStack)
ModuleRoute.NEIGHBOR_INFO ->
NeighborInfoConfigScreen(viewModel, onBack = navController::popBackStack)
ModuleRoute.AMBIENT_LIGHTING ->
AmbientLightingConfigScreen(viewModel, onBack = navController::popBackStack)
ModuleRoute.DETECTION_SENSOR ->
DetectionSensorConfigScreen(viewModel, onBack = navController::popBackStack)
ModuleRoute.PAXCOUNTER -> PaxcounterConfigScreen(viewModel, onBack = navController::popBackStack)
}
}
}
composable<SettingsRoutes.DebugPanel>(
deepLinks =
listOf(navDeepLink<SettingsRoutes.DebugPanel>(basePath = "$DEEP_LINK_BASE_URI/settings/debug_panel")),
) {
DebugScreen(onNavigateUp = navController::navigateUp)
}
}
}
context(_: NavGraphBuilder)
inline fun <reified R : Route, reified G : Graph> NavHostController.configComposable(
noinline content: @Composable (RadioConfigViewModel) -> Unit,
) {
configComposable(route = R::class, parentGraphRoute = G::class, content = content)
}
context(navGraphBuilder: NavGraphBuilder)
fun <R : Route, G : Graph> NavHostController.configComposable(
route: KClass<R>,
parentGraphRoute: KClass<G>,
content: @Composable (RadioConfigViewModel) -> Unit,
) {
navGraphBuilder.composable(route = route) { backStackEntry ->
val parentEntry = remember(backStackEntry) { getBackStackEntry(parentGraphRoute) }
content(hiltViewModel(parentEntry))
}
}

View file

@ -90,6 +90,7 @@ import com.geeksville.mesh.navigation.connectionsGraph
import com.geeksville.mesh.navigation.contactsGraph
import com.geeksville.mesh.navigation.mapGraph
import com.geeksville.mesh.navigation.nodesGraph
import com.geeksville.mesh.navigation.settingsGraph
import com.geeksville.mesh.repository.radio.MeshActivity
import com.geeksville.mesh.service.MeshService
import com.geeksville.mesh.ui.connections.DeviceType
@ -120,7 +121,6 @@ import org.meshtastic.core.ui.share.SharedContactDialog
import org.meshtastic.core.ui.theme.StatusColors.StatusBlue
import org.meshtastic.core.ui.theme.StatusColors.StatusGreen
import org.meshtastic.feature.node.metrics.annotateTraceroute
import org.meshtastic.feature.settings.navigation.settingsGraph
import org.meshtastic.proto.MeshProtos
import timber.log.Timber