diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadManager.kt b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadManager.kt index fc3297a5c2..26bb0404a7 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadManager.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadManager.kt @@ -12,9 +12,6 @@ import eu.kanade.tachiyomi.source.SourceManager import eu.kanade.tachiyomi.source.model.Page import eu.kanade.tachiyomi.util.system.ImageUtil import eu.kanade.tachiyomi.util.system.launchIO -import kotlinx.coroutines.DelicateCoroutinesApi -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.asFlow import kotlinx.coroutines.flow.drop @@ -23,7 +20,6 @@ import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.merge import kotlinx.coroutines.flow.onStart -import kotlinx.coroutines.launch import uy.kohesive.injekt.injectLazy import yokai.domain.download.DownloadPreferences import yokai.i18n.MR @@ -242,24 +238,15 @@ class DownloadManager(val context: Context) { * @param manga the manga of the chapters. * @param source the source of the chapters. */ - @OptIn(DelicateCoroutinesApi::class) fun deleteChapters(chapters: List, manga: Manga, source: Source, force: Boolean = false) { - val filteredChapters = if (force) chapters else getChaptersToDelete(chapters, manga) - GlobalScope.launch(Dispatchers.IO) { - val wasPaused = isPaused() + launchIO { + val filteredChapters = if (force) chapters else getChaptersToDelete(chapters, manga) if (filteredChapters.isEmpty()) { - return@launch + return@launchIO } - downloader.pause() - downloader.removeFromQueue(filteredChapters) - if (!wasPaused && queueState.value.isNotEmpty()) { - downloader.start() - } else if (queueState.value.isEmpty() && DownloadJob.isRunning(context)) { - DownloadJob.stop(context) - } else if (queueState.value.isEmpty()) { - downloader.stop() - } - downloader.removeFromQueue(filteredChapters) + + removeFromDownloadQueue(filteredChapters) + val chapterDirs = provider.findChapterDirs(filteredChapters, manga, source) + provider.findTempChapterDirs( filteredChapters, @@ -268,12 +255,30 @@ class DownloadManager(val context: Context) { ) chapterDirs.forEach { it.delete() } cache.removeChapters(filteredChapters, manga) + if (cache.getDownloadCount(manga, true) == 0) { // Delete manga directory if empty chapterDirs.firstOrNull()?.parentFile?.delete() } } } + private fun removeFromDownloadQueue(chapters: List) { + val wasRunning = downloader.isRunning + if (wasRunning) { + downloader.pause() + } + + downloader.removeFromQueue(chapters) + + if (wasRunning) { + if (queueState.value.isEmpty()) { + downloader.stop() + } else if (queueState.value.isNotEmpty()) { + downloader.start() + } + } + } + /** * return the list of all manga folders */ diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/download/Downloader.kt b/app/src/main/java/eu/kanade/tachiyomi/data/download/Downloader.kt index d869ad784a..0f2444eb8d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/download/Downloader.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/download/Downloader.kt @@ -700,7 +700,7 @@ class Downloader( } fun removeFromQueue(chapters: List) { - chapters.forEach(::removeFromQueue) + removeFromQueueIf { it.chapter.id in chapters.map { it.id } } } fun removeFromQueue(manga: Manga) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/download/model/Download.kt b/app/src/main/java/eu/kanade/tachiyomi/data/download/model/Download.kt index 183db5b1fc..dc5d0abbf3 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/download/model/Download.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/download/model/Download.kt @@ -45,7 +45,7 @@ class Download(val source: HttpSource, val manga: Manga, val chapter: Chapter) { } val progressFlows = pages!!.map(Page::progressFlow) - emitAll(combine(progressFlows) { it.average().toInt() }) + emitAll(combine(progressFlows) { it.average().roundToInt() }) } .distinctUntilChanged() .debounce(50) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadBottomPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadBottomPresenter.kt index 0ee0651ed7..3e940d16bb 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadBottomPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadBottomPresenter.kt @@ -37,7 +37,7 @@ class DownloadBottomPresenter : BaseCoroutinePresenter(), downloadManager.statusFlow().collect(::onStatusChange) } presenterScope.launchUI { - downloadManager.progressFlow().collect { view?.onUpdateDownloadedPages(it) } + downloadManager.progressFlow().collect(::onPageProgressUpdate) } } @@ -115,7 +115,6 @@ class DownloadBottomPresenter : BaseCoroutinePresenter(), } override fun onPageProgressUpdate(download: Download) { - super.onPageProgressUpdate(download) view?.onUpdateDownloadedPages(download) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadHolder.kt index 27c42fdb2b..f7e1ce7a5d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadHolder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadHolder.kt @@ -68,7 +68,7 @@ class DownloadHolder(private val view: View, val adapter: DownloadAdapter) : if (binding.downloadProgress.max == 1) { binding.downloadProgress.max = pages.size * 100 } - binding.downloadProgress.progress = download.pageProgress + binding.downloadProgress.setProgressCompat(download.pageProgress, true) } /** diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaDetailsPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaDetailsPresenter.kt index 33ebf4e332..67ed320378 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaDetailsPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaDetailsPresenter.kt @@ -60,6 +60,7 @@ import eu.kanade.tachiyomi.util.manga.MangaUtil import eu.kanade.tachiyomi.util.shouldDownloadNewChapters import eu.kanade.tachiyomi.util.storage.DiskUtil import eu.kanade.tachiyomi.util.system.ImageUtil +import eu.kanade.tachiyomi.util.system.e import eu.kanade.tachiyomi.util.system.launchIO import eu.kanade.tachiyomi.util.system.launchNonCancellableIO import eu.kanade.tachiyomi.util.system.launchNow @@ -75,6 +76,7 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job import kotlinx.coroutines.async import kotlinx.coroutines.awaitAll +import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.launchIn @@ -188,17 +190,23 @@ class MangaDetailsPresenter( syncData() presenterScope.launchUI { - downloadManager.statusFlow().collect(::onStatusChange) + downloadManager.statusFlow() + .filter { it.manga.id == mangaId } + .catch { error -> Logger.e(error) } + .collect(::onStatusChange) } presenterScope.launchUI { - downloadManager.progressFlow().collect(::onProgressUpdate) + downloadManager.progressFlow() + .filter { it.manga.id == mangaId } + .catch { error -> Logger.e(error) } + .collect(::onQueueUpdate) } presenterScope.launchIO { downloadManager.queueState.collectLatest(::onQueueUpdate) } runBlocking { - tracks = getTrack.awaitAllByMangaId(manga.id!!) + tracks = getTrack.awaitAllByMangaId(mangaId) } } @@ -287,7 +295,7 @@ class MangaDetailsPresenter( for (chapter in chapters) { if (downloadManager.isChapterDownloaded(chapter, manga)) { chapter.status = Download.State.DOWNLOADED - } else if (downloadManager.hasQueue()) { + } else if (queue.isNotEmpty()) { chapter.status = queue.find { it.chapter.id == chapter.id } ?.status ?: Download.State.default } @@ -380,14 +388,15 @@ class MangaDetailsPresenter( * @param chapter the chapter to delete. */ fun deleteChapter(chapter: ChapterItem) { - downloadManager.deleteChapters(listOf(chapter), manga, source, true) this.chapters.find { it.id == chapter.id }?.apply { if (chapter.chapter.bookmark && !preferences.removeBookmarkedChapters().get()) return@apply - status = Download.State.QUEUE + status = Download.State.NOT_DOWNLOADED download = null } view?.updateChapters(this.chapters) + + downloadManager.deleteChapters(listOf(chapter), manga, source, true) } /** @@ -395,22 +404,21 @@ class MangaDetailsPresenter( * @param chapters the list of chapters to delete. */ fun deleteChapters(chapters: List, update: Boolean = true, isEverything: Boolean = false) { - launchIO { - if (isEverything) { - downloadManager.deleteManga(manga, source) - } else { - downloadManager.deleteChapters(chapters, manga, source) - } - } chapters.forEach { chapter -> this.chapters.find { it.id == chapter.id }?.apply { if (chapter.chapter.bookmark && !preferences.removeBookmarkedChapters().get() && !isEverything) return@apply - status = Download.State.QUEUE + status = Download.State.NOT_DOWNLOADED download = null } } if (update) view?.updateChapters(this.chapters) + + if (isEverything) { + downloadManager.deleteManga(manga, source) + } else { + downloadManager.deleteChapters(chapters, manga, source) + } } suspend fun refreshMangaFromDb(): Manga { @@ -1143,6 +1151,12 @@ class MangaDetailsPresenter( return if (date <= 0L) null else date } + override fun onStatusChange(download: Download) { + super.onStatusChange(download) + chapters.find { it.id == download.chapter.id }?.status = download.status + onPageProgressUpdate(download) + } + private suspend fun onQueueUpdate(queue: List) = withIOContext { getChapters(queue) withUIContext { @@ -1151,12 +1165,14 @@ class MangaDetailsPresenter( } override fun onQueueUpdate(download: Download) { - presenterScope.launchIO { - onQueueUpdate(downloadManager.queueState.value) - } + // already handled by onStatusChange } override fun onProgressUpdate(download: Download) { + // already handled by onStatusChange + } + + override fun onPageProgressUpdate(download: Download) { chapters.find { it.id == download.chapter.id }?.download = download view?.updateChapterDownload(download) }