feat(ui): reintroduce navigation rail to tablet UI

This commit is contained in:
Harsh Shandilya 2024-11-30 13:53:11 +05:30
parent d2202204d2
commit 57bc93d5ea
2 changed files with 147 additions and 46 deletions

View file

@ -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

View file

@ -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,30 +150,71 @@ fun TabletScreen(
topBar = {
TopAppBar(
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(
painter = painterResource(id = R.drawable.ic_launcher_foreground),
contentDescription = "The app icon for Claw",
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 ->
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(),
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 = {
AnimatedPane {
@ -147,6 +243,7 @@ fun TabletScreen(
}
},
)
}
},
)
}