Обновлена навигация
This commit is contained in:
@@ -3,6 +3,7 @@ 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.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.rounded.Menu
|
||||
@@ -19,14 +20,18 @@ import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.navigation.compose.NavHost
|
||||
import androidx.navigation.compose.composable
|
||||
import androidx.navigation.compose.currentBackStackEntryAsState
|
||||
import androidx.navigation.toRoute
|
||||
import com.github.nullptroma.wallenc.presentation.navigation.NavBarItem
|
||||
import com.github.nullptroma.wallenc.presentation.navigation.NavBarItemData
|
||||
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.main.screens.local.vault.LocalVaultRoute
|
||||
import com.github.nullptroma.wallenc.presentation.screens.main.screens.remotes.RemoteVaultsRoute
|
||||
import com.github.nullptroma.wallenc.presentation.screens.settings.SettingsRoute
|
||||
import com.github.nullptroma.wallenc.presentation.screens.settings.SettingsScreen
|
||||
import com.github.nullptroma.wallenc.presentation.theme.WallencTheme
|
||||
@@ -46,59 +51,75 @@ fun WallencUi() {
|
||||
fun WallencNavRoot() {
|
||||
val navState = rememberNavigationState()
|
||||
|
||||
val topLevelScreenRoutes = rememberSaveable {
|
||||
val mainNavState = rememberNavigationState()
|
||||
val mainScreenRoutes = rememberSaveable {
|
||||
mutableMapOf(
|
||||
LocalVaultRoute::class.qualifiedName!! to LocalVaultRoute(),
|
||||
RemoteVaultsRoute::class.qualifiedName!! to RemoteVaultsRoute()
|
||||
)
|
||||
}
|
||||
|
||||
val topLevelRoutes = 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)
|
||||
mapOf(
|
||||
MainRoute::class.qualifiedName!! to NavBarItemData(
|
||||
R.string.nav_label_main, MainRoute::class.qualifiedName!!, Icons.Rounded.Menu
|
||||
),
|
||||
SettingsRoute::class.qualifiedName!! to NavBarItemData(
|
||||
R.string.nav_label_settings,
|
||||
SettingsRoute::class.qualifiedName!!,
|
||||
Icons.Rounded.Settings
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
Scaffold(
|
||||
bottomBar = {
|
||||
NavigationBar {
|
||||
|
||||
Scaffold(bottomBar = {
|
||||
NavigationBar(modifier = Modifier.height(64.dp)) {
|
||||
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
|
||||
val routeClassName = it.key
|
||||
val navBarItemData = it.value
|
||||
NavigationBarItem(icon = {
|
||||
if (navBarItemData.icon != null) Icon(
|
||||
navBarItemData.icon,
|
||||
contentDescription = stringResource(navBarItemData.nameStringResourceId)
|
||||
)
|
||||
},
|
||||
label = { Text(it.name) },
|
||||
label = { Text(stringResource(navBarItemData.nameStringResourceId)) },
|
||||
selected = currentRoute?.startsWith(routeClassName) == true,
|
||||
onClick = {
|
||||
var route = topLevelScreenRoutes[it.screenRouteClass]
|
||||
var route = topLevelRoutes[navBarItemData.screenRouteClass]
|
||||
if (route == null)
|
||||
throw NoSuchElementException("Screen route of type ${it.screenRouteClass} no found")
|
||||
if(currentRoute?.startsWith(routeClassName) != true)
|
||||
navState.navigationTo(route)
|
||||
}
|
||||
throw NullPointerException("Route $route not found")
|
||||
if (currentRoute?.startsWith(routeClassName) != true) navState.navigationTo(
|
||||
route
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
}) { innerPaddings ->
|
||||
NavHost(navState.navHostController, startDestination = topLevelScreenRoutes[MainRoute::class.qualifiedName]!!) {
|
||||
NavHost(
|
||||
navState.navHostController,
|
||||
startDestination = topLevelRoutes[MainRoute::class.qualifiedName]!!
|
||||
) {
|
||||
composable<MainRoute>(enterTransition = {
|
||||
fadeIn(tween(200))
|
||||
}, exitTransition = {
|
||||
fadeOut(tween(200))
|
||||
}) {
|
||||
MainScreen(Modifier.padding(innerPaddings), onSettingsRoute = { settingsRoute ->
|
||||
topLevelScreenRoutes[settingsRoute::class.qualifiedName!!] = settingsRoute
|
||||
navState.navigationTo(settingsRoute)
|
||||
})
|
||||
MainScreen(
|
||||
modifier = Modifier.padding(innerPaddings),
|
||||
navState = mainNavState,
|
||||
routes = mainScreenRoutes
|
||||
)
|
||||
}
|
||||
composable<SettingsRoute>(enterTransition = {
|
||||
fadeIn(tween(200))
|
||||
|
||||
@@ -2,4 +2,4 @@ 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)
|
||||
data class NavBarItemData(val nameStringResourceId: Int, val screenRouteClass: String, val icon: ImageVector?)
|
||||
@@ -6,4 +6,4 @@ import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
@Parcelize
|
||||
class MainRoute: ScreenRoute()
|
||||
open class MainRoute: ScreenRoute()
|
||||
@@ -1,39 +1,108 @@
|
||||
package com.github.nullptroma.wallenc.presentation.screens.main
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.imePadding
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.NavigationBar
|
||||
import androidx.compose.material3.NavigationBarItem
|
||||
import androidx.compose.material3.Scaffold
|
||||
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.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import com.github.nullptroma.wallenc.presentation.screens.settings.SettingsRoute
|
||||
import androidx.navigation.compose.NavHost
|
||||
import androidx.navigation.compose.composable
|
||||
import androidx.navigation.compose.currentBackStackEntryAsState
|
||||
import com.github.nullptroma.wallenc.presentation.R
|
||||
import com.github.nullptroma.wallenc.presentation.navigation.NavBarItemData
|
||||
import com.github.nullptroma.wallenc.presentation.navigation.NavigationState
|
||||
import com.github.nullptroma.wallenc.presentation.navigation.rememberNavigationState
|
||||
import com.github.nullptroma.wallenc.presentation.screens.main.screens.local.vault.LocalVaultRoute
|
||||
import com.github.nullptroma.wallenc.presentation.screens.main.screens.local.vault.LocalVaultScreen
|
||||
import com.github.nullptroma.wallenc.presentation.screens.main.screens.remotes.RemoteVaultsRoute
|
||||
import com.github.nullptroma.wallenc.presentation.screens.main.screens.remotes.RemoteVaultsScreen
|
||||
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@androidx.compose.runtime.Composable
|
||||
fun MainScreen(modifier: Modifier = Modifier,
|
||||
fun MainScreen(
|
||||
modifier: Modifier = Modifier,
|
||||
viewModel: MainViewModel = hiltViewModel(),
|
||||
onSettingsRoute: (SettingsRoute) -> Unit) {
|
||||
val state = viewModel.stateFlow
|
||||
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
|
||||
navState: NavigationState = rememberNavigationState(),
|
||||
routes: MutableMap<String, MainRoute> = rememberSaveable {
|
||||
mutableMapOf(
|
||||
LocalVaultRoute::class.qualifiedName!! to LocalVaultRoute(),
|
||||
RemoteVaultsRoute::class.qualifiedName!! to RemoteVaultsRoute()
|
||||
)
|
||||
}
|
||||
) {
|
||||
val topLevelNavBarItems = remember {
|
||||
mapOf(
|
||||
LocalVaultRoute::class.qualifiedName!! to NavBarItemData(
|
||||
R.string.nav_label_local_vault, LocalVaultRoute::class.qualifiedName!!, null
|
||||
),
|
||||
RemoteVaultsRoute::class.qualifiedName!! to NavBarItemData(
|
||||
R.string.nav_label_remote_vaults, RemoteVaultsRoute::class.qualifiedName!!, null
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
Scaffold(modifier = modifier, contentWindowInsets = WindowInsets(0.dp), bottomBar = {
|
||||
Column {
|
||||
NavigationBar(modifier = Modifier.height(48.dp)) {
|
||||
val navBackStackEntry by navState.navHostController.currentBackStackEntryAsState()
|
||||
val currentRoute = navBackStackEntry?.destination?.route
|
||||
topLevelNavBarItems.forEach {
|
||||
val routeClassName = it.key
|
||||
val navBarItemData = it.value
|
||||
NavigationBarItem(modifier = Modifier
|
||||
.weight(1f)
|
||||
.fillMaxHeight(),
|
||||
icon = { Text(stringResource(navBarItemData.nameStringResourceId)) },
|
||||
selected = currentRoute?.startsWith(routeClassName) == true,
|
||||
onClick = {
|
||||
var route = routes[navBarItemData.screenRouteClass]
|
||||
if (route == null)
|
||||
throw NullPointerException("Route $route not found")
|
||||
if (currentRoute?.startsWith(routeClassName) != true) navState.navigationTo(
|
||||
route
|
||||
)
|
||||
})
|
||||
Button( onClick = {
|
||||
focusManager.clearFocus()
|
||||
onSettingsRoute(SettingsRoute(text))
|
||||
}
|
||||
}
|
||||
HorizontalDivider()
|
||||
}
|
||||
}) { innerPaddings ->
|
||||
|
||||
NavHost(
|
||||
navState.navHostController,
|
||||
startDestination = routes[LocalVaultRoute::class.qualifiedName]!!
|
||||
) {
|
||||
composable<LocalVaultRoute>(enterTransition = {
|
||||
fadeIn(tween(200))
|
||||
}, exitTransition = {
|
||||
fadeOut(tween(200))
|
||||
}) {
|
||||
Text("Press Me!")
|
||||
LocalVaultScreen(modifier = Modifier.padding(innerPaddings))
|
||||
}
|
||||
composable<RemoteVaultsRoute>(enterTransition = {
|
||||
fadeIn(tween(200))
|
||||
}, exitTransition = {
|
||||
fadeOut(tween(200))
|
||||
}) {
|
||||
RemoteVaultsScreen(modifier = Modifier.padding(innerPaddings))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,9 @@
|
||||
package com.github.nullptroma.wallenc.presentation.screens.main
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.github.nullptroma.wallenc.domain.usecases.TestUseCase
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
|
||||
@HiltViewModel
|
||||
class MainViewModel @javax.inject.Inject constructor(
|
||||
testUseCase: TestUseCase,
|
||||
testUseCase2: TestUseCase,
|
||||
testUseCase3: TestUseCase,
|
||||
): ViewModel() {
|
||||
val stateFlow = MainScreenState("${testUseCase3.meta.name}, number ${testUseCase3.id}")
|
||||
class MainViewModel @javax.inject.Inject constructor(): ViewModel() {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.github.nullptroma.wallenc.presentation.screens.main.screens.local.vault
|
||||
|
||||
import com.github.nullptroma.wallenc.presentation.screens.main.MainRoute
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
@Parcelize
|
||||
class LocalVaultRoute: MainRoute()
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.github.nullptroma.wallenc.presentation.screens.main.screens.local.vault
|
||||
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun LocalVaultScreen(modifier: Modifier = Modifier,
|
||||
viewModel: LocalVaultViewModel = hiltViewModel()) {
|
||||
Text("Local vault screen")
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
package com.github.nullptroma.wallenc.presentation.screens.main.screens.local.vault
|
||||
|
||||
data class LocalVaultScreenState(val value: String)
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.github.nullptroma.wallenc.presentation.screens.main.screens.local.vault
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class LocalVaultViewModel @Inject constructor(): ViewModel() {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.github.nullptroma.wallenc.presentation.screens.main.screens.remotes
|
||||
|
||||
import com.github.nullptroma.wallenc.presentation.screens.main.MainRoute
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
@Parcelize
|
||||
class RemoteVaultsRoute: MainRoute()
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.github.nullptroma.wallenc.presentation.screens.main.screens.remotes
|
||||
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun RemoteVaultsScreen(modifier: Modifier = Modifier,
|
||||
viewModel: RemoteVaultsViewModel = hiltViewModel()) {
|
||||
Text("Remote vault screen")
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
package com.github.nullptroma.wallenc.presentation.screens.main.screens.remotes
|
||||
|
||||
data class RemoteVaultsScreenState(val value: String)
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.github.nullptroma.wallenc.presentation.screens.main.screens.remotes
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class RemoteVaultsViewModel @Inject constructor(): ViewModel() {
|
||||
|
||||
}
|
||||
@@ -1,4 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="nav_label_local_vault">Local</string>
|
||||
<string name="nav_label_remote_vaults">Remotes</string>
|
||||
<string name="nav_label_main">Main</string>
|
||||
<string name="nav_label_settings">Settings</string>
|
||||
|
||||
<string name="settings_title">Settings Screen Title!</string>
|
||||
</resources>
|
||||
Reference in New Issue
Block a user