diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/CardTemplateEditor.kt b/AnkiDroid/src/main/java/com/ichi2/anki/CardTemplateEditor.kt index b825ecc34680..83ce64b768c1 100644 --- a/AnkiDroid/src/main/java/com/ichi2/anki/CardTemplateEditor.kt +++ b/AnkiDroid/src/main/java/com/ichi2/anki/CardTemplateEditor.kt @@ -73,6 +73,7 @@ import com.ichi2.anki.dialogs.DeckSelectionDialog import com.ichi2.anki.dialogs.DeckSelectionDialog.DeckSelectionListener import com.ichi2.anki.dialogs.DiscardChangesDialog import com.ichi2.anki.dialogs.InsertFieldDialog +import com.ichi2.anki.libanki.CardOrdinal import com.ichi2.anki.libanki.CardTemplates import com.ichi2.anki.libanki.Collection import com.ichi2.anki.libanki.Note @@ -148,11 +149,11 @@ open class CardTemplateEditor : * The inner HashMap's key is the editor window ID (e.g., R.id.front_edit). * The value is the cursor position within that editor window. */ - private var tabToCursorPositions: HashMap> = HashMap() + private var tabToCursorPositions: HashMap> = HashMap() // the current editor view among front/style/back private var tabToViewId: HashMap = HashMap() - private var startingOrdId = 0 + private var startingOrdId: CardOrdinal = 0 /** * If true, the view is split in two. The template editor appears on the leading side and the previewer on the trailing side. @@ -193,7 +194,7 @@ open class CardTemplateEditor : // get id for currently edited note (optional) noteId = intent.getLongExtra(EDITOR_NOTE_ID, -1L) // get id for currently edited template (optional) - startingOrdId = intent.getIntExtra("ordId", -1) + startingOrdId = intent.getIntExtra(EDITOR_START_ORD_ID, -1) tabToCursorPositions[0] = hashMapOf() tabToViewId[0] = R.id.front_edit } else { @@ -1531,5 +1532,25 @@ open class CardTemplateEditor : @Suppress("unused") private const val REQUEST_CARD_BROWSER_APPEARANCE = 1 + + @CheckResult + fun getIntent( + context: Context, + noteTypeId: NoteTypeId, + noteId: NoteId? = null, + ord: CardOrdinal? = null, + ) = Intent(context, CardTemplateEditor::class.java) + .apply { + putExtra(EDITOR_NOTE_TYPE_ID, noteTypeId) + noteId?.let { putExtra(EDITOR_NOTE_ID, it) } + ord?.let { putExtra(EDITOR_START_ORD_ID, it) } + + Timber.d( + "Built intent for CardTemplateEditor; ntid: %s; nid: %s; ord: %s", + noteTypeId, + noteId, + ord, + ) + } } } diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/NoteEditorActivity.kt b/AnkiDroid/src/main/java/com/ichi2/anki/NoteEditorActivity.kt index eaea73b5f001..954ea5ab0104 100644 --- a/AnkiDroid/src/main/java/com/ichi2/anki/NoteEditorActivity.kt +++ b/AnkiDroid/src/main/java/com/ichi2/anki/NoteEditorActivity.kt @@ -28,6 +28,7 @@ import com.ichi2.anki.NoteEditorActivity.Companion.FRAGMENT_NAME_EXTRA import com.ichi2.anki.android.input.ShortcutGroup import com.ichi2.anki.android.input.ShortcutGroupProvider import com.ichi2.anki.databinding.ActivityNoteEditorBinding +import com.ichi2.anki.libanki.CardOrdinal import com.ichi2.anki.libanki.Collection import com.ichi2.anki.noteeditor.NoteEditorFragmentDelegate import com.ichi2.anki.noteeditor.NoteEditorLauncher @@ -245,7 +246,7 @@ class NoteEditorActivity : private fun createPreviewerFragment( fields: List, tags: List, - ord: Int, + ord: CardOrdinal, ): TemplatePreviewerFragment { val args = TemplatePreviewerArguments( diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/NoteEditorFragment.kt b/AnkiDroid/src/main/java/com/ichi2/anki/NoteEditorFragment.kt index be4042816cea..c42aac616f88 100644 --- a/AnkiDroid/src/main/java/com/ichi2/anki/NoteEditorFragment.kt +++ b/AnkiDroid/src/main/java/com/ichi2/anki/NoteEditorFragment.kt @@ -100,6 +100,7 @@ import com.ichi2.anki.dialogs.tags.TagsDialog import com.ichi2.anki.dialogs.tags.TagsDialogFactory import com.ichi2.anki.dialogs.tags.TagsDialogListener import com.ichi2.anki.libanki.Card +import com.ichi2.anki.libanki.CardOrdinal import com.ichi2.anki.libanki.Collection import com.ichi2.anki.libanki.Consts import com.ichi2.anki.libanki.DeckId @@ -111,7 +112,6 @@ import com.ichi2.anki.libanki.Note.ClozeUtils import com.ichi2.anki.libanki.NoteTypeId import com.ichi2.anki.libanki.NotetypeJson import com.ichi2.anki.libanki.Notetypes -import com.ichi2.anki.libanki.Notetypes.Companion.NOT_FOUND_NOTE_TYPE import com.ichi2.anki.libanki.Utils import com.ichi2.anki.libanki.clozeNumbersInNote import com.ichi2.anki.model.CardStateFilter @@ -1682,7 +1682,7 @@ class NoteEditorFragment : * @param fields The processed note fields * @return The ordinal (position) of the card template to display */ - suspend fun determineCardOrdinal(fields: MutableList): Int { + suspend fun determineCardOrdinal(fields: MutableList): CardOrdinal { val ord = if (editorNote!!.notetype.isCloze) { val tempNote = withCol { Note.fromNotetypeId(this@withCol, editorNote!!.notetype.id) } @@ -1800,20 +1800,14 @@ class NoteEditorFragment : } private fun showCardTemplateEditor() { - val intent = Intent(requireContext(), CardTemplateEditor::class.java) - // Pass the note type ID - intent.putExtra("noteTypeId", currentlySelectedNotetype!!.id) - Timber.d( - "showCardTemplateEditor() for model %s", - intent.getLongExtra("noteTypeId", NOT_FOUND_NOTE_TYPE), - ) - // Also pass the note id and ord if not adding new note - if (!addNote && currentEditedCard != null) { - intent.putExtra("noteId", currentEditedCard!!.nid) - Timber.d("showCardTemplateEditor() with note %s", currentEditedCard!!.nid) - intent.putExtra("ordId", currentEditedCard!!.ord) - Timber.d("showCardTemplateEditor() with ord %s", currentEditedCard!!.ord) - } + val intent = + CardTemplateEditor.getIntent( + requireContext(), + noteTypeId = currentlySelectedNotetype!!.id, + // Also pass the note id and ord if not adding new note + noteId = if (addNote) null else currentEditedCard?.nid, + ord = if (addNote) null else currentEditedCard?.ord, + ) requestTemplateEditLauncher.launch(intent) } diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/cardviewer/AndroidCardRenderContext.kt b/AnkiDroid/src/main/java/com/ichi2/anki/cardviewer/AndroidCardRenderContext.kt index fa64c6d8a72c..de5bb96680ad 100644 --- a/AnkiDroid/src/main/java/com/ichi2/anki/cardviewer/AndroidCardRenderContext.kt +++ b/AnkiDroid/src/main/java/com/ichi2/anki/cardviewer/AndroidCardRenderContext.kt @@ -20,6 +20,7 @@ import android.content.Context import androidx.annotation.CheckResult import anki.config.ConfigKey import com.ichi2.anki.libanki.Card +import com.ichi2.anki.libanki.CardOrdinal import com.ichi2.anki.libanki.Collection import com.ichi2.anki.libanki.TemplateManager.TemplateRenderContext.TemplateRenderOutput import com.ichi2.anki.libanki.template.MathJax @@ -67,7 +68,7 @@ class AndroidCardRenderContext( private fun render( content: String, - ord: Int, + ord: CardOrdinal, ): RenderedCard { val requiresMathjax = MathJax.textContainsMathjax(content) diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/cardviewer/TTS.kt b/AnkiDroid/src/main/java/com/ichi2/anki/cardviewer/TTS.kt index d08f5d60d2fa..7ae2cbc79753 100644 --- a/AnkiDroid/src/main/java/com/ichi2/anki/cardviewer/TTS.kt +++ b/AnkiDroid/src/main/java/com/ichi2/anki/cardviewer/TTS.kt @@ -24,6 +24,7 @@ import com.ichi2.anki.R import com.ichi2.anki.ReadText import com.ichi2.anki.backend.stripHTML import com.ichi2.anki.libanki.Card +import com.ichi2.anki.libanki.CardOrdinal import com.ichi2.anki.libanki.Collection import com.ichi2.anki.libanki.TTSTag import com.ichi2.anki.libanki.template.TemplateFilters @@ -47,7 +48,7 @@ class TTS { private fun getOrdUsingCardType( card: Card, col: Collection, - ): Int = + ): CardOrdinal = if (card.noteType(col).isCloze) { 0 } else { diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/notetype/ManageNoteTypesState.kt b/AnkiDroid/src/main/java/com/ichi2/anki/notetype/ManageNoteTypesState.kt index 18383588b5f2..d054b461a26c 100644 --- a/AnkiDroid/src/main/java/com/ichi2/anki/notetype/ManageNoteTypesState.kt +++ b/AnkiDroid/src/main/java/com/ichi2/anki/notetype/ManageNoteTypesState.kt @@ -70,10 +70,7 @@ data class ManageNoteTypesState( data class CardEditor( val ntid: NoteTypeId, ) : Destination { - override fun toIntent(context: Context): Intent = - Intent(context, CardTemplateEditor::class.java).apply { - putExtra(CardTemplateEditor.EDITOR_NOTE_TYPE_ID, ntid) - } + override fun toIntent(context: Context) = CardTemplateEditor.getIntent(context, noteTypeId = ntid) } data class FieldsEditor( diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/previewer/PreviewerHelpers.kt b/AnkiDroid/src/main/java/com/ichi2/anki/previewer/PreviewerHelpers.kt index 969e97527806..6143002ef76a 100644 --- a/AnkiDroid/src/main/java/com/ichi2/anki/previewer/PreviewerHelpers.kt +++ b/AnkiDroid/src/main/java/com/ichi2/anki/previewer/PreviewerHelpers.kt @@ -23,6 +23,7 @@ import com.google.android.material.card.MaterialCardView import com.google.android.material.shape.ShapeAppearanceModel import com.ichi2.anki.AnkiDroidApp import com.ichi2.anki.LanguageUtils +import com.ichi2.anki.libanki.CardOrdinal import com.ichi2.anki.settings.Prefs import com.ichi2.anki.settings.enums.FrameStyle import com.ichi2.themes.Themes @@ -93,7 +94,7 @@ fun stdHtml( * @return body classes used when showing a card */ fun bodyClassForCardOrd( - cardOrd: Int, + cardOrd: CardOrdinal, nightMode: Boolean = Themes.isNightTheme, ): String = "card card${cardOrd + 1} ${bodyClass(nightMode)} mathjax-rendered" diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/previewer/TemplatePreviewerFragment.kt b/AnkiDroid/src/main/java/com/ichi2/anki/previewer/TemplatePreviewerFragment.kt index 0c3d0aef3177..6be7c79c36df 100644 --- a/AnkiDroid/src/main/java/com/ichi2/anki/previewer/TemplatePreviewerFragment.kt +++ b/AnkiDroid/src/main/java/com/ichi2/anki/previewer/TemplatePreviewerFragment.kt @@ -24,6 +24,7 @@ import com.google.android.material.tabs.TabLayout import com.ichi2.anki.R import com.ichi2.anki.databinding.FragmentTemplatePreviewerBinding import com.ichi2.anki.launchCatchingTask +import com.ichi2.anki.libanki.CardOrdinal import com.ichi2.anki.snackbar.BaseSnackbarBuilderProvider import com.ichi2.anki.snackbar.SnackbarBuilder import com.ichi2.anki.utils.ext.doOnTabSelected @@ -145,7 +146,7 @@ class TemplatePreviewerFragment : * * @return The safe cloze ordinal number */ - suspend fun getSafeClozeOrd(): Int = viewModel.getSafeClozeOrd() + suspend fun getSafeClozeOrd(): CardOrdinal = viewModel.getSafeClozeOrd() companion object { const val ARGS_KEY = "templatePreviewerArgs" diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/previewer/TemplatePreviewerViewModel.kt b/AnkiDroid/src/main/java/com/ichi2/anki/previewer/TemplatePreviewerViewModel.kt index 10dd74a11200..5db5d8e98760 100644 --- a/AnkiDroid/src/main/java/com/ichi2/anki/previewer/TemplatePreviewerViewModel.kt +++ b/AnkiDroid/src/main/java/com/ichi2/anki/previewer/TemplatePreviewerViewModel.kt @@ -24,6 +24,7 @@ import com.ichi2.anki.NotetypeFile import com.ichi2.anki.asyncIO import com.ichi2.anki.launchCatchingIO import com.ichi2.anki.libanki.Card +import com.ichi2.anki.libanki.CardOrdinal import com.ichi2.anki.libanki.Consts.DEFAULT_DECK_ID import com.ichi2.anki.libanki.DeckId import com.ichi2.anki.libanki.Note @@ -49,16 +50,16 @@ class TemplatePreviewerViewModel( private val isCloze: Boolean /** - * identifies which of the card templates or cloze deletions it corresponds to - * * for card templates, values are from 0 to the number of templates minus 1 - * * for cloze deletions, values are from 0 to max cloze index minus 1 + * Identifies which of the card templates or cloze deletions it corresponds to + * + * @see CardOrdinal */ @VisibleForTesting - val ordFlow: MutableStateFlow + val ordFlow: MutableStateFlow private val note: Deferred private val templateNames: Deferred> - private val clozeOrds: Deferred>? + private val clozeOrds: Deferred>? override var currentCard: Deferred override val server = AnkiServer(this).also { it.start() } @@ -207,7 +208,7 @@ class TemplatePreviewerViewModel( ordFlow.value } - suspend fun getSafeClozeOrd(): Int = ordFlow.value.coerceIn(0, clozeOrds!!.await().size - 1) + suspend fun getSafeClozeOrd(): CardOrdinal = ordFlow.value.coerceIn(0, clozeOrds!!.await().size - 1) fun updateContent( fields: List, @@ -271,11 +272,7 @@ class TemplatePreviewerViewModel( /** * @param id id of the note. Use 0 for non-created notes. - * - * @param ord identifies which of the card templates or cloze deletions it corresponds to - * * for card templates, values are from 0 to the number of templates minus 1 - * * for cloze deletions, values are from 0 to max cloze index minus 1 - * + * @param ord See [CardOrdinal] * @param fillEmpty if blank fields should be replaced with placeholder content */ @Parcelize @@ -284,7 +281,7 @@ data class TemplatePreviewerArguments( val fields: List, val tags: List, val id: NoteId = 0, - val ord: Int = 0, + val ord: CardOrdinal = 0, val fillEmpty: Boolean = false, val deckId: DeckId = DEFAULT_DECK_ID, ) : Parcelable { diff --git a/libanki/src/main/java/com/ichi2/anki/libanki/Card.kt b/libanki/src/main/java/com/ichi2/anki/libanki/Card.kt index b5c25e56673b..57e0bd0deb75 100644 --- a/libanki/src/main/java/com/ichi2/anki/libanki/Card.kt +++ b/libanki/src/main/java/com/ichi2/anki/libanki/Card.kt @@ -28,6 +28,19 @@ import net.ankiweb.rsdroid.RustCleanup private typealias BackendCard = anki.cards.Card private typealias FSRSMemoryState = anki.cards.FsrsMemoryState +/** + * Identifies the card template or cloze deletion which the card refers to. + * + * Values: + * - **card templates**: from 0 to [`templates.size - 1`][NotetypeJson.templates] + * - **cloze deletions**: `{{c1::}}` refers to ord 0. etc... + * + * Primarily used during rendering to determine the template to select, or cloze to hide. + * + * Defined as [Card.ord] + */ +typealias CardOrdinal = Int + /** * A Card is the ultimate entity subject to review; it encapsulates the scheduling parameters (from which to derive * the next interval), the note it is derived from (from which field data is retrieved), its own ownership (which deck it @@ -68,7 +81,11 @@ open class Card : Cloneable { var id: CardId = 0 var nid: NoteId = 0 var did: DeckId = 0 - var ord = 0 + + /** + * @see CardOrdinal + */ + var ord: CardOrdinal = 0 var mod: Long = 0 private var usn = 0 diff --git a/libanki/src/main/java/com/ichi2/anki/libanki/CardTemplate.kt b/libanki/src/main/java/com/ichi2/anki/libanki/CardTemplate.kt index b2eb697ee88a..67a6ecc61f26 100644 --- a/libanki/src/main/java/com/ichi2/anki/libanki/CardTemplate.kt +++ b/libanki/src/main/java/com/ichi2/anki/libanki/CardTemplate.kt @@ -67,8 +67,12 @@ data class CardTemplate( */ var name by jsonString("name") - /** The 0-based ordinal of the template */ - val ord by jsonInt("ord") + /** + * The 0-based ordinal of the template + * + * @see CardOrdinal + */ + val ord: CardOrdinal by jsonInt("ord") /** * Format string for the question when reviewing @@ -107,7 +111,7 @@ data class CardTemplate( /** @see ord */ @RustCleanup("Check JSONObject.NULL") - fun setOrd(value: Int?) = jsonObject.put("ord", value ?: JSONObject.NULL) + fun setOrd(value: CardOrdinal?) = jsonObject.put("ord", value ?: JSONObject.NULL) fun deepClone() = CardTemplate(jsonObject.deepClone())