Refactor error handling
parent
da47dac3f7
commit
c50fa8f10c
@ -0,0 +1,66 @@
|
|||||||
|
package org.koitharu.kotatsu.core.exceptions.resolve
|
||||||
|
|
||||||
|
import android.content.DialogInterface
|
||||||
|
import android.view.View
|
||||||
|
import androidx.core.util.Consumer
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
|
import org.koitharu.kotatsu.R
|
||||||
|
import org.koitharu.kotatsu.core.ui.MangaErrorDialog
|
||||||
|
import org.koitharu.kotatsu.parsers.exception.ParseException
|
||||||
|
import org.koitharu.kotatsu.utils.ext.getDisplayMessage
|
||||||
|
|
||||||
|
class DialogErrorObserver(
|
||||||
|
host: View,
|
||||||
|
fragment: Fragment?,
|
||||||
|
resolver: ExceptionResolver?,
|
||||||
|
private val onResolved: Consumer<Boolean>?,
|
||||||
|
) : ErrorObserver(host, fragment, resolver, onResolved) {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
host: View,
|
||||||
|
fragment: Fragment?,
|
||||||
|
) : this(host, fragment, null, null)
|
||||||
|
|
||||||
|
override fun onChanged(error: Throwable?) {
|
||||||
|
if (error == null) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val listener = DialogListener(error)
|
||||||
|
val dialogBuilder = MaterialAlertDialogBuilder(activity ?: host.context)
|
||||||
|
.setMessage(error.getDisplayMessage(host.context.resources))
|
||||||
|
.setNegativeButton(R.string.close, listener)
|
||||||
|
.setOnCancelListener(listener)
|
||||||
|
if (canResolve(error)) {
|
||||||
|
dialogBuilder.setPositiveButton(ExceptionResolver.getResolveStringId(error), listener)
|
||||||
|
} else if (error is ParseException) {
|
||||||
|
val fm = fragmentManager
|
||||||
|
if (fm != null) {
|
||||||
|
dialogBuilder.setPositiveButton(R.string.details) { _, _ ->
|
||||||
|
MangaErrorDialog.show(fm, error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val dialog = dialogBuilder.create()
|
||||||
|
if (activity != null) {
|
||||||
|
dialog.setOwnerActivity(activity)
|
||||||
|
}
|
||||||
|
dialog.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
private inner class DialogListener(
|
||||||
|
private val error: Throwable,
|
||||||
|
) : DialogInterface.OnClickListener, DialogInterface.OnCancelListener {
|
||||||
|
|
||||||
|
override fun onClick(dialog: DialogInterface?, which: Int) {
|
||||||
|
when (which) {
|
||||||
|
DialogInterface.BUTTON_NEGATIVE -> onResolved?.accept(false)
|
||||||
|
DialogInterface.BUTTON_POSITIVE -> resolve(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCancel(dialog: DialogInterface?) {
|
||||||
|
onResolved?.accept(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,44 @@
|
|||||||
|
package org.koitharu.kotatsu.core.exceptions.resolve
|
||||||
|
|
||||||
|
import android.view.View
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.core.util.Consumer
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.fragment.app.FragmentManager
|
||||||
|
import androidx.lifecycle.LifecycleCoroutineScope
|
||||||
|
import androidx.lifecycle.LifecycleOwner
|
||||||
|
import androidx.lifecycle.Observer
|
||||||
|
import androidx.lifecycle.coroutineScope
|
||||||
|
import kotlinx.coroutines.isActive
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import org.koitharu.kotatsu.utils.ext.findActivity
|
||||||
|
import org.koitharu.kotatsu.utils.ext.viewLifecycleScope
|
||||||
|
|
||||||
|
abstract class ErrorObserver(
|
||||||
|
protected val host: View,
|
||||||
|
protected val fragment: Fragment?,
|
||||||
|
private val resolver: ExceptionResolver?,
|
||||||
|
private val onResolved: Consumer<Boolean>?,
|
||||||
|
) : Observer<Throwable> {
|
||||||
|
|
||||||
|
protected val activity = host.context.findActivity()
|
||||||
|
|
||||||
|
private val lifecycleScope: LifecycleCoroutineScope
|
||||||
|
get() = checkNotNull(fragment?.viewLifecycleScope ?: (activity as? LifecycleOwner)?.lifecycle?.coroutineScope)
|
||||||
|
|
||||||
|
protected val fragmentManager: FragmentManager?
|
||||||
|
get() = fragment?.childFragmentManager ?: (activity as? AppCompatActivity)?.supportFragmentManager
|
||||||
|
|
||||||
|
protected fun canResolve(error: Throwable): Boolean {
|
||||||
|
return resolver != null && ExceptionResolver.canResolve(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun resolve(error: Throwable) {
|
||||||
|
lifecycleScope.launch {
|
||||||
|
val isResolved = resolver?.resolve(error) ?: false
|
||||||
|
if (isActive) {
|
||||||
|
onResolved?.accept(isResolved)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,47 @@
|
|||||||
|
package org.koitharu.kotatsu.core.exceptions.resolve
|
||||||
|
|
||||||
|
import android.view.View
|
||||||
|
import androidx.core.util.Consumer
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import com.google.android.material.snackbar.Snackbar
|
||||||
|
import org.koitharu.kotatsu.R
|
||||||
|
import org.koitharu.kotatsu.core.ui.MangaErrorDialog
|
||||||
|
import org.koitharu.kotatsu.main.ui.owners.BottomNavOwner
|
||||||
|
import org.koitharu.kotatsu.parsers.exception.ParseException
|
||||||
|
import org.koitharu.kotatsu.utils.ext.getDisplayMessage
|
||||||
|
|
||||||
|
class SnackbarErrorObserver(
|
||||||
|
host: View,
|
||||||
|
fragment: Fragment?,
|
||||||
|
resolver: ExceptionResolver?,
|
||||||
|
onResolved: Consumer<Boolean>?,
|
||||||
|
) : ErrorObserver(host, fragment, resolver, onResolved) {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
host: View,
|
||||||
|
fragment: Fragment?,
|
||||||
|
) : this(host, fragment, null, null)
|
||||||
|
|
||||||
|
override fun onChanged(error: Throwable?) {
|
||||||
|
if (error == null) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val snackbar = Snackbar.make(host, error.getDisplayMessage(host.context.resources), Snackbar.LENGTH_SHORT)
|
||||||
|
if (activity is BottomNavOwner) {
|
||||||
|
snackbar.anchorView = activity.bottomNav
|
||||||
|
}
|
||||||
|
if (canResolve(error)) {
|
||||||
|
snackbar.setAction(ExceptionResolver.getResolveStringId(error)) {
|
||||||
|
resolve(error)
|
||||||
|
}
|
||||||
|
} else if (error is ParseException) {
|
||||||
|
val fm = fragmentManager
|
||||||
|
if (fm != null) {
|
||||||
|
snackbar.setAction(R.string.details) {
|
||||||
|
MangaErrorDialog.show(fm, error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
snackbar.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue