From 7b765a5fc257a780ccca7abd39d8099897e62693 Mon Sep 17 00:00:00 2001 From: Ahmad Ansori Palembani Date: Wed, 19 Jun 2024 16:36:35 +0700 Subject: [PATCH] refactor: Attempt 2 on getting library manga using flow --- .../data/library/LibraryUpdateJob.kt | 4 +- .../tachiyomi/ui/library/LibraryController.kt | 4 +- .../tachiyomi/ui/library/LibraryPresenter.kt | 108 ++++++++++-------- .../migrations/CustomInfoMigration.kt | 3 +- .../migrations/WorkManagerMigration.kt | 5 +- .../yokai/data/manga/MangaRepositoryImpl.kt | 3 + .../yokai/domain/manga/MangaRepository.kt | 1 + .../yokai/domain/manga/interactor/GetManga.kt | 1 + .../sqldelight/tachiyomi/data/mangas.sq | 5 + 9 files changed, 82 insertions(+), 52 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateJob.kt b/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateJob.kt index 911637481d..f04b63efb8 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateJob.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateJob.kt @@ -75,6 +75,7 @@ import kotlinx.coroutines.sync.withPermit import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get import yokai.domain.manga.interactor.GetLibraryManga +import yokai.domain.manga.interactor.UpdateManga import java.io.File import java.lang.ref.WeakReference import java.util.* @@ -92,6 +93,7 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet private val trackManager: TrackManager = Injekt.get() private val mangaShortcutManager: MangaShortcutManager = Injekt.get() private val getLibraryManga: GetLibraryManga = Injekt.get() + private val updateManga: UpdateManga = Injekt.get() private var extraDeferredJobs = mutableListOf>() @@ -277,7 +279,7 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet .build() } context.imageLoader.execute(request) - db.insertManga(manga).executeAsBlocking() + updateManga.await(manga.toMangaUpdate()) } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt index 7d5ece7a90..373a8ab316 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt @@ -1384,7 +1384,7 @@ open class LibraryController( private fun onRefresh() { showCategories(false) - presenter.getLibrary() + presenter.getLibrary(true) destroyActionModeIfNeeded() } @@ -1796,7 +1796,7 @@ open class LibraryController( val category = (adapter.getItem(position) as? LibraryHeaderItem)?.category ?: return if (!category.isDynamic) { ManageCategoryDialog(category) { - presenter.getLibrary() + presenter.getLibrary(true) }.showDialog(router) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt index 3f8e8ced6b..d8a55eb875 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt @@ -50,6 +50,7 @@ import eu.kanade.tachiyomi.util.system.withIOContext import eu.kanade.tachiyomi.util.system.withUIContext import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.combine import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking @@ -59,7 +60,10 @@ import uy.kohesive.injekt.api.get import uy.kohesive.injekt.injectLazy import yokai.domain.category.interactor.GetCategories import yokai.domain.chapter.interactor.GetChapters +import yokai.domain.chapter.interactor.UpdateChapters +import yokai.domain.chapter.models.ChapterUpdate import yokai.domain.manga.interactor.GetLibraryManga +import yokai.domain.manga.interactor.GetManga import yokai.domain.manga.interactor.UpdateManga import yokai.domain.manga.models.MangaUpdate import yokai.util.isLewd @@ -88,9 +92,10 @@ class LibraryPresenter( private val getCategories: GetCategories by injectLazy() private val getLibraryManga: GetLibraryManga by injectLazy() private val getChapters: GetChapters by injectLazy() + private val updateChapter: UpdateChapters by injectLazy() private val updateManga: UpdateManga by injectLazy() - private val libraryManga: List = emptyList() + private var libraryManga: List = emptyList() private val context = preferences.context private val viewContext @@ -176,7 +181,12 @@ class LibraryPresenter( lastLibraryItems = null lastAllLibraryItems = null } - getLibrary() + presenterScope.launch { + getLibraryManga.subscribe().collectLatest { + libraryManga = it.apply { if (groupType > BY_DEFAULT) { distinctBy { it.id } } } + getLibrary() + } + } if (!preferences.showLibrarySearchSuggestions().isSet()) { DelayedLibrarySuggestionsJob.setupTask(context, true) } else if (preferences.showLibrarySearchSuggestions().get() && @@ -200,7 +210,7 @@ class LibraryPresenter( } /** Get favorited manga for library and sort and filter it */ - fun getLibrary() { + fun getLibrary(forceFetch: Boolean = false) { presenterScope.launch { if (categories.isEmpty()) { val dbCategories = getCategories.await() @@ -210,7 +220,7 @@ class LibraryPresenter( categories = lastCategories ?: getCategories.await().toMutableList() } - val (library, hiddenItems) = withIOContext { getLibraryFromDB() } + val (library, hiddenItems) = withIOContext { getLibraryFromDB(forceFetch) } setDownloadCount(library) setUnreadBadge(library) setSourceLanguage(library) @@ -766,14 +776,12 @@ class LibraryPresenter( * * @return an list of all the manga in a itemized form. */ - private suspend fun getLibraryFromDB(): Pair, List> { + private suspend fun getLibraryFromDB(forceFetch: Boolean = false): Pair, List> { removeArticles = preferences.removeArticles().get() val categories = getCategories.await().toMutableList() - var libraryManga = getLibraryManga.await() + if (forceFetch) + libraryManga = getLibraryManga.await().apply { if (groupType > BY_DEFAULT) { distinctBy { it.id } } } val showAll = showAllCategories - if (groupType > BY_DEFAULT) { - libraryManga = libraryManga.distinctBy { it.id } - } val hiddenItems = mutableListOf() val items = if (groupType <= BY_DEFAULT || !libraryIsGrouped) { @@ -1222,6 +1230,7 @@ class LibraryPresenter( } } + // TODO: Use SQLDelight /** Shift a manga's category via drag & drop */ fun moveMangaToCategory( manga: LibraryManga, @@ -1360,15 +1369,14 @@ class LibraryPresenter( val mapMangaChapters = HashMap>() presenterScope.launchIO { mangaList.forEach { manga -> - val oldChapters = db.getChapters(manga).executeAsBlocking() - val chapters = oldChapters.copy() - chapters.forEach { - it.read = markRead - it.last_page_read = 0 + val chapters = getChapters.await(manga) + val updates = chapters.copy().mapNotNull { + if (it.id == null) return@mapNotNull null + ChapterUpdate(it.id!!, read = markRead, lastPageRead = 0) } - db.updateChaptersProgress(chapters).executeAsBlocking() + updateChapter.awaitAll(updates) - mapMangaChapters[manga] = oldChapters + mapMangaChapters[manga] = chapters } getLibrary() } @@ -1379,9 +1387,13 @@ class LibraryPresenter( mangaList: HashMap>, ) { launchIO { - mangaList.forEach { (_, chapters) -> - db.updateChaptersProgress(chapters).executeAsBlocking() - } + val updates = mangaList.values.map { chapters -> + chapters.mapNotNull { + if (it.id == null) return@mapNotNull null + ChapterUpdate(it.id!!, read = it.read, lastPageRead = it.last_page_read.toLong()) + } + }.flatten() + updateChapter.awaitAll(updates) getLibrary() } } @@ -1501,46 +1513,48 @@ class LibraryPresenter( } /** Give library manga to a date added based on min chapter fetch */ - fun updateDB() { - val db: DatabaseHelper = Injekt.get() - val getLibraryManga: GetLibraryManga by injectLazy() - val libraryManga = runBlocking { getLibraryManga.await() } - db.inTransaction { - libraryManga.forEach { manga -> - if (manga.date_added == 0L) { - val chapters = db.getChapters(manga).executeAsBlocking() - manga.date_added = chapters.minByOrNull { it.date_fetch }?.date_fetch ?: 0L - db.insertManga(manga).executeAsBlocking() - } + suspend fun updateDB( + getChapters: GetChapters = Injekt.get(), + getLibraryManga: GetLibraryManga = Injekt.get(), + updateManga: UpdateManga = Injekt.get(), + ) { + val libraryManga = getLibraryManga.await() + libraryManga.forEach { manga -> + if (manga.id == null) return@forEach + if (manga.date_added == 0L) { + val chapters = getChapters.await(manga) + manga.date_added = chapters.minByOrNull { it.date_fetch }?.date_fetch ?: 0L + updateManga.await(MangaUpdate(manga.id!!, dateAdded = manga.date_added)) } } } - suspend fun updateRatiosAndColors() { - val db: DatabaseHelper = Injekt.get() - val libraryManga = db.getFavoriteMangas().executeOnIO() + suspend fun updateRatiosAndColors( + getManga: GetManga = Injekt.get(), + ) { + val libraryManga = getManga.awaitFavorites() libraryManga.forEach { manga -> try { withUIContext { MangaCoverMetadata.setRatioAndColors(manga) } } catch (_: Exception) { } } MangaCoverMetadata.savePrefs() } - fun updateCustoms() { - val db: DatabaseHelper = Injekt.get() - val cc: CoverCache = Injekt.get() + suspend fun updateCustoms( + cc: CoverCache = Injekt.get(), + updateManga: UpdateManga = Injekt.get(), + ) { val getLibraryManga: GetLibraryManga by injectLazy() - val libraryManga = runBlocking { getLibraryManga.await() } - db.inTransaction { - libraryManga.forEach { manga -> - if (manga.thumbnail_url?.startsWith("custom", ignoreCase = true) == true) { - val file = cc.getCoverFile(manga) - if (file.exists()) { - file.renameTo(cc.getCustomCoverFile(manga)) - } - manga.thumbnail_url = - manga.thumbnail_url!!.lowercase(Locale.ROOT).substringAfter("custom-") - db.insertManga(manga).executeAsBlocking() + val libraryManga = getLibraryManga.await() + libraryManga.forEach { manga -> + if (manga.id == null) return@forEach + if (manga.thumbnail_url?.startsWith("custom", ignoreCase = true) == true) { + val file = cc.getCoverFile(manga) + if (file.exists()) { + file.renameTo(cc.getCustomCoverFile(manga)) } + manga.thumbnail_url = + manga.thumbnail_url!!.lowercase(Locale.ROOT).substringAfter("custom-") + updateManga.await(MangaUpdate(manga.id!!, thumbnailUrl = manga.thumbnail_url)) } } } diff --git a/app/src/main/java/yokai/core/migration/migrations/CustomInfoMigration.kt b/app/src/main/java/yokai/core/migration/migrations/CustomInfoMigration.kt index 609c7f0850..f96ba69af2 100644 --- a/app/src/main/java/yokai/core/migration/migrations/CustomInfoMigration.kt +++ b/app/src/main/java/yokai/core/migration/migrations/CustomInfoMigration.kt @@ -1,6 +1,7 @@ package yokai.core.migration.migrations import eu.kanade.tachiyomi.ui.library.LibraryPresenter +import eu.kanade.tachiyomi.util.system.withIOContext import yokai.core.migration.Migration import yokai.core.migration.MigrationContext @@ -9,7 +10,7 @@ class CustomInfoMigration : Migration { override suspend fun invoke(migrationContext: MigrationContext): Boolean { try { - LibraryPresenter.updateCustoms() + withIOContext { LibraryPresenter.updateCustoms() } } catch (e: Exception) { return false } diff --git a/app/src/main/java/yokai/core/migration/migrations/WorkManagerMigration.kt b/app/src/main/java/yokai/core/migration/migrations/WorkManagerMigration.kt index 2417b203d7..bec8ff1ca6 100644 --- a/app/src/main/java/yokai/core/migration/migrations/WorkManagerMigration.kt +++ b/app/src/main/java/yokai/core/migration/migrations/WorkManagerMigration.kt @@ -7,6 +7,7 @@ import eu.kanade.tachiyomi.data.library.LibraryUpdateJob import eu.kanade.tachiyomi.data.updater.AppUpdateJob import eu.kanade.tachiyomi.extension.ExtensionUpdateJob import eu.kanade.tachiyomi.ui.library.LibraryPresenter +import eu.kanade.tachiyomi.util.system.withIOContext import yokai.core.migration.Migration import yokai.core.migration.MigrationContext @@ -18,7 +19,9 @@ class WorkManagerMigration : Migration { override suspend fun invoke(migrationContext: MigrationContext): Boolean { val context: App = migrationContext.get() ?: return false - LibraryPresenter.updateDB() + withIOContext { + LibraryPresenter.updateDB() + } if (BuildConfig.INCLUDE_UPDATER) { AppUpdateJob.setupTask(context) } diff --git a/app/src/main/java/yokai/data/manga/MangaRepositoryImpl.kt b/app/src/main/java/yokai/data/manga/MangaRepositoryImpl.kt index 01d64aa8d5..127a72e8b9 100644 --- a/app/src/main/java/yokai/data/manga/MangaRepositoryImpl.kt +++ b/app/src/main/java/yokai/data/manga/MangaRepositoryImpl.kt @@ -20,6 +20,9 @@ class MangaRepositoryImpl(private val handler: DatabaseHandler) : MangaRepositor override suspend fun getMangaById(id: Long): Manga? = handler.awaitOneOrNull { mangasQueries.findById(id, Manga::mapper) } + override suspend fun getFavorites(): List = + handler.awaitList { mangasQueries.findFavorites(Manga::mapper) } + override fun getMangaListAsFlow(): Flow> = handler.subscribeToList { mangasQueries.findAll(Manga::mapper) } diff --git a/app/src/main/java/yokai/domain/manga/MangaRepository.kt b/app/src/main/java/yokai/domain/manga/MangaRepository.kt index a2f102543e..4efadc8e33 100644 --- a/app/src/main/java/yokai/domain/manga/MangaRepository.kt +++ b/app/src/main/java/yokai/domain/manga/MangaRepository.kt @@ -9,6 +9,7 @@ interface MangaRepository { suspend fun getMangaList(): List suspend fun getMangaByUrlAndSource(url: String, source: Long): Manga? suspend fun getMangaById(id: Long): Manga? + suspend fun getFavorites(): List fun getMangaListAsFlow(): Flow> suspend fun getLibraryManga(): List fun getLibraryMangaAsFlow(): Flow> diff --git a/app/src/main/java/yokai/domain/manga/interactor/GetManga.kt b/app/src/main/java/yokai/domain/manga/interactor/GetManga.kt index a5d00ad9ee..bfbed5cf50 100644 --- a/app/src/main/java/yokai/domain/manga/interactor/GetManga.kt +++ b/app/src/main/java/yokai/domain/manga/interactor/GetManga.kt @@ -10,4 +10,5 @@ class GetManga ( suspend fun awaitByUrlAndSource(url: String, source: Long) = mangaRepository.getMangaByUrlAndSource(url, source) suspend fun awaitById(id: Long) = mangaRepository.getMangaById(id) + suspend fun awaitFavorites() = mangaRepository.getFavorites() } diff --git a/data/src/commonMain/sqldelight/tachiyomi/data/mangas.sq b/data/src/commonMain/sqldelight/tachiyomi/data/mangas.sq index 1880f80de8..0f3d00a9b4 100644 --- a/data/src/commonMain/sqldelight/tachiyomi/data/mangas.sq +++ b/data/src/commonMain/sqldelight/tachiyomi/data/mangas.sq @@ -45,6 +45,11 @@ SELECT * FROM mangas WHERE favorite = 1 AND lower(title) = :title AND source = :source; +findFavorites: +SELECT * +FROM mangas +WHERE favorite = 1; + insert: INSERT INTO mangas (source, url, artist, author, description, genre, title, status, thumbnail_url, favorite, last_update, initialized, viewer, hide_title, chapter_flags, date_added, filtered_scanlators, update_strategy) VALUES (:source, :url, :artist, :author, :description, :genre, :title, :status, :thumbnailUrl, :favorite, :lastUpdate, :initialized, :viewer, :hideTitle, :chapterFlags, :dateAdded, :filteredScanlators, :updateStrategy);