Заложена навигация с передачей параметров и сохранением состояний

This commit is contained in:
Roman Pytkov
2024-11-10 00:09:40 +03:00
parent 7a9aee46a6
commit e8e170ebcd
10 changed files with 137 additions and 11 deletions

View File

@@ -1,14 +1,30 @@
package com.github.nullptroma.wallenc.presentation
import androidx.compose.animation.core.tween
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.Menu
import androidx.compose.material.icons.rounded.Settings
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.NavigationBar
import androidx.compose.material3.NavigationBarItem
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Modifier
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.toRoute
import com.github.nullptroma.wallenc.presentation.navigation.NavBarItem
import com.github.nullptroma.wallenc.presentation.navigation.rememberNavigationState
import com.github.nullptroma.wallenc.presentation.screens.main.MainRoute
import com.github.nullptroma.wallenc.presentation.screens.main.MainScreen
import com.github.nullptroma.wallenc.presentation.screens.settings.SettingsRoute
@@ -25,17 +41,70 @@ fun WallencUi() {
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun WallencNavRoot() {
val navController = rememberNavController()
Scaffold { innerPaddings ->
NavHost(navController, startDestination = MainRoute()) {
composable<MainRoute> {
val navState = rememberNavigationState()
val topLevelScreenRoutes = rememberSaveable {
mutableMapOf(
MainRoute::class.qualifiedName!! to MainRoute(),
SettingsRoute::class.qualifiedName!! to SettingsRoute("Base settings")
)
}
// Все пункты меню верхнего уровня
val topLevelNavBarItems = remember {
listOf(
NavBarItem("Main", MainRoute::class.qualifiedName!!, Icons.Rounded.Menu),
NavBarItem("Settings", SettingsRoute::class.qualifiedName!!, Icons.Rounded.Settings)
)
}
Scaffold(
bottomBar = {
NavigationBar {
val navBackStackEntry by navState.navHostController.currentBackStackEntryAsState()
val currentRoute = navBackStackEntry?.destination?.route
topLevelNavBarItems.forEach {
val routeClassName = it.screenRouteClass
NavigationBarItem(
icon = {
Icon(
it.icon,
contentDescription = it.name
)
},
label = { Text(it.name) },
selected = currentRoute?.startsWith(routeClassName) == true,
onClick = {
var route = topLevelScreenRoutes[it.screenRouteClass]
if(route == null)
throw NoSuchElementException("Screen route of type ${it.screenRouteClass} no found")
if(currentRoute?.startsWith(routeClassName) != true)
navState.navigationTo(route)
}
)
}
}
}) { innerPaddings ->
NavHost(navState.navHostController, startDestination = topLevelScreenRoutes[MainRoute::class.qualifiedName]!!) {
composable<MainRoute>(enterTransition = {
fadeIn(tween(200))
}, exitTransition = {
fadeOut(tween(200))
}) {
MainScreen(Modifier.padding(innerPaddings), onSettingsRoute = { settingsRoute ->
navController.navigate(settingsRoute)
topLevelScreenRoutes[settingsRoute::class.qualifiedName!!] = settingsRoute
navState.navigationTo(settingsRoute)
})
}
composable<SettingsRoute> {
composable<SettingsRoute>(enterTransition = {
fadeIn(tween(200))
}, exitTransition = {
fadeOut(tween(200))
}) {
val route: SettingsRoute = it.toRoute()
SettingsScreen(Modifier.padding(innerPaddings), route.text)
}

View File

@@ -0,0 +1,5 @@
package com.github.nullptroma.wallenc.presentation.navigation
import androidx.compose.ui.graphics.vector.ImageVector
data class NavBarItem(val name: String, val screenRouteClass: String, val icon: ImageVector)

View File

@@ -0,0 +1,29 @@
package com.github.nullptroma.wallenc.presentation.navigation
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.navigation.NavGraph.Companion.findStartDestination
import androidx.navigation.NavHostController
import androidx.navigation.compose.rememberNavController
import com.github.nullptroma.wallenc.presentation.screens.ScreenRoute
class NavigationState(
val navHostController: NavHostController
) {
fun navigationTo(route: ScreenRoute) {
navHostController.navigate(route) {
popUpTo(navHostController.graph.findStartDestination().id)
launchSingleTop = true
restoreState = true
}
}
}
@Composable
fun rememberNavigationState(
navHostController: NavHostController? = null
): NavigationState {
val controller = navHostController ?: rememberNavController()
return remember { NavigationState(controller) }
}

View File

@@ -0,0 +1,7 @@
package com.github.nullptroma.wallenc.presentation.screens
import android.os.Parcelable
import kotlinx.serialization.Serializable
@Serializable
abstract class ScreenRoute() : Parcelable

View File

@@ -1,5 +1,9 @@
package com.github.nullptroma.wallenc.presentation.screens.main
import com.github.nullptroma.wallenc.presentation.screens.ScreenRoute
import kotlinx.parcelize.Parcelize
import kotlinx.serialization.Serializable
@Serializable class MainRoute
@Serializable
@Parcelize
class MainRoute: ScreenRoute()

View File

@@ -9,10 +9,11 @@ import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalFocusManager
import androidx.hilt.navigation.compose.hiltViewModel
import com.github.nullptroma.wallenc.presentation.screens.settings.SettingsRoute
@@ -22,12 +23,14 @@ fun MainScreen(modifier: Modifier = Modifier,
viewModel: MainViewModel = hiltViewModel(),
onSettingsRoute: (SettingsRoute) -> Unit) {
val state = viewModel.stateFlow
var text by remember { mutableStateOf("") }
var text by rememberSaveable { mutableStateOf("") }
val focusManager = LocalFocusManager.current
Column(modifier = modifier.imePadding().fillMaxSize(), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center) {
TextField(text, onValueChange = { s ->
text = s
})
Button( onClick = {
focusManager.clearFocus()
onSettingsRoute(SettingsRoute(text))
}) {
Text("Press Me!")

View File

@@ -1,5 +1,9 @@
package com.github.nullptroma.wallenc.presentation.screens.settings
import com.github.nullptroma.wallenc.presentation.screens.ScreenRoute
import kotlinx.parcelize.Parcelize
import kotlinx.serialization.Serializable
@Serializable class SettingsRoute(val text: String)
@Serializable
@Parcelize
class SettingsRoute(val text: String): ScreenRoute()