From 5869fa0b4f2c43475dab900ab1f098d072b0f5ac Mon Sep 17 00:00:00 2001 From: Andreas Date: Fri, 8 Jul 2022 04:34:58 +0200 Subject: [PATCH] Reset lastPageRead when chapter is marked unread (#7475) * Reset lastPageRead when chapter is marked unread * Remove a bit of repetition in SetReadStatus (cherry picked from commit 5159eabc5dfd77dd7e4a480c1982bd1d2e5fbb92) # Conflicts: # app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt # app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt --- .../java/eu/kanade/domain/DomainModule.kt | 5 + .../chapter/interactor/SetReadStatus.kt | 105 ++++++++++++++++++ .../download/interactor/DeleteDownload.kt | 21 ++++ .../tachiyomi/ui/library/LibraryPresenter.kt | 37 +----- .../tachiyomi/ui/manga/MangaPresenter.kt | 13 +-- .../ui/recent/updates/UpdatesController.kt | 3 - .../ui/recent/updates/UpdatesPresenter.kt | 16 +-- 7 files changed, 151 insertions(+), 49 deletions(-) create mode 100644 app/src/main/java/eu/kanade/domain/chapter/interactor/SetReadStatus.kt create mode 100644 app/src/main/java/eu/kanade/domain/download/interactor/DeleteDownload.kt diff --git a/app/src/main/java/eu/kanade/domain/DomainModule.kt b/app/src/main/java/eu/kanade/domain/DomainModule.kt index 804bb6b49..e782379ed 100644 --- a/app/src/main/java/eu/kanade/domain/DomainModule.kt +++ b/app/src/main/java/eu/kanade/domain/DomainModule.kt @@ -14,11 +14,13 @@ import eu.kanade.domain.category.interactor.UpdateCategory import eu.kanade.domain.category.repository.CategoryRepository import eu.kanade.domain.chapter.interactor.GetChapter import eu.kanade.domain.chapter.interactor.GetChapterByMangaId +import eu.kanade.domain.chapter.interactor.SetReadStatus import eu.kanade.domain.chapter.interactor.ShouldUpdateDbChapter import eu.kanade.domain.chapter.interactor.SyncChaptersWithSource import eu.kanade.domain.chapter.interactor.SyncChaptersWithTrackServiceTwoWay import eu.kanade.domain.chapter.interactor.UpdateChapter import eu.kanade.domain.chapter.repository.ChapterRepository +import eu.kanade.domain.download.interactor.DeleteDownload import eu.kanade.domain.extension.interactor.GetExtensionLanguages import eu.kanade.domain.extension.interactor.GetExtensionSources import eu.kanade.domain.extension.interactor.GetExtensionUpdates @@ -94,6 +96,7 @@ class DomainModule : InjektModule { addFactory { GetChapter(get()) } addFactory { GetChapterByMangaId(get()) } addFactory { UpdateChapter(get()) } + addFactory { SetReadStatus(get(), get(), get(), get(), get()) } addFactory { ShouldUpdateDbChapter() } addFactory { SyncChaptersWithSource(get(), get(), get(), get()) } addFactory { SyncChaptersWithTrackServiceTwoWay(get(), get()) } @@ -105,6 +108,8 @@ class DomainModule : InjektModule { addFactory { RemoveHistoryById(get()) } addFactory { RemoveHistoryByMangaId(get()) } + addFactory { DeleteDownload(get(), get()) } + addFactory { GetExtensions(get(), get()) } addFactory { GetExtensionSources(get()) } addFactory { GetExtensionUpdates(get(), get()) } 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 new file mode 100644 index 000000000..7fcdc0ef5 --- /dev/null +++ b/app/src/main/java/eu/kanade/domain/chapter/interactor/SetReadStatus.kt @@ -0,0 +1,105 @@ +package eu.kanade.domain.chapter.interactor + +import eu.kanade.domain.chapter.model.Chapter +import eu.kanade.domain.chapter.model.ChapterUpdate +import eu.kanade.domain.chapter.repository.ChapterRepository +import eu.kanade.domain.download.interactor.DeleteDownload +import eu.kanade.domain.manga.model.Manga +import eu.kanade.domain.manga.repository.MangaRepository +import eu.kanade.tachiyomi.data.preference.PreferencesHelper +import eu.kanade.tachiyomi.source.SourceManager +import eu.kanade.tachiyomi.source.online.all.MergedSource +import eu.kanade.tachiyomi.util.system.logcat +import exh.source.MERGED_SOURCE_ID +import kotlinx.coroutines.NonCancellable +import kotlinx.coroutines.withContext +import logcat.LogPriority + +class SetReadStatus( + private val preferences: PreferencesHelper, + private val deleteDownload: DeleteDownload, + private val mangaRepository: MangaRepository, + private val chapterRepository: ChapterRepository, + private val sourceManager: SourceManager, +) { + + private val mapper = { chapter: Chapter, read: Boolean -> + ChapterUpdate( + read = read, + lastPageRead = if (!read) 0 else null, + id = chapter.id, + ) + } + + suspend fun await(read: Boolean, vararg values: Chapter): Result = withContext(NonCancellable) f@{ + val chapters = values.filterNot { it.read == read } + + if (chapters.isEmpty()) { + return@f Result.NoChapters + } + + val manga = chapters.fold(mutableSetOf()) { acc, chapter -> + if (acc.all { it.id != chapter.mangaId }) { + acc += mangaRepository.getMangaById(chapter.mangaId) + } + acc + } + + try { + chapterRepository.updateAll( + chapters.map { chapter -> + mapper(chapter, read) + }, + ) + } catch (e: Exception) { + logcat(LogPriority.ERROR, e) + return@f Result.InternalError(e) + } + + if (read && preferences.removeAfterMarkedAsRead()) { + manga.forEach { manga -> + deleteDownload.awaitAll( + manga = manga, + values = chapters + .filter { manga.id == it.mangaId } + .toTypedArray(), + ) + } + } + + Result.Success + } + + suspend fun await(mangaId: Long, read: Boolean): Result = withContext(NonCancellable) f@{ + return@f await( + read = read, + values = chapterRepository + .getChapterByMangaId(mangaId) + .toTypedArray(), + ) + } + + // SY --> + private suspend fun awaitMerged(mangaId: Long, read: Boolean) = withContext(NonCancellable) f@{ + val mergedSource = sourceManager.get(MERGED_SOURCE_ID) as MergedSource + return@f await( + read = read, + values = mergedSource + .getChapters(mangaId, dedupe = false) + .toTypedArray(), + ) + } + + suspend fun await(manga: Manga, read: Boolean) = if (manga.source == MERGED_SOURCE_ID) { + awaitMerged(manga.id, read) + } else { + await(manga.id, read) + } + // SY <-- + + sealed class Result { + object Success : Result() + object NoChapters : Result() + data class InternalError(val error: Throwable) : Result() + } +} diff --git a/app/src/main/java/eu/kanade/domain/download/interactor/DeleteDownload.kt b/app/src/main/java/eu/kanade/domain/download/interactor/DeleteDownload.kt new file mode 100644 index 000000000..546b7232c --- /dev/null +++ b/app/src/main/java/eu/kanade/domain/download/interactor/DeleteDownload.kt @@ -0,0 +1,21 @@ +package eu.kanade.domain.download.interactor + +import eu.kanade.domain.chapter.model.Chapter +import eu.kanade.domain.chapter.model.toDbChapter +import eu.kanade.domain.manga.model.Manga +import eu.kanade.tachiyomi.data.download.DownloadManager +import eu.kanade.tachiyomi.source.SourceManager +import kotlinx.coroutines.NonCancellable +import kotlinx.coroutines.withContext + +class DeleteDownload( + private val sourceManager: SourceManager, + private val downloadManager: DownloadManager, +) { + + suspend fun awaitAll(manga: Manga, vararg values: Chapter) = withContext(NonCancellable) { + sourceManager.get(manga.source)?.let { source -> + downloadManager.deleteChapters(values.map { it.toDbChapter() }, manga, source) + } + } +} 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 281849d66..0d1954833 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 @@ -9,9 +9,9 @@ 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.interactor.UpdateChapter import eu.kanade.domain.chapter.model.Chapter -import eu.kanade.domain.chapter.model.ChapterUpdate import eu.kanade.domain.chapter.model.toDbChapter import eu.kanade.domain.manga.interactor.GetLibraryManga import eu.kanade.domain.manga.interactor.GetMergedMangaById @@ -78,6 +78,7 @@ class LibraryPresenter( private val getTracks: GetTracks = Injekt.get(), private val getCategories: GetCategories = Injekt.get(), private val getChapterByMangaId: GetChapterByMangaId = Injekt.get(), + private val setReadStatus: SetReadStatus = Injekt.get(), private val updateChapter: UpdateChapter = Injekt.get(), private val updateManga: UpdateManga = Injekt.get(), private val setMangaCategories: SetMangaCategories = Injekt.get(), @@ -753,40 +754,14 @@ class LibraryPresenter( fun markReadStatus(mangas: List, read: Boolean) { mangas.forEach { manga -> launchIO { - val chapters = if (manga.source == MERGED_SOURCE_ID) getMergedChaptersByMangaId.await(manga.id) else getChapterByMangaId.await(manga.id) - - val toUpdate = chapters - .map { chapter -> - ChapterUpdate( - read = read, - lastPageRead = if (read) 0 else null, - id = chapter.id, - ) - } - updateChapter.awaitAll(toUpdate) - - if (read && preferences.removeAfterMarkedAsRead()) { - deleteChapters(manga, chapters) - } + setReadStatus.await( + manga = manga, + read = read, + ) } } } - private fun deleteChapters(manga: Manga, chapters: List) { - sourceManager.get(manga.source)?.let { source -> - // SY --> - if (source is MergedSource) { - val mergedMangas = runBlocking { getMergedMangaById.await(manga.id) } - val sources = mergedMangas.distinctBy { it.source }.map { sourceManager.getOrStub(it.source) } - chapters.groupBy { it.mangaId }.forEach { (mangaId, chapters) -> - val mergedManga = mergedMangas.firstOrNull { it.id == mangaId } ?: return@forEach - val mergedMangaSource = sources.firstOrNull { it.id == mergedManga.source } ?: return@forEach - downloadManager.deleteChapters(chapters.map { it.toDbChapter() }, mergedManga, mergedMangaSource) - } - } else /* SY <-- */ downloadManager.deleteChapters(chapters.map { it.toDbChapter() }, manga, source) - } - } - /** * Remove the selected manga. * 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 be91b1f39..cb29b1f83 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 @@ -7,6 +7,7 @@ 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.GetMergedChapterByMangaId +import eu.kanade.domain.chapter.interactor.SetReadStatus import eu.kanade.domain.chapter.interactor.SyncChaptersWithSource import eu.kanade.domain.chapter.interactor.SyncChaptersWithTrackServiceTwoWay import eu.kanade.domain.chapter.interactor.UpdateChapter @@ -139,6 +140,7 @@ class MangaPresenter( // SY <-- private val getDuplicateLibraryManga: GetDuplicateLibraryManga = Injekt.get(), private val setMangaChapterFlags: SetMangaChapterFlags = Injekt.get(), + private val setReadStatus: SetReadStatus = Injekt.get(), private val updateChapter: UpdateChapter = Injekt.get(), private val updateManga: UpdateManga = Injekt.get(), private val syncChaptersWithSource: SyncChaptersWithSource = Injekt.get(), @@ -937,13 +939,10 @@ class MangaPresenter( */ fun markChaptersRead(chapters: List, read: Boolean) { presenterScope.launchIO { - val modified = chapters.filterNot { it.read == read } - modified - .map { ChapterUpdate(id = it.id, read = read) } - .let { updateChapter.awaitAll(it) } - if (read && preferences.removeAfterMarkedAsRead()) { - deleteChapters(modified) - } + setReadStatus.await( + read = read, + values = chapters.toTypedArray(), + ) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/recent/updates/UpdatesController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/recent/updates/UpdatesController.kt index a76a192a0..3636c6983 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/recent/updates/UpdatesController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/recent/updates/UpdatesController.kt @@ -249,9 +249,6 @@ class UpdatesController : */ private fun markAsRead(chapters: List) { presenter.markChapterRead(chapters, true) - if (presenter.preferences.removeAfterMarkedAsRead()) { - deleteChapters(chapters) - } destroyActionModeIfNeeded() } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/recent/updates/UpdatesPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/recent/updates/UpdatesPresenter.kt index 79968240f..ce56e45dc 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/recent/updates/UpdatesPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/recent/updates/UpdatesPresenter.kt @@ -3,6 +3,7 @@ package eu.kanade.tachiyomi.ui.recent.updates import android.os.Bundle import eu.kanade.data.DatabaseHandler import eu.kanade.data.manga.mangaChapterMapper +import eu.kanade.domain.chapter.interactor.SetReadStatus import eu.kanade.domain.chapter.interactor.UpdateChapter import eu.kanade.domain.chapter.model.Chapter import eu.kanade.domain.chapter.model.ChapterUpdate @@ -40,6 +41,7 @@ class UpdatesPresenter : BasePresenter() { private val handler: DatabaseHandler by injectLazy() private val updateChapter: UpdateChapter by injectLazy() + private val setReadStatus: SetReadStatus by injectLazy() private val relativeTime: Int = preferences.relativeTime().get() private val dateFormat: DateFormat = preferences.dateFormat() @@ -167,14 +169,12 @@ class UpdatesPresenter : BasePresenter() { */ fun markChapterRead(items: List, read: Boolean) { presenterScope.launchIO { - val toUpdate = items.map { - ChapterUpdate( - read = read, - lastPageRead = if (!read) 0 else null, - id = it.chapter.id, - ) - } - updateChapter.awaitAll(toUpdate) + setReadStatus.await( + read = read, + values = items + .map { it.chapter } + .toTypedArray(), + ) } }