fetch stock notetypes from backend

This commit is contained in:
Damien Elmes 2020-05-15 16:05:58 +10:00
parent f650e5557f
commit 2ac33500eb
6 changed files with 59 additions and 123 deletions

View file

@ -71,7 +71,7 @@ message BackendInput {
AddOrUpdateNotetypeIn add_or_update_notetype = 57;
Empty get_all_decks = 58;
Empty check_database = 59;
Empty all_stock_notetypes = 60;
StockNoteType get_stock_notetype_legacy = 60;
int64 get_notetype_legacy = 61;
Empty get_notetype_names = 62;
Empty get_notetype_names_and_counts = 63;
@ -114,7 +114,6 @@ message BackendOutput {
string studied_today = 32;
string congrats_learn_msg = 33;
Empty abort_media_sync = 46;
AllStockNotetypesOut all_stock_notetypes = 60;
ClozeNumbersInNoteOut cloze_numbers_in_note = 87;
// fallible commands
@ -177,6 +176,7 @@ message BackendOutput {
Preferences get_preferences = 84;
Empty set_preferences = 85;
RenderCardOut render_existing_card = 86;
bytes get_stock_notetype_legacy = 60;
BackendError error = 2047;
}
@ -587,10 +587,6 @@ enum StockNoteType {
StockNoteTypeCloze = 4;
}
message AllStockNotetypesOut {
repeated NoteType notetypes = 1;
}
message NoteTypeNames {
repeated NoteTypeNameID entries = 1;
}

View file

@ -50,6 +50,7 @@ BackendNote = pb.Note
TagUsnTuple = pb.TagUsnTuple
NoteType = pb.NoteType
DeckTreeNode = pb.DeckTreeNode
StockNoteType = pb.StockNoteType
try:
import orjson
@ -602,12 +603,11 @@ class RustBackend:
).get_all_decks
return orjson.loads(jstr)
def all_stock_notetypes(self) -> List[NoteType]:
return list(
self._run_command(
pb.BackendInput(all_stock_notetypes=pb.Empty())
).all_stock_notetypes.notetypes
)
def get_stock_notetype_legacy(self, kind: StockNoteType) -> Dict[str, Any]:
bytes = self._run_command(
pb.BackendInput(get_stock_notetype_legacy=kind)
).get_stock_notetype_legacy
return orjson.loads(bytes)
def get_notetype_names_and_ids(self) -> List[pb.NoteTypeNameID]:
return list(

View file

@ -1,125 +1,62 @@
# Copyright: Ankitects Pty Ltd and contributors
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
from typing import Any, Callable, List, Optional, Tuple, Union
from typing import Callable, List, Tuple
from anki.collection import _Collection
from anki.consts import MODEL_CLOZE
from anki.lang import _
from anki.models import NoteType
from anki.rsbackend import StockNoteType
models: List[Tuple[Union[Callable[[], str], str], Callable[[Any], NoteType]]] = []
# Basic
##########################################################################
# add-on authors can add ("note type name", function_like_addBasicModel)
# to this list to have it shown in the add/clone note type screen
models: List[Tuple] = []
def _newBasicModel(col: _Collection, name: Optional[str] = None) -> NoteType:
mm = col.models
m = mm.new(name or _("Basic"))
fm = mm.newField(_("Front"))
mm.addField(m, fm)
fm = mm.newField(_("Back"))
mm.addField(m, fm)
t = mm.newTemplate(_("Card 1"))
t["qfmt"] = "{{" + _("Front") + "}}"
t["afmt"] = "{{FrontSide}}\n\n<hr id=answer>\n\n" + "{{" + _("Back") + "}}"
mm.addTemplate(m, t)
def add_stock_notetype(col: _Collection, kind: StockNoteType) -> NoteType:
m = col.backend.get_stock_notetype_legacy(kind)
col.models.add(m)
return m
def addBasicModel(col: _Collection) -> NoteType:
m = _newBasicModel(col)
col.models.add(m)
return m
models.append((lambda: _("Basic"), addBasicModel))
# Basic w/ typing
##########################################################################
return add_stock_notetype(col, StockNoteType.StockNoteTypeBasic)
def addBasicTypingModel(col: _Collection) -> NoteType:
mm = col.models
m = _newBasicModel(col, _("Basic (type in the answer)"))
t = m["tmpls"][0]
t["qfmt"] = "{{" + _("Front") + "}}\n\n{{type:" + _("Back") + "}}"
t["afmt"] = "{{" + _("Front") + "}}\n\n<hr id=answer>\n\n{{type:" + _("Back") + "}}"
mm.add(m)
return m
models.append((lambda: _("Basic (type in the answer)"), addBasicTypingModel))
# Forward & Reverse
##########################################################################
def _newForwardReverse(col: _Collection, name: Optional[str] = None) -> NoteType:
mm = col.models
m = _newBasicModel(col, name or _("Basic (and reversed card)"))
t = mm.newTemplate(_("Card 2"))
t["qfmt"] = "{{" + _("Back") + "}}"
t["afmt"] = "{{FrontSide}}\n\n<hr id=answer>\n\n" + "{{" + _("Front") + "}}"
mm.addTemplate(m, t)
return m
return add_stock_notetype(col, StockNoteType.StockNoteTypeBasicTyping)
def addForwardReverse(col: _Collection) -> NoteType:
m = _newForwardReverse(col)
col.models.add(m)
return m
models.append((lambda: _("Basic (and reversed card)"), addForwardReverse))
# Forward & Optional Reverse
##########################################################################
return add_stock_notetype(col, StockNoteType.StockNoteTypeBasicAndReversed)
def addForwardOptionalReverse(col: _Collection) -> NoteType:
mm = col.models
m = _newForwardReverse(col, _("Basic (optional reversed card)"))
av = _("Add Reverse")
fm = mm.newField(av)
mm.addField(m, fm)
t = m["tmpls"][1]
t["qfmt"] = "{{#%s}}%s{{/%s}}" % (av, t["qfmt"], av)
mm.add(m)
return m
models.append((lambda: _("Basic (optional reversed card)"), addForwardOptionalReverse))
# Cloze
##########################################################################
return add_stock_notetype(col, StockNoteType.StockNoteTypeBasicOptionalReversed)
def addClozeModel(col: _Collection) -> NoteType:
mm = col.models
m = mm.new(_("Cloze"))
m["type"] = MODEL_CLOZE
txt = _("Text")
fm = mm.newField(txt)
mm.addField(m, fm)
t = mm.newTemplate(_("Cloze"))
fmt = "{{cloze:%s}}" % txt
m[
"css"
] += """
.cloze {
font-weight: bold;
color: blue;
}
.nightMode .cloze {
color: lightblue;
}"""
t["qfmt"] = fmt
t["afmt"] = fmt
mm.addTemplate(m, t)
mm.add(m)
return m
return add_stock_notetype(col, StockNoteType.StockNoteTypeCloze)
models.append((lambda: _("Cloze"), addClozeModel))
def get_stock_notetypes(
col: _Collection,
) -> List[Tuple[str, Callable[[_Collection], NoteType]]]:
out: List[Tuple[str, Callable[[_Collection], NoteType]]] = []
# add standard
for (kind, func) in [
(StockNoteType.StockNoteTypeBasic, addBasicModel),
(StockNoteType.StockNoteTypeBasicTyping, addBasicTypingModel),
(StockNoteType.StockNoteTypeBasicAndReversed, addForwardReverse),
(StockNoteType.StockNoteTypeBasicOptionalReversed, addForwardOptionalReverse),
(StockNoteType.StockNoteTypeCloze, addClozeModel),
]:
m = col.backend.get_stock_notetype_legacy(kind)
out.append((m["name"], func))
# add extras from add-ons
for (name_or_func, func) in models:
if not isinstance(name_or_func, str):
name = name_or_func()
else:
name = name_or_func
out.append((name, func))
return out

View file

@ -7,7 +7,7 @@ from anki import Collection as aopen
from anki.dbproxy import emulate_named_args
from anki.lang import without_unicode_isolation
from anki.rsbackend import TR
from anki.stdmodels import addBasicModel, models
from anki.stdmodels import addBasicModel, get_stock_notetypes
from anki.utils import isWin
from tests.shared import assertException, getEmptyCol
@ -119,10 +119,10 @@ def test_addDelTags():
def test_timestamps():
deck = getEmptyCol()
assert len(deck.models.all_names_and_ids()) == len(models)
assert len(deck.models.all_names_and_ids()) == len(get_stock_notetypes(deck))
for i in range(100):
addBasicModel(deck)
assert len(deck.models.all_names_and_ids()) == 100 + len(models)
assert len(deck.models.all_names_and_ids()) == 100 + len(get_stock_notetypes(deck))
def test_furigana():

View file

@ -1,7 +1,6 @@
# Copyright: Ankitects Pty Ltd and contributors
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
import collections
from operator import itemgetter
from typing import List, Optional
@ -196,9 +195,7 @@ class AddModel(QDialog):
self.dialog.setupUi(self)
# standard models
self.models = []
for (name, func) in stdmodels.models:
if isinstance(name, collections.Callable): # type: ignore
name = name() # type: ignore
for (name, func) in stdmodels.get_stock_notetypes(self.col):
item = QListWidgetItem(_("Add: %s") % name)
self.dialog.models.addItem(item)
self.models.append((True, func))

View file

@ -308,12 +308,9 @@ impl Backend {
OValue::GetChangedNotetypes(self.get_changed_notetypes()?)
}
Value::GetAllDecks(_) => OValue::GetAllDecks(self.get_all_decks()?),
Value::AllStockNotetypes(_) => OValue::AllStockNotetypes(pb::AllStockNotetypesOut {
notetypes: all_stock_notetypes(&self.i18n)
.into_iter()
.map(Into::into)
.collect(),
}),
Value::GetStockNotetypeLegacy(kind) => {
OValue::GetStockNotetypeLegacy(self.get_stock_notetype_legacy(kind)?)
}
Value::GetNotetypeLegacy(id) => {
OValue::GetNotetypeLegacy(self.get_notetype_legacy(id)?)
}
@ -1151,6 +1148,15 @@ impl Backend {
numbers: set.into_iter().map(|n| n as u32).collect(),
}
}
fn get_stock_notetype_legacy(&self, kind: i32) -> Result<Vec<u8>> {
// fixme: use individual functions instead of full vec
let mut all = all_stock_notetypes(&self.i18n);
let idx = (kind as usize).min(all.len() - 1);
let nt = all.swap_remove(idx);
let schema11: NoteTypeSchema11 = nt.into();
serde_json::to_vec(&schema11).map_err(Into::into)
}
}
fn to_nids(ids: Vec<i64>) -> Vec<NoteID> {