From 7108993936f440e6ad7fa927966b4963ec913124 Mon Sep 17 00:00:00 2001 From: Ivan Iskandar <12537387+ivaniskandar@users.noreply.github.com> Date: Thu, 3 Feb 2022 09:41:20 +0700 Subject: [PATCH] Unify reader error layout (#6512) So nobody will think that the error layout is broken when they see different layout. --- .../ui/reader/viewer/ReaderButton.kt | 29 +++++ .../ui/reader/viewer/pager/PagerButton.kt | 24 ---- .../ui/reader/viewer/pager/PagerPageHolder.kt | 112 ++++------------ .../viewer/pager/PagerTransitionHolder.kt | 6 +- .../viewer/webtoon/WebtoonPageHolder.kt | 123 ++++-------------- app/src/main/res/layout/reader_error.xml | 31 +++++ 6 files changed, 111 insertions(+), 214 deletions(-) create mode 100644 app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ReaderButton.kt delete mode 100644 app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerButton.kt create mode 100644 app/src/main/res/layout/reader_error.xml diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ReaderButton.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ReaderButton.kt new file mode 100644 index 0000000000..5de966670f --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ReaderButton.kt @@ -0,0 +1,29 @@ +package eu.kanade.tachiyomi.ui.reader.viewer + +import android.content.Context +import android.util.AttributeSet +import android.view.MotionEvent +import com.google.android.material.button.MaterialButton +import eu.kanade.tachiyomi.R +import eu.kanade.tachiyomi.ui.reader.viewer.pager.PagerViewer + +/** + * A button class to be used by child views of the pager viewer. All tap gestures are handled by + * the pager, but this class disables that behavior to allow clickable buttons. + */ +class ReaderButton @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = R.attr.materialButtonStyle +) : MaterialButton(context, attrs, defStyleAttr) { + + var viewer: PagerViewer? = null + + override fun onTouchEvent(event: MotionEvent): Boolean { + viewer?.pager?.setGestureDetectorEnabled(false) + if (event.actionMasked == MotionEvent.ACTION_UP) { + viewer?.pager?.setGestureDetectorEnabled(true) + } + return super.onTouchEvent(event) + } +} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerButton.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerButton.kt deleted file mode 100644 index 0089ad5dc2..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerButton.kt +++ /dev/null @@ -1,24 +0,0 @@ -package eu.kanade.tachiyomi.ui.reader.viewer.pager - -import android.annotation.SuppressLint -import android.content.Context -import android.view.MotionEvent -import com.google.android.material.button.MaterialButton - -/** - * A button class to be used by child views of the pager viewer. All tap gestures are handled by - * the pager, but this class disables that behavior to allow clickable buttons. - */ -@SuppressLint("ViewConstructor") -class PagerButton(context: Context, viewer: PagerViewer) : MaterialButton(context) { - - init { - setOnTouchListener { _, event -> - viewer.pager.setGestureDetectorEnabled(false) - if (event.actionMasked == MotionEvent.ACTION_UP) { - viewer.pager.setGestureDetectorEnabled(true) - } - false - } - } -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerPageHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerPageHolder.kt index c2b4b7e322..e92de7dcf3 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerPageHolder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerPageHolder.kt @@ -3,14 +3,10 @@ package eu.kanade.tachiyomi.ui.reader.viewer.pager import android.annotation.SuppressLint import android.content.Context import android.view.Gravity -import android.view.ViewGroup -import android.view.ViewGroup.LayoutParams.WRAP_CONTENT -import android.widget.LinearLayout +import android.view.LayoutInflater import androidx.core.view.isVisible -import androidx.core.view.setMargins import androidx.core.view.updateLayoutParams -import com.google.android.material.textview.MaterialTextView -import eu.kanade.tachiyomi.R +import eu.kanade.tachiyomi.databinding.ReaderErrorBinding import eu.kanade.tachiyomi.source.model.Page import eu.kanade.tachiyomi.ui.reader.model.InsertPage import eu.kanade.tachiyomi.ui.reader.model.ReaderPage @@ -18,7 +14,6 @@ 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.system.ImageUtil -import eu.kanade.tachiyomi.util.system.dpToPx import eu.kanade.tachiyomi.widget.ViewPagerAdapter import rx.Observable import rx.Subscription @@ -54,14 +49,9 @@ class PagerPageHolder( } /** - * Retry button used to allow retrying. + * Error layout to show when the image fails to load. */ - private var retryButton: PagerButton? = null - - /** - * Error layout to show when the image fails to decode. - */ - private var decodeErrorLayout: ViewGroup? = null + private var errorLayout: ReaderErrorBinding? = null /** * Subscription for status changes of the page. @@ -176,8 +166,7 @@ class PagerPageHolder( */ private fun setQueued() { progressIndicator.show() - retryButton?.isVisible = false - decodeErrorLayout?.isVisible = false + errorLayout?.root?.isVisible = false } /** @@ -185,8 +174,7 @@ class PagerPageHolder( */ private fun setLoading() { progressIndicator.show() - retryButton?.isVisible = false - decodeErrorLayout?.isVisible = false + errorLayout?.root?.isVisible = false } /** @@ -194,8 +182,7 @@ class PagerPageHolder( */ private fun setDownloading() { progressIndicator.show() - retryButton?.isVisible = false - decodeErrorLayout?.isVisible = false + errorLayout?.root?.isVisible = false } /** @@ -203,8 +190,7 @@ class PagerPageHolder( */ private fun setImage() { progressIndicator.setProgress(0) - retryButton?.isVisible = false - decodeErrorLayout?.isVisible = false + errorLayout?.root?.isVisible = false unsubscribeReadImageHeader() val streamFn = page.stream ?: return @@ -299,7 +285,7 @@ class PagerPageHolder( */ private fun setError() { progressIndicator.hide() - initRetryButton().isVisible = true + showErrorLayout(withOpenInWebView = false) } override fun onImageLoaded() { @@ -313,7 +299,7 @@ class PagerPageHolder( override fun onImageLoadError() { super.onImageLoadError() progressIndicator.hide() - initDecodeErrorLayout().isVisible = true + showErrorLayout(withOpenInWebView = true) } /** @@ -324,78 +310,24 @@ class PagerPageHolder( viewer.activity.hideMenu() } - /** - * Initializes a button to retry pages. - */ - private fun initRetryButton(): PagerButton { - if (retryButton != null) return retryButton!! - - retryButton = PagerButton(context, viewer).apply { - layoutParams = LayoutParams(WRAP_CONTENT, WRAP_CONTENT).apply { - gravity = Gravity.CENTER - } - setText(R.string.action_retry) - setOnClickListener { + private fun showErrorLayout(withOpenInWebView: Boolean): ReaderErrorBinding { + if (errorLayout == null) { + errorLayout = ReaderErrorBinding.inflate(LayoutInflater.from(context), this, true) + errorLayout?.actionRetry?.viewer = viewer + errorLayout?.actionRetry?.setOnClickListener { page.chapter.pageLoader?.retryPage(page) } - } - addView(retryButton) - return retryButton!! - } - - /** - * Initializes a decode error layout. - */ - private fun initDecodeErrorLayout(): ViewGroup { - if (decodeErrorLayout != null) return decodeErrorLayout!! - - val margins = 8.dpToPx - - val decodeLayout = LinearLayout(context).apply { - gravity = Gravity.CENTER - orientation = LinearLayout.VERTICAL - } - decodeErrorLayout = decodeLayout - - MaterialTextView(context).apply { - layoutParams = LinearLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT).apply { - setMargins(margins) - } - gravity = Gravity.CENTER - setText(R.string.decode_image_error) - - decodeLayout.addView(this) - } - - PagerButton(context, viewer).apply { - layoutParams = LayoutParams(WRAP_CONTENT, WRAP_CONTENT).apply { - setMargins(margins) - } - setText(R.string.action_retry) - setOnClickListener { - page.chapter.pageLoader?.retryPage(page) - } - - decodeLayout.addView(this) - } - - val imageUrl = page.imageUrl - if (imageUrl.orEmpty().startsWith("http", true)) { - PagerButton(context, viewer).apply { - layoutParams = LayoutParams(WRAP_CONTENT, WRAP_CONTENT).apply { - setMargins(margins) - } - setText(R.string.action_open_in_web_view) - setOnClickListener { + val imageUrl = page.imageUrl + if (imageUrl.orEmpty().startsWith("http", true)) { + errorLayout?.actionOpenInWebView?.viewer = viewer + errorLayout?.actionOpenInWebView?.setOnClickListener { val intent = WebViewActivity.newIntent(context, imageUrl!!) context.startActivity(intent) } - - decodeLayout.addView(this) } } - - addView(decodeLayout) - return decodeLayout + errorLayout?.actionOpenInWebView?.isVisible = withOpenInWebView + errorLayout?.root?.isVisible = true + return errorLayout!! } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerTransitionHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerTransitionHolder.kt index c03585d226..3f97a212d6 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerTransitionHolder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerTransitionHolder.kt @@ -13,6 +13,7 @@ import com.google.android.material.progressindicator.CircularProgressIndicator import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.ui.reader.model.ChapterTransition import eu.kanade.tachiyomi.ui.reader.model.ReaderChapter +import eu.kanade.tachiyomi.ui.reader.viewer.ReaderButton import eu.kanade.tachiyomi.ui.reader.viewer.ReaderTransitionView import eu.kanade.tachiyomi.util.system.dpToPx import eu.kanade.tachiyomi.widget.ViewPagerAdapter @@ -126,13 +127,14 @@ class PagerTransitionHolder( text = context.getString(R.string.transition_pages_error, error.message) } - val retryBtn = PagerButton(context, viewer).apply { + val retryBtn = ReaderButton(context).apply { + viewer = this@PagerTransitionHolder.viewer wrapContent() setText(R.string.action_retry) setOnClickListener { val toChapter = transition.to if (toChapter != null) { - viewer.activity.requestPreloadChapter(toChapter) + this@PagerTransitionHolder.viewer.activity.requestPreloadChapter(toChapter) } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonPageHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonPageHolder.kt index 0674e7e63d..fecdfc9566 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonPageHolder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonPageHolder.kt @@ -2,18 +2,16 @@ package eu.kanade.tachiyomi.ui.reader.viewer.webtoon import android.content.res.Resources import android.view.Gravity +import android.view.LayoutInflater import android.view.ViewGroup import android.view.ViewGroup.LayoutParams.MATCH_PARENT import android.view.ViewGroup.LayoutParams.WRAP_CONTENT import android.widget.FrameLayout -import android.widget.LinearLayout import androidx.core.view.isVisible import androidx.core.view.updateLayoutParams import androidx.core.view.updateMargins import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView -import com.google.android.material.button.MaterialButton -import com.google.android.material.textview.MaterialTextView -import eu.kanade.tachiyomi.R +import eu.kanade.tachiyomi.databinding.ReaderErrorBinding import eu.kanade.tachiyomi.source.model.Page import eu.kanade.tachiyomi.ui.reader.model.ReaderPage import eu.kanade.tachiyomi.ui.reader.viewer.ReaderPageImageView @@ -52,14 +50,9 @@ class WebtoonPageHolder( private lateinit var progressContainer: ViewGroup /** - * Retry button container used to allow retrying. + * Error layout to show when the image fails to load. */ - private var retryContainer: ViewGroup? = null - - /** - * Error layout to show when the image fails to decode. - */ - private var decodeErrorLayout: ViewGroup? = null + private var errorLayout: ReaderErrorBinding? = null /** * Getter to retrieve the height of the recycler view. @@ -125,7 +118,7 @@ class WebtoonPageHolder( unsubscribeProgress() unsubscribeReadImageHeader() - removeDecodeErrorLayout() + removeErrorLayout() frame.recycle() progressIndicator.setProgress(0, animated = false) } @@ -219,8 +212,7 @@ class WebtoonPageHolder( private fun setQueued() { progressContainer.isVisible = true progressIndicator.show() - retryContainer?.isVisible = false - removeDecodeErrorLayout() + removeErrorLayout() } /** @@ -229,8 +221,7 @@ class WebtoonPageHolder( private fun setLoading() { progressContainer.isVisible = true progressIndicator.show() - retryContainer?.isVisible = false - removeDecodeErrorLayout() + removeErrorLayout() } /** @@ -239,8 +230,7 @@ class WebtoonPageHolder( private fun setDownloading() { progressContainer.isVisible = true progressIndicator.show() - retryContainer?.isVisible = false - removeDecodeErrorLayout() + removeErrorLayout() } /** @@ -248,8 +238,7 @@ class WebtoonPageHolder( */ private fun setImage() { progressIndicator.setProgress(0) - retryContainer?.isVisible = false - removeDecodeErrorLayout() + removeErrorLayout() unsubscribeReadImageHeader() val streamFn = page?.stream ?: return @@ -302,7 +291,7 @@ class WebtoonPageHolder( */ private fun setError() { progressContainer.isVisible = false - initRetryLayout().isVisible = true + initErrorLayout(withOpenInWebView = false) } /** @@ -317,7 +306,7 @@ class WebtoonPageHolder( */ private fun onImageDecodeError() { progressContainer.isVisible = false - initDecodeErrorLayout().isVisible = true + initErrorLayout(withOpenInWebView = true) } /** @@ -340,94 +329,32 @@ class WebtoonPageHolder( /** * Initializes a button to retry pages. */ - private fun initRetryLayout(): ViewGroup { - if (retryContainer != null) return retryContainer!! - - retryContainer = FrameLayout(context) - frame.addView(retryContainer, MATCH_PARENT, parentHeight) - - MaterialButton(context).apply { - layoutParams = FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT).apply { - gravity = Gravity.CENTER_HORIZONTAL - setMargins(0, parentHeight / 4, 0, 0) - } - setText(R.string.action_retry) - setOnClickListener { + private fun initErrorLayout(withOpenInWebView: Boolean): ReaderErrorBinding { + if (errorLayout == null) { + errorLayout = ReaderErrorBinding.inflate(LayoutInflater.from(context), frame, true) + errorLayout?.root?.layoutParams = FrameLayout.LayoutParams(MATCH_PARENT, (parentHeight * 0.8).toInt()) + errorLayout?.actionRetry?.setOnClickListener { page?.let { it.chapter.pageLoader?.retryPage(it) } } - - retryContainer!!.addView(this) - } - return retryContainer!! - } - - /** - * Initializes a decode error layout. - */ - private fun initDecodeErrorLayout(): ViewGroup { - if (decodeErrorLayout != null) return decodeErrorLayout!! - - val margins = 8.dpToPx - - val decodeLayout = LinearLayout(context).apply { - layoutParams = LinearLayout.LayoutParams(MATCH_PARENT, parentHeight).apply { - setMargins(0, parentHeight / 6, 0, 0) - } - gravity = Gravity.CENTER_HORIZONTAL - orientation = LinearLayout.VERTICAL - } - decodeErrorLayout = decodeLayout - - MaterialTextView(context).apply { - layoutParams = LinearLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT).apply { - setMargins(0, margins, 0, margins) - } - gravity = Gravity.CENTER - setText(R.string.decode_image_error) - - decodeLayout.addView(this) - } - - MaterialButton(context).apply { - layoutParams = FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT).apply { - setMargins(0, margins, 0, margins) - } - setText(R.string.action_retry) - setOnClickListener { - page?.let { it.chapter.pageLoader?.retryPage(it) } - } - - decodeLayout.addView(this) - } - - val imageUrl = page?.imageUrl - if (imageUrl.orEmpty().startsWith("http", true)) { - MaterialButton(context).apply { - layoutParams = FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT).apply { - setMargins(0, margins, 0, margins) - } - setText(R.string.action_open_in_web_view) - setOnClickListener { + val imageUrl = page?.imageUrl + if (imageUrl.orEmpty().startsWith("http", true)) { + errorLayout?.actionOpenInWebView?.setOnClickListener { val intent = WebViewActivity.newIntent(context, imageUrl!!) context.startActivity(intent) } - - decodeLayout.addView(this) } } - - frame.addView(decodeLayout) - return decodeLayout + errorLayout?.actionOpenInWebView?.isVisible = withOpenInWebView + return errorLayout!! } /** * Removes the decode error layout from the holder, if found. */ - private fun removeDecodeErrorLayout() { - val layout = decodeErrorLayout - if (layout != null) { - frame.removeView(layout) - decodeErrorLayout = null + private fun removeErrorLayout() { + errorLayout?.let { + frame.removeView(it.root) + errorLayout = null } } } diff --git a/app/src/main/res/layout/reader_error.xml b/app/src/main/res/layout/reader_error.xml new file mode 100644 index 0000000000..c926ef13dc --- /dev/null +++ b/app/src/main/res/layout/reader_error.xml @@ -0,0 +1,31 @@ + + + + + + + + + +