mirror of
https://github.com/msfjarvis/compose-lobsters
synced 2025-08-17 20:17:02 +05:30
Merge #130
130: Split API and database models r=msfjarvis a=msfjarvis - Introduces a new `SavedPost` table stripped down to only the necessary fields for persistence - Deletes the old `LobstersPost` table - Switches `LobstersItem` to take in a `SavedPost` for rendering - Replaces moshi-metadata-reflect with moshi-ksp Fixes #118 bors r+ Co-authored-by: Harsh Shandilya <me@msfjarvis.dev>
This commit is contained in:
commit
f10e2b79ac
27 changed files with 195 additions and 200 deletions
1
.github/ci-gradle.properties
vendored
Normal file
1
.github/ci-gradle.properties
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
|
5
.github/workflows/pull_request.yml
vendored
5
.github/workflows/pull_request.yml
vendored
|
@ -10,12 +10,17 @@ jobs:
|
||||||
test-pr:
|
test-pr:
|
||||||
runs-on: macOS-latest
|
runs-on: macOS-latest
|
||||||
steps:
|
steps:
|
||||||
|
|
||||||
- uses: actions/setup-java@d202f5dbf7256730fb690ec59f6381650114feb2
|
- uses: actions/setup-java@d202f5dbf7256730fb690ec59f6381650114feb2
|
||||||
with:
|
with:
|
||||||
java-version: '11'
|
java-version: '11'
|
||||||
|
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f
|
uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f
|
||||||
|
|
||||||
|
- name: Copy CI gradle.properties
|
||||||
|
run: mkdir -p ~/.gradle ; cp .github/ci-gradle.properties ~/.gradle/gradle.properties
|
||||||
|
|
||||||
- uses: burrunan/gradle-cache-action@03c71a8ba93d670980695505f48f49daf43704a6
|
- uses: burrunan/gradle-cache-action@03c71a8ba93d670980695505f48f49daf43704a6
|
||||||
name: Run unit tests
|
name: Run unit tests
|
||||||
with:
|
with:
|
||||||
|
|
6
.idea/kotlinScripting.xml
generated
Normal file
6
.idea/kotlinScripting.xml
generated
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="KotlinScriptingSettings">
|
||||||
|
<option name="suppressDefinitionsCheck" value="true" />
|
||||||
|
</component>
|
||||||
|
</project>
|
|
@ -1,12 +1,12 @@
|
||||||
plugins {
|
plugins {
|
||||||
kotlin("jvm")
|
kotlin("jvm")
|
||||||
|
id("com.google.devtools.ksp") version "1.4.30-1.0.0-alpha04"
|
||||||
`lobsters-plugin`
|
`lobsters-plugin`
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
api(Dependencies.ThirdParty.Retrofit.lib)
|
api(Dependencies.ThirdParty.Retrofit.lib)
|
||||||
implementation(project(":database"))
|
ksp(Dependencies.ThirdParty.Moshi.ksp)
|
||||||
implementation(Dependencies.ThirdParty.Moshi.moshiMetadataReflect)
|
|
||||||
implementation(Dependencies.ThirdParty.Retrofit.moshi)
|
implementation(Dependencies.ThirdParty.Retrofit.moshi)
|
||||||
testImplementation(Dependencies.Kotlin.Coroutines.core)
|
testImplementation(Dependencies.Kotlin.Coroutines.core)
|
||||||
testImplementation(Dependencies.Testing.junit)
|
testImplementation(Dependencies.Testing.junit)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package dev.msfjarvis.lobsters.data.api
|
package dev.msfjarvis.lobsters.data.api
|
||||||
|
|
||||||
import dev.msfjarvis.lobsters.data.local.LobstersPost
|
import dev.msfjarvis.lobsters.model.LobstersPost
|
||||||
import retrofit2.http.GET
|
import retrofit2.http.GET
|
||||||
import retrofit2.http.Query
|
import retrofit2.http.Query
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
package dev.msfjarvis.lobsters.model
|
package dev.msfjarvis.lobsters.model
|
||||||
|
|
||||||
import com.squareup.moshi.Json
|
import com.squareup.moshi.Json
|
||||||
|
import com.squareup.moshi.JsonClass
|
||||||
|
|
||||||
|
@JsonClass(generateAdapter = true)
|
||||||
class KeybaseSignature(
|
class KeybaseSignature(
|
||||||
@Json(name = "kb_username")
|
@Json(name = "kb_username")
|
||||||
val kbUsername: String,
|
val kbUsername: String,
|
||||||
@Json(name = "sig_hash")
|
@Json(name = "sig_hash")
|
||||||
val sigHash: String
|
val sigHash: String,
|
||||||
)
|
)
|
|
@ -0,0 +1,26 @@
|
||||||
|
package dev.msfjarvis.lobsters.model
|
||||||
|
|
||||||
|
import com.squareup.moshi.Json
|
||||||
|
import com.squareup.moshi.JsonClass
|
||||||
|
|
||||||
|
@JsonClass(generateAdapter = true)
|
||||||
|
class LobstersPost(
|
||||||
|
@Json(name = "short_id")
|
||||||
|
val shortId: String,
|
||||||
|
@Json(name = "short_id_url")
|
||||||
|
val shortIdUrl: String,
|
||||||
|
@Json(name = "created_at")
|
||||||
|
val createdAt: String,
|
||||||
|
val title: String,
|
||||||
|
val url: String,
|
||||||
|
val score: Long,
|
||||||
|
val flags: Long,
|
||||||
|
@Json(name = "comment_count")
|
||||||
|
val commentCount: Long,
|
||||||
|
val description: String,
|
||||||
|
@Json(name = "comments_url")
|
||||||
|
val commentsUrl: String,
|
||||||
|
@Json(name = "submitter_user")
|
||||||
|
val submitterUser: Submitter,
|
||||||
|
val tags: List<String>,
|
||||||
|
)
|
|
@ -1,7 +1,9 @@
|
||||||
package dev.msfjarvis.lobsters.model
|
package dev.msfjarvis.lobsters.model
|
||||||
|
|
||||||
import com.squareup.moshi.Json
|
import com.squareup.moshi.Json
|
||||||
|
import com.squareup.moshi.JsonClass
|
||||||
|
|
||||||
|
@JsonClass(generateAdapter = true)
|
||||||
class Submitter(
|
class Submitter(
|
||||||
val username: String,
|
val username: String,
|
||||||
@Json(name = "created_at")
|
@Json(name = "created_at")
|
||||||
|
@ -21,5 +23,5 @@ class Submitter(
|
||||||
@Json(name = "twitter_username")
|
@Json(name = "twitter_username")
|
||||||
val twitterUsername: String? = null,
|
val twitterUsername: String? = null,
|
||||||
@Json(name = "keybase_signatures")
|
@Json(name = "keybase_signatures")
|
||||||
val keybaseSignatures: List<KeybaseSignature> = emptyList()
|
val keybaseSignatures: List<KeybaseSignature> = emptyList(),
|
||||||
)
|
)
|
|
@ -2,7 +2,6 @@ package dev.msfjarvis.lobsters.data.api
|
||||||
|
|
||||||
import com.squareup.moshi.Moshi
|
import com.squareup.moshi.Moshi
|
||||||
import dev.msfjarvis.lobsters.util.TestUtils
|
import dev.msfjarvis.lobsters.util.TestUtils
|
||||||
import dev.zacsweers.moshix.reflect.MetadataKotlinJsonAdapterFactory
|
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import mockwebserver3.Dispatcher
|
import mockwebserver3.Dispatcher
|
||||||
import mockwebserver3.MockResponse
|
import mockwebserver3.MockResponse
|
||||||
|
@ -24,7 +23,6 @@ class LobstersApiTest {
|
||||||
private val webServer = MockWebServer()
|
private val webServer = MockWebServer()
|
||||||
private val apiData = TestUtils.getJson("hottest.json")
|
private val apiData = TestUtils.getJson("hottest.json")
|
||||||
private val moshi = Moshi.Builder()
|
private val moshi = Moshi.Builder()
|
||||||
.add(MetadataKotlinJsonAdapterFactory())
|
|
||||||
.build()
|
.build()
|
||||||
private val okHttp = OkHttpClient.Builder()
|
private val okHttp = OkHttpClient.Builder()
|
||||||
.build()
|
.build()
|
||||||
|
@ -63,7 +61,7 @@ class LobstersApiTest {
|
||||||
fun `no moderator posts in test data`() = runBlocking {
|
fun `no moderator posts in test data`() = runBlocking {
|
||||||
val posts = apiClient.getHottestPosts(1)
|
val posts = apiClient.getHottestPosts(1)
|
||||||
val moderatorPosts = posts.asSequence()
|
val moderatorPosts = posts.asSequence()
|
||||||
.filter { it.submitter_user.isModerator }
|
.filter { it.submitterUser.isModerator }
|
||||||
.toSet()
|
.toSet()
|
||||||
assertTrue(moderatorPosts.isEmpty())
|
assertTrue(moderatorPosts.isEmpty())
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,7 +54,6 @@ dependencies {
|
||||||
implementation(Dependencies.Kotlin.Coroutines.android)
|
implementation(Dependencies.Kotlin.Coroutines.android)
|
||||||
implementation(Dependencies.ThirdParty.accompanist)
|
implementation(Dependencies.ThirdParty.accompanist)
|
||||||
implementation(Dependencies.ThirdParty.Moshi.lib)
|
implementation(Dependencies.ThirdParty.Moshi.lib)
|
||||||
implementation(Dependencies.ThirdParty.Moshi.moshiMetadataReflect)
|
|
||||||
implementation(Dependencies.ThirdParty.Retrofit.moshi)
|
implementation(Dependencies.ThirdParty.Retrofit.moshi)
|
||||||
implementation(Dependencies.ThirdParty.SQLDelight.androidDriver)
|
implementation(Dependencies.ThirdParty.SQLDelight.androidDriver)
|
||||||
testImplementation(Dependencies.Testing.junit)
|
testImplementation(Dependencies.Testing.junit)
|
||||||
|
|
|
@ -2,8 +2,8 @@ package dev.msfjarvis.lobsters.data.remote
|
||||||
|
|
||||||
import androidx.paging.PagingSource
|
import androidx.paging.PagingSource
|
||||||
import androidx.paging.PagingState
|
import androidx.paging.PagingState
|
||||||
import dev.msfjarvis.lobsters.data.local.LobstersPost
|
|
||||||
import dev.msfjarvis.lobsters.data.repo.LobstersRepository
|
import dev.msfjarvis.lobsters.data.repo.LobstersRepository
|
||||||
|
import dev.msfjarvis.lobsters.model.LobstersPost
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class LobstersPagingSource @Inject constructor(
|
class LobstersPagingSource @Inject constructor(
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
package dev.msfjarvis.lobsters.data.repo
|
package dev.msfjarvis.lobsters.data.repo
|
||||||
|
|
||||||
import dev.msfjarvis.lobsters.data.api.LobstersApi
|
import dev.msfjarvis.lobsters.data.api.LobstersApi
|
||||||
import dev.msfjarvis.lobsters.data.local.LobstersPost
|
import dev.msfjarvis.lobsters.data.local.SavedPost
|
||||||
|
import dev.msfjarvis.lobsters.model.LobstersPost
|
||||||
import dev.msfjarvis.lobsters.database.LobstersDatabase
|
import dev.msfjarvis.lobsters.database.LobstersDatabase
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
@ -13,7 +14,7 @@ class LobstersRepository constructor(
|
||||||
private val lobstersDatabase: LobstersDatabase,
|
private val lobstersDatabase: LobstersDatabase,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
private val savedPostsCache: MutableMap<String, LobstersPost> = mutableMapOf()
|
private val savedPostsCache: MutableMap<String, SavedPost> = mutableMapOf()
|
||||||
private val _isCacheReady = MutableStateFlow(false)
|
private val _isCacheReady = MutableStateFlow(false)
|
||||||
val isCacheReady = _isCacheReady.asStateFlow()
|
val isCacheReady = _isCacheReady.asStateFlow()
|
||||||
|
|
||||||
|
@ -21,7 +22,7 @@ class LobstersRepository constructor(
|
||||||
return savedPostsCache.containsKey(postId)
|
return savedPostsCache.containsKey(postId)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getAllPostsFromCache(): List<LobstersPost> {
|
fun getAllPostsFromCache(): List<SavedPost> {
|
||||||
return savedPostsCache.values.toList()
|
return savedPostsCache.values.toList()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,29 +32,29 @@ class LobstersRepository constructor(
|
||||||
|
|
||||||
suspend fun updateCache() {
|
suspend fun updateCache() {
|
||||||
if (_isCacheReady.value) return
|
if (_isCacheReady.value) return
|
||||||
val posts = getAllPosts()
|
val posts = getSavedPosts()
|
||||||
|
|
||||||
posts.forEach {
|
posts.forEach {
|
||||||
savedPostsCache[it.short_id] = it
|
savedPostsCache[it.shortId] = it
|
||||||
}
|
}
|
||||||
_isCacheReady.value = true
|
_isCacheReady.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun getAllPosts(): List<LobstersPost> = withContext(Dispatchers.IO) {
|
private suspend fun getSavedPosts(): List<SavedPost> = withContext(Dispatchers.IO) {
|
||||||
return@withContext lobstersDatabase.postQueries.selectAllPosts().executeAsList()
|
return@withContext lobstersDatabase.savedPostQueries.selectAllPosts().executeAsList()
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun addPost(post: LobstersPost) = withContext(Dispatchers.IO) {
|
suspend fun addPost(post: SavedPost) = withContext(Dispatchers.IO) {
|
||||||
if (!savedPostsCache.containsKey(post.short_id)) {
|
if (!savedPostsCache.containsKey(post.shortId)) {
|
||||||
savedPostsCache.putIfAbsent(post.short_id, post)
|
savedPostsCache.putIfAbsent(post.shortId, post)
|
||||||
lobstersDatabase.postQueries.insertOrReplacePost(post)
|
lobstersDatabase.savedPostQueries.insertOrReplacePost(post)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun removePost(post: LobstersPost) = withContext(Dispatchers.IO) {
|
suspend fun removePost(post: SavedPost) = withContext(Dispatchers.IO) {
|
||||||
if (savedPostsCache.containsKey(post.short_id)) {
|
if (savedPostsCache.containsKey(post.shortId)) {
|
||||||
savedPostsCache.remove(post.short_id)
|
savedPostsCache.remove(post.shortId)
|
||||||
lobstersDatabase.postQueries.deletePost(post.short_id)
|
lobstersDatabase.savedPostQueries.deletePost(post.shortId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package dev.msfjarvis.lobsters.injection
|
package dev.msfjarvis.lobsters.injection
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import com.squareup.moshi.JsonAdapter
|
|
||||||
import com.squareup.sqldelight.android.AndroidSqliteDriver
|
import com.squareup.sqldelight.android.AndroidSqliteDriver
|
||||||
import com.squareup.sqldelight.db.SqlDriver
|
import com.squareup.sqldelight.db.SqlDriver
|
||||||
import dagger.Module
|
import dagger.Module
|
||||||
|
@ -10,10 +9,8 @@ import dagger.Reusable
|
||||||
import dagger.hilt.InstallIn
|
import dagger.hilt.InstallIn
|
||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
import dagger.hilt.components.SingletonComponent
|
import dagger.hilt.components.SingletonComponent
|
||||||
import dev.msfjarvis.lobsters.data.local.LobstersPost
|
import dev.msfjarvis.lobsters.data.local.SavedPost
|
||||||
import dev.msfjarvis.lobsters.database.LobstersDatabase
|
import dev.msfjarvis.lobsters.database.LobstersDatabase
|
||||||
import dev.msfjarvis.lobsters.model.Submitter
|
|
||||||
import dev.msfjarvis.lobsters.model.SubmitterAdapter
|
|
||||||
import dev.msfjarvis.lobsters.model.TagsAdapter
|
import dev.msfjarvis.lobsters.model.TagsAdapter
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@ -21,12 +18,6 @@ import javax.inject.Singleton
|
||||||
@InstallIn(SingletonComponent::class)
|
@InstallIn(SingletonComponent::class)
|
||||||
object DatabaseModule {
|
object DatabaseModule {
|
||||||
|
|
||||||
@Provides
|
|
||||||
@Reusable
|
|
||||||
fun providesSubmitterAdapter(jsonAdapter: JsonAdapter<Submitter>): SubmitterAdapter {
|
|
||||||
return SubmitterAdapter(jsonAdapter)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Reusable
|
@Reusable
|
||||||
fun providesTagsAdapter(): TagsAdapter {
|
fun providesTagsAdapter(): TagsAdapter {
|
||||||
|
@ -43,12 +34,11 @@ object DatabaseModule {
|
||||||
@Singleton
|
@Singleton
|
||||||
fun providesLobstersDatabase(
|
fun providesLobstersDatabase(
|
||||||
sqlDriver: SqlDriver,
|
sqlDriver: SqlDriver,
|
||||||
submitterAdapter: SubmitterAdapter,
|
|
||||||
tagsAdapter: TagsAdapter
|
tagsAdapter: TagsAdapter
|
||||||
): LobstersDatabase {
|
): LobstersDatabase {
|
||||||
return LobstersDatabase(
|
return LobstersDatabase(
|
||||||
sqlDriver,
|
sqlDriver,
|
||||||
LobstersPost.Adapter(submitterAdapter, tagsAdapter)
|
SavedPost.Adapter(tagsAdapter),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,11 @@
|
||||||
package dev.msfjarvis.lobsters.injection
|
package dev.msfjarvis.lobsters.injection
|
||||||
|
|
||||||
import com.squareup.moshi.JsonAdapter
|
|
||||||
import com.squareup.moshi.Moshi
|
import com.squareup.moshi.Moshi
|
||||||
import com.squareup.moshi.adapter
|
|
||||||
import dagger.Module
|
import dagger.Module
|
||||||
import dagger.Provides
|
import dagger.Provides
|
||||||
import dagger.Reusable
|
import dagger.Reusable
|
||||||
import dagger.hilt.InstallIn
|
import dagger.hilt.InstallIn
|
||||||
import dagger.hilt.components.SingletonComponent
|
import dagger.hilt.components.SingletonComponent
|
||||||
import dev.msfjarvis.lobsters.model.Submitter
|
|
||||||
import dev.zacsweers.moshix.reflect.MetadataKotlinJsonAdapterFactory
|
|
||||||
|
|
||||||
@Module
|
@Module
|
||||||
@InstallIn(SingletonComponent::class)
|
@InstallIn(SingletonComponent::class)
|
||||||
|
@ -18,14 +14,6 @@ object MoshiModule {
|
||||||
@Reusable
|
@Reusable
|
||||||
fun provideMoshi(): Moshi {
|
fun provideMoshi(): Moshi {
|
||||||
return Moshi.Builder()
|
return Moshi.Builder()
|
||||||
.add(MetadataKotlinJsonAdapterFactory())
|
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalStdlibApi::class)
|
|
||||||
@Provides
|
|
||||||
@Reusable
|
|
||||||
fun provideSubmitterJsonAdapter(moshi: Moshi): JsonAdapter<Submitter> {
|
|
||||||
return moshi.adapter()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,8 +11,10 @@ import androidx.compose.ui.Modifier
|
||||||
import androidx.paging.LoadState
|
import androidx.paging.LoadState
|
||||||
import androidx.paging.compose.LazyPagingItems
|
import androidx.paging.compose.LazyPagingItems
|
||||||
import androidx.paging.compose.items
|
import androidx.paging.compose.items
|
||||||
import dev.msfjarvis.lobsters.data.local.LobstersPost
|
import dev.msfjarvis.lobsters.data.local.SavedPost
|
||||||
|
import dev.msfjarvis.lobsters.model.LobstersPost
|
||||||
import dev.msfjarvis.lobsters.ui.urllauncher.LocalUrlLauncher
|
import dev.msfjarvis.lobsters.ui.urllauncher.LocalUrlLauncher
|
||||||
|
import dev.msfjarvis.lobsters.util.toDbModel
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun HottestPosts(
|
fun HottestPosts(
|
||||||
|
@ -20,7 +22,7 @@ fun HottestPosts(
|
||||||
listState: LazyListState,
|
listState: LazyListState,
|
||||||
isPostSaved: (String) -> Boolean,
|
isPostSaved: (String) -> Boolean,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
saveAction: (LobstersPost) -> Unit,
|
saveAction: (SavedPost) -> Unit,
|
||||||
) {
|
) {
|
||||||
val urlLauncher = LocalUrlLauncher.current
|
val urlLauncher = LocalUrlLauncher.current
|
||||||
|
|
||||||
|
@ -33,13 +35,15 @@ fun HottestPosts(
|
||||||
) {
|
) {
|
||||||
items(posts) { item ->
|
items(posts) { item ->
|
||||||
if (item != null) {
|
if (item != null) {
|
||||||
var isSaved by remember(item.short_id) { mutableStateOf(isPostSaved(item.short_id)) }
|
@Suppress("NAME_SHADOWING")
|
||||||
|
val item = item.toDbModel()
|
||||||
|
var isSaved by remember(item.shortId) { mutableStateOf(isPostSaved(item.shortId)) }
|
||||||
|
|
||||||
LobstersItem(
|
LobstersItem(
|
||||||
post = item,
|
post = item,
|
||||||
isSaved = isSaved,
|
isSaved = isSaved,
|
||||||
onClick = { urlLauncher.launch(item.url.ifEmpty { item.comments_url }) },
|
onClick = { urlLauncher.launch(item.url.ifEmpty { item.commentsUrl }) },
|
||||||
onLongClick = { urlLauncher.launch(item.comments_url) },
|
onLongClick = { urlLauncher.launch(item.commentsUrl) },
|
||||||
onSaveButtonClick = {
|
onSaveButtonClick = {
|
||||||
isSaved = isSaved.not()
|
isSaved = isSaved.not()
|
||||||
saveAction.invoke(item)
|
saveAction.invoke(item)
|
||||||
|
|
|
@ -29,43 +29,26 @@ import coil.transform.CircleCropTransformation
|
||||||
import dev.chrisbanes.accompanist.coil.CoilImage
|
import dev.chrisbanes.accompanist.coil.CoilImage
|
||||||
import dev.msfjarvis.lobsters.R
|
import dev.msfjarvis.lobsters.R
|
||||||
import dev.msfjarvis.lobsters.data.api.LobstersApi
|
import dev.msfjarvis.lobsters.data.api.LobstersApi
|
||||||
import dev.msfjarvis.lobsters.data.local.LobstersPost
|
import dev.msfjarvis.lobsters.data.local.SavedPost
|
||||||
import dev.msfjarvis.lobsters.model.Submitter
|
|
||||||
import dev.msfjarvis.lobsters.ui.theme.LobstersTheme
|
import dev.msfjarvis.lobsters.ui.theme.LobstersTheme
|
||||||
import dev.msfjarvis.lobsters.ui.theme.titleColor
|
import dev.msfjarvis.lobsters.ui.theme.titleColor
|
||||||
import dev.msfjarvis.lobsters.util.IconResource
|
import dev.msfjarvis.lobsters.util.IconResource
|
||||||
|
|
||||||
val TEST_POST = LobstersPost(
|
val TEST_POST = SavedPost(
|
||||||
"zqyydb",
|
shortId = "zqyydb",
|
||||||
"https://lobste.rs/s/zqyydb",
|
title = "k2k20 hackathon report: Bob Beck on LibreSSL progress",
|
||||||
"2020-09-21T07:11:14.000-05:00",
|
url = "https://undeadly.org/cgi?action=article;sid=20200921105847",
|
||||||
"k2k20 hackathon report: Bob Beck on LibreSSL progress",
|
createdAt = "2020-09-21T07:11:14.000-05:00",
|
||||||
"https://undeadly.org/cgi?action=article;sid=20200921105847",
|
commentsUrl = "https://lobste.rs/s/zqyydb/k2k20_hackathon_report_bob_beck_on",
|
||||||
4,
|
submitterName = "Vigdis",
|
||||||
0,
|
submitterAvatarUrl = "/avatars/Vigdis-100.png",
|
||||||
0,
|
tags = listOf("openbsd", "linux", "containers", "hack the planet", "no thanks"),
|
||||||
"",
|
|
||||||
"https://lobste.rs/s/zqyydb/k2k20_hackathon_report_bob_beck_on",
|
|
||||||
Submitter(
|
|
||||||
"Vigdis",
|
|
||||||
"2017-02-27T21:08:14.000-06:00",
|
|
||||||
false,
|
|
||||||
"Alleycat for the fun, sys/net admin for a living and OpenBSD contributions for the pleasure. (Not so) French dude in Montreal\r\n\r\nhttps://chown.me",
|
|
||||||
false,
|
|
||||||
76,
|
|
||||||
"/avatars/Vigdis-100.png",
|
|
||||||
"sevan",
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
emptyList(),
|
|
||||||
),
|
|
||||||
listOf("openbsd", "linux", "containers", "hack the planet", "no thanks"),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
@OptIn(ExperimentalFoundationApi::class)
|
@OptIn(ExperimentalFoundationApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun LobstersItem(
|
fun LobstersItem(
|
||||||
post: LobstersPost,
|
post: SavedPost,
|
||||||
isSaved: Boolean,
|
isSaved: Boolean,
|
||||||
onClick: () -> Unit,
|
onClick: () -> Unit,
|
||||||
onLongClick: () -> Unit,
|
onLongClick: () -> Unit,
|
||||||
|
@ -99,10 +82,10 @@ fun LobstersItem(
|
||||||
)
|
)
|
||||||
Row {
|
Row {
|
||||||
CoilImage(
|
CoilImage(
|
||||||
data = "${LobstersApi.BASE_URL}/${post.submitter_user.avatarUrl}",
|
data = "${LobstersApi.BASE_URL}/${post.submitterAvatarUrl}",
|
||||||
contentDescription = stringResource(
|
contentDescription = stringResource(
|
||||||
R.string.avatar_content_description,
|
R.string.avatar_content_description,
|
||||||
post.submitter_user.username
|
post.submitterName
|
||||||
),
|
),
|
||||||
fadeIn = true,
|
fadeIn = true,
|
||||||
requestBuilder = {
|
requestBuilder = {
|
||||||
|
@ -113,7 +96,7 @@ fun LobstersItem(
|
||||||
.padding(4.dp),
|
.padding(4.dp),
|
||||||
)
|
)
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(id = R.string.submitted_by, post.submitter_user.username),
|
text = stringResource(id = R.string.submitted_by, post.submitterName),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(4.dp),
|
.padding(4.dp),
|
||||||
)
|
)
|
||||||
|
|
|
@ -6,16 +6,16 @@ import androidx.compose.foundation.lazy.items
|
||||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import dev.msfjarvis.lobsters.data.local.LobstersPost
|
import dev.msfjarvis.lobsters.data.local.SavedPost
|
||||||
import dev.msfjarvis.lobsters.ui.urllauncher.LocalUrlLauncher
|
import dev.msfjarvis.lobsters.ui.urllauncher.LocalUrlLauncher
|
||||||
import dev.msfjarvis.lobsters.util.asZonedDateTime
|
import dev.msfjarvis.lobsters.util.asZonedDateTime
|
||||||
|
|
||||||
@OptIn(ExperimentalFoundationApi::class)
|
@OptIn(ExperimentalFoundationApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun SavedPosts(
|
fun SavedPosts(
|
||||||
posts: List<LobstersPost>,
|
posts: List<SavedPost>,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
saveAction: (LobstersPost) -> Unit,
|
saveAction: (SavedPost) -> Unit,
|
||||||
) {
|
) {
|
||||||
val listState = rememberLazyListState()
|
val listState = rememberLazyListState()
|
||||||
val urlLauncher = LocalUrlLauncher.current
|
val urlLauncher = LocalUrlLauncher.current
|
||||||
|
@ -27,7 +27,7 @@ fun SavedPosts(
|
||||||
state = listState,
|
state = listState,
|
||||||
modifier = Modifier.then(modifier),
|
modifier = Modifier.then(modifier),
|
||||||
) {
|
) {
|
||||||
val grouped = posts.groupBy { it.created_at.asZonedDateTime().month }
|
val grouped = posts.groupBy { it.createdAt.asZonedDateTime().month }
|
||||||
grouped.forEach { (month, posts) ->
|
grouped.forEach { (month, posts) ->
|
||||||
stickyHeader {
|
stickyHeader {
|
||||||
MonthHeader(month = month)
|
MonthHeader(month = month)
|
||||||
|
@ -36,8 +36,8 @@ fun SavedPosts(
|
||||||
LobstersItem(
|
LobstersItem(
|
||||||
post = item,
|
post = item,
|
||||||
isSaved = true,
|
isSaved = true,
|
||||||
onClick = { urlLauncher.launch(item.url.ifEmpty { item.comments_url }) },
|
onClick = { urlLauncher.launch(item.url.ifEmpty { item.commentsUrl }) },
|
||||||
onLongClick = { urlLauncher.launch(item.comments_url) },
|
onLongClick = { urlLauncher.launch(item.commentsUrl) },
|
||||||
onSaveButtonClick = { saveAction.invoke(item) },
|
onSaveButtonClick = { saveAction.invoke(item) },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ import androidx.paging.Pager
|
||||||
import androidx.paging.PagingConfig
|
import androidx.paging.PagingConfig
|
||||||
import androidx.paging.cachedIn
|
import androidx.paging.cachedIn
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import dev.msfjarvis.lobsters.data.local.LobstersPost
|
import dev.msfjarvis.lobsters.data.local.SavedPost
|
||||||
import dev.msfjarvis.lobsters.data.remote.LobstersPagingSource
|
import dev.msfjarvis.lobsters.data.remote.LobstersPagingSource
|
||||||
import dev.msfjarvis.lobsters.data.repo.LobstersRepository
|
import dev.msfjarvis.lobsters.data.repo.LobstersRepository
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
@ -21,7 +21,7 @@ class LobstersViewModel @Inject constructor(
|
||||||
private val lobstersRepository: LobstersRepository,
|
private val lobstersRepository: LobstersRepository,
|
||||||
private val pagingSource: LobstersPagingSource,
|
private val pagingSource: LobstersPagingSource,
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
private val _savedPosts = MutableStateFlow<List<LobstersPost>>(emptyList())
|
private val _savedPosts = MutableStateFlow<List<SavedPost>>(emptyList())
|
||||||
val savedPosts = _savedPosts.asStateFlow()
|
val savedPosts = _savedPosts.asStateFlow()
|
||||||
val posts = Pager(PagingConfig(25)) {
|
val posts = Pager(PagingConfig(25)) {
|
||||||
pagingSource
|
pagingSource
|
||||||
|
@ -35,9 +35,9 @@ class LobstersViewModel @Inject constructor(
|
||||||
}.launchIn(viewModelScope)
|
}.launchIn(viewModelScope)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun toggleSave(post: LobstersPost) {
|
fun toggleSave(post: SavedPost) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
val isSaved = lobstersRepository.isPostSaved(post.short_id)
|
val isSaved = lobstersRepository.isPostSaved(post.shortId)
|
||||||
if (isSaved) removeSavedPost(post) else savePost(post)
|
if (isSaved) removeSavedPost(post) else savePost(post)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -46,14 +46,14 @@ class LobstersViewModel @Inject constructor(
|
||||||
return lobstersRepository.isPostSaved(postId)
|
return lobstersRepository.isPostSaved(postId)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun savePost(post: LobstersPost) {
|
private fun savePost(post: SavedPost) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
lobstersRepository.addPost(post)
|
lobstersRepository.addPost(post)
|
||||||
_savedPosts.value = lobstersRepository.getAllPostsFromCache()
|
_savedPosts.value = lobstersRepository.getAllPostsFromCache()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun removeSavedPost(post: LobstersPost) {
|
private fun removeSavedPost(post: SavedPost) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
lobstersRepository.removePost(post)
|
lobstersRepository.removePost(post)
|
||||||
_savedPosts.value = lobstersRepository.getAllPostsFromCache()
|
_savedPosts.value = lobstersRepository.getAllPostsFromCache()
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
package dev.msfjarvis.lobsters.util
|
||||||
|
|
||||||
|
import dev.msfjarvis.lobsters.data.local.SavedPost
|
||||||
|
import dev.msfjarvis.lobsters.model.LobstersPost
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a [LobstersPost] object returned by the API into a [SavedPost] for persistence.
|
||||||
|
*/
|
||||||
|
fun LobstersPost.toDbModel(): SavedPost {
|
||||||
|
return SavedPost(
|
||||||
|
shortId = shortId,
|
||||||
|
title = title,
|
||||||
|
url = url,
|
||||||
|
createdAt = createdAt,
|
||||||
|
commentsUrl = commentsUrl,
|
||||||
|
submitterName = submitterUser.username,
|
||||||
|
submitterAvatarUrl = submitterUser.avatarUrl,
|
||||||
|
tags = tags,
|
||||||
|
)
|
||||||
|
}
|
|
@ -1,3 +1,12 @@
|
||||||
plugins {
|
plugins {
|
||||||
`lobsters-plugin`
|
`lobsters-plugin`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
subprojects {
|
||||||
|
configurations.configureEach {
|
||||||
|
resolutionStrategy {
|
||||||
|
// Retrofit depends on a very old version of Moshi that causes moshi-ksp to fail
|
||||||
|
force(Dependencies.ThirdParty.Moshi.lib)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -71,7 +71,7 @@ object Dependencies {
|
||||||
|
|
||||||
private const val version = "1.11.0"
|
private const val version = "1.11.0"
|
||||||
const val lib = "com.squareup.moshi:moshi:$version"
|
const val lib = "com.squareup.moshi:moshi:$version"
|
||||||
const val moshiMetadataReflect = "dev.zacsweers.moshix:moshi-metadata-reflect:0.9.1"
|
const val ksp = "dev.zacsweers.moshix:moshi-ksp:0.9.1"
|
||||||
}
|
}
|
||||||
|
|
||||||
object Retrofit {
|
object Retrofit {
|
||||||
|
|
|
@ -5,8 +5,6 @@ plugins {
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(Dependencies.ThirdParty.Moshi.lib)
|
|
||||||
implementation(Dependencies.ThirdParty.Moshi.moshiMetadataReflect)
|
|
||||||
testImplementation(Dependencies.Kotlin.Coroutines.core)
|
testImplementation(Dependencies.Kotlin.Coroutines.core)
|
||||||
testImplementation(Dependencies.ThirdParty.SQLDelight.jvmDriver)
|
testImplementation(Dependencies.ThirdParty.SQLDelight.jvmDriver)
|
||||||
testImplementation(Dependencies.Testing.junit)
|
testImplementation(Dependencies.Testing.junit)
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
package dev.msfjarvis.lobsters.model
|
|
||||||
|
|
||||||
import com.squareup.moshi.JsonAdapter
|
|
||||||
import com.squareup.sqldelight.ColumnAdapter
|
|
||||||
|
|
||||||
class SubmitterAdapter(private val submitterJsonAdapter: JsonAdapter<Submitter>) :
|
|
||||||
ColumnAdapter<Submitter, String> {
|
|
||||||
|
|
||||||
override fun decode(databaseValue: String): Submitter {
|
|
||||||
return submitterJsonAdapter.fromJson(databaseValue)!!
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun encode(value: Submitter): String {
|
|
||||||
return submitterJsonAdapter.toJson(value)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,45 +0,0 @@
|
||||||
import dev.msfjarvis.lobsters.model.Submitter;
|
|
||||||
import java.lang.Boolean;
|
|
||||||
import kotlin.collections.List;
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS LobstersPost(
|
|
||||||
short_id TEXT NOT NULL PRIMARY KEY,
|
|
||||||
short_id_url TEXT NOT NULL,
|
|
||||||
created_at TEXT NOT NULL,
|
|
||||||
title TEXT NOT NULL,
|
|
||||||
url TEXT NOT NULL,
|
|
||||||
score INTEGER NOT NULL,
|
|
||||||
flags INTEGER NOT NULL,
|
|
||||||
comment_count INTEGER NOT NULL,
|
|
||||||
description TEXT NOT NULL,
|
|
||||||
comments_url TEXT NOT NULL,
|
|
||||||
submitter_user TEXT as Submitter NOT NULL,
|
|
||||||
tags TEXT as List<String> NOT NULL
|
|
||||||
);
|
|
||||||
|
|
||||||
selectPost:
|
|
||||||
SELECT *
|
|
||||||
FROM LobstersPost
|
|
||||||
WHERE short_id = ?;
|
|
||||||
|
|
||||||
selectAllPosts:
|
|
||||||
SELECT *
|
|
||||||
FROM LobstersPost;
|
|
||||||
|
|
||||||
insertOrReplacePost:
|
|
||||||
INSERT OR REPLACE
|
|
||||||
INTO LobstersPost
|
|
||||||
VALUES ?;
|
|
||||||
|
|
||||||
deletePost:
|
|
||||||
DELETE
|
|
||||||
FROM LobstersPost
|
|
||||||
WHERE short_id = ?;
|
|
||||||
|
|
||||||
deleteAllPosts:
|
|
||||||
DELETE
|
|
||||||
FROM LobstersPost;
|
|
||||||
|
|
||||||
selectCount:
|
|
||||||
SELECT COUNT(*)
|
|
||||||
FROM LobstersPost;
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
import kotlin.collections.List;
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS SavedPost(
|
||||||
|
shortId TEXT NOT NULL PRIMARY KEY,
|
||||||
|
title TEXT NOT NULL,
|
||||||
|
url TEXT NOT NULL,
|
||||||
|
createdAt TEXT NOT NULL,
|
||||||
|
commentsUrl TEXT NOT NULL,
|
||||||
|
submitterName TEXT NOT NULL,
|
||||||
|
submitterAvatarUrl TEXT NOT NULL,
|
||||||
|
tags TEXT as List<String> NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
insertOrReplacePost:
|
||||||
|
INSERT OR REPLACE
|
||||||
|
INTO SavedPost
|
||||||
|
VALUES ?;
|
||||||
|
|
||||||
|
selectAllPosts:
|
||||||
|
SELECT *
|
||||||
|
FROM SavedPost;
|
||||||
|
|
||||||
|
selectCount:
|
||||||
|
SELECT COUNT(*)
|
||||||
|
FROM SavedPost;
|
||||||
|
|
||||||
|
deleteAllPosts:
|
||||||
|
DELETE
|
||||||
|
FROM SavedPost;
|
||||||
|
|
||||||
|
deletePost:
|
||||||
|
DELETE
|
||||||
|
FROM SavedPost
|
||||||
|
WHERE shortId = ?;
|
||||||
|
|
||||||
|
selectPost:
|
||||||
|
SELECT *
|
||||||
|
FROM SavedPost
|
||||||
|
WHERE shortId = ?;
|
|
@ -1,13 +1,8 @@
|
||||||
package dev.msfjarvis.lobsters.data.local
|
package dev.msfjarvis.lobsters.data.local
|
||||||
|
|
||||||
import com.squareup.moshi.Moshi
|
|
||||||
import com.squareup.moshi.adapter
|
|
||||||
import com.squareup.sqldelight.sqlite.driver.JdbcSqliteDriver
|
import com.squareup.sqldelight.sqlite.driver.JdbcSqliteDriver
|
||||||
import dev.msfjarvis.lobsters.database.LobstersDatabase
|
import dev.msfjarvis.lobsters.database.LobstersDatabase
|
||||||
import dev.msfjarvis.lobsters.model.Submitter
|
|
||||||
import dev.msfjarvis.lobsters.model.SubmitterAdapter
|
|
||||||
import dev.msfjarvis.lobsters.model.TagsAdapter
|
import dev.msfjarvis.lobsters.model.TagsAdapter
|
||||||
import dev.zacsweers.moshix.reflect.MetadataKotlinJsonAdapterFactory
|
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import org.junit.Assert.assertEquals
|
import org.junit.Assert.assertEquals
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
|
@ -16,19 +11,17 @@ import org.junit.Test
|
||||||
@OptIn(ExperimentalStdlibApi::class)
|
@OptIn(ExperimentalStdlibApi::class)
|
||||||
class SqlDelightQueriesTest {
|
class SqlDelightQueriesTest {
|
||||||
|
|
||||||
private lateinit var postQueries: PostQueries
|
private lateinit var postQueries: SavedPostQueries
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
fun setUp() {
|
fun setUp() {
|
||||||
val moshi = Moshi.Builder().add(MetadataKotlinJsonAdapterFactory()).build()
|
|
||||||
val submitterJsonAdapter = moshi.adapter<Submitter>()
|
|
||||||
val driver = JdbcSqliteDriver(JdbcSqliteDriver.IN_MEMORY)
|
val driver = JdbcSqliteDriver(JdbcSqliteDriver.IN_MEMORY)
|
||||||
LobstersDatabase.Schema.create(driver)
|
LobstersDatabase.Schema.create(driver)
|
||||||
val database = LobstersDatabase(
|
val database = LobstersDatabase(
|
||||||
driver,
|
driver,
|
||||||
LobstersPost.Adapter(SubmitterAdapter(submitterJsonAdapter), TagsAdapter())
|
SavedPost.Adapter(TagsAdapter()),
|
||||||
)
|
)
|
||||||
postQueries = database.postQueries
|
postQueries = database.savedPostQueries
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -63,7 +56,7 @@ class SqlDelightQueriesTest {
|
||||||
postQueries.insertOrReplacePost(post)
|
postQueries.insertOrReplacePost(post)
|
||||||
|
|
||||||
// Create a new post and try replacing it
|
// Create a new post and try replacing it
|
||||||
val newPost = post.copy(comment_count = 100)
|
val newPost = post.copy(submitterName = "Fake name")
|
||||||
postQueries.insertOrReplacePost(newPost)
|
postQueries.insertOrReplacePost(newPost)
|
||||||
|
|
||||||
// Check post count
|
// Check post count
|
||||||
|
@ -71,8 +64,8 @@ class SqlDelightQueriesTest {
|
||||||
assertEquals(1, postsCount)
|
assertEquals(1, postsCount)
|
||||||
|
|
||||||
// Check if post is updated
|
// Check if post is updated
|
||||||
val postFromDb = postQueries.selectPost(post.short_id).executeAsOne()
|
val postFromDb = postQueries.selectPost(post.shortId).executeAsOne()
|
||||||
assertEquals(100, postFromDb.comment_count)
|
assertEquals("Fake name", postFromDb.submitterName)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -84,7 +77,7 @@ class SqlDelightQueriesTest {
|
||||||
postQueries.insertOrReplacePost(post)
|
postQueries.insertOrReplacePost(post)
|
||||||
|
|
||||||
val postFromDb = postQueries.selectAllPosts().executeAsOne()
|
val postFromDb = postQueries.selectAllPosts().executeAsOne()
|
||||||
assertEquals("test_id_1", postFromDb.short_id)
|
assertEquals("test_id_1", postFromDb.shortId)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -97,9 +90,9 @@ class SqlDelightQueriesTest {
|
||||||
|
|
||||||
val postsFromDb = postQueries.selectAllPosts().executeAsList()
|
val postsFromDb = postQueries.selectAllPosts().executeAsList()
|
||||||
|
|
||||||
// Check if all posts have correct short_id
|
// Check if all posts have correct shortId
|
||||||
for (i in 1..5) {
|
for (i in 1..5) {
|
||||||
assertEquals("test_id_$i", postsFromDb[i - 1].short_id)
|
assertEquals("test_id_$i", postsFromDb[i - 1].shortId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,8 +109,8 @@ class SqlDelightQueriesTest {
|
||||||
|
|
||||||
// Check if size is 2, and only the correct post is deleted
|
// Check if size is 2, and only the correct post is deleted
|
||||||
assertEquals(2, postsFromDB.size)
|
assertEquals(2, postsFromDB.size)
|
||||||
assertEquals("test_id_1", postsFromDB[0].short_id)
|
assertEquals("test_id_1", postsFromDB[0].shortId)
|
||||||
assertEquals("test_id_3", postsFromDB[1].short_id)
|
assertEquals("test_id_3", postsFromDB[1].shortId)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -136,32 +129,18 @@ class SqlDelightQueriesTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun createTestData(count: Int): ArrayList<LobstersPost> {
|
private fun createTestData(count: Int): ArrayList<SavedPost> {
|
||||||
val posts = arrayListOf<LobstersPost>()
|
val posts = arrayListOf<SavedPost>()
|
||||||
|
|
||||||
for (i in 1..count) {
|
for (i in 1..count) {
|
||||||
val submitter = Submitter(
|
val post = SavedPost(
|
||||||
username = "test_user_$i",
|
shortId = "test_id_$i",
|
||||||
createdAt = "0",
|
createdAt = "0",
|
||||||
about = "test",
|
|
||||||
avatarUrl = "test_avatar_url",
|
|
||||||
invitedByUser = "test_user",
|
|
||||||
isAdmin = false,
|
|
||||||
isModerator = false
|
|
||||||
)
|
|
||||||
|
|
||||||
val post = LobstersPost(
|
|
||||||
short_id = "test_id_$i",
|
|
||||||
short_id_url = "test_id_url",
|
|
||||||
created_at = "0",
|
|
||||||
title = "test",
|
title = "test",
|
||||||
url = "test_url",
|
url = "test_url",
|
||||||
score = 0,
|
commentsUrl = "test_comments_url",
|
||||||
flags = 0,
|
submitterName = "test_user_$i",
|
||||||
comment_count = 0,
|
submitterAvatarUrl = "test_avatar_url",
|
||||||
description = "test",
|
|
||||||
comments_url = "test_comments_url",
|
|
||||||
submitter_user = submitter,
|
|
||||||
tags = listOf(),
|
tags = listOf(),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,9 @@
|
||||||
rootProject.name = "Claw"
|
rootProject.name = "Claw"
|
||||||
include(":app", ":api", ":database")
|
include(":app", ":api", ":database")
|
||||||
enableFeaturePreview("GRADLE_METADATA")
|
enableFeaturePreview("GRADLE_METADATA")
|
||||||
|
pluginManagement {
|
||||||
|
repositories {
|
||||||
|
google()
|
||||||
|
gradlePluginPortal()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue