Simplify repeated code that shows errors (#3762)
Instead of repeating the same if/else check on the error type when setting up the background message, move this in to BackgroundMessageView. Provide different `setup()` variants, including one that just takes a throwable and a handler, and figures out the correct drawables and error message. Update and simplify call sites.
This commit is contained in:
parent
af7e883165
commit
153a9ad9c2
14 changed files with 46 additions and 124 deletions
|
@ -46,7 +46,6 @@ import com.keylesspalace.tusky.util.viewBinding
|
||||||
import com.keylesspalace.tusky.viewmodel.AccountsInListViewModel
|
import com.keylesspalace.tusky.viewmodel.AccountsInListViewModel
|
||||||
import com.keylesspalace.tusky.viewmodel.State
|
import com.keylesspalace.tusky.viewmodel.State
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import java.io.IOException
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
private typealias AccountInfo = Pair<TimelineAccount, Boolean>
|
private typealias AccountInfo = Pair<TimelineAccount, Boolean>
|
||||||
|
@ -146,23 +145,10 @@ class AccountsInListFragment : DialogFragment(), Injectable {
|
||||||
|
|
||||||
private fun handleError(error: Throwable) {
|
private fun handleError(error: Throwable) {
|
||||||
binding.messageView.show()
|
binding.messageView.show()
|
||||||
val retryAction = { _: View ->
|
binding.messageView.setup(error) { _: View ->
|
||||||
binding.messageView.hide()
|
binding.messageView.hide()
|
||||||
viewModel.load(listId)
|
viewModel.load(listId)
|
||||||
}
|
}
|
||||||
if (error is IOException) {
|
|
||||||
binding.messageView.setup(
|
|
||||||
R.drawable.elephant_offline,
|
|
||||||
R.string.error_network,
|
|
||||||
retryAction
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
binding.messageView.setup(
|
|
||||||
R.drawable.elephant_error,
|
|
||||||
R.string.error_generic,
|
|
||||||
retryAction
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onRemoveFromList(accountId: String) {
|
private fun onRemoveFromList(accountId: String) {
|
||||||
|
|
|
@ -40,7 +40,6 @@ import com.keylesspalace.tusky.util.viewBinding
|
||||||
import com.keylesspalace.tusky.util.visible
|
import com.keylesspalace.tusky.util.visible
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import java.io.IOException
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class ListsForAccountFragment : DialogFragment(), Injectable {
|
class ListsForAccountFragment : DialogFragment(), Injectable {
|
||||||
|
@ -103,16 +102,7 @@ class ListsForAccountFragment : DialogFragment(), Injectable {
|
||||||
binding.listsView.hide()
|
binding.listsView.hide()
|
||||||
binding.messageView.apply {
|
binding.messageView.apply {
|
||||||
show()
|
show()
|
||||||
|
setup(error) { load() }
|
||||||
if (error is IOException) {
|
|
||||||
setup(R.drawable.elephant_offline, R.string.error_network) {
|
|
||||||
load()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
setup(R.drawable.elephant_error, R.string.error_generic) {
|
|
||||||
load()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,7 +51,6 @@ import com.mikepenz.iconics.utils.colorInt
|
||||||
import com.mikepenz.iconics.utils.sizeDp
|
import com.mikepenz.iconics.utils.sizeDp
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import java.io.IOException
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -133,12 +132,7 @@ class AccountMediaFragment :
|
||||||
}
|
}
|
||||||
is LoadState.Error -> {
|
is LoadState.Error -> {
|
||||||
binding.statusView.show()
|
binding.statusView.show()
|
||||||
|
binding.statusView.setup((loadState.refresh as LoadState.Error).error)
|
||||||
if ((loadState.refresh as LoadState.Error).error is IOException) {
|
|
||||||
binding.statusView.setup(R.drawable.elephant_offline, R.string.error_network, null)
|
|
||||||
} else {
|
|
||||||
binding.statusView.setup(R.drawable.elephant_error, R.string.error_generic, null)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
is LoadState.Loading -> {
|
is LoadState.Loading -> {
|
||||||
binding.progressBar.show()
|
binding.progressBar.show()
|
||||||
|
|
|
@ -393,16 +393,9 @@ class AccountListFragment :
|
||||||
|
|
||||||
if (adapter.itemCount == 0) {
|
if (adapter.itemCount == 0) {
|
||||||
binding.messageView.show()
|
binding.messageView.show()
|
||||||
if (throwable is IOException) {
|
binding.messageView.setup(throwable) {
|
||||||
binding.messageView.setup(R.drawable.elephant_offline, R.string.error_network) {
|
binding.messageView.hide()
|
||||||
binding.messageView.hide()
|
this.fetchAccounts(null)
|
||||||
this.fetchAccounts(null)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
binding.messageView.setup(R.drawable.elephant_error, R.string.error_generic) {
|
|
||||||
binding.messageView.hide()
|
|
||||||
this.fetchAccounts(null)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,7 +64,6 @@ import com.mikepenz.iconics.utils.sizeDp
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import java.io.IOException
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import kotlin.time.DurationUnit
|
import kotlin.time.DurationUnit
|
||||||
import kotlin.time.toDuration
|
import kotlin.time.toDuration
|
||||||
|
@ -139,16 +138,7 @@ class ConversationsFragment :
|
||||||
}
|
}
|
||||||
is LoadState.Error -> {
|
is LoadState.Error -> {
|
||||||
binding.statusView.show()
|
binding.statusView.show()
|
||||||
|
binding.statusView.setup((loadState.refresh as LoadState.Error).error) { refreshContent() }
|
||||||
if ((loadState.refresh as LoadState.Error).error is IOException) {
|
|
||||||
binding.statusView.setup(R.drawable.elephant_offline, R.string.error_network) {
|
|
||||||
refreshContent()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
binding.statusView.setup(R.drawable.elephant_error, R.string.error_generic) {
|
|
||||||
refreshContent()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
is LoadState.Loading -> {
|
is LoadState.Loading -> {
|
||||||
binding.progressBar.show()
|
binding.progressBar.show()
|
||||||
|
|
|
@ -31,7 +31,6 @@ import com.keylesspalace.tusky.util.viewBinding
|
||||||
import com.keylesspalace.tusky.util.visible
|
import com.keylesspalace.tusky.util.visible
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import java.io.IOException
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class FollowedTagsActivity :
|
class FollowedTagsActivity :
|
||||||
|
@ -108,11 +107,7 @@ class FollowedTagsActivity :
|
||||||
binding.followedTagsView.hide()
|
binding.followedTagsView.hide()
|
||||||
binding.followedTagsMessageView.show()
|
binding.followedTagsMessageView.show()
|
||||||
val errorState = loadState.refresh as LoadState.Error
|
val errorState = loadState.refresh as LoadState.Error
|
||||||
if (errorState.error is IOException) {
|
binding.followedTagsMessageView.setup(errorState.error) { retry() }
|
||||||
binding.followedTagsMessageView.setup(R.drawable.elephant_offline, R.string.error_network) { retry() }
|
|
||||||
} else {
|
|
||||||
binding.followedTagsMessageView.setup(R.drawable.elephant_error, R.string.error_generic) { retry() }
|
|
||||||
}
|
|
||||||
Log.w(TAG, "error loading followed hashtags", errorState.error)
|
Log.w(TAG, "error loading followed hashtags", errorState.error)
|
||||||
} else {
|
} else {
|
||||||
binding.followedTagsView.show()
|
binding.followedTagsView.show()
|
||||||
|
|
|
@ -26,7 +26,6 @@ import com.keylesspalace.tusky.util.viewBinding
|
||||||
import com.keylesspalace.tusky.view.EndlessOnScrollListener
|
import com.keylesspalace.tusky.view.EndlessOnScrollListener
|
||||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import java.io.IOException
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class InstanceListFragment : Fragment(R.layout.fragment_instance_list), Injectable, InstanceActionListener {
|
class InstanceListFragment : Fragment(R.layout.fragment_instance_list), Injectable, InstanceActionListener {
|
||||||
|
@ -146,16 +145,9 @@ class InstanceListFragment : Fragment(R.layout.fragment_instance_list), Injectab
|
||||||
|
|
||||||
if (adapter.itemCount == 0) {
|
if (adapter.itemCount == 0) {
|
||||||
binding.messageView.show()
|
binding.messageView.show()
|
||||||
if (throwable is IOException) {
|
binding.messageView.setup(throwable) {
|
||||||
binding.messageView.setup(R.drawable.elephant_offline, R.string.error_network) {
|
binding.messageView.hide()
|
||||||
binding.messageView.hide()
|
this.fetchInstances(null)
|
||||||
this.fetchInstances(null)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
binding.messageView.setup(R.drawable.elephant_error, R.string.error_generic) {
|
|
||||||
binding.messageView.hide()
|
|
||||||
this.fetchInstances(null)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,6 @@ import com.mikepenz.iconics.utils.colorInt
|
||||||
import com.mikepenz.iconics.utils.sizeDp
|
import com.mikepenz.iconics.utils.sizeDp
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import java.io.IOException
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class ScheduledStatusActivity :
|
class ScheduledStatusActivity :
|
||||||
|
@ -102,15 +101,7 @@ class ScheduledStatusActivity :
|
||||||
binding.errorMessageView.show()
|
binding.errorMessageView.show()
|
||||||
|
|
||||||
val errorState = loadState.refresh as LoadState.Error
|
val errorState = loadState.refresh as LoadState.Error
|
||||||
if (errorState.error is IOException) {
|
binding.errorMessageView.setup(errorState.error) { refreshStatuses() }
|
||||||
binding.errorMessageView.setup(R.drawable.elephant_offline, R.string.error_network) {
|
|
||||||
refreshStatuses()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
binding.errorMessageView.setup(R.drawable.elephant_error, R.string.error_generic) {
|
|
||||||
refreshStatuses()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (loadState.refresh != LoadState.Loading) {
|
if (loadState.refresh != LoadState.Loading) {
|
||||||
binding.swipeRefreshLayout.isRefreshing = false
|
binding.swipeRefreshLayout.isRefreshing = false
|
||||||
|
|
|
@ -79,7 +79,6 @@ import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||||
import io.reactivex.rxjava3.core.Observable
|
import io.reactivex.rxjava3.core.Observable
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import java.io.IOException
|
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@ -242,16 +241,7 @@ class TimelineFragment :
|
||||||
}
|
}
|
||||||
is LoadState.Error -> {
|
is LoadState.Error -> {
|
||||||
binding.statusView.show()
|
binding.statusView.show()
|
||||||
|
binding.statusView.setup((loadState.refresh as LoadState.Error).error) { onRefresh() }
|
||||||
if ((loadState.refresh as LoadState.Error).error is IOException) {
|
|
||||||
binding.statusView.setup(R.drawable.elephant_offline, R.string.error_network) {
|
|
||||||
onRefresh()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
binding.statusView.setup(R.drawable.elephant_error, R.string.error_generic) {
|
|
||||||
onRefresh()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
is LoadState.Loading -> {
|
is LoadState.Loading -> {
|
||||||
binding.progressBar.show()
|
binding.progressBar.show()
|
||||||
|
|
|
@ -60,7 +60,6 @@ import kotlinx.coroutines.CoroutineStart
|
||||||
import kotlinx.coroutines.awaitCancellation
|
import kotlinx.coroutines.awaitCancellation
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import java.io.IOException
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class ViewThreadFragment :
|
class ViewThreadFragment :
|
||||||
|
@ -201,21 +200,7 @@ class ViewThreadFragment :
|
||||||
binding.recyclerView.hide()
|
binding.recyclerView.hide()
|
||||||
binding.statusView.show()
|
binding.statusView.show()
|
||||||
|
|
||||||
if (uiState.throwable is IOException) {
|
binding.statusView.setup(uiState.throwable) { viewModel.retry(thisThreadsStatusId) }
|
||||||
binding.statusView.setup(
|
|
||||||
R.drawable.elephant_offline,
|
|
||||||
R.string.error_network
|
|
||||||
) {
|
|
||||||
viewModel.retry(thisThreadsStatusId)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
binding.statusView.setup(
|
|
||||||
R.drawable.elephant_error,
|
|
||||||
R.string.error_generic
|
|
||||||
) {
|
|
||||||
viewModel.retry(thisThreadsStatusId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
is ThreadUiState.Success -> {
|
is ThreadUiState.Success -> {
|
||||||
if (uiState.statusViewData.none { viewData -> viewData.isDetailed }) {
|
if (uiState.statusViewData.none { viewData -> viewData.isDetailed }) {
|
||||||
|
|
|
@ -53,7 +53,6 @@ import com.mikepenz.iconics.typeface.library.googlematerial.GoogleMaterial
|
||||||
import com.mikepenz.iconics.utils.colorInt
|
import com.mikepenz.iconics.utils.colorInt
|
||||||
import com.mikepenz.iconics.utils.sizeDp
|
import com.mikepenz.iconics.utils.sizeDp
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import java.io.IOException
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class ViewEditsFragment :
|
class ViewEditsFragment :
|
||||||
|
@ -112,14 +111,6 @@ class ViewEditsFragment :
|
||||||
binding.initialProgressBar.hide()
|
binding.initialProgressBar.hide()
|
||||||
|
|
||||||
when (uiState.throwable) {
|
when (uiState.throwable) {
|
||||||
is IOException -> {
|
|
||||||
binding.statusView.setup(
|
|
||||||
R.drawable.elephant_offline,
|
|
||||||
R.string.error_network
|
|
||||||
) {
|
|
||||||
viewModel.loadEdits(statusId, force = true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
is ViewEditsViewModel.MissingEditsException -> {
|
is ViewEditsViewModel.MissingEditsException -> {
|
||||||
binding.statusView.setup(
|
binding.statusView.setup(
|
||||||
R.drawable.elephant_friend_empty,
|
R.drawable.elephant_friend_empty,
|
||||||
|
@ -127,10 +118,7 @@ class ViewEditsFragment :
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
binding.statusView.setup(
|
binding.statusView.setup(uiState.throwable) {
|
||||||
R.drawable.elephant_error,
|
|
||||||
R.string.error_generic
|
|
||||||
) {
|
|
||||||
viewModel.loadEdits(statusId, force = true)
|
viewModel.loadEdits(statusId, force = true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
package com.keylesspalace.tusky.util
|
package com.keylesspalace.tusky.util
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import com.keylesspalace.tusky.R
|
||||||
import org.json.JSONException
|
import org.json.JSONException
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
import retrofit2.HttpException
|
import retrofit2.HttpException
|
||||||
|
import java.io.IOException
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* checks if this throwable indicates an error causes by a 4xx/5xx server response and
|
* checks if this throwable indicates an error causes by a 4xx/5xx server response and
|
||||||
|
@ -24,3 +27,16 @@ fun Throwable.getServerErrorMessage(): String? {
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return A drawable resource to accompany the error message for this throwable */
|
||||||
|
fun Throwable.getDrawableRes(): Int = when (this) {
|
||||||
|
is IOException -> R.drawable.elephant_offline
|
||||||
|
is HttpException -> R.drawable.elephant_offline
|
||||||
|
else -> R.drawable.elephant_error
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return A string error message for this throwable */
|
||||||
|
fun Throwable.getErrorString(context: Context): String = getServerErrorMessage() ?: when (this) {
|
||||||
|
is IOException -> context.getString(R.string.error_network)
|
||||||
|
else -> context.getString(R.string.error_generic)
|
||||||
|
}
|
||||||
|
|
|
@ -13,6 +13,8 @@ import androidx.annotation.StringRes
|
||||||
import com.keylesspalace.tusky.R
|
import com.keylesspalace.tusky.R
|
||||||
import com.keylesspalace.tusky.databinding.ViewBackgroundMessageBinding
|
import com.keylesspalace.tusky.databinding.ViewBackgroundMessageBinding
|
||||||
import com.keylesspalace.tusky.util.addDrawables
|
import com.keylesspalace.tusky.util.addDrawables
|
||||||
|
import com.keylesspalace.tusky.util.getDrawableRes
|
||||||
|
import com.keylesspalace.tusky.util.getErrorString
|
||||||
import com.keylesspalace.tusky.util.visible
|
import com.keylesspalace.tusky.util.visible
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -35,16 +37,26 @@ class BackgroundMessageView @JvmOverloads constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun setup(throwable: Throwable, listener: ((v: View) -> Unit)? = null) {
|
||||||
|
setup(throwable.getDrawableRes(), throwable.getErrorString(context), listener)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setup(
|
||||||
|
@DrawableRes imageRes: Int,
|
||||||
|
@StringRes messageRes: Int,
|
||||||
|
clickListener: ((v: View) -> Unit)? = null
|
||||||
|
) = setup(imageRes, context.getString(messageRes), clickListener)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Setup image, message and button.
|
* Setup image, message and button.
|
||||||
* If [clickListener] is `null` then the button will be hidden.
|
* If [clickListener] is `null` then the button will be hidden.
|
||||||
*/
|
*/
|
||||||
fun setup(
|
fun setup(
|
||||||
@DrawableRes imageRes: Int,
|
@DrawableRes imageRes: Int,
|
||||||
@StringRes messageRes: Int,
|
message: String,
|
||||||
clickListener: ((v: View) -> Unit)? = null
|
clickListener: ((v: View) -> Unit)? = null
|
||||||
) {
|
) {
|
||||||
binding.messageTextView.setText(messageRes)
|
binding.messageTextView.text = message
|
||||||
binding.messageTextView.movementMethod = LinkMovementMethod.getInstance()
|
binding.messageTextView.movementMethod = LinkMovementMethod.getInstance()
|
||||||
binding.imageView.setImageResource(imageRes)
|
binding.imageView.setImageResource(imageRes)
|
||||||
binding.button.setOnClickListener(clickListener)
|
binding.button.setOnClickListener(clickListener)
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
<resources>
|
<resources>
|
||||||
|
|
||||||
<string name="error_generic">An error occurred.</string>
|
<string name="error_generic">An error occurred.</string>
|
||||||
<string name="error_network">A network error occurred! Please check your connection and try again!</string>
|
<string name="error_network">A network error occurred. Please check your connection and try again.</string>
|
||||||
<string name="error_empty">This cannot be empty.</string>
|
<string name="error_empty">This cannot be empty.</string>
|
||||||
<string name="error_invalid_domain">Invalid domain entered</string>
|
<string name="error_invalid_domain">Invalid domain entered</string>
|
||||||
<string name="error_failed_app_registration">Failed authenticating with that instance. If this persists, try "Login in Browser" from the menu.</string>
|
<string name="error_failed_app_registration">Failed authenticating with that instance. If this persists, try "Login in Browser" from the menu.</string>
|
||||||
|
|
Loading…
Reference in a new issue