diff --git a/pylib/anki/decks.py b/pylib/anki/decks.py index 2eb0971f8..7a7a40765 100644 --- a/pylib/anki/decks.py +++ b/pylib/anki/decks.py @@ -11,7 +11,7 @@ from typing import Any, Dict, Iterable, List, Optional, Sequence, Tuple, Union import anki # pylint: disable=unused-import import anki._backend.backend_pb2 as _pb -from anki.collection import OpChangesWithCount +from anki.collection import OpChanges, OpChangesWithCount from anki.consts import * from anki.errors import NotFoundError from anki.utils import from_json_bytes, ids2str, intTime, legacy_func, to_json_bytes @@ -260,13 +260,13 @@ class DeckManager: deck=to_json_bytes(g), preserve_usn_and_mtime=preserve_usn ) - def rename(self, deck: Union[Deck, int], new_name: str) -> None: + def rename(self, deck: Union[Deck, DeckID], new_name: str) -> OpChanges: "Rename deck prefix to NAME if not exists. Updates children." if isinstance(deck, int): deck_id = deck else: deck_id = deck["id"] - self.col._backend.rename_deck(deck_id=deck_id, new_name=new_name) + return self.col._backend.rename_deck(deck_id=deck_id, new_name=new_name) # Drag/drop ############################################################# diff --git a/qt/aqt/deck_ops.py b/qt/aqt/deck_ops.py index 1722f69cb..1c310d552 100644 --- a/qt/aqt/deck_ops.py +++ b/qt/aqt/deck_ops.py @@ -3,7 +3,7 @@ from __future__ import annotations -from typing import Sequence +from typing import Callable, Sequence from anki.decks import DeckID from anki.lang import TR @@ -34,3 +34,15 @@ def reparent_decks( tr(TR.BROWSING_REPARENTED_DECKS, count=out.count), parent=parent ), ) + + +def rename_deck( + *, + mw: AnkiQt, + deck_id: DeckID, + new_name: str, + after_rename: Callable[[], None] = None, +) -> None: + mw.perform_op( + lambda: mw.col.decks.rename(deck_id, new_name), after_hooks=after_rename + ) diff --git a/qt/aqt/deckbrowser.py b/qt/aqt/deckbrowser.py index 9bea3204f..916d962b9 100644 --- a/qt/aqt/deckbrowser.py +++ b/qt/aqt/deckbrowser.py @@ -13,7 +13,7 @@ from anki.decks import DeckTreeNode from anki.errors import DeckIsFilteredError from anki.utils import intTime from aqt import AnkiQt, gui_hooks -from aqt.deck_ops import remove_decks, reparent_decks +from aqt.deck_ops import remove_decks, rename_deck, reparent_decks from aqt.qt import * from aqt.sound import av_player from aqt.toolbar import BottomBar @@ -276,19 +276,12 @@ class DeckBrowser: def _rename(self, did: int) -> None: deck = self.mw.col.decks.get(did) - oldName = deck["name"] - newName = getOnlyText(tr(TR.DECKS_NEW_DECK_NAME), default=oldName) - newName = newName.replace('"', "") - if not newName or newName == oldName: + current_name = deck["name"] + new_name = getOnlyText(tr(TR.DECKS_NEW_DECK_NAME), default=current_name) + if not new_name or new_name == current_name: return - try: - self.mw.col.decks.rename(deck, newName) - gui_hooks.sidebar_should_refresh_decks() - except DeckIsFilteredError as err: - showWarning(str(err)) - return - self.mw.update_undo_actions() - self.show() + + rename_deck(mw=self.mw, deck_id=did, new_name=new_name) def _options(self, did: str) -> None: # select the deck first, because the dyn deck conf assumes the deck diff --git a/qt/aqt/sidebar.py b/qt/aqt/sidebar.py index c4a415ced..5fa54e8a0 100644 --- a/qt/aqt/sidebar.py +++ b/qt/aqt/sidebar.py @@ -9,13 +9,13 @@ from typing import Dict, Iterable, List, Optional, Tuple, cast import aqt from anki.collection import Config, OpChanges, SearchJoiner, SearchNode from anki.decks import DeckTreeNode -from anki.errors import DeckIsFilteredError, InvalidInput +from anki.errors import InvalidInput from anki.notes import Note from anki.tags import TagTreeNode from anki.types import assert_exhaustive from aqt import colors, gui_hooks from aqt.clayout import CardLayout -from aqt.deck_ops import remove_decks, reparent_decks +from aqt.deck_ops import remove_decks, rename_deck, reparent_decks from aqt.models import Models from aqt.qt import * from aqt.tag_ops import remove_tags_for_all_notes, rename_tag, reparent_tags @@ -26,7 +26,6 @@ from aqt.utils import ( askUser, getOnlyText, show_invalid_search_error, - showWarning, tr, ) @@ -1154,18 +1153,21 @@ class SidebarTreeView(QTreeView): def rename_deck(self, item: SidebarItem, new_name: str) -> None: deck = self.mw.col.decks.get(item.id) - new_name = item.name_prefix + new_name - try: - self.mw.col.decks.rename(deck, new_name) - except DeckIsFilteredError as err: - showWarning(str(err)) + if not new_name: return - self.refresh( - lambda other: other.item_type == SidebarItemType.DECK - and other.id == item.id + new_name = item.name_prefix + new_name + if new_name == deck["name"]: + return + + rename_deck( + mw=self.mw, + deck_id=item.id, + new_name=new_name, + after_rename=lambda: self.refresh( + lambda other: other.item_type == SidebarItemType.DECK + and other.id == item.id + ), ) - self.mw.deckBrowser.refresh() - self.mw.update_undo_actions() def delete_decks(self, _item: SidebarItem) -> None: remove_decks(mw=self.mw, parent=self.browser, deck_ids=self._selected_decks()) diff --git a/rslib/src/scheduler/answering/mod.rs b/rslib/src/scheduler/answering/mod.rs index 762d38687..25f30be35 100644 --- a/rslib/src/scheduler/answering/mod.rs +++ b/rslib/src/scheduler/answering/mod.rs @@ -268,6 +268,7 @@ impl Collection { let timing = updater.timing; let mut card = updater.into_card(); self.update_card_inner(&mut card, original, usn)?; + println!("fixme: add_leech calls update_note_tags() which creates a transaction"); if answer.new_state.leeched() { self.add_leech_tag(card.note_id)?; }