mirror of
https://github.com/ankitects/anki.git
synced 2025-09-19 14:32:22 -04:00
more perform_op() tweaks
- pass the handler directly - reviewer special-cases for flags and notes are now applied at call site - drop the kind attribute on OpChanges which is not needed
This commit is contained in:
parent
9c8148ff0d
commit
3f62f54f14
18 changed files with 114 additions and 113 deletions
|
@ -879,11 +879,6 @@ table.review-log {{ {revlog_style} }}
|
||||||
assert_exhaustive(self._undo)
|
assert_exhaustive(self._undo)
|
||||||
assert False
|
assert False
|
||||||
|
|
||||||
def op_affects_study_queue(self, changes: OpChanges) -> bool:
|
|
||||||
if changes.kind == changes.SET_CARD_FLAG:
|
|
||||||
return False
|
|
||||||
return changes.card or changes.deck or changes.preference
|
|
||||||
|
|
||||||
def op_made_changes(self, changes: OpChanges) -> bool:
|
def op_made_changes(self, changes: OpChanges) -> bool:
|
||||||
for field in changes.DESCRIPTOR.fields:
|
for field in changes.DESCRIPTOR.fields:
|
||||||
if field.name != "kind":
|
if field.name != "kind":
|
||||||
|
|
|
@ -24,7 +24,6 @@ from aqt.editor import Editor
|
||||||
from aqt.exporting import ExportDialog
|
from aqt.exporting import ExportDialog
|
||||||
from aqt.find_and_replace import FindAndReplaceDialog
|
from aqt.find_and_replace import FindAndReplaceDialog
|
||||||
from aqt.main import ResetReason
|
from aqt.main import ResetReason
|
||||||
from aqt.operations import OpMeta
|
|
||||||
from aqt.operations.card import set_card_deck, set_card_flag
|
from aqt.operations.card import set_card_deck, set_card_flag
|
||||||
from aqt.operations.collection import undo
|
from aqt.operations.collection import undo
|
||||||
from aqt.operations.note import remove_notes
|
from aqt.operations.note import remove_notes
|
||||||
|
@ -128,12 +127,14 @@ class Browser(QMainWindow):
|
||||||
gui_hooks.browser_will_show(self)
|
gui_hooks.browser_will_show(self)
|
||||||
self.show()
|
self.show()
|
||||||
|
|
||||||
def on_operation_did_execute(self, changes: OpChanges, meta: OpMeta) -> None:
|
def on_operation_did_execute(
|
||||||
|
self, changes: OpChanges, handler: Optional[object]
|
||||||
|
) -> None:
|
||||||
focused = current_top_level_widget() == self
|
focused = current_top_level_widget() == self
|
||||||
self.table.op_executed(changes, meta, focused)
|
self.table.op_executed(changes, handler, focused)
|
||||||
self.sidebar.op_executed(changes, meta, focused)
|
self.sidebar.op_executed(changes, handler, focused)
|
||||||
if changes.note or changes.notetype:
|
if changes.note or changes.notetype:
|
||||||
if meta.handler is not self.editor:
|
if handler is not self.editor:
|
||||||
# fixme: this will leave the splitter shown, but with no current
|
# fixme: this will leave the splitter shown, but with no current
|
||||||
# note being edited
|
# note being edited
|
||||||
note = self.editor.note
|
note = self.editor.note
|
||||||
|
|
|
@ -5,7 +5,7 @@ from __future__ import annotations
|
||||||
|
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import Any
|
from typing import Any, Optional
|
||||||
|
|
||||||
import aqt
|
import aqt
|
||||||
from anki.collection import OpChanges
|
from anki.collection import OpChanges
|
||||||
|
@ -76,8 +76,10 @@ class DeckBrowser:
|
||||||
if self._refresh_needed:
|
if self._refresh_needed:
|
||||||
self.refresh()
|
self.refresh()
|
||||||
|
|
||||||
def op_executed(self, changes: OpChanges, focused: bool) -> bool:
|
def op_executed(
|
||||||
if self.mw.col.op_affects_study_queue(changes):
|
self, changes: OpChanges, handler: Optional[object], focused: bool
|
||||||
|
) -> bool:
|
||||||
|
if changes.study_queues:
|
||||||
self._refresh_needed = True
|
self._refresh_needed = True
|
||||||
|
|
||||||
if focused:
|
if focused:
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
# Copyright: Ankitects Pty Ltd and contributors
|
# Copyright: Ankitects Pty Ltd and contributors
|
||||||
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
import aqt.editor
|
import aqt.editor
|
||||||
from anki.collection import OpChanges
|
from anki.collection import OpChanges
|
||||||
from anki.errors import NotFoundError
|
from anki.errors import NotFoundError
|
||||||
from aqt import gui_hooks
|
from aqt import gui_hooks
|
||||||
from aqt.operations import OpMeta
|
|
||||||
from aqt.qt import *
|
from aqt.qt import *
|
||||||
from aqt.utils import disable_help_button, restoreGeom, saveGeom, tr
|
from aqt.utils import disable_help_button, restoreGeom, saveGeom, tr
|
||||||
|
|
||||||
|
@ -31,8 +31,10 @@ class EditCurrent(QDialog):
|
||||||
gui_hooks.operation_did_execute.append(self.on_operation_did_execute)
|
gui_hooks.operation_did_execute.append(self.on_operation_did_execute)
|
||||||
self.show()
|
self.show()
|
||||||
|
|
||||||
def on_operation_did_execute(self, changes: OpChanges, meta: OpMeta) -> None:
|
def on_operation_did_execute(
|
||||||
if changes.editor and meta.handler is not self.editor:
|
self, changes: OpChanges, handler: Optional[object]
|
||||||
|
) -> None:
|
||||||
|
if changes.editor and handler is not self.editor:
|
||||||
# reload note
|
# reload note
|
||||||
note = self.editor.note
|
note = self.editor.note
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -100,7 +100,7 @@ class Editor:
|
||||||
redrawing.
|
redrawing.
|
||||||
|
|
||||||
The editor will cause that hook to be fired when it saves changes. To avoid
|
The editor will cause that hook to be fired when it saves changes. To avoid
|
||||||
an unwanted refresh, the parent widget should check if meta.handler
|
an unwanted refresh, the parent widget should check if handler
|
||||||
corresponds to this editor instance, and ignore the change if it does.
|
corresponds to this editor instance, and ignore the change if it does.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
|
@ -61,7 +61,6 @@ from aqt.emptycards import show_empty_cards
|
||||||
from aqt.legacy import install_pylib_legacy
|
from aqt.legacy import install_pylib_legacy
|
||||||
from aqt.mediacheck import check_media_db
|
from aqt.mediacheck import check_media_db
|
||||||
from aqt.mediasync import MediaSyncer
|
from aqt.mediasync import MediaSyncer
|
||||||
from aqt.operations import OpMeta
|
|
||||||
from aqt.operations.collection import undo
|
from aqt.operations.collection import undo
|
||||||
from aqt.profiles import ProfileManager as ProfileManagerType
|
from aqt.profiles import ProfileManager as ProfileManagerType
|
||||||
from aqt.qt import *
|
from aqt.qt import *
|
||||||
|
@ -773,7 +772,7 @@ class AnkiQt(QMainWindow):
|
||||||
success: PerformOpOptionalSuccessCallback = None,
|
success: PerformOpOptionalSuccessCallback = None,
|
||||||
failure: PerformOpOptionalFailureCallback = None,
|
failure: PerformOpOptionalFailureCallback = None,
|
||||||
after_hooks: Optional[Callable[[], None]] = None,
|
after_hooks: Optional[Callable[[], None]] = None,
|
||||||
meta: OpMeta = OpMeta(),
|
handler: Optional[object] = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Run the provided operation on a background thread.
|
"""Run the provided operation on a background thread.
|
||||||
|
|
||||||
|
@ -827,7 +826,7 @@ class AnkiQt(QMainWindow):
|
||||||
status = self.col.undo_status()
|
status = self.col.undo_status()
|
||||||
self._update_undo_actions_for_status_and_save(status)
|
self._update_undo_actions_for_status_and_save(status)
|
||||||
# fire change hooks
|
# fire change hooks
|
||||||
self._fire_change_hooks_after_op_performed(result, after_hooks, meta)
|
self._fire_change_hooks_after_op_performed(result, after_hooks, handler)
|
||||||
|
|
||||||
self.taskman.with_progress(op, wrapped_done)
|
self.taskman.with_progress(op, wrapped_done)
|
||||||
|
|
||||||
|
@ -846,7 +845,7 @@ class AnkiQt(QMainWindow):
|
||||||
self,
|
self,
|
||||||
result: ResultWithChanges,
|
result: ResultWithChanges,
|
||||||
after_hooks: Optional[Callable[[], None]],
|
after_hooks: Optional[Callable[[], None]],
|
||||||
meta: OpMeta,
|
handler: Optional[object],
|
||||||
) -> None:
|
) -> None:
|
||||||
if isinstance(result, OpChanges):
|
if isinstance(result, OpChanges):
|
||||||
changes = result
|
changes = result
|
||||||
|
@ -856,7 +855,7 @@ class AnkiQt(QMainWindow):
|
||||||
# fire new hook
|
# fire new hook
|
||||||
print("op changes:")
|
print("op changes:")
|
||||||
print(changes)
|
print(changes)
|
||||||
gui_hooks.operation_did_execute(changes, meta)
|
gui_hooks.operation_did_execute(changes, handler)
|
||||||
# fire legacy hook so old code notices changes
|
# fire legacy hook so old code notices changes
|
||||||
if self.col.op_made_changes(changes):
|
if self.col.op_made_changes(changes):
|
||||||
gui_hooks.state_did_reset()
|
gui_hooks.state_did_reset()
|
||||||
|
@ -872,15 +871,17 @@ class AnkiQt(QMainWindow):
|
||||||
setattr(op, field.name, True)
|
setattr(op, field.name, True)
|
||||||
gui_hooks.operation_did_execute(op, None)
|
gui_hooks.operation_did_execute(op, None)
|
||||||
|
|
||||||
def on_operation_did_execute(self, changes: OpChanges, meta: OpMeta) -> None:
|
def on_operation_did_execute(
|
||||||
|
self, changes: OpChanges, handler: Optional[object]
|
||||||
|
) -> None:
|
||||||
"Notify current screen of changes."
|
"Notify current screen of changes."
|
||||||
focused = current_top_level_widget() == self
|
focused = current_top_level_widget() == self
|
||||||
if self.state == "review":
|
if self.state == "review":
|
||||||
dirty = self.reviewer.op_executed(changes, focused)
|
dirty = self.reviewer.op_executed(changes, handler, focused)
|
||||||
elif self.state == "overview":
|
elif self.state == "overview":
|
||||||
dirty = self.overview.op_executed(changes, focused)
|
dirty = self.overview.op_executed(changes, handler, focused)
|
||||||
elif self.state == "deckBrowser":
|
elif self.state == "deckBrowser":
|
||||||
dirty = self.deckBrowser.op_executed(changes, focused)
|
dirty = self.deckBrowser.op_executed(changes, handler, focused)
|
||||||
else:
|
else:
|
||||||
dirty = False
|
dirty = False
|
||||||
|
|
||||||
|
|
|
@ -1,16 +1,2 @@
|
||||||
# Copyright: Ankitects Pty Ltd and contributors
|
# Copyright: Ankitects Pty Ltd and contributors
|
||||||
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
from dataclasses import dataclass
|
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class OpMeta:
|
|
||||||
"""Metadata associated with an operation.
|
|
||||||
|
|
||||||
The `handler` field can be used by screens to ignore change
|
|
||||||
events they initiated themselves, if they have already made
|
|
||||||
the required changes."""
|
|
||||||
|
|
||||||
handler: Optional[object] = None
|
|
||||||
|
|
|
@ -3,16 +3,28 @@
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import Sequence
|
from typing import Optional, Sequence
|
||||||
|
|
||||||
from anki.cards import CardId
|
from anki.cards import CardId
|
||||||
from anki.decks import DeckId
|
from anki.decks import DeckId
|
||||||
from aqt import AnkiQt
|
from aqt import AnkiQt
|
||||||
|
from aqt.main import PerformOpOptionalSuccessCallback
|
||||||
|
|
||||||
|
|
||||||
def set_card_deck(*, mw: AnkiQt, card_ids: Sequence[CardId], deck_id: DeckId) -> None:
|
def set_card_deck(*, mw: AnkiQt, card_ids: Sequence[CardId], deck_id: DeckId) -> None:
|
||||||
mw.perform_op(lambda: mw.col.set_deck(card_ids, deck_id))
|
mw.perform_op(lambda: mw.col.set_deck(card_ids, deck_id))
|
||||||
|
|
||||||
|
|
||||||
def set_card_flag(*, mw: AnkiQt, card_ids: Sequence[CardId], flag: int) -> None:
|
def set_card_flag(
|
||||||
mw.perform_op(lambda: mw.col.set_user_flag_for_cards(flag, card_ids))
|
*,
|
||||||
|
mw: AnkiQt,
|
||||||
|
card_ids: Sequence[CardId],
|
||||||
|
flag: int,
|
||||||
|
handler: Optional[object] = None,
|
||||||
|
success: PerformOpOptionalSuccessCallback = None,
|
||||||
|
) -> None:
|
||||||
|
mw.perform_op(
|
||||||
|
lambda: mw.col.set_user_flag_for_cards(flag, card_ids),
|
||||||
|
handler=handler,
|
||||||
|
success=success,
|
||||||
|
)
|
||||||
|
|
|
@ -8,7 +8,6 @@ from typing import Callable, Optional, Sequence
|
||||||
from anki.decks import DeckCollapseScope, DeckId
|
from anki.decks import DeckCollapseScope, DeckId
|
||||||
from aqt import AnkiQt, QWidget
|
from aqt import AnkiQt, QWidget
|
||||||
from aqt.main import PerformOpOptionalSuccessCallback
|
from aqt.main import PerformOpOptionalSuccessCallback
|
||||||
from aqt.operations import OpMeta
|
|
||||||
from aqt.utils import getOnlyText, tooltip, tr
|
from aqt.utils import getOnlyText, tooltip, tr
|
||||||
|
|
||||||
|
|
||||||
|
@ -83,5 +82,5 @@ def set_deck_collapsed(
|
||||||
lambda: mw.col.decks.set_collapsed(
|
lambda: mw.col.decks.set_collapsed(
|
||||||
deck_id=deck_id, collapsed=collapsed, scope=scope
|
deck_id=deck_id, collapsed=collapsed, scope=scope
|
||||||
),
|
),
|
||||||
meta=OpMeta(handler=handler),
|
handler=handler,
|
||||||
)
|
)
|
||||||
|
|
|
@ -9,7 +9,6 @@ from anki.decks import DeckId
|
||||||
from anki.notes import Note, NoteId
|
from anki.notes import Note, NoteId
|
||||||
from aqt import AnkiQt
|
from aqt import AnkiQt
|
||||||
from aqt.main import PerformOpOptionalSuccessCallback
|
from aqt.main import PerformOpOptionalSuccessCallback
|
||||||
from aqt.operations import OpMeta
|
|
||||||
|
|
||||||
|
|
||||||
def add_note(
|
def add_note(
|
||||||
|
@ -25,7 +24,7 @@ def add_note(
|
||||||
def update_note(*, mw: AnkiQt, note: Note, handler: Optional[object]) -> None:
|
def update_note(*, mw: AnkiQt, note: Note, handler: Optional[object]) -> None:
|
||||||
mw.perform_op(
|
mw.perform_op(
|
||||||
lambda: mw.col.update_note(note),
|
lambda: mw.col.update_note(note),
|
||||||
meta=OpMeta(handler=handler),
|
handler=handler,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import Callable, Sequence
|
from typing import Callable, Optional, Sequence
|
||||||
|
|
||||||
from anki.collection import OpChangesWithCount
|
from anki.collection import OpChangesWithCount
|
||||||
from anki.notes import NoteId
|
from anki.notes import NoteId
|
||||||
|
@ -18,9 +18,12 @@ def add_tags_to_notes(
|
||||||
note_ids: Sequence[NoteId],
|
note_ids: Sequence[NoteId],
|
||||||
space_separated_tags: str,
|
space_separated_tags: str,
|
||||||
success: PerformOpOptionalSuccessCallback = None,
|
success: PerformOpOptionalSuccessCallback = None,
|
||||||
|
handler: Optional[object] = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
mw.perform_op(
|
mw.perform_op(
|
||||||
lambda: mw.col.tags.bulk_add(note_ids, space_separated_tags), success=success
|
lambda: mw.col.tags.bulk_add(note_ids, space_separated_tags),
|
||||||
|
success=success,
|
||||||
|
handler=handler,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -30,9 +33,12 @@ def remove_tags_from_notes(
|
||||||
note_ids: Sequence[NoteId],
|
note_ids: Sequence[NoteId],
|
||||||
space_separated_tags: str,
|
space_separated_tags: str,
|
||||||
success: PerformOpOptionalSuccessCallback = None,
|
success: PerformOpOptionalSuccessCallback = None,
|
||||||
|
handler: Optional[object] = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
mw.perform_op(
|
mw.perform_op(
|
||||||
lambda: mw.col.tags.bulk_remove(note_ids, space_separated_tags), success=success
|
lambda: mw.col.tags.bulk_remove(note_ids, space_separated_tags),
|
||||||
|
success=success,
|
||||||
|
handler=handler,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -64,8 +64,10 @@ class Overview:
|
||||||
if self._refresh_needed:
|
if self._refresh_needed:
|
||||||
self.refresh()
|
self.refresh()
|
||||||
|
|
||||||
def op_executed(self, changes: OpChanges, focused: bool) -> bool:
|
def op_executed(
|
||||||
if self.mw.col.op_affects_study_queue(changes):
|
self, changes: OpChanges, handler: Optional[object], focused: bool
|
||||||
|
) -> bool:
|
||||||
|
if changes.study_queues:
|
||||||
self._refresh_needed = True
|
self._refresh_needed = True
|
||||||
|
|
||||||
if focused:
|
if focused:
|
||||||
|
|
|
@ -14,7 +14,7 @@ from PyQt5.QtCore import Qt
|
||||||
|
|
||||||
from anki import hooks
|
from anki import hooks
|
||||||
from anki.cards import Card, CardId
|
from anki.cards import Card, CardId
|
||||||
from anki.collection import Config, OpChanges
|
from anki.collection import Config, OpChanges, OpChangesWithCount
|
||||||
from anki.tags import MARKED_TAG
|
from anki.tags import MARKED_TAG
|
||||||
from anki.utils import stripHTML
|
from anki.utils import stripHTML
|
||||||
from aqt import AnkiQt, gui_hooks
|
from aqt import AnkiQt, gui_hooks
|
||||||
|
@ -38,7 +38,6 @@ from aqt.webview import AnkiWebView
|
||||||
|
|
||||||
|
|
||||||
class RefreshNeeded(Enum):
|
class RefreshNeeded(Enum):
|
||||||
NO = auto()
|
|
||||||
NOTE_TEXT = auto()
|
NOTE_TEXT = auto()
|
||||||
QUEUES = auto()
|
QUEUES = auto()
|
||||||
|
|
||||||
|
@ -71,7 +70,7 @@ class Reviewer:
|
||||||
self._recordedAudio: Optional[str] = None
|
self._recordedAudio: Optional[str] = None
|
||||||
self.typeCorrect: str = None # web init happens before this is set
|
self.typeCorrect: str = None # web init happens before this is set
|
||||||
self.state: Optional[str] = None
|
self.state: Optional[str] = None
|
||||||
self._refresh_needed = RefreshNeeded.NO
|
self._refresh_needed: Optional[RefreshNeeded] = None
|
||||||
self.bottom = BottomBar(mw, mw.bottomWeb)
|
self.bottom = BottomBar(mw, mw.bottomWeb)
|
||||||
hooks.card_did_leech.append(self.onLeech)
|
hooks.card_did_leech.append(self.onLeech)
|
||||||
|
|
||||||
|
@ -102,29 +101,25 @@ class Reviewer:
|
||||||
self.mw.col.reset()
|
self.mw.col.reset()
|
||||||
self.nextCard()
|
self.nextCard()
|
||||||
self.mw.fade_in_webview()
|
self.mw.fade_in_webview()
|
||||||
self._refresh_needed = RefreshNeeded.NO
|
self._refresh_needed = None
|
||||||
elif self._refresh_needed is RefreshNeeded.NOTE_TEXT:
|
elif self._refresh_needed is RefreshNeeded.NOTE_TEXT:
|
||||||
self._redraw_current_card()
|
self._redraw_current_card()
|
||||||
self.mw.fade_in_webview()
|
self.mw.fade_in_webview()
|
||||||
self._refresh_needed = RefreshNeeded.NO
|
self._refresh_needed = None
|
||||||
|
|
||||||
def op_executed(self, changes: OpChanges, focused: bool) -> bool:
|
def op_executed(
|
||||||
if changes.note and changes.kind == OpChanges.UPDATE_NOTE_TAGS:
|
self, changes: OpChanges, handler: Optional[object], focused: bool
|
||||||
self.card.load()
|
) -> bool:
|
||||||
self._update_mark_icon()
|
if handler is not self:
|
||||||
elif changes.card and changes.kind == OpChanges.SET_CARD_FLAG:
|
if changes.study_queues:
|
||||||
# fixme: v3 mtime check
|
|
||||||
self.card.load()
|
|
||||||
self._update_flag_icon()
|
|
||||||
elif self.mw.col.op_affects_study_queue(changes):
|
|
||||||
self._refresh_needed = RefreshNeeded.QUEUES
|
self._refresh_needed = RefreshNeeded.QUEUES
|
||||||
elif changes.note or changes.notetype or changes.tag:
|
elif changes.editor:
|
||||||
self._refresh_needed = RefreshNeeded.NOTE_TEXT
|
self._refresh_needed = RefreshNeeded.NOTE_TEXT
|
||||||
|
|
||||||
if focused and self._refresh_needed is not RefreshNeeded.NO:
|
if focused and self._refresh_needed:
|
||||||
self.refresh_if_needed()
|
self.refresh_if_needed()
|
||||||
|
|
||||||
return self._refresh_needed is not RefreshNeeded.NO
|
return bool(self._refresh_needed)
|
||||||
|
|
||||||
def _redraw_current_card(self) -> None:
|
def _redraw_current_card(self) -> None:
|
||||||
self.card.load()
|
self.card.load()
|
||||||
|
@ -830,23 +825,45 @@ time = %(time)d;
|
||||||
self.mw.onDeckConf(self.mw.col.decks.get(self.card.current_deck_id()))
|
self.mw.onDeckConf(self.mw.col.decks.get(self.card.current_deck_id()))
|
||||||
|
|
||||||
def set_flag_on_current_card(self, desired_flag: int) -> None:
|
def set_flag_on_current_card(self, desired_flag: int) -> None:
|
||||||
|
def redraw_flag(out: OpChanges) -> None:
|
||||||
|
self.card.load()
|
||||||
|
self._update_flag_icon()
|
||||||
|
|
||||||
# need to toggle off?
|
# need to toggle off?
|
||||||
if self.card.user_flag() == desired_flag:
|
if self.card.user_flag() == desired_flag:
|
||||||
flag = 0
|
flag = 0
|
||||||
else:
|
else:
|
||||||
flag = desired_flag
|
flag = desired_flag
|
||||||
|
|
||||||
set_card_flag(mw=self.mw, card_ids=[self.card.id], flag=flag)
|
set_card_flag(
|
||||||
|
mw=self.mw,
|
||||||
|
card_ids=[self.card.id],
|
||||||
|
flag=flag,
|
||||||
|
handler=self,
|
||||||
|
success=redraw_flag,
|
||||||
|
)
|
||||||
|
|
||||||
def toggle_mark_on_current_note(self) -> None:
|
def toggle_mark_on_current_note(self) -> None:
|
||||||
|
def redraw_mark(out: OpChangesWithCount) -> None:
|
||||||
|
self.card.load()
|
||||||
|
self._update_mark_icon()
|
||||||
|
|
||||||
note = self.card.note()
|
note = self.card.note()
|
||||||
if note.has_tag(MARKED_TAG):
|
if note.has_tag(MARKED_TAG):
|
||||||
remove_tags_from_notes(
|
remove_tags_from_notes(
|
||||||
mw=self.mw, note_ids=[note.id], space_separated_tags=MARKED_TAG
|
mw=self.mw,
|
||||||
|
note_ids=[note.id],
|
||||||
|
space_separated_tags=MARKED_TAG,
|
||||||
|
handler=self,
|
||||||
|
success=redraw_mark,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
add_tags_to_notes(
|
add_tags_to_notes(
|
||||||
mw=self.mw, note_ids=[note.id], space_separated_tags=MARKED_TAG
|
mw=self.mw,
|
||||||
|
note_ids=[note.id],
|
||||||
|
space_separated_tags=MARKED_TAG,
|
||||||
|
handler=self,
|
||||||
|
success=redraw_mark,
|
||||||
)
|
)
|
||||||
|
|
||||||
def on_set_due(self) -> None:
|
def on_set_due(self) -> None:
|
||||||
|
|
|
@ -16,7 +16,6 @@ from anki.types import assert_exhaustive
|
||||||
from aqt import colors, gui_hooks
|
from aqt import colors, gui_hooks
|
||||||
from aqt.clayout import CardLayout
|
from aqt.clayout import CardLayout
|
||||||
from aqt.models import Models
|
from aqt.models import Models
|
||||||
from aqt.operations import OpMeta
|
|
||||||
from aqt.operations.deck import (
|
from aqt.operations.deck import (
|
||||||
remove_decks,
|
remove_decks,
|
||||||
rename_deck,
|
rename_deck,
|
||||||
|
@ -420,8 +419,10 @@ class SidebarTreeView(QTreeView):
|
||||||
# Refreshing
|
# Refreshing
|
||||||
###########################
|
###########################
|
||||||
|
|
||||||
def op_executed(self, changes: OpChanges, meta: OpMeta, focused: bool) -> None:
|
def op_executed(
|
||||||
if changes.browser_sidebar and not meta.handler is self:
|
self, changes: OpChanges, handler: Optional[object], focused: bool
|
||||||
|
) -> None:
|
||||||
|
if changes.browser_sidebar and not handler is self:
|
||||||
self._refresh_needed = True
|
self._refresh_needed = True
|
||||||
if focused:
|
if focused:
|
||||||
self.refresh_if_needed()
|
self.refresh_if_needed()
|
||||||
|
|
|
@ -29,7 +29,6 @@ from anki.errors import NotFoundError
|
||||||
from anki.notes import Note, NoteId
|
from anki.notes import Note, NoteId
|
||||||
from anki.utils import ids2str, isWin
|
from anki.utils import ids2str, isWin
|
||||||
from aqt import colors, gui_hooks
|
from aqt import colors, gui_hooks
|
||||||
from aqt.operations import OpMeta
|
|
||||||
from aqt.qt import *
|
from aqt.qt import *
|
||||||
from aqt.theme import theme_manager
|
from aqt.theme import theme_manager
|
||||||
from aqt.utils import (
|
from aqt.utils import (
|
||||||
|
@ -181,7 +180,9 @@ class Table:
|
||||||
def redraw_cells(self) -> None:
|
def redraw_cells(self) -> None:
|
||||||
self._model.redraw_cells()
|
self._model.redraw_cells()
|
||||||
|
|
||||||
def op_executed(self, changes: OpChanges, meta: OpMeta, focused: bool) -> None:
|
def op_executed(
|
||||||
|
self, changes: OpChanges, handler: Optional[object], focused: bool
|
||||||
|
) -> None:
|
||||||
if changes.browser_table:
|
if changes.browser_table:
|
||||||
self._model.mark_cache_stale()
|
self._model.mark_cache_stale()
|
||||||
if focused:
|
if focused:
|
||||||
|
|
|
@ -459,7 +459,7 @@ hooks = [
|
||||||
),
|
),
|
||||||
Hook(
|
Hook(
|
||||||
name="operation_did_execute",
|
name="operation_did_execute",
|
||||||
args=["changes: anki.collection.OpChanges", "meta: aqt.operations.OpMeta"],
|
args=["changes: anki.collection.OpChanges", "handler: Optional[object]"],
|
||||||
doc="""Called after an operation completes.
|
doc="""Called after an operation completes.
|
||||||
Changes can be inspected to determine whether the UI needs updating.
|
Changes can be inspected to determine whether the UI needs updating.
|
||||||
|
|
||||||
|
|
|
@ -1498,26 +1498,17 @@ message GetQueuedCardsOut {
|
||||||
}
|
}
|
||||||
|
|
||||||
message OpChanges {
|
message OpChanges {
|
||||||
// this is not an exhaustive list; we can add more cases as we need them
|
bool card = 1;
|
||||||
enum Kind {
|
bool note = 2;
|
||||||
OTHER = 0;
|
bool deck = 3;
|
||||||
UPDATE_NOTE_TAGS = 1;
|
bool tag = 4;
|
||||||
SET_CARD_FLAG = 2;
|
bool notetype = 5;
|
||||||
UPDATE_NOTE = 3;
|
bool preference = 6;
|
||||||
}
|
|
||||||
|
|
||||||
Kind kind = 1;
|
bool browser_table = 7;
|
||||||
bool card = 2;
|
bool browser_sidebar = 8;
|
||||||
bool note = 3;
|
bool editor = 9;
|
||||||
bool deck = 4;
|
bool study_queues = 10;
|
||||||
bool tag = 5;
|
|
||||||
bool notetype = 6;
|
|
||||||
bool preference = 7;
|
|
||||||
|
|
||||||
bool browser_table = 8;
|
|
||||||
bool browser_sidebar = 9;
|
|
||||||
bool editor = 10;
|
|
||||||
bool study_queues = 11;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message UndoStatus {
|
message UndoStatus {
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
use pb::op_changes::Kind;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backend_proto as pb,
|
backend_proto as pb,
|
||||||
ops::OpChanges,
|
ops::OpChanges,
|
||||||
|
@ -10,21 +8,9 @@ use crate::{
|
||||||
undo::{UndoOutput, UndoStatus},
|
undo::{UndoOutput, UndoStatus},
|
||||||
};
|
};
|
||||||
|
|
||||||
impl From<Op> for Kind {
|
|
||||||
fn from(o: Op) -> Self {
|
|
||||||
match o {
|
|
||||||
Op::SetFlag => Kind::SetCardFlag,
|
|
||||||
Op::UpdateTag => Kind::UpdateNoteTags,
|
|
||||||
Op::UpdateNote => Kind::UpdateNote,
|
|
||||||
_ => Kind::Other,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<OpChanges> for pb::OpChanges {
|
impl From<OpChanges> for pb::OpChanges {
|
||||||
fn from(c: OpChanges) -> Self {
|
fn from(c: OpChanges) -> Self {
|
||||||
pb::OpChanges {
|
pb::OpChanges {
|
||||||
kind: Kind::from(c.op) as i32,
|
|
||||||
card: c.changes.card,
|
card: c.changes.card,
|
||||||
note: c.changes.note,
|
note: c.changes.note,
|
||||||
deck: c.changes.deck,
|
deck: c.changes.deck,
|
||||||
|
|
Loading…
Reference in a new issue