mirror of
https://github.com/msfjarvis/compose-lobsters
synced 2025-08-14 12:57:04 +05:30
android: refactor and extract things from LobstersApp
This commit is contained in:
parent
baa3830966
commit
ad5a01b8d0
4 changed files with 106 additions and 93 deletions
|
@ -1,29 +0,0 @@
|
||||||
package dev.msfjarvis.claw.android.ui
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.os.Build
|
|
||||||
import androidx.compose.foundation.isSystemInDarkTheme
|
|
||||||
import androidx.compose.material3.ColorScheme
|
|
||||||
import androidx.compose.material3.dynamicDarkColorScheme
|
|
||||||
import androidx.compose.material3.dynamicLightColorScheme
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import dev.msfjarvis.claw.common.theme.DarkThemeColors
|
|
||||||
import dev.msfjarvis.claw.common.theme.LightThemeColors
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun decideColorScheme(context: Context): ColorScheme {
|
|
||||||
val isDarkTheme = isSystemInDarkTheme()
|
|
||||||
return if (Build.VERSION.SDK_INT >= 31) {
|
|
||||||
if (isDarkTheme) {
|
|
||||||
dynamicDarkColorScheme(context)
|
|
||||||
} else {
|
|
||||||
dynamicLightColorScheme(context)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (isDarkTheme) {
|
|
||||||
DarkThemeColors
|
|
||||||
} else {
|
|
||||||
LightThemeColors
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -12,10 +12,7 @@ import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.geometry.Offset
|
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
|
|
||||||
import androidx.compose.ui.input.nestedscroll.NestedScrollSource
|
|
||||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.platform.LocalUriHandler
|
import androidx.compose.ui.platform.LocalUriHandler
|
||||||
|
@ -35,8 +32,6 @@ import dev.msfjarvis.claw.common.comments.LocalHTMLConverter
|
||||||
import dev.msfjarvis.claw.common.theme.LobstersTheme
|
import dev.msfjarvis.claw.common.theme.LobstersTheme
|
||||||
import dev.msfjarvis.claw.common.urllauncher.UrlLauncher
|
import dev.msfjarvis.claw.common.urllauncher.UrlLauncher
|
||||||
|
|
||||||
private const val ScrollDelta = 50
|
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun LobstersApp(
|
fun LobstersApp(
|
||||||
|
@ -45,34 +40,19 @@ fun LobstersApp(
|
||||||
htmlConverter: HTMLConverter,
|
htmlConverter: HTMLConverter,
|
||||||
setWebUri: (String) -> Unit,
|
setWebUri: (String) -> Unit,
|
||||||
) {
|
) {
|
||||||
|
var isFabVisible by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
val systemUiController = rememberSystemUiController()
|
val systemUiController = rememberSystemUiController()
|
||||||
val networkListState = rememberLazyListState()
|
val networkListState = rememberLazyListState()
|
||||||
val savedListState = rememberLazyListState()
|
val savedListState = rememberLazyListState()
|
||||||
val navController = rememberNavController()
|
val navController = rememberNavController()
|
||||||
val postActions = rememberPostActions(urlLauncher, navController, viewModel)
|
val postActions = rememberPostActions(urlLauncher, navController, viewModel)
|
||||||
// The destination needs to be tracked here rather than used directly since
|
val currentDestination by currentNavigationDestination(navController)
|
||||||
// `NavController#currentDestination` is not a Composable state.
|
val nestedScrollConnection = rememberNestedScrollConnection { isFabVisible = it }
|
||||||
var currentDestination by remember { mutableStateOf<String?>(null) }
|
|
||||||
var isFabVisible by remember { mutableStateOf(false) }
|
|
||||||
val nestedScrollConnection = remember {
|
|
||||||
object : NestedScrollConnection {
|
|
||||||
override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset {
|
|
||||||
val delta = available.y
|
|
||||||
|
|
||||||
if (delta > ScrollDelta) {
|
val networkPosts = viewModel.pagerFlow.collectAsLazyPagingItems()
|
||||||
isFabVisible = true
|
val savedPosts by viewModel.savedPosts.collectAsState(emptyList())
|
||||||
} else if (delta < -ScrollDelta) {
|
|
||||||
isFabVisible = false
|
|
||||||
}
|
|
||||||
|
|
||||||
// We didn't consume any offset here so return Offset.Zero
|
|
||||||
return Offset.Zero
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
navController.addOnDestinationChangedListener { _, destination, _ ->
|
|
||||||
currentDestination = destination.route ?: Destinations.Hottest.getRoute()
|
|
||||||
}
|
|
||||||
LobstersTheme(
|
LobstersTheme(
|
||||||
LocalUriHandler provides urlLauncher,
|
LocalUriHandler provides urlLauncher,
|
||||||
LocalHTMLConverter provides htmlConverter,
|
LocalHTMLConverter provides htmlConverter,
|
||||||
|
@ -85,8 +65,6 @@ fun LobstersApp(
|
||||||
systemUiController.setStatusBarColor(color = statusBarColor)
|
systemUiController.setStatusBarColor(color = statusBarColor)
|
||||||
systemUiController.setNavigationBarColor(color = Color.Transparent)
|
systemUiController.setNavigationBarColor(color = Color.Transparent)
|
||||||
}
|
}
|
||||||
val networkPosts = viewModel.pagerFlow.collectAsLazyPagingItems()
|
|
||||||
val savedPosts by viewModel.savedPosts.collectAsState(emptyList())
|
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
topBar = { ClawAppBar(modifier = Modifier.statusBarsPadding()) },
|
topBar = { ClawAppBar(modifier = Modifier.statusBarsPadding()) },
|
||||||
|
|
|
@ -1,36 +0,0 @@
|
||||||
package dev.msfjarvis.claw.android.ui
|
|
||||||
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.runtime.remember
|
|
||||||
import androidx.navigation.NavController
|
|
||||||
import dev.msfjarvis.claw.android.viewmodel.ClawViewModel
|
|
||||||
import dev.msfjarvis.claw.common.posts.PostActions
|
|
||||||
import dev.msfjarvis.claw.common.urllauncher.UrlLauncher
|
|
||||||
import dev.msfjarvis.claw.database.local.SavedPost
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun rememberPostActions(
|
|
||||||
urlLauncher: UrlLauncher,
|
|
||||||
navController: NavController,
|
|
||||||
viewModel: ClawViewModel,
|
|
||||||
): PostActions {
|
|
||||||
return remember {
|
|
||||||
object : PostActions {
|
|
||||||
override fun viewPost(postUrl: String, commentsUrl: String) {
|
|
||||||
urlLauncher.openUri(postUrl.ifEmpty { commentsUrl })
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun viewComments(postId: String) {
|
|
||||||
navController.navigate(Destinations.Comments.getRoute(postId))
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun viewCommentsPage(commentsUrl: String) {
|
|
||||||
urlLauncher.openUri(commentsUrl)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun toggleSave(post: SavedPost) {
|
|
||||||
viewModel.toggleSave(post)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
100
android/src/main/kotlin/dev/msfjarvis/claw/android/ui/ext.kt
Normal file
100
android/src/main/kotlin/dev/msfjarvis/claw/android/ui/ext.kt
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
package dev.msfjarvis.claw.android.ui
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.os.Build
|
||||||
|
import androidx.compose.foundation.isSystemInDarkTheme
|
||||||
|
import androidx.compose.material3.ColorScheme
|
||||||
|
import androidx.compose.material3.dynamicDarkColorScheme
|
||||||
|
import androidx.compose.material3.dynamicLightColorScheme
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.State
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.ui.geometry.Offset
|
||||||
|
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
|
||||||
|
import androidx.compose.ui.input.nestedscroll.NestedScrollSource
|
||||||
|
import androidx.navigation.NavController
|
||||||
|
import dev.msfjarvis.claw.android.viewmodel.ClawViewModel
|
||||||
|
import dev.msfjarvis.claw.common.posts.PostActions
|
||||||
|
import dev.msfjarvis.claw.common.theme.DarkThemeColors
|
||||||
|
import dev.msfjarvis.claw.common.theme.LightThemeColors
|
||||||
|
import dev.msfjarvis.claw.common.urllauncher.UrlLauncher
|
||||||
|
import dev.msfjarvis.claw.database.local.SavedPost
|
||||||
|
|
||||||
|
// The destination needs to be tracked like this rather than used directly since
|
||||||
|
// `NavController#currentDestination` is not a Composable state.
|
||||||
|
@Composable
|
||||||
|
fun currentNavigationDestination(navController: NavController): State<String?> {
|
||||||
|
val currentDestination = remember { mutableStateOf<String?>(null) }
|
||||||
|
navController.addOnDestinationChangedListener { _, destination, _ ->
|
||||||
|
currentDestination.value = destination.route
|
||||||
|
}
|
||||||
|
return currentDestination
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun decideColorScheme(context: Context): ColorScheme {
|
||||||
|
val isDarkTheme = isSystemInDarkTheme()
|
||||||
|
return if (Build.VERSION.SDK_INT >= 31) {
|
||||||
|
if (isDarkTheme) {
|
||||||
|
dynamicDarkColorScheme(context)
|
||||||
|
} else {
|
||||||
|
dynamicLightColorScheme(context)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (isDarkTheme) {
|
||||||
|
DarkThemeColors
|
||||||
|
} else {
|
||||||
|
LightThemeColors
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun rememberPostActions(
|
||||||
|
urlLauncher: UrlLauncher,
|
||||||
|
navController: NavController,
|
||||||
|
viewModel: ClawViewModel,
|
||||||
|
): PostActions {
|
||||||
|
return remember {
|
||||||
|
object : PostActions {
|
||||||
|
override fun viewPost(postUrl: String, commentsUrl: String) {
|
||||||
|
urlLauncher.openUri(postUrl.ifEmpty { commentsUrl })
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun viewComments(postId: String) {
|
||||||
|
navController.navigate(Destinations.Comments.getRoute(postId))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun viewCommentsPage(commentsUrl: String) {
|
||||||
|
urlLauncher.openUri(commentsUrl)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toggleSave(post: SavedPost) {
|
||||||
|
viewModel.toggleSave(post)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private const val ScrollDelta = 50
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun rememberNestedScrollConnection(setVisibility: (Boolean) -> Unit): NestedScrollConnection {
|
||||||
|
return remember {
|
||||||
|
object : NestedScrollConnection {
|
||||||
|
override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset {
|
||||||
|
val delta = available.y
|
||||||
|
|
||||||
|
if (delta > ScrollDelta) {
|
||||||
|
setVisibility(true)
|
||||||
|
} else if (delta < -ScrollDelta) {
|
||||||
|
setVisibility(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// We didn't consume any offset here so return Offset.Zero
|
||||||
|
return Offset.Zero
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue