mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-03-28 02:32:24 -04:00
feat(ui): implement adaptive extra pane strategy for navigation
This commit enhances the navigation system to support adaptive layouts by integrating `SupportingPaneSceneStrategy` and marking specific routes to utilize the "extra pane" in list-detail scenarios. Specific changes include: - **Navigation Infrastructure**: Added `supportingPaneSceneStrategy` to `MeshtasticNavDisplay` and updated documentation to reflect support for `extraPane()` and supporting pane layouts. - **Node Feature**: Updated `NodeMap`, `TracerouteLog`, `TracerouteMap`, and generic node detail screens in `NodesNavigation.kt` to use `ListDetailSceneStrategy.extraPane()`. - **Messaging Feature**: Updated `Share` and `QuickChat` routes in `ContactsNavigation.kt` to use `ListDetailSceneStrategy.extraPane()`. - **API Integration**: Applied `ExperimentalMaterial3AdaptiveApi` where necessary to support the new adaptive navigation strategies. Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com>
This commit is contained in:
@@ -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<NavKey>()
|
||||
val supportingPaneSceneStrategy = rememberSupportingPaneSceneStrategy<NavKey>()
|
||||
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,
|
||||
|
||||
@@ -68,7 +68,7 @@ fun EntryProviderScope<NavKey>.contactsGraph(
|
||||
)
|
||||
}
|
||||
|
||||
entry<ContactsRoutes.Share> { args ->
|
||||
entry<ContactsRoutes.Share>(metadata = { ListDetailSceneStrategy.extraPane() }) { args ->
|
||||
val message = args.message
|
||||
val viewModel = koinViewModel<ContactsViewModel>()
|
||||
ShareScreen(
|
||||
@@ -80,7 +80,7 @@ fun EntryProviderScope<NavKey>.contactsGraph(
|
||||
)
|
||||
}
|
||||
|
||||
entry<ContactsRoutes.QuickChat> {
|
||||
entry<ContactsRoutes.QuickChat>(metadata = { ListDetailSceneStrategy.extraPane() }) {
|
||||
val viewModel = koinViewModel<QuickChatViewModel>()
|
||||
QuickChatScreen(viewModel = viewModel, onNavigateUp = { backStack.removeLastOrNull() })
|
||||
}
|
||||
|
||||
@@ -123,12 +123,12 @@ fun EntryProviderScope<NavKey>.nodeDetailGraph(
|
||||
)
|
||||
}
|
||||
|
||||
entry<NodeDetailRoutes.NodeMap> { args ->
|
||||
entry<NodeDetailRoutes.NodeMap>(metadata = { ListDetailSceneStrategy.extraPane() }) { args ->
|
||||
val mapScreen = org.meshtastic.core.ui.util.LocalNodeMapScreenProvider.current
|
||||
mapScreen(args.destNum) { backStack.removeLastOrNull() }
|
||||
}
|
||||
|
||||
entry<NodeDetailRoutes.TracerouteLog> { args ->
|
||||
entry<NodeDetailRoutes.TracerouteLog>(metadata = { ListDetailSceneStrategy.extraPane() }) { args ->
|
||||
val metricsViewModel =
|
||||
koinViewModel<MetricsViewModel>(key = "metrics-${args.destNum}") { parametersOf(args.destNum) }
|
||||
metricsViewModel.setNodeId(args.destNum)
|
||||
@@ -148,7 +148,7 @@ fun EntryProviderScope<NavKey>.nodeDetailGraph(
|
||||
)
|
||||
}
|
||||
|
||||
entry<NodeDetailRoutes.TracerouteMap> { args ->
|
||||
entry<NodeDetailRoutes.TracerouteMap>(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<NavKey>.nodeDetailGraph(
|
||||
|
||||
fun NavKey.isNodeDetailRoute(): Boolean = NodeDetailRoute.entries.any { this::class == it.routeClass }
|
||||
|
||||
@OptIn(ExperimentalMaterial3AdaptiveApi::class)
|
||||
private inline fun <reified R : Route> EntryProviderScope<NavKey>.addNodeDetailScreenComposable(
|
||||
backStack: NavBackStack<NavKey>,
|
||||
routeInfo: NodeDetailRoute,
|
||||
crossinline getDestNum: (R) -> Int,
|
||||
) {
|
||||
entry<R> { args ->
|
||||
entry<R>(metadata = { ListDetailSceneStrategy.extraPane() }) { args ->
|
||||
val destNum = getDestNum(args)
|
||||
val metricsViewModel = koinViewModel<MetricsViewModel>(key = "metrics-$destNum") { parametersOf(destNum) }
|
||||
metricsViewModel.setNodeId(destNum)
|
||||
|
||||
Reference in New Issue
Block a user