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

@ -20,10 +20,16 @@ import androidx.compose.runtime.Composable
import org.meshtastic.core.ui.viewmodel.UIViewModel
/**
* Encapsulates the headless, global UI components (dialogs, version checks, traceroute alerts) that need to be active
* across all platforms at the root of the application hierarchy.
* Common application-level setup for all Meshtastic platforms (Android, Desktop, etc.).
*
* This deduplicates the setup boilerplate from Android's MainScreen and DesktopMainScreen.
* This component encapsulates headless global UI logic that must reside at the root of the application hierarchy. It
* manages:
* - Shared system dialogs (e.g. contact/channel import)
* - Global version and firmware checks
* - System-wide alerts and snackbar hosts
* - Deep link navigation interception logic
*
* Platform hosts (Main.kt) should invoke this at the root of their theme before rendering the main NavDisplay.
*/
@Composable
fun MeshtasticCommonAppSetup(

View file

@ -87,18 +87,30 @@ class UIViewModel(
private val _navigationDeepLink = MutableSharedFlow<MeshtasticUri>(replay = 1)
val navigationDeepLink = _navigationDeepLink.asSharedFlow()
fun handleNavigationDeepLink(uri: MeshtasticUri) {
_navigationDeepLink.tryEmit(uri)
}
/**
* Unified handler for all Meshtastic deep links and OS intents.
*
* This method orchestrates two distinct types of URI handling:
* 1. **Navigation:** First attempts to parse the URI into a typed [NavKey] backstack via [DeepLinkRouter]. If
* successful, navigates the user to the target screen.
* 2. **Data Import:** If navigation fails, falls back to legacy contact/channel parsing via
* [dispatchMeshtasticUri]. This triggers import dialogs for shared nodes or channel configurations.
*/
fun handleDeepLink(uri: MeshtasticUri, onInvalid: () -> Unit = {}) {
val commonUri = org.meshtastic.core.common.util.CommonUri.parse(uri.uriString)
/** Unified handler for scanned Meshtastic URIs (contacts or channels). */
fun handleScannedUri(uri: MeshtasticUri, onInvalid: () -> Unit) {
org.meshtastic.core.common.util.CommonUri.parse(uri.uriString)
.dispatchMeshtasticUri(
onContact = { setSharedContactRequested(it) },
onChannel = { setRequestChannelSet(it) },
onInvalid = onInvalid,
)
// Try navigation routing first
if (org.meshtastic.core.navigation.DeepLinkRouter.route(commonUri) != null) {
_navigationDeepLink.tryEmit(uri)
return
}
// Fallback to channel/contact importing
commonUri.dispatchMeshtasticUri(
onContact = { setSharedContactRequested(it) },
onChannel = { setRequestChannelSet(it) },
onInvalid = onInvalid,
)
}
val theme: StateFlow<Int> = uiPrefs.theme