Просмотр исходного кода

Unify reader error layout (#6512)

So nobody will think that the error layout is broken when they see different
layout.
Ivan Iskandar 3 лет назад
Родитель
Сommit
7108993936

+ 29 - 0
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)
+    }
+}

+ 0 - 24
app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerButton.kt

@@ -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
-        }
-    }
-}

+ 22 - 90
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!!
     }
 }

+ 4 - 2
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 = [email protected]
             wrapContent()
             setText(R.string.action_retry)
             setOnClickListener {
                 val toChapter = transition.to
                 if (toChapter != null) {
-                    viewer.activity.requestPreloadChapter(toChapter)
+                    this@PagerTransitionHolder.viewer.activity.requestPreloadChapter(toChapter)
                 }
             }
         }

+ 25 - 98
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
         }
     }
 }

+ 31 - 0
app/src/main/res/layout/reader_error.xml

@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:layout_gravity="center"
+    android:gravity="center">
+
+    <TextView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_margin="8dp"
+        android:text="@string/decode_image_error"
+        android:textAppearance="?attr/textAppearanceBodyMedium" />
+
+    <eu.kanade.tachiyomi.ui.reader.viewer.ReaderButton
+        android:id="@+id/action_retry"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_margin="8dp"
+        android:text="@string/action_retry" />
+
+    <eu.kanade.tachiyomi.ui.reader.viewer.ReaderButton
+        android:id="@+id/action_open_in_web_view"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_margin="8dp"
+        android:text="@string/action_open_in_web_view"
+        android:visibility="gone" />
+
+</LinearLayout>