refactor: Attempt 2 on getting library manga using flow

This commit is contained in:
Ahmad Ansori Palembani 2024-06-19 16:36:35 +07:00
parent 535fcc81dd
commit 7b765a5fc2
Signed by: null2264
GPG key ID: BA64F8B60AF3EFB6
9 changed files with 82 additions and 52 deletions

View file

@ -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<Deferred<Any>>()
@ -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())
}
}
}

View file

@ -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)
}
}

View file

@ -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<LibraryManga> = emptyList()
private var libraryManga: List<LibraryManga> = 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<LibraryItem>, List<LibraryItem>> {
private suspend fun getLibraryFromDB(forceFetch: Boolean = false): Pair<List<LibraryItem>, List<LibraryItem>> {
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<LibraryItem>()
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<Manga, List<Chapter>>()
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<Manga, List<Chapter>>,
) {
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))
}
}
}

View file

@ -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
}

View file

@ -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)
}

View file

@ -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<Manga> =
handler.awaitList { mangasQueries.findFavorites(Manga::mapper) }
override fun getMangaListAsFlow(): Flow<List<Manga>> =
handler.subscribeToList { mangasQueries.findAll(Manga::mapper) }

View file

@ -9,6 +9,7 @@ interface MangaRepository {
suspend fun getMangaList(): List<Manga>
suspend fun getMangaByUrlAndSource(url: String, source: Long): Manga?
suspend fun getMangaById(id: Long): Manga?
suspend fun getFavorites(): List<Manga>
fun getMangaListAsFlow(): Flow<List<Manga>>
suspend fun getLibraryManga(): List<LibraryManga>
fun getLibraryMangaAsFlow(): Flow<List<LibraryManga>>

View file

@ -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()
}

View file

@ -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);