move navigation drawer to bottom tabs?

This commit is contained in:
William Brawner 2023-12-08 23:10:44 -07:00
parent ebb3663f06
commit 28459c13f6
Signed by: wbrawner
GPG key ID: 8FF12381C6C90D35
4 changed files with 78 additions and 137 deletions

View file

@ -27,6 +27,8 @@ abstract class EntryListViewModel(
private val _errorMessage = MutableStateFlow<String?>(null) private val _errorMessage = MutableStateFlow<String?>(null)
val errorMessage = _errorMessage.asStateFlow() val errorMessage = _errorMessage.asStateFlow()
protected open val entryStatus: EntryStatus? = null protected open val entryStatus: EntryStatus? = null
protected open val feedId: Int? = null
protected open val categoryId: Int? = null
private lateinit var pagingSource: EntryAndFeedPagingSource private lateinit var pagingSource: EntryAndFeedPagingSource
val entries = Pager(PagingConfig(pageSize = 15)) { val entries = Pager(PagingConfig(pageSize = 15)) {
EntryAndFeedPagingSource(entryRepository, entryStatus).also { EntryAndFeedPagingSource(entryRepository, entryStatus).also {

View file

@ -35,7 +35,6 @@ fun EntryScreen(
entryId: Long, entryId: Long,
navController: NavController, navController: NavController,
entryViewModel: EntryViewModel, entryViewModel: EntryViewModel,
setTitle: (String) -> Unit,
) { ) {
val coroutineScope = rememberCoroutineScope() val coroutineScope = rememberCoroutineScope()
val context = LocalContext.current val context = LocalContext.current
@ -58,7 +57,7 @@ fun EntryScreen(
entry?.let { entry?.let {
LaunchedEffect(it.entry.title) { LaunchedEffect(it.entry.title) {
// TODO: Use Material3 to use collapsing toolbar // TODO: Use Material3 to use collapsing toolbar
setTitle(it.entry.title) // setTitle(it.entry.title)
} }
EntryScreen( EntryScreen(
entry = it, entry = it,

View file

@ -74,176 +74,114 @@ fun MainScaffold(
) { ) {
val snackbarHostState = remember { SnackbarHostState() } val snackbarHostState = remember { SnackbarHostState() }
val scaffoldState = rememberScaffoldState(snackbarHostState = snackbarHostState) val scaffoldState = rememberScaffoldState(snackbarHostState = snackbarHostState)
val coroutineScope = rememberCoroutineScope()
val (title, setTitle) = remember { mutableStateOf("Unread") }
Scaffold( Scaffold(
scaffoldState = scaffoldState, scaffoldState = scaffoldState,
topBar = { topBar = {
TopAppBar( TopAppBar(
modifier = Modifier.statusBarsPadding(), modifier = Modifier.statusBarsPadding(),
navigationIcon = {
IconButton(onClick = {
coroutineScope.launch {
if (navController.currentDestination?.route?.startsWith("entries/") == true) {
navController.popBackStack()
} else {
scaffoldState.drawerState.open()
}
}
}) {
val icon =
if (navController.currentDestination?.route?.startsWith("entries/") == true) {
Icons.Default.ArrowBack
} else {
Icons.Default.Menu
}
Icon(
imageVector = icon,
contentDescription = "Menu"
)
}
},
title = { title = {
Text( Text(text = "nano")
text = title, Text(text = "flux", color = MaterialTheme.colors.primary)
maxLines = 1, },
overflow = TextOverflow.Ellipsis actions = {
) IconButton(onClick = onSettingsClicked) {
}) Icon(Icons.Default.Settings, contentDescription = "Settings", tint = MaterialTheme.colors.onSurface)
}
}
)
}, },
drawerContent = { bottomBar = {
val topPadding = WindowInsets.statusBars.asPaddingValues().calculateTopPadding() + 8.dp BottomAppBar(
Row(Modifier.padding(top = topPadding, start = 8.dp, end = 8.dp, bottom = 8.dp)) { modifier = Modifier.navigationBarsPadding(),
Text(text = "nano", fontSize = 24.sp) backgroundColor = MaterialTheme.colors.surface
Text(text = "flux", color = MaterialTheme.colors.primary, fontSize = 24.sp) ) {
BottomNavigationItem(
selected = navController.currentDestination?.route == null || navController.currentDestination?.route == "unread",
onClick = onUnreadClicked,
icon = { Icon(Icons.Default.Article, contentDescription = null) },
label = { Text("Entries") },
selectedContentColor = MaterialTheme.colors.primary
)
// BottomNavigationItem(
// selected = navController.currentDestination?.route == "starred",
// onClick = onStarredClicked,
// icon = { Icon(Icons.Default.Star, contentDescription = null) },
// label = { Text("Starred") },
// selectedContentColor = MaterialTheme.colors.primary
// )
// BottomNavigationItem(
// selected = navController.currentDestination?.route == "history",
// onClick = onHistoryClicked,
// icon = { Icon(Icons.Default.DateRange, contentDescription = null) },
// label = { Text("History") },
// selectedContentColor = MaterialTheme.colors.primary
// )
BottomNavigationItem(
selected = navController.currentDestination?.route == "feeds",
onClick = onFeedsClicked,
icon = { Icon(Icons.Default.List, contentDescription = null) },
label = { Text("Feeds") },
selectedContentColor = MaterialTheme.colors.primary,
enabled = false // remove when implemented
)
BottomNavigationItem(
selected = navController.currentDestination?.route == "categories",
onClick = onCategoriesClicked,
icon = { Icon(Icons.Default.Category, contentDescription = null) },
label = {
Text(
text = "Categories",
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
},
selectedContentColor = MaterialTheme.colors.primary,
enabled = false // remove when implemented
)
} }
DrawerButton( },
onClick = { ) { padding ->
onUnreadClicked()
coroutineScope.launch {
scaffoldState.drawerState.close()
}
},
icon = Icons.Default.Email, text = "Unread"
)
DrawerButton(
onClick = {
onStarredClicked()
coroutineScope.launch {
scaffoldState.drawerState.close()
}
},
icon = Icons.Default.Star,
text = "Starred"
)
DrawerButton(
onClick = {
onHistoryClicked()
coroutineScope.launch {
scaffoldState.drawerState.close()
}
},
icon = Icons.Default.DateRange,
text = "History"
)
DrawerButton(
onClick = {
onFeedsClicked()
coroutineScope.launch {
scaffoldState.drawerState.close()
}
},
icon = Icons.Default.List,
text = "Feeds"
)
DrawerButton(
onClick = {
onCategoriesClicked()
coroutineScope.launch {
scaffoldState.drawerState.close()
}
},
icon = Icons.Default.Info,
text = "Categories"
)
DrawerButton(
onClick = {
onSettingsClicked()
coroutineScope.launch {
scaffoldState.drawerState.close()
}
},
icon = Icons.Default.Settings,
text = "Settings"
)
}
) {
// TODO: Extract routes to constants // TODO: Extract routes to constants
NavHost( NavHost(
modifier = Modifier.padding(it), modifier = Modifier.padding(padding),
navController = navController, navController = navController,
startDestination = "unread" startDestination = "unread"
) { ) {
composable("unread") { composable("unread") {
LaunchedEffect(navController.currentBackStackEntry) {
setTitle("Unread")
}
EntryListScreen(navController, snackbarHostState, hiltViewModel<UnreadViewModel>()) EntryListScreen(navController, snackbarHostState, hiltViewModel<UnreadViewModel>())
} }
composable("starred") { composable("starred") {
LaunchedEffect(navController.currentBackStackEntry) {
setTitle("Starred")
}
EntryListScreen(navController, snackbarHostState, hiltViewModel<StarredViewModel>()) EntryListScreen(navController, snackbarHostState, hiltViewModel<StarredViewModel>())
} }
composable("history") { composable("history") {
LaunchedEffect(navController.currentBackStackEntry) { EntryListScreen(navController, snackbarHostState, hiltViewModel<HistoryViewModel>())
setTitle("History") }
} composable(
"feeds/{feedId}",
arguments = listOf(navArgument("feedId") { type = NavType.LongType })
) {
EntryListScreen(navController, snackbarHostState, hiltViewModel<HistoryViewModel>())
}
composable(
"categories/{categoryId}",
arguments = listOf(navArgument("categoryId") { type = NavType.LongType })
) {
EntryListScreen(navController, snackbarHostState, hiltViewModel<HistoryViewModel>()) EntryListScreen(navController, snackbarHostState, hiltViewModel<HistoryViewModel>())
} }
composable( composable(
"entries/{entryId}", "entries/{entryId}",
arguments = listOf(navArgument("entryId") { type = NavType.LongType }) arguments = listOf(navArgument("entryId") { type = NavType.LongType })
) { ) {
LaunchedEffect(navController.currentBackStackEntry) {
setTitle("")
}
EntryScreen( EntryScreen(
it.arguments!!.getLong("entryId"), it.arguments!!.getLong("entryId"),
navController, navController,
hiltViewModel(), hiltViewModel(),
setTitle,
) )
} }
} }
} }
} }
@Composable
fun DrawerButton(onClick: () -> Unit, icon: ImageVector, text: String) {
TextButton(onClick = onClick, modifier = Modifier.fillMaxWidth()) {
Row(
horizontalArrangement = Arrangement.Start,
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.fillMaxWidth()
) {
Icon(
imageVector = icon,
contentDescription = null,
tint = MaterialTheme.colors.onSurface
)
Spacer(Modifier.width(16.dp))
Text(
text = text,
color = MaterialTheme.colors.onSurface,
modifier = Modifier.padding(8.dp),
style = MaterialTheme.typography.body2
)
}
}
}
@Composable @Composable
@Preview @Preview
fun MainScaffold_Preview() { fun MainScaffold_Preview() {

View file

@ -9,7 +9,9 @@ import timber.log.Timber
class EntryAndFeedPagingSource( class EntryAndFeedPagingSource(
private val entryRepository: EntryRepository, private val entryRepository: EntryRepository,
private val entryStatus: EntryStatus? = null private val entryStatus: EntryStatus? = null,
private val feedId: Long? = null,
private val categoryId: Long? = null,
) : PagingSource<Int, EntryAndFeed>() { ) : PagingSource<Int, EntryAndFeed>() {
init { init {
Timber.tag("Nanoflux").d("EntryAndFeedPagingSource created") Timber.tag("Nanoflux").d("EntryAndFeedPagingSource created")