diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/instantnoteeditor/InstantEditorViewModel.kt b/AnkiDroid/src/main/java/com/ichi2/anki/instantnoteeditor/InstantEditorViewModel.kt index 4d058abfa141..e83cc6f0bb66 100644 --- a/AnkiDroid/src/main/java/com/ichi2/anki/instantnoteeditor/InstantEditorViewModel.kt +++ b/AnkiDroid/src/main/java/com/ichi2/anki/instantnoteeditor/InstantEditorViewModel.kt @@ -17,6 +17,7 @@ package com.ichi2.anki.instantnoteeditor +import androidx.annotation.CheckResult import androidx.annotation.VisibleForTesting import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData @@ -26,6 +27,7 @@ import com.ichi2.anki.CollectionManager.withCol import com.ichi2.anki.NoteFieldsCheckResult import com.ichi2.anki.OnErrorListener import com.ichi2.anki.checkNoteFieldsResponse +import com.ichi2.anki.common.utils.ext.replaceWith import com.ichi2.anki.instantnoteeditor.InstantNoteEditorActivity.DialogType import com.ichi2.anki.libanki.DeckId import com.ichi2.anki.libanki.Note @@ -180,6 +182,18 @@ class InstantEditorViewModel : } } + /** + * Extracts the cloze ordinals from text (if any). + * + * `"{{c2::text}} {{c1::more}}"` => `[2, 1]` + */ + @CheckResult + private fun getClozeOrdinals(text: String): List = + clozePattern + .findAll(text) + .mapNotNull { it.groups[2]?.value?.toIntOrNull() } + .toList() + /** * Retrieves all cloze text fields from the current editor note's note type. * @@ -206,6 +220,8 @@ class InstantEditorViewModel : fun setClozeFieldText(text: String?) { _actualClozeFieldText.value = text + intClozeList.replaceWith(getClozeOrdinals(text ?: "")) + _currentClozeNumber.value = (intClozeList.maxOrNull() ?: 0) + 1 } /** diff --git a/AnkiDroid/src/test/java/com/ichi2/anki/instanteditor/InstantEditorViewModelTest.kt b/AnkiDroid/src/test/java/com/ichi2/anki/instanteditor/InstantEditorViewModelTest.kt index 2e9604d12322..c62da3f09522 100644 --- a/AnkiDroid/src/test/java/com/ichi2/anki/instanteditor/InstantEditorViewModelTest.kt +++ b/AnkiDroid/src/test/java/com/ichi2/anki/instanteditor/InstantEditorViewModelTest.kt @@ -213,6 +213,52 @@ class InstantEditorViewModelTest : RobolectricTest() { assertEquals(word, cleanWord) } + @Test + fun `cloze numbering continues from existing clozes`() = + runViewModelTest { + val text = + "This is the {{c1::first cloze}}. " + + "This should be the {{c2::second cloze}}. " + + "Similarly, this one as {{c3::third cloze}}." + + setClozeFieldText(text) + + val result = buildClozeText("fourth") + + assertEquals("{{c4::fourth}}", result) + } + + @Test + fun `removing a cloze does not reset numbering`() = + runViewModelTest { + val text = "{{c1::first}} {{c2::second}} {{c3::third}}" + + setClozeFieldText(text) + + val words = getWordsFromFieldText().toMutableList() + + words[1] = buildClozeText(words[1]) // remove c2 + + val result = buildClozeText("fourth") + + assertEquals("{{c4::fourth}}", result) + } + + @Test + fun `toggling cloze mode does not reset numbering`() = + runViewModelTest { + val text = "{{c1::first}} {{c2::second}} {{c3::third}}" + + setClozeFieldText(text) + + toggleClozeMode() // switch to NO_INCREMENT mode + toggleClozeMode() // switch back to INCREMENT mode + + val result = buildClozeText("fourth") + + assertEquals("{{c4::fourth}}", result) + } + private fun runViewModelTest( initViewModel: () -> InstantEditorViewModel = { InstantEditorViewModel() }, testBody: suspend InstantEditorViewModel.() -> Unit,