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