Skip to content

Commit

Permalink
refactor: make currentCard async
Browse files Browse the repository at this point in the history
so it's safer/easier to handle it (specially with tests timing)
  • Loading branch information
BrayanDSO committed Mar 24, 2024
1 parent 21ac0cc commit 154da0a
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import com.ichi2.libanki.Card
import com.ichi2.libanki.Sound
import com.ichi2.libanki.TtsPlayer
import com.ichi2.libanki.note
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.launch
Expand All @@ -55,7 +56,7 @@ abstract class CardViewerViewModel(
protected val soundPlayer = soundPlayer.apply {
setSoundErrorListener(createSoundErrorListener())
}
protected lateinit var currentCard: Card
abstract var currentCard: Deferred<Card>

@CallSuper
override fun onCleared() {
Expand All @@ -80,7 +81,7 @@ abstract class CardViewerViewModel(

fun playSoundFromUrl(url: String) {
launchCatchingIO {
Sound.getAvTag(currentCard, url)?.let {
Sound.getAvTag(currentCard.await(), url)?.let {
soundPlayer.playOneSound(it)
}
}
Expand All @@ -92,7 +93,7 @@ abstract class CardViewerViewModel(

protected abstract suspend fun typeAnsFilter(text: String): String

private fun bodyClass(): String = bodyClassForCardOrd(currentCard.ord)
private suspend fun bodyClass(): String = bodyClassForCardOrd(currentCard.await().ord)

/** From the [desktop code](https://github.com/ankitects/anki/blob/1ff55475b93ac43748d513794bcaabd5d7df6d9d/qt/aqt/reviewer.py#L358) */
private suspend fun mungeQA(text: String): String =
Expand All @@ -106,19 +107,23 @@ abstract class CardViewerViewModel(
Timber.v("showQuestion()")
showingAnswer.emit(false)

val questionData = withCol { currentCard.question(this) }
val card = currentCard.await()
val questionData = withCol { card.question(this) }
val question = mungeQA(questionData)
val answer =
withCol { media.escapeMediaFilenames(currentCard.answer(this)) }
withCol { media.escapeMediaFilenames(card.answer(this)) }

eval.emit("_showQuestion(${Json.encodeToString(question)}, ${Json.encodeToString(answer)}, '${bodyClass()}');")
}

protected open suspend fun showAnswerInternal() {
Timber.v("showAnswer()")
showingAnswer.emit(true)
val answerData = withCol { currentCard.answer(this) }

val card = currentCard.await()
val answerData = withCol { card.answer(this) }
val answer = mungeQA(answerData)

eval.emit("_showAnswer(${Json.encodeToString(answer)}, '${bodyClass()}');")
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -221,8 +221,10 @@ class PreviewerFragment :
}

private fun editCard() {
val intent = viewModel.getNoteEditorDestination().toIntent(requireContext())
editCardLauncher.launch(intent)
lifecycleScope.launch {
val intent = viewModel.getNoteEditorDestination().toIntent(requireContext())
editCardLauncher.launch(intent)
}
}

override fun dispatchKeyEvent(event: KeyEvent): Boolean {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import com.ichi2.anki.CollectionManager.withCol
import com.ichi2.anki.Flag
import com.ichi2.anki.NoteEditor
import com.ichi2.anki.OnErrorListener
import com.ichi2.anki.asyncIO
import com.ichi2.anki.browser.PreviewerIdsFile
import com.ichi2.anki.cardviewer.SingleCardSide
import com.ichi2.anki.cardviewer.SoundPlayer
Expand All @@ -34,6 +35,7 @@ import com.ichi2.libanki.Card
import com.ichi2.libanki.hasTag
import com.ichi2.libanki.note
import com.ichi2.libanki.undoableOp
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.combine
Expand Down Expand Up @@ -61,6 +63,10 @@ class PreviewerViewModel(previewerIdsFile: PreviewerIdsFile, firstIndex: Int, so

private val showAnswerOnReload get() = showingAnswer.value || backSideOnly.value

override var currentCard: Deferred<Card> = asyncIO {
withCol { getCard(selectedCardIds[currentIndex.value]) }
}

/* *********************************************************************************************
************************ Public methods: meant to be used by the View **************************
********************************************************************************************* */
Expand Down Expand Up @@ -95,16 +101,18 @@ class PreviewerViewModel(previewerIdsFile: PreviewerIdsFile, firstIndex: Int, so

fun toggleMark() {
launchCatchingIO {
val note = withCol { currentCard.note() }
val card = currentCard.await()
val note = withCol { card.note() }
NoteService.toggleMark(note)
isMarked.emit(NoteService.isMarked(note))
}
}

fun setFlag(flag: Flag) {
launchCatchingIO {
val card = currentCard.await()
undoableOp {
setUserFlagForCards(listOf(currentCard.id), flag.code)
setUserFlagForCards(listOf(card.id), flag.code)
}
flagCode.emit(flag.code)
}
Expand Down Expand Up @@ -139,7 +147,7 @@ class PreviewerViewModel(previewerIdsFile: PreviewerIdsFile, firstIndex: Int, so
}
}

fun getNoteEditorDestination() = NoteEditorDestination(currentCard.id)
suspend fun getNoteEditorDestination() = NoteEditorDestination(currentCard.await().id)

fun handleEditCardResult(result: ActivityResult) {
if (result.data?.getBooleanExtra(NoteEditor.RELOAD_REQUIRED_EXTRA_KEY, false) == true ||
Expand Down Expand Up @@ -173,18 +181,21 @@ class PreviewerViewModel(previewerIdsFile: PreviewerIdsFile, firstIndex: Int, so
********************************************************************************************* */

private suspend fun showCard(showAnswer: Boolean) {
currentCard = withCol { getCard(selectedCardIds[currentIndex.value]) }
currentCard = asyncIO {
withCol { getCard(selectedCardIds[currentIndex.value]) }
}
if (showAnswer) showAnswerInternal() else showQuestion()
updateFlagIcon()
updateMarkIcon()
}

private suspend fun updateFlagIcon() {
flagCode.emit(currentCard.userFlag())
flagCode.emit(currentCard.await().userFlag())
}

private suspend fun updateMarkIcon() {
val isMarkedValue = withCol { currentCard.note().hasTag(MARKED_TAG) }
val card = currentCard.await()
val isMarkedValue = withCol { card.note().hasTag(MARKED_TAG) }
isMarked.emit(isMarkedValue)
}

Expand All @@ -194,14 +205,14 @@ class PreviewerViewModel(previewerIdsFile: PreviewerIdsFile, firstIndex: Int, so
showingAnswer.value -> CardSide.ANSWER
else -> CardSide.QUESTION
}
soundPlayer.loadCardSounds(currentCard)
soundPlayer.loadCardSounds(currentCard.await())
soundPlayer.playAllSoundsForSide(side)
}

/** From the [desktop code](https://github.com/ankitects/anki/blob/1ff55475b93ac43748d513794bcaabd5d7df6d9d/qt/aqt/reviewer.py#L671) */
override suspend fun typeAnsFilter(text: String): String {
return if (showingAnswer.value) {
typeAnsAnswerFilter(currentCard, text)
typeAnsAnswerFilter(currentCard.await(), text)
} else {
typeAnsQuestionFilter(text)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import com.ichi2.anki.cardviewer.SoundPlayer
import com.ichi2.anki.launchCatchingIO
import com.ichi2.anki.reviewer.CardSide
import com.ichi2.anki.utils.ext.ifNullOrEmpty
import com.ichi2.libanki.Card
import com.ichi2.libanki.Note
import com.ichi2.libanki.NotetypeJson
import kotlinx.coroutines.CompletableDeferred
Expand Down Expand Up @@ -57,6 +58,7 @@ class TemplatePreviewerViewModel(
private val note: Deferred<Note>
private val templateNames: Deferred<List<String>>
private val clozeOrds: Deferred<List<Int>>?
override var currentCard: Deferred<Card>

init {
note = asyncIO {
Expand All @@ -71,6 +73,17 @@ class TemplatePreviewerViewModel(
tags = arguments.tags
}
}
currentCard = asyncIO {
val note = note.await()
withCol {
note.ephemeralCard(
col = this,
ord = ordFlow.value,
customNoteType = notetype,
fillEmpty = fillEmpty
)
}
}
if (isCloze) {
val clozeNumbers = asyncIO {
val note = note.await()
Expand Down Expand Up @@ -101,16 +114,7 @@ class TemplatePreviewerViewModel(
return
}
launchCatchingIO {
val note = note.await()
ordFlow.collectLatest {
currentCard = withCol {
note.ephemeralCard(
col = this,
ord = ordFlow.value,
customNoteType = notetype,
fillEmpty = fillEmpty
)
}
showQuestion()
loadAndPlaySounds(CardSide.QUESTION)
}
Expand Down Expand Up @@ -159,15 +163,15 @@ class TemplatePreviewerViewModel(
********************************************************************************************* */

private suspend fun loadAndPlaySounds(side: CardSide) {
soundPlayer.loadCardSounds(currentCard)
soundPlayer.loadCardSounds(currentCard.await())
soundPlayer.playAllSoundsForSide(side)
}

// https://github.com/ankitects/anki/blob/df70564079f53e587dc44f015c503fdf6a70924f/qt/aqt/clayout.py#L579
override suspend fun typeAnsFilter(text: String): String {
val typeAnswerField = getTypeAnswerField(currentCard, text)
val typeAnswerField = getTypeAnswerField(currentCard.await(), text)
val expectedAnswer = typeAnswerField?.let {
getExpectedTypeInAnswer(currentCard, typeAnswerField)
getExpectedTypeInAnswer(currentCard.await(), typeAnswerField)
}.ifNullOrEmpty { "sample" }

val repl = if (showingAnswer.value) {
Expand Down

0 comments on commit 154da0a

Please sign in to comment.