mirror of
https://github.com/msfjarvis/compose-lobsters
synced 2025-08-14 21:07:04 +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]
|
## [Unreleased]
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Tablet users can now navigate between hottest/newest/saved posts again
|
||||||
|
|
||||||
## [1.52.0] - 2024-11-26
|
## [1.52.0] - 2024-11-26
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
|
@ -9,14 +9,27 @@
|
||||||
package dev.msfjarvis.claw.android.ui.screens
|
package dev.msfjarvis.claw.android.ui.screens
|
||||||
|
|
||||||
import androidx.activity.compose.BackHandler
|
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.Box
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
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.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.IconButton
|
||||||
import androidx.compose.material3.Scaffold
|
import androidx.compose.material3.Scaffold
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TopAppBar
|
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.ThreePaneScaffoldNavigator
|
||||||
import androidx.compose.material3.adaptive.navigation.rememberListDetailPaneScaffoldNavigator
|
import androidx.compose.material3.adaptive.navigation.rememberListDetailPaneScaffoldNavigator
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import androidx.compose.ui.Alignment
|
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.res.stringResource
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.unit.dp
|
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.navigation.compose.rememberNavController
|
||||||
import androidx.paging.compose.collectAsLazyPagingItems
|
import androidx.paging.compose.collectAsLazyPagingItems
|
||||||
import com.deliveryhero.whetstone.compose.injectedViewModel
|
import com.deliveryhero.whetstone.compose.injectedViewModel
|
||||||
import dev.msfjarvis.claw.android.R
|
import dev.msfjarvis.claw.android.R
|
||||||
import dev.msfjarvis.claw.android.ui.PostActions
|
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.lists.NetworkPosts
|
||||||
import dev.msfjarvis.claw.android.ui.navigation.Comments
|
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.ui.navigation.User
|
||||||
import dev.msfjarvis.claw.android.viewmodel.ClawViewModel
|
import dev.msfjarvis.claw.android.viewmodel.ClawViewModel
|
||||||
import dev.msfjarvis.claw.common.comments.CommentsPage
|
import dev.msfjarvis.claw.common.comments.CommentsPage
|
||||||
import dev.msfjarvis.claw.common.comments.HTMLConverter
|
import dev.msfjarvis.claw.common.comments.HTMLConverter
|
||||||
import dev.msfjarvis.claw.common.urllauncher.UrlLauncher
|
import dev.msfjarvis.claw.common.urllauncher.UrlLauncher
|
||||||
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
|
import kotlinx.collections.immutable.persistentMapOf
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
private fun ThreePaneScaffoldNavigator<*>.isListExpanded() =
|
private fun ThreePaneScaffoldNavigator<*>.isListExpanded() =
|
||||||
|
@ -68,9 +93,13 @@ fun TabletScreen(
|
||||||
) {
|
) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val hottestListState = rememberLazyListState()
|
val hottestListState = rememberLazyListState()
|
||||||
|
val newestListState = rememberLazyListState()
|
||||||
|
val savedListState = rememberLazyListState()
|
||||||
val navController = rememberNavController()
|
val navController = rememberNavController()
|
||||||
val coroutineScope = rememberCoroutineScope()
|
val coroutineScope = rememberCoroutineScope()
|
||||||
val hottestPosts = viewModel.hottestPosts.collectAsLazyPagingItems()
|
val hottestPosts = viewModel.hottestPosts.collectAsLazyPagingItems()
|
||||||
|
val newestPosts = viewModel.newestPosts.collectAsLazyPagingItems()
|
||||||
|
val savedPosts by viewModel.savedPostsByMonth.collectAsStateWithLifecycle(persistentMapOf())
|
||||||
val navigator = rememberListDetailPaneScaffoldNavigator<Comments>()
|
val navigator = rememberListDetailPaneScaffoldNavigator<Comments>()
|
||||||
val backBehavior =
|
val backBehavior =
|
||||||
if (navigator.isListExpanded() && navigator.isDetailExpanded()) {
|
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)) {
|
BackHandler(navigator.canNavigateBack(backBehavior)) {
|
||||||
coroutineScope.launch { navigator.navigateBack(backBehavior) }
|
coroutineScope.launch { navigator.navigateBack(backBehavior) }
|
||||||
}
|
}
|
||||||
|
@ -95,30 +150,71 @@ fun TabletScreen(
|
||||||
topBar = {
|
topBar = {
|
||||||
TopAppBar(
|
TopAppBar(
|
||||||
navigationIcon = {
|
navigationIcon = {
|
||||||
|
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(
|
Icon(
|
||||||
painter = painterResource(id = R.drawable.ic_launcher_foreground),
|
painter = painterResource(id = R.drawable.ic_launcher_foreground),
|
||||||
contentDescription = "The app icon for Claw",
|
contentDescription = "The app icon for Claw",
|
||||||
modifier = Modifier.size(48.dp),
|
modifier = Modifier.size(48.dp),
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
title = {
|
||||||
|
if (!navigator.canNavigateBack(backBehavior)) {
|
||||||
|
Text(text = stringResource(R.string.app_name), fontWeight = FontWeight.Bold)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
title = { Text(text = stringResource(R.string.app_name), fontWeight = FontWeight.Bold) },
|
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
content = { paddingValues ->
|
content = { paddingValues ->
|
||||||
|
Row {
|
||||||
|
ClawNavigationRail(navController = navController, items = navItems, isVisible = true)
|
||||||
ListDetailPaneScaffold(
|
ListDetailPaneScaffold(
|
||||||
modifier = modifier.padding(paddingValues),
|
modifier = modifier.padding(paddingValues),
|
||||||
directive = navigator.scaffoldDirective,
|
directive = navigator.scaffoldDirective,
|
||||||
value = navigator.scaffoldValue,
|
value = navigator.scaffoldValue,
|
||||||
listPane = {
|
listPane = {
|
||||||
AnimatedPane {
|
AnimatedPane {
|
||||||
|
NavHost(
|
||||||
|
navController = navController,
|
||||||
|
startDestination = Hottest,
|
||||||
|
enterTransition = { fadeIn(tween(350)) },
|
||||||
|
exitTransition = { fadeOut(tween(350)) },
|
||||||
|
) {
|
||||||
|
composable<Hottest> {
|
||||||
NetworkPosts(
|
NetworkPosts(
|
||||||
lazyPagingItems = hottestPosts,
|
lazyPagingItems = hottestPosts,
|
||||||
listState = hottestListState,
|
listState = hottestListState,
|
||||||
postActions = postActions,
|
postActions = postActions,
|
||||||
contentPadding = PaddingValues(),
|
contentPadding = PaddingValues(),
|
||||||
modifier = Modifier.fillMaxSize(),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
composable<Newest> {
|
||||||
|
NetworkPosts(
|
||||||
|
lazyPagingItems = newestPosts,
|
||||||
|
listState = newestListState,
|
||||||
|
postActions = postActions,
|
||||||
|
contentPadding = PaddingValues(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
composable<Saved> {
|
||||||
|
DatabasePosts(
|
||||||
|
items = savedPosts,
|
||||||
|
listState = savedListState,
|
||||||
|
postActions = postActions,
|
||||||
|
contentPadding = PaddingValues(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
detailPane = {
|
detailPane = {
|
||||||
AnimatedPane {
|
AnimatedPane {
|
||||||
|
@ -147,6 +243,7 @@ fun TabletScreen(
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue