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)
val errorMessage = _errorMessage.asStateFlow()
protected open val entryStatus: EntryStatus? = null
protected open val feedId: Int? = null
protected open val categoryId: Int? = null
private lateinit var pagingSource: EntryAndFeedPagingSource
val entries = Pager(PagingConfig(pageSize = 15)) {
EntryAndFeedPagingSource(entryRepository, entryStatus).also {

View file

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

View file

@ -74,176 +74,114 @@ fun MainScaffold(
) {
val snackbarHostState = remember { SnackbarHostState() }
val scaffoldState = rememberScaffoldState(snackbarHostState = snackbarHostState)
val coroutineScope = rememberCoroutineScope()
val (title, setTitle) = remember { mutableStateOf("Unread") }
Scaffold(
scaffoldState = scaffoldState,
topBar = {
TopAppBar(
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 = {
Text(text = "nano")
Text(text = "flux", color = MaterialTheme.colors.primary)
},
actions = {
IconButton(onClick = onSettingsClicked) {
Icon(Icons.Default.Settings, contentDescription = "Settings", tint = MaterialTheme.colors.onSurface)
}
}
)
},
bottomBar = {
BottomAppBar(
modifier = Modifier.navigationBarsPadding(),
backgroundColor = MaterialTheme.colors.surface
) {
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 = title,
text = "Categories",
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
})
},
drawerContent = {
val topPadding = WindowInsets.statusBars.asPaddingValues().calculateTopPadding() + 8.dp
Row(Modifier.padding(top = topPadding, start = 8.dp, end = 8.dp, bottom = 8.dp)) {
Text(text = "nano", fontSize = 24.sp)
Text(text = "flux", color = MaterialTheme.colors.primary, fontSize = 24.sp)
}
DrawerButton(
onClick = {
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"
selectedContentColor = MaterialTheme.colors.primary,
enabled = false // remove when implemented
)
}
) {
},
) { padding ->
// TODO: Extract routes to constants
NavHost(
modifier = Modifier.padding(it),
modifier = Modifier.padding(padding),
navController = navController,
startDestination = "unread"
) {
composable("unread") {
LaunchedEffect(navController.currentBackStackEntry) {
setTitle("Unread")
}
EntryListScreen(navController, snackbarHostState, hiltViewModel<UnreadViewModel>())
}
composable("starred") {
LaunchedEffect(navController.currentBackStackEntry) {
setTitle("Starred")
}
EntryListScreen(navController, snackbarHostState, hiltViewModel<StarredViewModel>())
}
composable("history") {
LaunchedEffect(navController.currentBackStackEntry) {
setTitle("History")
EntryListScreen(navController, snackbarHostState, hiltViewModel<HistoryViewModel>())
}
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>())
}
composable(
"entries/{entryId}",
arguments = listOf(navArgument("entryId") { type = NavType.LongType })
) {
LaunchedEffect(navController.currentBackStackEntry) {
setTitle("")
}
EntryScreen(
it.arguments!!.getLong("entryId"),
navController,
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
@Preview
fun MainScaffold_Preview() {

View file

@ -9,7 +9,9 @@ import timber.log.Timber
class EntryAndFeedPagingSource(
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>() {
init {
Timber.tag("Nanoflux").d("EntryAndFeedPagingSource created")