Skip to content

Commit

Permalink
Add support for unique post ID column (#440)
Browse files Browse the repository at this point in the history
We are creating a UUID based on the post link
  • Loading branch information
msasikanth authored Apr 13, 2024
1 parent c6a5717 commit 92b97ee
Show file tree
Hide file tree
Showing 26 changed files with 337 additions and 117 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package dev.sasikanth.rss.reader.core.model.local
import kotlinx.datetime.Instant

data class Post(
val id: String,
val title: String,
val description: String,
val imageUrl: String?,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import kotlinx.datetime.Instant

@Immutable
data class PostWithMetadata(
val id: String,
val title: String,
val description: String,
val imageUrl: String?,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package dev.sasikanth.rss.reader.database

import android.content.Context
import androidx.sqlite.db.SupportSQLiteDatabase
import app.cash.sqldelight.db.AfterVersion
import app.cash.sqldelight.db.SqlDriver
import app.cash.sqldelight.driver.android.AndroidSqliteDriver
import dev.sasikanth.rss.reader.di.scopes.AppScope
Expand All @@ -25,15 +26,18 @@ import me.tatarka.inject.annotations.Inject

@Inject
@AppScope
actual class DriverFactory(private val context: Context) {
actual class DriverFactory(
private val context: Context,
private val codeMigrations: Array<AfterVersion>,
) {

actual fun createDriver(): SqlDriver {
return AndroidSqliteDriver(
schema = ReaderDatabase.Schema,
context = context,
name = DB_NAME,
callback =
object : AndroidSqliteDriver.Callback(ReaderDatabase.Schema) {
object : AndroidSqliteDriver.Callback(ReaderDatabase.Schema, callbacks = codeMigrations) {
override fun onOpen(db: SupportSQLiteDatabase) {
db.setForeignKeyConstraintsEnabled(true)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import com.arkivanov.essenty.lifecycle.coroutines.coroutineScope
import com.arkivanov.essenty.lifecycle.doOnStart
import dev.sasikanth.rss.reader.about.AboutPresenterFactory
import dev.sasikanth.rss.reader.bookmarks.BookmarksPresenterFactory
import dev.sasikanth.rss.reader.core.model.local.PostWithMetadata
import dev.sasikanth.rss.reader.di.scopes.ActivityScope
import dev.sasikanth.rss.reader.feed.FeedPresenterFactory
import dev.sasikanth.rss.reader.home.HomePresenterFactory
Expand Down Expand Up @@ -160,21 +161,21 @@ class AppPresenter(
}
is Config.Reader -> {
Screen.Reader(
presenter = readerPresenter(config.postLink, componentContext) { navigation.pop() }
presenter = readerPresenter(config.postId, componentContext) { navigation.pop() }
)
}
}

private fun openPost(postLink: String) {
private fun openPost(post: PostWithMetadata) {
scope.launch {
val showReaderView =
withContext(dispatchersProvider.io) { settingsRepository.showReaderView.first() }

if (showReaderView) {
navigation.push(Config.Reader(postLink))
navigation.push(Config.Reader(post.id))
} else {
linkHandler.openLink(postLink)
rssRepository.updatePostReadStatus(read = true, link = postLink)
linkHandler.openLink(post.link)
rssRepository.updatePostReadStatus(read = true, id = post.id)
}
}
}
Expand Down Expand Up @@ -214,7 +215,7 @@ class AppPresenter(

@Serializable data object About : Config

@Serializable data class Reader(val postLink: String) : Config
@Serializable data class Reader(val postId: String) : Config
}

@Serializable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,5 @@ sealed interface BookmarksEvent {

data class OnPostClicked(val post: PostWithMetadata) : BookmarksEvent

data class TogglePostReadStatus(val postLink: String, val postRead: Boolean) : BookmarksEvent
data class TogglePostReadStatus(val postId: String, val postRead: Boolean) : BookmarksEvent
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ internal typealias BookmarksPresenterFactory =
(
ComponentContext,
goBack: () -> Unit,
openReaderView: (String) -> Unit,
openReaderView: (PostWithMetadata) -> Unit,
) -> BookmarksPresenter

@Inject
Expand All @@ -52,7 +52,7 @@ class BookmarksPresenter(
private val rssRepository: RssRepository,
@Assisted componentContext: ComponentContext,
@Assisted private val goBack: () -> Unit,
@Assisted private val openReaderView: (postLink: String) -> Unit,
@Assisted private val openReaderView: (post: PostWithMetadata) -> Unit,
) : ComponentContext by componentContext {

private val presenterInstance =
Expand Down Expand Up @@ -110,28 +110,25 @@ class BookmarksPresenter(
is BookmarksEvent.OnPostClicked -> {
// no-op
}
is BookmarksEvent.TogglePostReadStatus ->
togglePostReadStatus(event.postLink, event.postRead)
is BookmarksEvent.TogglePostReadStatus -> togglePostReadStatus(event.postId, event.postRead)
}
}

private fun togglePostReadStatus(postLink: String, postRead: Boolean) {
coroutineScope.launch {
rssRepository.updatePostReadStatus(read = !postRead, link = postLink)
}
private fun togglePostReadStatus(postId: String, postRead: Boolean) {
coroutineScope.launch { rssRepository.updatePostReadStatus(read = !postRead, id = postId) }
}

fun onPostClicked(
post: PostWithMetadata,
openReaderView: (postLink: String) -> Unit,
openReaderView: (post: PostWithMetadata) -> Unit,
openLink: (postLink: String) -> Unit
) {
coroutineScope.launch {
val hasPost = rssRepository.hasPost(post.link)
val hasPost = rssRepository.hasPost(post.id)
val hasFeed = rssRepository.hasFeed(post.feedLink)

if (hasPost && hasFeed) {
openReaderView(post.link)
openReaderView(post)
} else {
openLink(post.link)
}
Expand All @@ -141,9 +138,9 @@ class BookmarksPresenter(
private fun onPostBookmarkClicked(post: PostWithMetadata) {
coroutineScope.launch {
if (rssRepository.hasFeed(post.feedLink)) {
rssRepository.updateBookmarkStatus(bookmarked = !post.bookmarked, link = post.link)
rssRepository.updateBookmarkStatus(bookmarked = !post.bookmarked, id = post.id)
} else {
rssRepository.deleteBookmark(link = post.link)
rssRepository.deleteBookmark(id = post.id)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ internal fun BookmarksScreen(
},
togglePostReadClick = {
bookmarksPresenter.dispatch(
BookmarksEvent.TogglePostReadStatus(post.link, post.read)
BookmarksEvent.TogglePostReadStatus(post.id, post.read)
)
}
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* Copyright 2024 Sasikanth Miriyampalli
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package dev.sasikanth.rss.reader.database.migrations

import app.cash.sqldelight.Query
import app.cash.sqldelight.db.AfterVersion
import app.cash.sqldelight.db.QueryResult
import app.cash.sqldelight.db.SqlCursor
import app.cash.sqldelight.db.SqlDriver
import dev.sasikanth.rss.reader.utils.nameBasedUuidOf

object SQLCodeMigrations {

fun migrations(): Array<AfterVersion> {
return arrayOf(afterVersion12())
}

private fun afterVersion12(): AfterVersion {
return AfterVersion(12) { driver ->
val ids = PostsIdsQuery(driver).executeAsList()
ids.forEach { id ->
driver.execute(
identifier = null,
sql = "UPDATE post SET id = ? WHERE id = ?",
parameters = 2,
) {
bindString(0, nameBasedUuidOf(id).toString())
bindString(1, id)
}
}
}
}
}

private class PostsIdsQuery(
private val driver: SqlDriver,
) : Query<String>(mapper = { cursor -> cursor.getString(0)!! }) {
override fun addListener(listener: Listener) {
driver.addListener("post", listener = listener)
}

override fun removeListener(listener: Listener) {
driver.removeListener("post", listener = listener)
}

override fun <R> execute(mapper: (SqlCursor) -> QueryResult<R>): QueryResult<R> =
driver.executeQuery(null, "SELECT id FROM POST", mapper, 0, null)

override fun toString(): String = "Post.sq:posts"
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,14 @@
*/
package dev.sasikanth.rss.reader.di

import app.cash.sqldelight.db.AfterVersion
import app.cash.sqldelight.db.SqlDriver
import dev.sasikanth.rss.reader.database.Bookmark
import dev.sasikanth.rss.reader.database.DateAdapter
import dev.sasikanth.rss.reader.database.Feed
import dev.sasikanth.rss.reader.database.Post
import dev.sasikanth.rss.reader.database.ReaderDatabase
import dev.sasikanth.rss.reader.database.migrations.SQLCodeMigrations
import dev.sasikanth.rss.reader.di.scopes.AppScope
import me.tatarka.inject.annotations.Provides

Expand All @@ -46,6 +48,8 @@ internal interface DataComponent : SqlDriverPlatformComponent, DataStorePlatform
)
}

@Provides @AppScope fun providesMigrations(): Array<AfterVersion> = SQLCodeMigrations.migrations()

@Provides fun providesFeedQueries(database: ReaderDatabase) = database.feedQueries

@Provides fun providesPostQueries(database: ReaderDatabase) = database.postQueries
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,5 +50,5 @@ sealed interface HomeEvent {

data object SettingsClicked : HomeEvent

data class TogglePostReadStatus(val postLink: String, val postRead: Boolean) : HomeEvent
data class TogglePostReadStatus(val postId: String, val postRead: Boolean) : HomeEvent
}
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ internal typealias HomePresenterFactory =
openSearch: () -> Unit,
openBookmarks: () -> Unit,
openSettings: () -> Unit,
openPost: (String) -> Unit,
openPost: (PostWithMetadata) -> Unit,
openFeedInfo: (String) -> Unit,
) -> HomePresenter

Expand All @@ -89,7 +89,7 @@ class HomePresenter(
@Assisted private val openSearch: () -> Unit,
@Assisted private val openBookmarks: () -> Unit,
@Assisted private val openSettings: () -> Unit,
@Assisted private val openPost: (postLink: String) -> Unit,
@Assisted private val openPost: (post: PostWithMetadata) -> Unit,
@Assisted private val openFeedInfo: (String) -> Unit,
) : ComponentContext by componentContext {

Expand Down Expand Up @@ -137,7 +137,7 @@ class HomePresenter(
is HomeEvent.SearchClicked -> openSearch()
is HomeEvent.BookmarksClicked -> openBookmarks()
is HomeEvent.SettingsClicked -> openSettings()
is HomeEvent.OnPostClicked -> openPost(event.post.link)
is HomeEvent.OnPostClicked -> openPost(event.post)
else -> {
// no-op
}
Expand Down Expand Up @@ -192,14 +192,12 @@ class HomePresenter(
}
is HomeEvent.OnPostSourceClicked -> postSourceClicked(event.feedLink)
is HomeEvent.OnPostsTypeChanged -> onPostsTypeChanged(event.postsType)
is HomeEvent.TogglePostReadStatus -> togglePostReadStatus(event.postLink, event.postRead)
is HomeEvent.TogglePostReadStatus -> togglePostReadStatus(event.postId, event.postRead)
}
}

private fun togglePostReadStatus(postLink: String, postRead: Boolean) {
coroutineScope.launch {
rssRepository.updatePostReadStatus(read = !postRead, link = postLink)
}
private fun togglePostReadStatus(postId: String, postRead: Boolean) {
coroutineScope.launch { rssRepository.updatePostReadStatus(read = !postRead, id = postId) }
}

private fun onPostsTypeChanged(postsType: PostsType) {
Expand All @@ -215,7 +213,7 @@ class HomePresenter(

private fun onPostBookmarkClicked(post: PostWithMetadata) {
coroutineScope.launch {
rssRepository.updateBookmarkStatus(bookmarked = !post.bookmarked, link = post.link)
rssRepository.updateBookmarkStatus(bookmarked = !post.bookmarked, id = post.id)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ internal fun FeaturedSection(
onBookmarkClick = { onPostBookmarkClick(featuredPost) },
onCommentsClick = { onPostCommentsClick(featuredPost.commentsLink!!) },
onSourceClick = { onPostSourceClick(featuredPost.feedLink) },
onTogglePostReadClick = { onTogglePostReadClick(featuredPost.link, featuredPost.read) }
onTogglePostReadClick = { onTogglePostReadClick(featuredPost.id, featuredPost.read) }
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,8 +170,8 @@ internal fun HomeScreen(homePresenter: HomePresenter, modifier: Modifier = Modif
homePresenter.dispatch(HomeEvent.OnPostSourceClicked(feedLink))
},
onNoFeedsSwipeUp = { coroutineScope.launch { bottomSheetState.expand() } },
onTogglePostReadStatus = { postLink, postRead ->
homePresenter.dispatch(HomeEvent.TogglePostReadStatus(postLink, postRead))
onTogglePostReadStatus = { postId, postRead ->
homePresenter.dispatch(HomeEvent.TogglePostReadStatus(postId, postRead))
}
)
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ internal fun PostsList(
onPostBookmarkClick = { onPostBookmarkClick(post) },
onPostCommentsClick = { onPostCommentsClick(post.commentsLink!!) },
onPostSourceClick = { onPostSourceClick(post.feedLink) },
togglePostReadClick = { onTogglePostReadClick(post.link, post.read) }
togglePostReadClick = { onTogglePostReadClick(post.id, post.read) }
)
} else {
Box(Modifier.requiredHeight(132.dp))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ package dev.sasikanth.rss.reader.reader

sealed interface ReaderEvent {

data class Init(val postLink: String) : ReaderEvent
data class Init(val postId: String) : ReaderEvent

data object BackClicked : ReaderEvent

Expand Down
Loading

0 comments on commit 92b97ee

Please sign in to comment.