@@ -172,6 +172,7 @@ import com.ichi2.anki.utils.ext.dismissAllDialogFragments
172172import com.ichi2.anki.utils.ext.getSizeOfBitmapFromCollection
173173import com.ichi2.anki.utils.ext.setFragmentResultListener
174174import com.ichi2.anki.utils.ext.showDialogFragment
175+ import com.ichi2.anki.utils.runWithOOMCheck
175176import com.ichi2.anki.widgets.DeckAdapter
176177import com.ichi2.anki.worker.SyncMediaWorker
177178import com.ichi2.anki.worker.SyncWorker
@@ -198,6 +199,7 @@ import com.ichi2.utils.positiveButton
198199import com.ichi2.utils.show
199200import com.ichi2.utils.title
200201import com.ichi2.widget.WidgetStatus
202+ import kotlinx.coroutines.CancellationException
201203import kotlinx.coroutines.Dispatchers
202204import kotlinx.coroutines.Job
203205import kotlinx.coroutines.flow.collectLatest
@@ -557,22 +559,9 @@ open class DeckPicker :
557559 // Add background to Deckpicker activity
558560 val view = binding.deckpickerXlView ? : binding.rootLayout
559561
560- var hasDeckPickerBackground = false
561- try {
562- hasDeckPickerBackground = applyDeckPickerBackground()
563- } catch (e: OutOfMemoryError ) {
564- // 6608 - OOM should be catchable here.
565- Timber .w(e, " Failed to apply background - OOM" )
566- showThemedToast(this , getString(R .string.background_image_too_large), false )
567- } catch (e: Exception ) {
568- Timber .w(e, " Failed to apply background" )
569- showThemedToast(this , getString(R .string.failed_to_apply_background_image, e.localizedMessage), false )
570- }
571-
572562 deckListAdapter =
573563 DeckAdapter (
574564 this ,
575- activityHasBackground = hasDeckPickerBackground,
576565 onDeckSelected = { onDeckClick(it, DeckSelectionType .DEFAULT ) },
577566 onDeckCountsSelected = { onDeckClick(it, DeckSelectionType .SHOW_STUDY_OPTIONS ) },
578567 onDeckChildrenToggled = { deckId ->
@@ -587,6 +576,8 @@ open class DeckPicker :
587576 )
588577 deckPickerBinding.decks.adapter = deckListAdapter
589578
579+ lifecycleScope.launch { applyDeckPickerBackground() }
580+
590581 pullToSyncWrapper =
591582 deckPickerBinding.pullToSyncWrapper.apply {
592583 setDistanceToTriggerSync(SWIPE_TO_SYNC_TRIGGER_DISTANCE )
@@ -1065,43 +1056,82 @@ open class DeckPicker :
10651056 showDatabaseErrorDialog(DatabaseErrorDialogType .DIALOG_DISK_FULL )
10661057 }
10671058
1068- // throws doesn't seem to be checked by the compiler - consider it to be documentation
1069- @Throws(OutOfMemoryError ::class )
1070- private fun applyDeckPickerBackground (): Boolean {
1059+ // Note: when changing this method consider OutOfMemoryErrors
1060+ private suspend fun applyDeckPickerBackground () {
10711061 // Allow the user to clear data and get back to a good state if they provide an invalid background.
10721062 if (! Prefs .isBackgroundEnabled) {
10731063 Timber .d(" No DeckPicker background preference" )
10741064 deckPickerBinding.background.setBackgroundResource(0 )
1075- return false
1065+ deckListAdapter.activityHasBackground = false
1066+ return
10761067 }
10771068 val currentAnkiDroidDirectory = CollectionHelper .getCurrentAnkiDroidDirectory(this )
10781069 val imgFile = File (currentAnkiDroidDirectory, BackgroundImage .FILENAME )
10791070 if (! imgFile.exists()) {
10801071 Timber .d(" No DeckPicker background image" )
10811072 deckPickerBinding.background.setBackgroundResource(0 )
1082- return false
1073+ deckListAdapter.activityHasBackground = false
1074+ return
10831075 }
10841076
10851077 // TODO: Temporary fix to stop a crash on startup [15450], it can be removed either:
10861078 // * by moving this check to an upgrade path
10871079 // * once enough time has passed
10881080 // null shouldn't happen as we check for the file being present above this call
1089- val (bitmapWidth, bitmapHeight) = getSizeOfBitmapFromCollection(BackgroundImage .FILENAME ) ? : return false
1081+ val (bitmapWidth, bitmapHeight) = getSizeOfBitmapFromCollection(BackgroundImage .FILENAME ) ? : return
10901082 if (bitmapWidth <= 0 || bitmapHeight <= 0 ) {
10911083 Timber .w(" Decoding background image for dimensions info failed" )
10921084 deckPickerBinding.background.setBackgroundResource(0 )
1093- return false
1085+ deckListAdapter.activityHasBackground = false
1086+ return
10941087 }
10951088 if (bitmapWidth * bitmapHeight * BITMAP_BYTES_PER_PIXEL > BackgroundImage .MAX_BITMAP_SIZE ) {
10961089 Timber .w(" DeckPicker background image dimensions too large" )
10971090 deckPickerBinding.background.setBackgroundResource(0 )
1098- return false
1091+ deckListAdapter.activityHasBackground = false
1092+ return
1093+ }
1094+
1095+ fun onOOMError (error : OutOfMemoryError ) {
1096+ Timber .w(error, " Failed to apply background - OOM" )
1097+ showThemedToast(
1098+ this @DeckPicker,
1099+ getString(R .string.background_image_too_large),
1100+ false ,
1101+ )
1102+ deckListAdapter.activityHasBackground = false
10991103 }
11001104
1101- Timber .i(" Applying background" )
1102- val drawable = Drawable .createFromPath(imgFile.absolutePath)
1103- deckPickerBinding.background.setImageDrawable(drawable)
1104- return true
1105+ try {
1106+ Timber .i(" Applying background image selected by user" )
1107+ val drawable =
1108+ withContext(Dispatchers .IO ) {
1109+ // 6608 - OOM should be catchable here.
1110+ runWithOOMCheck(
1111+ { Drawable .createFromPath(imgFile.absolutePath) },
1112+ ::onOOMError,
1113+ )
1114+ }
1115+ runWithOOMCheck(
1116+ {
1117+ deckPickerBinding.background.setImageDrawable(drawable)
1118+ deckListAdapter.activityHasBackground = drawable != null
1119+ },
1120+ onError = ::onOOMError,
1121+ )
1122+ } catch (e: Exception ) {
1123+ if (e is CancellationException ) {
1124+ throw e
1125+ } else {
1126+ Timber .w(e, " Failed to apply background" )
1127+ showThemedToast(
1128+ this ,
1129+ getString(R .string.failed_to_apply_background_image, e.localizedMessage),
1130+ false ,
1131+ )
1132+ deckListAdapter.activityHasBackground = false
1133+ }
1134+ }
11051135 }
11061136
11071137 override fun onCreateOptionsMenu (menu : Menu ): Boolean {
0 commit comments