@@ -34,6 +34,8 @@ package com.ichi2.libanki
3434import androidx.annotation.CheckResult
3535import anki.collection.OpChanges
3636import anki.collection.OpChangesWithId
37+ import anki.notetypes.ChangeNotetypeInfo
38+ import anki.notetypes.ChangeNotetypeRequest
3739import anki.notetypes.Notetype
3840import anki.notetypes.NotetypeId
3941import anki.notetypes.NotetypeNameId
@@ -55,6 +57,7 @@ import com.ichi2.libanki.utils.insert
5557import com.ichi2.libanki.utils.len
5658import com.ichi2.libanki.utils.remove
5759import net.ankiweb.rsdroid.RustCleanup
60+ import net.ankiweb.rsdroid.exceptions.BackendInvalidInputException
5861import net.ankiweb.rsdroid.exceptions.BackendNotFoundException
5962import org.intellij.lang.annotations.Language
6063import org.json.JSONArray
@@ -527,6 +530,82 @@ class Notetypes(
527530 save(notetype)
528531 }
529532
533+ /*
534+ * Changing notetypes of notes
535+ * ***********************************************************
536+ */
537+
538+ /* *
539+ * @return The ID of the single note type which all supplied notes are using; throws otherwise
540+ *
541+ * @throws BackendInvalidInputException notes from different note types were supplied
542+ * @throws BackendInvalidInputException an empty list was supplied
543+ * @throws BackendNotFoundException One of the provided IDs was invalid
544+ */
545+ @CheckResult
546+ @LibAnkiAlias(" get_single_notetype_of_notes" )
547+ fun getSingleNotetypeOfNotes (noteIds : List <NoteId >): NoteTypeId = col.backend.getSingleNotetypeOfNotes(noteIds)
548+
549+ @CheckResult
550+ @LibAnkiAlias(" change_notetype_info" )
551+ fun changeNotetypeInfo (
552+ oldNoteTypeId : NoteTypeId ,
553+ newNoteTypeId : NoteTypeId ,
554+ ): ChangeNotetypeInfo =
555+ this .col.backend.getChangeNotetypeInfo(
556+ oldNotetypeId = oldNoteTypeId,
557+ newNotetypeId = newNoteTypeId,
558+ )
559+
560+ /* *
561+ * Assign a new notetype, optionally altering field/template order.
562+ *
563+ * To get defaults, use
564+ *
565+ * ```kotlin
566+ * val info = col.models.change_notetype_info(...)
567+ * val input = info.input
568+ * input.note_ids.extend([...])
569+ * ```
570+ *
571+ * The `newFields` and `newTemplates` lists are relative to the new notetype's
572+ * field/template count.
573+ *
574+ * Each value represents the index in the previous notetype.
575+ * -1 indicates the original value will be discarded.
576+ */
577+ @LibAnkiAlias(" change_notetype_of_notes" )
578+ fun changeNotetypeOfNotes (input : ChangeNotetypeRequest ): OpChanges {
579+ val opBytes = this .col.backend.changeNotetypeRaw(input.toByteArray())
580+ return OpChanges .parseFrom(opBytes)
581+ }
582+
583+ /* *
584+ * Restores a notetype to its original stock kind.
585+ *
586+ * @param notetypeId id of the changed notetype
587+ * @param forceKind optional stock kind to be forced instead of the original kind.
588+ * Older notetypes did not store their original stock kind, so we allow the UI
589+ * to pass in an override to use when missing, or for tests.
590+ */
591+ @CheckResult
592+ @LibAnkiAlias(" restore_notetype_to_stock" )
593+ fun restoreNotetypeToStock (
594+ notetypeId : NotetypeId ,
595+ forceKind : StockNotetype .Kind ? = null,
596+ ): OpChanges {
597+ val msg =
598+ restoreNotetypeToStockRequest {
599+ this .notetypeId = notetypeId
600+ forceKind?.let { this .forceKind = forceKind }
601+ }
602+ return col.backend.restoreNotetypeToStock(msg).also {
603+ // not in libAnki:
604+ // Remove the specific notetype from cache to ensure consistency after restoration
605+ removeFromCache(notetypeId.ntid)
606+ }
607+ }
608+
530609 /*
531610 # Model changing
532611 ##########################################################################
@@ -741,29 +820,5 @@ fun Collection.addNotetypeLegacy(json: ByteString): OpChangesWithId {
741820fun Collection.getStockNotetype (kind : StockNotetype .Kind ): NotetypeJson =
742821 NotetypeJson (fromJsonBytes(backend.getStockNotetypeLegacy(kind = kind)))
743822
744- /* *
745- * Restores a notetype to its original stock kind.
746- *
747- * @param notetypeId id of the changed notetype
748- * @param forceKind optional stock kind to be forced instead of the original kind.
749- * Older notetypes did not store their original stock kind, so we allow the UI
750- * to pass in an override to use when missing, or for tests.
751- */
752- @CheckResult
753- fun Collection.restoreNotetypeToStock (
754- notetypeId : NotetypeId ,
755- forceKind : StockNotetype .Kind ? = null,
756- ): OpChanges {
757- val msg =
758- restoreNotetypeToStockRequest {
759- this .notetypeId = notetypeId
760- forceKind?.let { this .forceKind = forceKind }
761- }
762- val result = backend.restoreNotetypeToStock(msg)
763- // Remove the specific notetype from cache to ensure consistency after restoration
764- notetypes.removeFromCache(notetypeId.ntid)
765- return result
766- }
767-
768823@NotInLibAnki
769824fun getStockNotetypeKinds (): List <StockNotetype .Kind > = StockNotetype .Kind .entries.filter { it != StockNotetype .Kind .UNRECOGNIZED }
0 commit comments