Compare commits

...
25 Commits
Author SHA1 Message Date
GitHub Actions b6421b01ba feat(release): bump version 2022-11-30 14:37:38 +00:00
Harsh Shandilya 9bc4a8c81b fix(readme): use an HTML image to downsize featured graphic 2022-11-30 15:01:20 +05:30
Harsh Shandilya 8cae135784 chore: refresh AGP experimental features opt-in 2022-11-30 14:35:56 +05:30
Harsh Shandilya eba5d64998 refactor: migrate all tests to kotest 2022-11-30 01:47:17 +05:30
Harsh Shandilya 8eec09e832 feat(gradle): add kotest deps 2022-11-30 01:32:15 +05:30
Harsh Shandilya 69537da95b chore: mark baseline profile as generated 2022-11-30 01:04:38 +05:30
Harsh Shandilya a679b88497 chore: update changelog 2022-11-30 01:04:38 +05:30
Harsh Shandilya e570b9d88f feat(android): refresh baseline profile 2022-11-30 01:04:38 +05:30
Harsh Shandilya ce37523e11 fix(benchmark): ensure UiAutomator is able to correctly find UI elements 2022-11-30 01:04:38 +05:30
Harsh Shandilya 3601c190ac fix(benchmark): disable baseline profile benchmark 2022-11-29 21:26:55 +05:30
Harsh Shandilya b0044dd0fc chore(deps): override ProfileInstaller version 2022-11-29 21:22:39 +05:30
Harsh Shandilya b2c2be45bf refactor: cleanup and simplify AndroidCommonPlugin 2022-11-29 21:22:39 +05:30
Harsh Shandilya 6f219b6da2 fix(benchmark): ensure benchmark build type is not obfuscated 2022-11-29 21:22:39 +05:30
Harsh Shandilya 8d6c567c84 refactor: simplify build type configuration 2022-11-29 21:22:39 +05:30
Harsh Shandilya 2b2010a22c fix(ci): only run one instance of snapshot workflow 2022-11-29 18:15:25 +05:30
Harsh Shandilya 27af06e180 chore: try out a full size image 2022-11-29 18:11:46 +05:30
Harsh Shandilya 499088cf43 chore: re-do README screenshot 2022-11-29 18:09:01 +05:30
renovate[bot]andGitHub ce579f21f9 fix(deps): update accompanist to v0.28.0 2022-11-29 04:51:00 +00:00
Harsh Shandilya 5a4643dc57 refactor: start consuming whetstone through Sonatype snapshots repository
It was much easier to set up automatic publishing than to constantly debug weird build errors from included builds
2022-11-29 03:29:06 +05:30
Harsh Shandilya 2a65dc4a9e chore(deps): bump whetstone tag 2022-11-29 02:17:04 +05:30
Harsh Shandilya d08aa25f76 fix: add changelog entry 2022-11-29 01:53:48 +05:30
Harsh Shandilya 410c7ccd1d fix: add missing DI annotation to CoilAppPlugin 2022-11-29 01:53:48 +05:30
Harsh Shandilya 5443cc1486 refactor: simplify swipe to refresh 2022-11-29 01:25:20 +05:30
Harsh Shandilya 683cb0cfbb fix: adjust capitalisation of CI steps 2022-11-28 19:56:59 +05:30
GitHub Actions cbf89b4158 feat(release): start next development iteration 2022-11-28 14:18:53 +00:00
30 changed files with 5376 additions and 3348 deletions
+1
View File
@@ -1,3 +1,4 @@
* text=auto eol=lf
**/dependencies/** linguist-generated
**/clawicons/** linguist-generated
android/src/main/baseline-prof.txt linguist-generated
Binary file not shown.

Before

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 KiB

+3
View File
@@ -10,6 +10,9 @@ on:
branches:
- main
concurrency:
group: ${{ github.workflow }}
jobs:
check:
runs-on: ubuntu-latest
+1 -1
View File
@@ -60,7 +60,7 @@ jobs:
- name: Clean secrets
run: scripts/signing-cleanup.sh
- name: Get Changelog Entry
- name: Get changelog entry
id: changelog_reader
uses: mindsers/changelog-reader-action@b97ce03a10d9bdbb07beb491c76a5a01d78cd3ef # v2.2.2
with:
+10 -1
View File
@@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
## [1.10.0] - 2022-11-30
### Changed
- Configure Coil image loader with better caching settings
- Refresh packaged baseline profile
## [1.9.0] - 2022-11-28
### Changed
@@ -81,7 +88,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Initial Play Store release
[Unreleased]: https://github.com/msfjarvis/compose-lobsters/compare/1.9.0...HEAD
[Unreleased]: https://github.com/msfjarvis/compose-lobsters/compare/1.10.0...HEAD
[1.10.0]: https://github.com/msfjarvis/compose-lobsters/compare/1.9.0...1.10.0
[1.9.0]: https://github.com/msfjarvis/compose-lobsters/compare/1.8.0...1.9.0
+3 -1
View File
@@ -2,7 +2,9 @@
Unofficial Android app for read-only access to [lobste.rs](https://lobste.rs), built with [Jetpack Compose](https://developer.android.com/jetpack/compose).
![Screenshots](./.github/readme_feature.png)
<img src="https://github.com/msfjarvis/compose-lobsters/blob/main/.github/readme_feature.webp"
alt="Get it on Google Play"
height="550" />
## Download
+1
View File
@@ -0,0 +1 @@
-dontobfuscate
+4 -2
View File
@@ -33,9 +33,10 @@ android {
}
buildTypes {
create("benchmark") {
signingConfig = signingConfigs.getByName("debug")
matchingFallbacks += listOf("release")
signingConfig = signingConfigs["debug"]
matchingFallbacks += "release"
isDebuggable = false
proguardFile("benchmark-rules.pro")
}
}
}
@@ -59,6 +60,7 @@ dependencies {
implementation(libs.androidx.lifecycle.compose)
implementation(libs.androidx.navigation.compose)
implementation(libs.androidx.paging.compose)
implementation(libs.androidx.profileinstaller)
implementation(libs.androidx.work.runtime.ktx)
implementation(libs.coil)
implementation(libs.copydown)
+5133 -3100
View File
File diff suppressed because it is too large Load Diff
@@ -20,11 +20,14 @@ import androidx.compose.runtime.SideEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalConfiguration
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
import androidx.compose.ui.text.font.FontWeight
import androidx.navigation.NavType
import androidx.navigation.compose.NavHost
@@ -54,7 +57,10 @@ import dev.msfjarvis.claw.common.urllauncher.UrlLauncher
import dev.msfjarvis.claw.common.user.UserProfile
import kotlinx.coroutines.launch
@OptIn(ExperimentalMaterial3Api::class)
@OptIn(
ExperimentalComposeUiApi::class,
ExperimentalMaterial3Api::class,
)
@Composable
fun LobstersApp(
urlLauncher: UrlLauncher,
@@ -156,7 +162,7 @@ fun LobstersApp(
isVisible = navItems.any { it.route == currentDestination },
)
},
modifier = modifier,
modifier = modifier.semantics { testTagsAsResourceId = true },
) { paddingValues ->
NavHost(
navController = navController,
@@ -174,7 +180,6 @@ fun LobstersApp(
lazyPagingItems = hottestPosts,
listState = hottestListState,
isPostSaved = viewModel::isPostSaved,
reloadPosts = viewModel::refreshHottestPosts,
postActions = postActions,
)
}
@@ -186,7 +191,6 @@ fun LobstersApp(
lazyPagingItems = newestPosts,
listState = newestListState,
isPostSaved = viewModel::isPostSaved,
reloadPosts = viewModel::refreshNewestPosts,
postActions = postActions,
)
}
@@ -20,6 +20,7 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.platform.testTag
import androidx.navigation.NavController
import dev.msfjarvis.claw.android.ui.navigation.Destinations
@@ -73,7 +74,8 @@ fun ClawNavigationBar(
if (navItem.route != Destinations.startDestination.route) {
navController.navigate(navItem.route)
}
}
},
modifier = Modifier.testTag(navItem.label.uppercase()),
)
}
}
@@ -40,13 +40,12 @@ fun NetworkPosts(
lazyPagingItems: LazyPagingItems<LobstersPost>,
listState: LazyListState,
isPostSaved: suspend (SavedPost) -> Boolean,
reloadPosts: () -> Unit,
postActions: PostActions,
modifier: Modifier = Modifier,
) {
val refreshLoadState = lazyPagingItems.loadState.refresh
val isRefreshing = refreshLoadState == LoadState.Loading
val pullRefreshState = rememberPullRefreshState(isRefreshing, reloadPosts)
val pullRefreshState = rememberPullRefreshState(isRefreshing, lazyPagingItems::refresh)
Box(modifier = modifier.fillMaxSize().pullRefresh(pullRefreshState)) {
if (lazyPagingItems.itemCount == 0 && refreshLoadState is LoadState.Error) {
NetworkError(
@@ -37,16 +37,10 @@ constructor(
private val pagingSourceFactory: LobstersPagingSource.Factory,
@IODispatcher private val ioDispatcher: CoroutineDispatcher,
) : ViewModel() {
private var hottestPostsPagingSource: LobstersPagingSource? = null
private var newestPostsPagingSource: LobstersPagingSource? = null
private val hottestPostsPager =
Pager(PagingConfig(20)) {
pagingSourceFactory.create(api::getHottestPosts).also { hottestPostsPagingSource = it }
}
Pager(PagingConfig(pageSize = 20)) { pagingSourceFactory.create(api::getHottestPosts) }
private val newestPostsPager =
Pager(PagingConfig(20)) {
pagingSourceFactory.create(api::getHottestPosts).also { newestPostsPagingSource = it }
}
Pager(PagingConfig(pageSize = 20)) { pagingSourceFactory.create(api::getHottestPosts) }
val hottestPosts
get() = hottestPostsPager.flow
@@ -104,12 +98,4 @@ constructor(
is Failure.ApiFailure -> throw IOException("API returned an invalid response")
}
}
fun refreshHottestPosts() {
hottestPostsPagingSource?.invalidate()
}
fun refreshNewestPosts() {
newestPostsPagingSource?.invalidate()
}
}
+2 -2
View File
@@ -1,5 +1,5 @@
#
# This file was automatically generated by 'versioning-plugin'. DO NOT EDIT MANUALLY.
#
versioning-plugin.versionCode=10900
versioning-plugin.versionName=1.9.0
versioning-plugin.versionCode=11000
versioning-plugin.versionName=1.10.0
+2 -2
View File
@@ -25,8 +25,8 @@ dependencies {
implementation(libs.dagger)
implementation(libs.javax.inject)
testImplementation(testFixtures(libs.eithernet))
testImplementation(kotlin("test-junit"))
testImplementation(libs.kotlinx.coroutines.core)
testImplementation(libs.kotest.assertions.core)
testImplementation(libs.kotest.runner.junit5)
testImplementation(libs.kotlinx.serialization.json)
testImplementation(libs.retrofit.kotlinxSerializationConverter)
}
@@ -11,42 +11,40 @@ import com.slack.eithernet.test.newEitherNetController
import dev.msfjarvis.claw.model.LobstersPost
import dev.msfjarvis.claw.model.LobstersPostDetails
import dev.msfjarvis.claw.model.User
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertIs
import kotlinx.coroutines.runBlocking
import io.kotest.core.spec.style.FunSpec
import io.kotest.matchers.collections.shouldHaveSize
import io.kotest.matchers.shouldBe
import io.kotest.matchers.types.shouldBeTypeOf
class ApiTest {
class ApiTest : FunSpec() {
private val wrapper = ApiWrapper(newEitherNetController())
private val api
get() = wrapper.api
@Test
fun `api gets correct number of items`() = runBlocking {
val posts = api.getHottestPosts(1)
assertIs<Success<List<LobstersPost>>>(posts)
assertEquals(25, posts.value.size)
}
init {
test("api gets correct number of items") {
val posts = api.getHottestPosts(1)
posts.shouldBeTypeOf<Success<List<LobstersPost>>>()
posts.value shouldHaveSize 25
}
@Test
fun `posts with no urls`() = runBlocking {
val posts = api.getHottestPosts(1)
assertIs<Success<List<LobstersPost>>>(posts)
val commentsOnlyPosts = posts.value.asSequence().filter { it.url.isEmpty() }.toSet()
assertEquals(2, commentsOnlyPosts.size)
}
test("posts with no urls") {
val posts = api.getHottestPosts(1)
posts.shouldBeTypeOf<Success<List<LobstersPost>>>()
val commentsOnlyPosts = posts.value.asSequence().filter { it.url.isEmpty() }.toSet()
commentsOnlyPosts shouldHaveSize 2
}
@Test
fun `post details with comments`() = runBlocking {
val postDetails = api.getPostDetails("tdfoqh")
assertIs<Success<LobstersPostDetails>>(postDetails)
assertEquals(7, postDetails.value.comments.size)
}
test("post details with comments") {
val postDetails = api.getPostDetails("tdfoqh")
postDetails.shouldBeTypeOf<Success<LobstersPostDetails>>()
postDetails.value.comments shouldHaveSize 7
}
@Test
fun `get user details`() = runBlocking {
val user = api.getUser("msfjarvis")
assertIs<Success<User>>(user)
assertEquals("msfjarvis", user.value.username)
test("get user details") {
val user = api.getUser("msfjarvis")
user.shouldBeTypeOf<Success<User>>()
user.value.username shouldBe "msfjarvis"
}
}
}
@@ -27,7 +27,7 @@ class ApiWrapper(controller: EitherNetController<LobstersApi>) {
init {
controller.enqueue(LobstersApi::getHottestPosts) { success(hottest) }
controller.enqueue(LobstersApi::getNewestPosts) { success(hottest) }
controller.enqueue(LobstersApi::getHottestPosts) { success(hottest) }
controller.enqueue(LobstersApi::getPostDetails) { success(postDetails) }
controller.enqueue(LobstersApi::getUser) { success(user) }
}
+2 -2
View File
@@ -20,8 +20,8 @@ android {
buildTypes {
create("benchmark") {
isDebuggable = true
signingConfig = getByName("debug").signingConfig
matchingFallbacks += listOf("release")
signingConfig = signingConfigs["debug"]
matchingFallbacks += "release"
}
}
@@ -15,10 +15,14 @@ import androidx.test.filters.LargeTest
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.UiDevice
import org.junit.Before
import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
@LargeTest
@Ignore(
"These tests fail saying that ProfileInstaller 1.3.0-alpha02 should be used which we already are"
)
class BaselineProfileBenchmark {
@get:Rule val benchmarkRule = MacrobenchmarkRule()
private lateinit var device: UiDevice
@@ -9,19 +9,51 @@ package dev.msfjarvis.claw.benchmark
import androidx.benchmark.macro.MacrobenchmarkScope
import androidx.test.uiautomator.By
import androidx.test.uiautomator.UiDevice
import androidx.test.uiautomator.Until
const val PACKAGE_NAME = "dev.msfjarvis.claw.android"
private const val AWAIT_TIMEOUT = 10_000L
private const val SAVE_BUTTON_DESC = "Add to saved posts"
private const val NAV_ID_HOTTEST = "HOTTEST"
private const val NAV_ID_NEWEST = "NEWEST"
private const val NAV_ID_SAVED = "SAVED"
private const val COMMENT_BUTTON_DESC = "Open comments"
fun MacrobenchmarkScope.exploreUI(device: UiDevice) {
startActivityAndWait()
device.run {
listOf("HOTTEST", "NEWEST", "SAVED").forEach { desc ->
findObject(By.desc(desc)).click()
waitForIdle()
}
findObject(By.desc("HOTTEST")).click()
waitForIdle()
findObjects(By.desc("Open comments")).first().click()
waitForIdle()
savePosts()
exploreScreens()
returnToHottestScreen()
openCommentsScreen()
}
}
private fun UiDevice.waitForSubmitterName() {
wait(Until.hasObject(By.textContains("Submitted by")), AWAIT_TIMEOUT)
}
private fun UiDevice.savePosts() {
waitForSubmitterName()
findObjects(By.desc(SAVE_BUTTON_DESC)).forEach { btn -> btn.click() }
}
private fun UiDevice.exploreScreens() {
listOf(NAV_ID_HOTTEST, NAV_ID_NEWEST, NAV_ID_SAVED).forEach { tag ->
findObject(By.res(tag)).click()
waitForSubmitterName()
}
}
private fun UiDevice.returnToHottestScreen() {
findObject(By.res(NAV_ID_HOTTEST)).click()
waitForSubmitterName()
}
private fun UiDevice.openCommentsScreen() {
findObjects(By.desc(COMMENT_BUTTON_DESC)).first().click()
waitForSubmitterName()
}
@@ -10,10 +10,9 @@ package dev.msfjarvis.aps.gradle
import com.android.build.api.dsl.LibraryExtension
import com.android.build.api.dsl.Lint
import com.android.build.api.dsl.TestExtension
import com.android.build.api.variant.ApplicationAndroidComponentsExtension
import com.android.build.api.variant.LibraryAndroidComponentsExtension
import com.android.build.gradle.TestedExtension
import com.android.build.gradle.BaseExtension
import com.android.build.gradle.internal.dsl.BaseAppModuleExtension
import org.gradle.android.AndroidCacheFixPlugin
import org.gradle.api.JavaVersion
@@ -35,21 +34,13 @@ class AndroidCommonPlugin : Plugin<Project> {
override fun apply(project: Project) {
project.configureSlimTests()
project.pluginManager.apply(AndroidCacheFixPlugin::class)
project.extensions.findByType<BaseAppModuleExtension>()?.run { lint.configureLint(project) }
project.extensions.findByType<LibraryExtension>()?.run { lint.configureLint(project) }
project.extensions.findByType<TestedExtension>()?.run {
project.extensions.findByType<BaseExtension>()?.run {
compileSdkVersion(COMPILE_SDK)
defaultConfig {
minSdk = MIN_SDK
targetSdk = TARGET_SDK
}
sourceSets {
named("main") { java.srcDirs("src/main/kotlin") }
named("test") { java.srcDirs("src/test/kotlin") }
named("androidTest") { java.srcDirs("src/androidTest/kotlin") }
}
packagingOptions {
resources.excludes.add("**/*.version")
resources.excludes.add("**/*.txt")
@@ -69,22 +60,8 @@ class AndroidCommonPlugin : Plugin<Project> {
unitTests.isReturnDefaultValues = true
}
}
project.extensions.findByType<TestExtension>()?.run {
compileSdk = COMPILE_SDK
defaultConfig {
minSdk = MIN_SDK
targetSdk = TARGET_SDK
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
testOptions {
animationsDisabled = true
unitTests.isReturnDefaultValues = true
}
}
project.extensions.findByType<BaseAppModuleExtension>()?.run { lint.configureLint(project) }
project.extensions.findByType<LibraryExtension>()?.run { lint.configureLint(project) }
}
}
@@ -37,6 +37,7 @@ class KotlinCommonPlugin : Plugin<Project> {
withType<Test>().configureEach {
maxParallelForks = Runtime.getRuntime().availableProcessors() * 2
testLogging { events(TestLogEvent.PASSED, TestLogEvent.SKIPPED, TestLogEvent.FAILED) }
useJUnitPlatform()
}
}
}
@@ -11,9 +11,13 @@ import coil.Coil
import coil.ImageLoader
import coil.disk.DiskCache
import coil.memory.MemoryCache
import com.deliveryhero.whetstone.app.ApplicationScope
import com.squareup.anvil.annotations.ContributesMultibinding
import dev.msfjarvis.claw.core.injection.AppPlugin
import javax.inject.Inject
class CoilAppPlugin : AppPlugin {
@ContributesMultibinding(ApplicationScope::class)
class CoilAppPlugin @Inject constructor() : AppPlugin {
override fun apply(application: Application) {
Coil.setImageLoader {
ImageLoader.Builder(application)
+3 -2
View File
@@ -33,7 +33,8 @@ dependencies {
implementation(projects.core)
implementation(libs.sqldelight.androidDriver)
implementation(libs.sqldelight.primitiveAdapters)
testImplementation(libs.sqldelight.jvmDriver)
testImplementation(libs.kotest.assertions.core)
testImplementation(libs.kotest.runner.junit5)
testImplementation(libs.kotlinx.coroutines.core)
testImplementation(kotlin("test-junit"))
testImplementation(libs.sqldelight.jvmDriver)
}
@@ -10,129 +10,110 @@ import app.cash.sqldelight.adapter.primitive.IntColumnAdapter
import app.cash.sqldelight.driver.jdbc.sqlite.JdbcSqliteDriver
import dev.msfjarvis.claw.database.LobstersDatabase
import dev.msfjarvis.claw.database.model.TagsAdapter
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlinx.coroutines.runBlocking
import org.junit.Before
import io.kotest.core.spec.style.FunSpec
import io.kotest.matchers.collections.shouldBeEmpty
import io.kotest.matchers.collections.shouldHaveSize
import io.kotest.matchers.shouldBe
class SqlDelightQueriesTest {
class SqlDelightQueriesTest : FunSpec() {
private lateinit var postQueries: SavedPostQueries
@Before
fun setUp() {
val driver = JdbcSqliteDriver(JdbcSqliteDriver.IN_MEMORY)
LobstersDatabase.Schema.create(driver)
val database =
LobstersDatabase(
driver,
SavedPost.Adapter(IntColumnAdapter, TagsAdapter()),
)
postQueries = database.savedPostQueries
}
@Test
fun selectCount() = runBlocking {
val posts = createTestData(5)
posts.forEach { postQueries.insertOrReplacePost(it) }
val postCount = postQueries.selectCount().executeAsOne()
assertEquals(5, postCount)
}
@Test
fun insertIntoDatabase() = runBlocking {
// Get 5 posts
val posts = createTestData(5)
// Insert posts into DB
posts.forEach { postQueries.insertOrReplacePost(it) }
// Check post count
val postsCount = postQueries.selectCount().executeAsOne()
assertEquals(5, postsCount)
}
@Test
fun replaceFromDatabase() = runBlocking {
// Get 1 post
val post = createTestData(1)[0]
// Insert post into DB
postQueries.insertOrReplacePost(post)
// Create a new post and try replacing it
val newPost = post.copy(submitterName = "Fake name")
postQueries.insertOrReplacePost(newPost)
// Check post count
val postsCount = postQueries.selectCount().executeAsOne()
assertEquals(1, postsCount)
// Check if post is updated
val postFromDb = postQueries.selectPost(post.shortId).executeAsOne()
assertEquals("Fake name", postFromDb.submitterName)
}
@Test
fun selectPost() = runBlocking {
// Get 1 post
val post = createTestData(1)[0]
// Insert post into DB
postQueries.insertOrReplacePost(post)
val postFromDb = postQueries.selectAllPosts().executeAsOne()
assertEquals("test_id_1", postFromDb.shortId)
}
@Test
fun selectAllPosts() = runBlocking {
// Get 5 post
val posts = createTestData(5)
// Insert posts into DB
posts.forEach { postQueries.insertOrReplacePost(it) }
val postsFromDb = postQueries.selectAllPosts().executeAsList()
// Check if all posts have correct shortId
for (i in 1..5) {
assertEquals("test_id_$i", postsFromDb[i - 1].shortId)
init {
beforeEach {
val driver = JdbcSqliteDriver(JdbcSqliteDriver.IN_MEMORY)
LobstersDatabase.Schema.create(driver)
val database =
LobstersDatabase(
driver,
SavedPost.Adapter(IntColumnAdapter, TagsAdapter()),
)
postQueries = database.savedPostQueries
}
}
@Test
fun deletePost() = runBlocking {
// Create 3 posts and insert them to DB
val posts = createTestData(3)
posts.forEach { postQueries.insertOrReplacePost(it) }
test("add and count posts") {
val posts = createTestData(5)
// Delete 2nd post
postQueries.deletePost("test_id_2")
posts.forEach { postQueries.insertOrReplacePost(it) }
val postsFromDB = postQueries.selectAllPosts().executeAsList()
val postCount = postQueries.selectCount().executeAsOne()
// Check if size is 2, and only the correct post is deleted
assertEquals(2, postsFromDB.size)
assertEquals("test_id_1", postsFromDB[0].shortId)
assertEquals("test_id_3", postsFromDB[1].shortId)
}
postCount shouldBe 5
}
@Test
fun deleteAllPost() = runBlocking {
// Create 5 posts and insert them to DB
val posts = createTestData(5)
posts.forEach { postQueries.insertOrReplacePost(it) }
test("update post in database") {
// Get 1 post
val post = createTestData(1)[0]
// Delete all posts
postQueries.deleteAllPosts()
// Insert post into DB
postQueries.insertOrReplacePost(post)
val postsCount = postQueries.selectCount().executeAsOne()
// Create a new post and try replacing it
val newPost = post.copy(submitterName = "Fake name")
postQueries.insertOrReplacePost(newPost)
// Check if db is empty
assertEquals(0, postsCount)
// Check post count
val postsCount = postQueries.selectCount().executeAsOne()
postsCount shouldBe 1
// Check if post is updated
val postFromDb = postQueries.selectPost(post.shortId).executeAsOne()
postFromDb.submitterName shouldBe "Fake name"
}
test("get post from db") {
// Get 1 post
val post = createTestData(1)[0]
// Insert post into DB
postQueries.insertOrReplacePost(post)
val postFromDb = postQueries.selectAllPosts().executeAsOne()
postFromDb.shortId shouldBe "test_id_1"
}
test("get multiple posts from db") {
// Get 5 post
val posts = createTestData(5)
// Insert posts into DB
posts.forEach { postQueries.insertOrReplacePost(it) }
val postsFromDb = postQueries.selectAllPosts().executeAsList()
// Check if all posts have correct shortId
postsFromDb.forEachIndexed { index, post -> post.shortId shouldBe "test_id_${index.inc()}" }
}
test("delete post") {
// Create 3 posts and insert them to DB
val posts = createTestData(3)
posts.forEach { postQueries.insertOrReplacePost(it) }
// Delete 2nd post
postQueries.deletePost("test_id_2")
val postsFromDB = postQueries.selectAllPosts().executeAsList()
// Check if size is 2, and only the correct post is deleted
postsFromDB shouldHaveSize 2
postsFromDB[0].shortId shouldBe "test_id_1"
postsFromDB[1].shortId shouldBe "test_id_3"
}
test("delete all posts") {
// Create 5 posts and insert them to DB
val posts = createTestData(5)
posts.forEach { postQueries.insertOrReplacePost(it) }
// Delete all posts
postQueries.deleteAllPosts()
val dbPosts = postQueries.selectAllPosts().executeAsList()
dbPosts.shouldBeEmpty()
}
}
private fun createTestData(count: Int): ArrayList<SavedPost> {
+1 -2
View File
@@ -2,7 +2,6 @@
<SmellBaseline>
<ManuallySuppressedIssues></ManuallySuppressedIssues>
<CurrentIssues>
<ID>LongMethod:LobstersApp.kt$@OptIn(ExperimentalMaterial3Api::class) @Composable fun LobstersApp( urlLauncher: UrlLauncher, htmlConverter: HTMLConverter, setWebUri: (String?) -&gt; Unit, modifier: Modifier = Modifier, viewModel: ClawViewModel = injectedViewModel(), )</ID>
<ID>LongParameterList:NetworkPosts.kt$( lazyPagingItems: LazyPagingItems&lt;LobstersPost&gt;, listState: LazyListState, isPostSaved: suspend (SavedPost) -&gt; Boolean, reloadPosts: () -&gt; Unit, postActions: PostActions, modifier: Modifier = Modifier, )</ID>
<ID>LongMethod:LobstersApp.kt$@OptIn( ExperimentalComposeUiApi::class, ExperimentalMaterial3Api::class, ) @Composable fun LobstersApp( urlLauncher: UrlLauncher, htmlConverter: HTMLConverter, setWebUri: (String?) -&gt; Unit, modifier: Modifier = Modifier, viewModel: ClawViewModel = injectedViewModel(), )</ID>
</CurrentIssues>
</SmellBaseline>
+9 -4
View File
@@ -53,9 +53,6 @@ android.nonTransitiveRClass=true
# instead of using a parameter wildcard which keeps them all.
android.useMinimalKeepRules=true
# Enable resource optimizations for release build
android.enableResourceOptimizations=true
# Default Android build features
android.defaults.buildfeatures.buildconfig=false
android.defaults.buildfeatures.aidl=false
@@ -63,8 +60,16 @@ android.defaults.buildfeatures.renderscript=false
android.defaults.buildfeatures.resvalues=false
android.defaults.buildfeatures.shaders=false
# Experimental features
android.disableEarlyManifestParsing=true
android.enablePartialRIncrementalBuilds=true
# TODO: enable once we're back on AGP 8.x
# android.experimental.testOptions.uninstallIncompatibleApks=true
android.enableBuildConfigAsBytecode=true
android.experimental.enableNewResourceShrinker.preciseShrinking=true
# Disable warnings about unsupported features, we know what we're doing
android.suppressUnsupportedOptionWarnings=android.enableR8.fullMode,android.enableResourceOptimizations,android.nonTransitiveRClass,android.suppressUnsupportedOptionWarnings,android.sdk.channel
android.suppressUnsupportedOptionWarnings=android.disableEarlyManifestParsing,android.enablePartialRIncrementalBuilds,android.enableBuildConfigAsBytecode,android.experimental.enableNewResourceShrinker.preciseShrinking,android.suppressUnsupportedOptionWarnings
# Maven publishing
GROUP=com.github.android-password-store
+6 -3
View File
@@ -1,5 +1,5 @@
[versions]
accompanist = "0.27.1"
accompanist = "0.28.0"
# @pin https://issuetracker.google.com/issues/259556213
agp = "7.3.1"
androidx-test = "1.5.0"
@@ -8,6 +8,7 @@ coil = "2.2.2"
composeCompiler = "1.4.0-alpha02"
coroutines = "1.6.4"
dagger = "2.44.2"
kotest = "5.5.4"
kotlin = "1.7.21"
# @pin Needs to be aligned with Retrofit
okhttp = "3.14.9"
@@ -15,7 +16,7 @@ retrofit = "2.9.0"
richtext = "0.15.0"
serialization = "1.4.1"
sqldelight = "2.0.0-alpha04"
whetstone = "0.3.0"
whetstone = "0.5.0-SNAPSHOT"
workmanager = "2.8.0-beta02"
[libraries]
@@ -68,6 +69,8 @@ eithernet = "com.slack.eithernet:eithernet:1.2.1"
javapoet = "com.squareup:javapoet:1.13.0"
javax-inject = "javax.inject:javax.inject:1"
jsoup = "org.jsoup:jsoup:1.15.3"
kotest-runner-junit5 = { module = "io.kotest:kotest-runner-junit5", version.ref = "kotest" }
kotest-assertions-core = { module = "io.kotest:kotest-assertions-core", version.ref = "kotest" }
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "coroutines" }
kotlinx-serialization-core = { module = "org.jetbrains.kotlinx:kotlinx-serialization-core", version.ref = "serialization" }
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "serialization" }
@@ -87,4 +90,4 @@ whetstone = { module = "com.deliveryhero.whetstone:whetstone", version.ref = "wh
android-test = { id = "com.android.test", version.ref = "agp" }
anvil = "com.squareup.anvil:2.4.2"
sqldelight = { id = "app.cash.sqldelight", version.ref = "sqldelight" }
whetstone = { id = "com.deliveryhero.whetstone", version.ref = "whetstone" }
whetstone = { id = "dev.msfjarvis.whetstone", version.ref = "whetstone" }
+8 -27
View File
@@ -6,8 +6,6 @@
*/
@file:Suppress("UnstableApiUsage")
import me.champeau.gradle.igp.gitRepositories
pluginManagement {
repositories {
exclusiveContent {
@@ -43,38 +41,17 @@ pluginManagement {
includeModule("gradle.plugin.org.gradle.android", "android-cache-fix-gradle-plugin")
includeModule("com.sergei-lapin.napt", "com.sergei-lapin.napt.gradle.plugin")
includeModule("com.sergei-lapin.napt", "gradle")
includeModule("me.champeau.includegit", "me.champeau.includegit.gradle.plugin")
includeModule("me.champeau.gradle.includegit", "plugin")
}
}
exclusiveContent {
forRepository { maven("https://oss.sonatype.org/content/repositories/snapshots/") }
filter { includeGroup("dev.msfjarvis.whetstone") }
}
includeBuild("build-logic")
mavenCentral()
}
}
plugins { id("me.champeau.includegit") version "0.1.5" }
gitRepositories {
checkoutsDirectory.set(rootProject.projectDir.resolve("build/checkouts"))
include("whetstone") {
uri.set("https://github.com/msfjarvis/whetstone")
tag.set("msfjarvis-2022-11-27")
includeBuild {
dependencySubstitution {
for (module in
listOf(
"whetstone",
"whetstone-compiler",
"whetstone-compose",
"whetstone-worker",
)) {
substitute(module("com.deliveryhero.whetstone:$module")).using(project(":$module"))
}
}
}
}
}
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
@@ -155,6 +132,10 @@ dependencyResolutionManagement {
includeModule("gradle.plugin.org.gradle.android", "android-cache-fix-gradle-plugin")
}
}
exclusiveContent {
forRepository { maven("https://oss.sonatype.org/content/repositories/snapshots/") }
filter { includeGroup("dev.msfjarvis.whetstone") }
}
mavenCentral()
}
}