Replace RxJava in webtoonholder

This commit is contained in:
Jays2Kings 2023-03-02 01:45:48 -05:00
parent b7fc06d2ad
commit 9c521e23ce

View file

@ -23,14 +23,15 @@ import eu.kanade.tachiyomi.ui.reader.viewer.ReaderPageImageView
import eu.kanade.tachiyomi.ui.reader.viewer.ReaderProgressBar import eu.kanade.tachiyomi.ui.reader.viewer.ReaderProgressBar
import eu.kanade.tachiyomi.util.system.ImageUtil import eu.kanade.tachiyomi.util.system.ImageUtil
import eu.kanade.tachiyomi.util.system.dpToPx import eu.kanade.tachiyomi.util.system.dpToPx
import eu.kanade.tachiyomi.util.system.launchIO
import eu.kanade.tachiyomi.util.system.withIOContext
import eu.kanade.tachiyomi.util.system.withUIContext
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlinx.coroutines.MainScope import kotlinx.coroutines.MainScope
import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import rx.Observable import kotlinx.coroutines.supervisorScope
import rx.Subscription import kotlinx.coroutines.suspendCancellableCoroutine
import rx.android.schedulers.AndroidSchedulers
import rx.schedulers.Schedulers
import java.io.BufferedInputStream import java.io.BufferedInputStream
import java.io.InputStream import java.io.InputStream
@ -85,22 +86,11 @@ class WebtoonPageHolder(
*/ */
private var loadJob: Job? = null private var loadJob: Job? = null
/**
* Job for status changes of the page.
*/
private var statusJob: Job? = null
/** /**
* Job for progress changes of the page. * Job for progress changes of the page.
*/ */
private var progressJob: Job? = null private var progressJob: Job? = null
/**
* Subscription used to read the header of the image. This is needed in order to instantiate
* the appropriate image view depending if the image is animated (GIF).
*/
private var readImageHeaderSubscription: Subscription? = null
init { init {
refreshLayoutParams() refreshLayoutParams()
frame.setBackgroundColor(Color.BLACK) frame.setBackgroundColor(Color.BLACK)
@ -136,7 +126,6 @@ class WebtoonPageHolder(
override fun recycle() { override fun recycle() {
cancelLoadJob() cancelLoadJob()
cancelProgressJob() cancelProgressJob()
unsubscribeReadImageHeader()
removeDecodeErrorLayout() removeDecodeErrorLayout()
frame.recycle() frame.recycle()
@ -150,13 +139,14 @@ class WebtoonPageHolder(
*/ */
private fun launchLoadJob() { private fun launchLoadJob() {
cancelLoadJob() cancelLoadJob()
loadJob = scope.launch { loadPageAndProcessStatus() }
}
private suspend fun loadPageAndProcessStatus() {
val page = page ?: return val page = page ?: return
val loader = page.chapter.pageLoader ?: return val loader = page.chapter.pageLoader ?: return
loadJob = scope.launch { supervisorScope {
loader.loadPage(page) launchIO { loader.loadPage(page) }
}
statusJob = scope.launch {
page.statusFlow.collectLatest { processStatus(it) } page.statusFlow.collectLatest { processStatus(it) }
} }
} }
@ -168,7 +158,6 @@ class WebtoonPageHolder(
cancelProgressJob() cancelProgressJob()
val page = page ?: return val page = page ?: return
progressJob = scope.launch { progressJob = scope.launch {
page.progressFlow.collectLatest { value -> progressBar.setProgress(value) } page.progressFlow.collectLatest { value -> progressBar.setProgress(value) }
} }
@ -179,7 +168,7 @@ class WebtoonPageHolder(
* *
* @param status the new status of the page. * @param status the new status of the page.
*/ */
private fun processStatus(status: Page.State) { private suspend fun processStatus(status: Page.State) {
when (status) { when (status) {
Page.State.QUEUE -> setQueued() Page.State.QUEUE -> setQueued()
Page.State.LOAD_PAGE -> setLoading() Page.State.LOAD_PAGE -> setLoading()
@ -203,9 +192,6 @@ class WebtoonPageHolder(
*/ */
private fun cancelLoadJob() { private fun cancelLoadJob() {
loadJob?.cancel() loadJob?.cancel()
loadJob = null
statusJob?.cancel()
statusJob = null
} }
/** /**
@ -213,15 +199,6 @@ class WebtoonPageHolder(
*/ */
private fun cancelProgressJob() { private fun cancelProgressJob() {
progressJob?.cancel() progressJob?.cancel()
progressJob = null
}
/**
* Unsubscribes from the read image header subscription.
*/
private fun unsubscribeReadImageHeader() {
removeSubscription(readImageHeaderSubscription)
readImageHeaderSubscription = null
} }
/** /**
@ -257,48 +234,40 @@ class WebtoonPageHolder(
/** /**
* Called when the page is ready. * Called when the page is ready.
*/ */
private fun setImage() { private suspend fun setImage() {
progressContainer.isVisible = true progressContainer.isVisible = true
progressBar.isVisible = true progressBar.isVisible = true
progressBar.completeAndFadeOut() progressBar.completeAndFadeOut()
retryContainer?.isVisible = false retryContainer?.isVisible = false
removeDecodeErrorLayout() removeDecodeErrorLayout()
unsubscribeReadImageHeader()
val streamFn = page?.stream ?: return val streamFn = page?.stream ?: return
var openStream: InputStream? = null val (openStream, isAnimated) = withIOContext {
readImageHeaderSubscription = Observable val stream = streamFn().buffered(16)
.fromCallable { val openStream = process(stream)
val stream = streamFn().buffered(16)
openStream = process(stream)
ImageUtil.isAnimatedAndSupported(stream) val isAnimated = ImageUtil.isAnimatedAndSupported(stream)
} Pair(openStream, isAnimated)
.subscribeOn(Schedulers.io()) }
.observeOn(AndroidSchedulers.mainThread())
.doOnNext { isAnimated ->
frame.setImage(
openStream!!,
isAnimated,
ReaderPageImageView.Config(
zoomDuration = viewer.config.doubleTapAnimDuration,
minimumScaleType = SubsamplingScaleImageView.SCALE_TYPE_FIT_WIDTH,
cropBorders =
if (viewer.hasMargins) {
viewer.config.verticalCropBorders
} else {
viewer.config.webtoonCropBorders
},
),
)
}
// Keep the Rx stream alive to close the input stream only when unsubscribed
.flatMap { Observable.never<Unit>() }
.doOnUnsubscribe { openStream?.close() }
.subscribe({}, {})
addSubscription(readImageHeaderSubscription) withUIContext {
frame.setImage(
openStream,
isAnimated,
ReaderPageImageView.Config(
zoomDuration = viewer.config.doubleTapAnimDuration,
minimumScaleType = SubsamplingScaleImageView.SCALE_TYPE_FIT_WIDTH,
cropBorders = viewer.config.run {
if (viewer.hasMargins) { verticalCropBorders } else { webtoonCropBorders }
},
),
)
}
// Suspend the coroutine to close the input stream only when the WebtoonPageHolder is recycled
suspendCancellableCoroutine<Nothing> { continuation ->
continuation.invokeOnCancellation { openStream.close() }
}
} }
private fun process(imageStream: BufferedInputStream): InputStream { private fun process(imageStream: BufferedInputStream): InputStream {