Reader fixes
This commit is contained in:
parent
d77a1e6925
commit
5b1f4f189b
5 changed files with 124 additions and 81 deletions
|
@ -1,71 +1,40 @@
|
||||||
package eu.kanade.tachiyomi.ui.reader.viewer.base
|
package eu.kanade.tachiyomi.ui.reader.viewer.base
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.Intent
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.support.v4.content.ContextCompat
|
import android.support.v4.content.ContextCompat
|
||||||
import android.view.Gravity
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
|
||||||
import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
|
|
||||||
import android.widget.Button
|
|
||||||
import android.widget.LinearLayout
|
|
||||||
import android.widget.TextView
|
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.source.model.Page
|
import eu.kanade.tachiyomi.data.source.model.Page
|
||||||
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
||||||
|
import kotlinx.android.synthetic.main.page_decode_error.view.*
|
||||||
|
|
||||||
class PageDecodeErrorLayout(context: Context) : LinearLayout(context) {
|
class PageDecodeErrorLayout(
|
||||||
|
val view: View,
|
||||||
/**
|
val page: Page,
|
||||||
* Text color for black theme.
|
val theme: Int,
|
||||||
*/
|
val retryListener: () -> Unit
|
||||||
private val whiteColor = ContextCompat.getColor(context, R.color.textColorSecondaryDark)
|
) {
|
||||||
|
|
||||||
/**
|
|
||||||
* Text color for white theme.
|
|
||||||
*/
|
|
||||||
private val blackColor = ContextCompat.getColor(context, R.color.textColorSecondaryLight)
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
orientation = LinearLayout.VERTICAL
|
val textColor = if (theme == ReaderActivity.BLACK_THEME)
|
||||||
gravity = Gravity.CENTER
|
ContextCompat.getColor(view.context, R.color.textColorSecondaryDark)
|
||||||
}
|
else
|
||||||
|
ContextCompat.getColor(view.context, R.color.textColorSecondaryLight)
|
||||||
|
|
||||||
constructor(context: Context, page: Page, theme: Int, retryListener: () -> Unit) : this(context) {
|
view.decode_error_text.setTextColor(textColor)
|
||||||
|
|
||||||
// Error message.
|
view.decode_retry.setOnClickListener {
|
||||||
TextView(context).apply {
|
|
||||||
gravity = Gravity.CENTER
|
|
||||||
setText(R.string.decode_image_error)
|
|
||||||
setTextColor(if (theme == ReaderActivity.BLACK_THEME) whiteColor else blackColor)
|
|
||||||
addView(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retry button.
|
|
||||||
Button(context).apply {
|
|
||||||
layoutParams = ViewGroup.LayoutParams(WRAP_CONTENT, WRAP_CONTENT)
|
|
||||||
setText(R.string.action_retry)
|
|
||||||
setOnClickListener {
|
|
||||||
retryListener()
|
retryListener()
|
||||||
}
|
}
|
||||||
addView(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Open in browser button.
|
view.decode_open_browser.setOnClickListener {
|
||||||
Button(context).apply {
|
val intent = android.content.Intent(android.content.Intent.ACTION_VIEW, Uri.parse(page.imageUrl))
|
||||||
layoutParams = ViewGroup.LayoutParams(WRAP_CONTENT, WRAP_CONTENT)
|
view.context.startActivity(intent)
|
||||||
setText(R.string.action_open_in_browser)
|
|
||||||
setOnClickListener { v ->
|
|
||||||
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(page.imageUrl))
|
|
||||||
context.startActivity(intent)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (page.imageUrl == null) {
|
if (page.imageUrl == null) {
|
||||||
visibility = View.GONE
|
view.decode_open_browser.visibility = View.GONE
|
||||||
}
|
}
|
||||||
addView(this)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -14,6 +14,7 @@ import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
||||||
import eu.kanade.tachiyomi.ui.reader.viewer.base.PageDecodeErrorLayout
|
import eu.kanade.tachiyomi.ui.reader.viewer.base.PageDecodeErrorLayout
|
||||||
import eu.kanade.tachiyomi.ui.reader.viewer.pager.horizontal.RightToLeftReader
|
import eu.kanade.tachiyomi.ui.reader.viewer.pager.horizontal.RightToLeftReader
|
||||||
import eu.kanade.tachiyomi.ui.reader.viewer.pager.vertical.VerticalReader
|
import eu.kanade.tachiyomi.ui.reader.viewer.pager.vertical.VerticalReader
|
||||||
|
import eu.kanade.tachiyomi.util.inflate
|
||||||
import kotlinx.android.synthetic.main.chapter_image.view.*
|
import kotlinx.android.synthetic.main.chapter_image.view.*
|
||||||
import kotlinx.android.synthetic.main.item_pager_reader.view.*
|
import kotlinx.android.synthetic.main.item_pager_reader.view.*
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
|
@ -45,7 +46,7 @@ class PageView @JvmOverloads constructor(context: Context, attrs: AttributeSet?
|
||||||
/**
|
/**
|
||||||
* Layout of decode error.
|
* Layout of decode error.
|
||||||
*/
|
*/
|
||||||
private var decodeErrorLayout: PageDecodeErrorLayout? = null
|
private var decodeErrorLayout: View? = null
|
||||||
|
|
||||||
fun initialize(reader: PagerReader, page: Page) {
|
fun initialize(reader: PagerReader, page: Page) {
|
||||||
val activity = reader.activity as ReaderActivity
|
val activity = reader.activity as ReaderActivity
|
||||||
|
@ -243,14 +244,20 @@ class PageView @JvmOverloads constructor(context: Context, attrs: AttributeSet?
|
||||||
* Called when an image fails to decode.
|
* Called when an image fails to decode.
|
||||||
*/
|
*/
|
||||||
private fun onImageDecodeError(reader: PagerReader) {
|
private fun onImageDecodeError(reader: PagerReader) {
|
||||||
|
progress_container.visibility = View.GONE
|
||||||
|
|
||||||
if (decodeErrorLayout != null || !reader.isAdded) return
|
if (decodeErrorLayout != null || !reader.isAdded) return
|
||||||
|
|
||||||
val activity = reader.activity as ReaderActivity
|
val activity = reader.activity as ReaderActivity
|
||||||
|
|
||||||
decodeErrorLayout = PageDecodeErrorLayout(context, page, activity.readerTheme,
|
val layout = inflate(R.layout.page_decode_error)
|
||||||
{ activity.presenter.retryPage(page) })
|
PageDecodeErrorLayout(layout, page, activity.readerTheme, {
|
||||||
|
if (reader.isAdded) {
|
||||||
addView(decodeErrorLayout)
|
activity.presenter.retryPage(page)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
decodeErrorLayout = layout
|
||||||
|
addView(layout)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -10,6 +10,7 @@ import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.source.model.Page
|
import eu.kanade.tachiyomi.data.source.model.Page
|
||||||
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
||||||
import eu.kanade.tachiyomi.ui.reader.viewer.base.PageDecodeErrorLayout
|
import eu.kanade.tachiyomi.ui.reader.viewer.base.PageDecodeErrorLayout
|
||||||
|
import eu.kanade.tachiyomi.util.inflate
|
||||||
import kotlinx.android.synthetic.main.chapter_image.view.*
|
import kotlinx.android.synthetic.main.chapter_image.view.*
|
||||||
import kotlinx.android.synthetic.main.item_webtoon_reader.view.*
|
import kotlinx.android.synthetic.main.item_webtoon_reader.view.*
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
|
@ -49,7 +50,7 @@ class WebtoonHolder(private val view: View, private val adapter: WebtoonAdapter)
|
||||||
/**
|
/**
|
||||||
* Layout of decode error.
|
* Layout of decode error.
|
||||||
*/
|
*/
|
||||||
private var decodeErrorLayout: PageDecodeErrorLayout? = null
|
private var decodeErrorLayout: View? = null
|
||||||
|
|
||||||
init {
|
init {
|
||||||
with(view.image_view) {
|
with(view.image_view) {
|
||||||
|
@ -74,7 +75,7 @@ class WebtoonHolder(private val view: View, private val adapter: WebtoonAdapter)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
view.progress_container.minimumHeight = view.resources.displayMetrics.heightPixels
|
view.progress_container.minimumHeight = view.resources.displayMetrics.heightPixels * 2
|
||||||
|
|
||||||
view.setOnTouchListener(adapter.touchListener)
|
view.setOnTouchListener(adapter.touchListener)
|
||||||
view.retry_button.setOnTouchListener { v, event ->
|
view.retry_button.setOnTouchListener { v, event ->
|
||||||
|
@ -107,6 +108,7 @@ class WebtoonHolder(private val view: View, private val adapter: WebtoonAdapter)
|
||||||
decodeErrorLayout = null
|
decodeErrorLayout = null
|
||||||
}
|
}
|
||||||
view.image_view.recycle()
|
view.image_view.recycle()
|
||||||
|
view.image_view.visibility = View.GONE
|
||||||
view.progress_container.visibility = View.VISIBLE
|
view.progress_container.visibility = View.VISIBLE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,24 +118,25 @@ class WebtoonHolder(private val view: View, private val adapter: WebtoonAdapter)
|
||||||
* @see processStatus
|
* @see processStatus
|
||||||
*/
|
*/
|
||||||
private fun observeStatus() {
|
private fun observeStatus() {
|
||||||
|
unsubscribeStatus()
|
||||||
|
|
||||||
val page = page ?: return
|
val page = page ?: return
|
||||||
|
|
||||||
val statusSubject = SerializedSubject(PublishSubject.create<Int>())
|
val statusSubject = SerializedSubject(PublishSubject.create<Int>())
|
||||||
page.setStatusSubject(statusSubject)
|
page.setStatusSubject(statusSubject)
|
||||||
|
|
||||||
statusSubscription?.unsubscribe()
|
|
||||||
statusSubscription = statusSubject.startWith(page.status)
|
statusSubscription = statusSubject.startWith(page.status)
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribe { processStatus(it) }
|
.subscribe { processStatus(it) }
|
||||||
|
|
||||||
webtoonReader.subscriptions.add(statusSubscription)
|
addSubscription(statusSubscription)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Observes the progress of the page and updates view.
|
* Observes the progress of the page and updates view.
|
||||||
*/
|
*/
|
||||||
private fun observeProgress() {
|
private fun observeProgress() {
|
||||||
progressSubscription?.unsubscribe()
|
unsubscribeProgress()
|
||||||
|
|
||||||
val page = page ?: return
|
val page = page ?: return
|
||||||
|
|
||||||
|
@ -145,6 +148,8 @@ class WebtoonHolder(private val view: View, private val adapter: WebtoonAdapter)
|
||||||
.subscribe { progress ->
|
.subscribe { progress ->
|
||||||
view.progress_text.text = view.context.getString(R.string.download_progress, progress)
|
view.progress_text.text = view.context.getString(R.string.download_progress, progress)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addSubscription(progressSubscription)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -171,12 +176,27 @@ class WebtoonHolder(private val view: View, private val adapter: WebtoonAdapter)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a subscription to a list of subscriptions that will automatically unsubscribe when the
|
||||||
|
* activity or the reader is destroyed.
|
||||||
|
*/
|
||||||
|
private fun addSubscription(subscription: Subscription?) {
|
||||||
|
webtoonReader.subscriptions.add(subscription)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a subscription from the list of subscriptions.
|
||||||
|
*/
|
||||||
|
private fun removeSubscription(subscription: Subscription?) {
|
||||||
|
subscription?.let { webtoonReader.subscriptions.remove(it) }
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unsubscribes from the status subscription.
|
* Unsubscribes from the status subscription.
|
||||||
*/
|
*/
|
||||||
private fun unsubscribeStatus() {
|
private fun unsubscribeStatus() {
|
||||||
page?.setStatusSubject(null)
|
page?.setStatusSubject(null)
|
||||||
statusSubscription?.unsubscribe()
|
removeSubscription(statusSubscription)
|
||||||
statusSubscription = null
|
statusSubscription = null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,7 +204,7 @@ class WebtoonHolder(private val view: View, private val adapter: WebtoonAdapter)
|
||||||
* Unsubscribes from the progress subscription.
|
* Unsubscribes from the progress subscription.
|
||||||
*/
|
*/
|
||||||
private fun unsubscribeProgress() {
|
private fun unsubscribeProgress() {
|
||||||
progressSubscription?.unsubscribe()
|
removeSubscription(progressSubscription)
|
||||||
progressSubscription = null
|
progressSubscription = null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -194,7 +214,7 @@ class WebtoonHolder(private val view: View, private val adapter: WebtoonAdapter)
|
||||||
private fun setQueued() = with(view) {
|
private fun setQueued() = with(view) {
|
||||||
progress_container.visibility = View.VISIBLE
|
progress_container.visibility = View.VISIBLE
|
||||||
progress_text.visibility = View.INVISIBLE
|
progress_text.visibility = View.INVISIBLE
|
||||||
retry_button.visibility = View.GONE
|
retry_container.visibility = View.GONE
|
||||||
decodeErrorLayout?.let {
|
decodeErrorLayout?.let {
|
||||||
(view as ViewGroup).removeView(it)
|
(view as ViewGroup).removeView(it)
|
||||||
decodeErrorLayout = null
|
decodeErrorLayout = null
|
||||||
|
@ -225,6 +245,7 @@ class WebtoonHolder(private val view: View, private val adapter: WebtoonAdapter)
|
||||||
val path = page?.imagePath
|
val path = page?.imagePath
|
||||||
if (path != null && File(path).exists()) {
|
if (path != null && File(path).exists()) {
|
||||||
progress_text.visibility = View.INVISIBLE
|
progress_text.visibility = View.INVISIBLE
|
||||||
|
image_view.visibility = View.VISIBLE
|
||||||
image_view.setImage(ImageSource.uri(path))
|
image_view.setImage(ImageSource.uri(path))
|
||||||
} else {
|
} else {
|
||||||
page?.status = Page.ERROR
|
page?.status = Page.ERROR
|
||||||
|
@ -236,7 +257,7 @@ class WebtoonHolder(private val view: View, private val adapter: WebtoonAdapter)
|
||||||
*/
|
*/
|
||||||
private fun setError() = with(view) {
|
private fun setError() = with(view) {
|
||||||
progress_container.visibility = View.GONE
|
progress_container.visibility = View.GONE
|
||||||
retry_button.visibility = View.VISIBLE
|
retry_container.visibility = View.VISIBLE
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -250,13 +271,19 @@ class WebtoonHolder(private val view: View, private val adapter: WebtoonAdapter)
|
||||||
* Called when the image fails to decode.
|
* Called when the image fails to decode.
|
||||||
*/
|
*/
|
||||||
private fun onImageDecodeError() {
|
private fun onImageDecodeError() {
|
||||||
|
view.progress_container.visibility = View.GONE
|
||||||
|
|
||||||
val page = page ?: return
|
val page = page ?: return
|
||||||
if (decodeErrorLayout != null || !webtoonReader.isAdded) return
|
if (decodeErrorLayout != null || !webtoonReader.isAdded) return
|
||||||
|
|
||||||
decodeErrorLayout = PageDecodeErrorLayout(view.context, page, readerActivity.readerTheme,
|
val layout = (view as ViewGroup).inflate(R.layout.page_decode_error)
|
||||||
{ readerActivity.presenter.retryPage(page) })
|
PageDecodeErrorLayout(layout, page, readerActivity.readerTheme, {
|
||||||
|
if (webtoonReader.isAdded) {
|
||||||
(view as ViewGroup).addView(decodeErrorLayout)
|
readerActivity.presenter.retryPage(page)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
decodeErrorLayout = layout
|
||||||
|
view.addView(layout)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -32,12 +32,20 @@
|
||||||
|
|
||||||
<include layout="@layout/chapter_image"/>
|
<include layout="@layout/chapter_image"/>
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="192dp"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:id="@+id/retry_container"
|
||||||
|
android:visibility="gone">
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:id="@+id/retry_button"
|
android:id="@+id/retry_button"
|
||||||
android:text="@string/action_retry"
|
android:text="@string/action_retry"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"/>
|
||||||
android:visibility="gone"/>
|
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
</FrameLayout>
|
</FrameLayout>
|
32
app/src/main/res/layout/page_decode_error.xml
Normal file
32
app/src/main/res/layout/page_decode_error.xml
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="512dp"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:gravity="center">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/decode_error_text"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/decode_image_error"
|
||||||
|
android:layout_margin="8dp"
|
||||||
|
android:gravity="center"/>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/decode_retry"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="8dp"
|
||||||
|
android:text="@string/action_retry"/>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/decode_open_browser"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="8dp"
|
||||||
|
android:text="@string/action_open_in_browser"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
Reference in a new issue