mirror of
https://github.com/msfjarvis/compose-lobsters
synced 2025-08-14 21:07:04 +05:30
feat: rewrite navigation on top of Nav3
This commit is contained in:
parent
9b322c212f
commit
17289a26f1
9 changed files with 115 additions and 582 deletions
|
@ -107,6 +107,8 @@ dependencies {
|
||||||
implementation(libs.androidx.core.splashscreen)
|
implementation(libs.androidx.core.splashscreen)
|
||||||
implementation(libs.androidx.lifecycle.compose)
|
implementation(libs.androidx.lifecycle.compose)
|
||||||
implementation(libs.androidx.navigation.compose)
|
implementation(libs.androidx.navigation.compose)
|
||||||
|
implementation(libs.androidx.navigation3.runtime)
|
||||||
|
implementation(libs.androidx.navigation3.ui)
|
||||||
implementation(libs.androidx.paging.compose)
|
implementation(libs.androidx.paging.compose)
|
||||||
implementation(libs.androidx.profileinstaller)
|
implementation(libs.androidx.profileinstaller)
|
||||||
implementation(libs.androidx.work.runtime)
|
implementation(libs.androidx.work.runtime)
|
||||||
|
|
|
@ -33,19 +33,6 @@
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
|
||||||
android:name=".SearchActivity"
|
|
||||||
android:configChanges="colorMode|density|fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode"
|
|
||||||
android:exported="true"
|
|
||||||
android:label="Claw Search"
|
|
||||||
android:launchMode="singleTask"
|
|
||||||
android:taskAffinity=""
|
|
||||||
android:theme="@style/Theme.Claw">
|
|
||||||
<intent-filter>
|
|
||||||
<action android:name="android.intent.action.MAIN" />
|
|
||||||
</intent-filter>
|
|
||||||
</activity>
|
|
||||||
|
|
||||||
<provider
|
<provider
|
||||||
android:name="androidx.startup.InitializationProvider"
|
android:name="androidx.startup.InitializationProvider"
|
||||||
android:authorities="${applicationId}.androidx-startup"
|
android:authorities="${applicationId}.androidx-startup"
|
||||||
|
|
|
@ -6,16 +6,13 @@
|
||||||
*/
|
*/
|
||||||
package dev.msfjarvis.claw.android
|
package dev.msfjarvis.claw.android
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.activity.enableEdgeToEdge
|
||||||
import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi
|
import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi
|
||||||
import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass
|
|
||||||
import androidx.compose.material3.windowsizeclass.calculateWindowSizeClass
|
import androidx.compose.material3.windowsizeclass.calculateWindowSizeClass
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
||||||
import com.deliveryhero.whetstone.activity.ContributesActivityInjector
|
import com.deliveryhero.whetstone.activity.ContributesActivityInjector
|
||||||
import dev.msfjarvis.claw.android.ui.screens.LobstersPostsScreen
|
import dev.msfjarvis.claw.android.ui.screens.Nav3Screen
|
||||||
import dev.msfjarvis.claw.android.ui.screens.TabletScreen
|
|
||||||
|
|
||||||
@ContributesActivityInjector
|
@ContributesActivityInjector
|
||||||
class MainActivity : BaseActivity() {
|
class MainActivity : BaseActivity() {
|
||||||
|
@ -24,24 +21,16 @@ class MainActivity : BaseActivity() {
|
||||||
@Composable
|
@Composable
|
||||||
override fun Content() {
|
override fun Content() {
|
||||||
val windowSizeClass = calculateWindowSizeClass(this)
|
val windowSizeClass = calculateWindowSizeClass(this)
|
||||||
|
Nav3Screen(
|
||||||
when (windowSizeClass.widthSizeClass) {
|
urlLauncher = urlLauncher,
|
||||||
WindowWidthSizeClass.Compact -> {
|
windowSizeClass = windowSizeClass,
|
||||||
LobstersPostsScreen(
|
setWebUri = { url -> webUri = url },
|
||||||
urlLauncher = urlLauncher,
|
)
|
||||||
windowSizeClass = windowSizeClass,
|
|
||||||
setWebUri = { url -> webUri = url },
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> {
|
|
||||||
TabletScreen(urlLauncher = urlLauncher, modifier = Modifier.fillMaxSize())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun preLaunch() {
|
override fun preLaunch() {
|
||||||
super.preLaunch()
|
super.preLaunch()
|
||||||
|
enableEdgeToEdge()
|
||||||
installSplashScreen()
|
installSplashScreen()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,19 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright © Harsh Shandilya.
|
|
||||||
* Use of this source code is governed by an MIT-style
|
|
||||||
* license that can be found in the LICENSE file or at
|
|
||||||
* https://opensource.org/licenses/MIT.
|
|
||||||
*/
|
|
||||||
package dev.msfjarvis.claw.android
|
|
||||||
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import com.deliveryhero.whetstone.activity.ContributesActivityInjector
|
|
||||||
import dev.msfjarvis.claw.android.ui.screens.SearchScreen
|
|
||||||
|
|
||||||
@ContributesActivityInjector
|
|
||||||
class SearchActivity : BaseActivity() {
|
|
||||||
@Composable
|
|
||||||
override fun Content() {
|
|
||||||
SearchScreen(urlLauncher = urlLauncher, setWebUri = { webUri = it }, viewModel = viewModel)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -20,21 +20,19 @@ import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.NavigationBarItem
|
import androidx.compose.material3.NavigationBarItem
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.snapshots.SnapshotStateList
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
import androidx.compose.ui.platform.testTag
|
import androidx.compose.ui.platform.testTag
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.navigation.NavController
|
|
||||||
import androidx.navigation.compose.currentBackStackEntryAsState
|
|
||||||
import dev.chrisbanes.haze.HazeDefaults
|
import dev.chrisbanes.haze.HazeDefaults
|
||||||
import dev.chrisbanes.haze.HazeState
|
import dev.chrisbanes.haze.HazeState
|
||||||
import dev.chrisbanes.haze.HazeStyle
|
import dev.chrisbanes.haze.HazeStyle
|
||||||
import dev.chrisbanes.haze.hazeEffect
|
import dev.chrisbanes.haze.hazeEffect
|
||||||
import dev.msfjarvis.claw.android.ui.navigation.AppDestinations
|
import dev.msfjarvis.claw.android.ui.navigation.AppDestinations
|
||||||
import dev.msfjarvis.claw.android.ui.navigation.Destination
|
import dev.msfjarvis.claw.android.ui.navigation.Destination
|
||||||
import dev.msfjarvis.claw.android.ui.navigation.matches
|
|
||||||
import dev.msfjarvis.claw.common.ui.FloatingNavigationBar
|
import dev.msfjarvis.claw.common.ui.FloatingNavigationBar
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
|
|
||||||
|
@ -42,7 +40,7 @@ const val AnimationDuration = 100
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ClawNavigationBar(
|
fun ClawNavigationBar(
|
||||||
navController: NavController,
|
backStack: SnapshotStateList<Destination>,
|
||||||
items: ImmutableList<NavigationItem>,
|
items: ImmutableList<NavigationItem>,
|
||||||
isVisible: Boolean,
|
isVisible: Boolean,
|
||||||
hazeState: HazeState,
|
hazeState: HazeState,
|
||||||
|
@ -85,10 +83,9 @@ fun ClawNavigationBar(
|
||||||
containerColor =
|
containerColor =
|
||||||
if (HazeDefaults.blurEnabled()) Color.Transparent else MaterialTheme.colorScheme.surface,
|
if (HazeDefaults.blurEnabled()) Color.Transparent else MaterialTheme.colorScheme.surface,
|
||||||
) {
|
) {
|
||||||
val navBackStackEntry = navController.currentBackStackEntryAsState().value
|
val currentDestination = backStack.firstOrNull()
|
||||||
val currentDestination = navBackStackEntry?.destination
|
|
||||||
items.forEach { navItem ->
|
items.forEach { navItem ->
|
||||||
val isSelected = currentDestination.matches(navItem.destination)
|
val isSelected = currentDestination == navItem.destination
|
||||||
NavigationBarItem(
|
NavigationBarItem(
|
||||||
icon = {
|
icon = {
|
||||||
Crossfade(isSelected, label = "nav-label") {
|
Crossfade(isSelected, label = "nav-label") {
|
||||||
|
@ -104,11 +101,7 @@ fun ClawNavigationBar(
|
||||||
if (isSelected) {
|
if (isSelected) {
|
||||||
navItem.listStateResetCallback()
|
navItem.listStateResetCallback()
|
||||||
} else {
|
} else {
|
||||||
navController.navigate(navItem.destination) {
|
backStack.add(navItem.destination)
|
||||||
popUpTo(navController.graph.startDestinationId) { saveState = true }
|
|
||||||
launchSingleTop = true
|
|
||||||
restoreState = true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
modifier = Modifier.testTag(navItem.label.uppercase()),
|
modifier = Modifier.testTag(navItem.label.uppercase()),
|
||||||
|
|
|
@ -6,13 +6,8 @@
|
||||||
*/
|
*/
|
||||||
package dev.msfjarvis.claw.android.ui.screens
|
package dev.msfjarvis.claw.android.ui.screens
|
||||||
|
|
||||||
import android.content.Intent
|
|
||||||
import androidx.activity.compose.LocalActivity
|
import androidx.activity.compose.LocalActivity
|
||||||
import androidx.compose.animation.AnimatedVisibility
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
import androidx.compose.animation.core.tween
|
|
||||||
import androidx.compose.animation.fadeIn
|
|
||||||
import androidx.compose.animation.fadeOut
|
|
||||||
import androidx.compose.foundation.layout.Row
|
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
|
@ -32,6 +27,7 @@ import androidx.compose.material3.windowsizeclass.WindowSizeClass
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateListOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
@ -44,22 +40,17 @@ import androidx.compose.ui.semantics.testTagsAsResourceId
|
||||||
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.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import androidx.navigation.compose.NavHost
|
import androidx.navigation3.runtime.entry
|
||||||
import androidx.navigation.compose.composable
|
import androidx.navigation3.runtime.entryProvider
|
||||||
import androidx.navigation.compose.currentBackStackEntryAsState
|
import androidx.navigation3.ui.NavDisplay
|
||||||
import androidx.navigation.compose.rememberNavController
|
|
||||||
import androidx.navigation.toRoute
|
|
||||||
import androidx.paging.compose.collectAsLazyPagingItems
|
import androidx.paging.compose.collectAsLazyPagingItems
|
||||||
import com.deliveryhero.whetstone.compose.injectedViewModel
|
import com.deliveryhero.whetstone.compose.injectedViewModel
|
||||||
import com.mikepenz.aboutlibraries.ui.compose.m3.LibrariesContainer
|
import com.mikepenz.aboutlibraries.ui.compose.m3.LibrariesContainer
|
||||||
import dev.chrisbanes.haze.HazeState
|
import dev.chrisbanes.haze.HazeState
|
||||||
import dev.chrisbanes.haze.hazeSource
|
|
||||||
import dev.msfjarvis.claw.android.MainActivity
|
import dev.msfjarvis.claw.android.MainActivity
|
||||||
import dev.msfjarvis.claw.android.R
|
import dev.msfjarvis.claw.android.R
|
||||||
import dev.msfjarvis.claw.android.SearchActivity
|
|
||||||
import dev.msfjarvis.claw.android.ui.PostActions
|
import dev.msfjarvis.claw.android.ui.PostActions
|
||||||
import dev.msfjarvis.claw.android.ui.decorations.ClawNavigationBar
|
import dev.msfjarvis.claw.android.ui.decorations.ClawNavigationBar
|
||||||
import dev.msfjarvis.claw.android.ui.decorations.ClawNavigationRail
|
|
||||||
import dev.msfjarvis.claw.android.ui.decorations.NavigationItem
|
import dev.msfjarvis.claw.android.ui.decorations.NavigationItem
|
||||||
import dev.msfjarvis.claw.android.ui.lists.DatabasePosts
|
import dev.msfjarvis.claw.android.ui.lists.DatabasePosts
|
||||||
import dev.msfjarvis.claw.android.ui.lists.NetworkPosts
|
import dev.msfjarvis.claw.android.ui.lists.NetworkPosts
|
||||||
|
@ -67,9 +58,11 @@ import dev.msfjarvis.claw.android.ui.navigation.AboutLibraries
|
||||||
import dev.msfjarvis.claw.android.ui.navigation.AppDestinations
|
import dev.msfjarvis.claw.android.ui.navigation.AppDestinations
|
||||||
import dev.msfjarvis.claw.android.ui.navigation.ClawNavigationType
|
import dev.msfjarvis.claw.android.ui.navigation.ClawNavigationType
|
||||||
import dev.msfjarvis.claw.android.ui.navigation.Comments
|
import dev.msfjarvis.claw.android.ui.navigation.Comments
|
||||||
|
import dev.msfjarvis.claw.android.ui.navigation.Destination
|
||||||
import dev.msfjarvis.claw.android.ui.navigation.Hottest
|
import dev.msfjarvis.claw.android.ui.navigation.Hottest
|
||||||
import dev.msfjarvis.claw.android.ui.navigation.Newest
|
import dev.msfjarvis.claw.android.ui.navigation.Newest
|
||||||
import dev.msfjarvis.claw.android.ui.navigation.Saved
|
import dev.msfjarvis.claw.android.ui.navigation.Saved
|
||||||
|
import dev.msfjarvis.claw.android.ui.navigation.Search
|
||||||
import dev.msfjarvis.claw.android.ui.navigation.Settings
|
import dev.msfjarvis.claw.android.ui.navigation.Settings
|
||||||
import dev.msfjarvis.claw.android.ui.navigation.User
|
import dev.msfjarvis.claw.android.ui.navigation.User
|
||||||
import dev.msfjarvis.claw.android.ui.navigation.any
|
import dev.msfjarvis.claw.android.ui.navigation.any
|
||||||
|
@ -85,26 +78,23 @@ import kotlinx.coroutines.launch
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun LobstersPostsScreen(
|
fun Nav3Screen(
|
||||||
urlLauncher: UrlLauncher,
|
urlLauncher: UrlLauncher,
|
||||||
windowSizeClass: WindowSizeClass,
|
windowSizeClass: WindowSizeClass,
|
||||||
setWebUri: (String?) -> Unit,
|
setWebUri: (String?) -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
viewModel: ClawViewModel = injectedViewModel(),
|
viewModel: ClawViewModel = injectedViewModel(),
|
||||||
) {
|
) {
|
||||||
|
val backStack = remember { mutableStateListOf<Destination>(Hottest) }
|
||||||
|
|
||||||
|
// region Pain
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val activity = LocalActivity.current
|
val activity = LocalActivity.current
|
||||||
val hottestListState = rememberLazyListState()
|
val hottestListState = rememberLazyListState()
|
||||||
val newestListState = rememberLazyListState()
|
val newestListState = rememberLazyListState()
|
||||||
val savedListState = rememberLazyListState()
|
val savedListState = rememberLazyListState()
|
||||||
val navController = rememberNavController()
|
|
||||||
val navBackStackEntry = navController.currentBackStackEntryAsState().value
|
|
||||||
val currentDestination = navBackStackEntry?.destination
|
|
||||||
val coroutineScope = rememberCoroutineScope()
|
val coroutineScope = rememberCoroutineScope()
|
||||||
val snackbarHostState = remember { SnackbarHostState() }
|
val snackbarHostState = remember { SnackbarHostState() }
|
||||||
val postActions = remember {
|
|
||||||
PostActions(context, urlLauncher, viewModel) { navController.navigate(Comments(it)) }
|
|
||||||
}
|
|
||||||
val hazeState = remember { HazeState() }
|
val hazeState = remember { HazeState() }
|
||||||
|
|
||||||
val hottestPosts = viewModel.hottestPosts.collectAsLazyPagingItems()
|
val hottestPosts = viewModel.hottestPosts.collectAsLazyPagingItems()
|
||||||
|
@ -116,7 +106,7 @@ fun LobstersPostsScreen(
|
||||||
val postIdOverride = activity?.intent?.extras?.getString(MainActivity.NAVIGATION_KEY)
|
val postIdOverride = activity?.intent?.extras?.getString(MainActivity.NAVIGATION_KEY)
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
if (postIdOverride != null) {
|
if (postIdOverride != null) {
|
||||||
navController.navigate(Comments(postIdOverride))
|
backStack.add(Comments(postIdOverride))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,16 +127,19 @@ fun LobstersPostsScreen(
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
val navDestinations = navItems.map(NavigationItem::destination).toPersistentList()
|
val navDestinations = navItems.map(NavigationItem::destination).toPersistentList()
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
val postActions = remember {
|
||||||
|
PostActions(context, urlLauncher, viewModel) { backStack.add(Comments(it)) }
|
||||||
|
}
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
topBar = {
|
topBar = {
|
||||||
TopAppBar(
|
TopAppBar(
|
||||||
modifier = Modifier.shadow(8.dp),
|
modifier = Modifier.shadow(8.dp),
|
||||||
navigationIcon = {
|
navigationIcon = {
|
||||||
if (
|
if (backStack.none { it in navDestinations }) {
|
||||||
navController.previousBackStackEntry != null && currentDestination.none(navDestinations)
|
IconButton(onClick = { if (backStack.removeLastOrNull() == null) activity?.finish() }) {
|
||||||
) {
|
|
||||||
IconButton(onClick = { if (!navController.popBackStack()) activity?.finish() }) {
|
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.AutoMirrored.Filled.ArrowBack,
|
imageVector = Icons.AutoMirrored.Filled.ArrowBack,
|
||||||
contentDescription = "Go back to previous screen",
|
contentDescription = "Go back to previous screen",
|
||||||
|
@ -161,18 +154,16 @@ fun LobstersPostsScreen(
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
title = {
|
title = {
|
||||||
if (currentDestination.any(navDestinations)) {
|
if (backStack.any { it in navDestinations }) {
|
||||||
Text(text = stringResource(R.string.app_name), fontWeight = FontWeight.Bold)
|
Text(text = stringResource(R.string.app_name), fontWeight = FontWeight.Bold)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
actions = {
|
actions = {
|
||||||
if (currentDestination.any(navDestinations)) {
|
if (backStack.any { it in navDestinations }) {
|
||||||
IconButton(
|
IconButton(onClick = { backStack.add(Search) }) {
|
||||||
onClick = { context.startActivity(Intent(context, SearchActivity::class.java)) }
|
|
||||||
) {
|
|
||||||
Icon(imageVector = Icons.Filled.Search, contentDescription = "Search posts")
|
Icon(imageVector = Icons.Filled.Search, contentDescription = "Search posts")
|
||||||
}
|
}
|
||||||
IconButton(onClick = { navController.navigate(Settings) }) {
|
IconButton(onClick = { backStack.add(Settings) }) {
|
||||||
Icon(imageVector = Icons.Filled.Tune, contentDescription = "Settings")
|
Icon(imageVector = Icons.Filled.Tune, contentDescription = "Settings")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -182,99 +173,87 @@ fun LobstersPostsScreen(
|
||||||
bottomBar = {
|
bottomBar = {
|
||||||
AnimatedVisibility(visible = navigationType == ClawNavigationType.BOTTOM_NAVIGATION) {
|
AnimatedVisibility(visible = navigationType == ClawNavigationType.BOTTOM_NAVIGATION) {
|
||||||
ClawNavigationBar(
|
ClawNavigationBar(
|
||||||
navController = navController,
|
backStack,
|
||||||
items = navItems,
|
items = navItems,
|
||||||
isVisible = currentDestination.any(navDestinations),
|
isVisible = backStack.any { it in navDestinations },
|
||||||
hazeState = hazeState,
|
hazeState = hazeState,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
snackbarHost = { SnackbarHost(snackbarHostState) },
|
snackbarHost = { SnackbarHost(snackbarHostState) },
|
||||||
modifier = modifier.semantics { testTagsAsResourceId = true },
|
modifier = Modifier.semantics { testTagsAsResourceId = true },
|
||||||
) { contentPadding ->
|
) { contentPadding ->
|
||||||
Row {
|
NavDisplay(
|
||||||
AnimatedVisibility(visible = navigationType == ClawNavigationType.NAVIGATION_RAIL) {
|
backStack = backStack,
|
||||||
ClawNavigationRail(
|
modifier = modifier,
|
||||||
navController = navController,
|
onBack = { backStack.removeLastOrNull() },
|
||||||
items = navItems,
|
entryProvider =
|
||||||
isVisible = currentDestination.any(navDestinations),
|
entryProvider {
|
||||||
)
|
entry<Hottest> {
|
||||||
}
|
setWebUri("https://lobste.rs/")
|
||||||
|
NetworkPosts(
|
||||||
NavHost(
|
lazyPagingItems = hottestPosts,
|
||||||
navController = navController,
|
listState = hottestListState,
|
||||||
startDestination = Hottest,
|
postActions = postActions,
|
||||||
// Make animations 2x faster than default specs
|
contentPadding = contentPadding,
|
||||||
enterTransition = { fadeIn(animationSpec = tween(350)) },
|
)
|
||||||
exitTransition = { fadeOut(animationSpec = tween(350)) },
|
}
|
||||||
modifier = Modifier.hazeSource(hazeState),
|
entry<Newest> {
|
||||||
) {
|
setWebUri("https://lobste.rs/")
|
||||||
composable<Hottest> {
|
NetworkPosts(
|
||||||
setWebUri("https://lobste.rs/")
|
lazyPagingItems = newestPosts,
|
||||||
NetworkPosts(
|
listState = newestListState,
|
||||||
lazyPagingItems = hottestPosts,
|
postActions = postActions,
|
||||||
listState = hottestListState,
|
contentPadding = contentPadding,
|
||||||
postActions = postActions,
|
)
|
||||||
contentPadding = contentPadding,
|
}
|
||||||
)
|
entry<Saved> {
|
||||||
}
|
setWebUri(null)
|
||||||
composable<Newest> {
|
DatabasePosts(
|
||||||
setWebUri("https://lobste.rs/")
|
items = savedPosts,
|
||||||
NetworkPosts(
|
listState = savedListState,
|
||||||
lazyPagingItems = newestPosts,
|
postActions = postActions,
|
||||||
listState = newestListState,
|
contentPadding = contentPadding,
|
||||||
postActions = postActions,
|
)
|
||||||
contentPadding = contentPadding,
|
}
|
||||||
)
|
entry<Settings> {
|
||||||
}
|
SettingsScreen(
|
||||||
composable<Saved> {
|
openInputStream = context.contentResolver::openInputStream,
|
||||||
setWebUri(null)
|
openOutputStream = context.contentResolver::openOutputStream,
|
||||||
DatabasePosts(
|
openLibrariesScreen = { backStack.add(AboutLibraries) },
|
||||||
items = savedPosts,
|
importPosts = viewModel::importPosts,
|
||||||
listState = savedListState,
|
exportPostsAsJson = viewModel::exportPostsAsJson,
|
||||||
postActions = postActions,
|
exportPostsAsHtml = viewModel::exportPostsAsHtml,
|
||||||
contentPadding = contentPadding,
|
snackbarHostState = snackbarHostState,
|
||||||
)
|
contentPadding = contentPadding,
|
||||||
}
|
modifier = Modifier.fillMaxSize(),
|
||||||
composable<Comments> { backStackEntry ->
|
)
|
||||||
val postId = backStackEntry.toRoute<Comments>().postId
|
}
|
||||||
setWebUri("https://lobste.rs/s/$postId")
|
entry<Comments> { dest ->
|
||||||
CommentsPage(
|
CommentsPage(
|
||||||
postId = postId,
|
postId = dest.postId,
|
||||||
postActions = postActions,
|
postActions = postActions,
|
||||||
getSeenComments = viewModel::getSeenComments,
|
getSeenComments = viewModel::getSeenComments,
|
||||||
markSeenComments = viewModel::markSeenComments,
|
markSeenComments = viewModel::markSeenComments,
|
||||||
contentPadding = contentPadding,
|
contentPadding = contentPadding,
|
||||||
openUserProfile = { navController.navigate(User(it)) },
|
openUserProfile = { backStack.add(User(it)) },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
composable<User> { backStackEntry ->
|
entry<User> { dest ->
|
||||||
val username = backStackEntry.toRoute<User>().username
|
UserProfile(
|
||||||
setWebUri("https://lobste.rs/u/$username")
|
username = dest.username,
|
||||||
UserProfile(
|
getProfile = viewModel::getUserProfile,
|
||||||
username = username,
|
contentPadding = contentPadding,
|
||||||
getProfile = viewModel::getUserProfile,
|
openUserProfile = { backStack.add(User(it)) },
|
||||||
contentPadding = contentPadding,
|
)
|
||||||
openUserProfile = { navController.navigate(User(it)) },
|
}
|
||||||
)
|
entry<Search> {
|
||||||
}
|
SearchScreen(urlLauncher = urlLauncher, setWebUri = setWebUri, viewModel = viewModel)
|
||||||
composable<Settings> {
|
}
|
||||||
SettingsScreen(
|
entry<AboutLibraries> {
|
||||||
openInputStream = context.contentResolver::openInputStream,
|
LibrariesContainer(contentPadding = contentPadding, modifier = Modifier.fillMaxSize())
|
||||||
openOutputStream = context.contentResolver::openOutputStream,
|
}
|
||||||
openLibrariesScreen = { navController.navigate(AboutLibraries) },
|
},
|
||||||
importPosts = viewModel::importPosts,
|
)
|
||||||
exportPostsAsJson = viewModel::exportPostsAsJson,
|
|
||||||
exportPostsAsHtml = viewModel::exportPostsAsHtml,
|
|
||||||
snackbarHostState = snackbarHostState,
|
|
||||||
contentPadding = contentPadding,
|
|
||||||
modifier = Modifier.fillMaxSize(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
composable<AboutLibraries> {
|
|
||||||
LibrariesContainer(contentPadding = contentPadding, modifier = Modifier.fillMaxSize())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,234 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright © Harsh Shandilya.
|
|
||||||
* Use of this source code is governed by an MIT-style
|
|
||||||
* license that can be found in the LICENSE file or at
|
|
||||||
* https://opensource.org/licenses/MIT.
|
|
||||||
*/
|
|
||||||
@file:OptIn(ExperimentalMaterial3AdaptiveApi::class)
|
|
||||||
|
|
||||||
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.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
|
|
||||||
import androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi
|
|
||||||
import androidx.compose.material3.adaptive.layout.AnimatedPane
|
|
||||||
import androidx.compose.material3.adaptive.layout.ListDetailPaneScaffold
|
|
||||||
import androidx.compose.material3.adaptive.layout.ListDetailPaneScaffoldRole
|
|
||||||
import androidx.compose.material3.adaptive.layout.PaneAdaptedValue
|
|
||||||
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
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.platform.LocalContext
|
|
||||||
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.AppDestinations
|
|
||||||
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.urllauncher.UrlLauncher
|
|
||||||
import kotlinx.collections.immutable.persistentListOf
|
|
||||||
import kotlinx.collections.immutable.persistentMapOf
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
|
|
||||||
private fun ThreePaneScaffoldNavigator<*>.isListExpanded() =
|
|
||||||
scaffoldValue[ListDetailPaneScaffoldRole.List] == PaneAdaptedValue.Expanded
|
|
||||||
|
|
||||||
private fun ThreePaneScaffoldNavigator<*>.isDetailExpanded() =
|
|
||||||
scaffoldValue[ListDetailPaneScaffoldRole.Detail] == PaneAdaptedValue.Expanded
|
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
|
||||||
@Composable
|
|
||||||
fun TabletScreen(
|
|
||||||
urlLauncher: UrlLauncher,
|
|
||||||
modifier: Modifier = Modifier,
|
|
||||||
viewModel: ClawViewModel = injectedViewModel(),
|
|
||||||
) {
|
|
||||||
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()) {
|
|
||||||
BackNavigationBehavior.PopUntilContentChange
|
|
||||||
} else {
|
|
||||||
BackNavigationBehavior.PopUntilScaffoldValueChange
|
|
||||||
}
|
|
||||||
|
|
||||||
val postActions = remember {
|
|
||||||
PostActions(context, urlLauncher, viewModel) {
|
|
||||||
coroutineScope.launch {
|
|
||||||
navigator.navigateTo(pane = ListDetailPaneScaffoldRole.Detail, contentKey = Comments(it))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val navItems =
|
|
||||||
persistentListOf(
|
|
||||||
NavigationItem(AppDestinations.HOTTEST) {
|
|
||||||
coroutineScope.launch {
|
|
||||||
if (hottestPosts.itemCount > 0) hottestListState.animateScrollToItem(index = 0)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
NavigationItem(AppDestinations.NEWEST) {
|
|
||||||
coroutineScope.launch {
|
|
||||||
if (newestPosts.itemCount > 0) newestListState.animateScrollToItem(index = 0)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
NavigationItem(AppDestinations.SAVED) {
|
|
||||||
coroutineScope.launch {
|
|
||||||
if (savedPosts.isNotEmpty()) savedListState.animateScrollToItem(index = 0)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
BackHandler(navigator.canNavigateBack(backBehavior)) {
|
|
||||||
coroutineScope.launch { navigator.navigateBack(backBehavior) }
|
|
||||||
}
|
|
||||||
|
|
||||||
Scaffold(
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
},
|
|
||||||
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,
|
|
||||||
getSeenComments = viewModel::getSeenComments,
|
|
||||||
markSeenComments = viewModel::markSeenComments,
|
|
||||||
contentPadding = PaddingValues(),
|
|
||||||
modifier = Modifier.fillMaxSize(),
|
|
||||||
openUserProfile = { navController.navigate(User(it)) },
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -1,167 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright © Harsh Shandilya.
|
|
||||||
* Use of this source code is governed by an MIT-style
|
|
||||||
* license that can be found in the LICENSE file or at
|
|
||||||
* https://opensource.org/licenses/MIT.
|
|
||||||
*/
|
|
||||||
package dev.msfjarvis.claw.android.ui.screens
|
|
||||||
|
|
||||||
import androidx.activity.compose.BackHandler
|
|
||||||
import androidx.compose.foundation.layout.Box
|
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
|
||||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
|
||||||
import androidx.compose.material3.Icon
|
|
||||||
import androidx.compose.material3.SnackbarHostState
|
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.material3.adaptive.navigationsuite.NavigationSuiteScaffold
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.runtime.getValue
|
|
||||||
import androidx.compose.runtime.mutableStateListOf
|
|
||||||
import androidx.compose.runtime.remember
|
|
||||||
import androidx.compose.runtime.saveable.rememberSaveable
|
|
||||||
import androidx.compose.ui.Alignment
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.platform.LocalContext
|
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
|
||||||
import androidx.paging.compose.collectAsLazyPagingItems
|
|
||||||
import com.deliveryhero.whetstone.compose.injectedViewModel
|
|
||||||
import com.mikepenz.aboutlibraries.ui.compose.m3.LibrariesContainer
|
|
||||||
import dev.msfjarvis.claw.android.ui.PostActions
|
|
||||||
import dev.msfjarvis.claw.android.ui.lists.DatabasePosts
|
|
||||||
import dev.msfjarvis.claw.android.ui.lists.NetworkPosts
|
|
||||||
import dev.msfjarvis.claw.android.ui.navigation.AboutLibraries
|
|
||||||
import dev.msfjarvis.claw.android.ui.navigation.AppDestinations
|
|
||||||
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.Settings
|
|
||||||
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.urllauncher.UrlLauncher
|
|
||||||
import dev.msfjarvis.claw.common.user.UserProfile
|
|
||||||
import kotlinx.collections.immutable.persistentMapOf
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun TabletScreen2(
|
|
||||||
urlLauncher: UrlLauncher,
|
|
||||||
setWebUri: (String?) -> Unit,
|
|
||||||
modifier: Modifier = Modifier,
|
|
||||||
viewModel: ClawViewModel = injectedViewModel(),
|
|
||||||
) {
|
|
||||||
// TODO: Needs a custom Saver implementation, should probably be an ArrayDeque
|
|
||||||
val navigationBackStack = rememberSaveable {
|
|
||||||
mutableStateListOf(AppDestinations.HOTTEST.destination)
|
|
||||||
}
|
|
||||||
|
|
||||||
val context = LocalContext.current
|
|
||||||
val hottestListState = rememberLazyListState()
|
|
||||||
val newestListState = rememberLazyListState()
|
|
||||||
val savedListState = rememberLazyListState()
|
|
||||||
val snackbarHostState = remember { SnackbarHostState() }
|
|
||||||
val postActions = remember {
|
|
||||||
PostActions(context, urlLauncher, viewModel) { navigationBackStack.add(Comments(it)) }
|
|
||||||
}
|
|
||||||
|
|
||||||
val hottestPosts = viewModel.hottestPosts.collectAsLazyPagingItems()
|
|
||||||
val newestPosts = viewModel.newestPosts.collectAsLazyPagingItems()
|
|
||||||
val savedPosts by viewModel.savedPostsByMonth.collectAsStateWithLifecycle(persistentMapOf())
|
|
||||||
|
|
||||||
BackHandler(navigationBackStack.size > 1) {
|
|
||||||
navigationBackStack.removeAt(navigationBackStack.size - 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
val contentPadding = PaddingValues()
|
|
||||||
|
|
||||||
NavigationSuiteScaffold(
|
|
||||||
navigationSuiteItems = {
|
|
||||||
AppDestinations.entries.forEach {
|
|
||||||
item(
|
|
||||||
icon = { Icon(imageVector = it.icon, contentDescription = it.label) },
|
|
||||||
selected = it.destination == navigationBackStack.first(),
|
|
||||||
onClick = { navigationBackStack.add(it.destination) },
|
|
||||||
)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
modifier = modifier,
|
|
||||||
) {
|
|
||||||
when (navigationBackStack.first()) {
|
|
||||||
AboutLibraries -> {
|
|
||||||
LibrariesContainer(contentPadding = contentPadding, modifier = Modifier.fillMaxSize())
|
|
||||||
}
|
|
||||||
Hottest -> {
|
|
||||||
setWebUri("https://lobste.rs/")
|
|
||||||
NetworkPosts(
|
|
||||||
lazyPagingItems = hottestPosts,
|
|
||||||
listState = hottestListState,
|
|
||||||
postActions = postActions,
|
|
||||||
contentPadding = contentPadding,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Newest -> {
|
|
||||||
setWebUri("https://lobste.rs/")
|
|
||||||
NetworkPosts(
|
|
||||||
lazyPagingItems = newestPosts,
|
|
||||||
listState = newestListState,
|
|
||||||
postActions = postActions,
|
|
||||||
contentPadding = contentPadding,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Saved -> {
|
|
||||||
setWebUri(null)
|
|
||||||
DatabasePosts(
|
|
||||||
items = savedPosts,
|
|
||||||
listState = savedListState,
|
|
||||||
postActions = postActions,
|
|
||||||
contentPadding = contentPadding,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Settings -> {
|
|
||||||
setWebUri(null)
|
|
||||||
SettingsScreen(
|
|
||||||
openInputStream = context.contentResolver::openInputStream,
|
|
||||||
openOutputStream = context.contentResolver::openOutputStream,
|
|
||||||
openLibrariesScreen = { navigationBackStack.add(AboutLibraries) },
|
|
||||||
importPosts = viewModel::importPosts,
|
|
||||||
exportPostsAsJson = viewModel::exportPostsAsJson,
|
|
||||||
exportPostsAsHtml = viewModel::exportPostsAsHtml,
|
|
||||||
snackbarHostState = snackbarHostState,
|
|
||||||
contentPadding = contentPadding,
|
|
||||||
modifier = Modifier.fillMaxSize(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
is Comments -> {
|
|
||||||
val postId = (navigationBackStack.first() as Comments).postId
|
|
||||||
setWebUri("https://lobste.rs/s/$postId")
|
|
||||||
CommentsPage(
|
|
||||||
postId = postId,
|
|
||||||
postActions = postActions,
|
|
||||||
getSeenComments = viewModel::getSeenComments,
|
|
||||||
markSeenComments = viewModel::markSeenComments,
|
|
||||||
contentPadding = contentPadding,
|
|
||||||
openUserProfile = { navigationBackStack.add(User(it)) },
|
|
||||||
)
|
|
||||||
}
|
|
||||||
is User -> {
|
|
||||||
val username = (navigationBackStack.first() as User).username
|
|
||||||
setWebUri("https://lobste.rs/u/$username")
|
|
||||||
UserProfile(
|
|
||||||
username = username,
|
|
||||||
getProfile = viewModel::getUserProfile,
|
|
||||||
contentPadding = contentPadding,
|
|
||||||
openUserProfile = { navigationBackStack.add(User(it)) },
|
|
||||||
)
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
Box(Modifier.fillMaxSize()) {
|
|
||||||
Text(
|
|
||||||
text = "Unexpected destination: ${navigationBackStack.first()}, please report this bug",
|
|
||||||
modifier = Modifier.align(Alignment.Center),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -17,6 +17,7 @@ kotlinResult = "2.0.1"
|
||||||
leakcanary = "3.0-alpha-8"
|
leakcanary = "3.0-alpha-8"
|
||||||
lifecycle = "2.9.0"
|
lifecycle = "2.9.0"
|
||||||
navigation = "2.9.0"
|
navigation = "2.9.0"
|
||||||
|
navigation3 = "1.0.0-alpha02"
|
||||||
retrofit = "3.0.0"
|
retrofit = "3.0.0"
|
||||||
richtext = "1.0.0-alpha02"
|
richtext = "1.0.0-alpha02"
|
||||||
sentry-sdk = "8.12.0"
|
sentry-sdk = "8.12.0"
|
||||||
|
@ -55,6 +56,8 @@ androidx-core-splashscreen = "androidx.core:core-splashscreen:1.2.0-beta02"
|
||||||
androidx-lifecycle-compose = { module = "androidx.lifecycle:lifecycle-viewmodel-compose", version.ref = "lifecycle" }
|
androidx-lifecycle-compose = { module = "androidx.lifecycle:lifecycle-viewmodel-compose", version.ref = "lifecycle" }
|
||||||
androidx-lint-gradle = "androidx.lint:lint-gradle:1.0.0-alpha05"
|
androidx-lint-gradle = "androidx.lint:lint-gradle:1.0.0-alpha05"
|
||||||
androidx-navigation-compose = { module = "androidx.navigation:navigation-compose", version.ref = "navigation" }
|
androidx-navigation-compose = { module = "androidx.navigation:navigation-compose", version.ref = "navigation" }
|
||||||
|
androidx-navigation3-runtime = { module = "androidx.navigation3:navigation3-runtime", version.ref = "navigation3" }
|
||||||
|
androidx-navigation3-ui = { module = "androidx.navigation3:navigation3-ui", version.ref = "navigation3" }
|
||||||
androidx-paging-compose = "androidx.paging:paging-compose:3.3.6"
|
androidx-paging-compose = "androidx.paging:paging-compose:3.3.6"
|
||||||
androidx-profileinstaller = "androidx.profileinstaller:profileinstaller:1.4.1"
|
androidx-profileinstaller = "androidx.profileinstaller:profileinstaller:1.4.1"
|
||||||
androidx-test-core = { module = "androidx.test:core", version.ref = "androidx-test" }
|
androidx-test-core = { module = "androidx.test:core", version.ref = "androidx-test" }
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue