diff --git a/.github/ci-gradle.properties b/.github/ci-gradle.properties
new file mode 100644
index 00000000..e32ec00b
--- /dev/null
+++ b/.github/ci-gradle.properties
@@ -0,0 +1 @@
+org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml
index f2f7394e..e1068afe 100644
--- a/.github/workflows/pull_request.yml
+++ b/.github/workflows/pull_request.yml
@@ -10,12 +10,17 @@ jobs:
test-pr:
runs-on: macOS-latest
steps:
+
- uses: actions/setup-java@d202f5dbf7256730fb690ec59f6381650114feb2
with:
java-version: '11'
+
- name: Checkout repository
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
name: Run unit tests
with:
diff --git a/.idea/kotlinScripting.xml b/.idea/kotlinScripting.xml
new file mode 100644
index 00000000..bc444dea
--- /dev/null
+++ b/.idea/kotlinScripting.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/api/build.gradle.kts b/api/build.gradle.kts
index 831037f2..519bbbfa 100644
--- a/api/build.gradle.kts
+++ b/api/build.gradle.kts
@@ -1,12 +1,12 @@
plugins {
kotlin("jvm")
+ id("com.google.devtools.ksp") version "1.4.30-1.0.0-alpha04"
`lobsters-plugin`
}
dependencies {
api(Dependencies.ThirdParty.Retrofit.lib)
- implementation(project(":database"))
- implementation(Dependencies.ThirdParty.Moshi.moshiMetadataReflect)
+ ksp(Dependencies.ThirdParty.Moshi.ksp)
implementation(Dependencies.ThirdParty.Retrofit.moshi)
testImplementation(Dependencies.Kotlin.Coroutines.core)
testImplementation(Dependencies.Testing.junit)
diff --git a/api/src/main/java/dev/msfjarvis/lobsters/data/api/LobstersApi.kt b/api/src/main/java/dev/msfjarvis/lobsters/data/api/LobstersApi.kt
index 9e2f4cff..b924fb3f 100644
--- a/api/src/main/java/dev/msfjarvis/lobsters/data/api/LobstersApi.kt
+++ b/api/src/main/java/dev/msfjarvis/lobsters/data/api/LobstersApi.kt
@@ -1,6 +1,6 @@
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.Query
diff --git a/database/src/main/java/dev/msfjarvis/lobsters/model/KeybaseSignature.kt b/api/src/main/java/dev/msfjarvis/lobsters/model/KeybaseSignature.kt
similarity index 65%
rename from database/src/main/java/dev/msfjarvis/lobsters/model/KeybaseSignature.kt
rename to api/src/main/java/dev/msfjarvis/lobsters/model/KeybaseSignature.kt
index c1cc62ed..243bdff9 100644
--- a/database/src/main/java/dev/msfjarvis/lobsters/model/KeybaseSignature.kt
+++ b/api/src/main/java/dev/msfjarvis/lobsters/model/KeybaseSignature.kt
@@ -1,10 +1,12 @@
package dev.msfjarvis.lobsters.model
import com.squareup.moshi.Json
+import com.squareup.moshi.JsonClass
+@JsonClass(generateAdapter = true)
class KeybaseSignature(
@Json(name = "kb_username")
val kbUsername: String,
@Json(name = "sig_hash")
- val sigHash: String
+ val sigHash: String,
)
diff --git a/api/src/main/java/dev/msfjarvis/lobsters/model/LobstersPost.kt b/api/src/main/java/dev/msfjarvis/lobsters/model/LobstersPost.kt
new file mode 100644
index 00000000..f6d947bd
--- /dev/null
+++ b/api/src/main/java/dev/msfjarvis/lobsters/model/LobstersPost.kt
@@ -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,
+)
diff --git a/database/src/main/java/dev/msfjarvis/lobsters/model/Submitter.kt b/api/src/main/java/dev/msfjarvis/lobsters/model/Submitter.kt
similarity index 82%
rename from database/src/main/java/dev/msfjarvis/lobsters/model/Submitter.kt
rename to api/src/main/java/dev/msfjarvis/lobsters/model/Submitter.kt
index e76e3de1..ea739b74 100644
--- a/database/src/main/java/dev/msfjarvis/lobsters/model/Submitter.kt
+++ b/api/src/main/java/dev/msfjarvis/lobsters/model/Submitter.kt
@@ -1,7 +1,9 @@
package dev.msfjarvis.lobsters.model
import com.squareup.moshi.Json
+import com.squareup.moshi.JsonClass
+@JsonClass(generateAdapter = true)
class Submitter(
val username: String,
@Json(name = "created_at")
@@ -21,5 +23,5 @@ class Submitter(
@Json(name = "twitter_username")
val twitterUsername: String? = null,
@Json(name = "keybase_signatures")
- val keybaseSignatures: List = emptyList()
+ val keybaseSignatures: List = emptyList(),
)
diff --git a/api/src/test/java/dev/msfjarvis/lobsters/data/api/LobstersApiTest.kt b/api/src/test/java/dev/msfjarvis/lobsters/data/api/LobstersApiTest.kt
index 8ece55f3..81e23c5b 100644
--- a/api/src/test/java/dev/msfjarvis/lobsters/data/api/LobstersApiTest.kt
+++ b/api/src/test/java/dev/msfjarvis/lobsters/data/api/LobstersApiTest.kt
@@ -2,7 +2,6 @@ package dev.msfjarvis.lobsters.data.api
import com.squareup.moshi.Moshi
import dev.msfjarvis.lobsters.util.TestUtils
-import dev.zacsweers.moshix.reflect.MetadataKotlinJsonAdapterFactory
import kotlinx.coroutines.runBlocking
import mockwebserver3.Dispatcher
import mockwebserver3.MockResponse
@@ -24,7 +23,6 @@ class LobstersApiTest {
private val webServer = MockWebServer()
private val apiData = TestUtils.getJson("hottest.json")
private val moshi = Moshi.Builder()
- .add(MetadataKotlinJsonAdapterFactory())
.build()
private val okHttp = OkHttpClient.Builder()
.build()
@@ -63,7 +61,7 @@ class LobstersApiTest {
fun `no moderator posts in test data`() = runBlocking {
val posts = apiClient.getHottestPosts(1)
val moderatorPosts = posts.asSequence()
- .filter { it.submitter_user.isModerator }
+ .filter { it.submitterUser.isModerator }
.toSet()
assertTrue(moderatorPosts.isEmpty())
}
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 41aece73..21adc11f 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -54,7 +54,6 @@ dependencies {
implementation(Dependencies.Kotlin.Coroutines.android)
implementation(Dependencies.ThirdParty.accompanist)
implementation(Dependencies.ThirdParty.Moshi.lib)
- implementation(Dependencies.ThirdParty.Moshi.moshiMetadataReflect)
implementation(Dependencies.ThirdParty.Retrofit.moshi)
implementation(Dependencies.ThirdParty.SQLDelight.androidDriver)
testImplementation(Dependencies.Testing.junit)
diff --git a/app/src/main/java/dev/msfjarvis/lobsters/data/remote/LobstersPagingSource.kt b/app/src/main/java/dev/msfjarvis/lobsters/data/remote/LobstersPagingSource.kt
index f50b5c2e..766d4f88 100644
--- a/app/src/main/java/dev/msfjarvis/lobsters/data/remote/LobstersPagingSource.kt
+++ b/app/src/main/java/dev/msfjarvis/lobsters/data/remote/LobstersPagingSource.kt
@@ -2,8 +2,8 @@ package dev.msfjarvis.lobsters.data.remote
import androidx.paging.PagingSource
import androidx.paging.PagingState
-import dev.msfjarvis.lobsters.data.local.LobstersPost
import dev.msfjarvis.lobsters.data.repo.LobstersRepository
+import dev.msfjarvis.lobsters.model.LobstersPost
import javax.inject.Inject
class LobstersPagingSource @Inject constructor(
diff --git a/app/src/main/java/dev/msfjarvis/lobsters/data/repo/LobstersRepository.kt b/app/src/main/java/dev/msfjarvis/lobsters/data/repo/LobstersRepository.kt
index 18e6f5c9..afba5a1e 100644
--- a/app/src/main/java/dev/msfjarvis/lobsters/data/repo/LobstersRepository.kt
+++ b/app/src/main/java/dev/msfjarvis/lobsters/data/repo/LobstersRepository.kt
@@ -1,7 +1,8 @@
package dev.msfjarvis.lobsters.data.repo
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 kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
@@ -13,7 +14,7 @@ class LobstersRepository constructor(
private val lobstersDatabase: LobstersDatabase,
) {
- private val savedPostsCache: MutableMap = mutableMapOf()
+ private val savedPostsCache: MutableMap = mutableMapOf()
private val _isCacheReady = MutableStateFlow(false)
val isCacheReady = _isCacheReady.asStateFlow()
@@ -21,7 +22,7 @@ class LobstersRepository constructor(
return savedPostsCache.containsKey(postId)
}
- fun getAllPostsFromCache(): List {
+ fun getAllPostsFromCache(): List {
return savedPostsCache.values.toList()
}
@@ -31,29 +32,29 @@ class LobstersRepository constructor(
suspend fun updateCache() {
if (_isCacheReady.value) return
- val posts = getAllPosts()
+ val posts = getSavedPosts()
posts.forEach {
- savedPostsCache[it.short_id] = it
+ savedPostsCache[it.shortId] = it
}
_isCacheReady.value = true
}
- private suspend fun getAllPosts(): List = withContext(Dispatchers.IO) {
- return@withContext lobstersDatabase.postQueries.selectAllPosts().executeAsList()
+ private suspend fun getSavedPosts(): List = withContext(Dispatchers.IO) {
+ return@withContext lobstersDatabase.savedPostQueries.selectAllPosts().executeAsList()
}
- suspend fun addPost(post: LobstersPost) = withContext(Dispatchers.IO) {
- if (!savedPostsCache.containsKey(post.short_id)) {
- savedPostsCache.putIfAbsent(post.short_id, post)
- lobstersDatabase.postQueries.insertOrReplacePost(post)
+ suspend fun addPost(post: SavedPost) = withContext(Dispatchers.IO) {
+ if (!savedPostsCache.containsKey(post.shortId)) {
+ savedPostsCache.putIfAbsent(post.shortId, post)
+ lobstersDatabase.savedPostQueries.insertOrReplacePost(post)
}
}
- suspend fun removePost(post: LobstersPost) = withContext(Dispatchers.IO) {
- if (savedPostsCache.containsKey(post.short_id)) {
- savedPostsCache.remove(post.short_id)
- lobstersDatabase.postQueries.deletePost(post.short_id)
+ suspend fun removePost(post: SavedPost) = withContext(Dispatchers.IO) {
+ if (savedPostsCache.containsKey(post.shortId)) {
+ savedPostsCache.remove(post.shortId)
+ lobstersDatabase.savedPostQueries.deletePost(post.shortId)
}
}
}
diff --git a/app/src/main/java/dev/msfjarvis/lobsters/injection/DatabaseModule.kt b/app/src/main/java/dev/msfjarvis/lobsters/injection/DatabaseModule.kt
index b0f461be..68fd581c 100644
--- a/app/src/main/java/dev/msfjarvis/lobsters/injection/DatabaseModule.kt
+++ b/app/src/main/java/dev/msfjarvis/lobsters/injection/DatabaseModule.kt
@@ -1,7 +1,6 @@
package dev.msfjarvis.lobsters.injection
import android.content.Context
-import com.squareup.moshi.JsonAdapter
import com.squareup.sqldelight.android.AndroidSqliteDriver
import com.squareup.sqldelight.db.SqlDriver
import dagger.Module
@@ -10,10 +9,8 @@ import dagger.Reusable
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
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.model.Submitter
-import dev.msfjarvis.lobsters.model.SubmitterAdapter
import dev.msfjarvis.lobsters.model.TagsAdapter
import javax.inject.Singleton
@@ -21,12 +18,6 @@ import javax.inject.Singleton
@InstallIn(SingletonComponent::class)
object DatabaseModule {
- @Provides
- @Reusable
- fun providesSubmitterAdapter(jsonAdapter: JsonAdapter): SubmitterAdapter {
- return SubmitterAdapter(jsonAdapter)
- }
-
@Provides
@Reusable
fun providesTagsAdapter(): TagsAdapter {
@@ -43,12 +34,11 @@ object DatabaseModule {
@Singleton
fun providesLobstersDatabase(
sqlDriver: SqlDriver,
- submitterAdapter: SubmitterAdapter,
tagsAdapter: TagsAdapter
): LobstersDatabase {
return LobstersDatabase(
sqlDriver,
- LobstersPost.Adapter(submitterAdapter, tagsAdapter)
+ SavedPost.Adapter(tagsAdapter),
)
}
}
diff --git a/app/src/main/java/dev/msfjarvis/lobsters/injection/MoshiModule.kt b/app/src/main/java/dev/msfjarvis/lobsters/injection/MoshiModule.kt
index 750ab673..3f0b22e7 100644
--- a/app/src/main/java/dev/msfjarvis/lobsters/injection/MoshiModule.kt
+++ b/app/src/main/java/dev/msfjarvis/lobsters/injection/MoshiModule.kt
@@ -1,15 +1,11 @@
package dev.msfjarvis.lobsters.injection
-import com.squareup.moshi.JsonAdapter
import com.squareup.moshi.Moshi
-import com.squareup.moshi.adapter
import dagger.Module
import dagger.Provides
import dagger.Reusable
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
-import dev.msfjarvis.lobsters.model.Submitter
-import dev.zacsweers.moshix.reflect.MetadataKotlinJsonAdapterFactory
@Module
@InstallIn(SingletonComponent::class)
@@ -18,14 +14,6 @@ object MoshiModule {
@Reusable
fun provideMoshi(): Moshi {
return Moshi.Builder()
- .add(MetadataKotlinJsonAdapterFactory())
.build()
}
-
- @OptIn(ExperimentalStdlibApi::class)
- @Provides
- @Reusable
- fun provideSubmitterJsonAdapter(moshi: Moshi): JsonAdapter {
- return moshi.adapter()
- }
}
diff --git a/app/src/main/java/dev/msfjarvis/lobsters/ui/posts/HottestPosts.kt b/app/src/main/java/dev/msfjarvis/lobsters/ui/posts/HottestPosts.kt
index b5f16348..ae3371b4 100644
--- a/app/src/main/java/dev/msfjarvis/lobsters/ui/posts/HottestPosts.kt
+++ b/app/src/main/java/dev/msfjarvis/lobsters/ui/posts/HottestPosts.kt
@@ -11,8 +11,10 @@ import androidx.compose.ui.Modifier
import androidx.paging.LoadState
import androidx.paging.compose.LazyPagingItems
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.util.toDbModel
@Composable
fun HottestPosts(
@@ -20,7 +22,7 @@ fun HottestPosts(
listState: LazyListState,
isPostSaved: (String) -> Boolean,
modifier: Modifier = Modifier,
- saveAction: (LobstersPost) -> Unit,
+ saveAction: (SavedPost) -> Unit,
) {
val urlLauncher = LocalUrlLauncher.current
@@ -33,13 +35,15 @@ fun HottestPosts(
) {
items(posts) { item ->
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(
post = item,
isSaved = isSaved,
- onClick = { urlLauncher.launch(item.url.ifEmpty { item.comments_url }) },
- onLongClick = { urlLauncher.launch(item.comments_url) },
+ onClick = { urlLauncher.launch(item.url.ifEmpty { item.commentsUrl }) },
+ onLongClick = { urlLauncher.launch(item.commentsUrl) },
onSaveButtonClick = {
isSaved = isSaved.not()
saveAction.invoke(item)
diff --git a/app/src/main/java/dev/msfjarvis/lobsters/ui/posts/LobstersItem.kt b/app/src/main/java/dev/msfjarvis/lobsters/ui/posts/LobstersItem.kt
index 9f77715d..41f4d461 100644
--- a/app/src/main/java/dev/msfjarvis/lobsters/ui/posts/LobstersItem.kt
+++ b/app/src/main/java/dev/msfjarvis/lobsters/ui/posts/LobstersItem.kt
@@ -29,43 +29,26 @@ import coil.transform.CircleCropTransformation
import dev.chrisbanes.accompanist.coil.CoilImage
import dev.msfjarvis.lobsters.R
import dev.msfjarvis.lobsters.data.api.LobstersApi
-import dev.msfjarvis.lobsters.data.local.LobstersPost
-import dev.msfjarvis.lobsters.model.Submitter
+import dev.msfjarvis.lobsters.data.local.SavedPost
import dev.msfjarvis.lobsters.ui.theme.LobstersTheme
import dev.msfjarvis.lobsters.ui.theme.titleColor
import dev.msfjarvis.lobsters.util.IconResource
-val TEST_POST = LobstersPost(
- "zqyydb",
- "https://lobste.rs/s/zqyydb",
- "2020-09-21T07:11:14.000-05:00",
- "k2k20 hackathon report: Bob Beck on LibreSSL progress",
- "https://undeadly.org/cgi?action=article;sid=20200921105847",
- 4,
- 0,
- 0,
- "",
- "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"),
+val TEST_POST = SavedPost(
+ shortId = "zqyydb",
+ title = "k2k20 hackathon report: Bob Beck on LibreSSL progress",
+ url = "https://undeadly.org/cgi?action=article;sid=20200921105847",
+ createdAt = "2020-09-21T07:11:14.000-05:00",
+ commentsUrl = "https://lobste.rs/s/zqyydb/k2k20_hackathon_report_bob_beck_on",
+ submitterName = "Vigdis",
+ submitterAvatarUrl = "/avatars/Vigdis-100.png",
+ tags = listOf("openbsd", "linux", "containers", "hack the planet", "no thanks"),
)
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun LobstersItem(
- post: LobstersPost,
+ post: SavedPost,
isSaved: Boolean,
onClick: () -> Unit,
onLongClick: () -> Unit,
@@ -99,10 +82,10 @@ fun LobstersItem(
)
Row {
CoilImage(
- data = "${LobstersApi.BASE_URL}/${post.submitter_user.avatarUrl}",
+ data = "${LobstersApi.BASE_URL}/${post.submitterAvatarUrl}",
contentDescription = stringResource(
R.string.avatar_content_description,
- post.submitter_user.username
+ post.submitterName
),
fadeIn = true,
requestBuilder = {
@@ -113,7 +96,7 @@ fun LobstersItem(
.padding(4.dp),
)
Text(
- text = stringResource(id = R.string.submitted_by, post.submitter_user.username),
+ text = stringResource(id = R.string.submitted_by, post.submitterName),
modifier = Modifier
.padding(4.dp),
)
diff --git a/app/src/main/java/dev/msfjarvis/lobsters/ui/posts/SavedPosts.kt b/app/src/main/java/dev/msfjarvis/lobsters/ui/posts/SavedPosts.kt
index d88df6a0..518658bc 100644
--- a/app/src/main/java/dev/msfjarvis/lobsters/ui/posts/SavedPosts.kt
+++ b/app/src/main/java/dev/msfjarvis/lobsters/ui/posts/SavedPosts.kt
@@ -6,16 +6,16 @@ import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.runtime.Composable
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.util.asZonedDateTime
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun SavedPosts(
- posts: List,
+ posts: List,
modifier: Modifier = Modifier,
- saveAction: (LobstersPost) -> Unit,
+ saveAction: (SavedPost) -> Unit,
) {
val listState = rememberLazyListState()
val urlLauncher = LocalUrlLauncher.current
@@ -27,7 +27,7 @@ fun SavedPosts(
state = listState,
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) ->
stickyHeader {
MonthHeader(month = month)
@@ -36,8 +36,8 @@ fun SavedPosts(
LobstersItem(
post = item,
isSaved = true,
- onClick = { urlLauncher.launch(item.url.ifEmpty { item.comments_url }) },
- onLongClick = { urlLauncher.launch(item.comments_url) },
+ onClick = { urlLauncher.launch(item.url.ifEmpty { item.commentsUrl }) },
+ onLongClick = { urlLauncher.launch(item.commentsUrl) },
onSaveButtonClick = { saveAction.invoke(item) },
)
}
diff --git a/app/src/main/java/dev/msfjarvis/lobsters/ui/viewmodel/LobstersViewModel.kt b/app/src/main/java/dev/msfjarvis/lobsters/ui/viewmodel/LobstersViewModel.kt
index 043006ce..c4e2fd4a 100644
--- a/app/src/main/java/dev/msfjarvis/lobsters/ui/viewmodel/LobstersViewModel.kt
+++ b/app/src/main/java/dev/msfjarvis/lobsters/ui/viewmodel/LobstersViewModel.kt
@@ -6,7 +6,7 @@ import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.cachedIn
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.repo.LobstersRepository
import javax.inject.Inject
@@ -21,7 +21,7 @@ class LobstersViewModel @Inject constructor(
private val lobstersRepository: LobstersRepository,
private val pagingSource: LobstersPagingSource,
) : ViewModel() {
- private val _savedPosts = MutableStateFlow>(emptyList())
+ private val _savedPosts = MutableStateFlow>(emptyList())
val savedPosts = _savedPosts.asStateFlow()
val posts = Pager(PagingConfig(25)) {
pagingSource
@@ -35,9 +35,9 @@ class LobstersViewModel @Inject constructor(
}.launchIn(viewModelScope)
}
- fun toggleSave(post: LobstersPost) {
+ fun toggleSave(post: SavedPost) {
viewModelScope.launch {
- val isSaved = lobstersRepository.isPostSaved(post.short_id)
+ val isSaved = lobstersRepository.isPostSaved(post.shortId)
if (isSaved) removeSavedPost(post) else savePost(post)
}
}
@@ -46,14 +46,14 @@ class LobstersViewModel @Inject constructor(
return lobstersRepository.isPostSaved(postId)
}
- private fun savePost(post: LobstersPost) {
+ private fun savePost(post: SavedPost) {
viewModelScope.launch {
lobstersRepository.addPost(post)
_savedPosts.value = lobstersRepository.getAllPostsFromCache()
}
}
- private fun removeSavedPost(post: LobstersPost) {
+ private fun removeSavedPost(post: SavedPost) {
viewModelScope.launch {
lobstersRepository.removePost(post)
_savedPosts.value = lobstersRepository.getAllPostsFromCache()
diff --git a/app/src/main/java/dev/msfjarvis/lobsters/util/DatabaseExtensions.kt b/app/src/main/java/dev/msfjarvis/lobsters/util/DatabaseExtensions.kt
new file mode 100644
index 00000000..13e85a29
--- /dev/null
+++ b/app/src/main/java/dev/msfjarvis/lobsters/util/DatabaseExtensions.kt
@@ -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,
+ )
+}
diff --git a/build.gradle.kts b/build.gradle.kts
index d3d9db38..ee3d8c2b 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -1,3 +1,12 @@
plugins {
`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)
+ }
+ }
+}
diff --git a/buildSrc/src/main/java/Dependencies.kt b/buildSrc/src/main/java/Dependencies.kt
index d2127563..2057680f 100644
--- a/buildSrc/src/main/java/Dependencies.kt
+++ b/buildSrc/src/main/java/Dependencies.kt
@@ -71,7 +71,7 @@ object Dependencies {
private const val version = "1.11.0"
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 {
diff --git a/database/build.gradle.kts b/database/build.gradle.kts
index 17e300c9..e4a4ed55 100644
--- a/database/build.gradle.kts
+++ b/database/build.gradle.kts
@@ -5,8 +5,6 @@ plugins {
}
dependencies {
- implementation(Dependencies.ThirdParty.Moshi.lib)
- implementation(Dependencies.ThirdParty.Moshi.moshiMetadataReflect)
testImplementation(Dependencies.Kotlin.Coroutines.core)
testImplementation(Dependencies.ThirdParty.SQLDelight.jvmDriver)
testImplementation(Dependencies.Testing.junit)
diff --git a/database/src/main/java/dev/msfjarvis/lobsters/model/SubmitterAdapter.kt b/database/src/main/java/dev/msfjarvis/lobsters/model/SubmitterAdapter.kt
deleted file mode 100644
index d89d282a..00000000
--- a/database/src/main/java/dev/msfjarvis/lobsters/model/SubmitterAdapter.kt
+++ /dev/null
@@ -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) :
- ColumnAdapter {
-
- override fun decode(databaseValue: String): Submitter {
- return submitterJsonAdapter.fromJson(databaseValue)!!
- }
-
- override fun encode(value: Submitter): String {
- return submitterJsonAdapter.toJson(value)
- }
-}
diff --git a/database/src/main/sqldelight/dev/msfjarvis/lobsters/data/local/Post.sq b/database/src/main/sqldelight/dev/msfjarvis/lobsters/data/local/Post.sq
deleted file mode 100644
index d2fe2f6f..00000000
--- a/database/src/main/sqldelight/dev/msfjarvis/lobsters/data/local/Post.sq
+++ /dev/null
@@ -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 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;
diff --git a/database/src/main/sqldelight/dev/msfjarvis/lobsters/data/local/SavedPost.sq b/database/src/main/sqldelight/dev/msfjarvis/lobsters/data/local/SavedPost.sq
new file mode 100644
index 00000000..1d88f39b
--- /dev/null
+++ b/database/src/main/sqldelight/dev/msfjarvis/lobsters/data/local/SavedPost.sq
@@ -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 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 = ?;
diff --git a/database/src/test/java/dev/msfjarvis/lobsters/data/local/SqlDelightQueriesTest.kt b/database/src/test/java/dev/msfjarvis/lobsters/data/local/SqlDelightQueriesTest.kt
index 909e8f10..43daf226 100644
--- a/database/src/test/java/dev/msfjarvis/lobsters/data/local/SqlDelightQueriesTest.kt
+++ b/database/src/test/java/dev/msfjarvis/lobsters/data/local/SqlDelightQueriesTest.kt
@@ -1,13 +1,8 @@
package dev.msfjarvis.lobsters.data.local
-import com.squareup.moshi.Moshi
-import com.squareup.moshi.adapter
import com.squareup.sqldelight.sqlite.driver.JdbcSqliteDriver
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.zacsweers.moshix.reflect.MetadataKotlinJsonAdapterFactory
import kotlinx.coroutines.runBlocking
import org.junit.Assert.assertEquals
import org.junit.Before
@@ -16,19 +11,17 @@ import org.junit.Test
@OptIn(ExperimentalStdlibApi::class)
class SqlDelightQueriesTest {
- private lateinit var postQueries: PostQueries
+ private lateinit var postQueries: SavedPostQueries
@Before
fun setUp() {
- val moshi = Moshi.Builder().add(MetadataKotlinJsonAdapterFactory()).build()
- val submitterJsonAdapter = moshi.adapter()
val driver = JdbcSqliteDriver(JdbcSqliteDriver.IN_MEMORY)
LobstersDatabase.Schema.create(driver)
val database = LobstersDatabase(
driver,
- LobstersPost.Adapter(SubmitterAdapter(submitterJsonAdapter), TagsAdapter())
+ SavedPost.Adapter(TagsAdapter()),
)
- postQueries = database.postQueries
+ postQueries = database.savedPostQueries
}
@Test
@@ -63,7 +56,7 @@ class SqlDelightQueriesTest {
postQueries.insertOrReplacePost(post)
// 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)
// Check post count
@@ -71,8 +64,8 @@ class SqlDelightQueriesTest {
assertEquals(1, postsCount)
// Check if post is updated
- val postFromDb = postQueries.selectPost(post.short_id).executeAsOne()
- assertEquals(100, postFromDb.comment_count)
+ val postFromDb = postQueries.selectPost(post.shortId).executeAsOne()
+ assertEquals("Fake name", postFromDb.submitterName)
}
@Test
@@ -84,7 +77,7 @@ class SqlDelightQueriesTest {
postQueries.insertOrReplacePost(post)
val postFromDb = postQueries.selectAllPosts().executeAsOne()
- assertEquals("test_id_1", postFromDb.short_id)
+ assertEquals("test_id_1", postFromDb.shortId)
}
@Test
@@ -97,9 +90,9 @@ class SqlDelightQueriesTest {
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) {
- 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
assertEquals(2, postsFromDB.size)
- assertEquals("test_id_1", postsFromDB[0].short_id)
- assertEquals("test_id_3", postsFromDB[1].short_id)
+ assertEquals("test_id_1", postsFromDB[0].shortId)
+ assertEquals("test_id_3", postsFromDB[1].shortId)
}
@Test
@@ -136,32 +129,18 @@ class SqlDelightQueriesTest {
}
- private fun createTestData(count: Int): ArrayList {
- val posts = arrayListOf()
+ private fun createTestData(count: Int): ArrayList {
+ val posts = arrayListOf()
for (i in 1..count) {
- val submitter = Submitter(
- username = "test_user_$i",
+ val post = SavedPost(
+ shortId = "test_id_$i",
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",
url = "test_url",
- score = 0,
- flags = 0,
- comment_count = 0,
- description = "test",
- comments_url = "test_comments_url",
- submitter_user = submitter,
+ commentsUrl = "test_comments_url",
+ submitterName = "test_user_$i",
+ submitterAvatarUrl = "test_avatar_url",
tags = listOf(),
)
diff --git a/settings.gradle.kts b/settings.gradle.kts
index d35f9890..704d0a6e 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -1,3 +1,9 @@
rootProject.name = "Claw"
include(":app", ":api", ":database")
enableFeaturePreview("GRADLE_METADATA")
+pluginManagement {
+ repositories {
+ google()
+ gradlePluginPortal()
+ }
+}