mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-11-04 08:08:55 +01:00 
			
		
		
		
	Track Page progress with StateFlow (#8749)
* Update ReaderProgressIndicator documentation
ReaderProgressIndicator is not always determinate (cc554530, #5605).
* Track Page progress with StateFlow
			
			
This commit is contained in:
		@@ -11,10 +11,9 @@ import androidx.annotation.IntRange
 | 
			
		||||
import com.google.android.material.progressindicator.CircularProgressIndicator
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A wrapper for [CircularProgressIndicator] that always rotates while being determinate.
 | 
			
		||||
 * A wrapper for [CircularProgressIndicator] that always rotates.
 | 
			
		||||
 *
 | 
			
		||||
 * By always rotating we give the feedback to the user that the application isn't 'stuck',
 | 
			
		||||
 * and by making it determinate the user also approximately knows how much the operation will take.
 | 
			
		||||
 * By always rotating we give the feedback to the user that the application isn't 'stuck'.
 | 
			
		||||
 */
 | 
			
		||||
class ReaderProgressIndicator @JvmOverloads constructor(
 | 
			
		||||
    context: Context,
 | 
			
		||||
 
 | 
			
		||||
@@ -13,8 +13,13 @@ import eu.kanade.tachiyomi.ui.reader.model.ReaderPage
 | 
			
		||||
import eu.kanade.tachiyomi.ui.reader.viewer.ReaderPageImageView
 | 
			
		||||
import eu.kanade.tachiyomi.ui.reader.viewer.ReaderProgressIndicator
 | 
			
		||||
import eu.kanade.tachiyomi.ui.webview.WebViewActivity
 | 
			
		||||
import eu.kanade.tachiyomi.util.lang.launchUI
 | 
			
		||||
import eu.kanade.tachiyomi.util.system.ImageUtil
 | 
			
		||||
import eu.kanade.tachiyomi.widget.ViewPagerAdapter
 | 
			
		||||
import kotlinx.coroutines.CoroutineScope
 | 
			
		||||
import kotlinx.coroutines.Dispatchers
 | 
			
		||||
import kotlinx.coroutines.Job
 | 
			
		||||
import kotlinx.coroutines.flow.collectLatest
 | 
			
		||||
import rx.Observable
 | 
			
		||||
import rx.Subscription
 | 
			
		||||
import rx.android.schedulers.AndroidSchedulers
 | 
			
		||||
@@ -22,7 +27,6 @@ import rx.schedulers.Schedulers
 | 
			
		||||
import java.io.BufferedInputStream
 | 
			
		||||
import java.io.ByteArrayInputStream
 | 
			
		||||
import java.io.InputStream
 | 
			
		||||
import java.util.concurrent.TimeUnit
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * View of the ViewPager that contains a page of a chapter.
 | 
			
		||||
@@ -54,15 +58,17 @@ class PagerPageHolder(
 | 
			
		||||
     */
 | 
			
		||||
    private var errorLayout: ReaderErrorBinding? = null
 | 
			
		||||
 | 
			
		||||
    private val scope = CoroutineScope(Dispatchers.IO)
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Subscription for status changes of the page.
 | 
			
		||||
     */
 | 
			
		||||
    private var statusSubscription: Subscription? = null
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Subscription for progress changes of the page.
 | 
			
		||||
     * Job for progress changes of the page.
 | 
			
		||||
     */
 | 
			
		||||
    private var progressSubscription: Subscription? = null
 | 
			
		||||
    private var progressJob: Job? = null
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Subscription used to read the header of the image. This is needed in order to instantiate
 | 
			
		||||
@@ -81,7 +87,7 @@ class PagerPageHolder(
 | 
			
		||||
    @SuppressLint("ClickableViewAccessibility")
 | 
			
		||||
    override fun onDetachedFromWindow() {
 | 
			
		||||
        super.onDetachedFromWindow()
 | 
			
		||||
        unsubscribeProgress()
 | 
			
		||||
        cancelProgressJob()
 | 
			
		||||
        unsubscribeStatus()
 | 
			
		||||
        unsubscribeReadImageHeader()
 | 
			
		||||
    }
 | 
			
		||||
@@ -100,18 +106,11 @@ class PagerPageHolder(
 | 
			
		||||
            .subscribe { processStatus(it) }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Observes the progress of the page and updates view.
 | 
			
		||||
     */
 | 
			
		||||
    private fun observeProgress() {
 | 
			
		||||
        progressSubscription?.unsubscribe()
 | 
			
		||||
 | 
			
		||||
        progressSubscription = Observable.interval(100, TimeUnit.MILLISECONDS)
 | 
			
		||||
            .map { page.progress }
 | 
			
		||||
            .distinctUntilChanged()
 | 
			
		||||
            .onBackpressureLatest()
 | 
			
		||||
            .observeOn(AndroidSchedulers.mainThread())
 | 
			
		||||
            .subscribe { value -> progressIndicator.setProgress(value) }
 | 
			
		||||
    private fun launchProgressJob() {
 | 
			
		||||
        progressJob?.cancel()
 | 
			
		||||
        progressJob = scope.launchUI {
 | 
			
		||||
            page.progressFlow.collectLatest { value -> progressIndicator.setProgress(value) }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -124,16 +123,16 @@ class PagerPageHolder(
 | 
			
		||||
            Page.State.QUEUE -> setQueued()
 | 
			
		||||
            Page.State.LOAD_PAGE -> setLoading()
 | 
			
		||||
            Page.State.DOWNLOAD_IMAGE -> {
 | 
			
		||||
                observeProgress()
 | 
			
		||||
                launchProgressJob()
 | 
			
		||||
                setDownloading()
 | 
			
		||||
            }
 | 
			
		||||
            Page.State.READY -> {
 | 
			
		||||
                setImage()
 | 
			
		||||
                unsubscribeProgress()
 | 
			
		||||
                cancelProgressJob()
 | 
			
		||||
            }
 | 
			
		||||
            Page.State.ERROR -> {
 | 
			
		||||
                setError()
 | 
			
		||||
                unsubscribeProgress()
 | 
			
		||||
                cancelProgressJob()
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@@ -146,12 +145,9 @@ class PagerPageHolder(
 | 
			
		||||
        statusSubscription = null
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Unsubscribes from the progress subscription.
 | 
			
		||||
     */
 | 
			
		||||
    private fun unsubscribeProgress() {
 | 
			
		||||
        progressSubscription?.unsubscribe()
 | 
			
		||||
        progressSubscription = null
 | 
			
		||||
    private fun cancelProgressJob() {
 | 
			
		||||
        progressJob?.cancel()
 | 
			
		||||
        progressJob = null
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 
 | 
			
		||||
@@ -18,15 +18,19 @@ import eu.kanade.tachiyomi.ui.reader.model.StencilPage
 | 
			
		||||
import eu.kanade.tachiyomi.ui.reader.viewer.ReaderPageImageView
 | 
			
		||||
import eu.kanade.tachiyomi.ui.reader.viewer.ReaderProgressIndicator
 | 
			
		||||
import eu.kanade.tachiyomi.ui.webview.WebViewActivity
 | 
			
		||||
import eu.kanade.tachiyomi.util.lang.launchUI
 | 
			
		||||
import eu.kanade.tachiyomi.util.system.ImageUtil
 | 
			
		||||
import eu.kanade.tachiyomi.util.system.dpToPx
 | 
			
		||||
import kotlinx.coroutines.CoroutineScope
 | 
			
		||||
import kotlinx.coroutines.Dispatchers
 | 
			
		||||
import kotlinx.coroutines.Job
 | 
			
		||||
import kotlinx.coroutines.flow.collectLatest
 | 
			
		||||
import rx.Observable
 | 
			
		||||
import rx.Subscription
 | 
			
		||||
import rx.android.schedulers.AndroidSchedulers
 | 
			
		||||
import rx.schedulers.Schedulers
 | 
			
		||||
import java.io.BufferedInputStream
 | 
			
		||||
import java.io.InputStream
 | 
			
		||||
import java.util.concurrent.TimeUnit
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Holder of the webtoon reader for a single page of a chapter.
 | 
			
		||||
@@ -67,15 +71,17 @@ class WebtoonPageHolder(
 | 
			
		||||
     */
 | 
			
		||||
    private var page: ReaderPage? = null
 | 
			
		||||
 | 
			
		||||
    private val scope = CoroutineScope(Dispatchers.IO)
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Subscription for status changes of the page.
 | 
			
		||||
     */
 | 
			
		||||
    private var statusSubscription: Subscription? = null
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Subscription for progress changes of the page.
 | 
			
		||||
     * Job for progress changes of the page.
 | 
			
		||||
     */
 | 
			
		||||
    private var progressSubscription: Subscription? = null
 | 
			
		||||
    private var progressJob: Job? = null
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Subscription used to read the header of the image. This is needed in order to instantiate
 | 
			
		||||
@@ -117,7 +123,7 @@ class WebtoonPageHolder(
 | 
			
		||||
     */
 | 
			
		||||
    override fun recycle() {
 | 
			
		||||
        unsubscribeStatus()
 | 
			
		||||
        unsubscribeProgress()
 | 
			
		||||
        cancelProgressJob()
 | 
			
		||||
        unsubscribeReadImageHeader()
 | 
			
		||||
 | 
			
		||||
        removeErrorLayout()
 | 
			
		||||
@@ -145,19 +151,14 @@ class WebtoonPageHolder(
 | 
			
		||||
    /**
 | 
			
		||||
     * Observes the progress of the page and updates view.
 | 
			
		||||
     */
 | 
			
		||||
    private fun observeProgress() {
 | 
			
		||||
        unsubscribeProgress()
 | 
			
		||||
    private fun launchProgressJob() {
 | 
			
		||||
        cancelProgressJob()
 | 
			
		||||
 | 
			
		||||
        val page = page ?: return
 | 
			
		||||
 | 
			
		||||
        progressSubscription = Observable.interval(100, TimeUnit.MILLISECONDS)
 | 
			
		||||
            .map { page.progress }
 | 
			
		||||
            .distinctUntilChanged()
 | 
			
		||||
            .onBackpressureLatest()
 | 
			
		||||
            .observeOn(AndroidSchedulers.mainThread())
 | 
			
		||||
            .subscribe { value -> progressIndicator.setProgress(value) }
 | 
			
		||||
 | 
			
		||||
        addSubscription(progressSubscription)
 | 
			
		||||
        progressJob = scope.launchUI {
 | 
			
		||||
            page.progressFlow.collectLatest { value -> progressIndicator.setProgress(value) }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -170,16 +171,16 @@ class WebtoonPageHolder(
 | 
			
		||||
            Page.State.QUEUE -> setQueued()
 | 
			
		||||
            Page.State.LOAD_PAGE -> setLoading()
 | 
			
		||||
            Page.State.DOWNLOAD_IMAGE -> {
 | 
			
		||||
                observeProgress()
 | 
			
		||||
                launchProgressJob()
 | 
			
		||||
                setDownloading()
 | 
			
		||||
            }
 | 
			
		||||
            Page.State.READY -> {
 | 
			
		||||
                setImage()
 | 
			
		||||
                unsubscribeProgress()
 | 
			
		||||
                cancelProgressJob()
 | 
			
		||||
            }
 | 
			
		||||
            Page.State.ERROR -> {
 | 
			
		||||
                setError()
 | 
			
		||||
                unsubscribeProgress()
 | 
			
		||||
                cancelProgressJob()
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@@ -195,9 +196,9 @@ class WebtoonPageHolder(
 | 
			
		||||
    /**
 | 
			
		||||
     * Unsubscribes from the progress subscription.
 | 
			
		||||
     */
 | 
			
		||||
    private fun unsubscribeProgress() {
 | 
			
		||||
        removeSubscription(progressSubscription)
 | 
			
		||||
        progressSubscription = null
 | 
			
		||||
    private fun cancelProgressJob() {
 | 
			
		||||
        progressJob?.cancel()
 | 
			
		||||
        progressJob = null
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user