Show error on ImageActivity
This commit is contained in:
@@ -3,7 +3,9 @@ package org.koitharu.kotatsu.core.util.ext
|
|||||||
import android.content.ActivityNotFoundException
|
import android.content.ActivityNotFoundException
|
||||||
import android.content.res.Resources
|
import android.content.res.Resources
|
||||||
import android.util.AndroidRuntimeException
|
import android.util.AndroidRuntimeException
|
||||||
|
import androidx.annotation.DrawableRes
|
||||||
import androidx.collection.arraySetOf
|
import androidx.collection.arraySetOf
|
||||||
|
import coil.network.HttpException
|
||||||
import okio.FileNotFoundException
|
import okio.FileNotFoundException
|
||||||
import okio.IOException
|
import okio.IOException
|
||||||
import org.acra.ktx.sendWithAcra
|
import org.acra.ktx.sendWithAcra
|
||||||
@@ -50,10 +52,8 @@ fun Throwable.getDisplayMessage(resources: Resources): String = when (this) {
|
|||||||
is WrongPasswordException -> resources.getString(R.string.wrong_password)
|
is WrongPasswordException -> resources.getString(R.string.wrong_password)
|
||||||
is NotFoundException -> resources.getString(R.string.not_found_404)
|
is NotFoundException -> resources.getString(R.string.not_found_404)
|
||||||
|
|
||||||
is HttpStatusException -> when (statusCode) {
|
is HttpException -> getHttpDisplayMessage(response.code, resources)
|
||||||
in 500..599 -> resources.getString(R.string.server_error, statusCode)
|
is HttpStatusException -> getHttpDisplayMessage(statusCode, resources)
|
||||||
else -> localizedMessage
|
|
||||||
}
|
|
||||||
|
|
||||||
is IOException -> getDisplayMessage(message, resources) ?: localizedMessage
|
is IOException -> getDisplayMessage(message, resources) ?: localizedMessage
|
||||||
else -> localizedMessage
|
else -> localizedMessage
|
||||||
@@ -61,6 +61,23 @@ fun Throwable.getDisplayMessage(resources: Resources): String = when (this) {
|
|||||||
resources.getString(R.string.error_occurred)
|
resources.getString(R.string.error_occurred)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@DrawableRes
|
||||||
|
fun Throwable.getDisplayIcon() = when (this) {
|
||||||
|
is AuthRequiredException -> R.drawable.ic_auth_key_large
|
||||||
|
is CloudFlareProtectedException -> R.drawable.ic_bot_large
|
||||||
|
is UnknownHostException,
|
||||||
|
is SocketTimeoutException,
|
||||||
|
-> R.drawable.ic_plug_large
|
||||||
|
|
||||||
|
else -> R.drawable.ic_error_large
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getHttpDisplayMessage(statusCode: Int, resources: Resources): String? = when (statusCode) {
|
||||||
|
404 -> resources.getString(R.string.not_found_404)
|
||||||
|
in 500..599 -> resources.getString(R.string.server_error, statusCode)
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
|
||||||
private fun getDisplayMessage(msg: String?, resources: Resources): String? = when {
|
private fun getDisplayMessage(msg: String?, resources: Resources): String? = when {
|
||||||
msg.isNullOrEmpty() -> null
|
msg.isNullOrEmpty() -> null
|
||||||
msg.contains(MSG_NO_SPACE_LEFT) -> resources.getString(R.string.error_no_space_left)
|
msg.contains(MSG_NO_SPACE_LEFT) -> resources.getString(R.string.error_no_space_left)
|
||||||
|
|||||||
@@ -5,32 +5,40 @@ import android.content.Intent
|
|||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.core.graphics.Insets
|
import androidx.core.graphics.Insets
|
||||||
import androidx.core.graphics.drawable.toBitmap
|
import androidx.core.graphics.drawable.toBitmap
|
||||||
|
import androidx.core.view.isVisible
|
||||||
import androidx.core.view.updateLayoutParams
|
import androidx.core.view.updateLayoutParams
|
||||||
import androidx.core.view.updatePadding
|
import androidx.core.view.updatePadding
|
||||||
import coil.ImageLoader
|
import coil.ImageLoader
|
||||||
import coil.request.CachePolicy
|
import coil.request.CachePolicy
|
||||||
|
import coil.request.ErrorResult
|
||||||
import coil.request.ImageRequest
|
import coil.request.ImageRequest
|
||||||
|
import coil.request.SuccessResult
|
||||||
import coil.target.ViewTarget
|
import coil.target.ViewTarget
|
||||||
import com.davemorrissey.labs.subscaleview.ImageSource
|
import com.davemorrissey.labs.subscaleview.ImageSource
|
||||||
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
|
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import org.koitharu.kotatsu.core.ui.BaseActivity
|
import org.koitharu.kotatsu.core.ui.BaseActivity
|
||||||
import org.koitharu.kotatsu.core.util.ext.enqueueWith
|
import org.koitharu.kotatsu.core.util.ext.enqueueWith
|
||||||
|
import org.koitharu.kotatsu.core.util.ext.getDisplayIcon
|
||||||
|
import org.koitharu.kotatsu.core.util.ext.getDisplayMessage
|
||||||
import org.koitharu.kotatsu.core.util.ext.getSerializableExtraCompat
|
import org.koitharu.kotatsu.core.util.ext.getSerializableExtraCompat
|
||||||
import org.koitharu.kotatsu.core.util.ext.indicator
|
|
||||||
import org.koitharu.kotatsu.databinding.ActivityImageBinding
|
import org.koitharu.kotatsu.databinding.ActivityImageBinding
|
||||||
|
import org.koitharu.kotatsu.databinding.ItemErrorStateBinding
|
||||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class ImageActivity : BaseActivity<ActivityImageBinding>() {
|
class ImageActivity : BaseActivity<ActivityImageBinding>(), ImageRequest.Listener, View.OnClickListener {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
lateinit var coil: ImageLoader
|
lateinit var coil: ImageLoader
|
||||||
|
|
||||||
|
private var errorBinding: ItemErrorStateBinding? = null
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
setContentView(ActivityImageBinding.inflate(layoutInflater))
|
setContentView(ActivityImageBinding.inflate(layoutInflater))
|
||||||
@@ -53,14 +61,40 @@ class ImageActivity : BaseActivity<ActivityImageBinding>() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onClick(v: View?) {
|
||||||
|
loadImage(intent.data)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onError(request: ImageRequest, result: ErrorResult) {
|
||||||
|
viewBinding.progressBar.hide()
|
||||||
|
with(errorBinding ?: ItemErrorStateBinding.bind(viewBinding.stubError.inflate())) {
|
||||||
|
errorBinding = this
|
||||||
|
root.isVisible = true
|
||||||
|
textViewError.text = result.throwable.getDisplayMessage(resources)
|
||||||
|
textViewError.setCompoundDrawablesWithIntrinsicBounds(0, result.throwable.getDisplayIcon(), 0, 0)
|
||||||
|
buttonRetry.isVisible = true
|
||||||
|
buttonRetry.setOnClickListener(this@ImageActivity)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStart(request: ImageRequest) {
|
||||||
|
viewBinding.progressBar.show()
|
||||||
|
(errorBinding?.root ?: viewBinding.stubError).isVisible = false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onSuccess(request: ImageRequest, result: SuccessResult) {
|
||||||
|
viewBinding.progressBar.hide()
|
||||||
|
(errorBinding?.root ?: viewBinding.stubError).isVisible = false
|
||||||
|
}
|
||||||
|
|
||||||
private fun loadImage(url: Uri?) {
|
private fun loadImage(url: Uri?) {
|
||||||
ImageRequest.Builder(this)
|
ImageRequest.Builder(this)
|
||||||
.data(url)
|
.data(url)
|
||||||
.memoryCachePolicy(CachePolicy.DISABLED)
|
.memoryCachePolicy(CachePolicy.DISABLED)
|
||||||
.lifecycle(this)
|
.lifecycle(this)
|
||||||
|
.listener(this)
|
||||||
.tag(intent.getSerializableExtraCompat<MangaSource>(EXTRA_SOURCE))
|
.tag(intent.getSerializableExtraCompat<MangaSource>(EXTRA_SOURCE))
|
||||||
.target(SsivTarget(viewBinding.ssiv))
|
.target(SsivTarget(viewBinding.ssiv))
|
||||||
.indicator(viewBinding.progressBar)
|
|
||||||
.enqueueWith(coil)
|
.enqueueWith(coil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,14 @@
|
|||||||
package org.koitharu.kotatsu.list.ui.model
|
package org.koitharu.kotatsu.list.ui.model
|
||||||
|
|
||||||
import org.koitharu.kotatsu.R
|
import org.koitharu.kotatsu.R
|
||||||
import org.koitharu.kotatsu.core.exceptions.CloudFlareProtectedException
|
|
||||||
import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver
|
import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver
|
||||||
import org.koitharu.kotatsu.core.prefs.ListMode
|
import org.koitharu.kotatsu.core.prefs.ListMode
|
||||||
import org.koitharu.kotatsu.core.ui.widgets.ChipsView
|
import org.koitharu.kotatsu.core.ui.widgets.ChipsView
|
||||||
|
import org.koitharu.kotatsu.core.util.ext.getDisplayIcon
|
||||||
import org.koitharu.kotatsu.core.util.ext.ifZero
|
import org.koitharu.kotatsu.core.util.ext.ifZero
|
||||||
import org.koitharu.kotatsu.history.data.PROGRESS_NONE
|
import org.koitharu.kotatsu.history.data.PROGRESS_NONE
|
||||||
import org.koitharu.kotatsu.list.domain.ListExtraProvider
|
import org.koitharu.kotatsu.list.domain.ListExtraProvider
|
||||||
import org.koitharu.kotatsu.parsers.exception.AuthRequiredException
|
|
||||||
import org.koitharu.kotatsu.parsers.model.Manga
|
import org.koitharu.kotatsu.parsers.model.Manga
|
||||||
import java.net.SocketTimeoutException
|
|
||||||
import java.net.UnknownHostException
|
|
||||||
|
|
||||||
suspend fun Manga.toListModel(
|
suspend fun Manga.toListModel(
|
||||||
extraProvider: ListExtraProvider?
|
extraProvider: ListExtraProvider?
|
||||||
@@ -79,7 +76,7 @@ suspend fun <C : MutableCollection<in MangaItemModel>> List<Manga>.toUi(
|
|||||||
|
|
||||||
fun Throwable.toErrorState(canRetry: Boolean = true) = ErrorState(
|
fun Throwable.toErrorState(canRetry: Boolean = true) = ErrorState(
|
||||||
exception = this,
|
exception = this,
|
||||||
icon = getErrorIcon(this),
|
icon = getDisplayIcon(),
|
||||||
canRetry = canRetry,
|
canRetry = canRetry,
|
||||||
buttonText = ExceptionResolver.getResolveStringId(this).ifZero { R.string.try_again },
|
buttonText = ExceptionResolver.getResolveStringId(this).ifZero { R.string.try_again },
|
||||||
)
|
)
|
||||||
@@ -88,13 +85,3 @@ fun Throwable.toErrorFooter() = ErrorFooter(
|
|||||||
exception = this,
|
exception = this,
|
||||||
icon = R.drawable.ic_alert_outline,
|
icon = R.drawable.ic_alert_outline,
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun getErrorIcon(error: Throwable) = when (error) {
|
|
||||||
is AuthRequiredException -> R.drawable.ic_auth_key_large
|
|
||||||
is CloudFlareProtectedException -> R.drawable.ic_bot_large
|
|
||||||
is UnknownHostException,
|
|
||||||
is SocketTimeoutException,
|
|
||||||
-> R.drawable.ic_plug_large
|
|
||||||
|
|
||||||
else -> R.drawable.ic_error_large
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -23,4 +23,10 @@
|
|||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
android:indeterminate="true" />
|
android:indeterminate="true" />
|
||||||
|
|
||||||
|
<ViewStub
|
||||||
|
android:id="@+id/stub_error"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout="@layout/item_error_state" />
|
||||||
|
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|||||||
Reference in New Issue
Block a user