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