Compare commits

...

8 Commits

Author SHA1 Message Date
Harsh Shandilya 9c0c270f5c chore: refresh feature graphic 2024-05-08 22:53:00 +05:30
Harsh Shandilya 8a9cc844b9 fix(deps): upgrade Compose Compiler to 1.5.14-dev-k1.9.24-50022def4af 2024-05-08 20:11:44 +05:30
renovate[bot] 452ba7dbf9
chore(deps): update kotlin and compose 2024-05-08 14:03:41 +00:00
Harsh Shandilya 9edfc23ee3 Merge remote-tracking branches 'origin/renovate/sentry' and 'origin/renovate/github-codeql-action-3.x'
* origin/renovate/sentry:
  fix(deps): update sentry to v7.9.0

* origin/renovate/github-codeql-action-3.x:
  chore(deps): update github/codeql-action action to v3.25.4
2024-05-08 19:32:17 +05:30
renovate[bot] 3057f5fede
fix(deps): update sentry to v7.9.0 2024-05-08 13:59:12 +00:00
renovate[bot] 157748bc61
chore(deps): update github/codeql-action action to v3.25.4 2024-05-08 13:59:06 +00:00
Harsh Shandilya 68a5de84f7 Revert "refactor(android): migrate to navigation safe-args"
This reverts commit 127a69249e.
2024-05-08 19:28:24 +05:30
Harsh Shandilya b69fa43d29 Revert "fix(android): correct navigation route for attribution page"
This reverts commit 60a7b815ea.
2024-05-08 19:24:05 +05:30
15 changed files with 174 additions and 144 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 262 KiB

After

Width:  |  Height:  |  Size: 313 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 261 KiB

After

Width:  |  Height:  |  Size: 310 KiB

View File

@ -29,7 +29,7 @@ jobs:
cache-read-only: true
- name: Initialize CodeQL
uses: github/codeql-action/init@d39d31e687223d841ef683f52467bd88e9b21c14 # v3.25.3
uses: github/codeql-action/init@ccf74c947955fd1cf117aef6a0e4e66191ef6f61 # v3.25.4
with:
languages: java
tools: latest
@ -41,7 +41,7 @@ jobs:
./gradlew assembleDebug assembleInternal
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@d39d31e687223d841ef683f52467bd88e9b21c14 # v3.25.3
uses: github/codeql-action/analyze@ccf74c947955fd1cf117aef6a0e4e66191ef6f61 # v3.25.4
with:
category: "/language:java"
mobsfscan:
@ -62,6 +62,6 @@ jobs:
args: . --sarif --output results.sarif || true
- name: Upload mobsfscan report
uses: github/codeql-action/upload-sarif@d39d31e687223d841ef683f52467bd88e9b21c14 # v3.25.3
uses: github/codeql-action/upload-sarif@ccf74c947955fd1cf117aef6a0e4e66191ef6f61 # v3.25.4
with:
sarif_file: results.sarif

View File

@ -20,8 +20,6 @@ plugins {
alias(libs.plugins.baselineprofile)
alias(libs.plugins.licensee)
alias(libs.plugins.tracelog)
alias(libs.plugins.kotlin.serialization)
alias(libs.plugins.navigation.safeargs)
}
android {

View File

@ -22,9 +22,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.testTag
import androidx.navigation.NavController
import androidx.navigation.compose.currentBackStackEntryAsState
import dev.msfjarvis.claw.android.ui.matches
import dev.msfjarvis.claw.android.ui.navigation.Destination
import dev.msfjarvis.claw.android.ui.navigation.Destinations
import kotlinx.collections.immutable.ImmutableList
const val AnimationDuration = 100
@ -53,13 +51,11 @@ fun ClawNavigationBar(
modifier = Modifier,
) {
NavigationBar(modifier = modifier) {
val navBackStackEntry = navController.currentBackStackEntryAsState().value
val currentDestination = navBackStackEntry?.destination
items.forEach { navItem ->
val isSelected = currentDestination.matches(navItem.destination)
val isCurrentDestination = navController.currentDestination?.route == navItem.route
NavigationBarItem(
icon = {
Crossfade(isSelected, label = "nav-label") {
Crossfade(isCurrentDestination, label = "nav-label") {
Icon(
imageVector = if (it) navItem.selectedIcon else navItem.icon,
contentDescription = navItem.label.replaceFirstChar(Char::uppercase),
@ -67,15 +63,16 @@ fun ClawNavigationBar(
}
},
label = { Text(text = navItem.label) },
selected = isSelected,
selected = isCurrentDestination,
onClick = {
if (isSelected) {
if (isCurrentDestination) {
navItem.listStateResetCallback()
} else {
navController.navigate(navItem.destination) {
popUpTo(navController.graph.startDestinationId) { saveState = true }
launchSingleTop = true
restoreState = true
navController.graph.startDestinationRoute?.let { startDestination ->
navController.popBackStack(startDestination, false)
}
if (navItem.route != Destinations.startDestination.route) {
navController.navigate(navItem.route)
}
}
},
@ -88,7 +85,7 @@ fun ClawNavigationBar(
class NavigationItem(
val label: String,
val destination: Destination,
val route: String,
val icon: ImageVector,
val selectedIcon: ImageVector,
val listStateResetCallback: () -> Unit,

View File

@ -22,8 +22,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.testTag
import androidx.navigation.NavController
import androidx.navigation.compose.currentBackStackEntryAsState
import dev.msfjarvis.claw.android.ui.matches
import dev.msfjarvis.claw.android.ui.navigation.Destinations
import kotlinx.collections.immutable.ImmutableList
@Composable
@ -50,14 +49,12 @@ fun ClawNavigationRail(
modifier = Modifier,
) {
NavigationRail(modifier = modifier) {
val navBackStackEntry = navController.currentBackStackEntryAsState().value
val currentDestination = navBackStackEntry?.destination
Spacer(Modifier.weight(1f))
items.forEach { navItem ->
val isSelected = currentDestination.matches(navItem.destination)
val isCurrentDestination = navController.currentDestination?.route == navItem.route
NavigationRailItem(
icon = {
Crossfade(isSelected, label = "nav-label") {
Crossfade(isCurrentDestination, label = "nav-label") {
Icon(
imageVector = if (it) navItem.selectedIcon else navItem.icon,
contentDescription = navItem.label.replaceFirstChar(Char::uppercase),
@ -65,15 +62,16 @@ fun ClawNavigationRail(
}
},
label = { Text(text = navItem.label) },
selected = isSelected,
selected = isCurrentDestination,
onClick = {
if (isSelected) {
if (isCurrentDestination) {
navItem.listStateResetCallback()
} else {
navController.navigate(navItem.destination) {
popUpTo(navController.graph.startDestinationId) { saveState = true }
launchSingleTop = true
restoreState = true
navController.graph.startDestinationRoute?.let { startDestination ->
navController.popBackStack(startDestination, false)
}
if (navItem.route != Destinations.startDestination.route) {
navController.navigate(navItem.route)
}
}
},

View File

@ -12,17 +12,12 @@ import androidx.activity.ComponentActivity
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.navigation.NavController
import androidx.navigation.NavDestination
import androidx.navigation.NavDestination.Companion.hasRoute
import androidx.navigation.NavDestination.Companion.hierarchy
import dev.msfjarvis.claw.android.ui.navigation.Comments
import dev.msfjarvis.claw.android.ui.navigation.Destination
import dev.msfjarvis.claw.android.ui.navigation.Destinations
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.model.LinkMetadata
import dev.msfjarvis.claw.model.UIPost
import kotlinx.collections.immutable.ImmutableList
fun Context.getActivity(): ComponentActivity? {
return when (this) {
@ -47,7 +42,10 @@ fun rememberPostActions(
override fun viewComments(postId: String) {
viewModel.markPostAsRead(postId)
navController.navigate(Comments(postId))
val currentRoute = navController.currentDestination?.route
val newRoute =
Destinations.Comments.route.replace(Destinations.Comments.PLACEHOLDER, postId)
if (currentRoute != Destinations.Comments.route) navController.navigate(newRoute)
}
override fun viewCommentsPage(post: UIPost) {
@ -68,21 +66,3 @@ fun rememberPostActions(
}
}
}
/**
* Walk through the [NavDestination]'s [hierarchy] to see if it has any destination that matches the
* route defined by [dest].
*/
fun NavDestination?.matches(dest: Destination): Boolean {
return this?.hierarchy?.any { it.hasRoute(dest::class) } == true
}
/** Check if this [NavDestination] [matches] any of the potential navigation [destinations]. */
fun NavDestination?.any(destinations: ImmutableList<Destination>): Boolean {
return destinations.any { this?.matches(it) == true }
}
/** Check if this [NavDestination] [matches] none of the potential navigation [destinations]. */
fun NavDestination?.none(destinations: ImmutableList<Destination>): Boolean {
return destinations.none { this?.matches(it) == true }
}

View File

@ -1,27 +0,0 @@
/*
* Copyright © 2024 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.navigation
import kotlinx.serialization.Serializable
sealed interface Destination
@Serializable data object Hottest : Destination
@Serializable data object Newest : Destination
@Serializable data object Saved : Destination
@Serializable data class Comments(val postId: String) : Destination
@Serializable data class User(val username: String) : Destination
@Serializable data object Search : Destination
@Serializable data object Settings : Destination
@Serializable data object AboutLibraries : Destination

View File

@ -0,0 +1,50 @@
/*
* Copyright © 2024 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.navigation
sealed class Destinations {
abstract val route: String
data object Hottest : Destinations() {
override val route = "hottest"
}
data object Newest : Destinations() {
override val route = "newest"
}
data object Saved : Destinations() {
override val route = "saved"
}
data object Comments : Destinations() {
const val PLACEHOLDER = "{postId}"
override val route = "comments/$PLACEHOLDER"
}
data object User : Destinations() {
const val PLACEHOLDER = "{username}"
override val route = "user/$PLACEHOLDER"
}
data object Search : Destinations() {
override val route = "search"
}
data object Settings : Destinations() {
override val route = "settings"
}
data object AboutLibraries : Destinations() {
override val route = "about_libraries"
}
companion object {
val startDestination
get() = Hottest
}
}

View File

@ -52,33 +52,26 @@ import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.semantics.testTagsAsResourceId
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.navigation.NavType
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController
import androidx.navigation.toRoute
import androidx.navigation.navArgument
import androidx.paging.compose.collectAsLazyPagingItems
import com.deliveryhero.whetstone.compose.injectedViewModel
import com.mikepenz.aboutlibraries.ui.compose.m3.LibrariesContainer
import dev.msfjarvis.claw.android.MainActivity
import dev.msfjarvis.claw.android.R
import dev.msfjarvis.claw.android.SearchActivity
import dev.msfjarvis.claw.android.ui.any
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.getActivity
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.ClawNavigationType
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.ui.none
import dev.msfjarvis.claw.android.ui.navigation.Destinations
import dev.msfjarvis.claw.android.ui.rememberPostActions
import dev.msfjarvis.claw.android.viewmodel.ClawViewModel
import dev.msfjarvis.claw.common.comments.CommentsPage
@ -88,7 +81,6 @@ import dev.msfjarvis.claw.common.urllauncher.UrlLauncher
import dev.msfjarvis.claw.common.user.UserProfile
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.persistentMapOf
import kotlinx.collections.immutable.toPersistentList
import kotlinx.coroutines.launch
@OptIn(ExperimentalComposeUiApi::class)
@ -105,11 +97,11 @@ fun LobstersPostsScreen(
val newestListState = rememberLazyListState()
val savedListState = rememberLazyListState()
val navController = rememberNavController()
val navBackStackEntry = navController.currentBackStackEntryAsState().value
val currentDestination = navBackStackEntry?.destination
val coroutineScope = rememberCoroutineScope()
val snackbarHostState = remember { SnackbarHostState() }
val postActions = rememberPostActions(urlLauncher, navController, viewModel)
val backStackEntry by navController.currentBackStackEntryAsState()
val currentDestination = backStackEntry?.destination?.route
val context = LocalContext.current
val hottestPosts = viewModel.hottestPosts.collectAsLazyPagingItems()
@ -121,7 +113,9 @@ fun LobstersPostsScreen(
val postIdOverride = context.getActivity()?.intent?.extras?.getString(MainActivity.NAVIGATION_KEY)
LaunchedEffect(Unit) {
if (postIdOverride != null) {
navController.navigate(Comments(postIdOverride))
navController.navigate(
Destinations.Comments.route.replace(Destinations.Comments.PLACEHOLDER, postIdOverride)
)
}
}
@ -129,7 +123,7 @@ fun LobstersPostsScreen(
persistentListOf(
NavigationItem(
label = "Hottest",
destination = Hottest,
route = Destinations.Hottest.route,
icon = Icons.Outlined.Whatshot,
selectedIcon = Icons.Filled.Whatshot,
) {
@ -139,7 +133,7 @@ fun LobstersPostsScreen(
},
NavigationItem(
label = "Newest",
destination = Newest,
route = Destinations.Newest.route,
icon = Icons.Outlined.NewReleases,
selectedIcon = Icons.Filled.NewReleases,
) {
@ -149,7 +143,7 @@ fun LobstersPostsScreen(
},
NavigationItem(
label = "Saved",
destination = Saved,
route = Destinations.Saved.route,
icon = Icons.Outlined.FavoriteBorder,
selectedIcon = Icons.Filled.Favorite,
) {
@ -158,14 +152,14 @@ fun LobstersPostsScreen(
}
},
)
val navDestinations = navItems.map(NavigationItem::destination).toPersistentList()
Scaffold(
topBar = {
ClawAppBar(
navigationIcon = {
if (
navController.previousBackStackEntry != null && currentDestination.none(navDestinations)
navController.previousBackStackEntry != null &&
navItems.none { it.route == currentDestination }
) {
IconButton(
onClick = { if (!navController.popBackStack()) context.getActivity()?.finish() }
@ -178,7 +172,7 @@ fun LobstersPostsScreen(
}
},
title = {
if (currentDestination.any(navDestinations)) {
if (navItems.any { it.route == currentDestination }) {
Row(verticalAlignment = Alignment.CenterVertically) {
Image(
painter = painterResource(id = R.drawable.ic_launcher_foreground),
@ -191,13 +185,13 @@ fun LobstersPostsScreen(
}
},
actions = {
if (currentDestination.any(navDestinations)) {
if (navItems.any { it.route == currentDestination }) {
IconButton(
onClick = { context.startActivity(Intent(context, SearchActivity::class.java)) }
) {
Icon(imageVector = Icons.Filled.Search, contentDescription = "Search posts")
}
IconButton(onClick = { navController.navigate(Settings) }) {
IconButton(onClick = { navController.navigate(Destinations.Settings.route) }) {
Icon(imageVector = Icons.Filled.Tune, contentDescription = "Settings")
}
}
@ -209,7 +203,7 @@ fun LobstersPostsScreen(
ClawNavigationBar(
navController = navController,
items = navItems,
isVisible = currentDestination.any(navDestinations),
isVisible = navItems.any { it.route == currentDestination },
)
}
},
@ -221,18 +215,18 @@ fun LobstersPostsScreen(
ClawNavigationRail(
navController = navController,
items = navItems,
isVisible = currentDestination.any(navDestinations),
isVisible = navItems.any { it.route == currentDestination },
)
}
NavHost(
navController = navController,
startDestination = Hottest,
startDestination = Destinations.startDestination.route,
// Make animations 2x faster than default specs
enterTransition = { fadeIn(animationSpec = tween(350)) },
exitTransition = { fadeOut(animationSpec = tween(350)) },
) {
composable<Hottest> {
composable(route = Destinations.Hottest.route) {
setWebUri("https://lobste.rs/")
NetworkPosts(
lazyPagingItems = hottestPosts,
@ -240,7 +234,7 @@ fun LobstersPostsScreen(
postActions = postActions,
)
}
composable<Newest> {
composable(route = Destinations.Newest.route) {
setWebUri("https://lobste.rs/")
NetworkPosts(
lazyPagingItems = newestPosts,
@ -248,42 +242,64 @@ fun LobstersPostsScreen(
postActions = postActions,
)
}
composable<Saved> {
composable(route = Destinations.Saved.route) {
setWebUri(null)
DatabasePosts(items = savedPosts, listState = savedListState, postActions = postActions)
}
composable<Comments> { backStackEntry ->
val postId = backStackEntry.toRoute<Comments>().postId
setWebUri("https://lobste.rs/s/${postId}")
composable(
route = Destinations.Comments.route,
arguments = listOf(navArgument("postId") { type = NavType.StringType }),
) { backStackEntry ->
val postId =
requireNotNull(backStackEntry.arguments?.getString("postId")) {
"Navigating to ${Destinations.Comments.route} without necessary 'postId' argument"
}
setWebUri("https://lobste.rs/s/$postId")
CommentsPage(
postId = postId,
postActions = postActions,
htmlConverter = htmlConverter,
getSeenComments = viewModel::getSeenComments,
markSeenComments = viewModel::markSeenComments,
openUserProfile = { navController.navigate(User(it)) },
openUserProfile = {
navController.navigate(
Destinations.User.route.replace(Destinations.User.PLACEHOLDER, it)
)
},
)
}
composable<User> { backStackEntry ->
val username = backStackEntry.toRoute<User>().username
setWebUri("https://lobste.rs/u/${username}")
composable(
route = Destinations.User.route,
arguments = listOf(navArgument("username") { type = NavType.StringType }),
) { backStackEntry ->
val username =
requireNotNull(backStackEntry.arguments?.getString("username")) {
"Navigating to ${Destinations.User.route} without necessary 'username' argument"
}
setWebUri("https://lobste.rs/u/$username")
UserProfile(
username = username,
getProfile = viewModel::getUserProfile,
openUserProfile = { navController.navigate(User(it)) },
openUserProfile = {
navController.navigate(
Destinations.User.route.replace(Destinations.User.PLACEHOLDER, it)
)
},
)
}
composable<Settings> {
composable(route = Destinations.Settings.route) {
SettingsScreen(
context = context,
openLibrariesScreen = { navController.navigate(AboutLibraries) },
openLibrariesScreen = { navController.navigate(Destinations.AboutLibraries.route) },
importPosts = viewModel::importPosts,
exportPostsAsJson = viewModel::exportPostsAsJson,
exportPostsAsHtml = viewModel::exportPostsAsHtml,
snackbarHostState = snackbarHostState,
)
}
composable<AboutLibraries> { LibrariesContainer(modifier = Modifier.fillMaxSize()) }
composable(route = Destinations.AboutLibraries.route) {
LibrariesContainer(modifier = Modifier.fillMaxSize())
}
}
}
}

View File

@ -11,15 +11,14 @@ import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material3.Scaffold
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.navigation.NavType
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import androidx.navigation.toRoute
import androidx.navigation.navArgument
import com.deliveryhero.whetstone.compose.injectedViewModel
import dev.msfjarvis.claw.android.ui.lists.SearchList
import dev.msfjarvis.claw.android.ui.navigation.Comments
import dev.msfjarvis.claw.android.ui.navigation.Search
import dev.msfjarvis.claw.android.ui.navigation.User
import dev.msfjarvis.claw.android.ui.navigation.Destinations
import dev.msfjarvis.claw.android.ui.rememberPostActions
import dev.msfjarvis.claw.android.viewmodel.ClawViewModel
import dev.msfjarvis.claw.common.comments.CommentsPage
@ -41,10 +40,10 @@ fun SearchScreen(
Scaffold(modifier = modifier) { paddingValues ->
NavHost(
navController = navController,
startDestination = Search,
startDestination = Destinations.Search.route,
modifier = Modifier.padding(paddingValues),
) {
composable<Search> {
composable(route = Destinations.Search.route) {
setWebUri("https://lobste.rs/search")
SearchList(
items = viewModel.searchResults,
@ -54,8 +53,14 @@ fun SearchScreen(
setSearchQuery = { query -> viewModel.searchQuery = query },
)
}
composable<Comments> { backStackEntry ->
val postId = backStackEntry.toRoute<Comments>().postId
composable(
route = Destinations.Comments.route,
arguments = listOf(navArgument("postId") { type = NavType.StringType }),
) { backStackEntry ->
val postId =
requireNotNull(backStackEntry.arguments?.getString("postId")) {
"Navigating to ${Destinations.Comments.route} without necessary 'postId' argument"
}
setWebUri("https://lobste.rs/s/$postId")
CommentsPage(
postId = postId,
@ -63,16 +68,30 @@ fun SearchScreen(
htmlConverter = htmlConverter,
getSeenComments = viewModel::getSeenComments,
markSeenComments = viewModel::markSeenComments,
openUserProfile = { navController.navigate(User(it)) },
openUserProfile = { username: String ->
navController.navigate(
Destinations.User.route.replace(Destinations.User.PLACEHOLDER, username)
)
},
)
}
composable<User> { backStackEntry ->
val username = backStackEntry.toRoute<User>().username
composable(
route = Destinations.User.route,
arguments = listOf(navArgument("username") { type = NavType.StringType }),
) { backStackEntry ->
val username =
requireNotNull(backStackEntry.arguments?.getString("username")) {
"Navigating to ${Destinations.User.route} without necessary 'username' argument"
}
setWebUri("https://lobste.rs/u/$username")
UserProfile(
username = username,
getProfile = viewModel::getUserProfile,
openUserProfile = { navController.navigate(User(it)) },
openUserProfile = {
navController.navigate(
Destinations.User.route.replace(Destinations.User.PLACEHOLDER, it)
)
},
)
}
}

View File

@ -33,7 +33,7 @@ class KotlinAndroidPlugin : Plugin<Project> {
project.tasks.withType<KotlinCompile>().configureEach {
compilerOptions.freeCompilerArgs.addAll(
"-P",
"plugin:androidx.compose.compiler.plugins.kotlin:strongSkipping=true",
"plugin:androidx.compose.compiler.plugins.kotlin:featureFlag=StrongSkipping",
)
if (matches != null) {
val (compilerKotlinVersion) = matches.destructured

View File

@ -4,19 +4,18 @@ agp = "8.5.0-alpha08"
benchmark = "1.3.0-alpha04"
coil = "2.6.0"
# @keep used for kotlinCompilerExtensionVersion
composeCompiler = "1.5.13"
composeCompiler = "1.5.14-dev-k1.9.24-50022def4af"
coroutines = "1.8.1-Beta"
dagger = "2.51.1"
glance = "1.0.0"
junit = "5.10.2"
konvert = "3.2.0"
kotlin = "1.9.23"
kotlin = "1.9.24"
kotlinResult = "2.0.0"
lifecycle = "2.8.0-rc01"
navigation = "2.8.0-alpha08"
retrofit = "2.11.0"
richtext = "1.0.0-alpha01"
sentry-sdk = "7.8.0"
sentry-sdk = "7.9.0"
serialization = "1.6.3"
sqldelight = "2.0.2"
whetstone = "0.9.0-beta02"
@ -48,7 +47,7 @@ androidx-lifecycle-common = { module = "androidx.lifecycle:lifecycle-common", ve
androidx-lifecycle-compose = { module = "androidx.lifecycle:lifecycle-viewmodel-compose", version.ref = "lifecycle" }
androidx-lifecycle-runtime = { module = "androidx.lifecycle:lifecycle-runtime", version.ref = "lifecycle" }
androidx-lint = "androidx.lint:lint-gradle:1.0.0-alpha01"
androidx-navigation-compose = { module = "androidx.navigation:navigation-compose", version.ref = "navigation" }
androidx-navigation-compose = "androidx.navigation:navigation-compose:2.8.0-alpha08"
androidx-paging-compose = "androidx.paging:paging-compose:3.3.0-rc01"
androidx-profileinstaller = "androidx.profileinstaller:profileinstaller:1.4.0-alpha01"
androidx-test-core = "androidx.test:core:1.6.0-alpha06"
@ -120,10 +119,9 @@ anvil = "com.squareup.anvil:2.5.0-beta08"
baselineprofile = { id = "androidx.baselineprofile", version.ref = "benchmark" }
dependencyAnalysis = "com.autonomousapps.dependency-analysis:1.31.0"
kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
ksp = "com.google.devtools.ksp:1.9.23-1.0.20"
ksp = "com.google.devtools.ksp:1.9.24-1.0.20"
licensee = "app.cash.licensee:1.11.0"
modulegraphassert = "com.jraska.module.graph.assertion:2.5.0"
navigation-safeargs = { id = "androidx.navigation.safeargs.kotlin", version.ref = "navigation" }
poko = "dev.drewhamilton.poko:0.15.2"
sqldelight = { id = "app.cash.sqldelight", version.ref = "sqldelight" }
tracelog = "dev.msfjarvis.tracelog:0.1.3"

View File

@ -12,12 +12,14 @@ appId: dev.msfjarvis.claw.android
- waitForAnimationToEnd
- takeScreenshot: "SavedPosts"
- tapOn: "Search posts"
- inputText: "Nix"
- inputText: "Rust"
- pressKey: Enter
- hideKeyboard
- waitForAnimationToEnd
- takeScreenshot: "SearchPage"
- back
# TODO: figure out why do I need to press back twice
- back
- tapOn: "Settings"
- tapOn: "Export"
- takeScreenshot: "SettingsPage"

View File

@ -14,7 +14,6 @@ pluginManagement {
includeGroup("androidx.baselineprofile")
includeGroup("androidx.benchmark")
includeGroup("androidx.databinding")
includeGroupAndSubgroups("androidx.navigation")
includeGroup("com.google.testing.platform")
includeGroupAndSubgroups("com.android")
}