move navigation drawer to bottom tabs?
This commit is contained in:
parent
ebb3663f06
commit
28459c13f6
4 changed files with 78 additions and 137 deletions
|
@ -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 {
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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")
|
||||||
|
|
Loading…
Reference in a new issue