From df04dcc8a3aabfe34ce587299110b63e44fbf3db Mon Sep 17 00:00:00 2001 From: Koitharu Date: Fri, 18 Aug 2023 15:40:56 +0300 Subject: [PATCH] Show error on ImageActivity --- .../kotatsu/core/util/ext/Throwable.kt | 25 ++++++++++-- .../kotatsu/image/ui/ImageActivity.kt | 40 +++++++++++++++++-- .../list/ui/model/ListModelConversionExt.kt | 17 +------- app/src/main/res/layout/activity_image.xml | 6 +++ 4 files changed, 66 insertions(+), 22 deletions(-) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Throwable.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Throwable.kt index 0a369f99f..f335ccdf9 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Throwable.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Throwable.kt @@ -3,7 +3,9 @@ package org.koitharu.kotatsu.core.util.ext import android.content.ActivityNotFoundException import android.content.res.Resources import android.util.AndroidRuntimeException +import androidx.annotation.DrawableRes import androidx.collection.arraySetOf +import coil.network.HttpException import okio.FileNotFoundException import okio.IOException 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 NotFoundException -> resources.getString(R.string.not_found_404) - is HttpStatusException -> when (statusCode) { - in 500..599 -> resources.getString(R.string.server_error, statusCode) - else -> localizedMessage - } + is HttpException -> getHttpDisplayMessage(response.code, resources) + is HttpStatusException -> getHttpDisplayMessage(statusCode, resources) is IOException -> getDisplayMessage(message, resources) ?: localizedMessage else -> localizedMessage @@ -61,6 +61,23 @@ fun Throwable.getDisplayMessage(resources: Resources): String = when (this) { 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 { msg.isNullOrEmpty() -> null msg.contains(MSG_NO_SPACE_LEFT) -> resources.getString(R.string.error_no_space_left) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/image/ui/ImageActivity.kt b/app/src/main/kotlin/org/koitharu/kotatsu/image/ui/ImageActivity.kt index 469ea71c7..56a11f004 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/image/ui/ImageActivity.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/image/ui/ImageActivity.kt @@ -5,32 +5,40 @@ import android.content.Intent import android.graphics.drawable.Drawable import android.net.Uri import android.os.Bundle +import android.view.View import android.view.ViewGroup import androidx.core.graphics.Insets import androidx.core.graphics.drawable.toBitmap +import androidx.core.view.isVisible import androidx.core.view.updateLayoutParams import androidx.core.view.updatePadding import coil.ImageLoader import coil.request.CachePolicy +import coil.request.ErrorResult import coil.request.ImageRequest +import coil.request.SuccessResult import coil.target.ViewTarget import com.davemorrissey.labs.subscaleview.ImageSource import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView import dagger.hilt.android.AndroidEntryPoint import org.koitharu.kotatsu.core.ui.BaseActivity 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.indicator import org.koitharu.kotatsu.databinding.ActivityImageBinding +import org.koitharu.kotatsu.databinding.ItemErrorStateBinding import org.koitharu.kotatsu.parsers.model.MangaSource import javax.inject.Inject @AndroidEntryPoint -class ImageActivity : BaseActivity() { +class ImageActivity : BaseActivity(), ImageRequest.Listener, View.OnClickListener { @Inject lateinit var coil: ImageLoader + private var errorBinding: ItemErrorStateBinding? = null + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(ActivityImageBinding.inflate(layoutInflater)) @@ -53,14 +61,40 @@ class ImageActivity : BaseActivity() { } } + 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?) { ImageRequest.Builder(this) .data(url) .memoryCachePolicy(CachePolicy.DISABLED) .lifecycle(this) + .listener(this) .tag(intent.getSerializableExtraCompat(EXTRA_SOURCE)) .target(SsivTarget(viewBinding.ssiv)) - .indicator(viewBinding.progressBar) .enqueueWith(coil) } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/model/ListModelConversionExt.kt b/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/model/ListModelConversionExt.kt index 066d1a6f2..2ecb9c6db 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/model/ListModelConversionExt.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/model/ListModelConversionExt.kt @@ -1,17 +1,14 @@ package org.koitharu.kotatsu.list.ui.model 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.prefs.ListMode 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.history.data.PROGRESS_NONE import org.koitharu.kotatsu.list.domain.ListExtraProvider -import org.koitharu.kotatsu.parsers.exception.AuthRequiredException import org.koitharu.kotatsu.parsers.model.Manga -import java.net.SocketTimeoutException -import java.net.UnknownHostException suspend fun Manga.toListModel( extraProvider: ListExtraProvider? @@ -79,7 +76,7 @@ suspend fun > List.toUi( fun Throwable.toErrorState(canRetry: Boolean = true) = ErrorState( exception = this, - icon = getErrorIcon(this), + icon = getDisplayIcon(), canRetry = canRetry, buttonText = ExceptionResolver.getResolveStringId(this).ifZero { R.string.try_again }, ) @@ -88,13 +85,3 @@ fun Throwable.toErrorFooter() = ErrorFooter( exception = this, 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 -} diff --git a/app/src/main/res/layout/activity_image.xml b/app/src/main/res/layout/activity_image.xml index 7d147e770..c76318b27 100644 --- a/app/src/main/res/layout/activity_image.xml +++ b/app/src/main/res/layout/activity_image.xml @@ -23,4 +23,10 @@ android:layout_gravity="center" android:indeterminate="true" /> + +