diff --git a/pylib/anki/collection.py b/pylib/anki/collection.py index 1fe89a700..14dbbafb2 100644 --- a/pylib/anki/collection.py +++ b/pylib/anki/collection.py @@ -385,7 +385,7 @@ class Collection: note.id = NoteId(out.note_id) return out.changes - def remove_notes(self, note_ids: Sequence[NoteId]) -> OpChanges: + def remove_notes(self, note_ids: Sequence[NoteId]) -> OpChangesWithCount: hooks.notes_will_be_deleted(self, note_ids) return self._backend.remove_notes(note_ids=note_ids, card_ids=[]) diff --git a/qt/aqt/addcards.py b/qt/aqt/addcards.py index bd60b8365..04e1f16ab 100644 --- a/qt/aqt/addcards.py +++ b/qt/aqt/addcards.py @@ -208,9 +208,9 @@ class AddCards(QDialog): self._load_new_note(sticky_fields_from=note) gui_hooks.add_cards_did_add_note(note) - add_note( - mw=self.mw, note=note, target_deck_id=target_deck_id, success=on_success - ) + add_note(parent=self, note=note, target_deck_id=target_deck_id).success( + on_success + ).run_in_background() def _note_can_be_added(self, note: Note) -> bool: result = note.duplicate_or_empty() diff --git a/qt/aqt/browser.py b/qt/aqt/browser.py index ce4d4925c..0458fe294 100644 --- a/qt/aqt/browser.py +++ b/qt/aqt/browser.py @@ -642,11 +642,7 @@ where id in %s""" self.focusTo = self.editor.currentField self.table.to_next_row() - remove_notes( - mw=self.mw, - note_ids=nids, - success=lambda _: tooltip(tr.browsing_note_deleted(count=len(nids))), - ) + remove_notes(parent=self, note_ids=nids).run_in_background() # legacy diff --git a/qt/aqt/editor.py b/qt/aqt/editor.py index 999a8dfa6..08539a8e3 100644 --- a/qt/aqt/editor.py +++ b/qt/aqt/editor.py @@ -558,7 +558,9 @@ class Editor: def _save_current_note(self) -> None: "Call after note is updated with data from webview." - update_note(mw=self.mw, note=self.note, handler=self) + update_note(parent=self.widget, note=self.note).run_in_background( + initiator=self + ) def fonts(self) -> List[Tuple[str, int, bool]]: return [ diff --git a/qt/aqt/operations/note.py b/qt/aqt/operations/note.py index dfe28ba92..dae7f8287 100644 --- a/qt/aqt/operations/note.py +++ b/qt/aqt/operations/note.py @@ -3,35 +3,34 @@ from __future__ import annotations -from typing import Optional, Sequence +from typing import Sequence +from anki.collection import OpChanges, OpChangesWithCount from anki.decks import DeckId from anki.notes import Note, NoteId -from aqt import AnkiQt -from aqt.main import PerformOpOptionalSuccessCallback +from aqt.operations import CollectionOp +from aqt.qt import QWidget +from aqt.utils import tooltip, tr def add_note( *, - mw: AnkiQt, + parent: QWidget, note: Note, target_deck_id: DeckId, - success: PerformOpOptionalSuccessCallback = None, -) -> None: - mw.perform_op(lambda: mw.col.add_note(note, target_deck_id), success=success) +) -> CollectionOp[OpChanges]: + return CollectionOp(parent, lambda col: col.add_note(note, target_deck_id)) -def update_note(*, mw: AnkiQt, note: Note, handler: Optional[object]) -> None: - mw.perform_op( - lambda: mw.col.update_note(note), - handler=handler, - ) +def update_note(*, parent: QWidget, note: Note) -> CollectionOp[OpChanges]: + return CollectionOp(parent, lambda col: col.update_note(note)) def remove_notes( *, - mw: AnkiQt, + parent: QWidget, note_ids: Sequence[NoteId], - success: PerformOpOptionalSuccessCallback = None, -) -> None: - mw.perform_op(lambda: mw.col.remove_notes(note_ids), success=success) +) -> CollectionOp[OpChangesWithCount]: + return CollectionOp(parent, lambda col: col.remove_notes(note_ids)).success( + lambda out: tooltip(tr.browsing_cards_deleted(count=out.count)), + ) diff --git a/qt/aqt/reviewer.py b/qt/aqt/reviewer.py index 0e3bf90c8..553063d80 100644 --- a/qt/aqt/reviewer.py +++ b/qt/aqt/reviewer.py @@ -901,14 +901,7 @@ time = %(time)d; if self.mw.state != "review" or not self.card: return - # fixme: pass this back from the backend method instead - cnt = len(self.card.note().cards()) - - remove_notes( - mw=self.mw, - note_ids=[self.card.nid], - success=lambda _: tooltip(tr.studying_note_and_its_card_deleted(count=cnt)), - ) + remove_notes(parent=self.mw, note_ids=[self.card.nid]).run_in_background() def onRecordVoice(self) -> None: def after_record(path: str) -> None: diff --git a/rslib/backend.proto b/rslib/backend.proto index e5430c48d..6bcfd36c3 100644 --- a/rslib/backend.proto +++ b/rslib/backend.proto @@ -163,7 +163,7 @@ service NotesService { rpc DefaultDeckForNotetype(NotetypeId) returns (DeckId); rpc UpdateNote(UpdateNoteIn) returns (OpChanges); rpc GetNote(NoteId) returns (Note); - rpc RemoveNotes(RemoveNotesIn) returns (OpChanges); + rpc RemoveNotes(RemoveNotesIn) returns (OpChangesWithCount); rpc ClozeNumbersInNote(Note) returns (ClozeNumbersInNoteOut); rpc AfterNoteUpdates(AfterNoteUpdatesIn) returns (OpChanges); rpc FieldNamesForNotes(FieldNamesForNotesIn) returns (FieldNamesForNotesOut); diff --git a/rslib/src/backend/notes.rs b/rslib/src/backend/notes.rs index 75c6edaca..ceeb53976 100644 --- a/rslib/src/backend/notes.rs +++ b/rslib/src/backend/notes.rs @@ -63,7 +63,7 @@ impl NotesService for Backend { }) } - fn remove_notes(&self, input: pb::RemoveNotesIn) -> Result { + fn remove_notes(&self, input: pb::RemoveNotesIn) -> Result { self.with_col(|col| { if !input.note_ids.is_empty() { col.remove_notes( diff --git a/rslib/src/notes/mod.rs b/rslib/src/notes/mod.rs index 861455c93..14074d088 100644 --- a/rslib/src/notes/mod.rs +++ b/rslib/src/notes/mod.rs @@ -402,19 +402,21 @@ impl Collection { } /// Remove provided notes, and any cards that use them. - pub(crate) fn remove_notes(&mut self, nids: &[NoteId]) -> Result> { + pub(crate) fn remove_notes(&mut self, nids: &[NoteId]) -> Result> { let usn = self.usn()?; self.transact(Op::RemoveNote, |col| { + let mut card_count = 0; for nid in nids { let nid = *nid; if let Some(_existing_note) = col.storage.get_note(nid)? { for card in col.storage.all_cards_of_note(nid)? { + card_count += 1; col.remove_card_and_add_grave_undoable(card, usn)?; } col.remove_note_only_undoable(nid, usn)?; } } - Ok(()) + Ok(card_count) }) }