diff --git a/app/src/main/kotlin/com/davemorrissey/labs/subscaleview/SubsamplingScaleImageView.kt b/app/src/main/kotlin/com/davemorrissey/labs/subscaleview/SubsamplingScaleImageView.kt index ec0873df4..517b81f47 100644 --- a/app/src/main/kotlin/com/davemorrissey/labs/subscaleview/SubsamplingScaleImageView.kt +++ b/app/src/main/kotlin/com/davemorrissey/labs/subscaleview/SubsamplingScaleImageView.kt @@ -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]. diff --git a/app/src/main/kotlin/eu/kanade/tachiyomi/ui/reader/viewer/ReaderPageImageView.kt b/app/src/main/kotlin/eu/kanade/tachiyomi/ui/reader/viewer/ReaderPageImageView.kt index 39301d1e2..03641d9ab 100644 --- a/app/src/main/kotlin/eu/kanade/tachiyomi/ui/reader/viewer/ReaderPageImageView.kt +++ b/app/src/main/kotlin/eu/kanade/tachiyomi/ui/reader/viewer/ReaderPageImageView.kt @@ -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 { _, _, _ -> diff --git a/app/src/main/kotlin/eu/kanade/tachiyomi/ui/reader/viewer/ReaderProgressIndicator.kt b/app/src/main/kotlin/eu/kanade/tachiyomi/ui/reader/viewer/ReaderProgressIndicator.kt index 0fb714cec..d3f2cefc3 100644 --- a/app/src/main/kotlin/eu/kanade/tachiyomi/ui/reader/viewer/ReaderProgressIndicator.kt +++ b/app/src/main/kotlin/eu/kanade/tachiyomi/ui/reader/viewer/ReaderProgressIndicator.kt @@ -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 } diff --git a/app/src/main/kotlin/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerPageHolder.kt b/app/src/main/kotlin/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerPageHolder.kt index 03c8c76d9..1ab5cf6fa 100644 --- a/app/src/main/kotlin/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerPageHolder.kt +++ b/app/src/main/kotlin/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerPageHolder.kt @@ -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() } /** diff --git a/app/src/main/kotlin/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonPageHolder.kt b/app/src/main/kotlin/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonPageHolder.kt index 6f487050f..e1884da5f 100644 --- a/app/src/main/kotlin/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonPageHolder.kt +++ b/app/src/main/kotlin/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonPageHolder.kt @@ -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) }