kopia lustrzana https://github.com/meshtastic/Meshtastic-Android
feat: adaptive nav (#2079)
rodzic
606d1520d8
commit
95224c20ef
|
@ -183,6 +183,7 @@ dependencies {
|
|||
implementation(libs.bundles.androidx)
|
||||
implementation(libs.bundles.ui)
|
||||
debugImplementation(libs.bundles.ui.tooling)
|
||||
implementation(libs.bundles.adaptive)
|
||||
implementation(libs.bundles.lifecycle)
|
||||
implementation(libs.bundles.navigation)
|
||||
implementation(libs.bundles.coroutines)
|
||||
|
|
|
@ -37,15 +37,10 @@ import androidx.activity.result.contract.ActivityResultContracts
|
|||
import androidx.activity.viewModels
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.isSystemInDarkTheme
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.systemBarsPadding
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.SideEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalView
|
||||
import androidx.core.content.edit
|
||||
import androidx.core.net.toUri
|
||||
|
@ -157,16 +152,10 @@ class MainActivity : AppCompatActivity(), Logging {
|
|||
AppCompatDelegate.setDefaultNightMode(theme)
|
||||
}
|
||||
}
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.background(MaterialTheme.colorScheme.background)
|
||||
.systemBarsPadding()
|
||||
) {
|
||||
MainScreen(
|
||||
viewModel = model,
|
||||
onAction = ::onMainMenuAction
|
||||
)
|
||||
}
|
||||
MainScreen(
|
||||
viewModel = model,
|
||||
onAction = ::onMainMenuAction,
|
||||
)
|
||||
}
|
||||
}
|
||||
// Handle any intent
|
||||
|
|
|
@ -19,7 +19,8 @@ package com.geeksville.mesh.ui
|
|||
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.safeDrawingPadding
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
||||
|
@ -37,15 +38,15 @@ import androidx.compose.material3.ExperimentalMaterial3Api
|
|||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.NavigationBar
|
||||
import androidx.compose.material3.NavigationBarItem
|
||||
import androidx.compose.material3.PlainTooltip
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.SnackbarHost
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TooltipBox
|
||||
import androidx.compose.material3.TooltipDefaults
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo
|
||||
import androidx.compose.material3.adaptive.navigationsuite.NavigationSuiteScaffold
|
||||
import androidx.compose.material3.adaptive.navigationsuite.NavigationSuiteScaffoldDefaults
|
||||
import androidx.compose.material3.adaptive.navigationsuite.NavigationSuiteType
|
||||
import androidx.compose.material3.rememberTooltipState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
|
@ -63,11 +64,9 @@ import androidx.compose.ui.res.stringResource
|
|||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.navigation.NavController
|
||||
import androidx.navigation.NavDestination
|
||||
import androidx.navigation.NavDestination.Companion.hasRoute
|
||||
import androidx.navigation.NavDestination.Companion.hierarchy
|
||||
import androidx.navigation.NavGraph.Companion.findStartDestination
|
||||
import androidx.navigation.NavHostController
|
||||
import androidx.navigation.compose.currentBackStackEntryAsState
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
|
@ -106,12 +105,12 @@ enum class TopLevelDestination(@StringRes val label: Int, val icon: ImageVector,
|
|||
}
|
||||
}
|
||||
|
||||
@Suppress("LongMethod")
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Suppress("LongMethod", "CyclomaticComplexMethod")
|
||||
@Composable
|
||||
fun MainScreen(
|
||||
modifier: Modifier = Modifier,
|
||||
viewModel: UIViewModel = hiltViewModel(),
|
||||
onAction: (MainMenuAction) -> Unit
|
||||
onAction: (MainMenuAction) -> Unit,
|
||||
) {
|
||||
val navController = rememberNavController()
|
||||
val connectionState by viewModel.connectionState.collectAsStateWithLifecycle()
|
||||
|
@ -158,36 +157,84 @@ fun MainScreen(
|
|||
onDismiss = { viewModel.clearTracerouteResponse() }
|
||||
)
|
||||
}
|
||||
|
||||
Scaffold(
|
||||
modifier = modifier.safeDrawingPadding(),
|
||||
topBar = {
|
||||
val navSuiteType =
|
||||
NavigationSuiteScaffoldDefaults.navigationSuiteType(currentWindowAdaptiveInfo())
|
||||
val currentDestination = navController.currentBackStackEntryAsState().value?.destination
|
||||
val topLevelDestination = TopLevelDestination.fromNavDestination(currentDestination)
|
||||
NavigationSuiteScaffold(
|
||||
modifier = Modifier.safeDrawingPadding(),
|
||||
navigationSuiteItems = {
|
||||
TopLevelDestination.entries.forEach { destination ->
|
||||
val isSelected = destination == topLevelDestination
|
||||
val isConnectionsRoute = destination == TopLevelDestination.Connections
|
||||
item(
|
||||
icon = {
|
||||
TooltipBox(
|
||||
positionProvider = TooltipDefaults.rememberTooltipPositionProvider(),
|
||||
tooltip = {
|
||||
PlainTooltip {
|
||||
Text(
|
||||
if (isConnectionsRoute) {
|
||||
connectionState.getTooltipString()
|
||||
} else {
|
||||
stringResource(id = destination.label)
|
||||
},
|
||||
)
|
||||
}
|
||||
},
|
||||
state = rememberTooltipState()
|
||||
) {
|
||||
TopLevelNavIcon(destination, connectionState)
|
||||
}
|
||||
},
|
||||
selected = isSelected,
|
||||
label = {
|
||||
if (navSuiteType != NavigationSuiteType.ShortNavigationBarCompact) {
|
||||
Text(stringResource(id = destination.label))
|
||||
}
|
||||
},
|
||||
onClick = {
|
||||
navController.navigate(destination.route) {
|
||||
// Pop up to the start destination of the graph to
|
||||
// avoid building up a large stack of destinations
|
||||
// on the back stack as users select items
|
||||
// destination.route
|
||||
// popUpTo(navController.graph.findStartDestination().id) {
|
||||
// saveState = true
|
||||
// }
|
||||
// Avoid multiple copies of the same destination when
|
||||
// reselecting the same item
|
||||
launchSingleTop = true
|
||||
// Restore state when reselecting a previously selected item
|
||||
restoreState = true
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
) {
|
||||
MainAppBar(
|
||||
title = title,
|
||||
isManaged = localConfig.security.isManaged,
|
||||
navController = navController,
|
||||
) { action ->
|
||||
when (action) {
|
||||
MainMenuAction.DEBUG -> navController.navigate(Route.DebugPanel)
|
||||
MainMenuAction.RADIO_CONFIG -> navController.navigate(RadioConfigRoutes.RadioConfig())
|
||||
MainMenuAction.QUICK_CHAT -> navController.navigate(ContactsRoutes.QuickChat)
|
||||
else -> onAction(action)
|
||||
}
|
||||
}
|
||||
},
|
||||
bottomBar = {
|
||||
BottomNavigation(
|
||||
connectionState = connectionState,
|
||||
onAction = { action ->
|
||||
when (action) {
|
||||
MainMenuAction.DEBUG -> navController.navigate(Route.DebugPanel)
|
||||
MainMenuAction.RADIO_CONFIG -> navController.navigate(RadioConfigRoutes.RadioConfig())
|
||||
MainMenuAction.QUICK_CHAT -> navController.navigate(ContactsRoutes.QuickChat)
|
||||
else -> onAction(action)
|
||||
}
|
||||
},
|
||||
)
|
||||
NavGraph(
|
||||
uIViewModel = viewModel,
|
||||
navController = navController,
|
||||
)
|
||||
},
|
||||
snackbarHost = { SnackbarHost(hostState = viewModel.snackbarState) }
|
||||
) { innerPadding ->
|
||||
NavGraph(
|
||||
modifier = Modifier.padding(innerPadding),
|
||||
uIViewModel = viewModel,
|
||||
navController = navController,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -378,62 +425,6 @@ private fun MainMenuActions(
|
|||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
private fun BottomNavigation(
|
||||
connectionState: MeshService.ConnectionState,
|
||||
navController: NavController,
|
||||
) {
|
||||
val currentDestination = navController.currentBackStackEntryAsState().value?.destination
|
||||
val topLevelDestination = TopLevelDestination.fromNavDestination(currentDestination)
|
||||
|
||||
NavigationBar {
|
||||
TopLevelDestination.entries.forEach { destination ->
|
||||
val isSelected = destination == topLevelDestination
|
||||
val isConnectionsRoute = destination == TopLevelDestination.Connections
|
||||
NavigationBarItem(
|
||||
icon = {
|
||||
TooltipBox(
|
||||
positionProvider = TooltipDefaults.rememberTooltipPositionProvider(),
|
||||
tooltip = {
|
||||
PlainTooltip {
|
||||
Text(
|
||||
if (isConnectionsRoute) {
|
||||
connectionState.getTooltipString()
|
||||
} else {
|
||||
stringResource(id = destination.label)
|
||||
},
|
||||
)
|
||||
}
|
||||
},
|
||||
state = rememberTooltipState()
|
||||
) {
|
||||
TopLevelNavIcon(destination, connectionState)
|
||||
}
|
||||
},
|
||||
selected = isSelected,
|
||||
onClick = {
|
||||
if (!isSelected) {
|
||||
navController.navigate(destination.route) {
|
||||
// Pop up to the start destination of the graph to
|
||||
// avoid building up a large stack of destinations
|
||||
// on the back stack as users select items
|
||||
popUpTo(navController.graph.findStartDestination().id) {
|
||||
saveState = true
|
||||
}
|
||||
// Avoid multiple copies of the same destination when
|
||||
// reselecting the same item
|
||||
launchSingleTop = true
|
||||
// Restore state when reselecting a previously selected item
|
||||
restoreState = true
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun MeshService.ConnectionState.getConnectionColor(): Color {
|
||||
return when (this) {
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
[versions]
|
||||
adaptive = "1.2.0-alpha06"
|
||||
adaptive-navigation-suite = "1.3.2"
|
||||
agp = "8.10.1"
|
||||
appcompat = "1.7.1"
|
||||
appintro = "6.3.1"
|
||||
|
@ -53,6 +55,11 @@ agp = { group = "com.android.tools.build", name = "gradle", version.ref = "agp"
|
|||
activity = { group = "androidx.activity", name = "activity" }
|
||||
actvity-ktx = { group = "androidx.activity", name = "activity-ktx" }
|
||||
activity-compose = { group = "androidx.activity", name = "activity-compose" }
|
||||
adaptive = { group = "androidx.compose.material3.adaptive", name = "adaptive", version.ref = "adaptive" }
|
||||
adaptive-layout = { group = "androidx.compose.material3.adaptive", name = "adaptive-layout", version.ref = "adaptive" }
|
||||
adaptive-navigation = { group = "androidx.compose.material3.adaptive", name = "adaptive-navigation", version.ref = "adaptive" }
|
||||
adaptive-navigation-android = { group = "androidx.compose.material3.adaptive", name = "adaptive-navigation-android", version.ref = "adaptive" }
|
||||
adaptive-navigation-suite = { group = "androidx.compose.material3", name = "material3-adaptive-navigation-suite", version.ref = "adaptive-navigation-suite" }
|
||||
appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
|
||||
appcompat-resources = { group = "androidx.appcompat", name = "appcompat-resources", version.ref = "appcompat" }
|
||||
appintro = { group = "com.github.AppIntro", name = "AppIntro", version.ref = "appintro" }
|
||||
|
@ -139,6 +146,7 @@ androidx = ["core-ktx", "appcompat", "appcompat-resources", "cardview", "fragmen
|
|||
|
||||
# UI
|
||||
ui = ["material", "constraintlayout", "viewpager2", "compose-material3", "compose-material-icons-extended", "compose-ui-tooling-preview", "compose-runtime-livedata"]
|
||||
adaptive = ["adaptive", "adaptive-layout", "adaptive-navigation", "adaptive-navigation-android", "adaptive-navigation-suite"]
|
||||
ui-tooling = ["compose-ui-tooling"] #Separate for debugImplementation
|
||||
|
||||
# Lifecycle
|
||||
|
|
Ładowanie…
Reference in New Issue