From e8e170ebcd8d8492ae9c42ee5adec7e3c5dcedbd Mon Sep 17 00:00:00 2001 From: Roman Pytkov Date: Sun, 10 Nov 2024 00:09:40 +0300 Subject: [PATCH] =?UTF-8?q?=D0=97=D0=B0=D0=BB=D0=BE=D0=B6=D0=B5=D0=BD?= =?UTF-8?q?=D0=B0=20=D0=BD=D0=B0=D0=B2=D0=B8=D0=B3=D0=B0=D1=86=D0=B8=D1=8F?= =?UTF-8?q?=20=D1=81=20=D0=BF=D0=B5=D1=80=D0=B5=D0=B4=D0=B0=D1=87=D0=B5?= =?UTF-8?q?=D0=B9=20=D0=BF=D0=B0=D1=80=D0=B0=D0=BC=D0=B5=D1=82=D1=80=D0=BE?= =?UTF-8?q?=D0=B2=20=D0=B8=20=D1=81=D0=BE=D1=85=D1=80=D0=B0=D0=BD=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=D0=BC=20=D1=81=D0=BE=D1=81=D1=82=D0=BE=D1=8F?= =?UTF-8?q?=D0=BD=D0=B8=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/AndroidManifest.xml | 1 + gradle/libs.versions.toml | 2 + presentation/build.gradle.kts | 2 + .../wallenc/presentation/WallencUi.kt | 83 +++++++++++++++++-- .../presentation/navigation/NavBarItem.kt | 5 ++ .../navigation/NavigationState.kt | 29 +++++++ .../presentation/screens/ScreenRoute.kt | 7 ++ .../presentation/screens/main/MainRoute.kt | 6 +- .../presentation/screens/main/MainScreen.kt | 7 +- .../screens/settings/SettingsRoute.kt | 6 +- 10 files changed, 137 insertions(+), 11 deletions(-) create mode 100644 presentation/src/main/java/com/github/nullptroma/wallenc/presentation/navigation/NavBarItem.kt create mode 100644 presentation/src/main/java/com/github/nullptroma/wallenc/presentation/navigation/NavigationState.kt create mode 100644 presentation/src/main/java/com/github/nullptroma/wallenc/presentation/screens/ScreenRoute.kt diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 423c093..bde8f25 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -12,6 +12,7 @@ android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/Theme.Wallenc" + android:enableOnBackInvokedCallback="true" tools:targetApi="31"> - NavHost(navController, startDestination = MainRoute()) { - composable { + 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(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 { + composable(enterTransition = { + fadeIn(tween(200)) + }, exitTransition = { + fadeOut(tween(200)) + }) { val route: SettingsRoute = it.toRoute() SettingsScreen(Modifier.padding(innerPaddings), route.text) } diff --git a/presentation/src/main/java/com/github/nullptroma/wallenc/presentation/navigation/NavBarItem.kt b/presentation/src/main/java/com/github/nullptroma/wallenc/presentation/navigation/NavBarItem.kt new file mode 100644 index 0000000..10592e0 --- /dev/null +++ b/presentation/src/main/java/com/github/nullptroma/wallenc/presentation/navigation/NavBarItem.kt @@ -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) diff --git a/presentation/src/main/java/com/github/nullptroma/wallenc/presentation/navigation/NavigationState.kt b/presentation/src/main/java/com/github/nullptroma/wallenc/presentation/navigation/NavigationState.kt new file mode 100644 index 0000000..4df0c42 --- /dev/null +++ b/presentation/src/main/java/com/github/nullptroma/wallenc/presentation/navigation/NavigationState.kt @@ -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) } +} \ No newline at end of file diff --git a/presentation/src/main/java/com/github/nullptroma/wallenc/presentation/screens/ScreenRoute.kt b/presentation/src/main/java/com/github/nullptroma/wallenc/presentation/screens/ScreenRoute.kt new file mode 100644 index 0000000..5db3b96 --- /dev/null +++ b/presentation/src/main/java/com/github/nullptroma/wallenc/presentation/screens/ScreenRoute.kt @@ -0,0 +1,7 @@ +package com.github.nullptroma.wallenc.presentation.screens + +import android.os.Parcelable +import kotlinx.serialization.Serializable + +@Serializable +abstract class ScreenRoute() : Parcelable \ No newline at end of file diff --git a/presentation/src/main/java/com/github/nullptroma/wallenc/presentation/screens/main/MainRoute.kt b/presentation/src/main/java/com/github/nullptroma/wallenc/presentation/screens/main/MainRoute.kt index 7a83314..994d79d 100644 --- a/presentation/src/main/java/com/github/nullptroma/wallenc/presentation/screens/main/MainRoute.kt +++ b/presentation/src/main/java/com/github/nullptroma/wallenc/presentation/screens/main/MainRoute.kt @@ -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 \ No newline at end of file +@Serializable +@Parcelize +class MainRoute: ScreenRoute() \ No newline at end of file diff --git a/presentation/src/main/java/com/github/nullptroma/wallenc/presentation/screens/main/MainScreen.kt b/presentation/src/main/java/com/github/nullptroma/wallenc/presentation/screens/main/MainScreen.kt index c5660f5..91fb003 100644 --- a/presentation/src/main/java/com/github/nullptroma/wallenc/presentation/screens/main/MainScreen.kt +++ b/presentation/src/main/java/com/github/nullptroma/wallenc/presentation/screens/main/MainScreen.kt @@ -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!") diff --git a/presentation/src/main/java/com/github/nullptroma/wallenc/presentation/screens/settings/SettingsRoute.kt b/presentation/src/main/java/com/github/nullptroma/wallenc/presentation/screens/settings/SettingsRoute.kt index 73995c4..2faaac9 100644 --- a/presentation/src/main/java/com/github/nullptroma/wallenc/presentation/screens/settings/SettingsRoute.kt +++ b/presentation/src/main/java/com/github/nullptroma/wallenc/presentation/screens/settings/SettingsRoute.kt @@ -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) \ No newline at end of file +@Serializable +@Parcelize +class SettingsRoute(val text: String): ScreenRoute()