mirror of
https://github.com/msfjarvis/compose-lobsters
synced 2025-08-14 17:37:05 +05:30
feat(ui): reintroduce navigation rail to tablet UI
This commit is contained in:
parent
d2202204d2
commit
57bc93d5ea
2 changed files with 147 additions and 46 deletions
|
@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
## [Unreleased]
|
||||
|
||||
### Fixed
|
||||
|
||||
- Tablet users can now navigate between hottest/newest/saved posts again
|
||||
|
||||
## [1.52.0] - 2024-11-26
|
||||
|
||||
### Added
|
||||
|
|
|
@ -9,14 +9,27 @@
|
|||
package dev.msfjarvis.claw.android.ui.screens
|
||||
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
||||
import androidx.compose.material.icons.filled.Favorite
|
||||
import androidx.compose.material.icons.filled.NewReleases
|
||||
import androidx.compose.material.icons.filled.Whatshot
|
||||
import androidx.compose.material.icons.outlined.FavoriteBorder
|
||||
import androidx.compose.material.icons.outlined.NewReleases
|
||||
import androidx.compose.material.icons.outlined.Whatshot
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
|
@ -29,6 +42,7 @@ import androidx.compose.material3.adaptive.navigation.BackNavigationBehavior
|
|||
import androidx.compose.material3.adaptive.navigation.ThreePaneScaffoldNavigator
|
||||
import androidx.compose.material3.adaptive.navigation.rememberListDetailPaneScaffoldNavigator
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.Alignment
|
||||
|
@ -38,18 +52,29 @@ import androidx.compose.ui.res.painterResource
|
|||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.navigation.compose.NavHost
|
||||
import androidx.navigation.compose.composable
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import androidx.paging.compose.collectAsLazyPagingItems
|
||||
import com.deliveryhero.whetstone.compose.injectedViewModel
|
||||
import dev.msfjarvis.claw.android.R
|
||||
import dev.msfjarvis.claw.android.ui.PostActions
|
||||
import dev.msfjarvis.claw.android.ui.decorations.ClawNavigationRail
|
||||
import dev.msfjarvis.claw.android.ui.decorations.NavigationItem
|
||||
import dev.msfjarvis.claw.android.ui.lists.DatabasePosts
|
||||
import dev.msfjarvis.claw.android.ui.lists.NetworkPosts
|
||||
import dev.msfjarvis.claw.android.ui.navigation.Comments
|
||||
import dev.msfjarvis.claw.android.ui.navigation.Hottest
|
||||
import dev.msfjarvis.claw.android.ui.navigation.Newest
|
||||
import dev.msfjarvis.claw.android.ui.navigation.Saved
|
||||
import dev.msfjarvis.claw.android.ui.navigation.User
|
||||
import dev.msfjarvis.claw.android.viewmodel.ClawViewModel
|
||||
import dev.msfjarvis.claw.common.comments.CommentsPage
|
||||
import dev.msfjarvis.claw.common.comments.HTMLConverter
|
||||
import dev.msfjarvis.claw.common.urllauncher.UrlLauncher
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.persistentMapOf
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
private fun ThreePaneScaffoldNavigator<*>.isListExpanded() =
|
||||
|
@ -68,9 +93,13 @@ fun TabletScreen(
|
|||
) {
|
||||
val context = LocalContext.current
|
||||
val hottestListState = rememberLazyListState()
|
||||
val newestListState = rememberLazyListState()
|
||||
val savedListState = rememberLazyListState()
|
||||
val navController = rememberNavController()
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
val hottestPosts = viewModel.hottestPosts.collectAsLazyPagingItems()
|
||||
val newestPosts = viewModel.newestPosts.collectAsLazyPagingItems()
|
||||
val savedPosts by viewModel.savedPostsByMonth.collectAsStateWithLifecycle(persistentMapOf())
|
||||
val navigator = rememberListDetailPaneScaffoldNavigator<Comments>()
|
||||
val backBehavior =
|
||||
if (navigator.isListExpanded() && navigator.isDetailExpanded()) {
|
||||
|
@ -87,6 +116,32 @@ fun TabletScreen(
|
|||
}
|
||||
}
|
||||
|
||||
val navItems =
|
||||
persistentListOf(
|
||||
NavigationItem(
|
||||
label = "Hottest",
|
||||
destination = Hottest,
|
||||
icon = Icons.Outlined.Whatshot,
|
||||
selectedIcon = Icons.Filled.Whatshot,
|
||||
) {
|
||||
coroutineScope.launch {
|
||||
if (hottestPosts.itemCount > 0) hottestListState.animateScrollToItem(index = 0)
|
||||
}
|
||||
},
|
||||
NavigationItem(
|
||||
label = "Newest",
|
||||
destination = Newest,
|
||||
icon = Icons.Outlined.NewReleases,
|
||||
selectedIcon = Icons.Filled.NewReleases,
|
||||
) {},
|
||||
NavigationItem(
|
||||
label = "Saved",
|
||||
destination = Saved,
|
||||
icon = Icons.Outlined.FavoriteBorder,
|
||||
selectedIcon = Icons.Filled.Favorite,
|
||||
) {},
|
||||
)
|
||||
|
||||
BackHandler(navigator.canNavigateBack(backBehavior)) {
|
||||
coroutineScope.launch { navigator.navigateBack(backBehavior) }
|
||||
}
|
||||
|
@ -95,58 +150,100 @@ fun TabletScreen(
|
|||
topBar = {
|
||||
TopAppBar(
|
||||
navigationIcon = {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.ic_launcher_foreground),
|
||||
contentDescription = "The app icon for Claw",
|
||||
modifier = Modifier.size(48.dp),
|
||||
)
|
||||
},
|
||||
title = { Text(text = stringResource(R.string.app_name), fontWeight = FontWeight.Bold) },
|
||||
)
|
||||
},
|
||||
content = { paddingValues ->
|
||||
ListDetailPaneScaffold(
|
||||
modifier = modifier.padding(paddingValues),
|
||||
directive = navigator.scaffoldDirective,
|
||||
value = navigator.scaffoldValue,
|
||||
listPane = {
|
||||
AnimatedPane {
|
||||
NetworkPosts(
|
||||
lazyPagingItems = hottestPosts,
|
||||
listState = hottestListState,
|
||||
postActions = postActions,
|
||||
contentPadding = PaddingValues(),
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
if (navigator.canNavigateBack(backBehavior)) {
|
||||
IconButton(
|
||||
onClick = { coroutineScope.launch { navigator.navigateBack(backBehavior) } }
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.AutoMirrored.Filled.ArrowBack,
|
||||
contentDescription = "Go back to previous screen",
|
||||
)
|
||||
}
|
||||
} else {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.ic_launcher_foreground),
|
||||
contentDescription = "The app icon for Claw",
|
||||
modifier = Modifier.size(48.dp),
|
||||
)
|
||||
}
|
||||
},
|
||||
detailPane = {
|
||||
AnimatedPane {
|
||||
when (val contentKey = navigator.currentDestination?.contentKey) {
|
||||
null -> {
|
||||
Box(Modifier.fillMaxSize()) {
|
||||
Text(
|
||||
text = "Select a post to view comments",
|
||||
modifier = Modifier.align(Alignment.Center),
|
||||
)
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
CommentsPage(
|
||||
postId = contentKey.postId,
|
||||
postActions = postActions,
|
||||
htmlConverter = htmlConverter,
|
||||
getSeenComments = viewModel::getSeenComments,
|
||||
markSeenComments = viewModel::markSeenComments,
|
||||
openUserProfile = { navController.navigate(User(it)) },
|
||||
contentPadding = PaddingValues(),
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
)
|
||||
}
|
||||
}
|
||||
title = {
|
||||
if (!navigator.canNavigateBack(backBehavior)) {
|
||||
Text(text = stringResource(R.string.app_name), fontWeight = FontWeight.Bold)
|
||||
}
|
||||
},
|
||||
)
|
||||
},
|
||||
content = { paddingValues ->
|
||||
Row {
|
||||
ClawNavigationRail(navController = navController, items = navItems, isVisible = true)
|
||||
ListDetailPaneScaffold(
|
||||
modifier = modifier.padding(paddingValues),
|
||||
directive = navigator.scaffoldDirective,
|
||||
value = navigator.scaffoldValue,
|
||||
listPane = {
|
||||
AnimatedPane {
|
||||
NavHost(
|
||||
navController = navController,
|
||||
startDestination = Hottest,
|
||||
enterTransition = { fadeIn(tween(350)) },
|
||||
exitTransition = { fadeOut(tween(350)) },
|
||||
) {
|
||||
composable<Hottest> {
|
||||
NetworkPosts(
|
||||
lazyPagingItems = hottestPosts,
|
||||
listState = hottestListState,
|
||||
postActions = postActions,
|
||||
contentPadding = PaddingValues(),
|
||||
)
|
||||
}
|
||||
composable<Newest> {
|
||||
NetworkPosts(
|
||||
lazyPagingItems = newestPosts,
|
||||
listState = newestListState,
|
||||
postActions = postActions,
|
||||
contentPadding = PaddingValues(),
|
||||
)
|
||||
}
|
||||
composable<Saved> {
|
||||
DatabasePosts(
|
||||
items = savedPosts,
|
||||
listState = savedListState,
|
||||
postActions = postActions,
|
||||
contentPadding = PaddingValues(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
detailPane = {
|
||||
AnimatedPane {
|
||||
when (val contentKey = navigator.currentDestination?.contentKey) {
|
||||
null -> {
|
||||
Box(Modifier.fillMaxSize()) {
|
||||
Text(
|
||||
text = "Select a post to view comments",
|
||||
modifier = Modifier.align(Alignment.Center),
|
||||
)
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
CommentsPage(
|
||||
postId = contentKey.postId,
|
||||
postActions = postActions,
|
||||
htmlConverter = htmlConverter,
|
||||
getSeenComments = viewModel::getSeenComments,
|
||||
markSeenComments = viewModel::markSeenComments,
|
||||
openUserProfile = { navController.navigate(User(it)) },
|
||||
contentPadding = PaddingValues(),
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue