From b2565c7f8bdc79adaefc1e668e2c6b2745b2a77c Mon Sep 17 00:00:00 2001 From: arkon Date: Sun, 30 Oct 2022 22:56:07 -0400 Subject: [PATCH] Clean up library download chapters logic We can probably clean up the same logic in the manga controller at some point too, but that stuff's messy. Also fixes the spacing issue that the new icon introduced. (cherry picked from commit 33e90d64497f920be825b803e1342a2e6c937111) # Conflicts: # app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt --- .../java/eu/kanade/domain/SYDomainModule.kt | 2 +- .../interactor/GetMergedChapterByMangaId.kt | 79 ++++++++++++++-- .../chapter/interactor/SetReadStatus.kt | 11 +-- .../interactor/GetNextUnreadChapters.kt | 30 ++++-- .../components/MangaBottomActionMenu.kt | 20 ++-- .../components/LibraryComfortableGrid.kt | 2 +- .../library/components/LibraryCompactGrid.kt | 4 +- .../source/online/all/MergedSource.kt | 91 ++---------------- .../tachiyomi/ui/library/LibraryController.kt | 13 ++- .../tachiyomi/ui/library/LibraryPresenter.kt | 93 ++++++++----------- .../tachiyomi/ui/manga/MangaPresenter.kt | 5 +- .../tachiyomi/ui/reader/ReaderPresenter.kt | 5 +- 12 files changed, 174 insertions(+), 181 deletions(-) diff --git a/app/src/main/java/eu/kanade/domain/SYDomainModule.kt b/app/src/main/java/eu/kanade/domain/SYDomainModule.kt index b4ca627de..301c2ab1a 100644 --- a/app/src/main/java/eu/kanade/domain/SYDomainModule.kt +++ b/app/src/main/java/eu/kanade/domain/SYDomainModule.kt @@ -120,7 +120,7 @@ class SYDomainModule : InjektModule { addFactory { GetMergedManga(get()) } addFactory { GetMergedMangaById(get()) } addFactory { GetMergedReferencesById(get()) } - addFactory { GetMergedChapterByMangaId(get()) } + addFactory { GetMergedChapterByMangaId(get(), get(), get()) } addFactory { InsertMergedReference(get()) } addFactory { UpdateMergedSettings(get()) } addFactory { DeleteByMergeId(get()) } diff --git a/app/src/main/java/eu/kanade/domain/chapter/interactor/GetMergedChapterByMangaId.kt b/app/src/main/java/eu/kanade/domain/chapter/interactor/GetMergedChapterByMangaId.kt index a915b1d9a..809dcd15d 100644 --- a/app/src/main/java/eu/kanade/domain/chapter/interactor/GetMergedChapterByMangaId.kt +++ b/app/src/main/java/eu/kanade/domain/chapter/interactor/GetMergedChapterByMangaId.kt @@ -2,16 +2,39 @@ package eu.kanade.domain.chapter.interactor import eu.kanade.domain.chapter.model.Chapter import eu.kanade.domain.chapter.repository.ChapterRepository +import eu.kanade.domain.manga.interactor.GetMergedReferencesById +import eu.kanade.tachiyomi.source.SourceManager import eu.kanade.tachiyomi.util.system.logcat +import exh.merged.sql.models.MergedMangaReference +import exh.source.MERGED_SOURCE_ID import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.flow.map import logcat.LogPriority class GetMergedChapterByMangaId( private val chapterRepository: ChapterRepository, + private val getMergedReferencesById: GetMergedReferencesById, + private val sourceManager: SourceManager, ) { - suspend fun await(mangaId: Long): List { + suspend fun await(mangaId: Long, editScanlators: Boolean = false, dedupe: Boolean = true): List { + return transformMergedChapters(mangaId, getFromDatabase(mangaId), editScanlators, dedupe) + } + + suspend fun subscribe(mangaId: Long, editScanlators: Boolean = false, dedupe: Boolean = true): Flow> { + return try { + chapterRepository.getMergedChapterByMangaIdAsFlow(mangaId) + .map { + transformMergedChapters(mangaId, it, editScanlators, dedupe) + } + } catch (e: Exception) { + logcat(LogPriority.ERROR, e) + flowOf(emptyList()) + } + } + + private suspend fun getFromDatabase(mangaId: Long): List { return try { chapterRepository.getMergedChapterByMangaId(mangaId) } catch (e: Exception) { @@ -20,12 +43,54 @@ class GetMergedChapterByMangaId( } } - suspend fun subscribe(mangaId: Long): Flow> { - return try { - chapterRepository.getMergedChapterByMangaIdAsFlow(mangaId) - } catch (e: Exception) { - logcat(LogPriority.ERROR, e) - flowOf(emptyList()) + // TODO more chapter dedupe + suspend fun transformMergedChapters(mangaId: Long, chapterList: List, editScanlators: Boolean, dedupe: Boolean): List { + val mangaReferences = getMergedReferencesById.await(mangaId) + val chapters = if (editScanlators) { + val sources = mangaReferences.map { sourceManager.getOrStub(it.mangaSourceId) to it.mangaId } + chapterList.map { chapter -> + val source = sources.firstOrNull { chapter.mangaId == it.second }?.first + if (source != null) { + chapter.copy( + scanlator = if (chapter.scanlator.isNullOrBlank()) { + source.name + } else { + "$source: ${chapter.scanlator}" + }, + ) + } else { + chapter + } + } + } else { + chapterList + } + return if (dedupe) dedupeChapterList(mangaReferences, chapters) else chapters + } + + private fun dedupeChapterList(mangaReferences: List, chapterList: List): List { + return when (mangaReferences.firstOrNull { it.mangaSourceId == MERGED_SOURCE_ID }?.chapterSortMode) { + MergedMangaReference.CHAPTER_SORT_NO_DEDUPE, MergedMangaReference.CHAPTER_SORT_NONE -> chapterList + MergedMangaReference.CHAPTER_SORT_PRIORITY -> chapterList + MergedMangaReference.CHAPTER_SORT_MOST_CHAPTERS -> { + findSourceWithMostChapters(chapterList)?.let { mangaId -> + chapterList.filter { it.mangaId == mangaId } + } ?: chapterList + } + MergedMangaReference.CHAPTER_SORT_HIGHEST_CHAPTER_NUMBER -> { + findSourceWithHighestChapterNumber(chapterList)?.let { mangaId -> + chapterList.filter { it.mangaId == mangaId } + } ?: chapterList + } + else -> chapterList } } + + private fun findSourceWithMostChapters(chapterList: List): Long? { + return chapterList.groupBy { it.mangaId }.maxByOrNull { it.value.size }?.key + } + + private fun findSourceWithHighestChapterNumber(chapterList: List): Long? { + return chapterList.maxByOrNull { it.chapterNumber }?.mangaId + } } diff --git a/app/src/main/java/eu/kanade/domain/chapter/interactor/SetReadStatus.kt b/app/src/main/java/eu/kanade/domain/chapter/interactor/SetReadStatus.kt index 4f3c6a61c..1d3bc67e0 100644 --- a/app/src/main/java/eu/kanade/domain/chapter/interactor/SetReadStatus.kt +++ b/app/src/main/java/eu/kanade/domain/chapter/interactor/SetReadStatus.kt @@ -7,8 +7,6 @@ import eu.kanade.domain.download.interactor.DeleteDownload import eu.kanade.domain.download.service.DownloadPreferences import eu.kanade.domain.manga.model.Manga import eu.kanade.domain.manga.repository.MangaRepository -import eu.kanade.tachiyomi.source.SourceManager -import eu.kanade.tachiyomi.source.online.all.MergedSource import eu.kanade.tachiyomi.util.lang.withNonCancellableContext import eu.kanade.tachiyomi.util.system.logcat import exh.source.MERGED_SOURCE_ID @@ -19,7 +17,9 @@ class SetReadStatus( private val deleteDownload: DeleteDownload, private val mangaRepository: MangaRepository, private val chapterRepository: ChapterRepository, - private val sourceManager: SourceManager, + // SY --> + private val getMergedChapterByMangaId: GetMergedChapterByMangaId, + // SY <-- ) { private val mapper = { chapter: Chapter, read: Boolean -> @@ -75,11 +75,10 @@ class SetReadStatus( // SY --> private suspend fun awaitMerged(mangaId: Long, read: Boolean) = withNonCancellableContext f@{ - val mergedSource = sourceManager.get(MERGED_SOURCE_ID) as MergedSource return@f await( read = read, - chapters = mergedSource - .getChapters(mangaId, dedupe = false) + chapters = getMergedChapterByMangaId + .await(mangaId, dedupe = false) .toTypedArray(), ) } diff --git a/app/src/main/java/eu/kanade/domain/history/interactor/GetNextUnreadChapters.kt b/app/src/main/java/eu/kanade/domain/history/interactor/GetNextUnreadChapters.kt index e03114fe2..a6810c59e 100644 --- a/app/src/main/java/eu/kanade/domain/history/interactor/GetNextUnreadChapters.kt +++ b/app/src/main/java/eu/kanade/domain/history/interactor/GetNextUnreadChapters.kt @@ -1,15 +1,19 @@ package eu.kanade.domain.history.interactor -import eu.kanade.domain.chapter.interactor.GetChapter import eu.kanade.domain.chapter.interactor.GetChapterByMangaId +import eu.kanade.domain.chapter.interactor.GetMergedChapterByMangaId import eu.kanade.domain.chapter.model.Chapter import eu.kanade.domain.history.repository.HistoryRepository import eu.kanade.domain.manga.interactor.GetManga import eu.kanade.tachiyomi.util.chapter.getChapterSort +import exh.source.MERGED_SOURCE_ID +import kotlin.math.max class GetNextUnreadChapters( - private val getChapter: GetChapter, private val getChapterByMangaId: GetChapterByMangaId, + // SY --> + private val getMergedChapterByMangaId: GetMergedChapterByMangaId, + // SY <-- private val getManga: GetManga, private val historyRepository: HistoryRepository, ) { @@ -19,15 +23,23 @@ class GetNextUnreadChapters( return await(history.mangaId, history.chapterId).firstOrNull() } - suspend fun await(mangaId: Long, chapterId: Long): List { - val chapter = getChapter.await(chapterId) ?: return emptyList() + suspend fun await(mangaId: Long): List { val manga = getManga.await(mangaId) ?: return emptyList() - - val chapters = getChapterByMangaId.await(mangaId) + // SY --> + if (manga.source == MERGED_SOURCE_ID) { + return getMergedChapterByMangaId.await(mangaId) + .sortedWith(getChapterSort(manga, sortDescending = false)) + .filterNot { it.read } + } + // SY <-- + return getChapterByMangaId.await(mangaId) .sortedWith(getChapterSort(manga, sortDescending = false)) - val currChapterIndex = chapters.indexOfFirst { chapter.id == it.id } - return chapters - .subList(currChapterIndex, chapters.size) .filterNot { it.read } } + + suspend fun await(mangaId: Long, fromChapterId: Long): List { + val unreadChapters = await(mangaId) + val currChapterIndex = unreadChapters.indexOfFirst { it.id == fromChapterId } + return unreadChapters.subList(max(0, currChapterIndex), unreadChapters.size) + } } diff --git a/app/src/main/java/eu/kanade/presentation/components/MangaBottomActionMenu.kt b/app/src/main/java/eu/kanade/presentation/components/MangaBottomActionMenu.kt index 3aad34cfd..45d8cb708 100644 --- a/app/src/main/java/eu/kanade/presentation/components/MangaBottomActionMenu.kt +++ b/app/src/main/java/eu/kanade/presentation/components/MangaBottomActionMenu.kt @@ -9,7 +9,6 @@ import androidx.compose.animation.shrinkVertically import androidx.compose.foundation.combinedClickable import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.RowScope @@ -179,6 +178,7 @@ private fun RowScope.Button( toConfirm: Boolean, onLongClick: () -> Unit, onClick: () -> Unit, + content: (@Composable () -> Unit)? = null, ) { val animatedWeight by animateFloatAsState(if (toConfirm) 2f else 1f) Column( @@ -210,6 +210,7 @@ private fun RowScope.Button( style = MaterialTheme.typography.labelSmall, ) } + content?.invoke() } } @@ -272,15 +273,14 @@ fun LibraryBottomActionMenu( ) } if (onDownloadClicked != null) { - Box { - var downloadExpanded by remember { mutableStateOf(false) } - this@Row.Button( - title = stringResource(R.string.action_download), - icon = Icons.Outlined.Download, - toConfirm = confirm[3], - onLongClick = { onLongClickItem(3) }, - onClick = { downloadExpanded = !downloadExpanded }, - ) + var downloadExpanded by remember { mutableStateOf(false) } + Button( + title = stringResource(R.string.action_download), + icon = Icons.Outlined.Download, + toConfirm = confirm[3], + onLongClick = { onLongClickItem(3) }, + onClick = { downloadExpanded = !downloadExpanded }, + ) { val onDismissRequest = { downloadExpanded = false } DownloadDropdownMenu( expanded = downloadExpanded, diff --git a/app/src/main/java/eu/kanade/presentation/library/components/LibraryComfortableGrid.kt b/app/src/main/java/eu/kanade/presentation/library/components/LibraryComfortableGrid.kt index f28066c93..b35105cfd 100644 --- a/app/src/main/java/eu/kanade/presentation/library/components/LibraryComfortableGrid.kt +++ b/app/src/main/java/eu/kanade/presentation/library/components/LibraryComfortableGrid.kt @@ -72,7 +72,7 @@ fun LibraryComfortableGrid( ) }, // SY --> - buttonBottom = if (showStartReadingButton) { + buttonBottom = if (showStartReadingButton && libraryItem.unreadCount > 0) { { StartReadingButton(onOpenReader = { onOpenReader(libraryItem.libraryManga) }) } } else { null diff --git a/app/src/main/java/eu/kanade/presentation/library/components/LibraryCompactGrid.kt b/app/src/main/java/eu/kanade/presentation/library/components/LibraryCompactGrid.kt index fe8f10d8d..e5deee168 100644 --- a/app/src/main/java/eu/kanade/presentation/library/components/LibraryCompactGrid.kt +++ b/app/src/main/java/eu/kanade/presentation/library/components/LibraryCompactGrid.kt @@ -73,12 +73,12 @@ fun LibraryCompactGrid( ) }, // SY --> - buttonTop = if (showStartReadingButton && showTitle) { + buttonTop = if (showStartReadingButton && showTitle && libraryItem.unreadCount > 0) { { StartReadingButton(onOpenReader = { onOpenReader(libraryItem.libraryManga) }) } } else { null }, - buttonBottom = if (showStartReadingButton && !showTitle) { + buttonBottom = if (showStartReadingButton && !showTitle && libraryItem.unreadCount > 0) { { StartReadingButton(onOpenReader = { onOpenReader(libraryItem.libraryManga) }) } } else { null diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/online/all/MergedSource.kt b/app/src/main/java/eu/kanade/tachiyomi/source/online/all/MergedSource.kt index 123706c8d..7453540ca 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/source/online/all/MergedSource.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/source/online/all/MergedSource.kt @@ -1,7 +1,6 @@ package eu.kanade.tachiyomi.source.online.all import eu.kanade.domain.category.interactor.GetCategories -import eu.kanade.domain.chapter.interactor.GetMergedChapterByMangaId import eu.kanade.domain.chapter.interactor.SyncChaptersWithSource import eu.kanade.domain.chapter.model.Chapter import eu.kanade.domain.chapter.model.toDbChapter @@ -27,19 +26,16 @@ import exh.source.MERGED_SOURCE_ID import kotlinx.coroutines.CancellationException import kotlinx.coroutines.async import kotlinx.coroutines.awaitAll -import kotlinx.coroutines.runBlocking import kotlinx.coroutines.supervisorScope import kotlinx.coroutines.sync.Semaphore import kotlinx.coroutines.sync.withPermit import okhttp3.Response -import uy.kohesive.injekt.Injekt -import uy.kohesive.injekt.api.get import uy.kohesive.injekt.injectLazy class MergedSource : HttpSource() { private val getManga: GetManga by injectLazy() private val getMergedReferencesById: GetMergedReferencesById by injectLazy() - private val getMergedChaptersByMangaId: GetMergedChapterByMangaId by injectLazy() + private val syncChaptersWithSource: SyncChaptersWithSource by injectLazy() private val networkToLocalManga: NetworkToLocalManga by injectLazy() private val updateManga: UpdateManga by injectLazy() private val getCategories: GetCategories by injectLazy() @@ -76,18 +72,12 @@ class MergedSource : HttpSource() { override suspend fun getMangaDetails(manga: SManga): SManga { return withIOContext { - val mergedManga = getManga.await(manga.url, id) ?: throw Exception("merged manga not in db") + val mergedManga = requireNotNull(getManga.await(manga.url, id)) { "merged manga not in db" } val mangaReferences = getMergedReferencesById.await(mergedManga.id) .apply { - if (isEmpty()) { - throw IllegalArgumentException( - "Manga references are empty, info unavailable, merge is likely corrupted", - ) - } - if (size == 1 && first().mangaSourceId == MERGED_SOURCE_ID) { - throw IllegalArgumentException( - "Manga references contain only the merged reference, merge is likely corrupted", - ) + require(isNotEmpty()) { "Manga references are empty, info unavailable, merge is likely corrupted" } + require(!(size == 1 && first().mangaSourceId == MERGED_SOURCE_ID)) { + "Manga references contain only the merged reference, merge is likely corrupted" } } @@ -102,77 +92,14 @@ class MergedSource : HttpSource() { } } - // TODO more chapter dedupe - suspend fun transformMergedChapters(mangaId: Long, chapterList: List, editScanlators: Boolean, dedupe: Boolean): List { - val mangaReferences = getMergedReferencesById.await(mangaId) - val chapters = if (editScanlators) { - val sources = mangaReferences.map { sourceManager.getOrStub(it.mangaSourceId) to it.mangaId } - chapterList.map { chapter -> - val source = sources.firstOrNull { chapter.mangaId == it.second }?.first - if (source != null) { - chapter.copy( - scanlator = if (chapter.scanlator.isNullOrBlank()) { - source.name - } else { - "$source: ${chapter.scanlator}" - }, - ) - } else { - chapter - } - } - } else { - chapterList - } - return if (dedupe) dedupeChapterList(mangaReferences, chapters) else chapters - } - - fun getChaptersAsBlocking(mangaId: Long, editScanlators: Boolean = false, dedupe: Boolean = true): List { - return runBlocking { getChapters(mangaId, editScanlators, dedupe) } - } - - suspend fun getChapters(mangaId: Long, editScanlators: Boolean = false, dedupe: Boolean = true): List { - return transformMergedChapters(mangaId, getMergedChaptersByMangaId.await(mangaId), editScanlators, dedupe) - } - - private fun dedupeChapterList(mangaReferences: List, chapterList: List): List { - return when (mangaReferences.firstOrNull { it.mangaSourceId == MERGED_SOURCE_ID }?.chapterSortMode) { - MergedMangaReference.CHAPTER_SORT_NO_DEDUPE, MergedMangaReference.CHAPTER_SORT_NONE -> chapterList - MergedMangaReference.CHAPTER_SORT_PRIORITY -> chapterList - MergedMangaReference.CHAPTER_SORT_MOST_CHAPTERS -> { - findSourceWithMostChapters(chapterList)?.let { mangaId -> - chapterList.filter { it.mangaId == mangaId } - } ?: chapterList - } - MergedMangaReference.CHAPTER_SORT_HIGHEST_CHAPTER_NUMBER -> { - findSourceWithHighestChapterNumber(chapterList)?.let { mangaId -> - chapterList.filter { it.mangaId == mangaId } - } ?: chapterList - } - else -> chapterList - } - } - - private fun findSourceWithMostChapters(chapterList: List): Long? { - return chapterList.groupBy { it.mangaId }.maxByOrNull { it.value.size }?.key - } - - private fun findSourceWithHighestChapterNumber(chapterList: List): Long? { - return chapterList.maxByOrNull { it.chapterNumber }?.mangaId - } - - suspend fun fetchChaptersForMergedManga(manga: Manga, downloadChapters: Boolean = true, editScanlators: Boolean = false, dedupe: Boolean = true): List { - return withIOContext { - fetchChaptersAndSync(manga, downloadChapters) - getChapters(manga.id, editScanlators, dedupe) - } + suspend fun fetchChaptersForMergedManga(manga: Manga, downloadChapters: Boolean = true, editScanlators: Boolean = false, dedupe: Boolean = true) { + fetchChaptersAndSync(manga, downloadChapters) } suspend fun fetchChaptersAndSync(manga: Manga, downloadChapters: Boolean = true): List { - val syncChaptersWithSource = Injekt.get() val mangaReferences = getMergedReferencesById.await(manga.id) - if (mangaReferences.isEmpty()) { - throw IllegalArgumentException("Manga references are empty, chapters unavailable, merge is likely corrupted") + require(mangaReferences.isNotEmpty()) { + "Manga references are empty, chapters unavailable, merge is likely corrupted" } val ifDownloadNewChapters = downloadChapters && manga.shouldDownloadNewChapters(getCategories.await(manga.id).map { it.id }, downloadPreferences) 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 d8e281a25..9ad2f32be 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 @@ -35,6 +35,7 @@ import eu.kanade.tachiyomi.ui.manga.MangaController import eu.kanade.tachiyomi.ui.reader.ReaderActivity import eu.kanade.tachiyomi.util.lang.launchIO import eu.kanade.tachiyomi.util.lang.launchUI +import eu.kanade.tachiyomi.util.lang.withUIContext import eu.kanade.tachiyomi.util.system.toast import exh.favorites.FavoritesIntroDialog import exh.favorites.FavoritesSyncStatus @@ -509,10 +510,14 @@ class LibraryController( private fun startReading(manga: Manga) { val activity = activity ?: return - val chapter = presenter.getFirstUnread(manga) ?: return - val intent = ReaderActivity.newIntent(activity, manga.id, chapter.id) - presenter.clearSelection() - startActivity(intent) + viewScope.launchIO { + val chapter = presenter.getFirstUnread(manga) ?: return@launchIO + val intent = ReaderActivity.newIntent(activity, manga.id, chapter.id) + presenter.clearSelection() + withUIContext { + startActivity(intent) + } + } } // <-- EXH } 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 4c3c15fb7..c26f1739d 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt @@ -20,11 +20,11 @@ import eu.kanade.domain.base.BasePreferences import eu.kanade.domain.category.interactor.GetCategories import eu.kanade.domain.category.interactor.SetMangaCategories import eu.kanade.domain.category.model.Category -import eu.kanade.domain.chapter.interactor.GetChapterByMangaId import eu.kanade.domain.chapter.interactor.GetMergedChapterByMangaId import eu.kanade.domain.chapter.interactor.SetReadStatus import eu.kanade.domain.chapter.model.Chapter import eu.kanade.domain.chapter.model.toDbChapter +import eu.kanade.domain.history.interactor.GetNextUnreadChapters import eu.kanade.domain.library.model.LibraryDisplayMode import eu.kanade.domain.library.model.LibraryGroup import eu.kanade.domain.library.model.LibraryManga @@ -54,7 +54,6 @@ import eu.kanade.tachiyomi.data.cache.CoverCache import eu.kanade.tachiyomi.data.database.models.toDomainManga import eu.kanade.tachiyomi.data.download.DownloadCache import eu.kanade.tachiyomi.data.download.DownloadManager -import eu.kanade.tachiyomi.data.download.model.Download import eu.kanade.tachiyomi.data.library.CustomMangaManager import eu.kanade.tachiyomi.data.track.TrackManager import eu.kanade.tachiyomi.data.track.TrackStatus @@ -65,7 +64,6 @@ import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.online.HttpSource import eu.kanade.tachiyomi.source.online.all.MergedSource import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter -import eu.kanade.tachiyomi.util.chapter.getChapterSort import eu.kanade.tachiyomi.util.lang.launchIO import eu.kanade.tachiyomi.util.lang.launchNonCancellable import eu.kanade.tachiyomi.util.lang.withIOContext @@ -82,7 +80,6 @@ import exh.search.SearchEngine import exh.search.Text import exh.source.EH_SOURCE_ID import exh.source.MERGED_SOURCE_ID -import exh.source.isEhBasedManga import exh.source.isMetadataSource import exh.util.cancellable import exh.util.isLewd @@ -123,7 +120,7 @@ class LibraryPresenter( private val getLibraryManga: GetLibraryManga = Injekt.get(), private val getTracksPerManga: GetTracksPerManga = Injekt.get(), private val getCategories: GetCategories = Injekt.get(), - private val getChapterByMangaId: GetChapterByMangaId = Injekt.get(), + private val getNextUnreadChapters: GetNextUnreadChapters = Injekt.get(), private val setReadStatus: SetReadStatus = Injekt.get(), private val updateManga: UpdateManga = Injekt.get(), private val setMangaCategories: SetMangaCategories = Injekt.get(), @@ -602,25 +599,6 @@ class LibraryPresenter( return mangaCategories.flatten().distinct().subtract(common) } - fun shouldDownloadChapter(manga: Manga, chapter: Chapter): Boolean { - val activeDownload = downloadManager.queue.find { chapter.id == it.chapter.id } - val downloaded = downloadManager.isChapterDownloaded(chapter.name, chapter.scanlator, manga.title, manga.source) - val state = when { - activeDownload != null -> activeDownload.status - downloaded -> Download.State.DOWNLOADED - else -> Download.State.NOT_DOWNLOADED - } - return state == Download.State.NOT_DOWNLOADED - } - - suspend fun getNotDownloadedUnreadChapters(manga: Manga): List { - return getChapterByMangaId.await(manga.id) - .filter { chapter -> - !chapter.read && shouldDownloadChapter(manga, chapter) - } - .sortedWith(getChapterSort(manga, sortDescending = false)) - } - /** * Queues the amount specified of unread chapters from the list of mangas given. * @@ -630,31 +608,48 @@ class LibraryPresenter( fun downloadUnreadChapters(mangas: List, amount: Int?) { presenterScope.launchNonCancellable { mangas.forEach { manga -> + // SY --> if (manga.source == MERGED_SOURCE_ID) { - val mergedSource = sourceManager.get(MERGED_SOURCE_ID) as MergedSource val mergedMangas = getMergedMangaById.await(manga.id) - mergedSource - .getChapters(manga.id) - .filter { !it.read } + .associateBy { it.id } + getNextUnreadChapters.await(manga.id) .let { if (amount != null) it.take(amount) else it } .groupBy { it.mangaId } .forEach ab@{ (mangaId, chapters) -> - val mergedManga = mergedMangas.firstOrNull { it.id == mangaId } ?: return@ab - downloadManager.downloadChapters(mergedManga, chapters.map(Chapter::toDbChapter)) - } - } else { - /* SY --> */ - val chapters = if (manga.isEhBasedManga()) { - getChapterByMangaId.await(manga.id).minByOrNull { it.sourceOrder } - ?.takeUnless { it.read } - .let(::listOfNotNull) - } else { - /* SY <-- */ getNotDownloadedUnreadChapters(manga) - .let { if (amount != null) it.take(amount) else it } - } + val mergedManga = mergedMangas[mangaId] ?: return@ab + val downloadChapters = chapters.filterNot { chapter -> + downloadManager.queue.any { chapter.id == it.chapter.id } || + downloadManager.isChapterDownloaded( + chapter.name, + chapter.scanlator, + mergedManga.ogTitle, + mergedManga.source, + ) + } - downloadManager.downloadChapters(manga, chapters.map { it.toDbChapter() }) + downloadManager.downloadChapters(mergedManga, downloadChapters.map(Chapter::toDbChapter)) + } + + return@forEach } + + // SY <-- + val chapters = getNextUnreadChapters.await(manga.id) + .filterNot { chapter -> + downloadManager.queue.any { chapter.id == it.chapter.id } || + downloadManager.isChapterDownloaded( + chapter.name, + chapter.scanlator, + // SY --> + manga.ogTitle, + // SY <-- + manga.source, + + ) + } + .let { if (amount != null) it.take(amount) else it } + + downloadManager.downloadChapters(manga, chapters.map { it.toDbChapter() }) } } } @@ -1082,18 +1077,8 @@ class LibraryPresenter( // SY --> /** Returns first unread chapter of a manga */ - fun getFirstUnread(manga: Manga): Chapter? { - val chapters = if (manga.source == MERGED_SOURCE_ID) { - (sourceManager.get(MERGED_SOURCE_ID) as MergedSource).getChaptersAsBlocking(manga.id) - } else { - runBlocking { getChapterByMangaId.await(manga.id) } - } - return if (manga.isEhBasedManga()) { - val chapter = chapters.sortedBy { it.sourceOrder }.getOrNull(0) - if (chapter?.read == false) chapter else null - } else { - chapters.sortedByDescending { it.sourceOrder }.find { !it.read } - } + suspend fun getFirstUnread(manga: Manga): Chapter? { + return getNextUnreadChapters.await(manga.id).firstOrNull() } private fun getGroupedMangaItems(groupType: Int, libraryManga: List): Pair> { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt index fd9ff0b04..44d61b72e 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt @@ -266,7 +266,7 @@ class MangaPresenter( .distinctUntilChanged() // SY --> .combine( - getMergedChapterByMangaId.subscribe(mangaId) + getMergedChapterByMangaId.subscribe(mangaId, true) .distinctUntilChanged(), ) { (manga, chapters), mergedChapters -> if (manga.source == MERGED_SOURCE_ID) { @@ -351,7 +351,7 @@ class MangaPresenter( presenterScope.launchIO { val manga = getMangaAndChapters.awaitManga(mangaId) // SY --> - val chapters = (if (manga.source == MERGED_SOURCE_ID) getMergedChapterByMangaId.await(mangaId) else getMangaAndChapters.awaitChapters(mangaId)) + val chapters = (if (manga.source == MERGED_SOURCE_ID) getMergedChapterByMangaId.await(mangaId, true) else getMangaAndChapters.awaitChapters(mangaId)) .toChapterItemsParams(manga, null) val mergedData = getMergedReferencesById.await(mangaId).takeIf { it.isNotEmpty() }?.let { references -> MergedMangaData( @@ -1041,7 +1041,6 @@ class MangaPresenter( } } else { successState.source.fetchChaptersForMergedManga(successState.manga, manualFetch, true, dedupe) - Unit } } } catch (e: Throwable) { 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 32a4789ec..853554ce7 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 @@ -8,6 +8,7 @@ import androidx.annotation.ColorInt import com.jakewharton.rxrelay.BehaviorRelay import eu.kanade.domain.base.BasePreferences import eu.kanade.domain.chapter.interactor.GetChapterByMangaId +import eu.kanade.domain.chapter.interactor.GetMergedChapterByMangaId import eu.kanade.domain.chapter.interactor.UpdateChapter import eu.kanade.domain.chapter.model.ChapterUpdate import eu.kanade.domain.chapter.model.toDbChapter @@ -121,6 +122,7 @@ class ReaderPresenter( private val getFlatMetadataById: GetFlatMetadataById = Injekt.get(), private val getMergedManga: GetMergedManga = Injekt.get(), private val getMergedReferencesById: GetMergedReferencesById = Injekt.get(), + private val getMergedChapterByMangaId: GetMergedChapterByMangaId = Injekt.get(), // SY <-- ) : BasePresenter() { @@ -183,8 +185,7 @@ class ReaderPresenter( // SY <-- val chapters = runBlocking { /* SY --> */ if (manga.source == MERGED_SOURCE_ID) { - (sourceManager.get(MERGED_SOURCE_ID) as MergedSource) - .getChapters(manga.id!!) + getMergedChapterByMangaId.await(manga.id!!) } else { /* SY <-- */ getChapterByMangaId.await(manga.id!!) }