remove deck protobuf from frontend

Like the previous change, avoid exposing the protobuf as a public API
for now. It requires more thought, and is probably better done with
either extra helper accessors like decks.name(), or via a native class.
This commit is contained in:
Damien Elmes 2021-05-31 16:24:51 +10:00
parent bb323615dd
commit 29c4869aef
10 changed files with 57 additions and 59 deletions

View file

@ -39,7 +39,7 @@ from anki.cards import Card, CardId
from anki.config import Config, ConfigManager
from anki.consts import *
from anki.dbproxy import DBProxy
from anki.decks import Deck, DeckId, DeckManager
from anki.decks import DeckId, DeckManager
from anki.errors import AbortSchemaModification, DBError
from anki.lang import FormatTimeSpan
from anki.media import MediaManager, media_paths_from_col_path
@ -335,14 +335,6 @@ class Collection:
note=note._to_backend_note(), skip_undo_entry=False
)
def get_deck(self, id: DeckId) -> Deck:
"Get a new-style deck object."
return self._backend.get_deck(id)
def update_deck(self, deck: Deck) -> OpChanges:
"Save updates to an existing deck."
return self._backend.update_deck(deck)
getCard = get_card
getNote = get_note

View file

@ -33,9 +33,6 @@ defaultDynamicDeck = 1
DeckDict = Dict[str, Any]
DeckConfigDict = Dict[str, Any]
# currently only supports read-only access
Deck = _pb.Deck
DeckId = NewType("DeckId", int)
DeckConfigId = NewType("DeckConfigId", int)
@ -290,6 +287,9 @@ class DeckManager:
deck=to_json_bytes(g), preserve_usn_and_mtime=preserve_usn
)
def update_dict(self, deck: DeckDict) -> OpChanges:
return self.col._backend.update_deck_legacy(json=to_json_bytes(deck))
def rename(self, deck: Union[DeckDict, DeckId], new_name: str) -> OpChanges:
"Rename deck prefix to NAME if not exists. Updates children."
if isinstance(deck, int):
@ -455,15 +455,12 @@ class DeckManager:
# Deck selection
#############################################################
def get_current(self) -> Deck:
return self.col._backend.get_current_deck()
def set_current(self, deck: DeckId) -> OpChanges:
return self.col._backend.set_current_deck(deck)
def get_current_id(self) -> DeckId:
"The currently selected deck ID."
return DeckId(self.get_current().id)
return DeckId(self.col._backend.get_current_deck().id)
# legacy
@ -528,7 +525,7 @@ class DeckManager:
)
def deck_and_child_ids(self, deck_id: DeckId) -> List[DeckId]:
parent_name = self.col.get_deck(deck_id).name
parent_name = self.name(deck_id)
out = [deck_id]
out.extend(self.child_ids(parent_name))
return out

View file

@ -13,7 +13,7 @@ from anki.collection import (
SearchJoiner,
SearchNode,
)
from anki.decks import Deck, DeckCollapseScope, DeckId, DeckTreeNode
from anki.decks import DeckCollapseScope, DeckId, DeckTreeNode
from anki.models import NotetypeId
from anki.notes import Note
from anki.tags import TagTreeNode
@ -902,8 +902,8 @@ class SidebarTreeView(QTreeView):
full_name = item.name_prefix + new_name
deck_id = DeckId(item.id)
def after_fetch(deck: Deck) -> None:
if full_name == deck.name:
def after_fetch(name: str) -> None:
if full_name == name:
return
rename_deck(
@ -914,7 +914,7 @@ class SidebarTreeView(QTreeView):
QueryOp(
parent=self.browser,
op=lambda col: col.get_deck(deck_id),
op=lambda col: col.decks.name(deck_id),
success=after_fetch,
).run_in_background()

View file

@ -9,7 +9,7 @@ from typing import Any, Optional
import aqt
from anki.collection import OpChanges
from anki.decks import Deck, DeckCollapseScope, DeckId, DeckTreeNode
from anki.decks import DeckCollapseScope, DeckId, DeckTreeNode
from aqt import AnkiQt, gui_hooks
from aqt.deckoptions import display_options_for_deck_id
from aqt.operations import QueryOp
@ -278,9 +278,9 @@ class DeckBrowser:
self.mw.onExport(did=did)
def _rename(self, did: DeckId) -> None:
def prompt(deck: Deck) -> None:
new_name = getOnlyText(tr.decks_new_deck_name(), default=deck.name)
if not new_name or new_name == deck.name:
def prompt(name: str) -> None:
new_name = getOnlyText(tr.decks_new_deck_name(), default=name)
if not new_name or new_name == name:
return
else:
rename_deck(
@ -288,7 +288,7 @@ class DeckBrowser:
).run_in_background()
QueryOp(
parent=self.mw, op=lambda col: col.get_deck(did), success=prompt
parent=self.mw, op=lambda col: col.decks.name(did), success=prompt
).run_in_background()
def _options(self, did: DeckId) -> None:

View file

@ -4,9 +4,9 @@
from __future__ import annotations
import aqt
from anki.decks import Deck
from anki.decks import DeckDict
from aqt.operations import QueryOp
from aqt.operations.deck import update_deck
from aqt.operations.deck import update_deck_dict
from aqt.qt import *
from aqt.utils import addCloseShortcut, disable_help_button, restoreGeom, saveGeom, tr
@ -21,16 +21,16 @@ class DeckDescriptionDialog(QDialog):
self.mw = mw
# set on success
self.deck: Deck
self.deck: DeckDict
QueryOp(
parent=self.mw,
op=lambda col: col.decks.get_current(),
op=lambda col: col.decks.current(),
success=self._setup_and_show,
).run_in_background()
def _setup_and_show(self, deck: Deck) -> None:
if deck.WhichOneof("kind") != "normal":
def _setup_and_show(self, deck: DeckDict) -> None:
if deck["dyn"]:
return
self.deck = deck
@ -53,11 +53,11 @@ class DeckDescriptionDialog(QDialog):
self.enable_markdown = QCheckBox(tr.deck_config_description_markdown())
self.enable_markdown.setToolTip(tr.deck_config_description_markdown_hint())
self.enable_markdown.setChecked(self.deck.normal.markdown_description)
self.enable_markdown.setChecked(self.deck.get("md", False))
box.addWidget(self.enable_markdown)
self.description = QPlainTextEdit()
self.description.setPlainText(self.deck.normal.description)
self.description.setPlainText(self.deck.get("desc", ""))
box.addWidget(self.description)
button_box = QDialogButtonBox()
@ -69,10 +69,10 @@ class DeckDescriptionDialog(QDialog):
self.show()
def save_and_accept(self) -> None:
self.deck.normal.description = self.description.toPlainText()
self.deck.normal.markdown_description = self.enable_markdown.isChecked()
self.deck["desc"] = self.description.toPlainText()
self.deck["md"] = self.enable_markdown.isChecked()
update_deck(parent=self, deck=self.deck).success(
update_deck_dict(parent=self, deck=self.deck).success(
lambda _: self.accept()
).run_in_background()

View file

@ -8,7 +8,7 @@ from typing import List, Optional
import aqt
import aqt.deckconf
from anki.cards import Card
from anki.decks import Deck, DeckId
from anki.decks import DeckDict, DeckId
from anki.lang import without_unicode_isolation
from aqt import gui_hooks
from aqt.qt import *
@ -29,7 +29,7 @@ class DeckOptionsDialog(QDialog):
TITLE = "deckOptions"
silentlyClose = True
def __init__(self, mw: aqt.main.AnkiQt, deck: Deck) -> None:
def __init__(self, mw: aqt.main.AnkiQt, deck: DeckDict) -> None:
QDialog.__init__(self, mw, Qt.Window)
self.mw = mw
self._deck = deck
@ -54,10 +54,10 @@ class DeckOptionsDialog(QDialog):
self.web.eval(
f"""const $deckOptions = anki.deckOptions(
document.getElementById('main'), {self._deck.id});"""
document.getElementById('main'), {self._deck["id"]});"""
)
self.setWindowTitle(
without_unicode_isolation(tr.actions_options_for(val=self._deck.name))
without_unicode_isolation(tr.actions_options_for(val=self._deck["name"]))
)
gui_hooks.deck_options_did_load(self)
@ -68,28 +68,28 @@ class DeckOptionsDialog(QDialog):
def confirm_deck_then_display_options(active_card: Optional[Card] = None) -> None:
decks = [aqt.mw.col.decks.get_current()]
decks = [aqt.mw.col.decks.current()]
if card := active_card:
if card.odid and card.odid != decks[0].id:
decks.append(aqt.mw.col.get_deck(card.odid))
if card.odid and card.odid != decks[0]["id"]:
decks.append(aqt.mw.col.decks.get(card.odid))
if not any(d.id == card.did for d in decks):
decks.append(aqt.mw.col.get_deck(card.odid))
if not any(d["id"] == card.did for d in decks):
decks.append(aqt.mw.col.decks.get(card.odid))
if len(decks) == 1:
display_options_for_deck(decks[0])
else:
decks.sort(key=lambda x: x.WhichOneof("kind") == "filtered")
decks.sort(key=lambda x: x["dyn"])
_deck_prompt_dialog(decks)
def _deck_prompt_dialog(decks: List[Deck]) -> None:
def _deck_prompt_dialog(decks: List[DeckDict]) -> None:
diag = QDialog(aqt.mw.app.activeWindow())
diag.setWindowTitle("Anki")
box = QVBoxLayout()
box.addWidget(QLabel(tr.deck_config_which_deck()))
for deck in decks:
button = QPushButton(deck.name)
button = QPushButton(deck["name"])
qconnect(button.clicked, lambda _, deck=deck: display_options_for_deck(deck))
qconnect(button.clicked, diag.close)
box.addWidget(button)
@ -101,15 +101,15 @@ def _deck_prompt_dialog(decks: List[Deck]) -> None:
def display_options_for_deck_id(deck_id: DeckId) -> None:
display_options_for_deck(aqt.mw.col.get_deck(deck_id))
display_options_for_deck(aqt.mw.col.decks.get(deck_id))
def display_options_for_deck(deck: Deck) -> None:
if deck.WhichOneof("kind") == "normal":
def display_options_for_deck(deck: DeckDict) -> None:
if not deck["dyn"]:
if KeyboardModifiersPressed().shift or aqt.mw.col.schedVer() == 1:
deck_legacy = aqt.mw.col.decks.get(DeckId(deck.id))
deck_legacy = aqt.mw.col.decks.get(DeckId(deck["id"]))
aqt.deckconf.DeckConf(aqt.mw, deck_legacy)
else:
DeckOptionsDialog(aqt.mw, deck)
else:
aqt.dialogs.open("FilteredDeckConfigDialog", aqt.mw, deck_id=deck.id)
aqt.dialogs.open("FilteredDeckConfigDialog", aqt.mw, deck_id=deck["id"])

View file

@ -6,7 +6,7 @@ from __future__ import annotations
from typing import Optional, Sequence
from anki.collection import OpChanges, OpChangesWithCount, OpChangesWithId
from anki.decks import Deck, DeckCollapseScope, DeckId, UpdateDeckConfigs
from anki.decks import DeckCollapseScope, DeckDict, DeckId, UpdateDeckConfigs
from aqt import QWidget
from aqt.operations import CollectionOp
from aqt.utils import getOnlyText, tooltip, tr
@ -88,5 +88,5 @@ def update_deck_configs(
return CollectionOp(parent, lambda col: col.decks.update_deck_configs(input))
def update_deck(*, parent: QWidget, deck: Deck) -> CollectionOp[OpChanges]:
return CollectionOp(parent, lambda col: col.update_deck(deck))
def update_deck_dict(*, parent: QWidget, deck: DeckDict) -> CollectionOp[OpChanges]:
return CollectionOp(parent, lambda col: col.decks.update_dict(deck))

View file

@ -94,7 +94,7 @@ class Overview:
elif url == "anki":
print("anki menu")
elif url == "opts":
display_options_for_deck(self.mw.col.decks.get_current())
display_options_for_deck(self.mw.col.decks.current())
elif url == "cram":
aqt.dialogs.open("FilteredDeckConfigDialog", self.mw)
elif url == "refresh":
@ -117,7 +117,7 @@ class Overview:
def _shortcutKeys(self) -> List[Tuple[str, Callable]]:
return [
("o", lambda: display_options_for_deck(self.mw.col.decks.get_current())),
("o", lambda: display_options_for_deck(self.mw.col.decks.current())),
("r", self.rebuild_current_filtered_deck),
("e", self.empty_current_filtered_deck),
("c", self.onCustomStudyKey),

View file

@ -144,6 +144,7 @@ service DecksService {
rpc GetDeckIdByName(String) returns (DeckId);
rpc GetDeck(DeckId) returns (Deck);
rpc UpdateDeck(Deck) returns (OpChanges);
rpc UpdateDeckLegacy(Json) returns (OpChanges);
rpc SetDeckCollapsed(SetDeckCollapsedIn) returns (OpChanges);
rpc GetDeckLegacy(DeckId) returns (Json);
rpc GetDeckNames(GetDeckNamesIn) returns (DeckNames);

View file

@ -97,6 +97,14 @@ impl DecksService for Backend {
})
}
fn update_deck_legacy(&self, input: pb::Json) -> Result<pb::OpChanges> {
self.with_col(|col| {
let deck: DeckSchema11 = serde_json::from_slice(&input.json)?;
let mut deck = deck.into();
col.update_deck(&mut deck).map(Into::into)
})
}
fn get_deck_legacy(&self, input: pb::DeckId) -> Result<pb::Json> {
self.with_col(|col| {
let deck: DeckSchema11 = col