Unify reader error layout (#6512)
So nobody will think that the error layout is broken when they see different layout.
This commit is contained in:
parent
b6553bdc34
commit
7108993936
6 changed files with 111 additions and 214 deletions
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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!!
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
app/src/main/res/layout/reader_error.xml
Normal file
31
app/src/main/res/layout/reader_error.xml
Normal file
|
@ -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>
|
Reference in a new issue