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 3c7dba520..67eb510bf 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 @@ -22,6 +22,7 @@ import kotlinx.coroutines.CancellationException import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job +import kotlinx.coroutines.NonCancellable import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.async import kotlinx.coroutines.delay @@ -41,6 +42,7 @@ import kotlinx.coroutines.flow.transformLatest import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import kotlinx.coroutines.supervisorScope +import kotlinx.coroutines.withContext import logcat.LogPriority import mihon.core.archive.ZipWriter import nl.adaptivity.xmlutil.serialization.XML @@ -91,6 +93,8 @@ class Downloader( val queueState = _queueState.asStateFlow() private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO) + + // Kept when canceled, so the next job can wait for it to finish private var downloaderJob: Job? = null /** @@ -183,7 +187,12 @@ class Downloader( private fun launchDownloaderJob() { if (isRunning) return + val previousJob = downloaderJob downloaderJob = scope.launch { + // Page writes block, so a canceled job can still be writing the pages this one would start on. Not + // cancelable, so a job canceled while waiting still finishes after the one before it. + withContext(NonCancellable) { previousJob?.join() } + val activeDownloadsFlow = combine( queueState, downloadPreferences.parallelSourceLimit.changes(), @@ -253,7 +262,6 @@ class Downloader( */ private fun cancelDownloaderJob() { downloaderJob?.cancel() - downloaderJob = null } /**