mirror of
https://github.com/null2264/yokai.git
synced 2025-06-21 10:44:42 +00:00
refactor: Attempt 2 on getting library manga using flow
This commit is contained in:
parent
535fcc81dd
commit
7b765a5fc2
9 changed files with 82 additions and 52 deletions
|
@ -75,6 +75,7 @@ import kotlinx.coroutines.sync.withPermit
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
import yokai.domain.manga.interactor.GetLibraryManga
|
import yokai.domain.manga.interactor.GetLibraryManga
|
||||||
|
import yokai.domain.manga.interactor.UpdateManga
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.lang.ref.WeakReference
|
import java.lang.ref.WeakReference
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
@ -92,6 +93,7 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
|
||||||
private val trackManager: TrackManager = Injekt.get()
|
private val trackManager: TrackManager = Injekt.get()
|
||||||
private val mangaShortcutManager: MangaShortcutManager = Injekt.get()
|
private val mangaShortcutManager: MangaShortcutManager = Injekt.get()
|
||||||
private val getLibraryManga: GetLibraryManga = Injekt.get()
|
private val getLibraryManga: GetLibraryManga = Injekt.get()
|
||||||
|
private val updateManga: UpdateManga = Injekt.get()
|
||||||
|
|
||||||
private var extraDeferredJobs = mutableListOf<Deferred<Any>>()
|
private var extraDeferredJobs = mutableListOf<Deferred<Any>>()
|
||||||
|
|
||||||
|
@ -277,7 +279,7 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
context.imageLoader.execute(request)
|
context.imageLoader.execute(request)
|
||||||
db.insertManga(manga).executeAsBlocking()
|
updateManga.await(manga.toMangaUpdate())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1384,7 +1384,7 @@ open class LibraryController(
|
||||||
|
|
||||||
private fun onRefresh() {
|
private fun onRefresh() {
|
||||||
showCategories(false)
|
showCategories(false)
|
||||||
presenter.getLibrary()
|
presenter.getLibrary(true)
|
||||||
destroyActionModeIfNeeded()
|
destroyActionModeIfNeeded()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1796,7 +1796,7 @@ open class LibraryController(
|
||||||
val category = (adapter.getItem(position) as? LibraryHeaderItem)?.category ?: return
|
val category = (adapter.getItem(position) as? LibraryHeaderItem)?.category ?: return
|
||||||
if (!category.isDynamic) {
|
if (!category.isDynamic) {
|
||||||
ManageCategoryDialog(category) {
|
ManageCategoryDialog(category) {
|
||||||
presenter.getLibrary()
|
presenter.getLibrary(true)
|
||||||
}.showDialog(router)
|
}.showDialog(router)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,6 +50,7 @@ import eu.kanade.tachiyomi.util.system.withIOContext
|
||||||
import eu.kanade.tachiyomi.util.system.withUIContext
|
import eu.kanade.tachiyomi.util.system.withUIContext
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
|
@ -59,7 +60,10 @@ import uy.kohesive.injekt.api.get
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
import yokai.domain.category.interactor.GetCategories
|
import yokai.domain.category.interactor.GetCategories
|
||||||
import yokai.domain.chapter.interactor.GetChapters
|
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.GetLibraryManga
|
||||||
|
import yokai.domain.manga.interactor.GetManga
|
||||||
import yokai.domain.manga.interactor.UpdateManga
|
import yokai.domain.manga.interactor.UpdateManga
|
||||||
import yokai.domain.manga.models.MangaUpdate
|
import yokai.domain.manga.models.MangaUpdate
|
||||||
import yokai.util.isLewd
|
import yokai.util.isLewd
|
||||||
|
@ -88,9 +92,10 @@ class LibraryPresenter(
|
||||||
private val getCategories: GetCategories by injectLazy()
|
private val getCategories: GetCategories by injectLazy()
|
||||||
private val getLibraryManga: GetLibraryManga by injectLazy()
|
private val getLibraryManga: GetLibraryManga by injectLazy()
|
||||||
private val getChapters: GetChapters by injectLazy()
|
private val getChapters: GetChapters by injectLazy()
|
||||||
|
private val updateChapter: UpdateChapters by injectLazy()
|
||||||
private val updateManga: UpdateManga 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 context = preferences.context
|
||||||
private val viewContext
|
private val viewContext
|
||||||
|
@ -176,7 +181,12 @@ class LibraryPresenter(
|
||||||
lastLibraryItems = null
|
lastLibraryItems = null
|
||||||
lastAllLibraryItems = null
|
lastAllLibraryItems = null
|
||||||
}
|
}
|
||||||
|
presenterScope.launch {
|
||||||
|
getLibraryManga.subscribe().collectLatest {
|
||||||
|
libraryManga = it.apply { if (groupType > BY_DEFAULT) { distinctBy { it.id } } }
|
||||||
getLibrary()
|
getLibrary()
|
||||||
|
}
|
||||||
|
}
|
||||||
if (!preferences.showLibrarySearchSuggestions().isSet()) {
|
if (!preferences.showLibrarySearchSuggestions().isSet()) {
|
||||||
DelayedLibrarySuggestionsJob.setupTask(context, true)
|
DelayedLibrarySuggestionsJob.setupTask(context, true)
|
||||||
} else if (preferences.showLibrarySearchSuggestions().get() &&
|
} else if (preferences.showLibrarySearchSuggestions().get() &&
|
||||||
|
@ -200,7 +210,7 @@ class LibraryPresenter(
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get favorited manga for library and sort and filter it */
|
/** Get favorited manga for library and sort and filter it */
|
||||||
fun getLibrary() {
|
fun getLibrary(forceFetch: Boolean = false) {
|
||||||
presenterScope.launch {
|
presenterScope.launch {
|
||||||
if (categories.isEmpty()) {
|
if (categories.isEmpty()) {
|
||||||
val dbCategories = getCategories.await()
|
val dbCategories = getCategories.await()
|
||||||
|
@ -210,7 +220,7 @@ class LibraryPresenter(
|
||||||
categories = lastCategories ?: getCategories.await().toMutableList()
|
categories = lastCategories ?: getCategories.await().toMutableList()
|
||||||
}
|
}
|
||||||
|
|
||||||
val (library, hiddenItems) = withIOContext { getLibraryFromDB() }
|
val (library, hiddenItems) = withIOContext { getLibraryFromDB(forceFetch) }
|
||||||
setDownloadCount(library)
|
setDownloadCount(library)
|
||||||
setUnreadBadge(library)
|
setUnreadBadge(library)
|
||||||
setSourceLanguage(library)
|
setSourceLanguage(library)
|
||||||
|
@ -766,14 +776,12 @@ class LibraryPresenter(
|
||||||
*
|
*
|
||||||
* @return an list of all the manga in a itemized form.
|
* @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()
|
removeArticles = preferences.removeArticles().get()
|
||||||
val categories = getCategories.await().toMutableList()
|
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
|
val showAll = showAllCategories
|
||||||
if (groupType > BY_DEFAULT) {
|
|
||||||
libraryManga = libraryManga.distinctBy { it.id }
|
|
||||||
}
|
|
||||||
val hiddenItems = mutableListOf<LibraryItem>()
|
val hiddenItems = mutableListOf<LibraryItem>()
|
||||||
|
|
||||||
val items = if (groupType <= BY_DEFAULT || !libraryIsGrouped) {
|
val items = if (groupType <= BY_DEFAULT || !libraryIsGrouped) {
|
||||||
|
@ -1222,6 +1230,7 @@ class LibraryPresenter(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Use SQLDelight
|
||||||
/** Shift a manga's category via drag & drop */
|
/** Shift a manga's category via drag & drop */
|
||||||
fun moveMangaToCategory(
|
fun moveMangaToCategory(
|
||||||
manga: LibraryManga,
|
manga: LibraryManga,
|
||||||
|
@ -1360,15 +1369,14 @@ class LibraryPresenter(
|
||||||
val mapMangaChapters = HashMap<Manga, List<Chapter>>()
|
val mapMangaChapters = HashMap<Manga, List<Chapter>>()
|
||||||
presenterScope.launchIO {
|
presenterScope.launchIO {
|
||||||
mangaList.forEach { manga ->
|
mangaList.forEach { manga ->
|
||||||
val oldChapters = db.getChapters(manga).executeAsBlocking()
|
val chapters = getChapters.await(manga)
|
||||||
val chapters = oldChapters.copy()
|
val updates = chapters.copy().mapNotNull {
|
||||||
chapters.forEach {
|
if (it.id == null) return@mapNotNull null
|
||||||
it.read = markRead
|
ChapterUpdate(it.id!!, read = markRead, lastPageRead = 0)
|
||||||
it.last_page_read = 0
|
|
||||||
}
|
}
|
||||||
db.updateChaptersProgress(chapters).executeAsBlocking()
|
updateChapter.awaitAll(updates)
|
||||||
|
|
||||||
mapMangaChapters[manga] = oldChapters
|
mapMangaChapters[manga] = chapters
|
||||||
}
|
}
|
||||||
getLibrary()
|
getLibrary()
|
||||||
}
|
}
|
||||||
|
@ -1379,9 +1387,13 @@ class LibraryPresenter(
|
||||||
mangaList: HashMap<Manga, List<Chapter>>,
|
mangaList: HashMap<Manga, List<Chapter>>,
|
||||||
) {
|
) {
|
||||||
launchIO {
|
launchIO {
|
||||||
mangaList.forEach { (_, chapters) ->
|
val updates = mangaList.values.map { chapters ->
|
||||||
db.updateChaptersProgress(chapters).executeAsBlocking()
|
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()
|
getLibrary()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1501,37 +1513,40 @@ class LibraryPresenter(
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Give library manga to a date added based on min chapter fetch */
|
/** Give library manga to a date added based on min chapter fetch */
|
||||||
fun updateDB() {
|
suspend fun updateDB(
|
||||||
val db: DatabaseHelper = Injekt.get()
|
getChapters: GetChapters = Injekt.get(),
|
||||||
val getLibraryManga: GetLibraryManga by injectLazy()
|
getLibraryManga: GetLibraryManga = Injekt.get(),
|
||||||
val libraryManga = runBlocking { getLibraryManga.await() }
|
updateManga: UpdateManga = Injekt.get(),
|
||||||
db.inTransaction {
|
) {
|
||||||
|
val libraryManga = getLibraryManga.await()
|
||||||
libraryManga.forEach { manga ->
|
libraryManga.forEach { manga ->
|
||||||
|
if (manga.id == null) return@forEach
|
||||||
if (manga.date_added == 0L) {
|
if (manga.date_added == 0L) {
|
||||||
val chapters = db.getChapters(manga).executeAsBlocking()
|
val chapters = getChapters.await(manga)
|
||||||
manga.date_added = chapters.minByOrNull { it.date_fetch }?.date_fetch ?: 0L
|
manga.date_added = chapters.minByOrNull { it.date_fetch }?.date_fetch ?: 0L
|
||||||
db.insertManga(manga).executeAsBlocking()
|
updateManga.await(MangaUpdate(manga.id!!, dateAdded = manga.date_added))
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun updateRatiosAndColors() {
|
suspend fun updateRatiosAndColors(
|
||||||
val db: DatabaseHelper = Injekt.get()
|
getManga: GetManga = Injekt.get(),
|
||||||
val libraryManga = db.getFavoriteMangas().executeOnIO()
|
) {
|
||||||
|
val libraryManga = getManga.awaitFavorites()
|
||||||
libraryManga.forEach { manga ->
|
libraryManga.forEach { manga ->
|
||||||
try { withUIContext { MangaCoverMetadata.setRatioAndColors(manga) } } catch (_: Exception) { }
|
try { withUIContext { MangaCoverMetadata.setRatioAndColors(manga) } } catch (_: Exception) { }
|
||||||
}
|
}
|
||||||
MangaCoverMetadata.savePrefs()
|
MangaCoverMetadata.savePrefs()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateCustoms() {
|
suspend fun updateCustoms(
|
||||||
val db: DatabaseHelper = Injekt.get()
|
cc: CoverCache = Injekt.get(),
|
||||||
val cc: CoverCache = Injekt.get()
|
updateManga: UpdateManga = Injekt.get(),
|
||||||
|
) {
|
||||||
val getLibraryManga: GetLibraryManga by injectLazy()
|
val getLibraryManga: GetLibraryManga by injectLazy()
|
||||||
val libraryManga = runBlocking { getLibraryManga.await() }
|
val libraryManga = getLibraryManga.await()
|
||||||
db.inTransaction {
|
|
||||||
libraryManga.forEach { manga ->
|
libraryManga.forEach { manga ->
|
||||||
|
if (manga.id == null) return@forEach
|
||||||
if (manga.thumbnail_url?.startsWith("custom", ignoreCase = true) == true) {
|
if (manga.thumbnail_url?.startsWith("custom", ignoreCase = true) == true) {
|
||||||
val file = cc.getCoverFile(manga)
|
val file = cc.getCoverFile(manga)
|
||||||
if (file.exists()) {
|
if (file.exists()) {
|
||||||
|
@ -1539,8 +1554,7 @@ class LibraryPresenter(
|
||||||
}
|
}
|
||||||
manga.thumbnail_url =
|
manga.thumbnail_url =
|
||||||
manga.thumbnail_url!!.lowercase(Locale.ROOT).substringAfter("custom-")
|
manga.thumbnail_url!!.lowercase(Locale.ROOT).substringAfter("custom-")
|
||||||
db.insertManga(manga).executeAsBlocking()
|
updateManga.await(MangaUpdate(manga.id!!, thumbnailUrl = manga.thumbnail_url))
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package yokai.core.migration.migrations
|
package yokai.core.migration.migrations
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.ui.library.LibraryPresenter
|
import eu.kanade.tachiyomi.ui.library.LibraryPresenter
|
||||||
|
import eu.kanade.tachiyomi.util.system.withIOContext
|
||||||
import yokai.core.migration.Migration
|
import yokai.core.migration.Migration
|
||||||
import yokai.core.migration.MigrationContext
|
import yokai.core.migration.MigrationContext
|
||||||
|
|
||||||
|
@ -9,7 +10,7 @@ class CustomInfoMigration : Migration {
|
||||||
|
|
||||||
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
|
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
|
||||||
try {
|
try {
|
||||||
LibraryPresenter.updateCustoms()
|
withIOContext { LibraryPresenter.updateCustoms() }
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import eu.kanade.tachiyomi.data.library.LibraryUpdateJob
|
||||||
import eu.kanade.tachiyomi.data.updater.AppUpdateJob
|
import eu.kanade.tachiyomi.data.updater.AppUpdateJob
|
||||||
import eu.kanade.tachiyomi.extension.ExtensionUpdateJob
|
import eu.kanade.tachiyomi.extension.ExtensionUpdateJob
|
||||||
import eu.kanade.tachiyomi.ui.library.LibraryPresenter
|
import eu.kanade.tachiyomi.ui.library.LibraryPresenter
|
||||||
|
import eu.kanade.tachiyomi.util.system.withIOContext
|
||||||
import yokai.core.migration.Migration
|
import yokai.core.migration.Migration
|
||||||
import yokai.core.migration.MigrationContext
|
import yokai.core.migration.MigrationContext
|
||||||
|
|
||||||
|
@ -18,7 +19,9 @@ class WorkManagerMigration : Migration {
|
||||||
|
|
||||||
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
|
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
|
||||||
val context: App = migrationContext.get() ?: return false
|
val context: App = migrationContext.get() ?: return false
|
||||||
|
withIOContext {
|
||||||
LibraryPresenter.updateDB()
|
LibraryPresenter.updateDB()
|
||||||
|
}
|
||||||
if (BuildConfig.INCLUDE_UPDATER) {
|
if (BuildConfig.INCLUDE_UPDATER) {
|
||||||
AppUpdateJob.setupTask(context)
|
AppUpdateJob.setupTask(context)
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,9 @@ class MangaRepositoryImpl(private val handler: DatabaseHandler) : MangaRepositor
|
||||||
override suspend fun getMangaById(id: Long): Manga? =
|
override suspend fun getMangaById(id: Long): Manga? =
|
||||||
handler.awaitOneOrNull { mangasQueries.findById(id, Manga::mapper) }
|
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>> =
|
override fun getMangaListAsFlow(): Flow<List<Manga>> =
|
||||||
handler.subscribeToList { mangasQueries.findAll(Manga::mapper) }
|
handler.subscribeToList { mangasQueries.findAll(Manga::mapper) }
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ interface MangaRepository {
|
||||||
suspend fun getMangaList(): List<Manga>
|
suspend fun getMangaList(): List<Manga>
|
||||||
suspend fun getMangaByUrlAndSource(url: String, source: Long): Manga?
|
suspend fun getMangaByUrlAndSource(url: String, source: Long): Manga?
|
||||||
suspend fun getMangaById(id: Long): Manga?
|
suspend fun getMangaById(id: Long): Manga?
|
||||||
|
suspend fun getFavorites(): List<Manga>
|
||||||
fun getMangaListAsFlow(): Flow<List<Manga>>
|
fun getMangaListAsFlow(): Flow<List<Manga>>
|
||||||
suspend fun getLibraryManga(): List<LibraryManga>
|
suspend fun getLibraryManga(): List<LibraryManga>
|
||||||
fun getLibraryMangaAsFlow(): Flow<List<LibraryManga>>
|
fun getLibraryMangaAsFlow(): Flow<List<LibraryManga>>
|
||||||
|
|
|
@ -10,4 +10,5 @@ class GetManga (
|
||||||
|
|
||||||
suspend fun awaitByUrlAndSource(url: String, source: Long) = mangaRepository.getMangaByUrlAndSource(url, source)
|
suspend fun awaitByUrlAndSource(url: String, source: Long) = mangaRepository.getMangaByUrlAndSource(url, source)
|
||||||
suspend fun awaitById(id: Long) = mangaRepository.getMangaById(id)
|
suspend fun awaitById(id: Long) = mangaRepository.getMangaById(id)
|
||||||
|
suspend fun awaitFavorites() = mangaRepository.getFavorites()
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,6 +45,11 @@ SELECT *
|
||||||
FROM mangas
|
FROM mangas
|
||||||
WHERE favorite = 1 AND lower(title) = :title AND source = :source;
|
WHERE favorite = 1 AND lower(title) = :title AND source = :source;
|
||||||
|
|
||||||
|
findFavorites:
|
||||||
|
SELECT *
|
||||||
|
FROM mangas
|
||||||
|
WHERE favorite = 1;
|
||||||
|
|
||||||
insert:
|
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)
|
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);
|
VALUES (:source, :url, :artist, :author, :description, :genre, :title, :status, :thumbnailUrl, :favorite, :lastUpdate, :initialized, :viewer, :hideTitle, :chapterFlags, :dateAdded, :filteredScanlators, :updateStrategy);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue