revert: Revert PagerPageHolder refactor

This commit is contained in:
Ahmad Ansori Palembani 2024-06-12 12:22:23 +07:00
parent 2a95f3d60d
commit a2a36ca839
Signed by: null2264
GPG key ID: BA64F8B60AF3EFB6

View file

@ -33,13 +33,11 @@ import eu.kanade.tachiyomi.util.system.ImageUtil.isPagePadded
import eu.kanade.tachiyomi.util.system.ThemeUtil import eu.kanade.tachiyomi.util.system.ThemeUtil
import eu.kanade.tachiyomi.util.system.bottomCutoutInset import eu.kanade.tachiyomi.util.system.bottomCutoutInset
import eu.kanade.tachiyomi.util.system.dpToPx import eu.kanade.tachiyomi.util.system.dpToPx
import eu.kanade.tachiyomi.util.system.e
import eu.kanade.tachiyomi.util.system.getResourceColor import eu.kanade.tachiyomi.util.system.getResourceColor
import eu.kanade.tachiyomi.util.system.isInNightMode import eu.kanade.tachiyomi.util.system.isInNightMode
import eu.kanade.tachiyomi.util.system.launchIO import eu.kanade.tachiyomi.util.system.launchIO
import eu.kanade.tachiyomi.util.system.launchUI import eu.kanade.tachiyomi.util.system.launchUI
import eu.kanade.tachiyomi.util.system.topCutoutInset import eu.kanade.tachiyomi.util.system.topCutoutInset
import eu.kanade.tachiyomi.util.system.withIOContext
import eu.kanade.tachiyomi.util.system.withUIContext import eu.kanade.tachiyomi.util.system.withUIContext
import eu.kanade.tachiyomi.util.view.backgroundColor import eu.kanade.tachiyomi.util.view.backgroundColor
import eu.kanade.tachiyomi.util.view.isVisibleOnScreen import eu.kanade.tachiyomi.util.view.isVisibleOnScreen
@ -50,13 +48,13 @@ 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 kotlinx.coroutines.supervisorScope
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import okio.Buffer import okio.Buffer
import okio.BufferedSource import okio.BufferedSource
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
import java.io.InputStream import java.io.InputStream
import kotlin.math.min import kotlin.math.min
import kotlin.math.roundToInt
/** /**
* View of the ViewPager that contains a page of a chapter. * View of the ViewPager that contains a page of a chapter.
@ -89,12 +87,41 @@ class PagerPageHolder(
*/ */
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.
*/
private var progressJob: Job? = null
/** /**
* Job for loading the page. * Job for loading the page.
*/ */
private var extraLoadJob: Job? = null private var extraLoadJob: Job? = null
/**
* Job for status changes of the page.
*/
private var extraStatusJob: Job? = null
/**
* Job for progress changes of the page.
*/
private var extraProgressJob: Job? = null
/**
* Job 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 readImageHeaderJob: Job? = null
private var status = Page.State.READY private var status = Page.State.READY
private var extraStatus = Page.State.READY
private var progress: Int = 0
private var extraProgress: Int = 0
private var scope = MainScope() private var scope = MainScope()
@ -105,8 +132,7 @@ class PagerPageHolder(
marginStart = ((context.resources.displayMetrics.widthPixels) / 2 + viewer.config.hingeGapSize) / 2 marginStart = ((context.resources.displayMetrics.widthPixels) / 2 + viewer.config.hingeGapSize) / 2
} }
} }
loadJob = scope.launch { loadPageAndProcessStatus(1) } launchLoadJob()
extraLoadJob = scope.launch { loadPageAndProcessStatus(2) }
setBackgroundColor( setBackgroundColor(
when (val theme = viewer.config.readerTheme) { when (val theme = viewer.config.readerTheme) {
ReaderBackgroundColor.SMART_THEME.prefValue -> Color.TRANSPARENT ReaderBackgroundColor.SMART_THEME.prefValue -> Color.TRANSPARENT
@ -163,15 +189,64 @@ class PagerPageHolder(
*/ */
override fun onDetachedFromWindow() { override fun onDetachedFromWindow() {
super.onDetachedFromWindow() super.onDetachedFromWindow()
cancelProgressJob(1)
loadJob?.cancel() cancelLoadJob(1)
loadJob = null cancelProgressJob(2)
extraLoadJob?.cancel() cancelLoadJob(2)
extraLoadJob = null cancelReadImageHeader()
(pageView as? SubsamplingScaleImageView)?.setOnImageEventListener(null) (pageView as? SubsamplingScaleImageView)?.setOnImageEventListener(null)
} }
/**
* Starts loading the page and processing changes to the page's status.
*
* @see processStatus
*/
private fun launchLoadJob() {
loadJob?.cancel()
statusJob?.cancel()
val loader = page.chapter.pageLoader ?: return
loadJob = scope.launch {
loader.loadPage(page)
}
statusJob = scope.launch {
page.statusFlow.collectLatest { processStatus(it) }
}
val extraPage = extraPage ?: return
extraLoadJob = scope.launch {
loader.loadPage(extraPage)
}
extraStatusJob = scope.launch {
extraPage.statusFlow.collectLatest { processStatus2(it) }
}
}
private fun launchProgressJob() {
progressJob?.cancel()
progressJob = scope.launch {
page.progressFlow.collectLatest { value ->
progress = value
if (extraPage == null) {
progressBar.setProgress(progress)
} else {
progressBar.setProgress(((progress + extraProgress) / 2 * 0.95f).roundToInt())
}
}
}
}
private fun launchProgressJob2() {
val extraPage = extraPage ?: return
extraProgressJob?.cancel()
extraProgressJob = scope.launch {
extraPage.progressFlow.collectLatest { value ->
extraProgress = value
progressBar.setProgress(((progress + extraProgress) / 2 * 0.95f).roundToInt())
}
}
}
fun onPageSelected(forward: Boolean?) { fun onPageSelected(forward: Boolean?) {
(pageView as? SubsamplingScaleImageView)?.apply { (pageView as? SubsamplingScaleImageView)?.apply {
if (isReady) { if (isReady) {
@ -282,29 +357,90 @@ class PagerPageHolder(
} }
} }
private suspend fun loadPageAndProcessStatus(index: Int) { /**
val page = (if (index == 1) page else extraPage) ?: return * Called when the status of the page changes.
*
val loader = page.chapter.pageLoader ?: return * @param status the new status of the page.
supervisorScope { */
launchIO { private fun processStatus(status: Page.State) {
loader.loadPage(page)
}
page.statusFlow.collectLatest {
when (status) { when (status) {
Page.State.QUEUE -> setQueued() Page.State.QUEUE -> setQueued()
Page.State.LOAD_PAGE -> setLoading() Page.State.LOAD_PAGE -> setLoading()
Page.State.DOWNLOAD_IMAGE -> { Page.State.DOWNLOAD_IMAGE -> {
launchProgressJob()
setDownloading() setDownloading()
page.progressFlow.collectLatest { value ->
progressBar.setProgress(value)
} }
Page.State.READY -> {
if (extraStatus == Page.State.READY || extraPage == null) {
setImage()
} }
Page.State.READY -> setImage() cancelProgressJob(1)
Page.State.ERROR -> setError() }
Page.State.ERROR -> {
setError()
cancelProgressJob(1)
} }
} }
} }
/**
* Called when the status of the page changes.
*
* @param status the new status of the page.
*/
private fun processStatus2(status: Page.State) {
when (status) {
Page.State.QUEUE -> setQueued()
Page.State.LOAD_PAGE -> setLoading()
Page.State.DOWNLOAD_IMAGE -> {
launchProgressJob2()
setDownloading()
}
Page.State.READY -> {
if (this.status == Page.State.READY) {
setImage()
}
cancelProgressJob(2)
}
Page.State.ERROR -> {
setError()
cancelProgressJob(2)
}
}
}
/**
* Cancels loading the page and processing changes to the page's status.
*/
private fun cancelLoadJob(page: Int) {
if (page == 1) {
loadJob?.cancel()
loadJob = null
statusJob?.cancel()
statusJob = null
} else {
extraLoadJob?.cancel()
extraLoadJob = null
extraStatusJob?.cancel()
extraStatusJob = null
}
}
private fun cancelProgressJob(page: Int) {
(if (page == 1) progressJob else extraProgressJob)?.cancel()
if (page == 1) {
progressJob = null
} else {
extraProgressJob = null
}
}
/**
* Unsubscribes from the read image header subscription.
*/
private fun cancelReadImageHeader() {
readImageHeaderJob?.cancel()
readImageHeaderJob = null
} }
/** /**
@ -334,71 +470,68 @@ class PagerPageHolder(
/** /**
* Called when the page is ready. * Called when the page is ready.
*/ */
private suspend fun setImage() { private fun setImage() {
progressBar.isVisible = true progressBar.isVisible = true
if (extraPage == null) { if (extraPage == null) {
progressBar.setProgress(0) progressBar.completeAndFadeOut()
} else { } else {
progressBar.setProgress(95) progressBar.setProgress(95)
} }
errorLayout?.isVisible = false errorLayout?.isVisible = false
val streamFn = page.stream ?: return cancelReadImageHeader()
readImageHeaderJob = scope.launchIO {
val streamFn = page.stream ?: return@launchIO
val streamFn2 = extraPage?.stream val streamFn2 = extraPage?.stream
var actualSource: BufferedSource? = null
try { try {
val (source, isAnimated, _bg) = withIOContext { val source1 = streamFn().buffered(16).use { Buffer().readFrom(it) }
streamFn().buffered(16).use { source1 -> val source2 = streamFn2?.invoke()?.buffered(16)?.use { Buffer().readFrom(it) }
if (extraPage != null) {
streamFn2?.invoke()
?.buffered(16)
} else {
null
}.use { source2 ->
val actualSource = this@PagerPageHolder.mergeOrSplitPages(
Buffer().readFrom(source1),
source2?.let { Buffer().readFrom(it) },
)
val isAnimated = ImageUtil.isAnimatedAndSupported(actualSource) actualSource = this@PagerPageHolder.mergeOrSplitPages(source1, source2)
val isAnimated = ImageUtil.isAnimatedAndSupported(source1) ||
(source2?.let { ImageUtil.isAnimatedAndSupported(source2) } ?: false)
withUIContext {
val bgColor = ReaderBackgroundColor.fromPreference(viewer.config.readerTheme) val bgColor = ReaderBackgroundColor.fromPreference(viewer.config.readerTheme)
val bgType = getBGType(viewer.config.readerTheme, context)
val background = if (bgColor.isSmartColor) {
if (!isAnimated) { if (!isAnimated) {
if (page.bg != null && page.bgType == bgType) page.bg if (bgColor.isSmartColor) {
val bgType = getBGType(viewer.config.readerTheme, context)
if (page.bg != null && page.bgType == bgType) {
setImage(actualSource, false, imageConfig)
pageView?.background = page.bg
}
// if the user switches to automatic when pages are already cached, the bg needs to be loaded
else { else {
val background =
try { try {
setBG(actualSource.peek().inputStream()) setBG(actualSource.peek().inputStream())
} catch (e: Exception) { } catch (e: Exception) {
Logger.e(e) { e.localizedMessage?.toString() ?: "" } Logger.e(e) { e.localizedMessage?.toString() ?: "" }
ColorDrawable(Color.WHITE) ColorDrawable(Color.WHITE)
} }
} setImage(actualSource, false, imageConfig)
} else {
page.bg
}
} else {
null
}
Triple(actualSource, isAnimated, Pair(background, bgType)) pageView?.background = background
}
}
}
withUIContext {
val (bg, bgType) = _bg
if (bg != null) {
pageView?.background = bg
page.bg = pageView?.background page.bg = pageView?.background
if (!isAnimated) page.bgType = bgType page.bgType = bgType
} }
setImage(source, isAnimated, imageConfig) } else {
setImage(actualSource, false, imageConfig)
}
} else {
setImage(actualSource, true, imageConfig)
if (bgColor.isSmartColor && page.bg != null) {
pageView?.background = page.bg
}
}
}
} catch (_: Exception) {
try {
actualSource?.let { closeSources(it) }
} catch (_: Exception) {
} }
} catch (e: Exception) {
Logger.e(e)
withUIContext {
setError()
} }
} }
} }