From 731b85c5ad70f4cc5d404627565cd1c4b9d07f3d Mon Sep 17 00:00:00 2001 From: David Allison <62114487+david-allison@users.noreply.github.com> Date: Thu, 2 May 2024 11:37:52 +0100 Subject: [PATCH] fix: lateinit property of questions and answers not initialised `isAfterRecreation = true` -> sounds were not loaded This was triggered if "Don't keep activities" was set Fixes 16302 --- .../com/ichi2/anki/SingleFragmentActivity.kt | 1 + .../ichi2/anki/cardviewer/CardMediaPlayer.kt | 18 ++++++++++++++++++ .../ichi2/anki/previewer/PreviewerViewModel.kt | 13 ++++++++++++- 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/SingleFragmentActivity.kt b/AnkiDroid/src/main/java/com/ichi2/anki/SingleFragmentActivity.kt index 88fc97815a76..e66e0bcb4c7a 100644 --- a/AnkiDroid/src/main/java/com/ichi2/anki/SingleFragmentActivity.kt +++ b/AnkiDroid/src/main/java/com/ichi2/anki/SingleFragmentActivity.kt @@ -46,6 +46,7 @@ open class SingleFragmentActivity : AnkiActivity() { setTransparentStatusBar() // avoid recreating the fragment on configuration changes + // the fragment should handle state restoration if (savedInstanceState != null) { return } diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/cardviewer/CardMediaPlayer.kt b/AnkiDroid/src/main/java/com/ichi2/anki/cardviewer/CardMediaPlayer.kt index 776aef4ddaa5..535322de98a1 100644 --- a/AnkiDroid/src/main/java/com/ichi2/anki/cardviewer/CardMediaPlayer.kt +++ b/AnkiDroid/src/main/java/com/ichi2/anki/cardviewer/CardMediaPlayer.kt @@ -148,6 +148,24 @@ class CardMediaPlayer : Closeable { } } + /** + * Ensures that [questions] and [answers] are loaded + * + * Does not affect playback if they are + */ + suspend fun ensureCardSoundsLoaded(card: Card) { + if (this::questions.isInitialized) return + + Timber.i("loading sounds for card %d", card.id) + val renderOutput = withCol { card.renderOutput(this) } + this.questions = renderOutput.questionAvTags + this.answers = renderOutput.answerAvTags + + if (!this::config.isInitialized || !config.appliesTo(card)) { + config = withCol { CardSoundConfig.create(card) } + } + } + suspend fun playAllSoundsForSide(cardSide: CardSide): Job? { if (!isEnabled) return null playSoundsJob { diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/previewer/PreviewerViewModel.kt b/AnkiDroid/src/main/java/com/ichi2/anki/previewer/PreviewerViewModel.kt index 79f893f7b76f..932c96cba7f9 100644 --- a/AnkiDroid/src/main/java/com/ichi2/anki/previewer/PreviewerViewModel.kt +++ b/AnkiDroid/src/main/java/com/ichi2/anki/previewer/PreviewerViewModel.kt @@ -31,6 +31,7 @@ import com.ichi2.anki.launchCatchingIO import com.ichi2.anki.reviewer.CardSide import com.ichi2.anki.servicelayer.MARKED_TAG import com.ichi2.anki.servicelayer.NoteService +import com.ichi2.annotations.NeedsTest import com.ichi2.libanki.Card import com.ichi2.libanki.hasTag import com.ichi2.libanki.note @@ -72,9 +73,19 @@ class PreviewerViewModel(previewerIdsFile: PreviewerIdsFile, firstIndex: Int, ca ********************************************************************************************* */ /** Call this after the webView has finished loading the page */ + @NeedsTest("16302 - a sound-only card on the back/flipped with 'don't keep activities'") + @NeedsTest("16302 - on config changes, sound continues to play") override fun onPageFinished(isAfterRecreation: Boolean) { if (isAfterRecreation) { - launchCatchingIO { showCard(showAnswerOnReload) } + launchCatchingIO { + showCard(showAnswerOnReload) + // isAfterRecreation can either mean: + // * after config change (ViewModel exists) + // * after recreation (ViewModel did not exist) + // if the ViewModel existed, we want to continue playing audio + // if not, we want to setup the sound player + cardMediaPlayer.ensureCardSoundsLoaded(currentCard.await()) + } return } launchCatchingIO {