Fix recycled item's height being 0 in webtoon mode
Refactor reader page holder and miscellaneous cleanups
This commit is contained in:
1 parent
73afe05a18
commit
1e97407936
5 files changed
+45
-188
No files matched your search
+2
-21
@@ -1336,8 +1336,7 @@ open class SubsamplingScaleImageView @JvmOverloads constructor(
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a listener allowing notification of load and error events. Extend [DefaultOnImageEventListener]
|
||||
* to simplify implementation.
|
||||
* Add a listener allowing notification of load and error events.
|
||||
*
|
||||
* @param onImageEventListener an [OnImageEventListener] instance.
|
||||
*/
|
||||
@@ -1391,7 +1390,7 @@ open class SubsamplingScaleImageView @JvmOverloads constructor(
|
||||
/**
|
||||
* An event listener, allowing subclasses and activities to be notified of significant events.
|
||||
*/
|
||||
interface OnImageEventListener {
|
||||
fun interface OnImageEventListener {
|
||||
/**
|
||||
* Called when the dimensions of the image and view are known, and either a preview image,
|
||||
* the full size image, or base layer tiles are loaded. This indicates the scale and translate
|
||||
@@ -1399,16 +1398,6 @@ open class SubsamplingScaleImageView @JvmOverloads constructor(
|
||||
* graphic, or inform a subclass that it is safe to draw overlays.
|
||||
*/
|
||||
fun onReady()
|
||||
|
||||
/**
|
||||
* Indicates an error initiliasing the decoder when using a tiling, or when loading the full
|
||||
* size bitmap when tiling is disabled. This method cannot be relied upon; certain encoding
|
||||
* types of supported image formats can result in corrupt or blank images being loaded and
|
||||
* displayed with no detectable error.
|
||||
*
|
||||
* @param e The exception thrown. This error is also logged by the view.
|
||||
*/
|
||||
fun onImageLoadError(e: Exception)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1467,14 +1456,6 @@ open class SubsamplingScaleImageView @JvmOverloads constructor(
|
||||
|
||||
private data class ScaleAndTranslate(var scale: Float, val vTranslate: PointF)
|
||||
|
||||
/**
|
||||
* Default implementation of [OnImageEventListener] for extension. This does nothing in any method.
|
||||
*/
|
||||
open class DefaultOnImageEventListener : OnImageEventListener {
|
||||
override fun onReady() {}
|
||||
override fun onImageLoadError(e: Exception) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder class used to set additional options for a scale animation. Create an instance using [.animateScale],
|
||||
* then set your options and call [.start].
|
||||
|
||||
@@ -53,9 +53,7 @@ open class ReaderPageImageView @JvmOverloads constructor(
|
||||
private var config: Config? = null
|
||||
|
||||
var onImageLoaded: (() -> Unit)? = null
|
||||
var onImageLoadError: (() -> Unit)? = null
|
||||
var onScaleChanged: ((newScale: Float) -> Unit)? = null
|
||||
var onViewClicked: (() -> Unit)? = null
|
||||
|
||||
/**
|
||||
* For automatic background. Will be set as background color when [onImageLoaded] is called.
|
||||
@@ -68,40 +66,22 @@ open class ReaderPageImageView @JvmOverloads constructor(
|
||||
background = pageBackground
|
||||
}
|
||||
|
||||
@CallSuper
|
||||
open fun onImageLoadError() {
|
||||
onImageLoadError?.invoke()
|
||||
}
|
||||
|
||||
@CallSuper
|
||||
open fun onScaleChanged(newScale: Float) {
|
||||
onScaleChanged?.invoke(newScale)
|
||||
}
|
||||
|
||||
@CallSuper
|
||||
open fun onViewClicked() {
|
||||
onViewClicked?.invoke()
|
||||
}
|
||||
|
||||
open fun onPageSelected(forward: Boolean) {
|
||||
with(pageView as? SubsamplingScaleImageView) {
|
||||
if (this == null) return
|
||||
if (isReady) {
|
||||
landscapeZoom(forward)
|
||||
} else {
|
||||
setOnImageEventListener(
|
||||
object : SubsamplingScaleImageView.DefaultOnImageEventListener() {
|
||||
override fun onReady() {
|
||||
setupZoom(config)
|
||||
landscapeZoom(forward)
|
||||
this@ReaderPageImageView.onImageLoaded()
|
||||
}
|
||||
|
||||
override fun onImageLoadError(e: Exception) {
|
||||
onImageLoadError()
|
||||
}
|
||||
},
|
||||
)
|
||||
setOnImageEventListener {
|
||||
setupZoom(config)
|
||||
landscapeZoom(forward)
|
||||
this@ReaderPageImageView.onImageLoaded()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -221,7 +201,6 @@ open class ReaderPageImageView @JvmOverloads constructor(
|
||||
}
|
||||
},
|
||||
)
|
||||
setOnClickListener { this@ReaderPageImageView.onViewClicked() }
|
||||
}
|
||||
addView(pageView, MATCH_PARENT, MATCH_PARENT)
|
||||
}
|
||||
@@ -248,19 +227,11 @@ open class ReaderPageImageView @JvmOverloads constructor(
|
||||
setMinimumScaleType(config.minimumScaleType)
|
||||
setMinimumDpi(1) // Just so that very small image will be fit for initial load
|
||||
setCropBorders(config.cropBorders)
|
||||
setOnImageEventListener(
|
||||
object : SubsamplingScaleImageView.DefaultOnImageEventListener() {
|
||||
override fun onReady() {
|
||||
setupZoom(config)
|
||||
if (isVisibleOnScreen()) landscapeZoom(true)
|
||||
this@ReaderPageImageView.onImageLoaded()
|
||||
}
|
||||
|
||||
override fun onImageLoadError(e: Exception) {
|
||||
this@ReaderPageImageView.onImageLoadError()
|
||||
}
|
||||
},
|
||||
)
|
||||
setOnImageEventListener {
|
||||
setupZoom(config)
|
||||
if (isVisibleOnScreen()) landscapeZoom(true)
|
||||
this@ReaderPageImageView.onImageLoaded()
|
||||
}
|
||||
|
||||
setImage(image, bounds)
|
||||
isVisible = true
|
||||
@@ -292,11 +263,6 @@ open class ReaderPageImageView @JvmOverloads constructor(
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onSingleTapConfirmed(e: MotionEvent): Boolean {
|
||||
this@ReaderPageImageView.onViewClicked()
|
||||
return super.onSingleTapConfirmed(e)
|
||||
}
|
||||
},
|
||||
)
|
||||
setOnScaleChangeListener { _, _, _ ->
|
||||
|
||||
+13
-5
@@ -2,15 +2,16 @@ package eu.kanade.tachiyomi.ui.reader.viewer
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.Gravity
|
||||
import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
import android.widget.FrameLayout
|
||||
import androidx.annotation.IntRange
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableFloatStateOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.AbstractComposeView
|
||||
import androidx.compose.ui.platform.ViewCompositionStrategy
|
||||
import androidx.core.view.isVisible
|
||||
@@ -23,7 +24,6 @@ class ReaderProgressIndicator @JvmOverloads constructor(
|
||||
) : AbstractComposeView(context, attrs, defStyleAttr) {
|
||||
|
||||
init {
|
||||
layoutParams = FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT, Gravity.CENTER)
|
||||
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnDetachedFromWindowOrReleasedFromPool)
|
||||
}
|
||||
|
||||
@@ -33,7 +33,9 @@ class ReaderProgressIndicator @JvmOverloads constructor(
|
||||
@Composable
|
||||
override fun Content() {
|
||||
EhTheme {
|
||||
if (visible) CombinedCircularProgressIndicator(progress = progress)
|
||||
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
|
||||
if (visible) CombinedCircularProgressIndicator(progress = progress)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,6 +49,12 @@ class ReaderProgressIndicator @JvmOverloads constructor(
|
||||
isVisible = false
|
||||
}
|
||||
|
||||
fun reset() {
|
||||
progress = 0f
|
||||
visible = false
|
||||
isVisible = true
|
||||
}
|
||||
|
||||
fun setProgress(@IntRange(from = 0, to = 100) progress: Int) {
|
||||
this.progress = progress / 100f
|
||||
}
|
||||
|
||||
@@ -49,11 +49,6 @@ class PagerPageHolder(
|
||||
*/
|
||||
private var statusJob: Job? = null
|
||||
|
||||
/**
|
||||
* Job for progress changes of the page.
|
||||
*/
|
||||
private var progressJob: Job? = null
|
||||
|
||||
init {
|
||||
addView(progressIndicator)
|
||||
statusJob = scope.launch(Dispatchers.Main) {
|
||||
@@ -69,39 +64,25 @@ class PagerPageHolder(
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
override fun onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow()
|
||||
cancelProgressJob()
|
||||
unsubscribeStatus()
|
||||
progressIndicator.hide()
|
||||
}
|
||||
|
||||
private fun launchProgressJob() {
|
||||
progressJob?.cancel()
|
||||
progressJob = scope.launch(Dispatchers.Main) {
|
||||
page.progressFlow.collectLatest { value -> progressIndicator.setProgress(value) }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the status of the page changes.
|
||||
*
|
||||
* @param status the new status of the page.
|
||||
*/
|
||||
private fun processStatus(status: Page.State) {
|
||||
private suspend fun processStatus(status: Page.State) {
|
||||
when (status) {
|
||||
Page.State.QUEUE -> setQueued()
|
||||
Page.State.LOAD_PAGE -> setLoading()
|
||||
Page.State.DOWNLOAD_IMAGE -> {
|
||||
launchProgressJob()
|
||||
setDownloading()
|
||||
page.progressFlow.collectLatest { value -> progressIndicator.setProgress(value) }
|
||||
}
|
||||
Page.State.READY -> {
|
||||
page.image?.let { setImage(it) }
|
||||
cancelProgressJob()
|
||||
}
|
||||
Page.State.ERROR -> {
|
||||
setError()
|
||||
cancelProgressJob()
|
||||
}
|
||||
Page.State.READY -> page.image?.let { setImage(it) } ?: setError()
|
||||
Page.State.ERROR -> setError()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,11 +94,6 @@ class PagerPageHolder(
|
||||
statusJob = null
|
||||
}
|
||||
|
||||
private fun cancelProgressJob() {
|
||||
progressJob?.cancel()
|
||||
progressJob = null
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the page is queued.
|
||||
*/
|
||||
@@ -149,8 +125,6 @@ class PagerPageHolder(
|
||||
*/
|
||||
private fun setImage(image: Image) {
|
||||
progressIndicator.setProgress(0)
|
||||
progressIndicator.hide()
|
||||
removeErrorLayout()
|
||||
setImage(
|
||||
image,
|
||||
Config(
|
||||
@@ -177,15 +151,7 @@ class PagerPageHolder(
|
||||
override fun onImageLoaded() {
|
||||
super.onImageLoaded()
|
||||
progressIndicator.hide()
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when an image fails to decode.
|
||||
*/
|
||||
override fun onImageLoadError() {
|
||||
super.onImageLoadError()
|
||||
progressIndicator.hide()
|
||||
showErrorLayout()
|
||||
removeErrorLayout()
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+15
-79
@@ -1,11 +1,9 @@
|
||||
package eu.kanade.tachiyomi.ui.reader.viewer.webtoon
|
||||
|
||||
import android.content.res.Resources
|
||||
import android.view.ViewGroup
|
||||
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
|
||||
import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
import android.widget.FrameLayout
|
||||
import androidx.core.view.isVisible
|
||||
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
|
||||
import com.hippo.ehviewer.image.Image
|
||||
import eu.kanade.tachiyomi.source.model.Page
|
||||
@@ -34,14 +32,10 @@ class WebtoonPageHolder(
|
||||
|
||||
/**
|
||||
* Loading progress bar to indicate the current progress.
|
||||
* Needed to keep a minimum height size of the holder, otherwise the adapter would create more
|
||||
* views to fill the screen, which is not wanted.
|
||||
*/
|
||||
private val progressIndicator = createProgressIndicator()
|
||||
|
||||
/**
|
||||
* Progress bar container. Needed to keep a minimum height size of the holder, otherwise the
|
||||
* adapter would create more views to fill the screen, which is not wanted.
|
||||
*/
|
||||
private lateinit var progressContainer: ViewGroup
|
||||
private val progressIndicator = ReaderProgressIndicator(context)
|
||||
|
||||
/**
|
||||
* Error layout to show when the image fails to load.
|
||||
@@ -57,7 +51,7 @@ class WebtoonPageHolder(
|
||||
/**
|
||||
* Page of a chapter.
|
||||
*/
|
||||
private var page: ReaderPage? = null
|
||||
private lateinit var page: ReaderPage
|
||||
|
||||
private val scope = CoroutineScope(Dispatchers.IO)
|
||||
|
||||
@@ -66,16 +60,11 @@ class WebtoonPageHolder(
|
||||
*/
|
||||
private var statusJob: Job? = null
|
||||
|
||||
/**
|
||||
* Job for progress changes of the page.
|
||||
*/
|
||||
private var progressJob: Job? = null
|
||||
|
||||
init {
|
||||
frame.addView(progressIndicator, MATCH_PARENT, defaultHeight)
|
||||
refreshLayoutParams()
|
||||
|
||||
frame.onImageLoaded = { onImageDecoded() }
|
||||
frame.onImageLoadError = { onImageDecodeError() }
|
||||
frame.onScaleChanged = { viewer.activity.hideMenu() }
|
||||
}
|
||||
|
||||
@@ -110,25 +99,11 @@ class WebtoonPageHolder(
|
||||
*/
|
||||
override fun recycle() {
|
||||
statusJob?.cancel()
|
||||
cancelProgressJob()
|
||||
progressIndicator.hide()
|
||||
statusJob = null
|
||||
|
||||
removeErrorLayout()
|
||||
frame.recycle()
|
||||
progressIndicator.setProgress(0)
|
||||
}
|
||||
|
||||
/**
|
||||
* Observes the progress of the page and updates view.
|
||||
*/
|
||||
private fun launchProgressJob() {
|
||||
cancelProgressJob()
|
||||
|
||||
val page = page ?: return
|
||||
|
||||
progressJob = scope.launch(Dispatchers.Main) {
|
||||
page.progressFlow.collectLatest { value -> progressIndicator.setProgress(value) }
|
||||
}
|
||||
progressIndicator.reset()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -136,38 +111,23 @@ class WebtoonPageHolder(
|
||||
*
|
||||
* @param status the new status of the page.
|
||||
*/
|
||||
private fun processStatus(status: Page.State) {
|
||||
private suspend fun processStatus(status: Page.State) {
|
||||
when (status) {
|
||||
Page.State.QUEUE -> setQueued()
|
||||
Page.State.LOAD_PAGE -> setLoading()
|
||||
Page.State.DOWNLOAD_IMAGE -> {
|
||||
launchProgressJob()
|
||||
setDownloading()
|
||||
page.progressFlow.collectLatest { value -> progressIndicator.setProgress(value) }
|
||||
}
|
||||
Page.State.READY -> {
|
||||
page?.image?.let { setImage(it) }
|
||||
cancelProgressJob()
|
||||
}
|
||||
Page.State.ERROR -> {
|
||||
setError()
|
||||
cancelProgressJob()
|
||||
}
|
||||
Page.State.READY -> page.image?.let { setImage(it) } ?: setError()
|
||||
Page.State.ERROR -> setError()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsubscribes from the progress subscription.
|
||||
*/
|
||||
private fun cancelProgressJob() {
|
||||
progressJob?.cancel()
|
||||
progressJob = null
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the page is queued.
|
||||
*/
|
||||
private fun setQueued() {
|
||||
progressContainer.isVisible = true
|
||||
progressIndicator.setProgress(0)
|
||||
progressIndicator.show()
|
||||
removeErrorLayout()
|
||||
@@ -178,7 +138,6 @@ class WebtoonPageHolder(
|
||||
* Called when the page is loading.
|
||||
*/
|
||||
private fun setLoading() {
|
||||
progressContainer.isVisible = true
|
||||
progressIndicator.show()
|
||||
removeErrorLayout()
|
||||
}
|
||||
@@ -187,7 +146,6 @@ class WebtoonPageHolder(
|
||||
* Called when the page is downloading
|
||||
*/
|
||||
private fun setDownloading() {
|
||||
progressContainer.isVisible = true
|
||||
progressIndicator.show()
|
||||
removeErrorLayout()
|
||||
}
|
||||
@@ -197,8 +155,6 @@ class WebtoonPageHolder(
|
||||
*/
|
||||
private fun setImage(drawable: Image) {
|
||||
progressIndicator.setProgress(0)
|
||||
progressIndicator.hide()
|
||||
removeErrorLayout()
|
||||
frame.setImage(
|
||||
drawable,
|
||||
ReaderPageImageView.Config(
|
||||
@@ -214,7 +170,6 @@ class WebtoonPageHolder(
|
||||
*/
|
||||
private fun setError() {
|
||||
progressIndicator.hide()
|
||||
progressContainer.isVisible = false
|
||||
initErrorLayout()
|
||||
}
|
||||
|
||||
@@ -222,27 +177,8 @@ class WebtoonPageHolder(
|
||||
* Called when the image is decoded and going to be displayed.
|
||||
*/
|
||||
private fun onImageDecoded() {
|
||||
progressContainer.isVisible = false
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the image fails to decode.
|
||||
*/
|
||||
private fun onImageDecodeError() {
|
||||
progressContainer.isVisible = false
|
||||
initErrorLayout()
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new progress bar.
|
||||
*/
|
||||
private fun createProgressIndicator(): ReaderProgressIndicator {
|
||||
progressContainer = FrameLayout(context)
|
||||
frame.addView(progressContainer, MATCH_PARENT, defaultHeight)
|
||||
|
||||
val progress = ReaderProgressIndicator(context)
|
||||
progressContainer.addView(progress)
|
||||
return progress
|
||||
progressIndicator.hide()
|
||||
removeErrorLayout()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -250,8 +186,8 @@ class WebtoonPageHolder(
|
||||
*/
|
||||
private fun initErrorLayout() {
|
||||
if (errorLayout == null) {
|
||||
errorLayout = ReaderErrorLayout(context, page!!.errorMsg) {
|
||||
viewer.activity.retryPage(page!!.index)
|
||||
errorLayout = ReaderErrorLayout(context, page.errorMsg) {
|
||||
viewer.activity.retryPage(page.index)
|
||||
}.also {
|
||||
frame.addView(it)
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user