mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-11-04 16:18:55 +01:00 
			
		
		
		
	Downloads with conductor. Remove flexible adapter 4 dependency and unused classes.
This commit is contained in:
		@@ -1,39 +0,0 @@
 | 
			
		||||
package eu.kanade.tachiyomi.ui.base.adapter
 | 
			
		||||
 | 
			
		||||
import android.support.v7.widget.RecyclerView
 | 
			
		||||
import android.view.View
 | 
			
		||||
 | 
			
		||||
import eu.davidea.flexibleadapter4.FlexibleAdapter
 | 
			
		||||
 | 
			
		||||
abstract class FlexibleViewHolder(view: View,
 | 
			
		||||
                                  private val adapter: FlexibleAdapter<*, *>,
 | 
			
		||||
                                  private val itemClickListener: FlexibleViewHolder.OnListItemClickListener) :
 | 
			
		||||
        RecyclerView.ViewHolder(view), View.OnClickListener, View.OnLongClickListener {
 | 
			
		||||
 | 
			
		||||
    init {
 | 
			
		||||
        view.setOnClickListener(this)
 | 
			
		||||
        view.setOnLongClickListener(this)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onClick(view: View) {
 | 
			
		||||
        if (itemClickListener.onListItemClick(adapterPosition)) {
 | 
			
		||||
            toggleActivation()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onLongClick(view: View): Boolean {
 | 
			
		||||
        itemClickListener.onListItemLongClick(adapterPosition)
 | 
			
		||||
        toggleActivation()
 | 
			
		||||
        return true
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun toggleActivation() {
 | 
			
		||||
        itemView.isActivated = adapter.isSelected(adapterPosition)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    interface OnListItemClickListener {
 | 
			
		||||
        fun onListItemClick(position: Int): Boolean
 | 
			
		||||
        fun onListItemLongClick(position: Int)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,41 +0,0 @@
 | 
			
		||||
package eu.kanade.tachiyomi.ui.base.adapter
 | 
			
		||||
 | 
			
		||||
import android.support.v4.app.Fragment
 | 
			
		||||
import android.support.v4.app.FragmentManager
 | 
			
		||||
import android.support.v4.app.FragmentStatePagerAdapter
 | 
			
		||||
import android.util.SparseArray
 | 
			
		||||
import android.view.ViewGroup
 | 
			
		||||
import java.util.*
 | 
			
		||||
 | 
			
		||||
abstract class SmartFragmentStatePagerAdapter(fragmentManager: FragmentManager) :
 | 
			
		||||
        FragmentStatePagerAdapter(fragmentManager) {
 | 
			
		||||
    // Sparse array to keep track of registered fragments in memory
 | 
			
		||||
    private val registeredFragments = SparseArray<Fragment>()
 | 
			
		||||
 | 
			
		||||
    // Register the fragment when the item is instantiated
 | 
			
		||||
    override fun instantiateItem(container: ViewGroup, position: Int): Any {
 | 
			
		||||
        val fragment = super.instantiateItem(container, position) as Fragment
 | 
			
		||||
        registeredFragments.put(position, fragment)
 | 
			
		||||
        return fragment
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Unregister when the item is inactive
 | 
			
		||||
    override fun destroyItem(container: ViewGroup?, position: Int, `object`: Any) {
 | 
			
		||||
        registeredFragments.remove(position)
 | 
			
		||||
        super.destroyItem(container, position, `object`)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Returns the fragment for the position (if instantiated)
 | 
			
		||||
    fun getRegisteredFragment(position: Int): Fragment {
 | 
			
		||||
        return registeredFragments.get(position)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun getRegisteredFragments(): List<Fragment> {
 | 
			
		||||
        val fragments = ArrayList<Fragment>()
 | 
			
		||||
        for (i in 0..registeredFragments.size() - 1) {
 | 
			
		||||
            fragments.add(registeredFragments.valueAt(i))
 | 
			
		||||
        }
 | 
			
		||||
        return fragments
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,8 +1,7 @@
 | 
			
		||||
package eu.kanade.tachiyomi.ui.download
 | 
			
		||||
 | 
			
		||||
import android.content.Context
 | 
			
		||||
import android.support.v7.widget.RecyclerView
 | 
			
		||||
import android.view.ViewGroup
 | 
			
		||||
import eu.davidea.flexibleadapter4.FlexibleAdapter
 | 
			
		||||
import eu.kanade.tachiyomi.R
 | 
			
		||||
import eu.kanade.tachiyomi.data.download.model.Download
 | 
			
		||||
import eu.kanade.tachiyomi.util.inflate
 | 
			
		||||
@@ -12,7 +11,9 @@ import eu.kanade.tachiyomi.util.inflate
 | 
			
		||||
 *
 | 
			
		||||
 * @param context the context of the fragment containing this adapter.
 | 
			
		||||
 */
 | 
			
		||||
class DownloadAdapter(private val context: Context) : FlexibleAdapter<DownloadHolder, Download>() {
 | 
			
		||||
class DownloadAdapter : RecyclerView.Adapter<DownloadHolder>() {
 | 
			
		||||
 | 
			
		||||
    private var items = emptyList<Download>()
 | 
			
		||||
 | 
			
		||||
    init {
 | 
			
		||||
        setHasStableIds(true)
 | 
			
		||||
@@ -24,10 +25,17 @@ class DownloadAdapter(private val context: Context) : FlexibleAdapter<DownloadHo
 | 
			
		||||
     * @param downloads the list to set.
 | 
			
		||||
     */
 | 
			
		||||
    fun setItems(downloads: List<Download>) {
 | 
			
		||||
        mItems = downloads
 | 
			
		||||
        items = downloads
 | 
			
		||||
        notifyDataSetChanged()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the number of downloads in the adapter
 | 
			
		||||
     */
 | 
			
		||||
    override fun getItemCount(): Int {
 | 
			
		||||
        return items.size
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the identifier for a download.
 | 
			
		||||
     *
 | 
			
		||||
@@ -35,7 +43,7 @@ class DownloadAdapter(private val context: Context) : FlexibleAdapter<DownloadHo
 | 
			
		||||
     * @return an identifier for the item.
 | 
			
		||||
     */
 | 
			
		||||
    override fun getItemId(position: Int): Long {
 | 
			
		||||
        return getItem(position).chapter.id!!
 | 
			
		||||
        return items[position].chapter.id!!
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -57,14 +65,8 @@ class DownloadAdapter(private val context: Context) : FlexibleAdapter<DownloadHo
 | 
			
		||||
     * @param position the position to bind.
 | 
			
		||||
     */
 | 
			
		||||
    override fun onBindViewHolder(holder: DownloadHolder, position: Int) {
 | 
			
		||||
        val download = getItem(position)
 | 
			
		||||
        val download = items[position]
 | 
			
		||||
        holder.onSetValues(download)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Used to filter the list. Not used.
 | 
			
		||||
     */
 | 
			
		||||
    override fun updateDataSet(param: String) {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,246 +1,252 @@
 | 
			
		||||
package eu.kanade.tachiyomi.ui.download
 | 
			
		||||
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
import android.support.v7.widget.LinearLayoutManager
 | 
			
		||||
import android.view.Menu
 | 
			
		||||
import android.view.MenuItem
 | 
			
		||||
import eu.kanade.tachiyomi.R
 | 
			
		||||
import eu.kanade.tachiyomi.data.download.DownloadService
 | 
			
		||||
import eu.kanade.tachiyomi.data.download.model.Download
 | 
			
		||||
import eu.kanade.tachiyomi.source.model.Page
 | 
			
		||||
import eu.kanade.tachiyomi.ui.base.activity.BaseRxActivity
 | 
			
		||||
import eu.kanade.tachiyomi.util.plusAssign
 | 
			
		||||
import kotlinx.android.synthetic.main.fragment_download_queue.*
 | 
			
		||||
import kotlinx.android.synthetic.main.toolbar.*
 | 
			
		||||
import nucleus.factory.RequiresPresenter
 | 
			
		||||
import rx.Observable
 | 
			
		||||
import rx.Subscription
 | 
			
		||||
import rx.android.schedulers.AndroidSchedulers
 | 
			
		||||
import rx.subscriptions.CompositeSubscription
 | 
			
		||||
import java.util.*
 | 
			
		||||
import java.util.concurrent.TimeUnit
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Activity that shows the currently active downloads.
 | 
			
		||||
 * Uses R.layout.fragment_download_queue.
 | 
			
		||||
 */
 | 
			
		||||
@RequiresPresenter(DownloadPresenter::class)
 | 
			
		||||
class DownloadActivity : BaseRxActivity<DownloadPresenter>() {
 | 
			
		||||
    /**
 | 
			
		||||
     * Adapter containing the active downloads.
 | 
			
		||||
     */
 | 
			
		||||
    private lateinit var adapter: DownloadAdapter
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Subscription list to be cleared during [onDestroy].
 | 
			
		||||
     */
 | 
			
		||||
    private val subscriptions 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.
 | 
			
		||||
     */
 | 
			
		||||
    private var isRunning: Boolean = false
 | 
			
		||||
 | 
			
		||||
    override fun onCreate(savedState: Bundle?) {
 | 
			
		||||
        setAppTheme()
 | 
			
		||||
        super.onCreate(savedState)
 | 
			
		||||
        setContentView(R.layout.activity_download_manager)
 | 
			
		||||
        setupToolbar(toolbar)
 | 
			
		||||
        setToolbarTitle(R.string.label_download_queue)
 | 
			
		||||
 | 
			
		||||
        // Check if download queue is empty and update information accordingly.
 | 
			
		||||
        setInformationView()
 | 
			
		||||
 | 
			
		||||
        // Initialize adapter.
 | 
			
		||||
        adapter = DownloadAdapter(this)
 | 
			
		||||
        recycler.adapter = adapter
 | 
			
		||||
 | 
			
		||||
        // Set the layout manager for the recycler and fixed size.
 | 
			
		||||
        recycler.layoutManager = LinearLayoutManager(this)
 | 
			
		||||
        recycler.setHasFixedSize(true)
 | 
			
		||||
 | 
			
		||||
        // Suscribe to changes
 | 
			
		||||
        subscriptions += DownloadService.runningRelay
 | 
			
		||||
                .observeOn(AndroidSchedulers.mainThread())
 | 
			
		||||
                .subscribe { onQueueStatusChange(it) }
 | 
			
		||||
 | 
			
		||||
        subscriptions += presenter.getDownloadStatusObservable()
 | 
			
		||||
                .observeOn(AndroidSchedulers.mainThread())
 | 
			
		||||
                .subscribe { onStatusChange(it) }
 | 
			
		||||
 | 
			
		||||
        subscriptions += presenter.getDownloadProgressObservable()
 | 
			
		||||
                .observeOn(AndroidSchedulers.mainThread())
 | 
			
		||||
                .subscribe { onUpdateDownloadedPages(it) }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onDestroy() {
 | 
			
		||||
        for (subscription in progressSubscriptions.values) {
 | 
			
		||||
            subscription.unsubscribe()
 | 
			
		||||
        }
 | 
			
		||||
        progressSubscriptions.clear()
 | 
			
		||||
        subscriptions.clear()
 | 
			
		||||
        super.onDestroy()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onCreateOptionsMenu(menu: Menu): Boolean {
 | 
			
		||||
        menuInflater.inflate(R.menu.download_queue, menu)
 | 
			
		||||
        return true
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onPrepareOptionsMenu(menu: Menu): Boolean {
 | 
			
		||||
        // Set start button visibility.
 | 
			
		||||
        menu.findItem(R.id.start_queue).isVisible = !isRunning && !presenter.downloadQueue.isEmpty()
 | 
			
		||||
 | 
			
		||||
        // Set pause button visibility.
 | 
			
		||||
        menu.findItem(R.id.pause_queue).isVisible = isRunning
 | 
			
		||||
 | 
			
		||||
        // Set clear button visibility.
 | 
			
		||||
        menu.findItem(R.id.clear_queue).isVisible = !presenter.downloadQueue.isEmpty()
 | 
			
		||||
        return true
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onOptionsItemSelected(item: MenuItem): Boolean {
 | 
			
		||||
        when (item.itemId) {
 | 
			
		||||
            R.id.start_queue -> DownloadService.start(this)
 | 
			
		||||
            R.id.pause_queue -> {
 | 
			
		||||
                DownloadService.stop(this)
 | 
			
		||||
                presenter.pauseDownloads()
 | 
			
		||||
            }
 | 
			
		||||
            R.id.clear_queue -> {
 | 
			
		||||
                DownloadService.stop(this)
 | 
			
		||||
                presenter.clearQueue()
 | 
			
		||||
            }
 | 
			
		||||
            else -> return super.onOptionsItemSelected(item)
 | 
			
		||||
        }
 | 
			
		||||
        return true
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 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)
 | 
			
		||||
                // Get the sum of percentages for all the pages.
 | 
			
		||||
                .flatMap {
 | 
			
		||||
                    Observable.from(download.pages)
 | 
			
		||||
                            .map(Page::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.
 | 
			
		||||
     *
 | 
			
		||||
     * @param running whether the queue is now running or not.
 | 
			
		||||
     */
 | 
			
		||||
    private fun onQueueStatusChange(running: Boolean) {
 | 
			
		||||
        isRunning = running
 | 
			
		||||
        supportInvalidateOptionsMenu()
 | 
			
		||||
 | 
			
		||||
        // Check if download queue is empty and update information accordingly.
 | 
			
		||||
        setInformationView()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Called from the presenter to assign the downloads for the adapter.
 | 
			
		||||
     *
 | 
			
		||||
     * @param downloads the downloads from the queue.
 | 
			
		||||
     */
 | 
			
		||||
    fun onNextDownloads(downloads: List<Download>) {
 | 
			
		||||
        supportInvalidateOptionsMenu()
 | 
			
		||||
        setInformationView()
 | 
			
		||||
        adapter.setItems(downloads)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Called when the progress of a download changes.
 | 
			
		||||
     *
 | 
			
		||||
     * @param download the download whose progress has changed.
 | 
			
		||||
     */
 | 
			
		||||
    fun onUpdateProgress(download: Download) {
 | 
			
		||||
        getHolder(download)?.notifyProgress()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Called when a page of a download is downloaded.
 | 
			
		||||
     *
 | 
			
		||||
     * @param download the download whose page has been downloaded.
 | 
			
		||||
     */
 | 
			
		||||
    fun onUpdateDownloadedPages(download: Download) {
 | 
			
		||||
        getHolder(download)?.notifyDownloadedPages()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the holder for the given download.
 | 
			
		||||
     *
 | 
			
		||||
     * @param download the download to find.
 | 
			
		||||
     * @return the holder of the download or null if it's not bound.
 | 
			
		||||
     */
 | 
			
		||||
    private fun getHolder(download: Download): DownloadHolder? {
 | 
			
		||||
        return recycler.findViewHolderForItemId(download.chapter.id!!) as? DownloadHolder
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Set information view when queue is empty
 | 
			
		||||
     */
 | 
			
		||||
    private fun setInformationView() {
 | 
			
		||||
        updateEmptyView(presenter.downloadQueue.isEmpty(),
 | 
			
		||||
                R.string.information_no_downloads, R.drawable.ic_file_download_black_128dp)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun updateEmptyView(show: Boolean, textResource: Int, drawable: Int) {
 | 
			
		||||
//        if (show) empty_view.show(drawable, textResource) else empty_view.hide()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
package eu.kanade.tachiyomi.ui.download
 | 
			
		||||
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
import android.support.v7.widget.LinearLayoutManager
 | 
			
		||||
import android.view.*
 | 
			
		||||
import eu.kanade.tachiyomi.R
 | 
			
		||||
import eu.kanade.tachiyomi.data.download.DownloadService
 | 
			
		||||
import eu.kanade.tachiyomi.data.download.model.Download
 | 
			
		||||
import eu.kanade.tachiyomi.source.model.Page
 | 
			
		||||
import eu.kanade.tachiyomi.ui.base.controller.NucleusController
 | 
			
		||||
import kotlinx.android.synthetic.main.activity_download_manager.view.*
 | 
			
		||||
import rx.Observable
 | 
			
		||||
import rx.Subscription
 | 
			
		||||
import rx.android.schedulers.AndroidSchedulers
 | 
			
		||||
import java.util.*
 | 
			
		||||
import java.util.concurrent.TimeUnit
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Controller that shows the currently active downloads.
 | 
			
		||||
 * Uses R.layout.fragment_download_queue.
 | 
			
		||||
 */
 | 
			
		||||
class DownloadController : NucleusController<DownloadPresenter>() {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Adapter containing the active downloads.
 | 
			
		||||
     */
 | 
			
		||||
    private var adapter: DownloadAdapter? = null
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Map of subscriptions for active downloads.
 | 
			
		||||
     */
 | 
			
		||||
    private val progressSubscriptions by lazy { HashMap<Download, Subscription>() }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Whether the download queue is running or not.
 | 
			
		||||
     */
 | 
			
		||||
    private var isRunning: Boolean = false
 | 
			
		||||
 | 
			
		||||
    init {
 | 
			
		||||
        setHasOptionsMenu(true)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun inflateView(inflater: LayoutInflater, container: ViewGroup): View {
 | 
			
		||||
        return inflater.inflate(R.layout.activity_download_manager, container, false)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun createPresenter(): DownloadPresenter {
 | 
			
		||||
        return DownloadPresenter()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun getTitle(): String? {
 | 
			
		||||
        return resources?.getString(R.string.label_download_queue)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onViewCreated(view: View, savedViewState: Bundle?) {
 | 
			
		||||
        super.onViewCreated(view, savedViewState)
 | 
			
		||||
 | 
			
		||||
        // Check if download queue is empty and update information accordingly.
 | 
			
		||||
        setInformationView()
 | 
			
		||||
 | 
			
		||||
        // Initialize adapter.
 | 
			
		||||
        adapter = DownloadAdapter()
 | 
			
		||||
        with(view) {
 | 
			
		||||
            recycler.adapter = adapter
 | 
			
		||||
 | 
			
		||||
            // Set the layout manager for the recycler and fixed size.
 | 
			
		||||
            recycler.layoutManager = LinearLayoutManager(context)
 | 
			
		||||
            recycler.setHasFixedSize(true)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Suscribe to changes
 | 
			
		||||
        DownloadService.runningRelay
 | 
			
		||||
                .observeOn(AndroidSchedulers.mainThread())
 | 
			
		||||
                .subscribeUntilDestroy { onQueueStatusChange(it) }
 | 
			
		||||
 | 
			
		||||
        presenter.getDownloadStatusObservable()
 | 
			
		||||
                .observeOn(AndroidSchedulers.mainThread())
 | 
			
		||||
                .subscribeUntilDestroy { onStatusChange(it) }
 | 
			
		||||
 | 
			
		||||
        presenter.getDownloadProgressObservable()
 | 
			
		||||
                .observeOn(AndroidSchedulers.mainThread())
 | 
			
		||||
                .subscribeUntilDestroy { onUpdateDownloadedPages(it) }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onDestroyView(view: View) {
 | 
			
		||||
        super.onDestroyView(view)
 | 
			
		||||
        for (subscription in progressSubscriptions.values) {
 | 
			
		||||
            subscription.unsubscribe()
 | 
			
		||||
        }
 | 
			
		||||
        progressSubscriptions.clear()
 | 
			
		||||
        adapter = null
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
 | 
			
		||||
        inflater.inflate(R.menu.download_queue, menu)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onPrepareOptionsMenu(menu: Menu) {
 | 
			
		||||
        // Set start button visibility.
 | 
			
		||||
        menu.findItem(R.id.start_queue).isVisible = !isRunning && !presenter.downloadQueue.isEmpty()
 | 
			
		||||
 | 
			
		||||
        // Set pause button visibility.
 | 
			
		||||
        menu.findItem(R.id.pause_queue).isVisible = isRunning
 | 
			
		||||
 | 
			
		||||
        // Set clear button visibility.
 | 
			
		||||
        menu.findItem(R.id.clear_queue).isVisible = !presenter.downloadQueue.isEmpty()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onOptionsItemSelected(item: MenuItem): Boolean {
 | 
			
		||||
        val context = applicationContext ?: return false
 | 
			
		||||
        when (item.itemId) {
 | 
			
		||||
            R.id.start_queue -> DownloadService.start(context)
 | 
			
		||||
            R.id.pause_queue -> {
 | 
			
		||||
                DownloadService.stop(context)
 | 
			
		||||
                presenter.pauseDownloads()
 | 
			
		||||
            }
 | 
			
		||||
            R.id.clear_queue -> {
 | 
			
		||||
                DownloadService.stop(context)
 | 
			
		||||
                presenter.clearQueue()
 | 
			
		||||
            }
 | 
			
		||||
            else -> return super.onOptionsItemSelected(item)
 | 
			
		||||
        }
 | 
			
		||||
        return true
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 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)
 | 
			
		||||
                // Get the sum of percentages for all the pages.
 | 
			
		||||
                .flatMap {
 | 
			
		||||
                    Observable.from(download.pages)
 | 
			
		||||
                            .map(Page::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.
 | 
			
		||||
     *
 | 
			
		||||
     * @param running whether the queue is now running or not.
 | 
			
		||||
     */
 | 
			
		||||
    private fun onQueueStatusChange(running: Boolean) {
 | 
			
		||||
        isRunning = running
 | 
			
		||||
        activity?.invalidateOptionsMenu()
 | 
			
		||||
 | 
			
		||||
        // Check if download queue is empty and update information accordingly.
 | 
			
		||||
        setInformationView()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Called from the presenter to assign the downloads for the adapter.
 | 
			
		||||
     *
 | 
			
		||||
     * @param downloads the downloads from the queue.
 | 
			
		||||
     */
 | 
			
		||||
    fun onNextDownloads(downloads: List<Download>) {
 | 
			
		||||
        activity?.invalidateOptionsMenu()
 | 
			
		||||
        setInformationView()
 | 
			
		||||
        adapter?.setItems(downloads)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Called when the progress of a download changes.
 | 
			
		||||
     *
 | 
			
		||||
     * @param download the download whose progress has changed.
 | 
			
		||||
     */
 | 
			
		||||
    fun onUpdateProgress(download: Download) {
 | 
			
		||||
        getHolder(download)?.notifyProgress()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Called when a page of a download is downloaded.
 | 
			
		||||
     *
 | 
			
		||||
     * @param download the download whose page has been downloaded.
 | 
			
		||||
     */
 | 
			
		||||
    fun onUpdateDownloadedPages(download: Download) {
 | 
			
		||||
        getHolder(download)?.notifyDownloadedPages()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the holder for the given download.
 | 
			
		||||
     *
 | 
			
		||||
     * @param download the download to find.
 | 
			
		||||
     * @return the holder of the download or null if it's not bound.
 | 
			
		||||
     */
 | 
			
		||||
    private fun getHolder(download: Download): DownloadHolder? {
 | 
			
		||||
        val recycler = view?.recycler ?: return null
 | 
			
		||||
        return recycler.findViewHolderForItemId(download.chapter.id!!) as? DownloadHolder
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Set information view when queue is empty
 | 
			
		||||
     */
 | 
			
		||||
    private fun setInformationView() {
 | 
			
		||||
        val emptyView = view?.empty_view ?: return
 | 
			
		||||
        if (presenter.downloadQueue.isEmpty()) {
 | 
			
		||||
            emptyView.show(R.drawable.ic_file_download_black_128dp,
 | 
			
		||||
                    R.string.information_no_downloads)
 | 
			
		||||
        } else {
 | 
			
		||||
            emptyView.hide()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -12,9 +12,9 @@ import uy.kohesive.injekt.injectLazy
 | 
			
		||||
import java.util.*
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Presenter of [DownloadActivity].
 | 
			
		||||
 * Presenter of [DownloadController].
 | 
			
		||||
 */
 | 
			
		||||
class DownloadPresenter : BasePresenter<DownloadActivity>() {
 | 
			
		||||
class DownloadPresenter : BasePresenter<DownloadController>() {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Download manager.
 | 
			
		||||
@@ -33,7 +33,7 @@ class DownloadPresenter : BasePresenter<DownloadActivity>() {
 | 
			
		||||
        downloadQueue.getUpdatedObservable()
 | 
			
		||||
                .observeOn(AndroidSchedulers.mainThread())
 | 
			
		||||
                .map { ArrayList(it) }
 | 
			
		||||
                .subscribeLatestCache(DownloadActivity::onNextDownloads, { view, error ->
 | 
			
		||||
                .subscribeLatestCache(DownloadController::onNextDownloads, { view, error ->
 | 
			
		||||
                    Timber.e(error)
 | 
			
		||||
                })
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,6 @@
 | 
			
		||||
package eu.kanade.tachiyomi.ui.main
 | 
			
		||||
 | 
			
		||||
import android.animation.ObjectAnimator
 | 
			
		||||
import android.content.Intent
 | 
			
		||||
import android.graphics.Color
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
import android.support.v4.view.GravityCompat
 | 
			
		||||
@@ -19,7 +18,7 @@ import eu.kanade.tachiyomi.ui.base.controller.NoToolbarElevationController
 | 
			
		||||
import eu.kanade.tachiyomi.ui.base.controller.SecondaryDrawerController
 | 
			
		||||
import eu.kanade.tachiyomi.ui.base.controller.TabbedController
 | 
			
		||||
import eu.kanade.tachiyomi.ui.catalogue.CatalogueController
 | 
			
		||||
import eu.kanade.tachiyomi.ui.download.DownloadActivity
 | 
			
		||||
import eu.kanade.tachiyomi.ui.download.DownloadController
 | 
			
		||||
import eu.kanade.tachiyomi.ui.latest_updates.LatestUpdatesController
 | 
			
		||||
import eu.kanade.tachiyomi.ui.library.LibraryController
 | 
			
		||||
import eu.kanade.tachiyomi.ui.manga.MangaController
 | 
			
		||||
@@ -85,7 +84,9 @@ class MainActivity : BaseActivity() {
 | 
			
		||||
                    R.id.nav_drawer_catalogues -> setRoot(CatalogueController(), id)
 | 
			
		||||
                    R.id.nav_drawer_latest_updates -> setRoot(LatestUpdatesController(), id)
 | 
			
		||||
                    R.id.nav_drawer_downloads -> {
 | 
			
		||||
                        startActivity(Intent(this, DownloadActivity::class.java))
 | 
			
		||||
                        router.pushController(RouterTransaction.with(DownloadController())
 | 
			
		||||
                                .pushChangeHandler(FadeChangeHandler())
 | 
			
		||||
                                .popChangeHandler(FadeChangeHandler()))
 | 
			
		||||
                    }
 | 
			
		||||
                    R.id.nav_drawer_settings ->
 | 
			
		||||
                        router.pushController(RouterTransaction.with(SettingsMainController())
 | 
			
		||||
@@ -109,6 +110,7 @@ class MainActivity : BaseActivity() {
 | 
			
		||||
                SHORTCUT_CATALOGUES -> setSelectedDrawerItem(R.id.nav_drawer_catalogues)
 | 
			
		||||
                SHORTCUT_MANGA -> router.setRoot(
 | 
			
		||||
                        RouterTransaction.with(MangaController(intent.extras)))
 | 
			
		||||
                SHORTCUT_DOWNLOADS -> setSelectedDrawerItem(R.id.nav_drawer_downloads)
 | 
			
		||||
                else -> setSelectedDrawerItem(startScreenId)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@@ -225,6 +227,7 @@ class MainActivity : BaseActivity() {
 | 
			
		||||
        private const val SHORTCUT_RECENTLY_UPDATED = "eu.kanade.tachiyomi.SHOW_RECENTLY_UPDATED"
 | 
			
		||||
        private const val SHORTCUT_RECENTLY_READ = "eu.kanade.tachiyomi.SHOW_RECENTLY_READ"
 | 
			
		||||
        private const val SHORTCUT_CATALOGUES = "eu.kanade.tachiyomi.SHOW_CATALOGUES"
 | 
			
		||||
        const val SHORTCUT_DOWNLOADS = "eu.kanade.tachiyomi.SHOW_DOWNLOADS"
 | 
			
		||||
        const val SHORTCUT_MANGA = "eu.kanade.tachiyomi.SHOW_MANGA"
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user