From 29633b64aa1b3d87392362f31f4fc250d930722b Mon Sep 17 00:00:00 2001 From: Andreas Date: Sun, 3 Jul 2022 00:51:33 +0200 Subject: [PATCH] Use SQLDelight for all Chapter related queries (#7440) --- .../data/chapter/ChapterRepositoryImpl.kt | 4 ++ .../domain/chapter/interactor/GetChapter.kt | 9 +++++ .../chapter/repository/ChapterRepository.kt | 2 + .../tachiyomi/data/database/DatabaseHelper.kt | 3 +- .../data/database/queries/ChapterQueries.kt | 37 ------------------ .../tachiyomi/data/download/DownloadStore.kt | 14 +++++-- .../data/notification/NotificationReceiver.kt | 38 +++++++++++-------- .../tachiyomi/ui/reader/ReaderPresenter.kt | 15 +++++--- app/src/main/sqldelight/data/chapters.sq | 6 +++ 9 files changed, 63 insertions(+), 65 deletions(-) delete mode 100644 app/src/main/java/eu/kanade/tachiyomi/data/database/queries/ChapterQueries.kt diff --git a/app/src/main/java/eu/kanade/data/chapter/ChapterRepositoryImpl.kt b/app/src/main/java/eu/kanade/data/chapter/ChapterRepositoryImpl.kt index fe9eafc15..8f1b37dec 100644 --- a/app/src/main/java/eu/kanade/data/chapter/ChapterRepositoryImpl.kt +++ b/app/src/main/java/eu/kanade/data/chapter/ChapterRepositoryImpl.kt @@ -99,4 +99,8 @@ class ChapterRepositoryImpl( override suspend fun getChapterByMangaIdAsFlow(mangaId: Long): Flow> { return handler.subscribeToList { chaptersQueries.getChaptersByMangaId(mangaId, chapterMapper) } } + + override suspend fun getChapterByUrlAndMangaId(url: String, mangaId: Long): Chapter? { + return handler.awaitOneOrNull { chaptersQueries.getChapterByUrlAndMangaId(url, mangaId, chapterMapper) } + } } diff --git a/app/src/main/java/eu/kanade/domain/chapter/interactor/GetChapter.kt b/app/src/main/java/eu/kanade/domain/chapter/interactor/GetChapter.kt index 28724ef58..8d4be8a77 100644 --- a/app/src/main/java/eu/kanade/domain/chapter/interactor/GetChapter.kt +++ b/app/src/main/java/eu/kanade/domain/chapter/interactor/GetChapter.kt @@ -17,4 +17,13 @@ class GetChapter( null } } + + suspend fun await(url: String, mangaId: Long): Chapter? { + return try { + chapterRepository.getChapterByUrlAndMangaId(url, mangaId) + } catch (e: Exception) { + logcat(LogPriority.ERROR, e) + null + } + } } diff --git a/app/src/main/java/eu/kanade/domain/chapter/repository/ChapterRepository.kt b/app/src/main/java/eu/kanade/domain/chapter/repository/ChapterRepository.kt index 2a2abd5f3..311ad4b8d 100644 --- a/app/src/main/java/eu/kanade/domain/chapter/repository/ChapterRepository.kt +++ b/app/src/main/java/eu/kanade/domain/chapter/repository/ChapterRepository.kt @@ -19,4 +19,6 @@ interface ChapterRepository { suspend fun getChapterById(id: Long): Chapter? suspend fun getChapterByMangaIdAsFlow(mangaId: Long): Flow> + + suspend fun getChapterByUrlAndMangaId(url: String, mangaId: Long): Chapter? } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/DatabaseHelper.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/DatabaseHelper.kt index 620fc51e2..d0fb524a9 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/DatabaseHelper.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/DatabaseHelper.kt @@ -8,7 +8,6 @@ import eu.kanade.tachiyomi.data.database.mappers.MangaTypeMapping import eu.kanade.tachiyomi.data.database.models.Chapter import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.database.models.MangaCategory -import eu.kanade.tachiyomi.data.database.queries.ChapterQueries import eu.kanade.tachiyomi.data.database.queries.MangaCategoryQueries import eu.kanade.tachiyomi.data.database.queries.MangaQueries @@ -18,7 +17,7 @@ import eu.kanade.tachiyomi.data.database.queries.MangaQueries class DatabaseHelper( openHelper: SupportSQLiteOpenHelper, ) : - MangaQueries, ChapterQueries, MangaCategoryQueries { + MangaQueries, MangaCategoryQueries { override val db = DefaultStorIOSQLite.builder() .sqliteOpenHelper(openHelper) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/ChapterQueries.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/ChapterQueries.kt deleted file mode 100644 index 22ae7af18..000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/ChapterQueries.kt +++ /dev/null @@ -1,37 +0,0 @@ -package eu.kanade.tachiyomi.data.database.queries - -import com.pushtorefresh.storio.sqlite.queries.Query -import eu.kanade.tachiyomi.data.database.DbProvider -import eu.kanade.tachiyomi.data.database.models.Chapter -import eu.kanade.tachiyomi.data.database.resolvers.ChapterProgressPutResolver -import eu.kanade.tachiyomi.data.database.tables.ChapterTable - -interface ChapterQueries : DbProvider { - - fun getChapter(id: Long) = db.get() - .`object`(Chapter::class.java) - .withQuery( - Query.builder() - .table(ChapterTable.TABLE) - .where("${ChapterTable.COL_ID} = ?") - .whereArgs(id) - .build(), - ) - .prepare() - - fun getChapter(url: String, mangaId: Long) = db.get() - .`object`(Chapter::class.java) - .withQuery( - Query.builder() - .table(ChapterTable.TABLE) - .where("${ChapterTable.COL_URL} = ? AND ${ChapterTable.COL_MANGA_ID} = ?") - .whereArgs(url, mangaId) - .build(), - ) - .prepare() - - fun updateChapterProgress(chapter: Chapter) = db.put() - .`object`(chapter) - .withPutResolver(ChapterProgressPutResolver()) - .prepare() -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadStore.kt b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadStore.kt index 0f4624d3a..443620ff4 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadStore.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadStore.kt @@ -2,11 +2,15 @@ package eu.kanade.tachiyomi.data.download import android.content.Context import androidx.core.content.edit -import eu.kanade.tachiyomi.data.database.DatabaseHelper +import eu.kanade.domain.chapter.interactor.GetChapter +import eu.kanade.domain.chapter.model.toDbChapter +import eu.kanade.domain.manga.interactor.GetMangaById +import eu.kanade.domain.manga.model.toDbManga import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.download.model.Download import eu.kanade.tachiyomi.source.SourceManager import eu.kanade.tachiyomi.source.online.HttpSource +import kotlinx.coroutines.runBlocking import kotlinx.serialization.Serializable import kotlinx.serialization.decodeFromString import kotlinx.serialization.encodeToString @@ -29,7 +33,9 @@ class DownloadStore( private val preferences = context.getSharedPreferences("active_downloads", Context.MODE_PRIVATE) private val json: Json by injectLazy() - private val db: DatabaseHelper by injectLazy() + + private val getMangaById: GetMangaById by injectLazy() + private val getChapter: GetChapter by injectLazy() /** * Counter used to keep the queue order. @@ -90,10 +96,10 @@ class DownloadStore( val cachedManga = mutableMapOf() for ((mangaId, chapterId) in objs) { val manga = cachedManga.getOrPut(mangaId) { - db.getManga(mangaId).executeAsBlocking() + runBlocking { getMangaById.await(mangaId)?.toDbManga() } } ?: continue val source = sourceManager.get(manga.source) as? HttpSource ?: continue - val chapter = db.getChapter(chapterId).executeAsBlocking() ?: continue + val chapter = runBlocking { getChapter.await(chapterId) }?.toDbChapter() ?: continue downloads.add(Download(source, manga, chapter)) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationReceiver.kt b/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationReceiver.kt index 887c0ae4b..9ed42985d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationReceiver.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationReceiver.kt @@ -7,9 +7,14 @@ import android.content.Intent import android.net.Uri import android.os.Build import androidx.core.content.ContextCompat +import eu.kanade.domain.chapter.interactor.GetChapter +import eu.kanade.domain.chapter.interactor.UpdateChapter +import eu.kanade.domain.chapter.model.toChapterUpdate +import eu.kanade.domain.chapter.model.toDbChapter +import eu.kanade.domain.manga.interactor.GetMangaById +import eu.kanade.domain.manga.model.toDbManga import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.backup.BackupRestoreService -import eu.kanade.tachiyomi.data.database.DatabaseHelper import eu.kanade.tachiyomi.data.database.models.Chapter import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.download.DownloadManager @@ -27,6 +32,7 @@ import eu.kanade.tachiyomi.util.storage.getUriCompat import eu.kanade.tachiyomi.util.system.notificationManager import eu.kanade.tachiyomi.util.system.toShareIntent import eu.kanade.tachiyomi.util.system.toast +import kotlinx.coroutines.runBlocking import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get import uy.kohesive.injekt.injectLazy @@ -40,6 +46,9 @@ import eu.kanade.tachiyomi.BuildConfig.APPLICATION_ID as ID */ class NotificationReceiver : BroadcastReceiver() { + private val getMangaById: GetMangaById by injectLazy() + private val getChapter: GetChapter by injectLazy() + private val updateChapter: UpdateChapter by injectLazy() private val downloadManager: DownloadManager by injectLazy() override fun onReceive(context: Context, intent: Intent) { @@ -169,9 +178,8 @@ class NotificationReceiver : BroadcastReceiver() { * @param chapterId id of chapter */ private fun openChapter(context: Context, mangaId: Long, chapterId: Long) { - val db = Injekt.get() - val manga = db.getManga(mangaId).executeAsBlocking() - val chapter = db.getChapter(chapterId).executeAsBlocking() + val manga = runBlocking { getMangaById.await(mangaId) } + val chapter = runBlocking { getChapter.await(chapterId) } if (manga != null && chapter != null) { val intent = ReaderActivity.newIntent(context, manga.id, chapter.id).apply { flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP @@ -232,25 +240,25 @@ class NotificationReceiver : BroadcastReceiver() { * @param mangaId id of manga */ private fun markAsRead(chapterUrls: Array, mangaId: Long) { - val db: DatabaseHelper = Injekt.get() val preferences: PreferencesHelper = Injekt.get() val sourceManager: SourceManager = Injekt.get() launchIO { - chapterUrls.mapNotNull { db.getChapter(it, mangaId).executeAsBlocking() } - .forEach { - it.read = true - db.updateChapterProgress(it).executeAsBlocking() + val toUpdate = chapterUrls.mapNotNull { getChapter.await(it, mangaId) } + .map { + val chapter = it.copy(read = true) if (preferences.removeAfterMarkedAsRead()) { - val manga = db.getManga(mangaId).executeAsBlocking() + val manga = getMangaById.await(mangaId) if (manga != null) { val source = sourceManager.get(manga.source) if (source != null) { - downloadManager.deleteChapters(listOf(it), manga, source) + downloadManager.deleteChapters(listOf(it.toDbChapter()), manga.toDbManga(), source) } } } + chapter.toChapterUpdate() } + updateChapter.awaitAll(toUpdate) } } @@ -261,12 +269,10 @@ class NotificationReceiver : BroadcastReceiver() { * @param mangaId id of manga */ private fun downloadChapters(chapterUrls: Array, mangaId: Long) { - val db: DatabaseHelper = Injekt.get() - launchIO { - val chapters = chapterUrls.mapNotNull { db.getChapter(it, mangaId).executeAsBlocking() } - val manga = db.getManga(mangaId).executeAsBlocking() - if (chapters.isNotEmpty() && manga != null) { + val manga = getMangaById.await(mangaId)?.toDbManga() + val chapters = chapterUrls.mapNotNull { getChapter.await(it, mangaId)?.toDbChapter() } + if (manga != null && chapters.isNotEmpty()) { downloadManager.downloadChapters(manga, chapters) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt index ef197ea25..75ad5f653 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt @@ -540,13 +540,16 @@ class ReaderPresenter( * Bookmarks the currently active chapter. */ fun bookmarkCurrentChapter(bookmarked: Boolean) { - if (getCurrentChapter()?.chapter == null) { - return + val chapter = getCurrentChapter()?.chapter ?: return + chapter.bookmark = bookmarked // Otherwise the bookmark icon doesn't update + launchIO { + updateChapter.await( + ChapterUpdate( + id = chapter.id!!.toLong(), + bookmark = bookmarked, + ), + ) } - - val chapter = getCurrentChapter()?.chapter!! - chapter.bookmark = bookmarked - db.updateChapterProgress(chapter).executeAsBlocking() } /** diff --git a/app/src/main/sqldelight/data/chapters.sq b/app/src/main/sqldelight/data/chapters.sq index ec80bba3a..4452d3233 100644 --- a/app/src/main/sqldelight/data/chapters.sq +++ b/app/src/main/sqldelight/data/chapters.sq @@ -33,6 +33,12 @@ SELECT * FROM chapters WHERE url = :chapterUrl; +getChapterByUrlAndMangaId: +SELECT * +FROM chapters +WHERE url = :chapterUrl +AND manga_id = :mangaId; + removeChaptersWithIds: DELETE FROM chapters WHERE _id IN :chapterIds;