mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-10-31 14:27:57 +01:00 
			
		
		
		
	Minor changes to fix a possible crash in the downloads view
This commit is contained in:
		| @@ -10,7 +10,13 @@ import eu.kanade.tachiyomi.ui.main.MainActivity | ||||
| import eu.kanade.tachiyomi.widget.NpaLinearLayoutManager | ||||
| import kotlinx.android.synthetic.main.fragment_download_queue.* | ||||
| import nucleus.factory.RequiresPresenter | ||||
| import rx.Observable | ||||
| import rx.Subscription | ||||
| import rx.android.schedulers.AndroidSchedulers | ||||
| import rx.schedulers.Schedulers | ||||
| import rx.subscriptions.CompositeSubscription | ||||
| import java.util.* | ||||
| import java.util.concurrent.TimeUnit | ||||
|  | ||||
| /** | ||||
|  * Fragment that shows the currently active downloads. | ||||
| @@ -40,9 +46,14 @@ class DownloadFragment : BaseRxFragment<DownloadPresenter>() { | ||||
|     private var clearButton: MenuItem? = null | ||||
|  | ||||
|     /** | ||||
|      * Subscription to know if the download queue is running. | ||||
|      * Subscription list to be cleared during [onPause]. | ||||
|      */ | ||||
|     private var queueStatusSubscription: Subscription? = null | ||||
|     private val resumeSubscriptions by lazy { CompositeSubscription() } | ||||
|  | ||||
|     /** | ||||
|      * Map of subscriptions for active downloads. | ||||
|      */ | ||||
|     private val progressSubscriptions by lazy { HashMap<Download, Subscription>() } | ||||
|  | ||||
|     /** | ||||
|      * Whether the download queue is running or not. | ||||
| @@ -66,8 +77,7 @@ class DownloadFragment : BaseRxFragment<DownloadPresenter>() { | ||||
|         setHasOptionsMenu(true) | ||||
|     } | ||||
|  | ||||
|     override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, | ||||
|                               savedState: Bundle?): View? { | ||||
|     override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedState: Bundle?): View { | ||||
|         return inflater.inflate(R.layout.fragment_download_queue, container, false) | ||||
|     } | ||||
|  | ||||
| @@ -123,15 +133,91 @@ class DownloadFragment : BaseRxFragment<DownloadPresenter>() { | ||||
|  | ||||
|     override fun onResume() { | ||||
|         super.onResume() | ||||
|         queueStatusSubscription = presenter.downloadManager.runningSubject | ||||
|         presenter.downloadManager.runningSubject | ||||
|                 .observeOn(AndroidSchedulers.mainThread()) | ||||
|                 .subscribe { onQueueStatusChange(it) } | ||||
|                 .apply { resumeSubscriptions.add(this) } | ||||
|  | ||||
|         presenter.getStatusObservable() | ||||
|                 .observeOn(AndroidSchedulers.mainThread()) | ||||
|                 .subscribe { onStatusChange(it) } | ||||
|                 .apply { resumeSubscriptions.add(this) } | ||||
|  | ||||
|         presenter.getProgressObservable() | ||||
|                 .observeOn(AndroidSchedulers.mainThread()) | ||||
|                 .subscribe { onUpdateDownloadedPages(it) } | ||||
|                 .apply { resumeSubscriptions.add(this) } | ||||
|     } | ||||
|  | ||||
|     override fun onPause() { | ||||
|         queueStatusSubscription?.unsubscribe() | ||||
|         for (subscription in progressSubscriptions.values) { | ||||
|             subscription.unsubscribe() | ||||
|         } | ||||
|         progressSubscriptions.clear() | ||||
|         resumeSubscriptions.clear() | ||||
|         super.onPause() | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Called when the status of a download changes. | ||||
|      * | ||||
|      * @param download the download whose status has changed. | ||||
|      */ | ||||
|     private fun onStatusChange(download: Download) { | ||||
|         when (download.status) { | ||||
|             Download.DOWNLOADING -> { | ||||
|                 observeProgress(download) | ||||
|                 // Initial update of the downloaded pages | ||||
|                 onUpdateDownloadedPages(download) | ||||
|             } | ||||
|             Download.DOWNLOADED -> { | ||||
|                 unsubscribeProgress(download) | ||||
|                 onUpdateProgress(download) | ||||
|                 onUpdateDownloadedPages(download) | ||||
|             } | ||||
|             Download.ERROR -> unsubscribeProgress(download) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Observe the progress of a download and notify the view. | ||||
|      * | ||||
|      * @param download the download to observe its progress. | ||||
|      */ | ||||
|     private fun observeProgress(download: Download) { | ||||
|         val subscription = Observable.interval(50, TimeUnit.MILLISECONDS, Schedulers.newThread()) | ||||
|                 // Get the sum of percentages for all the pages. | ||||
|                 .flatMap { | ||||
|                     Observable.from(download.pages) | ||||
|                             .map { it.progress } | ||||
|                             .reduce { x, y -> x + y } | ||||
|                 } | ||||
|                 // Keep only the latest emission to avoid backpressure. | ||||
|                 .onBackpressureLatest() | ||||
|                 .observeOn(AndroidSchedulers.mainThread()) | ||||
|                 .subscribe { progress -> | ||||
|                     // Update the view only if the progress has changed. | ||||
|                     if (download.totalProgress != progress) { | ||||
|                         download.totalProgress = progress | ||||
|                         onUpdateProgress(download) | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|         // Avoid leaking subscriptions | ||||
|         progressSubscriptions.remove(download)?.unsubscribe() | ||||
|  | ||||
|         progressSubscriptions.put(download, subscription) | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Unsubscribes the given download from the progress subscriptions. | ||||
|      * | ||||
|      * @param download the download to unsubscribe. | ||||
|      */ | ||||
|     private fun unsubscribeProgress(download: Download) { | ||||
|         progressSubscriptions.remove(download)?.unsubscribe() | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Called when the queue's status has changed. Updates the visibility of the buttons. | ||||
|      * | ||||
| @@ -157,16 +243,16 @@ class DownloadFragment : BaseRxFragment<DownloadPresenter>() { | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Called from the presenter when the status of a download changes. | ||||
|      * Called when the progress of a download changes. | ||||
|      * | ||||
|      * @param download the download whose status has changed. | ||||
|      * @param download the download whose progress has changed. | ||||
|      */ | ||||
|     fun onUpdateProgress(download: Download) { | ||||
|         getHolder(download)?.notifyProgress() | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Called from the presenter when a page of a download is downloaded. | ||||
|      * Called when a page of a download is downloaded. | ||||
|      * | ||||
|      * @param download the download whose page has been downloaded. | ||||
|      */ | ||||
|   | ||||
| @@ -10,7 +10,7 @@ import kotlinx.android.synthetic.main.item_download.view.* | ||||
|  * All the elements from the layout file "item_download" are available in this class. | ||||
|  * | ||||
|  * @param view the inflated view for this holder. | ||||
|  * @constructor creates a new library holder. | ||||
|  * @constructor creates a new download holder. | ||||
|  */ | ||||
| class DownloadHolder(private val view: View) : RecyclerView.ViewHolder(view) { | ||||
|  | ||||
|   | ||||
| @@ -6,12 +6,7 @@ import eu.kanade.tachiyomi.data.download.model.Download | ||||
| import eu.kanade.tachiyomi.data.download.model.DownloadQueue | ||||
| import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter | ||||
| import rx.Observable | ||||
| import rx.Subscription | ||||
| import rx.android.schedulers.AndroidSchedulers | ||||
| import rx.schedulers.Schedulers | ||||
| import timber.log.Timber | ||||
| import java.util.* | ||||
| import java.util.concurrent.TimeUnit | ||||
| import javax.inject.Inject | ||||
|  | ||||
| /** | ||||
| @@ -19,6 +14,13 @@ import javax.inject.Inject | ||||
|  */ | ||||
| class DownloadPresenter : BasePresenter<DownloadFragment>() { | ||||
|  | ||||
|     companion object { | ||||
|         /** | ||||
|          * Id of the restartable that returns the download queue. | ||||
|          */ | ||||
|         const val GET_DOWNLOAD_QUEUE = 1 | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Download manager. | ||||
|      */ | ||||
| @@ -30,28 +32,6 @@ class DownloadPresenter : BasePresenter<DownloadFragment>() { | ||||
|     val downloadQueue: DownloadQueue | ||||
|         get() = downloadManager.queue | ||||
|  | ||||
|     /** | ||||
|      * Map of subscriptions for active downloads. | ||||
|      */ | ||||
|     private val progressSubscriptions by lazy { HashMap<Download, Subscription>() } | ||||
|  | ||||
|     /** | ||||
|      * Subscription for status changes on downloads. | ||||
|      */ | ||||
|     private var statusSubscription: Subscription? = null | ||||
|  | ||||
|     /** | ||||
|      * Subscription for downloaded pages for active downloads. | ||||
|      */ | ||||
|     private var pageProgressSubscription: Subscription? = null | ||||
|  | ||||
|     companion object { | ||||
|         /** | ||||
|          * Id of the restartable that returns the download queue. | ||||
|          */ | ||||
|         const val GET_DOWNLOAD_QUEUE = 1 | ||||
|     } | ||||
|  | ||||
|     override fun onCreate(savedState: Bundle?) { | ||||
|         super.onCreate(savedState) | ||||
|  | ||||
| @@ -65,102 +45,14 @@ class DownloadPresenter : BasePresenter<DownloadFragment>() { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     override fun onTakeView(view: DownloadFragment) { | ||||
|         super.onTakeView(view) | ||||
|  | ||||
|         statusSubscription = downloadQueue.getStatusObservable() | ||||
|     fun getStatusObservable(): Observable<Download> { | ||||
|         return downloadQueue.getStatusObservable() | ||||
|                 .startWith(downloadQueue.getActiveDownloads()) | ||||
|                 .observeOn(AndroidSchedulers.mainThread()) | ||||
|                 .subscribe { processStatus(it, view) } | ||||
|     } | ||||
|  | ||||
|         add(statusSubscription) | ||||
|  | ||||
|         pageProgressSubscription = downloadQueue.getProgressObservable() | ||||
|     fun getProgressObservable(): Observable<Download> { | ||||
|         return downloadQueue.getProgressObservable() | ||||
|                 .onBackpressureBuffer() | ||||
|                 .observeOn(AndroidSchedulers.mainThread()) | ||||
|                 .subscribe { view.onUpdateDownloadedPages(it) } | ||||
|  | ||||
|         add(pageProgressSubscription) | ||||
|     } | ||||
|  | ||||
|     override fun onDropView() { | ||||
|         destroySubscriptions() | ||||
|         super.onDropView() | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Process the status of a download when its status has changed and notify the view. | ||||
|      * | ||||
|      * @param download the download whose status has changed. | ||||
|      * @param view the view. | ||||
|      */ | ||||
|     private fun processStatus(download: Download, view: DownloadFragment) { | ||||
|         when (download.status) { | ||||
|             Download.DOWNLOADING -> { | ||||
|                 observeProgress(download, view) | ||||
|                 // Initial update of the downloaded pages | ||||
|                 view.onUpdateDownloadedPages(download) | ||||
|             } | ||||
|             Download.DOWNLOADED -> { | ||||
|                 unsubscribeProgress(download) | ||||
|                 view.onUpdateProgress(download) | ||||
|                 view.onUpdateDownloadedPages(download) | ||||
|             } | ||||
|             Download.ERROR -> unsubscribeProgress(download) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Observe the progress of a download and notify the view. | ||||
|      * | ||||
|      * @param download the download to observe its progress. | ||||
|      * @param view the view. | ||||
|      */ | ||||
|     private fun observeProgress(download: Download, view: DownloadFragment) { | ||||
|         val subscription = Observable.interval(50, TimeUnit.MILLISECONDS, Schedulers.newThread()) | ||||
|                 // Get the sum of percentages for all the pages. | ||||
|                 .flatMap { | ||||
|                     Observable.from(download.pages) | ||||
|                             .map { it.progress } | ||||
|                             .reduce { x, y -> x + y } | ||||
|                 } | ||||
|                 // Keep only the latest emission to avoid backpressure. | ||||
|                 .onBackpressureLatest() | ||||
|                 .observeOn(AndroidSchedulers.mainThread()) | ||||
|                 .subscribe { progress -> | ||||
|                     // Update the view only if the progress has changed. | ||||
|                     if (download.totalProgress != progress) { | ||||
|                         download.totalProgress = progress | ||||
|                         view.onUpdateProgress(download) | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|         // Avoid leaking subscriptions | ||||
|         progressSubscriptions.remove(download)?.unsubscribe() | ||||
|  | ||||
|         progressSubscriptions.put(download, subscription) | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Unsubscribes the given download from the progress subscriptions. | ||||
|      * | ||||
|      * @param download the download to unsubscribe. | ||||
|      */ | ||||
|     private fun unsubscribeProgress(download: Download) { | ||||
|         progressSubscriptions.remove(download)?.unsubscribe() | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Destroys all the subscriptions of the presenter. | ||||
|      */ | ||||
|     private fun destroySubscriptions() { | ||||
|         for (subscription in progressSubscriptions.values) { | ||||
|             subscription.unsubscribe() | ||||
|         } | ||||
|         progressSubscriptions.clear() | ||||
|  | ||||
|         remove(pageProgressSubscription) | ||||
|         remove(statusSubscription) | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|   | ||||
		Reference in New Issue
	
	Block a user