Refactor navigation to use NodeDetail route and fix radio settings (#4960)

This commit is contained in:
James Rich
2026-03-31 09:03:02 -05:00
committed by GitHub
parent c75c9b34d6
commit 6a5115b897
7 changed files with 19 additions and 28 deletions

View File

@@ -445,18 +445,6 @@ class BleRadioInterface(
// onDisconnect is handled by SharedRadioInterfaceService.stopInterfaceLocked() directly.
serviceScope.launch {
withContext(NonCancellable) {
// Send ToRadio.disconnect before dropping the BLE link. The firmware calls its
// own close() immediately on receipt, resetting the PhoneAPI state machine
// (config nonce, packet queue, observers) without waiting for the 6-second BLE
// supervision timeout. Best-effort: if the write fails we still disconnect below.
val currentService = radioService
if (currentService != null) {
try {
withTimeoutOrNull(2_000L) { currentService.sendToRadio(ToRadio(disconnect = true).encode()) }
} catch (@Suppress("TooGenericExceptionCaught") e: Exception) {
Logger.w(e) { "[$address] Failed to send disconnect signal" }
}
}
try {
bleConnection.disconnect()
} catch (@Suppress("TooGenericExceptionCaught") e: Exception) {

View File

@@ -32,8 +32,8 @@ fun EntryProviderScope<NavKey>.connectionsGraph(backStack: NavBackStack<NavKey>)
ConnectionsScreen(
scanModel = koinViewModel<ScannerViewModel>(),
radioConfigViewModel = koinViewModel<RadioConfigViewModel>(),
onClickNodeChip = { backStack.add(NodesRoutes.NodeDetailGraph(it)) },
onNavigateToNodeDetails = { backStack.add(NodesRoutes.NodeDetailGraph(it)) },
onClickNodeChip = { backStack.add(NodesRoutes.NodeDetail(it)) },
onNavigateToNodeDetails = { backStack.add(NodesRoutes.NodeDetail(it)) },
onConfigNavigate = { route -> backStack.add(route) },
)
}
@@ -42,8 +42,8 @@ fun EntryProviderScope<NavKey>.connectionsGraph(backStack: NavBackStack<NavKey>)
ConnectionsScreen(
scanModel = koinViewModel<ScannerViewModel>(),
radioConfigViewModel = koinViewModel<RadioConfigViewModel>(),
onClickNodeChip = { backStack.add(NodesRoutes.NodeDetailGraph(it)) },
onNavigateToNodeDetails = { backStack.add(NodesRoutes.NodeDetailGraph(it)) },
onClickNodeChip = { backStack.add(NodesRoutes.NodeDetail(it)) },
onNavigateToNodeDetails = { backStack.add(NodesRoutes.NodeDetail(it)) },
onConfigNavigate = { route -> backStack.add(route) },
)
}

View File

@@ -26,8 +26,8 @@ fun EntryProviderScope<NavKey>.mapGraph(backStack: NavBackStack<NavKey>) {
entry<MapRoutes.Map> { args ->
val mapScreen = org.meshtastic.core.ui.util.LocalMapMainScreenProvider.current
mapScreen(
{ backStack.add(NodesRoutes.NodeDetailGraph(it)) }, // onClickNodeChip
{ backStack.add(NodesRoutes.NodeDetailGraph(it)) }, // navigateToNodeDetails
{ backStack.add(NodesRoutes.NodeDetail(it)) }, // onClickNodeChip
{ backStack.add(NodesRoutes.NodeDetail(it)) }, // navigateToNodeDetails
args.waypointId,
)
}

View File

@@ -28,6 +28,7 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import org.koin.compose.viewmodel.koinViewModel
import org.meshtastic.core.navigation.ContactsRoutes
import org.meshtastic.core.navigation.NodesRoutes
import org.meshtastic.core.navigation.replaceLast
import org.meshtastic.core.ui.component.ScrollToTopEvent
import org.meshtastic.feature.messaging.QuickChatScreen
@@ -60,7 +61,7 @@ fun EntryProviderScope<NavKey>.contactsGraph(
contactKey = contactKey,
message = args.message,
viewModel = messageViewModel,
navigateToNodeDetails = { backStack.add(org.meshtastic.core.navigation.NodesRoutes.NodeDetailGraph(it)) },
navigateToNodeDetails = { backStack.add(NodesRoutes.NodeDetail(it)) },
navigateToQuickChatOptions = { backStack.add(org.meshtastic.core.navigation.ContactsRoutes.QuickChat) },
onNavigateBack = { backStack.removeLastOrNull() },
)

View File

@@ -47,9 +47,9 @@ fun AdaptiveContactsScreen(
onClearSharedContactRequested = onClearSharedContactRequested,
onClearRequestChannelUrl = onClearRequestChannelUrl,
viewModel = contactsViewModel,
onClickNodeChip = { backStack.add(NodesRoutes.NodeDetailGraph(it)) },
onClickNodeChip = { backStack.add(NodesRoutes.NodeDetail(it)) },
onNavigateToMessages = { contactKey -> backStack.add(ContactsRoutes.Messages(contactKey)) },
onNavigateToNodeDetails = { backStack.add(NodesRoutes.NodeDetailGraph(it)) },
onNavigateToNodeDetails = { backStack.add(NodesRoutes.NodeDetail(it)) },
scrollToTopEvents = scrollToTopEvents,
activeContactKey = null,
)

View File

@@ -18,7 +18,9 @@ package org.meshtastic.feature.settings.navigation
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.SideEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.navigation3.runtime.EntryProviderScope
import androidx.navigation3.runtime.NavBackStack
@@ -70,14 +72,14 @@ import kotlin.reflect.KClass
@Composable
fun getRadioConfigViewModel(backStack: NavBackStack<NavKey>): RadioConfigViewModel {
val viewModel = koinViewModel<RadioConfigViewModel>()
LaunchedEffect(backStack) {
val destNum =
val destNum =
remember(backStack.toList()) {
backStack.lastOrNull { it is SettingsRoutes.Settings }?.let { (it as SettingsRoutes.Settings).destNum }
?: backStack
.lastOrNull { it is SettingsRoutes.SettingsGraph }
?.let { (it as SettingsRoutes.SettingsGraph).destNum }
viewModel.initDestNum(destNum)
}
}
SideEffect { viewModel.initDestNum(destNum) }
return viewModel
}
@@ -87,7 +89,7 @@ fun EntryProviderScope<NavKey>.settingsGraph(backStack: NavBackStack<NavKey>) {
SettingsMainScreen(
settingsViewModel = koinViewModel(),
radioConfigViewModel = getRadioConfigViewModel(backStack),
onClickNodeChip = { backStack.add(NodesRoutes.NodeDetailGraph(it)) },
onClickNodeChip = { backStack.add(NodesRoutes.NodeDetail(it)) },
onNavigate = { backStack.add(it) },
)
}
@@ -96,7 +98,7 @@ fun EntryProviderScope<NavKey>.settingsGraph(backStack: NavBackStack<NavKey>) {
SettingsMainScreen(
settingsViewModel = koinViewModel(),
radioConfigViewModel = getRadioConfigViewModel(backStack),
onClickNodeChip = { backStack.add(NodesRoutes.NodeDetailGraph(it)) },
onClickNodeChip = { backStack.add(NodesRoutes.NodeDetail(it)) },
onNavigate = { backStack.add(it) },
)
}

View File

@@ -433,7 +433,7 @@ open class RadioConfigViewModel(
}
fun setResponseStateLoading(route: Enum<*>) {
val destNum = destNode.value?.num ?: return
val destNum = destNumFlow.value ?: destNode.value?.num ?: return
_radioConfigState.update { it.copy(route = route.name, responseState = ResponseState.Loading()) }