mirror of
https://github.com/ankitects/anki.git
synced 2025-09-18 22:12:21 -04:00
fetch stock notetypes from backend
This commit is contained in:
parent
f650e5557f
commit
2ac33500eb
6 changed files with 59 additions and 123 deletions
|
@ -71,7 +71,7 @@ message BackendInput {
|
||||||
AddOrUpdateNotetypeIn add_or_update_notetype = 57;
|
AddOrUpdateNotetypeIn add_or_update_notetype = 57;
|
||||||
Empty get_all_decks = 58;
|
Empty get_all_decks = 58;
|
||||||
Empty check_database = 59;
|
Empty check_database = 59;
|
||||||
Empty all_stock_notetypes = 60;
|
StockNoteType get_stock_notetype_legacy = 60;
|
||||||
int64 get_notetype_legacy = 61;
|
int64 get_notetype_legacy = 61;
|
||||||
Empty get_notetype_names = 62;
|
Empty get_notetype_names = 62;
|
||||||
Empty get_notetype_names_and_counts = 63;
|
Empty get_notetype_names_and_counts = 63;
|
||||||
|
@ -114,7 +114,6 @@ message BackendOutput {
|
||||||
string studied_today = 32;
|
string studied_today = 32;
|
||||||
string congrats_learn_msg = 33;
|
string congrats_learn_msg = 33;
|
||||||
Empty abort_media_sync = 46;
|
Empty abort_media_sync = 46;
|
||||||
AllStockNotetypesOut all_stock_notetypes = 60;
|
|
||||||
ClozeNumbersInNoteOut cloze_numbers_in_note = 87;
|
ClozeNumbersInNoteOut cloze_numbers_in_note = 87;
|
||||||
|
|
||||||
// fallible commands
|
// fallible commands
|
||||||
|
@ -177,6 +176,7 @@ message BackendOutput {
|
||||||
Preferences get_preferences = 84;
|
Preferences get_preferences = 84;
|
||||||
Empty set_preferences = 85;
|
Empty set_preferences = 85;
|
||||||
RenderCardOut render_existing_card = 86;
|
RenderCardOut render_existing_card = 86;
|
||||||
|
bytes get_stock_notetype_legacy = 60;
|
||||||
|
|
||||||
BackendError error = 2047;
|
BackendError error = 2047;
|
||||||
}
|
}
|
||||||
|
@ -587,10 +587,6 @@ enum StockNoteType {
|
||||||
StockNoteTypeCloze = 4;
|
StockNoteTypeCloze = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
message AllStockNotetypesOut {
|
|
||||||
repeated NoteType notetypes = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
message NoteTypeNames {
|
message NoteTypeNames {
|
||||||
repeated NoteTypeNameID entries = 1;
|
repeated NoteTypeNameID entries = 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,6 +50,7 @@ BackendNote = pb.Note
|
||||||
TagUsnTuple = pb.TagUsnTuple
|
TagUsnTuple = pb.TagUsnTuple
|
||||||
NoteType = pb.NoteType
|
NoteType = pb.NoteType
|
||||||
DeckTreeNode = pb.DeckTreeNode
|
DeckTreeNode = pb.DeckTreeNode
|
||||||
|
StockNoteType = pb.StockNoteType
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import orjson
|
import orjson
|
||||||
|
@ -602,12 +603,11 @@ class RustBackend:
|
||||||
).get_all_decks
|
).get_all_decks
|
||||||
return orjson.loads(jstr)
|
return orjson.loads(jstr)
|
||||||
|
|
||||||
def all_stock_notetypes(self) -> List[NoteType]:
|
def get_stock_notetype_legacy(self, kind: StockNoteType) -> Dict[str, Any]:
|
||||||
return list(
|
bytes = self._run_command(
|
||||||
self._run_command(
|
pb.BackendInput(get_stock_notetype_legacy=kind)
|
||||||
pb.BackendInput(all_stock_notetypes=pb.Empty())
|
).get_stock_notetype_legacy
|
||||||
).all_stock_notetypes.notetypes
|
return orjson.loads(bytes)
|
||||||
)
|
|
||||||
|
|
||||||
def get_notetype_names_and_ids(self) -> List[pb.NoteTypeNameID]:
|
def get_notetype_names_and_ids(self) -> List[pb.NoteTypeNameID]:
|
||||||
return list(
|
return list(
|
||||||
|
|
|
@ -1,125 +1,62 @@
|
||||||
# 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 Any, Callable, List, Optional, Tuple, Union
|
from typing import Callable, List, Tuple
|
||||||
|
|
||||||
from anki.collection import _Collection
|
from anki.collection import _Collection
|
||||||
from anki.consts import MODEL_CLOZE
|
|
||||||
from anki.lang import _
|
|
||||||
from anki.models import NoteType
|
from anki.models import NoteType
|
||||||
|
from anki.rsbackend import StockNoteType
|
||||||
|
|
||||||
models: List[Tuple[Union[Callable[[], str], str], Callable[[Any], NoteType]]] = []
|
# 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
|
||||||
# Basic
|
models: List[Tuple] = []
|
||||||
##########################################################################
|
|
||||||
|
|
||||||
|
|
||||||
def _newBasicModel(col: _Collection, name: Optional[str] = None) -> NoteType:
|
def add_stock_notetype(col: _Collection, kind: StockNoteType) -> NoteType:
|
||||||
mm = col.models
|
m = col.backend.get_stock_notetype_legacy(kind)
|
||||||
m = mm.new(name or _("Basic"))
|
col.models.add(m)
|
||||||
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)
|
|
||||||
return m
|
return m
|
||||||
|
|
||||||
|
|
||||||
def addBasicModel(col: _Collection) -> NoteType:
|
def addBasicModel(col: _Collection) -> NoteType:
|
||||||
m = _newBasicModel(col)
|
return add_stock_notetype(col, StockNoteType.StockNoteTypeBasic)
|
||||||
col.models.add(m)
|
|
||||||
return m
|
|
||||||
|
|
||||||
|
|
||||||
models.append((lambda: _("Basic"), addBasicModel))
|
|
||||||
|
|
||||||
# Basic w/ typing
|
|
||||||
##########################################################################
|
|
||||||
|
|
||||||
|
|
||||||
def addBasicTypingModel(col: _Collection) -> NoteType:
|
def addBasicTypingModel(col: _Collection) -> NoteType:
|
||||||
mm = col.models
|
return add_stock_notetype(col, StockNoteType.StockNoteTypeBasicTyping)
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
def addForwardReverse(col: _Collection) -> NoteType:
|
def addForwardReverse(col: _Collection) -> NoteType:
|
||||||
m = _newForwardReverse(col)
|
return add_stock_notetype(col, StockNoteType.StockNoteTypeBasicAndReversed)
|
||||||
col.models.add(m)
|
|
||||||
return m
|
|
||||||
|
|
||||||
|
|
||||||
models.append((lambda: _("Basic (and reversed card)"), addForwardReverse))
|
|
||||||
|
|
||||||
# Forward & Optional Reverse
|
|
||||||
##########################################################################
|
|
||||||
|
|
||||||
|
|
||||||
def addForwardOptionalReverse(col: _Collection) -> NoteType:
|
def addForwardOptionalReverse(col: _Collection) -> NoteType:
|
||||||
mm = col.models
|
return add_stock_notetype(col, StockNoteType.StockNoteTypeBasicOptionalReversed)
|
||||||
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
|
|
||||||
##########################################################################
|
|
||||||
|
|
||||||
|
|
||||||
def addClozeModel(col: _Collection) -> NoteType:
|
def addClozeModel(col: _Collection) -> NoteType:
|
||||||
mm = col.models
|
return add_stock_notetype(col, StockNoteType.StockNoteTypeCloze)
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
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
|
||||||
|
|
|
@ -7,7 +7,7 @@ from anki import Collection as aopen
|
||||||
from anki.dbproxy import emulate_named_args
|
from anki.dbproxy import emulate_named_args
|
||||||
from anki.lang import without_unicode_isolation
|
from anki.lang import without_unicode_isolation
|
||||||
from anki.rsbackend import TR
|
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 anki.utils import isWin
|
||||||
from tests.shared import assertException, getEmptyCol
|
from tests.shared import assertException, getEmptyCol
|
||||||
|
|
||||||
|
@ -119,10 +119,10 @@ def test_addDelTags():
|
||||||
|
|
||||||
def test_timestamps():
|
def test_timestamps():
|
||||||
deck = getEmptyCol()
|
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):
|
for i in range(100):
|
||||||
addBasicModel(deck)
|
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():
|
def test_furigana():
|
||||||
|
|
|
@ -1,7 +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
|
||||||
|
|
||||||
import collections
|
|
||||||
from operator import itemgetter
|
from operator import itemgetter
|
||||||
from typing import List, Optional
|
from typing import List, Optional
|
||||||
|
|
||||||
|
@ -196,9 +195,7 @@ class AddModel(QDialog):
|
||||||
self.dialog.setupUi(self)
|
self.dialog.setupUi(self)
|
||||||
# standard models
|
# standard models
|
||||||
self.models = []
|
self.models = []
|
||||||
for (name, func) in stdmodels.models:
|
for (name, func) in stdmodels.get_stock_notetypes(self.col):
|
||||||
if isinstance(name, collections.Callable): # type: ignore
|
|
||||||
name = name() # type: ignore
|
|
||||||
item = QListWidgetItem(_("Add: %s") % name)
|
item = QListWidgetItem(_("Add: %s") % name)
|
||||||
self.dialog.models.addItem(item)
|
self.dialog.models.addItem(item)
|
||||||
self.models.append((True, func))
|
self.models.append((True, func))
|
||||||
|
|
|
@ -308,12 +308,9 @@ impl Backend {
|
||||||
OValue::GetChangedNotetypes(self.get_changed_notetypes()?)
|
OValue::GetChangedNotetypes(self.get_changed_notetypes()?)
|
||||||
}
|
}
|
||||||
Value::GetAllDecks(_) => OValue::GetAllDecks(self.get_all_decks()?),
|
Value::GetAllDecks(_) => OValue::GetAllDecks(self.get_all_decks()?),
|
||||||
Value::AllStockNotetypes(_) => OValue::AllStockNotetypes(pb::AllStockNotetypesOut {
|
Value::GetStockNotetypeLegacy(kind) => {
|
||||||
notetypes: all_stock_notetypes(&self.i18n)
|
OValue::GetStockNotetypeLegacy(self.get_stock_notetype_legacy(kind)?)
|
||||||
.into_iter()
|
}
|
||||||
.map(Into::into)
|
|
||||||
.collect(),
|
|
||||||
}),
|
|
||||||
Value::GetNotetypeLegacy(id) => {
|
Value::GetNotetypeLegacy(id) => {
|
||||||
OValue::GetNotetypeLegacy(self.get_notetype_legacy(id)?)
|
OValue::GetNotetypeLegacy(self.get_notetype_legacy(id)?)
|
||||||
}
|
}
|
||||||
|
@ -1151,6 +1148,15 @@ impl Backend {
|
||||||
numbers: set.into_iter().map(|n| n as u32).collect(),
|
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> {
|
fn to_nids(ids: Vec<i64>) -> Vec<NoteID> {
|
||||||
|
|
Loading…
Reference in a new issue