11package com.microsoft.device.dualscreen.twopanelayout.twopanelayoutnav
22
33import android.annotation.SuppressLint
4+ import android.content.Context
5+ import android.os.Bundle
46import androidx.activity.compose.BackHandler
57import androidx.compose.runtime.Composable
68import androidx.compose.runtime.getValue
@@ -10,11 +12,15 @@ import androidx.compose.runtime.saveable.rememberSaveable
1012import androidx.compose.runtime.setValue
1113import androidx.compose.ui.Modifier
1214import androidx.compose.ui.layout.Layout
15+ import androidx.compose.ui.platform.LocalContext
16+ import androidx.core.net.toUri
1317import androidx.navigation.NavBackStackEntry
18+ import androidx.navigation.NavDeepLinkRequest
1419import androidx.navigation.NavDestination
1520import androidx.navigation.NavGraph
1621import androidx.navigation.NavHostController
1722import androidx.navigation.NavOptionsBuilder
23+ import androidx.navigation.compose.ComposeNavigator
1824import androidx.navigation.compose.NavHost
1925import com.microsoft.device.dualscreen.twopanelayout.Screen
2026import com.microsoft.device.dualscreen.twopanelayout.TwoPaneNavScope
@@ -32,27 +38,47 @@ internal var getPane1Destination: () -> String = { "" }
3238internal var getPane2Destination: () -> String = { " " }
3339internal var getSinglePaneDestination: () -> String = { " " }
3440internal val backStack = mutableListOf<TwoPaneBackStackEntry >()
35- internal val graphContent = mutableMapOf<String , @Composable TwoPaneNavScope .(NavBackStackEntry ) - > Unit > ()
41+ internal val graphDestinations =
42+ mutableMapOf<ComposeNavigator .Destination , @Composable TwoPaneNavScope .(NavBackStackEntry ) - > Unit > ()
3643
3744internal fun isSinglePaneHandler (): Boolean {
3845 return isSinglePane
3946}
4047
41- private fun verifyRoute (route : String ) {
42- if (! graphContent.keys.contains(route))
43- throw IllegalArgumentException (" Invalid route $route , not present in list of routes ${graphContent.keys} " )
48+ @SuppressLint(" RestrictedApi" )
49+ private fun getDeepLinkMatchForRoute (route : String ): NavDestination .DeepLinkMatch {
50+ val navDeepLinkRequest = NavDeepLinkRequest .Builder .fromUri(NavDestination .createRoute(route).toUri()).build()
51+ var match: NavDestination .DeepLinkMatch ? = null
52+
53+ graphDestinations.keys.firstOrNull {
54+ match = it.matchDeepLink(navDeepLinkRequest)
55+ match != null
56+ }
57+ ? : throw IllegalArgumentException (" Invalid route $route , not present in list of destinations ${graphDestinations.keys} " )
58+
59+ return match!! .apply { removePlaceholderArgs() }
4460}
4561
46- private fun findGraphContent (route : String ): @Composable TwoPaneNavScope .() -> Unit {
47- verifyRoute(route)
62+ @SuppressLint(" RestrictedApi" )
63+ private fun NavDestination.DeepLinkMatch.removePlaceholderArgs () {
64+ matchingArgs?.let {
65+ for (argName in it.keySet()) {
66+ if (it.getString(argName) == " {$argName }" )
67+ matchingArgs?.remove(argName)
68+ }
69+ }
70+ }
4871
49- val content = graphContent[route]!!
72+ @SuppressLint(" RestrictedApi" )
73+ private fun findGraphContent (route : String , context : Context ): @Composable TwoPaneNavScope .() -> Unit {
74+ val match = getDeepLinkMatchForRoute(route)
75+ val destination = match.destination
76+ val content = graphDestinations[destination]!!
77+ val args = destination.addInDefaultArgs(match.matchingArgs) ? : Bundle ()
5078
51- // REVISIT: passing in empty entry, may update in the future if arguments need to be passed through
52- @SuppressLint(" RestrictedApi" )
53- val emptyBackStackEntry = NavBackStackEntry .create(null , NavDestination (" " ))
79+ val backStackEntry = NavBackStackEntry .create(context, destination, args)
5480
55- return { content(emptyBackStackEntry ) }
81+ return { content(backStackEntry ) }
5682}
5783
5884@Composable
@@ -110,13 +136,13 @@ internal fun TwoPaneContainer(
110136 // Initialize navigation method handlers
111137 navigatePane1To = { route ->
112138 if (currentPane1 != route) {
113- verifyRoute (route)
139+ getDeepLinkMatchForRoute (route)
114140 currentPane1 = route
115141 }
116142 }
117143 navigatePane2To = { route ->
118144 if (currentPane2 != route) {
119- verifyRoute (route)
145+ getDeepLinkMatchForRoute (route)
120146 currentPane2 = route
121147 }
122148 }
@@ -126,8 +152,9 @@ internal fun TwoPaneContainer(
126152 backStack.initialize(pane1StartDestination, pane2StartDestination)
127153
128154 // Find the destinations to display in each pane
129- val pane1 = findGraphContent(currentPane1)
130- val pane2 = findGraphContent(currentPane2)
155+ val context = LocalContext .current
156+ val pane1 = findGraphContent(currentPane1, context)
157+ val pane2 = findGraphContent(currentPane2, context)
131158
132159 val measurePolicy = twoPaneMeasurePolicy(
133160 windowMode = windowState.windowMode,
0 commit comments