diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/CoroutineHelpers.kt b/AnkiDroid/src/main/java/com/ichi2/anki/CoroutineHelpers.kt index a54f849b3165..b2b2b62f7e87 100644 --- a/AnkiDroid/src/main/java/com/ichi2/anki/CoroutineHelpers.kt +++ b/AnkiDroid/src/main/java/com/ichi2/anki/CoroutineHelpers.kt @@ -16,11 +16,13 @@ package com.ichi2.anki +import android.app.Activity import android.content.Context import android.view.WindowManager import androidx.appcompat.app.AlertDialog import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentActivity +import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.coroutineScope import anki.collection.Progress import com.ichi2.anki.snackbar.showSnackbar @@ -247,3 +249,33 @@ suspend fun AnkiActivity.userAcceptsSchemaChange(col: Collection): Boolean { .show() } } + +/** + * Launch a job that catches any uncaught errors, informs the user and prints it to Log. + * Errors from the backend contain localized text that is often suitable to show to the user as-is. + * Other errors should ideally be handled in the block. + */ +fun LifecycleOwner.catchingLifecycleScope( + activity: Activity, + errorMessage: String? = null, + block: suspend CoroutineScope.() -> Unit +): Job = lifecycle.coroutineScope.launch { + try { + block() + } catch (e: CancellationException) { + throw e + } catch (e: Exception) { + // TODO: localize + Timber.w(e, errorMessage) + UIUtils.showDismissibleSnackbar(activity, "An error occurred: $e", R.string.close) + CrashReportService.sendExceptionReport(e, activity::class.java.simpleName) + } +} + +/** + * @see [LifecycleOwner.catchingLifecycleScope] + */ +fun Fragment.catchingLifecycleScope( + errorMessage: String? = null, + block: suspend CoroutineScope.() -> Unit +) = (this as LifecycleOwner).catchingLifecycleScope(requireActivity(), errorMessage, block) diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/Statistics.kt b/AnkiDroid/src/main/java/com/ichi2/anki/Statistics.kt index 09bc02537e18..1daeabf3ef5f 100644 --- a/AnkiDroid/src/main/java/com/ichi2/anki/Statistics.kt +++ b/AnkiDroid/src/main/java/com/ichi2/anki/Statistics.kt @@ -44,7 +44,6 @@ import com.ichi2.anki.stats.AnkiStatsTaskHandler import com.ichi2.anki.stats.AnkiStatsTaskHandler.Companion.getInstance import com.ichi2.anki.stats.ChartView import com.ichi2.anki.widgets.DeckDropDownAdapter.SubtitleListener -import com.ichi2.async.catchingLifecycleScope import com.ichi2.libanki.Collection import com.ichi2.libanki.DeckId import com.ichi2.libanki.Decks @@ -451,7 +450,7 @@ class Statistics : NavigationDrawerActivity(), DeckSelectionListener, SubtitleLi private fun createStatisticOverview() { val handler = (requireActivity() as Statistics).taskHandler - statisticsJob = catchingLifecycleScope(requireActivity(), "createStatisticOverview failed with error") { + statisticsJob = catchingLifecycleScope("createStatisticOverview failed with error") { handler.createStatisticsOverview(mWebView, mProgressBar) } }