From 9c0911891d433143d34f6be02605a8923f9b0fb8 Mon Sep 17 00:00:00 2001 From: llama <100429699+iamllama@users.noreply.github.com> Date: Fri, 17 Jan 2025 13:03:00 +0800 Subject: [PATCH] Fix "Create copy" for IO notes (#3730) * expose get_image_occlusion_fields * fix create copy for io * revert current impl * passthru original note id when creating copy * add IOCloningMode * fix create copy for io --- qt/aqt/addcards.py | 6 ++-- qt/aqt/editor.py | 31 +++++++++++++------ ts/editor/NoteEditor.svelte | 2 +- ts/routes/image-occlusion/MaskEditor.svelte | 17 +++++++--- .../add-or-update-note.svelte.ts | 7 +++-- ts/routes/image-occlusion/lib.ts | 7 ++++- 6 files changed, 49 insertions(+), 21 deletions(-) diff --git a/qt/aqt/addcards.py b/qt/aqt/addcards.py index 306ac910f..7d155a872 100644 --- a/qt/aqt/addcards.py +++ b/qt/aqt/addcards.py @@ -78,7 +78,7 @@ class AddCards(QMainWindow): new_note.fields = note.fields[:] new_note.tags = note.tags[:] - self.setAndFocusNote(new_note) + self.setAndFocusNote(new_note, orig_note_id=note.id) def setupEditor(self) -> None: self.editor = aqt.editor.Editor( @@ -143,8 +143,8 @@ class AddCards(QMainWindow): b.setEnabled(False) self.historyButton = b - def setAndFocusNote(self, note: Note) -> None: - self.editor.set_note(note, focusTo=0) + def setAndFocusNote(self, note: Note, orig_note_id: NoteId | None = None) -> None: + self.editor.set_note(note, focusTo=0, orig_note_id=orig_note_id) def show_notetype_selector(self) -> None: self.editor.call_after_note_saved(self.notetype_chooser.choose_notetype) diff --git a/qt/aqt/editor.py b/qt/aqt/editor.py index 0806f3dc5..72ec7bcd8 100644 --- a/qt/aqt/editor.py +++ b/qt/aqt/editor.py @@ -524,20 +524,26 @@ require("anki/ui").loaded.then(() => require("anki/NoteEditor").instances[0].too ###################################################################### def set_note( - self, note: Note | None, hide: bool = True, focusTo: int | None = None + self, + note: Note | None, + hide: bool = True, + focusTo: int | None = None, + orig_note_id: NoteId | None = None, ) -> None: "Make NOTE the current note." self.note = note self.currentField = None if self.note: - self.loadNote(focusTo=focusTo) + self.loadNote(focusTo=focusTo, orig_note_id=orig_note_id) elif hide: self.widget.hide() def loadNoteKeepingFocus(self) -> None: self.loadNote(self.currentField) - def loadNote(self, focusTo: int | None = None) -> None: + def loadNote( + self, focusTo: int | None = None, orig_note_id: NoteId | None = None + ) -> None: if not self.note: return @@ -596,12 +602,13 @@ require("anki/ui").loaded.then(() => require("anki/NoteEditor").instances[0].too sticky = [field["sticky"] for field in self.note_type()["flds"]] js += " setSticky(%s);" % json.dumps(sticky) - if ( - self.editorMode != EditorMode.ADD_CARDS - and self.current_notetype_is_image_occlusion() - ): - io_options = self._create_edit_io_options(note_id=self.note.id) - js += " setupMaskEditor(%s);" % json.dumps(io_options) + if self.current_notetype_is_image_occlusion(): + if self.editorMode is not EditorMode.ADD_CARDS: + io_options = self._create_edit_io_options(note_id=self.note.id) + js += " setupMaskEditor(%s);" % json.dumps(io_options) + elif orig_note_id: + io_options = self._create_clone_io_options(cloned_note_id=orig_note_id) + js += " setupMaskEditor(%s);" % json.dumps(io_options) js = gui_hooks.editor_will_load_note(js, self.note, self) self.web.evalWithCallback( @@ -1161,6 +1168,12 @@ require("anki/ui").loaded.then(() => require("anki/NoteEditor").instances[0].too "html": image_field_html, } + @staticmethod + def _create_clone_io_options(cloned_note_id: NoteId) -> dict: + return { + "mode": {"kind": "add", "clonedNoteId": cloned_note_id}, + } + @staticmethod def _create_edit_io_options(note_id: NoteId) -> dict: return {"mode": {"kind": "edit", "noteId": note_id}} diff --git a/ts/editor/NoteEditor.svelte b/ts/editor/NoteEditor.svelte index 77c394f56..d0aea8466 100644 --- a/ts/editor/NoteEditor.svelte +++ b/ts/editor/NoteEditor.svelte @@ -431,7 +431,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html imageOcclusionMode = undefined; await tick(); imageOcclusionMode = options.mode; - if (options.mode.kind === "add") { + if (options.mode.kind === "add" && !("clonedNoteId" in options.mode)) { fieldStores[ioFields.image].set(options.html); // the image field is set programmatically and does not need debouncing // commit immediately to avoid a race condition with the occlusions field diff --git a/ts/routes/image-occlusion/MaskEditor.svelte b/ts/routes/image-occlusion/MaskEditor.svelte index 918123753..36de4db84 100644 --- a/ts/routes/image-occlusion/MaskEditor.svelte +++ b/ts/routes/image-occlusion/MaskEditor.svelte @@ -44,10 +44,19 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html function init(_node: HTMLDivElement) { if (mode.kind == "add") { - // Editing occlusions on a new note through the "Add" window - setupMaskEditor(mode.imagePath, onImageLoaded).then((canvas1) => { - canvas = canvas1; - }); + if ("clonedNoteId" in mode) { + // Editing occlusions on a new note cloned from an existing note via "Create copy" + setupMaskEditorForEdit(mode.clonedNoteId, onImageLoaded).then( + (canvas1) => { + canvas = canvas1; + }, + ); + } else { + // Editing occlusions on a new note through the "Add" window + setupMaskEditor(mode.imagePath, onImageLoaded).then((canvas1) => { + canvas = canvas1; + }); + } } else { // Editing occlusions on an existing note through the "Browser" window setupMaskEditorForEdit(mode.noteId, onImageLoaded).then((canvas1) => { diff --git a/ts/routes/image-occlusion/add-or-update-note.svelte.ts b/ts/routes/image-occlusion/add-or-update-note.svelte.ts index 8721403f0..ce31eaaaf 100644 --- a/ts/routes/image-occlusion/add-or-update-note.svelte.ts +++ b/ts/routes/image-occlusion/add-or-update-note.svelte.ts @@ -7,7 +7,7 @@ import * as tr from "@generated/ftl"; import { get } from "svelte/store"; import { mount } from "svelte"; -import type { IOMode } from "./lib"; +import type { IOAddingMode, IOMode } from "./lib"; import { exportShapesToClozeDeletions } from "./shapes/to-cloze"; import { notesDataStore, tagsWritable } from "./store"; import Toast from "./Toast.svelte"; @@ -40,8 +40,9 @@ export const addOrUpdateNote = async function( showResult(mode.noteId, result, noteCount); } else { const result = await addImageOcclusionNote({ - notetypeId: BigInt(mode.notetypeId), - imagePath: mode.imagePath, + // IOCloningMode is not used on mobile + notetypeId: BigInt(( mode).notetypeId), + imagePath: ( mode).imagePath, occlusions: occlusionCloze, header, backExtra, diff --git a/ts/routes/image-occlusion/lib.ts b/ts/routes/image-occlusion/lib.ts index 77bfe7354..8986fa3ff 100644 --- a/ts/routes/image-occlusion/lib.ts +++ b/ts/routes/image-occlusion/lib.ts @@ -7,9 +7,14 @@ export interface IOAddingMode { imagePath: string; } +export interface IOCloningMode { + kind: "add"; + clonedNoteId: number; +} + export interface IOEditingMode { kind: "edit"; noteId: number; } -export type IOMode = IOAddingMode | IOEditingMode; +export type IOMode = IOAddingMode | IOEditingMode | IOCloningMode;