From 5159eabc5dfd77dd7e4a480c1982bd1d2e5fbb92 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 --- .../java/eu/kanade/domain/DomainModule.kt | 5 ++ .../chapter/interactor/SetReadStatus.kt | 86 +++++++++++++++++++ .../download/interactor/DeleteDownload.kt | 21 +++++ .../tachiyomi/ui/library/LibraryPresenter.kt | 29 ++----- .../tachiyomi/ui/manga/MangaPresenter.kt | 13 ++- .../ui/recent/updates/UpdatesController.kt | 3 - .../ui/recent/updates/UpdatesPresenter.kt | 16 ++-- 7 files changed, 132 insertions(+), 41 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 804bb6b493..7615d99992 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()) } 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 0000000000..2264f234b2 --- /dev/null +++ b/app/src/main/java/eu/kanade/domain/chapter/interactor/SetReadStatus.kt @@ -0,0 +1,86 @@ +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.util.system.logcat +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 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(), + ) + } + + suspend fun await(manga: Manga, read: Boolean) = + await(manga.id, read) + + 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 0000000000..546b7232c2 --- /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 9feb5461b1..8e9e3b7db9 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt @@ -8,9 +8,8 @@ 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.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.UpdateManga @@ -65,6 +64,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(), @@ -533,31 +533,14 @@ class LibraryPresenter( fun markReadStatus(mangas: List, read: Boolean) { mangas.forEach { manga -> launchIO { - val chapters = 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 -> - 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 64da8563fa..d5bb94a303 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 @@ -5,6 +5,7 @@ import androidx.compose.runtime.Immutable 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.SetReadStatus import eu.kanade.domain.chapter.interactor.SyncChaptersWithSource import eu.kanade.domain.chapter.interactor.SyncChaptersWithTrackServiceTwoWay import eu.kanade.domain.chapter.interactor.UpdateChapter @@ -79,6 +80,7 @@ class MangaPresenter( private val getMangaAndChapters: GetMangaWithChapters = Injekt.get(), 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(), @@ -525,13 +527,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 a76a192a03..3636c69830 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 3f6d70cf67..530aae9d90 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(), + ) } }