diff --git a/android/build.gradle.kts b/android/build.gradle.kts
index 2fc6a755..caae4f45 100644
--- a/android/build.gradle.kts
+++ b/android/build.gradle.kts
@@ -64,7 +64,6 @@ whetstone {
dependencies {
implementation(platform(libs.androidx.compose.bom))
implementation(platform(libs.okhttp.bom))
- implementation(libs.accompanist.sysuicontroller)
implementation(libs.androidx.activity.compose)
implementation(libs.androidx.compose.material)
implementation(libs.androidx.compose.material.icons.extended)
diff --git a/android/src/main/kotlin/dev/msfjarvis/claw/android/MainActivity.kt b/android/src/main/kotlin/dev/msfjarvis/claw/android/MainActivity.kt
index 8d555323..f2369f3c 100644
--- a/android/src/main/kotlin/dev/msfjarvis/claw/android/MainActivity.kt
+++ b/android/src/main/kotlin/dev/msfjarvis/claw/android/MainActivity.kt
@@ -11,14 +11,16 @@ import android.net.Uri
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
+import androidx.activity.enableEdgeToEdge
import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi
import androidx.compose.material3.windowsizeclass.calculateWindowSizeClass
+import androidx.compose.ui.platform.LocalUriHandler
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
-import androidx.core.view.WindowCompat
import com.deliveryhero.whetstone.Whetstone
import com.deliveryhero.whetstone.activity.ContributesActivityInjector
import dev.msfjarvis.claw.android.ui.LobstersApp
import dev.msfjarvis.claw.common.comments.HTMLConverter
+import dev.msfjarvis.claw.common.theme.LobstersTheme
import dev.msfjarvis.claw.common.urllauncher.UrlLauncher
import javax.inject.Inject
@@ -34,16 +36,20 @@ class MainActivity : ComponentActivity() {
super.onCreate(savedInstanceState)
installSplashScreen()
Whetstone.inject(this)
- WindowCompat.setDecorFitsSystemWindows(window, false)
+ enableEdgeToEdge()
setContent {
val windowSizeClass = calculateWindowSizeClass(this)
-
- LobstersApp(
- urlLauncher = urlLauncher,
- htmlConverter = htmlConverter,
- windowSizeClass = windowSizeClass,
- setWebUri = { url -> webUri = url },
- )
+ LobstersTheme(
+ dynamicColor = true,
+ providedValues = arrayOf(LocalUriHandler provides urlLauncher),
+ ) {
+ LobstersApp(
+ urlLauncher = urlLauncher,
+ htmlConverter = htmlConverter,
+ windowSizeClass = windowSizeClass,
+ setWebUri = { url -> webUri = url },
+ )
+ }
}
}
diff --git a/android/src/main/kotlin/dev/msfjarvis/claw/android/ui/LobstersApp.kt b/android/src/main/kotlin/dev/msfjarvis/claw/android/ui/LobstersApp.kt
index b2a55b94..0f12963e 100644
--- a/android/src/main/kotlin/dev/msfjarvis/claw/android/ui/LobstersApp.kt
+++ b/android/src/main/kotlin/dev/msfjarvis/claw/android/ui/LobstersApp.kt
@@ -39,7 +39,6 @@ import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
-import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.semantics.testTagsAsResourceId
@@ -58,7 +57,6 @@ import dev.msfjarvis.claw.android.ui.datatransfer.DataTransferScreen
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.TransparentSystemBars
import dev.msfjarvis.claw.android.ui.lists.DatabasePosts
import dev.msfjarvis.claw.android.ui.lists.NetworkPosts
import dev.msfjarvis.claw.android.ui.lists.SearchList
@@ -68,7 +66,6 @@ import dev.msfjarvis.claw.android.viewmodel.ClawViewModel
import dev.msfjarvis.claw.api.LobstersApi
import dev.msfjarvis.claw.common.comments.CommentsPage
import dev.msfjarvis.claw.common.comments.HTMLConverter
-import dev.msfjarvis.claw.common.theme.LobstersTheme
import dev.msfjarvis.claw.common.ui.decorations.ClawAppBar
import dev.msfjarvis.claw.common.urllauncher.UrlLauncher
import dev.msfjarvis.claw.common.user.UserProfile
@@ -104,193 +101,186 @@ fun LobstersApp(
val navigationType = ClawNavigationType.fromSize(windowSizeClass.widthSizeClass)
- LobstersTheme(
- dynamicColor = true,
- providedValues = arrayOf(LocalUriHandler provides urlLauncher),
- ) {
- val navItems =
- persistentListOf(
- NavigationItem(
- label = "Hottest",
- route = Destinations.Hottest.route,
- icon = Icons.Outlined.Whatshot,
- selectedIcon = Icons.Filled.Whatshot,
- ) {
- coroutineScope.launch { hottestListState.animateScrollToItem(index = 0) }
- },
- NavigationItem(
- label = "Newest",
- route = Destinations.Newest.route,
- icon = Icons.Outlined.NewReleases,
- selectedIcon = Icons.Filled.NewReleases,
- ) {
- coroutineScope.launch { newestListState.animateScrollToItem(index = 0) }
- },
- NavigationItem(
- label = "Saved",
- route = Destinations.Saved.route,
- icon = Icons.Outlined.FavoriteBorder,
- selectedIcon = Icons.Filled.Favorite,
- ) {
- coroutineScope.launch { savedListState.animateScrollToItem(index = 0) }
- },
- NavigationItem(
- label = "Search",
- route = Destinations.Search.route,
- icon = Icons.Outlined.Search,
- selectedIcon = Icons.Filled.Search,
- ) {
- coroutineScope.launch { searchListState.animateScrollToItem(index = 0) }
- },
- )
+ val navItems =
+ persistentListOf(
+ NavigationItem(
+ label = "Hottest",
+ route = Destinations.Hottest.route,
+ icon = Icons.Outlined.Whatshot,
+ selectedIcon = Icons.Filled.Whatshot,
+ ) {
+ coroutineScope.launch { hottestListState.animateScrollToItem(index = 0) }
+ },
+ NavigationItem(
+ label = "Newest",
+ route = Destinations.Newest.route,
+ icon = Icons.Outlined.NewReleases,
+ selectedIcon = Icons.Filled.NewReleases,
+ ) {
+ coroutineScope.launch { newestListState.animateScrollToItem(index = 0) }
+ },
+ NavigationItem(
+ label = "Saved",
+ route = Destinations.Saved.route,
+ icon = Icons.Outlined.FavoriteBorder,
+ selectedIcon = Icons.Filled.Favorite,
+ ) {
+ coroutineScope.launch { savedListState.animateScrollToItem(index = 0) }
+ },
+ NavigationItem(
+ label = "Search",
+ route = Destinations.Search.route,
+ icon = Icons.Outlined.Search,
+ selectedIcon = Icons.Filled.Search,
+ ) {
+ coroutineScope.launch { searchListState.animateScrollToItem(index = 0) }
+ },
+ )
- TransparentSystemBars()
-
- Scaffold(
- topBar = {
- if (currentDestination != Destinations.Search.route) {
- ClawAppBar(
- navigationIcon = {
- if (
- navController.previousBackStackEntry != null &&
- navItems.none { it.route == currentDestination }
+ Scaffold(
+ topBar = {
+ if (currentDestination != Destinations.Search.route) {
+ ClawAppBar(
+ navigationIcon = {
+ if (
+ navController.previousBackStackEntry != null &&
+ navItems.none { it.route == currentDestination }
+ ) {
+ IconButton(
+ onClick = { if (!navController.popBackStack()) context.getActivity()?.finish() },
) {
- IconButton(
- onClick = { if (!navController.popBackStack()) context.getActivity()?.finish() },
- ) {
- Icon(
- imageVector = Icons.Filled.ArrowBack,
- contentDescription = "Go back to previous screen",
- )
- }
+ Icon(
+ imageVector = Icons.Filled.ArrowBack,
+ contentDescription = "Go back to previous screen",
+ )
}
- },
- title = {
- if (navItems.any { it.route == currentDestination }) {
- Text(text = stringResource(R.string.app_name), fontWeight = FontWeight.Bold)
+ }
+ },
+ title = {
+ if (navItems.any { it.route == currentDestination }) {
+ Text(text = stringResource(R.string.app_name), fontWeight = FontWeight.Bold)
+ }
+ },
+ actions = {
+ if (navItems.any { it.route == currentDestination }) {
+ IconButton(onClick = { navController.navigate(Destinations.DataTransfer.route) }) {
+ Icon(
+ imageVector = Icons.Filled.ImportExport,
+ contentDescription = "Data transfer options",
+ )
}
- },
- actions = {
- if (navItems.any { it.route == currentDestination }) {
- IconButton(onClick = { navController.navigate(Destinations.DataTransfer.route) }) {
- Icon(
- imageVector = Icons.Filled.ImportExport,
- contentDescription = "Data transfer options",
- )
- }
- }
- },
- )
- }
- },
- bottomBar = {
- AnimatedVisibility(visible = navigationType == ClawNavigationType.BOTTOM_NAVIGATION) {
- ClawNavigationBar(
- navController = navController,
- items = navItems,
- isVisible = navItems.any { it.route == currentDestination },
- )
- }
- },
- snackbarHost = { SnackbarHost(snackbarHostState) },
- modifier = modifier.semantics { testTagsAsResourceId = true },
- ) { paddingValues ->
- Row(modifier = Modifier.padding(paddingValues)) {
- AnimatedVisibility(visible = navigationType == ClawNavigationType.NAVIGATION_RAIL) {
- ClawNavigationRail(
- navController = navController,
- items = navItems,
- isVisible = navItems.any { it.route == currentDestination },
- )
- }
+ }
+ },
+ )
+ }
+ },
+ bottomBar = {
+ AnimatedVisibility(visible = navigationType == ClawNavigationType.BOTTOM_NAVIGATION) {
+ ClawNavigationBar(
+ navController = navController,
+ items = navItems,
+ isVisible = navItems.any { it.route == currentDestination },
+ )
+ }
+ },
+ snackbarHost = { SnackbarHost(snackbarHostState) },
+ modifier = modifier.semantics { testTagsAsResourceId = true },
+ ) { paddingValues ->
+ Row(modifier = Modifier.padding(paddingValues)) {
+ AnimatedVisibility(visible = navigationType == ClawNavigationType.NAVIGATION_RAIL) {
+ ClawNavigationRail(
+ navController = navController,
+ items = navItems,
+ isVisible = navItems.any { it.route == currentDestination },
+ )
+ }
- NavHost(
- navController = navController,
- startDestination = Destinations.startDestination.route,
- // Make animations 2x faster than default specs
- enterTransition = { fadeIn(animationSpec = tween(350)) },
- exitTransition = { fadeOut(animationSpec = tween(350)) },
- ) {
- val uri = LobstersApi.BASE_URL
- composable(route = Destinations.Hottest.route) {
- setWebUri("https://lobste.rs/")
- NetworkPosts(
- lazyPagingItems = hottestPosts,
- listState = hottestListState,
- isPostSaved = viewModel::isPostSaved,
- isPostRead = viewModel::isPostRead,
- postActions = postActions,
- )
- }
- composable(route = Destinations.Newest.route) {
- setWebUri("https://lobste.rs/")
- NetworkPosts(
- lazyPagingItems = newestPosts,
- listState = newestListState,
- isPostSaved = viewModel::isPostSaved,
- isPostRead = viewModel::isPostRead,
- postActions = postActions,
- )
- }
- composable(route = Destinations.Saved.route) {
- setWebUri(null)
- DatabasePosts(
- items = savedPosts,
- listState = savedListState,
- postActions = postActions,
- )
- }
- composable(Destinations.Search.route) {
- setWebUri("https://lobste.rs/search")
- SearchList(
- items = viewModel.searchResults,
- listState = searchListState,
- isPostSaved = viewModel::isPostSaved,
- postActions = postActions,
- searchQuery = viewModel.searchQuery,
- setSearchQuery = { query -> viewModel.searchQuery = query },
- )
- }
- composable(
- route = Destinations.Comments.route,
- arguments = listOf(navArgument("postId") { type = NavType.StringType }),
- deepLinks =
- listOf(
- navDeepLink { uriPattern = "$uri/s/${Destinations.Comments.placeholder}/.*" },
- navDeepLink { uriPattern = "$uri/s/${Destinations.Comments.placeholder}" },
- ),
- ) { backStackEntry ->
- val postId = requireNotNull(backStackEntry.arguments?.getString("postId"))
- setWebUri("https://lobste.rs/s/$postId")
- CommentsPage(
- postId = postId,
- postActions = postActions,
- htmlConverter = htmlConverter,
- getSeenComments = viewModel::getSeenComments,
- markSeenComments = viewModel::markSeenComments,
- )
- }
- composable(
- route = Destinations.User.route,
- arguments = listOf(navArgument("username") { type = NavType.StringType }),
- deepLinks =
- listOf(navDeepLink { uriPattern = "$uri/u/${Destinations.User.placeholder}" }),
- ) { backStackEntry ->
- val username = requireNotNull(backStackEntry.arguments?.getString("username"))
- setWebUri("https://lobste.rs/u/$username")
- UserProfile(
- username = username,
- getProfile = viewModel::getUserProfile,
- )
- }
- composable(route = Destinations.DataTransfer.route) {
- DataTransferScreen(
- context = context,
- importPosts = viewModel::importPosts,
- exportPosts = viewModel::exportPosts,
- snackbarHostState = snackbarHostState,
- )
- }
+ NavHost(
+ navController = navController,
+ startDestination = Destinations.startDestination.route,
+ // Make animations 2x faster than default specs
+ enterTransition = { fadeIn(animationSpec = tween(350)) },
+ exitTransition = { fadeOut(animationSpec = tween(350)) },
+ ) {
+ val uri = LobstersApi.BASE_URL
+ composable(route = Destinations.Hottest.route) {
+ setWebUri("https://lobste.rs/")
+ NetworkPosts(
+ lazyPagingItems = hottestPosts,
+ listState = hottestListState,
+ isPostSaved = viewModel::isPostSaved,
+ isPostRead = viewModel::isPostRead,
+ postActions = postActions,
+ )
+ }
+ composable(route = Destinations.Newest.route) {
+ setWebUri("https://lobste.rs/")
+ NetworkPosts(
+ lazyPagingItems = newestPosts,
+ listState = newestListState,
+ isPostSaved = viewModel::isPostSaved,
+ isPostRead = viewModel::isPostRead,
+ postActions = postActions,
+ )
+ }
+ composable(route = Destinations.Saved.route) {
+ setWebUri(null)
+ DatabasePosts(
+ items = savedPosts,
+ listState = savedListState,
+ postActions = postActions,
+ )
+ }
+ composable(Destinations.Search.route) {
+ setWebUri("https://lobste.rs/search")
+ SearchList(
+ items = viewModel.searchResults,
+ listState = searchListState,
+ isPostSaved = viewModel::isPostSaved,
+ postActions = postActions,
+ searchQuery = viewModel.searchQuery,
+ setSearchQuery = { query -> viewModel.searchQuery = query },
+ )
+ }
+ composable(
+ route = Destinations.Comments.route,
+ arguments = listOf(navArgument("postId") { type = NavType.StringType }),
+ deepLinks =
+ listOf(
+ navDeepLink { uriPattern = "$uri/s/${Destinations.Comments.placeholder}/.*" },
+ navDeepLink { uriPattern = "$uri/s/${Destinations.Comments.placeholder}" },
+ ),
+ ) { backStackEntry ->
+ val postId = requireNotNull(backStackEntry.arguments?.getString("postId"))
+ setWebUri("https://lobste.rs/s/$postId")
+ CommentsPage(
+ postId = postId,
+ postActions = postActions,
+ htmlConverter = htmlConverter,
+ getSeenComments = viewModel::getSeenComments,
+ markSeenComments = viewModel::markSeenComments,
+ )
+ }
+ composable(
+ route = Destinations.User.route,
+ arguments = listOf(navArgument("username") { type = NavType.StringType }),
+ deepLinks =
+ listOf(navDeepLink { uriPattern = "$uri/u/${Destinations.User.placeholder}" }),
+ ) { backStackEntry ->
+ val username = requireNotNull(backStackEntry.arguments?.getString("username"))
+ setWebUri("https://lobste.rs/u/$username")
+ UserProfile(
+ username = username,
+ getProfile = viewModel::getUserProfile,
+ )
+ }
+ composable(route = Destinations.DataTransfer.route) {
+ DataTransferScreen(
+ context = context,
+ importPosts = viewModel::importPosts,
+ exportPosts = viewModel::exportPosts,
+ snackbarHostState = snackbarHostState,
+ )
}
}
}
diff --git a/android/src/main/kotlin/dev/msfjarvis/claw/android/ui/decorations/TransparentSystemBars.kt b/android/src/main/kotlin/dev/msfjarvis/claw/android/ui/decorations/TransparentSystemBars.kt
deleted file mode 100644
index fa4d7123..00000000
--- a/android/src/main/kotlin/dev/msfjarvis/claw/android/ui/decorations/TransparentSystemBars.kt
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright © 2023 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.decorations
-
-import androidx.compose.foundation.isSystemInDarkTheme
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.DisposableEffect
-import androidx.compose.ui.graphics.Color
-import com.google.accompanist.systemuicontroller.rememberSystemUiController
-
-@Composable
-fun TransparentSystemBars() {
- val systemUiController = rememberSystemUiController()
- val useDarkIcons = !isSystemInDarkTheme()
-
- DisposableEffect(systemUiController, useDarkIcons) {
- systemUiController.setSystemBarsColor(color = Color.Transparent, darkIcons = useDarkIcons)
-
- onDispose {}
- }
-}
diff --git a/android/src/main/res/values-night/bools.xml b/android/src/main/res/values-night/bools.xml
deleted file mode 100644
index 5aa45310..00000000
--- a/android/src/main/res/values-night/bools.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
- false
-
diff --git a/android/src/main/res/values/bools.xml b/android/src/main/res/values/bools.xml
deleted file mode 100644
index 13c4d573..00000000
--- a/android/src/main/res/values/bools.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
- true
-
diff --git a/android/src/main/res/values/themes.xml b/android/src/main/res/values/themes.xml
index 8b622cca..a5e498e2 100644
--- a/android/src/main/res/values/themes.xml
+++ b/android/src/main/res/values/themes.xml
@@ -19,7 +19,5 @@
- true
-
+
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index be7c6bee..3dfe8558 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -1,5 +1,4 @@
[versions]
-accompanist = "0.33.0-alpha"
agp = "8.2.0-alpha16"
benchmark = "1.2.0-beta03"
coil = "2.4.0"
@@ -18,8 +17,7 @@ whetstone = "0.6.0"
workmanager = "2.9.0-alpha02"
[libraries]
-accompanist-sysuicontroller = { module = "com.google.accompanist:accompanist-systemuicontroller", version.ref = "accompanist" }
-androidx-activity-compose = "androidx.activity:activity-compose:1.7.2"
+androidx-activity-compose = "androidx.activity:activity-compose:1.8.0-alpha06"
androidx-benchmark-macro-junit4 = { module = "androidx.benchmark:benchmark-macro-junit4", version.ref = "benchmark" }
androidx-browser = "androidx.browser:browser:1.6.0"
androidx-compose-animation = { module = "androidx.compose.animation:animation" }