Navigate with enum defines. Create new TopBarState
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
2023-01-28 10:06:58 +01:00
parent 48374c5980
commit 6aedb0d7f9
7 changed files with 129 additions and 91 deletions

View File

@@ -17,11 +17,8 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.navigation.NavDestination.Companion.hierarchy
import androidx.navigation.NavGraph.Companion.findStartDestination
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.currentBackStackEntryAsState import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController import androidx.navigation.compose.rememberNavController
import com.google.accompanist.systemuicontroller.rememberSystemUiController import com.google.accompanist.systemuicontroller.rememberSystemUiController
@@ -106,10 +103,7 @@ class MainActivity : AppCompatActivity(), ISettingsChangeListener {
fabAction: () -> Unit fabAction: () -> Unit
) { ) {
var topBarTitle by remember { mutableStateOf("") } var topBarState by remember { mutableStateOf(TopBarState()) }
var topBarIcon by remember { mutableStateOf(Icons.Filled.Menu) }
var topBarActions by remember { mutableStateOf(emptyList<TopBarAction>()) }
var topBarNavigationAction by remember { mutableStateOf(NavigationAction {}) }
Scaffold( Scaffold(
floatingActionButton = { floatingActionButton = {
@@ -120,26 +114,20 @@ class MainActivity : AppCompatActivity(), ISettingsChangeListener {
} }
} }
}, },
topBar = { topBar = { TopBar(topBarState) }) { paddings ->
TopBar(
topBarTitle,
topBarIcon,
{ topBarNavigationAction.action() },
topBarActions
)
}) { paddings ->
NavHost( NavHost(
navController = navController, navController = navController,
startDestination = "counter", startDestination = Route.COUNTER.name,
modifier = Modifier.padding(paddings) modifier = Modifier.padding(paddings)
) { ) {
composable("counter") { composable(Route.COUNTER) {
var expanded by remember { mutableStateOf(false) } var expanded by remember { mutableStateOf(false) }
Counter(counterViewModel) topBarState = TopBarState(
topBarActions = (listOf( title = stringResource(R.string.app_name),
actions = (listOf(
TopBarAction( TopBarAction(
Icons.Outlined.Undo, Icons.Outlined.Undo,
mainViewModel.isUndoActionActive, mainViewModel.isUndoActionActive,
@@ -168,28 +156,21 @@ class MainActivity : AppCompatActivity(), ISettingsChangeListener {
}, },
)) ))
topBarIcon = Icons.Outlined.Menu ) { scope.launch { drawerState.open() } }
topBarTitle = stringResource(R.string.app_name)
topBarNavigationAction =
NavigationAction { scope.launch { drawerState.open() } }
}
composable("history") {
HistoryList(historyViewModel) { navController.navigate("counter") } Counter(counterViewModel)
topBarActions = emptyList()
topBarIcon = Icons.Outlined.Menu
topBarTitle = stringResource(R.string.menu_history)
topBarNavigationAction =
NavigationAction { scope.launch { drawerState.open() } }
} }
composable("settings") { composable(Route.HISTORY) {
topBarState =
TopBarState(title = stringResource(R.string.menu_history)) { scope.launch { drawerState.open() } }
HistoryList(historyViewModel) { navController.navigate(Route.COUNTER) }
}
composable(Route.SETTINGS) {
topBarState =
TopBarState(title = stringResource(R.string.menu_settings)) { scope.launch { drawerState.open() } }
SettingsView(settingsViewModel) SettingsView(settingsViewModel)
topBarActions = emptyList()
topBarIcon = Icons.Outlined.Menu
topBarTitle = stringResource(R.string.menu_settings)
topBarNavigationAction =
NavigationAction { scope.launch { drawerState.open() } }
} }
} }
} }
@@ -204,40 +185,27 @@ class MainActivity : AppCompatActivity(), ISettingsChangeListener {
val navController = rememberNavController() val navController = rememberNavController()
val items = listOf( val items = listOf(
Screen("counter", Icons.Outlined.Calculate, R.string.app_name), Screen(Route.COUNTER, Icons.Outlined.Calculate, R.string.app_name),
Screen("history", Icons.Outlined.List, R.string.menu_history), Screen(Route.HISTORY, Icons.Outlined.List, R.string.menu_history),
Screen("settings", Icons.Outlined.Settings, R.string.menu_settings) Screen(Route.SETTINGS, Icons.Outlined.Settings, R.string.menu_settings)
) )
val navBackStackEntry by navController.currentBackStackEntryAsState() val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentDestination = navBackStackEntry?.destination val currentDestination =
Route.valueOf(navBackStackEntry?.destination?.route ?: Route.COUNTER.name)
ModalNavigationDrawer( ModalNavigationDrawer(
drawerState = drawerState, drawerState = drawerState,
gesturesEnabled = drawerState.isOpen, gesturesEnabled = drawerState.isOpen,
drawerContent = { drawerContent = {
ModalDrawerSheet { DrawerContent(
screens = items,
selectedScreen = items.first { it.route == currentDestination }) {
scope.launch {
drawerState.close()
Spacer(Modifier.height(20.dp))
items.forEach { screen ->
NavigationDrawerItem(
icon = { Icon(screen.icon, contentDescription = null) },
label = { Text(stringResource(screen.resourceId)) },
selected = currentDestination?.hierarchy?.any { it.route == screen.route } == true,
onClick = {
scope.launch { drawerState.close() }
navController.navigate(screen.route) {
popUpTo(navController.graph.findStartDestination().id) {
saveState = true
}
launchSingleTop = true
restoreState = true
}
},
modifier = Modifier.padding(NavigationDrawerItemDefaults.ItemPadding)
)
} }
navController.navigate(it)
} }
} }
) { ) {
@@ -245,10 +213,34 @@ class MainActivity : AppCompatActivity(), ISettingsChangeListener {
drawerState, drawerState,
scope, scope,
navController, navController,
counterViewModel.keyboardHidden && (currentDestination?.hierarchy?.any { it.route == "counter" } == true) counterViewModel.keyboardHidden && (currentDestination == Route.COUNTER)
) { counterViewModel.showKeyboard() } ) { counterViewModel.showKeyboard() }
} }
} }
private class Screen(val route: String, val icon: ImageVector, @StringRes val resourceId: Int) @OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun DrawerContent(
screens: List<Screen>,
selectedScreen: Screen,
onElementClicked: (Route) -> Unit
) {
ModalDrawerSheet {
Spacer(Modifier.height(20.dp))
screens.forEach { screen ->
NavigationDrawerItem(
icon = { Icon(screen.icon, contentDescription = null) },
label = { Text(stringResource(screen.resourceId)) },
selected = screen == selectedScreen,
onClick = { onElementClicked(screen.route) },
modifier = Modifier.padding(NavigationDrawerItemDefaults.ItemPadding)
)
}
}
}
private class Screen(val route: Route, val icon: ImageVector, @StringRes val resourceId: Int)
} }

