Reader fixes

This commit is contained in:
len 2016-10-24 22:16:50 +02:00
parent d77a1e6925
commit 5b1f4f189b
5 changed files with 124 additions and 81 deletions

View File

@ -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)
view.decode_error_text.setTextColor(textColor)
view.decode_retry.setOnClickListener {
retryListener()
}
view.decode_open_browser.setOnClickListener {
val intent = android.content.Intent(android.content.Intent.ACTION_VIEW, Uri.parse(page.imageUrl))
view.context.startActivity(intent)
}
if (page.imageUrl == null) {
view.decode_open_browser.visibility = View.GONE
}
} }
constructor(context: Context, page: Page, theme: Int, retryListener: () -> Unit) : this(context) {
// Error message.
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()
}
addView(this)
}
// Open in browser button.
Button(context).apply {
layoutParams = ViewGroup.LayoutParams(WRAP_CONTENT, WRAP_CONTENT)
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) {
visibility = View.GONE
}
addView(this)
}
}
} }

View File

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

View File

@ -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)
} }
/** /**

View File

@ -32,12 +32,20 @@
<include layout="@layout/chapter_image"/> <include layout="@layout/chapter_image"/>
<Button <FrameLayout
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="192dp"
android:id="@+id/retry_button" android:layout_gravity="center_horizontal"
android:text="@string/action_retry" android:id="@+id/retry_container"
android:layout_gravity="center" android:visibility="gone">
android:visibility="gone"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/retry_button"
android:text="@string/action_retry"
android:layout_gravity="center"/>
</FrameLayout>
</FrameLayout> </FrameLayout>

View 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>