feat: implement unified deep link routing for Kotlin Multiplatform (#4910)

Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com>
This commit is contained in:
James Rich 2026-03-24 19:21:24 -05:00 committed by GitHub
parent 553ca2f8ed
commit b0e91a390c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
23 changed files with 325 additions and 75 deletions

View file

@ -218,6 +218,27 @@
<data android:pathPrefix="/V/" />
</intent-filter>
<!-- App Links for modern RESTful navigation paths -->
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="http" />
<data android:scheme="https" />
<data android:host="meshtastic.org" />
<data android:pathPrefix="/share" />
<data android:pathPrefix="/connections" />
<data android:pathPrefix="/map" />
<data android:pathPrefix="/messages" />
<data android:pathPrefix="/quickchat" />
<data android:pathPrefix="/nodes" />
<data android:pathPrefix="/settings" />
<data android:pathPrefix="/channels" />
<data android:pathPrefix="/firmware" />
</intent-filter>
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
</intent-filter>

View file

@ -211,14 +211,8 @@ class MainActivity : ComponentActivity() {
private fun handleMeshtasticUri(uri: Uri) {
Logger.d { "Handling Meshtastic URI: $uri" }
if (uri.toString().startsWith(DEEP_LINK_BASE_URI)) {
model.handleNavigationDeepLink(uri.toMeshtasticUri())
return
}
model.handleScannedUri(uri.toMeshtasticUri()) {
lifecycleScope.launch { showToast(Res.string.channel_invalid) }
}
model.handleDeepLink(uri.toMeshtasticUri()) { lifecycleScope.launch { showToast(Res.string.channel_invalid) } }
}
private fun createShareIntent(message: String): PendingIntent {

View file

@ -97,8 +97,17 @@ import org.meshtastic.feature.settings.radio.channel.channelsGraph
@Composable
fun MainScreen(uIViewModel: UIViewModel = koinViewModel(), scanModel: ScannerViewModel = koinViewModel()) {
val backStack = rememberNavBackStack(MeshtasticNavSavedStateConfig, NodesRoutes.NodesGraph as NavKey)
// LaunchedEffect(uIViewModel) { uIViewModel.navigationDeepLink.collectLatest { uri -> navController.navigate(uri) }
// }
LaunchedEffect(uIViewModel) {
uIViewModel.navigationDeepLink.collect { uri ->
val commonUri = org.meshtastic.core.common.util.CommonUri.parse(uri.uriString)
org.meshtastic.core.navigation.DeepLinkRouter.route(commonUri)?.let { navKeys ->
backStack.clear()
backStack.addAll(navKeys)
}
}
}
val connectionState by uIViewModel.connectionState.collectAsStateWithLifecycle()
val unreadMessageCount by uIViewModel.unreadMessageCount.collectAsStateWithLifecycle()
@ -239,6 +248,7 @@ fun MainScreen(uIViewModel: UIViewModel = koinViewModel(), scanModel: ScannerVie
nodesGraph(
backStack = backStack,
scrollToTopEvents = uIViewModel.scrollToTopEventFlow,
onHandleDeepLink = uIViewModel::handleDeepLink,
nodeMapScreen = { destNum, onNavigateUp ->
val vm =
org.koin.compose.viewmodel.koinViewModel<