diff --git a/core/ui/src/commonMain/kotlin/org/meshtastic/core/ui/component/MeshtasticNavDisplay.kt b/core/ui/src/commonMain/kotlin/org/meshtastic/core/ui/component/MeshtasticNavDisplay.kt index 96d5aa472..0a1a4155d 100644 --- a/core/ui/src/commonMain/kotlin/org/meshtastic/core/ui/component/MeshtasticNavDisplay.kt +++ b/core/ui/src/commonMain/kotlin/org/meshtastic/core/ui/component/MeshtasticNavDisplay.kt @@ -23,6 +23,7 @@ import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi import androidx.compose.material3.adaptive.navigation3.rememberListDetailSceneStrategy +import androidx.compose.material3.adaptive.navigation3.rememberSupportingPaneSceneStrategy import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.lifecycle.viewmodel.navigation3.rememberViewModelStoreNavEntryDecorator @@ -54,8 +55,10 @@ private const val TRANSITION_DURATION_MS = 350 * **Scene strategies** (evaluated in order): * - [DialogSceneStrategy] — entries annotated with `metadata = DialogSceneStrategy.dialog()` render as overlay * [Dialog][androidx.compose.ui.window.Dialog] windows with proper backstack lifecycle. - * - [ListDetailSceneStrategy] — entries annotated with `listPane()` / `detailPane()` render in adaptive list-detail + * - [androidx.compose.material3.adaptive.navigation3.ListDetailSceneStrategy] — entries annotated with `listPane()`, `detailPane()`, or `extraPane()` render in adaptive list-detail * layout on wider screens. + * - [androidx.compose.material3.adaptive.navigation3.SupportingPaneSceneStrategy] — entries annotated with `mainPane()`, `supportingPane()`, or `extraPane()` render in adaptive + * supporting pane layout. * - [SinglePaneSceneStrategy] — default single-pane fallback. * * **Transitions**: A uniform 350 ms crossfade for both forward and pop navigation. @@ -72,12 +75,18 @@ fun MeshtasticNavDisplay( modifier: Modifier = Modifier, ) { val listDetailSceneStrategy = rememberListDetailSceneStrategy() + val supportingPaneSceneStrategy = rememberSupportingPaneSceneStrategy() NavDisplay( backStack = backStack, entryProvider = entryProvider, entryDecorators = listOf(rememberSaveableStateHolderNavEntryDecorator(), rememberViewModelStoreNavEntryDecorator()), - sceneStrategies = listOf(DialogSceneStrategy(), listDetailSceneStrategy, SinglePaneSceneStrategy()), + sceneStrategies = listOf( + DialogSceneStrategy(), + listDetailSceneStrategy, + supportingPaneSceneStrategy, + SinglePaneSceneStrategy() + ), transitionSpec = meshtasticTransitionSpec(), popTransitionSpec = meshtasticTransitionSpec(), modifier = modifier, diff --git a/feature/messaging/src/commonMain/kotlin/org/meshtastic/feature/messaging/navigation/ContactsNavigation.kt b/feature/messaging/src/commonMain/kotlin/org/meshtastic/feature/messaging/navigation/ContactsNavigation.kt index 4db201db7..6a42af857 100644 --- a/feature/messaging/src/commonMain/kotlin/org/meshtastic/feature/messaging/navigation/ContactsNavigation.kt +++ b/feature/messaging/src/commonMain/kotlin/org/meshtastic/feature/messaging/navigation/ContactsNavigation.kt @@ -68,7 +68,7 @@ fun EntryProviderScope.contactsGraph( ) } - entry { args -> + entry(metadata = { ListDetailSceneStrategy.extraPane() }) { args -> val message = args.message val viewModel = koinViewModel() ShareScreen( @@ -80,7 +80,7 @@ fun EntryProviderScope.contactsGraph( ) } - entry { + entry(metadata = { ListDetailSceneStrategy.extraPane() }) { val viewModel = koinViewModel() QuickChatScreen(viewModel = viewModel, onNavigateUp = { backStack.removeLastOrNull() }) } diff --git a/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/navigation/NodesNavigation.kt b/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/navigation/NodesNavigation.kt index d68f064a8..eb3018865 100644 --- a/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/navigation/NodesNavigation.kt +++ b/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/navigation/NodesNavigation.kt @@ -123,12 +123,12 @@ fun EntryProviderScope.nodeDetailGraph( ) } - entry { args -> + entry(metadata = { ListDetailSceneStrategy.extraPane() }) { args -> val mapScreen = org.meshtastic.core.ui.util.LocalNodeMapScreenProvider.current mapScreen(args.destNum) { backStack.removeLastOrNull() } } - entry { args -> + entry(metadata = { ListDetailSceneStrategy.extraPane() }) { args -> val metricsViewModel = koinViewModel(key = "metrics-${args.destNum}") { parametersOf(args.destNum) } metricsViewModel.setNodeId(args.destNum) @@ -148,7 +148,7 @@ fun EntryProviderScope.nodeDetailGraph( ) } - entry { args -> + entry(metadata = { ListDetailSceneStrategy.extraPane() }) { args -> val tracerouteMapScreen = org.meshtastic.core.ui.util.LocalTracerouteMapScreenProvider.current tracerouteMapScreen(args.destNum, args.requestId, args.logUuid) { backStack.removeLastOrNull() } } @@ -178,12 +178,13 @@ fun EntryProviderScope.nodeDetailGraph( fun NavKey.isNodeDetailRoute(): Boolean = NodeDetailRoute.entries.any { this::class == it.routeClass } +@OptIn(ExperimentalMaterial3AdaptiveApi::class) private inline fun EntryProviderScope.addNodeDetailScreenComposable( backStack: NavBackStack, routeInfo: NodeDetailRoute, crossinline getDestNum: (R) -> Int, ) { - entry { args -> + entry(metadata = { ListDetailSceneStrategy.extraPane() }) { args -> val destNum = getDestNum(args) val metricsViewModel = koinViewModel(key = "metrics-$destNum") { parametersOf(destNum) } metricsViewModel.setNodeId(destNum)