Settings tab in navigation drawer

This commit is contained in:
Sad Ellie 2023-02-26 14:13:02 +04:00
parent df44a33415
commit 9d665823ba
11 changed files with 122 additions and 39 deletions

View File

@ -21,6 +21,7 @@ package com.sadellie.unitto
import androidx.compose.animation.core.tween
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Calculate
import androidx.compose.material.icons.filled.Settings
import androidx.compose.material.icons.filled.SwapHoriz
import androidx.compose.material3.DrawerValue
import androidx.compose.material3.MaterialTheme
@ -35,6 +36,7 @@ import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.navigation.NavDestination.Companion.hierarchy
import androidx.navigation.NavGraph.Companion.findStartDestination
import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController
@ -76,9 +78,29 @@ internal fun UnittoApp() {
TopLevelDestinations.Calculator to Icons.Default.Calculate,
TopLevelDestinations.Converter to Icons.Default.SwapHoriz
)
val additionalTabs = listOf(
TopLevelDestinations.Settings to Icons.Default.Settings
)
val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentRoute by remember(navBackStackEntry?.destination) {
derivedStateOf { navBackStackEntry?.destination?.route }
val currentRoute: TopLevelDestinations? by remember(navBackStackEntry?.destination) {
derivedStateOf {
val hierarchyRoutes = navBackStackEntry?.destination?.hierarchy?.map { it.route }
?: emptySequence()
(mainTabs + additionalTabs)
.map { it.first }
.firstOrNull {
hierarchyRoutes.contains(it.route)
}
}
}
val gesturesEnabled: Boolean by remember(navBackStackEntry?.destination) {
derivedStateOf {
// Will be true for routes like
// [null, calculator_route, settings_graph, settings_route, themes_route]
// We disable drawer drag gesture when we are too deep
navController.backQueue.size <= 4
}
}
Themmo(
@ -88,18 +110,19 @@ internal fun UnittoApp() {
) {
val statusBarColor = when (currentRoute) {
// Match text field container color
TopLevelDestinations.Calculator.route -> MaterialTheme.colorScheme.surfaceVariant
TopLevelDestinations.Calculator -> MaterialTheme.colorScheme.surfaceVariant
else -> MaterialTheme.colorScheme.background
}
val navigationBarColor = MaterialTheme.colorScheme.background
ModalNavigationDrawer(
drawerState = drawerState,
gesturesEnabled = true,
gesturesEnabled = gesturesEnabled,
drawerContent = {
UnittoDrawerSheet(
modifier = Modifier,
mainTabs = mainTabs,
additionalTabs = additionalTabs,
currentDestination = currentRoute
) {
drawerScope.launch { drawerState.close() }

View File

@ -19,6 +19,7 @@
package com.sadellie.unitto
import androidx.compose.runtime.Composable
import androidx.navigation.NavGraph.Companion.findStartDestination
import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import com.sadellie.unitto.feature.calculator.navigation.calculatorScreen
@ -50,10 +51,20 @@ internal fun UnittoNavigation(
navController = navController,
startDestination = startDestination
) {
fun navigateToSettings() {
navController.navigateToSettings {
popUpTo(navController.graph.findStartDestination().id) {
saveState = true
}
launchSingleTop = true
restoreState = true
}
}
converterScreen(
navigateToLeftScreen = navController::navigateToLeftSide,
navigateToRightScreen = navController::navigateToRightSide,
navigateToSettings = navController::navigateToSettings,
navigateToSettings = ::navigateToSettings,
navigateToMenu = openDrawer,
viewModel = converterViewModel
)
@ -75,12 +86,13 @@ internal fun UnittoNavigation(
settingGraph(
settingsViewModel = settingsViewModel,
themmoController = themmoController,
navController = navController
navController = navController,
menuButtonClick = openDrawer
)
calculatorScreen(
navigateToMenu = openDrawer,
navigateToSettings = navController::navigateToSettings
navigateToSettings = ::navigateToSettings
)
epochScreen(navigateToMenu = openDrawer)

View File

@ -38,6 +38,11 @@ sealed class TopLevelDestinations(
route = "epoch_route",
name = R.string.epoch_converter
)
object Settings : TopLevelDestinations(
route = "settings_graph",
name = R.string.settings_screen
)
}
val TOP_LEVEL_DESTINATIONS: Map<TopLevelDestinations, Int> by lazy {

View File

@ -21,12 +21,16 @@ package com.sadellie.unitto.core.ui.common
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Calculate
import androidx.compose.material3.Divider
import androidx.compose.material3.ModalDrawerSheet
import androidx.compose.material3.NavigationDrawerItemDefaults
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.sadellie.unitto.core.base.TopLevelDestinations
@ -34,7 +38,8 @@ import com.sadellie.unitto.core.base.TopLevelDestinations
fun UnittoDrawerSheet(
modifier: Modifier,
mainTabs: List<Pair<TopLevelDestinations, ImageVector>>,
currentDestination: String?,
additionalTabs: List<Pair<TopLevelDestinations, ImageVector>>,
currentDestination: TopLevelDestinations?,
onItemClick: (String) -> Unit
) {
ModalDrawerSheet(
@ -49,9 +54,41 @@ fun UnittoDrawerSheet(
modifier = Modifier.padding(NavigationDrawerItemDefaults.ItemPadding),
destination = destination,
icon = icon,
selected = destination.route == currentDestination,
selected = destination == currentDestination,
onClick = onItemClick
)
}
Divider(Modifier.padding(28.dp, 16.dp))
additionalTabs.forEach { (destination, icon) ->
UnittoDrawerItem(
modifier = Modifier.padding(NavigationDrawerItemDefaults.ItemPadding),
destination = destination,
icon = icon,
selected = destination == currentDestination,
onClick = onItemClick
)
}
}
}
@Preview
@Composable
private fun PreviewUnittoDrawerSheet() {
UnittoDrawerSheet(
modifier = Modifier,
mainTabs = listOf(
TopLevelDestinations.Calculator to Icons.Default.Calculate,
TopLevelDestinations.Calculator to Icons.Default.Calculate,
TopLevelDestinations.Settings to Icons.Default.Calculate
),
additionalTabs = listOf(
TopLevelDestinations.Calculator to Icons.Default.Calculate,
TopLevelDestinations.Calculator to Icons.Default.Calculate,
TopLevelDestinations.Calculator to Icons.Default.Calculate
),
currentDestination = TopLevelDestinations.Settings,
onItemClick = {}
)
}

View File

@ -29,16 +29,16 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
/**
* Commonly used LargeTopAppBar with scroll behavior.
* Template screen. Uses [Scaffold] and [LargeTopAppBar]
*
* @param title Text that is displayed in top bar.
* @param navigateUpAction Action when user click arrow button at the top.
* @param content Content that can be scrolled. Don't forget to use padding values.
* @param title See [LargeTopAppBar]
* @param navigationIcon See [LargeTopAppBar]
* @param content See [Scaffold]
*/
@Composable
fun UnittoLargeTopAppBar(
fun UnittoScreenWithLargeTopBar(
title: String,
navigateUpAction: () -> Unit,
navigationIcon: @Composable () -> Unit,
content: @Composable (PaddingValues) -> Unit
) {
val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior(
@ -52,9 +52,7 @@ fun UnittoLargeTopAppBar(
title = {
Text(text = title)
},
navigationIcon = {
NavigateUpButton { navigateUpAction() }
},
navigationIcon = navigationIcon,
scrollBehavior = scrollBehavior
)
},

View File

@ -46,7 +46,8 @@ import androidx.compose.ui.res.stringResource
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.sadellie.unitto.core.base.BuildConfig
import com.sadellie.unitto.core.ui.R
import com.sadellie.unitto.core.ui.common.UnittoLargeTopAppBar
import com.sadellie.unitto.core.ui.common.NavigateUpButton
import com.sadellie.unitto.core.ui.common.UnittoScreenWithLargeTopBar
import com.sadellie.unitto.core.ui.openLink
@Composable
@ -60,9 +61,9 @@ internal fun AboutScreen(
var aboutItemClick: Int by rememberSaveable { mutableStateOf(0) }
var showDialog: Boolean by rememberSaveable { mutableStateOf(false) }
UnittoLargeTopAppBar(
UnittoScreenWithLargeTopBar(
title = stringResource(R.string.about_unitto),
navigateUpAction = navigateUpAction
navigationIcon = { NavigateUpButton(navigateUpAction) }
) { padding ->
LazyColumn(contentPadding = padding) {
// CURRENCY RATE NOTE

View File

@ -49,7 +49,8 @@ import com.sadellie.unitto.core.base.SEPARATORS
import com.sadellie.unitto.core.base.TOP_LEVEL_DESTINATIONS
import com.sadellie.unitto.core.ui.R
import com.sadellie.unitto.core.ui.common.Header
import com.sadellie.unitto.core.ui.common.UnittoLargeTopAppBar
import com.sadellie.unitto.core.ui.common.MenuButton
import com.sadellie.unitto.core.ui.common.UnittoScreenWithLargeTopBar
import com.sadellie.unitto.core.ui.common.UnittoListItem
import com.sadellie.unitto.core.ui.openLink
import com.sadellie.unitto.feature.settings.components.AlertDialogWithList
@ -60,7 +61,7 @@ import com.sadellie.unitto.feature.settings.navigation.unitsGroupRoute
@Composable
internal fun SettingsScreen(
viewModel: SettingsViewModel,
navigateUpAction: () -> Unit,
menuButtonClick: () -> Unit,
navControllerAction: (String) -> Unit
) {
val mContext = LocalContext.current
@ -69,9 +70,9 @@ internal fun SettingsScreen(
mutableStateOf(DialogState.NONE)
}
UnittoLargeTopAppBar(
UnittoScreenWithLargeTopBar(
title = stringResource(R.string.settings_screen),
navigateUpAction = navigateUpAction
navigationIcon = { MenuButton(menuButtonClick) }
) { padding ->
LazyColumn(contentPadding = padding) {

View File

@ -31,9 +31,10 @@ import androidx.compose.material.icons.filled.Palette
import androidx.compose.material3.Icon
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource
import com.sadellie.unitto.core.ui.common.UnittoLargeTopAppBar
import com.sadellie.unitto.core.ui.common.UnittoScreenWithLargeTopBar
import com.sadellie.unitto.core.ui.common.UnittoListItem
import com.sadellie.unitto.core.ui.R
import com.sadellie.unitto.core.ui.common.NavigateUpButton
import io.github.sadellie.themmo.ThemingMode
import io.github.sadellie.themmo.ThemmoController
@ -43,9 +44,9 @@ internal fun ThemesScreen(
themmoController: ThemmoController,
viewModel: SettingsViewModel
) {
UnittoLargeTopAppBar(
UnittoScreenWithLargeTopBar(
title = stringResource(R.string.theme_setting),
navigateUpAction = navigateUpAction
navigationIcon = { NavigateUpButton(navigateUpAction) }
) { paddingValues ->
LazyColumn(contentPadding = paddingValues) {
item {

View File

@ -37,7 +37,8 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.sadellie.unitto.core.ui.R
import com.sadellie.unitto.core.ui.common.UnittoLargeTopAppBar
import com.sadellie.unitto.core.ui.common.NavigateUpButton
import com.sadellie.unitto.core.ui.common.UnittoScreenWithLargeTopBar
import com.sadellie.unitto.core.ui.openLink
import com.sadellie.unitto.data.licenses.ALL_LIBRARIES
@ -53,9 +54,9 @@ internal fun ThirdPartyLicensesScreen(
) {
val mContext = LocalContext.current
UnittoLargeTopAppBar(
UnittoScreenWithLargeTopBar(
title = stringResource(R.string.third_party_licenses),
navigateUpAction = navigateUpAction
navigationIcon = { NavigateUpButton(navigateUpAction) }
) { padding ->
LazyColumn(
verticalArrangement = Arrangement.spacedBy(16.dp),

View File

@ -48,8 +48,9 @@ import androidx.compose.ui.draw.clip
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.sadellie.unitto.core.ui.common.Header
import com.sadellie.unitto.core.ui.common.UnittoLargeTopAppBar
import com.sadellie.unitto.core.ui.common.UnittoScreenWithLargeTopBar
import com.sadellie.unitto.core.ui.R
import com.sadellie.unitto.core.ui.common.NavigateUpButton
import org.burnoutcrew.reorderable.ReorderableItem
import org.burnoutcrew.reorderable.detectReorder
import org.burnoutcrew.reorderable.detectReorderAfterLongPress
@ -61,9 +62,9 @@ internal fun UnitGroupsScreen(
viewModel: SettingsViewModel,
navigateUpAction: () -> Unit
) {
UnittoLargeTopAppBar(
UnittoScreenWithLargeTopBar(
title = stringResource(R.string.unit_groups_setting),
navigateUpAction = navigateUpAction
navigationIcon = { NavigateUpButton(navigateUpAction) }
) { paddingValues ->
val shownUnits = viewModel.shownUnitGroups.collectAsState()

View File

@ -21,8 +21,10 @@ package com.sadellie.unitto.feature.settings.navigation
import androidx.navigation.NavController
import androidx.navigation.NavGraphBuilder
import androidx.navigation.NavHostController
import androidx.navigation.NavOptionsBuilder
import androidx.navigation.compose.composable
import androidx.navigation.compose.navigation
import com.sadellie.unitto.core.base.TopLevelDestinations
import com.sadellie.unitto.feature.settings.AboutScreen
import com.sadellie.unitto.feature.settings.SettingsScreen
import com.sadellie.unitto.feature.settings.SettingsViewModel
@ -31,15 +33,15 @@ import com.sadellie.unitto.feature.settings.ThirdPartyLicensesScreen
import com.sadellie.unitto.feature.settings.UnitGroupsScreen
import io.github.sadellie.themmo.ThemmoController
const val settingsGraph = "settings_graph"
private val settingsGraph: String by lazy { TopLevelDestinations.Settings.route }
private const val settingsRoute = "settings_route"
internal const val themesRoute = "themes_route"
internal const val unitsGroupRoute = "units_group_route"
internal const val thirdPartyRoute = "third_party_route"
internal const val aboutRoute = "about_route"
fun NavController.navigateToSettings() {
navigate(settingsRoute)
fun NavController.navigateToSettings(builder: NavOptionsBuilder.() -> Unit) {
navigate(settingsRoute, builder)
}
fun NavController.navigateToUnitGroups() {
@ -49,13 +51,14 @@ fun NavController.navigateToUnitGroups() {
fun NavGraphBuilder.settingGraph(
settingsViewModel: SettingsViewModel,
themmoController: ThemmoController,
navController: NavHostController
navController: NavHostController,
menuButtonClick: () -> Unit
) {
navigation(settingsRoute, settingsGraph) {
composable(settingsRoute) {
SettingsScreen(
viewModel = settingsViewModel,
navigateUpAction = { navController.navigateUp() }
menuButtonClick = menuButtonClick
) { route -> navController.navigate(route) }
}