View File

@@ -0,0 +1,18 @@
package me.zobrist.tichucounter.domain
import androidx.compose.runtime.Composable
import androidx.navigation.*
import androidx.navigation.compose.composable
fun NavController.navigate(route: Route) {
this.navigate(route.name)
}
fun NavGraphBuilder.composable(
route: Route,
arguments: List<NamedNavArgument> = emptyList(),
deepLinks: List<NavDeepLink> = emptyList(),
content: @Composable (NavBackStackEntry) -> Unit
) {
this.composable(route.name, arguments, deepLinks, content)
}

View File

@@ -1,3 +0,0 @@
package me.zobrist.tichucounter.domain
class NavigationAction(val action: () -> Unit)

View File

@@ -0,0 +1,3 @@
package me.zobrist.tichucounter.domain
enum class Route { COUNTER, HISTORY, SETTINGS }

View File

@@ -3,4 +3,9 @@ package me.zobrist.tichucounter.domain
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.graphics.vector.ImageVector
class TopBarAction(val imageVector: ImageVector, val isActive: Boolean, val action: () -> Unit, val composeCode: @Composable () -> Unit = {}) class TopBarAction(
val imageVector: ImageVector,
val isActive: Boolean,
val action: () -> Unit,
val composeCode: @Composable () -> Unit = {}
)

View File

@@ -0,0 +1,12 @@
package me.zobrist.tichucounter.domain
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Menu
import androidx.compose.ui.graphics.vector.ImageVector
data class TopBarState(
var title: String = "",
var icon: ImageVector = Icons.Outlined.Menu,
var actions: List<TopBarAction> = emptyList(),
var onNavigate: () -> Unit = {}
)

View File

@@ -5,6 +5,17 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import me.zobrist.tichucounter.domain.TopBarAction import me.zobrist.tichucounter.domain.TopBarAction
import me.zobrist.tichucounter.domain.TopBarState
@Composable
fun TopBar(topBarState: TopBarState) {
TopBar(
topBarState.title,
topBarState.icon,
topBarState.onNavigate,
topBarState.actions
)
}
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable