Replace RxJava in DownloadQueueScreenModel (#8872)

This commit is contained in:
Two-Ai 2023-01-09 23:08:04 -05:00 committed by GitHub
parent 46774771ec
commit 2245658363
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 32 additions and 35 deletions

View file

@ -18,9 +18,8 @@ data class Download(
var pages: List<Page>? = null, var pages: List<Page>? = null,
) { ) {
@Volatile val totalProgress: Int
@Transient get() = pages?.sumOf(Page::progress) ?: 0
var totalProgress: Int = 0
@Volatile @Volatile
@Transient @Transient

View file

@ -11,19 +11,21 @@ import eu.kanade.tachiyomi.data.download.model.Download
import eu.kanade.tachiyomi.databinding.DownloadListBinding import eu.kanade.tachiyomi.databinding.DownloadListBinding
import eu.kanade.tachiyomi.source.model.Page import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.util.system.logcat import eu.kanade.tachiyomi.util.system.logcat
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.update import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import logcat.LogPriority import logcat.LogPriority
import rx.Observable
import rx.Subscription
import rx.android.schedulers.AndroidSchedulers
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import java.util.concurrent.TimeUnit
class DownloadQueueScreenModel( class DownloadQueueScreenModel(
private val downloadManager: DownloadManager = Injekt.get(), private val downloadManager: DownloadManager = Injekt.get(),
@ -40,9 +42,9 @@ class DownloadQueueScreenModel(
var adapter: DownloadAdapter? = null var adapter: DownloadAdapter? = null
/** /**
* Map of subscriptions for active downloads. * Map of jobs for active downloads.
*/ */
val progressSubscriptions by lazy { mutableMapOf<Download, Subscription>() } private val progressJobs = mutableMapOf<Download, Job>()
val listener = object : DownloadAdapter.DownloadItemListener { val listener = object : DownloadAdapter.DownloadItemListener {
/** /**
@ -130,10 +132,10 @@ class DownloadQueueScreenModel(
} }
override fun onDispose() { override fun onDispose() {
for (subscription in progressSubscriptions.values) { for (job in progressJobs.values) {
subscription.unsubscribe() job.cancel()
} }
progressSubscriptions.clear() progressJobs.clear()
adapter = null adapter = null
} }
@ -180,16 +182,16 @@ class DownloadQueueScreenModel(
fun onStatusChange(download: Download) { fun onStatusChange(download: Download) {
when (download.status) { when (download.status) {
Download.State.DOWNLOADING -> { Download.State.DOWNLOADING -> {
observeProgress(download) launchProgressJob(download)
// Initial update of the downloaded pages // Initial update of the downloaded pages
onUpdateDownloadedPages(download) onUpdateDownloadedPages(download)
} }
Download.State.DOWNLOADED -> { Download.State.DOWNLOADED -> {
unsubscribeProgress(download) cancelProgressJob(download)
onUpdateProgress(download) onUpdateProgress(download)
onUpdateDownloadedPages(download) onUpdateDownloadedPages(download)
} }
Download.State.ERROR -> unsubscribeProgress(download) Download.State.ERROR -> cancelProgressJob(download)
else -> { else -> {
/* unused */ /* unused */
} }
@ -201,29 +203,25 @@ class DownloadQueueScreenModel(
* *
* @param download the download to observe its progress. * @param download the download to observe its progress.
*/ */
private fun observeProgress(download: Download) { private fun launchProgressJob(download: Download) {
val subscription = Observable.interval(50, TimeUnit.MILLISECONDS) val job = coroutineScope.launch {
// Get the sum of percentages for all the pages. while (download.pages == null) {
.flatMap { delay(50)
Observable.from(download.pages)
.map(Page::progress)
.reduce { x, y -> x + y }
} }
// Keep only the latest emission to avoid backpressure.
.onBackpressureLatest() val progressFlows = download.pages!!.map(Page::progressFlow)
.observeOn(AndroidSchedulers.mainThread()) combine(progressFlows, Array<Int>::sum)
.subscribe { progress -> .distinctUntilChanged()
// Update the view only if the progress has changed. .debounce(50)
if (download.totalProgress != progress) { .collectLatest {
download.totalProgress = progress
onUpdateProgress(download) onUpdateProgress(download)
} }
} }
// Avoid leaking subscriptions // Avoid leaking jobs
progressSubscriptions.remove(download)?.unsubscribe() progressJobs.remove(download)?.cancel()
progressSubscriptions[download] = subscription progressJobs[download] = job
} }
/** /**
@ -231,8 +229,8 @@ class DownloadQueueScreenModel(
* *
* @param download the download to unsubscribe. * @param download the download to unsubscribe.
*/ */
private fun unsubscribeProgress(download: Download) { private fun cancelProgressJob(download: Download) {
progressSubscriptions.remove(download)?.unsubscribe() progressJobs.remove(download)?.cancel()
} }
/** /**