mirror of
https://github.com/ankitects/anki.git
synced 2025-09-25 01:06:35 -04:00
parent
fcfa6bab4e
commit
9f4a06abee
42 changed files with 403 additions and 403 deletions
|
@ -27,7 +27,7 @@ from anki.sound import AVTag
|
||||||
# - lrn queue: integer timestamp
|
# - lrn queue: integer timestamp
|
||||||
|
|
||||||
# types
|
# types
|
||||||
CardID = NewType("CardID", int)
|
CardId = NewType("CardId", int)
|
||||||
|
|
||||||
|
|
||||||
class Card:
|
class Card:
|
||||||
|
@ -35,15 +35,15 @@ class Card:
|
||||||
timerStarted: Optional[float]
|
timerStarted: Optional[float]
|
||||||
lastIvl: int
|
lastIvl: int
|
||||||
ord: int
|
ord: int
|
||||||
nid: anki.notes.NoteID
|
nid: anki.notes.NoteId
|
||||||
id: CardID
|
id: CardId
|
||||||
did: anki.decks.DeckID
|
did: anki.decks.DeckId
|
||||||
odid: anki.decks.DeckID
|
odid: anki.decks.DeckId
|
||||||
queue: CardQueue
|
queue: CardQueue
|
||||||
type: CardType
|
type: CardType
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self, col: anki.collection.Collection, id: Optional[CardID] = None
|
self, col: anki.collection.Collection, id: Optional[CardId] = None
|
||||||
) -> None:
|
) -> None:
|
||||||
self.col = col.weakref()
|
self.col = col.weakref()
|
||||||
self.timerStarted = None
|
self.timerStarted = None
|
||||||
|
@ -64,9 +64,9 @@ class Card:
|
||||||
def _load_from_backend_card(self, c: _pb.Card) -> None:
|
def _load_from_backend_card(self, c: _pb.Card) -> None:
|
||||||
self._render_output = None
|
self._render_output = None
|
||||||
self._note = None
|
self._note = None
|
||||||
self.id = CardID(c.id)
|
self.id = CardId(c.id)
|
||||||
self.nid = anki.notes.NoteID(c.note_id)
|
self.nid = anki.notes.NoteId(c.note_id)
|
||||||
self.did = anki.decks.DeckID(c.deck_id)
|
self.did = anki.decks.DeckId(c.deck_id)
|
||||||
self.ord = c.template_idx
|
self.ord = c.template_idx
|
||||||
self.mod = c.mtime_secs
|
self.mod = c.mtime_secs
|
||||||
self.usn = c.usn
|
self.usn = c.usn
|
||||||
|
@ -79,7 +79,7 @@ class Card:
|
||||||
self.lapses = c.lapses
|
self.lapses = c.lapses
|
||||||
self.left = c.remaining_steps
|
self.left = c.remaining_steps
|
||||||
self.odue = c.original_due
|
self.odue = c.original_due
|
||||||
self.odid = anki.decks.DeckID(c.original_deck_id)
|
self.odid = anki.decks.DeckId(c.original_deck_id)
|
||||||
self.flags = c.flags
|
self.flags = c.flags
|
||||||
self.data = c.data
|
self.data = c.data
|
||||||
|
|
||||||
|
@ -167,8 +167,8 @@ class Card:
|
||||||
def startTimer(self) -> None:
|
def startTimer(self) -> None:
|
||||||
self.timerStarted = time.time()
|
self.timerStarted = time.time()
|
||||||
|
|
||||||
def current_deck_id(self) -> anki.decks.DeckID:
|
def current_deck_id(self) -> anki.decks.DeckId:
|
||||||
return anki.decks.DeckID(self.odid or self.did)
|
return anki.decks.DeckId(self.odid or self.did)
|
||||||
|
|
||||||
def timeLimit(self) -> int:
|
def timeLimit(self) -> int:
|
||||||
"Time limit for answering in milliseconds."
|
"Time limit for answering in milliseconds."
|
||||||
|
|
|
@ -17,7 +17,7 @@ Preferences = _pb.Preferences
|
||||||
UndoStatus = _pb.UndoStatus
|
UndoStatus = _pb.UndoStatus
|
||||||
OpChanges = _pb.OpChanges
|
OpChanges = _pb.OpChanges
|
||||||
OpChangesWithCount = _pb.OpChangesWithCount
|
OpChangesWithCount = _pb.OpChangesWithCount
|
||||||
OpChangesWithID = _pb.OpChangesWithID
|
OpChangesWithId = _pb.OpChangesWithId
|
||||||
DefaultsForAdding = _pb.DeckAndNotetype
|
DefaultsForAdding = _pb.DeckAndNotetype
|
||||||
BrowserRow = _pb.BrowserRow
|
BrowserRow = _pb.BrowserRow
|
||||||
|
|
||||||
|
@ -34,16 +34,16 @@ from dataclasses import dataclass, field
|
||||||
import anki.latex
|
import anki.latex
|
||||||
from anki import hooks
|
from anki import hooks
|
||||||
from anki._backend import RustBackend, Translations
|
from anki._backend import RustBackend, Translations
|
||||||
from anki.cards import Card, CardID
|
from anki.cards import Card, CardId
|
||||||
from anki.config import Config, ConfigManager
|
from anki.config import Config, ConfigManager
|
||||||
from anki.consts import *
|
from anki.consts import *
|
||||||
from anki.dbproxy import DBProxy
|
from anki.dbproxy import DBProxy
|
||||||
from anki.decks import DeckID, DeckManager
|
from anki.decks import DeckId, DeckManager
|
||||||
from anki.errors import AnkiError, DBError
|
from anki.errors import AnkiError, DBError
|
||||||
from anki.lang import FormatTimeSpan
|
from anki.lang import FormatTimeSpan
|
||||||
from anki.media import MediaManager, media_paths_from_col_path
|
from anki.media import MediaManager, media_paths_from_col_path
|
||||||
from anki.models import ModelManager, NoteType, NoteTypeID
|
from anki.models import ModelManager, NoteType, NoteTypeId
|
||||||
from anki.notes import Note, NoteID
|
from anki.notes import Note, NoteId
|
||||||
from anki.scheduler.v1 import Scheduler as V1Scheduler
|
from anki.scheduler.v1 import Scheduler as V1Scheduler
|
||||||
from anki.scheduler.v2 import Scheduler as V2Scheduler
|
from anki.scheduler.v2 import Scheduler as V2Scheduler
|
||||||
from anki.scheduler.v3 import Scheduler as V3TestScheduler
|
from anki.scheduler.v3 import Scheduler as V3TestScheduler
|
||||||
|
@ -317,7 +317,7 @@ class Collection:
|
||||||
# Object creation helpers
|
# Object creation helpers
|
||||||
##########################################################################
|
##########################################################################
|
||||||
|
|
||||||
def get_card(self, id: CardID) -> Card:
|
def get_card(self, id: CardId) -> Card:
|
||||||
return Card(self, id)
|
return Card(self, id)
|
||||||
|
|
||||||
def update_card(self, card: Card) -> None:
|
def update_card(self, card: Card) -> None:
|
||||||
|
@ -325,7 +325,7 @@ class Collection:
|
||||||
Unlike card.flush(), this will invalidate any current checkpoint."""
|
Unlike card.flush(), this will invalidate any current checkpoint."""
|
||||||
self._backend.update_card(card=card._to_backend_card(), skip_undo_entry=False)
|
self._backend.update_card(card=card._to_backend_card(), skip_undo_entry=False)
|
||||||
|
|
||||||
def get_note(self, id: NoteID) -> Note:
|
def get_note(self, id: NoteId) -> Note:
|
||||||
return Note(self, id=id)
|
return Note(self, id=id)
|
||||||
|
|
||||||
def update_note(self, note: Note) -> OpChanges:
|
def update_note(self, note: Note) -> OpChanges:
|
||||||
|
@ -356,7 +356,7 @@ class Collection:
|
||||||
# Deletion logging
|
# Deletion logging
|
||||||
##########################################################################
|
##########################################################################
|
||||||
|
|
||||||
def _logRem(self, ids: List[Union[int, NoteID]], type: int) -> None:
|
def _logRem(self, ids: List[Union[int, NoteId]], type: int) -> None:
|
||||||
self.db.executemany(
|
self.db.executemany(
|
||||||
"insert into graves values (%d, ?, %d)" % (self.usn(), type),
|
"insert into graves values (%d, ?, %d)" % (self.usn(), type),
|
||||||
([x] for x in ids),
|
([x] for x in ids),
|
||||||
|
@ -368,16 +368,16 @@ class Collection:
|
||||||
def new_note(self, notetype: NoteType) -> Note:
|
def new_note(self, notetype: NoteType) -> Note:
|
||||||
return Note(self, notetype)
|
return Note(self, notetype)
|
||||||
|
|
||||||
def add_note(self, note: Note, deck_id: DeckID) -> OpChanges:
|
def add_note(self, note: Note, deck_id: DeckId) -> OpChanges:
|
||||||
out = self._backend.add_note(note=note._to_backend_note(), deck_id=deck_id)
|
out = self._backend.add_note(note=note._to_backend_note(), deck_id=deck_id)
|
||||||
note.id = NoteID(out.note_id)
|
note.id = NoteId(out.note_id)
|
||||||
return out.changes
|
return out.changes
|
||||||
|
|
||||||
def remove_notes(self, note_ids: Sequence[NoteID]) -> OpChanges:
|
def remove_notes(self, note_ids: Sequence[NoteId]) -> OpChanges:
|
||||||
hooks.notes_will_be_deleted(self, note_ids)
|
hooks.notes_will_be_deleted(self, note_ids)
|
||||||
return self._backend.remove_notes(note_ids=note_ids, card_ids=[])
|
return self._backend.remove_notes(note_ids=note_ids, card_ids=[])
|
||||||
|
|
||||||
def remove_notes_by_card(self, card_ids: List[CardID]) -> None:
|
def remove_notes_by_card(self, card_ids: List[CardId]) -> None:
|
||||||
if hooks.notes_will_be_deleted.count():
|
if hooks.notes_will_be_deleted.count():
|
||||||
nids = self.db.list(
|
nids = self.db.list(
|
||||||
f"select nid from cards where id in {ids2str(card_ids)}"
|
f"select nid from cards where id in {ids2str(card_ids)}"
|
||||||
|
@ -385,8 +385,8 @@ class Collection:
|
||||||
hooks.notes_will_be_deleted(self, nids)
|
hooks.notes_will_be_deleted(self, nids)
|
||||||
self._backend.remove_notes(note_ids=[], card_ids=card_ids)
|
self._backend.remove_notes(note_ids=[], card_ids=card_ids)
|
||||||
|
|
||||||
def card_ids_of_note(self, note_id: NoteID) -> Sequence[CardID]:
|
def card_ids_of_note(self, note_id: NoteId) -> Sequence[CardId]:
|
||||||
return [CardID(id) for id in self._backend.cards_of_note(note_id)]
|
return [CardId(id) for id in self._backend.cards_of_note(note_id)]
|
||||||
|
|
||||||
def defaults_for_adding(
|
def defaults_for_adding(
|
||||||
self, *, current_review_card: Optional[Card]
|
self, *, current_review_card: Optional[Card]
|
||||||
|
@ -398,20 +398,20 @@ class Collection:
|
||||||
if card := current_review_card:
|
if card := current_review_card:
|
||||||
home_deck = card.current_deck_id()
|
home_deck = card.current_deck_id()
|
||||||
else:
|
else:
|
||||||
home_deck = DeckID(0)
|
home_deck = DeckId(0)
|
||||||
|
|
||||||
return self._backend.defaults_for_adding(
|
return self._backend.defaults_for_adding(
|
||||||
home_deck_of_current_review_card=home_deck,
|
home_deck_of_current_review_card=home_deck,
|
||||||
)
|
)
|
||||||
|
|
||||||
def default_deck_for_notetype(self, notetype_id: NoteTypeID) -> Optional[DeckID]:
|
def default_deck_for_notetype(self, notetype_id: NoteTypeId) -> Optional[DeckId]:
|
||||||
"""If 'change deck depending on notetype' is enabled in the preferences,
|
"""If 'change deck depending on notetype' is enabled in the preferences,
|
||||||
return the last deck used with the provided notetype, if any.."""
|
return the last deck used with the provided notetype, if any.."""
|
||||||
if self.get_config_bool(Config.Bool.ADDING_DEFAULTS_TO_CURRENT_DECK):
|
if self.get_config_bool(Config.Bool.ADDING_DEFAULTS_TO_CURRENT_DECK):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
return (
|
return (
|
||||||
DeckID(
|
DeckId(
|
||||||
self._backend.default_deck_for_notetype(
|
self._backend.default_deck_for_notetype(
|
||||||
ntid=notetype_id,
|
ntid=notetype_id,
|
||||||
)
|
)
|
||||||
|
@ -432,10 +432,10 @@ class Collection:
|
||||||
self.add_note(note, note.model()["did"])
|
self.add_note(note, note.model()["did"])
|
||||||
return len(note.cards())
|
return len(note.cards())
|
||||||
|
|
||||||
def remNotes(self, ids: Sequence[NoteID]) -> None:
|
def remNotes(self, ids: Sequence[NoteId]) -> None:
|
||||||
self.remove_notes(ids)
|
self.remove_notes(ids)
|
||||||
|
|
||||||
def _remNotes(self, ids: List[NoteID]) -> None:
|
def _remNotes(self, ids: List[NoteId]) -> None:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# Cards
|
# Cards
|
||||||
|
@ -447,11 +447,11 @@ class Collection:
|
||||||
def cardCount(self) -> Any:
|
def cardCount(self) -> Any:
|
||||||
return self.db.scalar("select count() from cards")
|
return self.db.scalar("select count() from cards")
|
||||||
|
|
||||||
def remove_cards_and_orphaned_notes(self, card_ids: Sequence[CardID]) -> None:
|
def remove_cards_and_orphaned_notes(self, card_ids: Sequence[CardId]) -> None:
|
||||||
"You probably want .remove_notes_by_card() instead."
|
"You probably want .remove_notes_by_card() instead."
|
||||||
self._backend.remove_cards(card_ids=card_ids)
|
self._backend.remove_cards(card_ids=card_ids)
|
||||||
|
|
||||||
def set_deck(self, card_ids: Sequence[CardID], deck_id: int) -> OpChanges:
|
def set_deck(self, card_ids: Sequence[CardId], deck_id: int) -> OpChanges:
|
||||||
return self._backend.set_deck(card_ids=card_ids, deck_id=deck_id)
|
return self._backend.set_deck(card_ids=card_ids, deck_id=deck_id)
|
||||||
|
|
||||||
def get_empty_cards(self) -> EmptyCardsReport:
|
def get_empty_cards(self) -> EmptyCardsReport:
|
||||||
|
@ -459,10 +459,10 @@ class Collection:
|
||||||
|
|
||||||
# legacy
|
# legacy
|
||||||
|
|
||||||
def remCards(self, ids: List[CardID], notes: bool = True) -> None:
|
def remCards(self, ids: List[CardId], notes: bool = True) -> None:
|
||||||
self.remove_cards_and_orphaned_notes(ids)
|
self.remove_cards_and_orphaned_notes(ids)
|
||||||
|
|
||||||
def emptyCids(self) -> List[CardID]:
|
def emptyCids(self) -> List[CardId]:
|
||||||
print("emptyCids() will go away")
|
print("emptyCids() will go away")
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
@ -470,7 +470,7 @@ class Collection:
|
||||||
##########################################################################
|
##########################################################################
|
||||||
|
|
||||||
def after_note_updates(
|
def after_note_updates(
|
||||||
self, nids: List[NoteID], mark_modified: bool, generate_cards: bool = True
|
self, nids: List[NoteId], mark_modified: bool, generate_cards: bool = True
|
||||||
) -> None:
|
) -> None:
|
||||||
self._backend.after_note_updates(
|
self._backend.after_note_updates(
|
||||||
nids=nids, generate_cards=generate_cards, mark_notes_modified=mark_modified
|
nids=nids, generate_cards=generate_cards, mark_notes_modified=mark_modified
|
||||||
|
@ -478,11 +478,11 @@ class Collection:
|
||||||
|
|
||||||
# legacy
|
# legacy
|
||||||
|
|
||||||
def updateFieldCache(self, nids: List[NoteID]) -> None:
|
def updateFieldCache(self, nids: List[NoteId]) -> None:
|
||||||
self.after_note_updates(nids, mark_modified=False, generate_cards=False)
|
self.after_note_updates(nids, mark_modified=False, generate_cards=False)
|
||||||
|
|
||||||
# this also updates field cache
|
# this also updates field cache
|
||||||
def genCards(self, nids: List[NoteID]) -> List[int]:
|
def genCards(self, nids: List[NoteId]) -> List[int]:
|
||||||
self.after_note_updates(nids, mark_modified=False, generate_cards=True)
|
self.after_note_updates(nids, mark_modified=False, generate_cards=True)
|
||||||
# previously returned empty cards, no longer does
|
# previously returned empty cards, no longer does
|
||||||
return []
|
return []
|
||||||
|
@ -495,7 +495,7 @@ class Collection:
|
||||||
query: str,
|
query: str,
|
||||||
order: Union[bool, str, BuiltinSort.Kind.V] = False,
|
order: Union[bool, str, BuiltinSort.Kind.V] = False,
|
||||||
reverse: bool = False,
|
reverse: bool = False,
|
||||||
) -> Sequence[CardID]:
|
) -> Sequence[CardId]:
|
||||||
"""Return card ids matching the provided search.
|
"""Return card ids matching the provided search.
|
||||||
|
|
||||||
To programmatically construct a search string, see .build_search_string().
|
To programmatically construct a search string, see .build_search_string().
|
||||||
|
@ -526,10 +526,10 @@ class Collection:
|
||||||
builtin=_pb.SortOrder.Builtin(kind=order, reverse=reverse)
|
builtin=_pb.SortOrder.Builtin(kind=order, reverse=reverse)
|
||||||
)
|
)
|
||||||
return [
|
return [
|
||||||
CardID(id) for id in self._backend.search_cards(search=query, order=mode)
|
CardId(id) for id in self._backend.search_cards(search=query, order=mode)
|
||||||
]
|
]
|
||||||
|
|
||||||
def find_notes(self, *terms: Union[str, SearchNode]) -> Sequence[NoteID]:
|
def find_notes(self, *terms: Union[str, SearchNode]) -> Sequence[NoteId]:
|
||||||
"""Return note ids matching the provided search or searches.
|
"""Return note ids matching the provided search or searches.
|
||||||
|
|
||||||
If more than one search is provided, they will be ANDed together.
|
If more than one search is provided, they will be ANDed together.
|
||||||
|
@ -541,14 +541,14 @@ class Collection:
|
||||||
that have a card in deck called "test", and have the text "foo".
|
that have a card in deck called "test", and have the text "foo".
|
||||||
"""
|
"""
|
||||||
return [
|
return [
|
||||||
NoteID(did)
|
NoteId(did)
|
||||||
for did in self._backend.search_notes(self.build_search_string(*terms))
|
for did in self._backend.search_notes(self.build_search_string(*terms))
|
||||||
]
|
]
|
||||||
|
|
||||||
def find_and_replace(
|
def find_and_replace(
|
||||||
self,
|
self,
|
||||||
*,
|
*,
|
||||||
note_ids: Sequence[NoteID],
|
note_ids: Sequence[NoteId],
|
||||||
search: str,
|
search: str,
|
||||||
replacement: str,
|
replacement: str,
|
||||||
regex: bool = False,
|
regex: bool = False,
|
||||||
|
@ -576,7 +576,7 @@ class Collection:
|
||||||
dupes = []
|
dupes = []
|
||||||
fields: Dict[int, int] = {}
|
fields: Dict[int, int] = {}
|
||||||
|
|
||||||
def ordForMid(mid: NoteTypeID) -> int:
|
def ordForMid(mid: NoteTypeId) -> int:
|
||||||
if mid not in fields:
|
if mid not in fields:
|
||||||
model = self.models.get(mid)
|
model = self.models.get(mid)
|
||||||
for c, f in enumerate(model["flds"]):
|
for c, f in enumerate(model["flds"]):
|
||||||
|
@ -742,7 +742,7 @@ class Collection:
|
||||||
|
|
||||||
return CollectionStats(self)
|
return CollectionStats(self)
|
||||||
|
|
||||||
def card_stats(self, card_id: CardID, include_revlog: bool) -> str:
|
def card_stats(self, card_id: CardId, include_revlog: bool) -> str:
|
||||||
import anki.stats as st
|
import anki.stats as st
|
||||||
|
|
||||||
if include_revlog:
|
if include_revlog:
|
||||||
|
@ -1035,7 +1035,7 @@ table.review-log {{ {revlog_style} }}
|
||||||
|
|
||||||
##########################################################################
|
##########################################################################
|
||||||
|
|
||||||
def set_user_flag_for_cards(self, flag: int, cids: Sequence[CardID]) -> OpChanges:
|
def set_user_flag_for_cards(self, flag: int, cids: Sequence[CardId]) -> OpChanges:
|
||||||
return self._backend.set_flag(card_ids=cids, flag=flag)
|
return self._backend.set_flag(card_ids=cids, flag=flag)
|
||||||
|
|
||||||
def set_wants_abort(self) -> None:
|
def set_wants_abort(self) -> None:
|
||||||
|
|
|
@ -11,15 +11,15 @@ from typing import Any, Dict, Iterable, List, NewType, Optional, Sequence, Tuple
|
||||||
|
|
||||||
import anki # pylint: disable=unused-import
|
import anki # pylint: disable=unused-import
|
||||||
import anki._backend.backend_pb2 as _pb
|
import anki._backend.backend_pb2 as _pb
|
||||||
from anki.cards import CardID
|
from anki.cards import CardId
|
||||||
from anki.collection import OpChanges, OpChangesWithCount, OpChangesWithID
|
from anki.collection import OpChanges, OpChangesWithCount, OpChangesWithId
|
||||||
from anki.consts import *
|
from anki.consts import *
|
||||||
from anki.errors import NotFoundError
|
from anki.errors import NotFoundError
|
||||||
from anki.utils import from_json_bytes, ids2str, intTime, legacy_func, to_json_bytes
|
from anki.utils import from_json_bytes, ids2str, intTime, legacy_func, to_json_bytes
|
||||||
|
|
||||||
# public exports
|
# public exports
|
||||||
DeckTreeNode = _pb.DeckTreeNode
|
DeckTreeNode = _pb.DeckTreeNode
|
||||||
DeckNameID = _pb.DeckNameID
|
DeckNameId = _pb.DeckNameId
|
||||||
FilteredDeckConfig = _pb.FilteredDeck
|
FilteredDeckConfig = _pb.FilteredDeck
|
||||||
|
|
||||||
# legacy code may pass this in as the type argument to .id()
|
# legacy code may pass this in as the type argument to .id()
|
||||||
|
@ -30,11 +30,11 @@ defaultDynamicDeck = 1
|
||||||
DeckDict = Dict[str, Any]
|
DeckDict = Dict[str, Any]
|
||||||
DeckConfigDict = Dict[str, Any]
|
DeckConfigDict = Dict[str, Any]
|
||||||
|
|
||||||
DeckID = NewType("DeckID", int)
|
DeckId = NewType("DeckId", int)
|
||||||
DeckConfID = NewType("DeckConfID", int)
|
DeckConfId = NewType("DeckConfId", int)
|
||||||
|
|
||||||
DEFAULT_DECK_ID = DeckID(1)
|
DEFAULT_DECK_ID = DeckId(1)
|
||||||
DEFAULT_DECK_CONF_ID = DeckConfID(1)
|
DEFAULT_DECK_CONF_ID = DeckConfId(1)
|
||||||
|
|
||||||
|
|
||||||
class DecksDictProxy:
|
class DecksDictProxy:
|
||||||
|
@ -47,7 +47,7 @@ class DecksDictProxy:
|
||||||
|
|
||||||
def __getitem__(self, item: Any) -> Any:
|
def __getitem__(self, item: Any) -> Any:
|
||||||
self._warn()
|
self._warn()
|
||||||
return self._col.decks.get(DeckID(int(item)))
|
return self._col.decks.get(DeckId(int(item)))
|
||||||
|
|
||||||
def __setitem__(self, key: Any, val: Any) -> None:
|
def __setitem__(self, key: Any, val: Any) -> None:
|
||||||
self._warn()
|
self._warn()
|
||||||
|
@ -107,16 +107,16 @@ class DeckManager:
|
||||||
# Deck save/load
|
# Deck save/load
|
||||||
#############################################################
|
#############################################################
|
||||||
|
|
||||||
def add_normal_deck_with_name(self, name: str) -> OpChangesWithID:
|
def add_normal_deck_with_name(self, name: str) -> OpChangesWithId:
|
||||||
"If deck exists, return existing id."
|
"If deck exists, return existing id."
|
||||||
if id := self.col.decks.id_for_name(name):
|
if id := self.col.decks.id_for_name(name):
|
||||||
return OpChangesWithID(id=id)
|
return OpChangesWithId(id=id)
|
||||||
else:
|
else:
|
||||||
deck = self.col.decks.new_deck_legacy(filtered=False)
|
deck = self.col.decks.new_deck_legacy(filtered=False)
|
||||||
deck["name"] = name
|
deck["name"] = name
|
||||||
return self.add_deck_legacy(deck)
|
return self.add_deck_legacy(deck)
|
||||||
|
|
||||||
def add_deck_legacy(self, deck: DeckDict) -> OpChangesWithID:
|
def add_deck_legacy(self, deck: DeckDict) -> OpChangesWithId:
|
||||||
"Add a deck created with new_deck_legacy(). Must have id of 0."
|
"Add a deck created with new_deck_legacy(). Must have id of 0."
|
||||||
assert deck["id"] == 0
|
assert deck["id"] == 0
|
||||||
return self.col._backend.add_deck_legacy(to_json_bytes(deck))
|
return self.col._backend.add_deck_legacy(to_json_bytes(deck))
|
||||||
|
@ -125,8 +125,8 @@ class DeckManager:
|
||||||
self,
|
self,
|
||||||
name: str,
|
name: str,
|
||||||
create: bool = True,
|
create: bool = True,
|
||||||
type: DeckConfID = DeckConfID(0),
|
type: DeckConfId = DeckConfId(0),
|
||||||
) -> Optional[DeckID]:
|
) -> Optional[DeckId]:
|
||||||
"Add a deck with NAME. Reuse deck if already exists. Return id as int."
|
"Add a deck with NAME. Reuse deck if already exists. Return id as int."
|
||||||
id = self.id_for_name(name)
|
id = self.id_for_name(name)
|
||||||
if id:
|
if id:
|
||||||
|
@ -137,40 +137,40 @@ class DeckManager:
|
||||||
deck = self.new_deck_legacy(bool(type))
|
deck = self.new_deck_legacy(bool(type))
|
||||||
deck["name"] = name
|
deck["name"] = name
|
||||||
out = self.add_deck_legacy(deck)
|
out = self.add_deck_legacy(deck)
|
||||||
return DeckID(out.id)
|
return DeckId(out.id)
|
||||||
|
|
||||||
@legacy_func(sub="remove")
|
@legacy_func(sub="remove")
|
||||||
def rem(self, did: DeckID, cardsToo: bool = True, childrenToo: bool = True) -> None:
|
def rem(self, did: DeckId, cardsToo: bool = True, childrenToo: bool = True) -> None:
|
||||||
"Remove the deck. If cardsToo, delete any cards inside."
|
"Remove the deck. If cardsToo, delete any cards inside."
|
||||||
if isinstance(did, str):
|
if isinstance(did, str):
|
||||||
did = int(did)
|
did = int(did)
|
||||||
assert cardsToo and childrenToo
|
assert cardsToo and childrenToo
|
||||||
self.remove([did])
|
self.remove([did])
|
||||||
|
|
||||||
def remove(self, dids: Sequence[DeckID]) -> OpChangesWithCount:
|
def remove(self, dids: Sequence[DeckId]) -> OpChangesWithCount:
|
||||||
return self.col._backend.remove_decks(dids)
|
return self.col._backend.remove_decks(dids)
|
||||||
|
|
||||||
def all_names_and_ids(
|
def all_names_and_ids(
|
||||||
self, skip_empty_default: bool = False, include_filtered: bool = True
|
self, skip_empty_default: bool = False, include_filtered: bool = True
|
||||||
) -> Sequence[DeckNameID]:
|
) -> Sequence[DeckNameId]:
|
||||||
"A sorted sequence of deck names and IDs."
|
"A sorted sequence of deck names and IDs."
|
||||||
return self.col._backend.get_deck_names(
|
return self.col._backend.get_deck_names(
|
||||||
skip_empty_default=skip_empty_default, include_filtered=include_filtered
|
skip_empty_default=skip_empty_default, include_filtered=include_filtered
|
||||||
)
|
)
|
||||||
|
|
||||||
def id_for_name(self, name: str) -> Optional[DeckID]:
|
def id_for_name(self, name: str) -> Optional[DeckId]:
|
||||||
try:
|
try:
|
||||||
return DeckID(self.col._backend.get_deck_id_by_name(name))
|
return DeckId(self.col._backend.get_deck_id_by_name(name))
|
||||||
except NotFoundError:
|
except NotFoundError:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def get_legacy(self, did: DeckID) -> Optional[DeckDict]:
|
def get_legacy(self, did: DeckId) -> Optional[DeckDict]:
|
||||||
try:
|
try:
|
||||||
return from_json_bytes(self.col._backend.get_deck_legacy(did))
|
return from_json_bytes(self.col._backend.get_deck_legacy(did))
|
||||||
except NotFoundError:
|
except NotFoundError:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def have(self, id: DeckID) -> bool:
|
def have(self, id: DeckId) -> bool:
|
||||||
return not self.get_legacy(id)
|
return not self.get_legacy(id)
|
||||||
|
|
||||||
def get_all_legacy(self) -> List[DeckDict]:
|
def get_all_legacy(self) -> List[DeckDict]:
|
||||||
|
@ -193,7 +193,7 @@ class DeckManager:
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def find_deck_in_tree(
|
def find_deck_in_tree(
|
||||||
cls, node: DeckTreeNode, deck_id: DeckID
|
cls, node: DeckTreeNode, deck_id: DeckId
|
||||||
) -> Optional[DeckTreeNode]:
|
) -> Optional[DeckTreeNode]:
|
||||||
if node.deck_id == deck_id:
|
if node.deck_id == deck_id:
|
||||||
return node
|
return node
|
||||||
|
@ -220,12 +220,12 @@ class DeckManager:
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
def collapse(self, did: DeckID) -> None:
|
def collapse(self, did: DeckId) -> None:
|
||||||
deck = self.get(did)
|
deck = self.get(did)
|
||||||
deck["collapsed"] = not deck["collapsed"]
|
deck["collapsed"] = not deck["collapsed"]
|
||||||
self.save(deck)
|
self.save(deck)
|
||||||
|
|
||||||
def collapseBrowser(self, did: DeckID) -> None:
|
def collapseBrowser(self, did: DeckId) -> None:
|
||||||
deck = self.get(did)
|
deck = self.get(did)
|
||||||
collapsed = deck.get("browserCollapsed", False)
|
collapsed = deck.get("browserCollapsed", False)
|
||||||
deck["browserCollapsed"] = not collapsed
|
deck["browserCollapsed"] = not collapsed
|
||||||
|
@ -235,7 +235,7 @@ class DeckManager:
|
||||||
return len(self.all_names_and_ids())
|
return len(self.all_names_and_ids())
|
||||||
|
|
||||||
def card_count(
|
def card_count(
|
||||||
self, dids: Union[DeckID, Iterable[DeckID]], include_subdecks: bool
|
self, dids: Union[DeckId, Iterable[DeckId]], include_subdecks: bool
|
||||||
) -> Any:
|
) -> Any:
|
||||||
if isinstance(dids, int):
|
if isinstance(dids, int):
|
||||||
dids = {dids}
|
dids = {dids}
|
||||||
|
@ -249,13 +249,13 @@ class DeckManager:
|
||||||
)
|
)
|
||||||
return count
|
return count
|
||||||
|
|
||||||
def get(self, did: Union[DeckID, str], default: bool = True) -> Optional[DeckDict]:
|
def get(self, did: Union[DeckId, str], default: bool = True) -> Optional[DeckDict]:
|
||||||
if not did:
|
if not did:
|
||||||
if default:
|
if default:
|
||||||
return self.get_legacy(DEFAULT_DECK_ID)
|
return self.get_legacy(DEFAULT_DECK_ID)
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
id = DeckID(int(did))
|
id = DeckId(int(did))
|
||||||
deck = self.get_legacy(id)
|
deck = self.get_legacy(id)
|
||||||
if deck:
|
if deck:
|
||||||
return deck
|
return deck
|
||||||
|
@ -277,7 +277,7 @@ class DeckManager:
|
||||||
deck=to_json_bytes(g), preserve_usn_and_mtime=preserve_usn
|
deck=to_json_bytes(g), preserve_usn_and_mtime=preserve_usn
|
||||||
)
|
)
|
||||||
|
|
||||||
def rename(self, deck: Union[DeckDict, DeckID], new_name: str) -> OpChanges:
|
def rename(self, deck: Union[DeckDict, DeckId], new_name: str) -> OpChanges:
|
||||||
"Rename deck prefix to NAME if not exists. Updates children."
|
"Rename deck prefix to NAME if not exists. Updates children."
|
||||||
if isinstance(deck, int):
|
if isinstance(deck, int):
|
||||||
deck_id = deck
|
deck_id = deck
|
||||||
|
@ -289,7 +289,7 @@ class DeckManager:
|
||||||
#############################################################
|
#############################################################
|
||||||
|
|
||||||
def reparent(
|
def reparent(
|
||||||
self, deck_ids: Sequence[DeckID], new_parent: DeckID
|
self, deck_ids: Sequence[DeckId], new_parent: DeckId
|
||||||
) -> OpChangesWithCount:
|
) -> OpChangesWithCount:
|
||||||
"""Rename one or more source decks that were dropped on `new_parent`.
|
"""Rename one or more source decks that were dropped on `new_parent`.
|
||||||
If new_parent is 0, decks will be placed at the top level."""
|
If new_parent is 0, decks will be placed at the top level."""
|
||||||
|
@ -300,14 +300,14 @@ class DeckManager:
|
||||||
# legacy
|
# legacy
|
||||||
def renameForDragAndDrop(
|
def renameForDragAndDrop(
|
||||||
self,
|
self,
|
||||||
draggedDeckDid: Union[DeckID, str],
|
draggedDeckDid: Union[DeckId, str],
|
||||||
ontoDeckDid: Optional[Union[DeckID, str]],
|
ontoDeckDid: Optional[Union[DeckId, str]],
|
||||||
) -> None:
|
) -> None:
|
||||||
if not ontoDeckDid:
|
if not ontoDeckDid:
|
||||||
onto = 0
|
onto = 0
|
||||||
else:
|
else:
|
||||||
onto = int(ontoDeckDid)
|
onto = int(ontoDeckDid)
|
||||||
self.reparent([DeckID(int(draggedDeckDid))], DeckID(onto))
|
self.reparent([DeckId(int(draggedDeckDid))], DeckId(onto))
|
||||||
|
|
||||||
# Deck configurations
|
# Deck configurations
|
||||||
#############################################################
|
#############################################################
|
||||||
|
@ -316,11 +316,11 @@ class DeckManager:
|
||||||
"A list of all deck config."
|
"A list of all deck config."
|
||||||
return list(from_json_bytes(self.col._backend.all_deck_config_legacy()))
|
return list(from_json_bytes(self.col._backend.all_deck_config_legacy()))
|
||||||
|
|
||||||
def confForDid(self, did: DeckID) -> DeckConfigDict:
|
def confForDid(self, did: DeckId) -> DeckConfigDict:
|
||||||
deck = self.get(did, default=False)
|
deck = self.get(did, default=False)
|
||||||
assert deck
|
assert deck
|
||||||
if "conf" in deck:
|
if "conf" in deck:
|
||||||
dcid = DeckConfID(int(deck["conf"])) # may be a string
|
dcid = DeckConfId(int(deck["conf"])) # may be a string
|
||||||
conf = self.get_config(dcid)
|
conf = self.get_config(dcid)
|
||||||
if not conf:
|
if not conf:
|
||||||
# fall back on default
|
# fall back on default
|
||||||
|
@ -330,7 +330,7 @@ class DeckManager:
|
||||||
# dynamic decks have embedded conf
|
# dynamic decks have embedded conf
|
||||||
return deck
|
return deck
|
||||||
|
|
||||||
def get_config(self, conf_id: DeckConfID) -> Optional[DeckConfigDict]:
|
def get_config(self, conf_id: DeckConfId) -> Optional[DeckConfigDict]:
|
||||||
try:
|
try:
|
||||||
return from_json_bytes(self.col._backend.get_deck_config_legacy(conf_id))
|
return from_json_bytes(self.col._backend.get_deck_config_legacy(conf_id))
|
||||||
except NotFoundError:
|
except NotFoundError:
|
||||||
|
@ -355,10 +355,10 @@ class DeckManager:
|
||||||
|
|
||||||
def add_config_returning_id(
|
def add_config_returning_id(
|
||||||
self, name: str, clone_from: Optional[DeckConfigDict] = None
|
self, name: str, clone_from: Optional[DeckConfigDict] = None
|
||||||
) -> DeckConfID:
|
) -> DeckConfId:
|
||||||
return self.add_config(name, clone_from)["id"]
|
return self.add_config(name, clone_from)["id"]
|
||||||
|
|
||||||
def remove_config(self, id: DeckConfID) -> None:
|
def remove_config(self, id: DeckConfId) -> None:
|
||||||
"Remove a configuration and update all decks using it."
|
"Remove a configuration and update all decks using it."
|
||||||
self.col.modSchema(check=True)
|
self.col.modSchema(check=True)
|
||||||
for g in self.all():
|
for g in self.all():
|
||||||
|
@ -370,11 +370,11 @@ class DeckManager:
|
||||||
self.save(g)
|
self.save(g)
|
||||||
self.col._backend.remove_deck_config(id)
|
self.col._backend.remove_deck_config(id)
|
||||||
|
|
||||||
def setConf(self, grp: DeckConfigDict, id: DeckConfID) -> None:
|
def setConf(self, grp: DeckConfigDict, id: DeckConfId) -> None:
|
||||||
grp["conf"] = id
|
grp["conf"] = id
|
||||||
self.save(grp)
|
self.save(grp)
|
||||||
|
|
||||||
def didsForConf(self, conf: DeckConfigDict) -> List[DeckID]:
|
def didsForConf(self, conf: DeckConfigDict) -> List[DeckId]:
|
||||||
dids = []
|
dids = []
|
||||||
for deck in self.all():
|
for deck in self.all():
|
||||||
if "conf" in deck and deck["conf"] == conf["id"]:
|
if "conf" in deck and deck["conf"] == conf["id"]:
|
||||||
|
@ -401,19 +401,19 @@ class DeckManager:
|
||||||
# Deck utils
|
# Deck utils
|
||||||
#############################################################
|
#############################################################
|
||||||
|
|
||||||
def name(self, did: DeckID, default: bool = False) -> str:
|
def name(self, did: DeckId, default: bool = False) -> str:
|
||||||
deck = self.get(did, default=default)
|
deck = self.get(did, default=default)
|
||||||
if deck:
|
if deck:
|
||||||
return deck["name"]
|
return deck["name"]
|
||||||
return self.col.tr.decks_no_deck()
|
return self.col.tr.decks_no_deck()
|
||||||
|
|
||||||
def name_if_exists(self, did: DeckID) -> Optional[str]:
|
def name_if_exists(self, did: DeckId) -> Optional[str]:
|
||||||
deck = self.get(did, default=False)
|
deck = self.get(did, default=False)
|
||||||
if deck:
|
if deck:
|
||||||
return deck["name"]
|
return deck["name"]
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def setDeck(self, cids: List[CardID], did: DeckID) -> None:
|
def setDeck(self, cids: List[CardId], did: DeckId) -> None:
|
||||||
self.col.db.execute(
|
self.col.db.execute(
|
||||||
f"update cards set did=?,usn=?,mod=? where id in {ids2str(cids)}",
|
f"update cards set did=?,usn=?,mod=? where id in {ids2str(cids)}",
|
||||||
did,
|
did,
|
||||||
|
@ -421,7 +421,7 @@ class DeckManager:
|
||||||
intTime(),
|
intTime(),
|
||||||
)
|
)
|
||||||
|
|
||||||
def cids(self, did: DeckID, children: bool = False) -> List[CardID]:
|
def cids(self, did: DeckId, children: bool = False) -> List[CardId]:
|
||||||
if not children:
|
if not children:
|
||||||
return self.col.db.list("select id from cards where did=?", did)
|
return self.col.db.list("select id from cards where did=?", did)
|
||||||
dids = [did]
|
dids = [did]
|
||||||
|
@ -429,27 +429,27 @@ class DeckManager:
|
||||||
dids.append(id)
|
dids.append(id)
|
||||||
return self.col.db.list(f"select id from cards where did in {ids2str(dids)}")
|
return self.col.db.list(f"select id from cards where did in {ids2str(dids)}")
|
||||||
|
|
||||||
def for_card_ids(self, cids: List[CardID]) -> List[DeckID]:
|
def for_card_ids(self, cids: List[CardId]) -> List[DeckId]:
|
||||||
return self.col.db.list(f"select did from cards where id in {ids2str(cids)}")
|
return self.col.db.list(f"select did from cards where id in {ids2str(cids)}")
|
||||||
|
|
||||||
# Deck selection
|
# Deck selection
|
||||||
#############################################################
|
#############################################################
|
||||||
|
|
||||||
def active(self) -> List[DeckID]:
|
def active(self) -> List[DeckId]:
|
||||||
"The currrently active dids."
|
"The currrently active dids."
|
||||||
return self.col.get_config("activeDecks", [1])
|
return self.col.get_config("activeDecks", [1])
|
||||||
|
|
||||||
def selected(self) -> DeckID:
|
def selected(self) -> DeckId:
|
||||||
"The currently selected did."
|
"The currently selected did."
|
||||||
return DeckID(int(self.col.conf["curDeck"]))
|
return DeckId(int(self.col.conf["curDeck"]))
|
||||||
|
|
||||||
def current(self) -> DeckDict:
|
def current(self) -> DeckDict:
|
||||||
return self.get(self.selected())
|
return self.get(self.selected())
|
||||||
|
|
||||||
def select(self, did: DeckID) -> None:
|
def select(self, did: DeckId) -> None:
|
||||||
"Select a new branch."
|
"Select a new branch."
|
||||||
# make sure arg is an int; legacy callers may be passing in a string
|
# make sure arg is an int; legacy callers may be passing in a string
|
||||||
did = DeckID(did)
|
did = DeckId(did)
|
||||||
current = self.selected()
|
current = self.selected()
|
||||||
active = self.deck_and_child_ids(did)
|
active = self.deck_and_child_ids(did)
|
||||||
if current != did or active != self.active():
|
if current != did or active != self.active():
|
||||||
|
@ -490,31 +490,31 @@ class DeckManager:
|
||||||
def key(cls, deck: DeckDict) -> List[str]:
|
def key(cls, deck: DeckDict) -> List[str]:
|
||||||
return cls.path(deck["name"])
|
return cls.path(deck["name"])
|
||||||
|
|
||||||
def children(self, did: DeckID) -> List[Tuple[str, DeckID]]:
|
def children(self, did: DeckId) -> List[Tuple[str, DeckId]]:
|
||||||
"All children of did, as (name, id)."
|
"All children of did, as (name, id)."
|
||||||
name = self.get(did)["name"]
|
name = self.get(did)["name"]
|
||||||
actv = []
|
actv = []
|
||||||
for g in self.all_names_and_ids():
|
for g in self.all_names_and_ids():
|
||||||
if g.name.startswith(f"{name}::"):
|
if g.name.startswith(f"{name}::"):
|
||||||
actv.append((g.name, DeckID(g.id)))
|
actv.append((g.name, DeckId(g.id)))
|
||||||
return actv
|
return actv
|
||||||
|
|
||||||
def child_ids(self, parent_name: str) -> Iterable[DeckID]:
|
def child_ids(self, parent_name: str) -> Iterable[DeckId]:
|
||||||
prefix = f"{parent_name}::"
|
prefix = f"{parent_name}::"
|
||||||
return (
|
return (
|
||||||
DeckID(d.id) for d in self.all_names_and_ids() if d.name.startswith(prefix)
|
DeckId(d.id) for d in self.all_names_and_ids() if d.name.startswith(prefix)
|
||||||
)
|
)
|
||||||
|
|
||||||
def deck_and_child_ids(self, deck_id: DeckID) -> List[DeckID]:
|
def deck_and_child_ids(self, deck_id: DeckId) -> List[DeckId]:
|
||||||
parent_name = self.get_legacy(deck_id)["name"]
|
parent_name = self.get_legacy(deck_id)["name"]
|
||||||
out = [deck_id]
|
out = [deck_id]
|
||||||
out.extend(self.child_ids(parent_name))
|
out.extend(self.child_ids(parent_name))
|
||||||
return out
|
return out
|
||||||
|
|
||||||
childMapNode = Dict[DeckID, Any]
|
childMapNode = Dict[DeckId, Any]
|
||||||
# Change to Dict[int, "DeckManager.childMapNode"] when MyPy allow recursive type
|
# Change to Dict[int, "DeckManager.childMapNode"] when MyPy allow recursive type
|
||||||
|
|
||||||
def childDids(self, did: DeckID, childMap: DeckManager.childMapNode) -> List:
|
def childDids(self, did: DeckId, childMap: DeckManager.childMapNode) -> List:
|
||||||
def gather(node: DeckManager.childMapNode, arr: List) -> None:
|
def gather(node: DeckManager.childMapNode, arr: List) -> None:
|
||||||
for did, child in node.items():
|
for did, child in node.items():
|
||||||
arr.append(did)
|
arr.append(did)
|
||||||
|
@ -542,7 +542,7 @@ class DeckManager:
|
||||||
return childMap
|
return childMap
|
||||||
|
|
||||||
def parents(
|
def parents(
|
||||||
self, did: DeckID, nameMap: Optional[Dict[str, DeckDict]] = None
|
self, did: DeckId, nameMap: Optional[Dict[str, DeckDict]] = None
|
||||||
) -> List[DeckDict]:
|
) -> List[DeckDict]:
|
||||||
"All parents of did."
|
"All parents of did."
|
||||||
# get parent and grandparent names
|
# get parent and grandparent names
|
||||||
|
@ -584,14 +584,14 @@ class DeckManager:
|
||||||
# Dynamic decks
|
# Dynamic decks
|
||||||
##########################################################################
|
##########################################################################
|
||||||
|
|
||||||
def new_filtered(self, name: str) -> DeckID:
|
def new_filtered(self, name: str) -> DeckId:
|
||||||
"Return a new dynamic deck and set it as the current deck."
|
"Return a new dynamic deck and set it as the current deck."
|
||||||
did = self.id(name, type=DEFAULT_DECK_CONF_ID)
|
did = self.id(name, type=DEFAULT_DECK_CONF_ID)
|
||||||
self.select(did)
|
self.select(did)
|
||||||
return did
|
return did
|
||||||
|
|
||||||
# 1 for dyn, 0 for standard
|
# 1 for dyn, 0 for standard
|
||||||
def isDyn(self, did: Union[DeckID, str]) -> int:
|
def isDyn(self, did: Union[DeckId, str]) -> int:
|
||||||
return self.get(did)["dyn"]
|
return self.get(did)["dyn"]
|
||||||
|
|
||||||
# legacy
|
# legacy
|
||||||
|
|
|
@ -12,9 +12,9 @@ from typing import Any, Dict, List, Optional, Tuple, Union
|
||||||
from zipfile import ZipFile
|
from zipfile import ZipFile
|
||||||
|
|
||||||
from anki import hooks
|
from anki import hooks
|
||||||
from anki.cards import CardID
|
from anki.cards import CardId
|
||||||
from anki.collection import Collection
|
from anki.collection import Collection
|
||||||
from anki.decks import DeckID
|
from anki.decks import DeckId
|
||||||
from anki.utils import ids2str, namedtmp, splitFields, stripHTML
|
from anki.utils import ids2str, namedtmp, splitFields, stripHTML
|
||||||
|
|
||||||
|
|
||||||
|
@ -28,8 +28,8 @@ class Exporter:
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
col: Collection,
|
col: Collection,
|
||||||
did: Optional[DeckID] = None,
|
did: Optional[DeckId] = None,
|
||||||
cids: Optional[List[CardID]] = None,
|
cids: Optional[List[CardId]] = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
self.col = col.weakref()
|
self.col = col.weakref()
|
||||||
self.did = did
|
self.did = did
|
||||||
|
@ -185,7 +185,7 @@ class AnkiExporter(Exporter):
|
||||||
def key(col: Collection) -> str:
|
def key(col: Collection) -> str:
|
||||||
return col.tr.exporting_anki_20_deck()
|
return col.tr.exporting_anki_20_deck()
|
||||||
|
|
||||||
def deckIds(self) -> List[DeckID]:
|
def deckIds(self) -> List[DeckId]:
|
||||||
if self.cids:
|
if self.cids:
|
||||||
return self.col.decks.for_card_ids(self.cids)
|
return self.col.decks.for_card_ids(self.cids)
|
||||||
elif self.did:
|
elif self.did:
|
||||||
|
|
|
@ -6,7 +6,7 @@ from __future__ import annotations
|
||||||
from typing import TYPE_CHECKING, Optional, Set
|
from typing import TYPE_CHECKING, Optional, Set
|
||||||
|
|
||||||
from anki.hooks import *
|
from anki.hooks import *
|
||||||
from anki.notes import NoteID
|
from anki.notes import NoteId
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from anki.collection import Collection
|
from anki.collection import Collection
|
||||||
|
@ -30,7 +30,7 @@ class Finder:
|
||||||
|
|
||||||
def findReplace(
|
def findReplace(
|
||||||
col: Collection,
|
col: Collection,
|
||||||
nids: List[NoteID],
|
nids: List[NoteId],
|
||||||
src: str,
|
src: str,
|
||||||
dst: str,
|
dst: str,
|
||||||
regex: bool = False,
|
regex: bool = False,
|
||||||
|
@ -49,7 +49,7 @@ def findReplace(
|
||||||
).count
|
).count
|
||||||
|
|
||||||
|
|
||||||
def fieldNamesForNotes(col: Collection, nids: List[NoteID]) -> List[str]:
|
def fieldNamesForNotes(col: Collection, nids: List[NoteId]) -> List[str]:
|
||||||
return list(col.field_names_for_note_ids(nids))
|
return list(col.field_names_for_note_ids(nids))
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -5,13 +5,13 @@ import os
|
||||||
import unicodedata
|
import unicodedata
|
||||||
from typing import Any, Dict, List, Optional, Tuple
|
from typing import Any, Dict, List, Optional, Tuple
|
||||||
|
|
||||||
from anki.cards import CardID
|
from anki.cards import CardId
|
||||||
from anki.collection import Collection
|
from anki.collection import Collection
|
||||||
from anki.consts import *
|
from anki.consts import *
|
||||||
from anki.decks import DeckID, DeckManager
|
from anki.decks import DeckId, DeckManager
|
||||||
from anki.importing.base import Importer
|
from anki.importing.base import Importer
|
||||||
from anki.models import NoteTypeID
|
from anki.models import NoteTypeId
|
||||||
from anki.notes import NoteID
|
from anki.notes import NoteId
|
||||||
from anki.utils import intTime, joinFields, splitFields, stripHTMLMedia
|
from anki.utils import intTime, joinFields, splitFields, stripHTMLMedia
|
||||||
|
|
||||||
GUID = 1
|
GUID = 1
|
||||||
|
@ -31,7 +31,7 @@ class Anki2Importer(Importer):
|
||||||
super().__init__(col, file)
|
super().__init__(col, file)
|
||||||
|
|
||||||
# set later, defined here for typechecking
|
# set later, defined here for typechecking
|
||||||
self._decks: Dict[DeckID, DeckID] = {}
|
self._decks: Dict[DeckId, DeckId] = {}
|
||||||
self.source_needs_upgrade = False
|
self.source_needs_upgrade = False
|
||||||
|
|
||||||
def run(self, media: None = None) -> None:
|
def run(self, media: None = None) -> None:
|
||||||
|
@ -81,7 +81,7 @@ class Anki2Importer(Importer):
|
||||||
|
|
||||||
def _importNotes(self) -> None:
|
def _importNotes(self) -> None:
|
||||||
# build guid -> (id,mod,mid) hash & map of existing note ids
|
# build guid -> (id,mod,mid) hash & map of existing note ids
|
||||||
self._notes: Dict[str, Tuple[NoteID, int, NoteTypeID]] = {}
|
self._notes: Dict[str, Tuple[NoteId, int, NoteTypeId]] = {}
|
||||||
existing = {}
|
existing = {}
|
||||||
for id, guid, mod, mid in self.dst.db.execute(
|
for id, guid, mod, mid in self.dst.db.execute(
|
||||||
"select id, guid, mod, mid from notes"
|
"select id, guid, mod, mid from notes"
|
||||||
|
@ -212,9 +212,9 @@ class Anki2Importer(Importer):
|
||||||
|
|
||||||
def _prepareModels(self) -> None:
|
def _prepareModels(self) -> None:
|
||||||
"Prepare index of schema hashes."
|
"Prepare index of schema hashes."
|
||||||
self._modelMap: Dict[NoteTypeID, NoteTypeID] = {}
|
self._modelMap: Dict[NoteTypeId, NoteTypeId] = {}
|
||||||
|
|
||||||
def _mid(self, srcMid: NoteTypeID) -> Any:
|
def _mid(self, srcMid: NoteTypeId) -> Any:
|
||||||
"Return local id for remote MID."
|
"Return local id for remote MID."
|
||||||
# already processed this mid?
|
# already processed this mid?
|
||||||
if srcMid in self._modelMap:
|
if srcMid in self._modelMap:
|
||||||
|
@ -243,7 +243,7 @@ class Anki2Importer(Importer):
|
||||||
self.dst.models.update(model)
|
self.dst.models.update(model)
|
||||||
break
|
break
|
||||||
# as they don't match, try next id
|
# as they don't match, try next id
|
||||||
mid = NoteTypeID(mid + 1)
|
mid = NoteTypeId(mid + 1)
|
||||||
# save map and return new mid
|
# save map and return new mid
|
||||||
self._modelMap[srcMid] = mid
|
self._modelMap[srcMid] = mid
|
||||||
return mid
|
return mid
|
||||||
|
@ -251,7 +251,7 @@ class Anki2Importer(Importer):
|
||||||
# Decks
|
# Decks
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
||||||
def _did(self, did: DeckID) -> Any:
|
def _did(self, did: DeckId) -> Any:
|
||||||
"Given did in src col, return local id."
|
"Given did in src col, return local id."
|
||||||
# already converted?
|
# already converted?
|
||||||
if did in self._decks:
|
if did in self._decks:
|
||||||
|
@ -302,7 +302,7 @@ class Anki2Importer(Importer):
|
||||||
if self.source_needs_upgrade:
|
if self.source_needs_upgrade:
|
||||||
self.src.upgrade_to_v2_scheduler()
|
self.src.upgrade_to_v2_scheduler()
|
||||||
# build map of (guid, ord) -> cid and used id cache
|
# build map of (guid, ord) -> cid and used id cache
|
||||||
self._cards: Dict[Tuple[str, int], CardID] = {}
|
self._cards: Dict[Tuple[str, int], CardId] = {}
|
||||||
existing = {}
|
existing = {}
|
||||||
for guid, ord, cid in self.dst.db.execute(
|
for guid, ord, cid in self.dst.db.execute(
|
||||||
"select f.guid, c.ord, c.id from cards c, notes f " "where c.nid = f.id"
|
"select f.guid, c.ord, c.id from cards c, notes f " "where c.nid = f.id"
|
||||||
|
@ -427,7 +427,7 @@ insert or ignore into revlog values (?,?,?,?,?,?,?,?,?)""",
|
||||||
# the user likely used subdirectories
|
# the user likely used subdirectories
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def _mungeMedia(self, mid: NoteTypeID, fieldsStr: str) -> str:
|
def _mungeMedia(self, mid: NoteTypeId, fieldsStr: str) -> str:
|
||||||
fields = splitFields(fieldsStr)
|
fields = splitFields(fieldsStr)
|
||||||
|
|
||||||
def repl(match):
|
def repl(match):
|
||||||
|
|
|
@ -9,8 +9,8 @@ from anki.collection import Collection
|
||||||
from anki.config import Config
|
from anki.config import Config
|
||||||
from anki.consts import NEW_CARDS_RANDOM, STARTING_FACTOR
|
from anki.consts import NEW_CARDS_RANDOM, STARTING_FACTOR
|
||||||
from anki.importing.base import Importer
|
from anki.importing.base import Importer
|
||||||
from anki.models import NoteTypeID
|
from anki.models import NoteTypeId
|
||||||
from anki.notes import NoteID
|
from anki.notes import NoteId
|
||||||
from anki.utils import (
|
from anki.utils import (
|
||||||
fieldChecksum,
|
fieldChecksum,
|
||||||
guid64,
|
guid64,
|
||||||
|
@ -20,9 +20,9 @@ from anki.utils import (
|
||||||
timestampID,
|
timestampID,
|
||||||
)
|
)
|
||||||
|
|
||||||
TagMappedUpdate = Tuple[int, int, str, str, NoteID, str, str]
|
TagMappedUpdate = Tuple[int, int, str, str, NoteId, str, str]
|
||||||
TagModifiedUpdate = Tuple[int, int, str, str, NoteID, str]
|
TagModifiedUpdate = Tuple[int, int, str, str, NoteId, str]
|
||||||
NoTagUpdate = Tuple[int, int, str, NoteID, str]
|
NoTagUpdate = Tuple[int, int, str, NoteId, str]
|
||||||
Updates = Union[TagMappedUpdate, TagModifiedUpdate, NoTagUpdate]
|
Updates = Union[TagMappedUpdate, TagModifiedUpdate, NoTagUpdate]
|
||||||
|
|
||||||
# Stores a list of fields, tags and deck
|
# Stores a list of fields, tags and deck
|
||||||
|
@ -120,7 +120,7 @@ class NoteImporter(Importer):
|
||||||
if f == "_tags":
|
if f == "_tags":
|
||||||
self._tagsMapped = True
|
self._tagsMapped = True
|
||||||
# gather checks for duplicate comparison
|
# gather checks for duplicate comparison
|
||||||
csums: Dict[str, List[NoteID]] = {}
|
csums: Dict[str, List[NoteId]] = {}
|
||||||
for csum, id in self.col.db.execute(
|
for csum, id in self.col.db.execute(
|
||||||
"select csum, id from notes where mid = ?", self.model["id"]
|
"select csum, id from notes where mid = ?", self.model["id"]
|
||||||
):
|
):
|
||||||
|
@ -131,12 +131,12 @@ class NoteImporter(Importer):
|
||||||
firsts: Dict[str, bool] = {}
|
firsts: Dict[str, bool] = {}
|
||||||
fld0idx = self.mapping.index(self.model["flds"][0]["name"])
|
fld0idx = self.mapping.index(self.model["flds"][0]["name"])
|
||||||
self._fmap = self.col.models.fieldMap(self.model)
|
self._fmap = self.col.models.fieldMap(self.model)
|
||||||
self._nextID = NoteID(timestampID(self.col.db, "notes"))
|
self._nextID = NoteId(timestampID(self.col.db, "notes"))
|
||||||
# loop through the notes
|
# loop through the notes
|
||||||
updates: List[Updates] = []
|
updates: List[Updates] = []
|
||||||
updateLog = []
|
updateLog = []
|
||||||
new = []
|
new = []
|
||||||
self._ids: List[NoteID] = []
|
self._ids: List[NoteId] = []
|
||||||
self._cards: List[Tuple] = []
|
self._cards: List[Tuple] = []
|
||||||
dupeCount = 0
|
dupeCount = 0
|
||||||
dupes: List[str] = []
|
dupes: List[str] = []
|
||||||
|
@ -230,9 +230,9 @@ class NoteImporter(Importer):
|
||||||
|
|
||||||
def newData(
|
def newData(
|
||||||
self, n: ForeignNote
|
self, n: ForeignNote
|
||||||
) -> Tuple[NoteID, str, NoteTypeID, int, int, str, str, str, int, int, str]:
|
) -> Tuple[NoteId, str, NoteTypeId, int, int, str, str, str, int, int, str]:
|
||||||
id = self._nextID
|
id = self._nextID
|
||||||
self._nextID = NoteID(self._nextID + 1)
|
self._nextID = NoteId(self._nextID + 1)
|
||||||
self._ids.append(id)
|
self._ids.append(id)
|
||||||
self.processFields(n)
|
self.processFields(n)
|
||||||
# note id for card updates later
|
# note id for card updates later
|
||||||
|
@ -255,7 +255,7 @@ class NoteImporter(Importer):
|
||||||
def addNew(
|
def addNew(
|
||||||
self,
|
self,
|
||||||
rows: List[
|
rows: List[
|
||||||
Tuple[NoteID, str, NoteTypeID, int, int, str, str, str, int, int, str]
|
Tuple[NoteId, str, NoteTypeId, int, int, str, str, str, int, int, str]
|
||||||
],
|
],
|
||||||
) -> None:
|
) -> None:
|
||||||
self.col.db.executemany(
|
self.col.db.executemany(
|
||||||
|
@ -263,7 +263,7 @@ class NoteImporter(Importer):
|
||||||
)
|
)
|
||||||
|
|
||||||
def updateData(
|
def updateData(
|
||||||
self, n: ForeignNote, id: NoteID, sflds: List[str]
|
self, n: ForeignNote, id: NoteId, sflds: List[str]
|
||||||
) -> Optional[Updates]:
|
) -> Optional[Updates]:
|
||||||
self._ids.append(id)
|
self._ids.append(id)
|
||||||
self.processFields(n, sflds)
|
self.processFields(n, sflds)
|
||||||
|
|
|
@ -17,7 +17,7 @@ import anki
|
||||||
import anki._backend.backend_pb2 as _pb
|
import anki._backend.backend_pb2 as _pb
|
||||||
from anki.consts import *
|
from anki.consts import *
|
||||||
from anki.latex import render_latex, render_latex_returning_errors
|
from anki.latex import render_latex, render_latex_returning_errors
|
||||||
from anki.models import NoteTypeID
|
from anki.models import NoteTypeId
|
||||||
from anki.sound import SoundOrVideoTag
|
from anki.sound import SoundOrVideoTag
|
||||||
from anki.template import av_tags_to_native
|
from anki.template import av_tags_to_native
|
||||||
from anki.utils import intTime
|
from anki.utils import intTime
|
||||||
|
@ -160,7 +160,7 @@ class MediaManager:
|
||||||
##########################################################################
|
##########################################################################
|
||||||
|
|
||||||
def filesInStr(
|
def filesInStr(
|
||||||
self, mid: NoteTypeID, string: str, includeRemote: bool = False
|
self, mid: NoteTypeId, string: str, includeRemote: bool = False
|
||||||
) -> List[str]:
|
) -> List[str]:
|
||||||
l = []
|
l = []
|
||||||
model = self.col.models.get(mid)
|
model = self.col.models.get(mid)
|
||||||
|
|
|
@ -27,15 +27,15 @@ from anki.utils import (
|
||||||
)
|
)
|
||||||
|
|
||||||
# public exports
|
# public exports
|
||||||
NoteTypeNameID = _pb.NoteTypeNameID
|
NoteTypeNameId = _pb.NoteTypeNameId
|
||||||
NoteTypeNameIDUseCount = _pb.NoteTypeNameIDUseCount
|
NoteTypeNameIdUseCount = _pb.NoteTypeNameIdUseCount
|
||||||
|
|
||||||
|
|
||||||
# types
|
# types
|
||||||
NoteType = Dict[str, Any]
|
NoteType = Dict[str, Any]
|
||||||
Field = Dict[str, Any]
|
Field = Dict[str, Any]
|
||||||
Template = Dict[str, Union[str, int, None]]
|
Template = Dict[str, Union[str, int, None]]
|
||||||
NoteTypeID = NewType("NoteTypeID", int)
|
NoteTypeId = NewType("NoteTypeId", int)
|
||||||
|
|
||||||
|
|
||||||
class ModelsDictProxy:
|
class ModelsDictProxy:
|
||||||
|
@ -48,7 +48,7 @@ class ModelsDictProxy:
|
||||||
|
|
||||||
def __getitem__(self, item: Any) -> Any:
|
def __getitem__(self, item: Any) -> Any:
|
||||||
self._warn()
|
self._warn()
|
||||||
return self._col.models.get(NoteTypeID(int(item)))
|
return self._col.models.get(NoteTypeId(int(item)))
|
||||||
|
|
||||||
def __setitem__(self, key: str, val: Any) -> None:
|
def __setitem__(self, key: str, val: Any) -> None:
|
||||||
self._warn()
|
self._warn()
|
||||||
|
@ -115,16 +115,16 @@ class ModelManager:
|
||||||
# need to cache responses from the backend. Please do not
|
# need to cache responses from the backend. Please do not
|
||||||
# access the cache directly!
|
# access the cache directly!
|
||||||
|
|
||||||
_cache: Dict[NoteTypeID, NoteType] = {}
|
_cache: Dict[NoteTypeId, NoteType] = {}
|
||||||
|
|
||||||
def _update_cache(self, nt: NoteType) -> None:
|
def _update_cache(self, nt: NoteType) -> None:
|
||||||
self._cache[nt["id"]] = nt
|
self._cache[nt["id"]] = nt
|
||||||
|
|
||||||
def _remove_from_cache(self, ntid: NoteTypeID) -> None:
|
def _remove_from_cache(self, ntid: NoteTypeId) -> None:
|
||||||
if ntid in self._cache:
|
if ntid in self._cache:
|
||||||
del self._cache[ntid]
|
del self._cache[ntid]
|
||||||
|
|
||||||
def _get_cached(self, ntid: NoteTypeID) -> Optional[NoteType]:
|
def _get_cached(self, ntid: NoteTypeId) -> Optional[NoteType]:
|
||||||
return self._cache.get(ntid)
|
return self._cache.get(ntid)
|
||||||
|
|
||||||
def _clear_cache(self) -> None:
|
def _clear_cache(self) -> None:
|
||||||
|
@ -133,10 +133,10 @@ class ModelManager:
|
||||||
# Listing note types
|
# Listing note types
|
||||||
#############################################################
|
#############################################################
|
||||||
|
|
||||||
def all_names_and_ids(self) -> Sequence[NoteTypeNameID]:
|
def all_names_and_ids(self) -> Sequence[NoteTypeNameId]:
|
||||||
return self.col._backend.get_notetype_names()
|
return self.col._backend.get_notetype_names()
|
||||||
|
|
||||||
def all_use_counts(self) -> Sequence[NoteTypeNameIDUseCount]:
|
def all_use_counts(self) -> Sequence[NoteTypeNameIdUseCount]:
|
||||||
return self.col._backend.get_notetype_names_and_counts()
|
return self.col._backend.get_notetype_names_and_counts()
|
||||||
|
|
||||||
# legacy
|
# legacy
|
||||||
|
@ -144,11 +144,11 @@ class ModelManager:
|
||||||
def allNames(self) -> List[str]:
|
def allNames(self) -> List[str]:
|
||||||
return [n.name for n in self.all_names_and_ids()]
|
return [n.name for n in self.all_names_and_ids()]
|
||||||
|
|
||||||
def ids(self) -> List[NoteTypeID]:
|
def ids(self) -> List[NoteTypeId]:
|
||||||
return [NoteTypeID(n.id) for n in self.all_names_and_ids()]
|
return [NoteTypeId(n.id) for n in self.all_names_and_ids()]
|
||||||
|
|
||||||
# only used by importing code
|
# only used by importing code
|
||||||
def have(self, id: NoteTypeID) -> bool:
|
def have(self, id: NoteTypeId) -> bool:
|
||||||
if isinstance(id, str):
|
if isinstance(id, str):
|
||||||
id = int(id)
|
id = int(id)
|
||||||
return any(True for e in self.all_names_and_ids() if e.id == id)
|
return any(True for e in self.all_names_and_ids() if e.id == id)
|
||||||
|
@ -163,7 +163,7 @@ class ModelManager:
|
||||||
m = self.get(self.col.conf["curModel"])
|
m = self.get(self.col.conf["curModel"])
|
||||||
if m:
|
if m:
|
||||||
return m
|
return m
|
||||||
return self.get(NoteTypeID(self.all_names_and_ids()[0].id))
|
return self.get(NoteTypeId(self.all_names_and_ids()[0].id))
|
||||||
|
|
||||||
def setCurrent(self, m: NoteType) -> None:
|
def setCurrent(self, m: NoteType) -> None:
|
||||||
self.col.conf["curModel"] = m["id"]
|
self.col.conf["curModel"] = m["id"]
|
||||||
|
@ -171,13 +171,13 @@ class ModelManager:
|
||||||
# Retrieving and creating models
|
# Retrieving and creating models
|
||||||
#############################################################
|
#############################################################
|
||||||
|
|
||||||
def id_for_name(self, name: str) -> Optional[NoteTypeID]:
|
def id_for_name(self, name: str) -> Optional[NoteTypeId]:
|
||||||
try:
|
try:
|
||||||
return NoteTypeID(self.col._backend.get_notetype_id_by_name(name))
|
return NoteTypeId(self.col._backend.get_notetype_id_by_name(name))
|
||||||
except NotFoundError:
|
except NotFoundError:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def get(self, id: NoteTypeID) -> Optional[NoteType]:
|
def get(self, id: NoteTypeId) -> Optional[NoteType]:
|
||||||
"Get model with ID, or None."
|
"Get model with ID, or None."
|
||||||
# deal with various legacy input types
|
# deal with various legacy input types
|
||||||
if id is None:
|
if id is None:
|
||||||
|
@ -196,7 +196,7 @@ class ModelManager:
|
||||||
|
|
||||||
def all(self) -> List[NoteType]:
|
def all(self) -> List[NoteType]:
|
||||||
"Get all models."
|
"Get all models."
|
||||||
return [self.get(NoteTypeID(nt.id)) for nt in self.all_names_and_ids()]
|
return [self.get(NoteTypeId(nt.id)) for nt in self.all_names_and_ids()]
|
||||||
|
|
||||||
def byName(self, name: str) -> Optional[NoteType]:
|
def byName(self, name: str) -> Optional[NoteType]:
|
||||||
"Get model with NAME."
|
"Get model with NAME."
|
||||||
|
@ -223,10 +223,10 @@ class ModelManager:
|
||||||
|
|
||||||
def remove_all_notetypes(self) -> None:
|
def remove_all_notetypes(self) -> None:
|
||||||
for nt in self.all_names_and_ids():
|
for nt in self.all_names_and_ids():
|
||||||
self._remove_from_cache(NoteTypeID(nt.id))
|
self._remove_from_cache(NoteTypeId(nt.id))
|
||||||
self.col._backend.remove_notetype(nt.id)
|
self.col._backend.remove_notetype(nt.id)
|
||||||
|
|
||||||
def remove(self, id: NoteTypeID) -> None:
|
def remove(self, id: NoteTypeId) -> None:
|
||||||
"Modifies schema."
|
"Modifies schema."
|
||||||
self._remove_from_cache(id)
|
self._remove_from_cache(id)
|
||||||
self.col._backend.remove_notetype(id)
|
self.col._backend.remove_notetype(id)
|
||||||
|
@ -258,7 +258,7 @@ class ModelManager:
|
||||||
# Tools
|
# Tools
|
||||||
##################################################
|
##################################################
|
||||||
|
|
||||||
def nids(self, ntid: NoteTypeID) -> List[anki.notes.NoteID]:
|
def nids(self, ntid: NoteTypeId) -> List[anki.notes.NoteId]:
|
||||||
"Note ids for M."
|
"Note ids for M."
|
||||||
if isinstance(ntid, dict):
|
if isinstance(ntid, dict):
|
||||||
# legacy callers passed in note type
|
# legacy callers passed in note type
|
||||||
|
@ -404,7 +404,7 @@ class ModelManager:
|
||||||
self.reposition_template(m, template, idx)
|
self.reposition_template(m, template, idx)
|
||||||
self.save(m)
|
self.save(m)
|
||||||
|
|
||||||
def template_use_count(self, ntid: NoteTypeID, ord: int) -> int:
|
def template_use_count(self, ntid: NoteTypeId, ord: int) -> int:
|
||||||
return self.col.db.scalar(
|
return self.col.db.scalar(
|
||||||
"""
|
"""
|
||||||
select count() from cards, notes where cards.nid = notes.id
|
select count() from cards, notes where cards.nid = notes.id
|
||||||
|
@ -421,7 +421,7 @@ and notes.mid = ? and cards.ord = ?""",
|
||||||
def change(
|
def change(
|
||||||
self,
|
self,
|
||||||
m: NoteType,
|
m: NoteType,
|
||||||
nids: List[anki.notes.NoteID],
|
nids: List[anki.notes.NoteId],
|
||||||
newModel: NoteType,
|
newModel: NoteType,
|
||||||
fmap: Optional[Dict[int, Union[None, int]]],
|
fmap: Optional[Dict[int, Union[None, int]]],
|
||||||
cmap: Optional[Dict[int, Union[None, int]]],
|
cmap: Optional[Dict[int, Union[None, int]]],
|
||||||
|
@ -436,7 +436,7 @@ and notes.mid = ? and cards.ord = ?""",
|
||||||
|
|
||||||
def _changeNotes(
|
def _changeNotes(
|
||||||
self,
|
self,
|
||||||
nids: List[anki.notes.NoteID],
|
nids: List[anki.notes.NoteId],
|
||||||
newModel: NoteType,
|
newModel: NoteType,
|
||||||
map: Dict[int, Union[None, int]],
|
map: Dict[int, Union[None, int]],
|
||||||
) -> None:
|
) -> None:
|
||||||
|
@ -468,7 +468,7 @@ and notes.mid = ? and cards.ord = ?""",
|
||||||
|
|
||||||
def _changeCards(
|
def _changeCards(
|
||||||
self,
|
self,
|
||||||
nids: List[anki.notes.NoteID],
|
nids: List[anki.notes.NoteId],
|
||||||
oldModel: NoteType,
|
oldModel: NoteType,
|
||||||
newModel: NoteType,
|
newModel: NoteType,
|
||||||
map: Dict[int, Union[None, int]],
|
map: Dict[int, Union[None, int]],
|
||||||
|
|
|
@ -11,27 +11,27 @@ import anki # pylint: disable=unused-import
|
||||||
import anki._backend.backend_pb2 as _pb
|
import anki._backend.backend_pb2 as _pb
|
||||||
from anki import hooks
|
from anki import hooks
|
||||||
from anki.consts import MODEL_STD
|
from anki.consts import MODEL_STD
|
||||||
from anki.models import NoteType, NoteTypeID, Template
|
from anki.models import NoteType, NoteTypeId, Template
|
||||||
from anki.utils import joinFields
|
from anki.utils import joinFields
|
||||||
|
|
||||||
DuplicateOrEmptyResult = _pb.NoteIsDuplicateOrEmptyOut.State
|
DuplicateOrEmptyResult = _pb.NoteIsDuplicateOrEmptyOut.State
|
||||||
|
|
||||||
# types
|
# types
|
||||||
NoteID = NewType("NoteID", int)
|
NoteId = NewType("NoteId", int)
|
||||||
|
|
||||||
|
|
||||||
class Note:
|
class Note:
|
||||||
# not currently exposed
|
# not currently exposed
|
||||||
flags = 0
|
flags = 0
|
||||||
data = ""
|
data = ""
|
||||||
id: NoteID
|
id: NoteId
|
||||||
mid: NoteTypeID
|
mid: NoteTypeId
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
col: anki.collection.Collection,
|
col: anki.collection.Collection,
|
||||||
model: Optional[NoteType] = None,
|
model: Optional[NoteType] = None,
|
||||||
id: Optional[NoteID] = None,
|
id: Optional[NoteId] = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
assert not (model and id)
|
assert not (model and id)
|
||||||
self.col = col.weakref()
|
self.col = col.weakref()
|
||||||
|
@ -51,9 +51,9 @@ class Note:
|
||||||
self._load_from_backend_note(n)
|
self._load_from_backend_note(n)
|
||||||
|
|
||||||
def _load_from_backend_note(self, n: _pb.Note) -> None:
|
def _load_from_backend_note(self, n: _pb.Note) -> None:
|
||||||
self.id = NoteID(n.id)
|
self.id = NoteId(n.id)
|
||||||
self.guid = n.guid
|
self.guid = n.guid
|
||||||
self.mid = NoteTypeID(n.notetype_id)
|
self.mid = NoteTypeId(n.notetype_id)
|
||||||
self.mod = n.mtime_secs
|
self.mod = n.mtime_secs
|
||||||
self.usn = n.usn
|
self.usn = n.usn
|
||||||
self.tags = list(n.tags)
|
self.tags = list(n.tags)
|
||||||
|
@ -124,7 +124,7 @@ class Note:
|
||||||
def cards(self) -> List[anki.cards.Card]:
|
def cards(self) -> List[anki.cards.Card]:
|
||||||
return [self.col.getCard(id) for id in self.card_ids()]
|
return [self.col.getCard(id) for id in self.card_ids()]
|
||||||
|
|
||||||
def card_ids(self) -> Sequence[anki.cards.CardID]:
|
def card_ids(self) -> Sequence[anki.cards.CardId]:
|
||||||
return self.col.card_ids_of_note(self.id)
|
return self.col.card_ids_of_note(self.id)
|
||||||
|
|
||||||
def model(self) -> Optional[NoteType]:
|
def model(self) -> Optional[NoteType]:
|
||||||
|
|
|
@ -5,7 +5,7 @@ from __future__ import annotations
|
||||||
|
|
||||||
import anki
|
import anki
|
||||||
import anki._backend.backend_pb2 as _pb
|
import anki._backend.backend_pb2 as _pb
|
||||||
from anki.collection import OpChanges, OpChangesWithCount, OpChangesWithID
|
from anki.collection import OpChanges, OpChangesWithCount, OpChangesWithId
|
||||||
from anki.config import Config
|
from anki.config import Config
|
||||||
|
|
||||||
SchedTimingToday = _pb.SchedTimingTodayOut
|
SchedTimingToday = _pb.SchedTimingTodayOut
|
||||||
|
@ -13,9 +13,9 @@ SchedTimingToday = _pb.SchedTimingTodayOut
|
||||||
|
|
||||||
from typing import List, Optional, Sequence
|
from typing import List, Optional, Sequence
|
||||||
|
|
||||||
from anki.cards import CardID
|
from anki.cards import CardId
|
||||||
from anki.consts import CARD_TYPE_NEW, NEW_CARDS_RANDOM, QUEUE_TYPE_NEW, QUEUE_TYPE_REV
|
from anki.consts import CARD_TYPE_NEW, NEW_CARDS_RANDOM, QUEUE_TYPE_NEW, QUEUE_TYPE_REV
|
||||||
from anki.decks import DeckConfigDict, DeckID, DeckTreeNode
|
from anki.decks import DeckConfigDict, DeckId, DeckTreeNode
|
||||||
from anki.notes import Note
|
from anki.notes import Note
|
||||||
from anki.utils import ids2str, intTime
|
from anki.utils import ids2str, intTime
|
||||||
|
|
||||||
|
@ -91,27 +91,27 @@ select id from cards where did in %s and queue = {QUEUE_TYPE_REV} and due <= ? l
|
||||||
# Filtered deck handling
|
# Filtered deck handling
|
||||||
##########################################################################
|
##########################################################################
|
||||||
|
|
||||||
def rebuild_filtered_deck(self, deck_id: DeckID) -> OpChangesWithCount:
|
def rebuild_filtered_deck(self, deck_id: DeckId) -> OpChangesWithCount:
|
||||||
return self.col._backend.rebuild_filtered_deck(deck_id)
|
return self.col._backend.rebuild_filtered_deck(deck_id)
|
||||||
|
|
||||||
def empty_filtered_deck(self, deck_id: DeckID) -> OpChanges:
|
def empty_filtered_deck(self, deck_id: DeckId) -> OpChanges:
|
||||||
return self.col._backend.empty_filtered_deck(deck_id)
|
return self.col._backend.empty_filtered_deck(deck_id)
|
||||||
|
|
||||||
def get_or_create_filtered_deck(self, deck_id: DeckID) -> FilteredDeckForUpdate:
|
def get_or_create_filtered_deck(self, deck_id: DeckId) -> FilteredDeckForUpdate:
|
||||||
return self.col._backend.get_or_create_filtered_deck(deck_id)
|
return self.col._backend.get_or_create_filtered_deck(deck_id)
|
||||||
|
|
||||||
def add_or_update_filtered_deck(
|
def add_or_update_filtered_deck(
|
||||||
self, deck: FilteredDeckForUpdate
|
self, deck: FilteredDeckForUpdate
|
||||||
) -> OpChangesWithID:
|
) -> OpChangesWithId:
|
||||||
return self.col._backend.add_or_update_filtered_deck(deck)
|
return self.col._backend.add_or_update_filtered_deck(deck)
|
||||||
|
|
||||||
# Suspending & burying
|
# Suspending & burying
|
||||||
##########################################################################
|
##########################################################################
|
||||||
|
|
||||||
def unsuspend_cards(self, ids: Sequence[CardID]) -> OpChanges:
|
def unsuspend_cards(self, ids: Sequence[CardId]) -> OpChanges:
|
||||||
return self.col._backend.restore_buried_and_suspended_cards(ids)
|
return self.col._backend.restore_buried_and_suspended_cards(ids)
|
||||||
|
|
||||||
def unbury_cards(self, ids: List[CardID]) -> OpChanges:
|
def unbury_cards(self, ids: List[CardId]) -> OpChanges:
|
||||||
return self.col._backend.restore_buried_and_suspended_cards(ids)
|
return self.col._backend.restore_buried_and_suspended_cards(ids)
|
||||||
|
|
||||||
def unbury_cards_in_current_deck(
|
def unbury_cards_in_current_deck(
|
||||||
|
@ -120,12 +120,12 @@ select id from cards where did in %s and queue = {QUEUE_TYPE_REV} and due <= ? l
|
||||||
) -> None:
|
) -> None:
|
||||||
self.col._backend.unbury_cards_in_current_deck(mode)
|
self.col._backend.unbury_cards_in_current_deck(mode)
|
||||||
|
|
||||||
def suspend_cards(self, ids: Sequence[CardID]) -> OpChanges:
|
def suspend_cards(self, ids: Sequence[CardId]) -> OpChanges:
|
||||||
return self.col._backend.bury_or_suspend_cards(
|
return self.col._backend.bury_or_suspend_cards(
|
||||||
card_ids=ids, mode=BuryOrSuspend.SUSPEND
|
card_ids=ids, mode=BuryOrSuspend.SUSPEND
|
||||||
)
|
)
|
||||||
|
|
||||||
def bury_cards(self, ids: Sequence[CardID], manual: bool = True) -> OpChanges:
|
def bury_cards(self, ids: Sequence[CardId], manual: bool = True) -> OpChanges:
|
||||||
if manual:
|
if manual:
|
||||||
mode = BuryOrSuspend.BURY_USER
|
mode = BuryOrSuspend.BURY_USER
|
||||||
else:
|
else:
|
||||||
|
@ -138,13 +138,13 @@ select id from cards where did in %s and queue = {QUEUE_TYPE_REV} and due <= ? l
|
||||||
# Resetting/rescheduling
|
# Resetting/rescheduling
|
||||||
##########################################################################
|
##########################################################################
|
||||||
|
|
||||||
def schedule_cards_as_new(self, card_ids: List[CardID]) -> OpChanges:
|
def schedule_cards_as_new(self, card_ids: List[CardId]) -> OpChanges:
|
||||||
"Put cards at the end of the new queue."
|
"Put cards at the end of the new queue."
|
||||||
return self.col._backend.schedule_cards_as_new(card_ids=card_ids, log=True)
|
return self.col._backend.schedule_cards_as_new(card_ids=card_ids, log=True)
|
||||||
|
|
||||||
def set_due_date(
|
def set_due_date(
|
||||||
self,
|
self,
|
||||||
card_ids: List[CardID],
|
card_ids: List[CardId],
|
||||||
days: str,
|
days: str,
|
||||||
config_key: Optional[Config.String.Key.V] = None,
|
config_key: Optional[Config.String.Key.V] = None,
|
||||||
) -> OpChanges:
|
) -> OpChanges:
|
||||||
|
@ -163,7 +163,7 @@ select id from cards where did in %s and queue = {QUEUE_TYPE_REV} and due <= ? l
|
||||||
config_key=key, # type: ignore
|
config_key=key, # type: ignore
|
||||||
)
|
)
|
||||||
|
|
||||||
def resetCards(self, ids: List[CardID]) -> None:
|
def resetCards(self, ids: List[CardId]) -> None:
|
||||||
"Completely reset cards for export."
|
"Completely reset cards for export."
|
||||||
sids = ids2str(ids)
|
sids = ids2str(ids)
|
||||||
assert self.col.db
|
assert self.col.db
|
||||||
|
@ -185,7 +185,7 @@ select id from cards where did in %s and queue = {QUEUE_TYPE_REV} and due <= ? l
|
||||||
|
|
||||||
def reposition_new_cards(
|
def reposition_new_cards(
|
||||||
self,
|
self,
|
||||||
card_ids: Sequence[CardID],
|
card_ids: Sequence[CardId],
|
||||||
starting_from: int,
|
starting_from: int,
|
||||||
step_size: int,
|
step_size: int,
|
||||||
randomize: bool,
|
randomize: bool,
|
||||||
|
@ -199,10 +199,10 @@ select id from cards where did in %s and queue = {QUEUE_TYPE_REV} and due <= ? l
|
||||||
shift_existing=shift_existing,
|
shift_existing=shift_existing,
|
||||||
)
|
)
|
||||||
|
|
||||||
def randomizeCards(self, did: DeckID) -> None:
|
def randomizeCards(self, did: DeckId) -> None:
|
||||||
self.col._backend.sort_deck(deck_id=did, randomize=True)
|
self.col._backend.sort_deck(deck_id=did, randomize=True)
|
||||||
|
|
||||||
def orderCards(self, did: DeckID) -> None:
|
def orderCards(self, did: DeckId) -> None:
|
||||||
self.col._backend.sort_deck(deck_id=did, randomize=False)
|
self.col._backend.sort_deck(deck_id=did, randomize=False)
|
||||||
|
|
||||||
def resortConf(self, conf: DeckConfigDict) -> None:
|
def resortConf(self, conf: DeckConfigDict) -> None:
|
||||||
|
@ -213,7 +213,7 @@ select id from cards where did in %s and queue = {QUEUE_TYPE_REV} and due <= ? l
|
||||||
self.orderCards(did)
|
self.orderCards(did)
|
||||||
|
|
||||||
# for post-import
|
# for post-import
|
||||||
def maybeRandomizeDeck(self, did: Optional[DeckID] = None) -> None:
|
def maybeRandomizeDeck(self, did: Optional[DeckId] = None) -> None:
|
||||||
if not did:
|
if not did:
|
||||||
did = self.col.decks.selected()
|
did = self.col.decks.selected()
|
||||||
conf = self.col.decks.confForDid(did)
|
conf = self.col.decks.confForDid(did)
|
||||||
|
@ -224,7 +224,7 @@ select id from cards where did in %s and queue = {QUEUE_TYPE_REV} and due <= ? l
|
||||||
# legacy
|
# legacy
|
||||||
def sortCards(
|
def sortCards(
|
||||||
self,
|
self,
|
||||||
cids: List[CardID],
|
cids: List[CardId],
|
||||||
start: int = 1,
|
start: int = 1,
|
||||||
step: int = 1,
|
step: int = 1,
|
||||||
shuffle: bool = False,
|
shuffle: bool = False,
|
||||||
|
|
|
@ -3,10 +3,10 @@
|
||||||
|
|
||||||
from typing import List, Optional, Tuple
|
from typing import List, Optional, Tuple
|
||||||
|
|
||||||
from anki.cards import Card, CardID
|
from anki.cards import Card, CardId
|
||||||
from anki.consts import CARD_TYPE_RELEARNING, QUEUE_TYPE_DAY_LEARN_RELEARN
|
from anki.consts import CARD_TYPE_RELEARNING, QUEUE_TYPE_DAY_LEARN_RELEARN
|
||||||
from anki.decks import DeckConfigDict, DeckID
|
from anki.decks import DeckConfigDict, DeckId
|
||||||
from anki.notes import NoteID
|
from anki.notes import NoteId
|
||||||
from anki.scheduler.base import SchedulerBase, UnburyCurrentDeck
|
from anki.scheduler.base import SchedulerBase, UnburyCurrentDeck
|
||||||
from anki.utils import from_json_bytes, ids2str
|
from anki.utils import from_json_bytes, ids2str
|
||||||
|
|
||||||
|
@ -15,11 +15,11 @@ class SchedulerBaseWithLegacy(SchedulerBase):
|
||||||
"Legacy aliases and helpers. These will go away in the future."
|
"Legacy aliases and helpers. These will go away in the future."
|
||||||
|
|
||||||
def reschedCards(
|
def reschedCards(
|
||||||
self, card_ids: List[CardID], min_interval: int, max_interval: int
|
self, card_ids: List[CardId], min_interval: int, max_interval: int
|
||||||
) -> None:
|
) -> None:
|
||||||
self.set_due_date(card_ids, f"{min_interval}-{max_interval}!")
|
self.set_due_date(card_ids, f"{min_interval}-{max_interval}!")
|
||||||
|
|
||||||
def buryNote(self, nid: NoteID) -> None:
|
def buryNote(self, nid: NoteId) -> None:
|
||||||
note = self.col.get_note(nid)
|
note = self.col.get_note(nid)
|
||||||
self.bury_cards(note.card_ids())
|
self.bury_cards(note.card_ids())
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ class SchedulerBaseWithLegacy(SchedulerBase):
|
||||||
print("_nextDueMsg() is obsolete")
|
print("_nextDueMsg() is obsolete")
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
def rebuildDyn(self, did: Optional[DeckID] = None) -> Optional[int]:
|
def rebuildDyn(self, did: Optional[DeckId] = None) -> Optional[int]:
|
||||||
did = did or self.col.decks.selected()
|
did = did or self.col.decks.selected()
|
||||||
count = self.rebuild_filtered_deck(did).count or None
|
count = self.rebuild_filtered_deck(did).count or None
|
||||||
if not count:
|
if not count:
|
||||||
|
@ -58,7 +58,7 @@ class SchedulerBaseWithLegacy(SchedulerBase):
|
||||||
self.col.decks.select(did)
|
self.col.decks.select(did)
|
||||||
return count
|
return count
|
||||||
|
|
||||||
def emptyDyn(self, did: Optional[DeckID], lim: Optional[str] = None) -> None:
|
def emptyDyn(self, did: Optional[DeckId], lim: Optional[str] = None) -> None:
|
||||||
if lim is None:
|
if lim is None:
|
||||||
self.empty_filtered_deck(did)
|
self.empty_filtered_deck(did)
|
||||||
return
|
return
|
||||||
|
@ -80,13 +80,13 @@ due = (case when odue>0 then odue else due end), odue = 0, odid = 0, usn = ? whe
|
||||||
self.col.usn(),
|
self.col.usn(),
|
||||||
)
|
)
|
||||||
|
|
||||||
def remFromDyn(self, cids: List[CardID]) -> None:
|
def remFromDyn(self, cids: List[CardId]) -> None:
|
||||||
self.emptyDyn(None, f"id in {ids2str(cids)} and odid")
|
self.emptyDyn(None, f"id in {ids2str(cids)} and odid")
|
||||||
|
|
||||||
# used by v2 scheduler and some add-ons
|
# used by v2 scheduler and some add-ons
|
||||||
def update_stats(
|
def update_stats(
|
||||||
self,
|
self,
|
||||||
deck_id: DeckID,
|
deck_id: DeckId,
|
||||||
new_delta: int = 0,
|
new_delta: int = 0,
|
||||||
review_delta: int = 0,
|
review_delta: int = 0,
|
||||||
milliseconds_delta: int = 0,
|
milliseconds_delta: int = 0,
|
||||||
|
|
|
@ -12,7 +12,7 @@ import anki
|
||||||
from anki import hooks
|
from anki import hooks
|
||||||
from anki.cards import Card
|
from anki.cards import Card
|
||||||
from anki.consts import *
|
from anki.consts import *
|
||||||
from anki.decks import DeckID
|
from anki.decks import DeckId
|
||||||
from anki.utils import ids2str, intTime
|
from anki.utils import ids2str, intTime
|
||||||
|
|
||||||
from .v2 import QueueConfig
|
from .v2 import QueueConfig
|
||||||
|
@ -300,7 +300,7 @@ limit %d"""
|
||||||
if card.odid:
|
if card.odid:
|
||||||
card.did = card.odid
|
card.did = card.odid
|
||||||
card.odue = 0
|
card.odue = 0
|
||||||
card.odid = DeckID(0)
|
card.odid = DeckId(0)
|
||||||
# if rescheduling is off, it needs to be set back to a new card
|
# if rescheduling is off, it needs to be set back to a new card
|
||||||
if not resched and not lapse:
|
if not resched and not lapse:
|
||||||
card.queue = QUEUE_TYPE_NEW
|
card.queue = QUEUE_TYPE_NEW
|
||||||
|
@ -403,7 +403,7 @@ where queue in ({QUEUE_TYPE_LRN},{QUEUE_TYPE_DAY_LEARN_RELEARN}) and type = {CAR
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
def _lrnForDeck(self, did: DeckID) -> int:
|
def _lrnForDeck(self, did: DeckId) -> int:
|
||||||
cnt = (
|
cnt = (
|
||||||
self.col.db.scalar(
|
self.col.db.scalar(
|
||||||
f"""
|
f"""
|
||||||
|
@ -428,7 +428,7 @@ and due <= ? limit ?)""",
|
||||||
# Reviews
|
# Reviews
|
||||||
##########################################################################
|
##########################################################################
|
||||||
|
|
||||||
def _deckRevLimit(self, did: DeckID) -> int:
|
def _deckRevLimit(self, did: DeckId) -> int:
|
||||||
return self._deckNewLimit(did, self._deckRevLimitSingle)
|
return self._deckNewLimit(did, self._deckRevLimitSingle)
|
||||||
|
|
||||||
def _resetRev(self) -> None:
|
def _resetRev(self) -> None:
|
||||||
|
@ -543,7 +543,7 @@ did = ? and queue = {QUEUE_TYPE_REV} and due <= ? limit ?""",
|
||||||
card.due = card.odue
|
card.due = card.odue
|
||||||
if card.odid:
|
if card.odid:
|
||||||
card.did = card.odid
|
card.did = card.odid
|
||||||
card.odid = DeckID(0)
|
card.odid = DeckId(0)
|
||||||
card.odue = 0
|
card.odue = 0
|
||||||
|
|
||||||
# Interval management
|
# Interval management
|
||||||
|
@ -620,7 +620,7 @@ did = ? and queue = {QUEUE_TYPE_REV} and due <= ? limit ?""",
|
||||||
if card.odid:
|
if card.odid:
|
||||||
card.did = card.odid
|
card.did = card.odid
|
||||||
card.odue = 0
|
card.odue = 0
|
||||||
card.odid = DeckID(0)
|
card.odid = DeckId(0)
|
||||||
card.queue = QUEUE_TYPE_SUSPENDED
|
card.queue = QUEUE_TYPE_SUSPENDED
|
||||||
# notify UI
|
# notify UI
|
||||||
hooks.card_did_leech(card)
|
hooks.card_did_leech(card)
|
||||||
|
|
|
@ -11,9 +11,9 @@ from typing import Any, Callable, Dict, List, Optional, Tuple, Union
|
||||||
import anki # pylint: disable=unused-import
|
import anki # pylint: disable=unused-import
|
||||||
import anki._backend.backend_pb2 as _pb
|
import anki._backend.backend_pb2 as _pb
|
||||||
from anki import hooks
|
from anki import hooks
|
||||||
from anki.cards import Card, CardID
|
from anki.cards import Card, CardId
|
||||||
from anki.consts import *
|
from anki.consts import *
|
||||||
from anki.decks import DeckConfigDict, DeckDict, DeckID
|
from anki.decks import DeckConfigDict, DeckDict, DeckId
|
||||||
from anki.lang import FormatTimeSpan
|
from anki.lang import FormatTimeSpan
|
||||||
from anki.scheduler.legacy import SchedulerBaseWithLegacy
|
from anki.scheduler.legacy import SchedulerBaseWithLegacy
|
||||||
from anki.utils import ids2str, intTime
|
from anki.utils import ids2str, intTime
|
||||||
|
@ -76,7 +76,7 @@ class Scheduler(SchedulerBaseWithLegacy):
|
||||||
def _reset_counts(self) -> None:
|
def _reset_counts(self) -> None:
|
||||||
tree = self.deck_due_tree(self.col.decks.selected())
|
tree = self.deck_due_tree(self.col.decks.selected())
|
||||||
node = self.col.decks.find_deck_in_tree(
|
node = self.col.decks.find_deck_in_tree(
|
||||||
tree, DeckID(int(self.col.conf["curDeck"]))
|
tree, DeckId(int(self.col.conf["curDeck"]))
|
||||||
)
|
)
|
||||||
if not node:
|
if not node:
|
||||||
# current deck points to a missing deck
|
# current deck points to a missing deck
|
||||||
|
@ -146,7 +146,7 @@ class Scheduler(SchedulerBaseWithLegacy):
|
||||||
|
|
||||||
def _resetNew(self) -> None:
|
def _resetNew(self) -> None:
|
||||||
self._newDids = self.col.decks.active()[:]
|
self._newDids = self.col.decks.active()[:]
|
||||||
self._newQueue: List[CardID] = []
|
self._newQueue: List[CardId] = []
|
||||||
self._updateNewCardRatio()
|
self._updateNewCardRatio()
|
||||||
|
|
||||||
def _fillNew(self, recursing: bool = False) -> bool:
|
def _fillNew(self, recursing: bool = False) -> bool:
|
||||||
|
@ -212,7 +212,7 @@ class Scheduler(SchedulerBaseWithLegacy):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def _deckNewLimit(
|
def _deckNewLimit(
|
||||||
self, did: DeckID, fn: Optional[Callable[[DeckDict], int]] = None
|
self, did: DeckId, fn: Optional[Callable[[DeckDict], int]] = None
|
||||||
) -> int:
|
) -> int:
|
||||||
if not fn:
|
if not fn:
|
||||||
fn = self._deckNewLimitSingle
|
fn = self._deckNewLimitSingle
|
||||||
|
@ -227,7 +227,7 @@ class Scheduler(SchedulerBaseWithLegacy):
|
||||||
lim = min(rem, lim)
|
lim = min(rem, lim)
|
||||||
return lim
|
return lim
|
||||||
|
|
||||||
def _newForDeck(self, did: DeckID, lim: int) -> int:
|
def _newForDeck(self, did: DeckId, lim: int) -> int:
|
||||||
"New count for a single deck."
|
"New count for a single deck."
|
||||||
if not lim:
|
if not lim:
|
||||||
return 0
|
return 0
|
||||||
|
@ -303,8 +303,8 @@ select count() from cards where did in %s and queue = {QUEUE_TYPE_PREVIEW}
|
||||||
def _resetLrn(self) -> None:
|
def _resetLrn(self) -> None:
|
||||||
self._updateLrnCutoff(force=True)
|
self._updateLrnCutoff(force=True)
|
||||||
self._resetLrnCount()
|
self._resetLrnCount()
|
||||||
self._lrnQueue: List[Tuple[int, CardID]] = []
|
self._lrnQueue: List[Tuple[int, CardId]] = []
|
||||||
self._lrnDayQueue: List[CardID] = []
|
self._lrnDayQueue: List[CardId] = []
|
||||||
self._lrnDids = self.col.decks.active()[:]
|
self._lrnDids = self.col.decks.active()[:]
|
||||||
|
|
||||||
# sub-day learning
|
# sub-day learning
|
||||||
|
@ -399,7 +399,7 @@ did = ? and queue = {QUEUE_TYPE_DAY_LEARN_RELEARN} and due <= ? limit ?""",
|
||||||
return hooks.scheduler_review_limit_for_single_deck(lim, d)
|
return hooks.scheduler_review_limit_for_single_deck(lim, d)
|
||||||
|
|
||||||
def _resetRev(self) -> None:
|
def _resetRev(self) -> None:
|
||||||
self._revQueue: List[CardID] = []
|
self._revQueue: List[CardId] = []
|
||||||
|
|
||||||
def _fillRev(self, recursing: bool = False) -> bool:
|
def _fillRev(self, recursing: bool = False) -> bool:
|
||||||
"True if a review card can be fetched."
|
"True if a review card can be fetched."
|
||||||
|
@ -791,7 +791,7 @@ limit ?"""
|
||||||
if card.odid:
|
if card.odid:
|
||||||
card.did = card.odid
|
card.did = card.odid
|
||||||
card.odue = 0
|
card.odue = 0
|
||||||
card.odid = DeckID(0)
|
card.odid = DeckId(0)
|
||||||
|
|
||||||
def _restorePreviewCard(self, card: Card) -> None:
|
def _restorePreviewCard(self, card: Card) -> None:
|
||||||
assert card.odid
|
assert card.odid
|
||||||
|
@ -1075,7 +1075,7 @@ limit ?"""
|
||||||
##########################################################################
|
##########################################################################
|
||||||
|
|
||||||
def _burySiblings(self, card: Card) -> None:
|
def _burySiblings(self, card: Card) -> None:
|
||||||
toBury: List[CardID] = []
|
toBury: List[CardId] = []
|
||||||
nconf = self._newConf(card)
|
nconf = self._newConf(card)
|
||||||
buryNew = nconf.get("bury", True)
|
buryNew = nconf.get("bury", True)
|
||||||
rconf = self._revConf(card)
|
rconf = self._revConf(card)
|
||||||
|
|
|
@ -19,8 +19,8 @@ import anki # pylint: disable=unused-import
|
||||||
import anki._backend.backend_pb2 as _pb
|
import anki._backend.backend_pb2 as _pb
|
||||||
import anki.collection
|
import anki.collection
|
||||||
from anki.collection import OpChangesWithCount
|
from anki.collection import OpChangesWithCount
|
||||||
from anki.decks import DeckID
|
from anki.decks import DeckId
|
||||||
from anki.notes import NoteID
|
from anki.notes import NoteId
|
||||||
from anki.utils import ids2str
|
from anki.utils import ids2str
|
||||||
|
|
||||||
# public exports
|
# public exports
|
||||||
|
@ -50,7 +50,7 @@ class TagManager:
|
||||||
def clear_unused_tags(self) -> OpChangesWithCount:
|
def clear_unused_tags(self) -> OpChangesWithCount:
|
||||||
return self.col._backend.clear_unused_tags()
|
return self.col._backend.clear_unused_tags()
|
||||||
|
|
||||||
def byDeck(self, did: DeckID, children: bool = False) -> List[str]:
|
def byDeck(self, did: DeckId, children: bool = False) -> List[str]:
|
||||||
basequery = "select n.tags from cards c, notes n WHERE c.nid = n.id"
|
basequery = "select n.tags from cards c, notes n WHERE c.nid = n.id"
|
||||||
if not children:
|
if not children:
|
||||||
query = f"{basequery} AND c.did=?"
|
query = f"{basequery} AND c.did=?"
|
||||||
|
@ -70,11 +70,11 @@ class TagManager:
|
||||||
# Bulk addition/removal from specific notes
|
# Bulk addition/removal from specific notes
|
||||||
#############################################################
|
#############################################################
|
||||||
|
|
||||||
def bulk_add(self, note_ids: Sequence[NoteID], tags: str) -> OpChangesWithCount:
|
def bulk_add(self, note_ids: Sequence[NoteId], tags: str) -> OpChangesWithCount:
|
||||||
"""Add space-separate tags to provided notes, returning changed count."""
|
"""Add space-separate tags to provided notes, returning changed count."""
|
||||||
return self.col._backend.add_note_tags(note_ids=note_ids, tags=tags)
|
return self.col._backend.add_note_tags(note_ids=note_ids, tags=tags)
|
||||||
|
|
||||||
def bulk_remove(self, note_ids: Sequence[NoteID], tags: str) -> OpChangesWithCount:
|
def bulk_remove(self, note_ids: Sequence[NoteId], tags: str) -> OpChangesWithCount:
|
||||||
return self.col._backend.remove_note_tags(note_ids=note_ids, tags=tags)
|
return self.col._backend.remove_note_tags(note_ids=note_ids, tags=tags)
|
||||||
|
|
||||||
# Find&replace
|
# Find&replace
|
||||||
|
@ -177,12 +177,12 @@ class TagManager:
|
||||||
) -> None:
|
) -> None:
|
||||||
print("tags.register() is deprecated and no longer works")
|
print("tags.register() is deprecated and no longer works")
|
||||||
|
|
||||||
def bulkAdd(self, ids: List[NoteID], tags: str, add: bool = True) -> None:
|
def bulkAdd(self, ids: List[NoteId], tags: str, add: bool = True) -> None:
|
||||||
"Add tags in bulk. TAGS is space-separated."
|
"Add tags in bulk. TAGS is space-separated."
|
||||||
if add:
|
if add:
|
||||||
self.bulk_add(ids, tags)
|
self.bulk_add(ids, tags)
|
||||||
else:
|
else:
|
||||||
self.bulk_remove(ids, tags)
|
self.bulk_remove(ids, tags)
|
||||||
|
|
||||||
def bulkRem(self, ids: List[NoteID], tags: str) -> None:
|
def bulkRem(self, ids: List[NoteId], tags: str) -> None:
|
||||||
self.bulkAdd(ids, tags, False)
|
self.bulkAdd(ids, tags, False)
|
||||||
|
|
|
@ -23,7 +23,7 @@ hooks = [
|
||||||
Hook(name="schema_will_change", args=["proceed: bool"], return_type="bool"),
|
Hook(name="schema_will_change", args=["proceed: bool"], return_type="bool"),
|
||||||
Hook(
|
Hook(
|
||||||
name="notes_will_be_deleted",
|
name="notes_will_be_deleted",
|
||||||
args=["col: anki.collection.Collection", "ids: Sequence[anki.notes.NoteID]"],
|
args=["col: anki.collection.Collection", "ids: Sequence[anki.notes.NoteId]"],
|
||||||
legacy_hook="remNotes",
|
legacy_hook="remNotes",
|
||||||
),
|
),
|
||||||
Hook(name="media_files_did_export", args=["count: int"]),
|
Hook(name="media_files_did_export", args=["count: int"]),
|
||||||
|
|
|
@ -8,9 +8,9 @@ import aqt.editor
|
||||||
import aqt.forms
|
import aqt.forms
|
||||||
from anki.collection import OpChanges, SearchNode
|
from anki.collection import OpChanges, SearchNode
|
||||||
from anki.consts import MODEL_CLOZE
|
from anki.consts import MODEL_CLOZE
|
||||||
from anki.decks import DeckID
|
from anki.decks import DeckId
|
||||||
from anki.models import NoteTypeID
|
from anki.models import NoteTypeId
|
||||||
from anki.notes import DuplicateOrEmptyResult, Note, NoteID
|
from anki.notes import DuplicateOrEmptyResult, Note, NoteId
|
||||||
from anki.utils import htmlToTextLine, isMac
|
from anki.utils import htmlToTextLine, isMac
|
||||||
from aqt import AnkiQt, gui_hooks
|
from aqt import AnkiQt, gui_hooks
|
||||||
from aqt.note_ops import add_note
|
from aqt.note_ops import add_note
|
||||||
|
@ -48,7 +48,7 @@ class AddCards(QDialog):
|
||||||
self.setupEditor()
|
self.setupEditor()
|
||||||
self.setupButtons()
|
self.setupButtons()
|
||||||
self._load_new_note()
|
self._load_new_note()
|
||||||
self.history: List[NoteID] = []
|
self.history: List[NoteId] = []
|
||||||
self._last_added_note: Optional[Note] = None
|
self._last_added_note: Optional[Note] = None
|
||||||
restoreGeom(self, "add")
|
restoreGeom(self, "add")
|
||||||
addCloseShortcut(self)
|
addCloseShortcut(self)
|
||||||
|
@ -65,12 +65,12 @@ class AddCards(QDialog):
|
||||||
self.notetype_chooser = NoteTypeChooser(
|
self.notetype_chooser = NoteTypeChooser(
|
||||||
mw=self.mw,
|
mw=self.mw,
|
||||||
widget=self.form.modelArea,
|
widget=self.form.modelArea,
|
||||||
starting_notetype_id=NoteTypeID(defaults.notetype_id),
|
starting_notetype_id=NoteTypeId(defaults.notetype_id),
|
||||||
on_button_activated=self.show_notetype_selector,
|
on_button_activated=self.show_notetype_selector,
|
||||||
on_notetype_changed=self.on_notetype_change,
|
on_notetype_changed=self.on_notetype_change,
|
||||||
)
|
)
|
||||||
self.deck_chooser = aqt.deckchooser.DeckChooser(
|
self.deck_chooser = aqt.deckchooser.DeckChooser(
|
||||||
self.mw, self.form.deckArea, starting_deck_id=DeckID(defaults.deck_id)
|
self.mw, self.form.deckArea, starting_deck_id=DeckId(defaults.deck_id)
|
||||||
)
|
)
|
||||||
|
|
||||||
def helpRequested(self) -> None:
|
def helpRequested(self) -> None:
|
||||||
|
@ -110,7 +110,7 @@ class AddCards(QDialog):
|
||||||
def show_notetype_selector(self) -> None:
|
def show_notetype_selector(self) -> None:
|
||||||
self.editor.call_after_note_saved(self.notetype_chooser.choose_notetype)
|
self.editor.call_after_note_saved(self.notetype_chooser.choose_notetype)
|
||||||
|
|
||||||
def on_notetype_change(self, notetype_id: NoteTypeID) -> None:
|
def on_notetype_change(self, notetype_id: NoteTypeId) -> None:
|
||||||
# need to adjust current deck?
|
# need to adjust current deck?
|
||||||
if deck_id := self.mw.col.default_deck_for_notetype(notetype_id):
|
if deck_id := self.mw.col.default_deck_for_notetype(notetype_id):
|
||||||
self.deck_chooser.selected_deck_id = deck_id
|
self.deck_chooser.selected_deck_id = deck_id
|
||||||
|
@ -179,7 +179,7 @@ class AddCards(QDialog):
|
||||||
gui_hooks.add_cards_will_show_history_menu(self, m)
|
gui_hooks.add_cards_will_show_history_menu(self, m)
|
||||||
m.exec_(self.historyButton.mapToGlobal(QPoint(0, 0)))
|
m.exec_(self.historyButton.mapToGlobal(QPoint(0, 0)))
|
||||||
|
|
||||||
def editHistory(self, nid: NoteID) -> None:
|
def editHistory(self, nid: NoteId) -> None:
|
||||||
aqt.dialogs.open("Browser", self.mw, search=(SearchNode(nid=nid),))
|
aqt.dialogs.open("Browser", self.mw, search=(SearchNode(nid=nid),))
|
||||||
|
|
||||||
def add_current_note(self) -> None:
|
def add_current_note(self) -> None:
|
||||||
|
|
|
@ -22,13 +22,13 @@ from typing import (
|
||||||
|
|
||||||
import aqt
|
import aqt
|
||||||
import aqt.forms
|
import aqt.forms
|
||||||
from anki.cards import Card, CardID
|
from anki.cards import Card, CardId
|
||||||
from anki.collection import BrowserRow, Collection, Config, OpChanges, SearchNode
|
from anki.collection import BrowserRow, Collection, Config, OpChanges, SearchNode
|
||||||
from anki.consts import *
|
from anki.consts import *
|
||||||
from anki.errors import NotFoundError
|
from anki.errors import NotFoundError
|
||||||
from anki.lang import without_unicode_isolation
|
from anki.lang import without_unicode_isolation
|
||||||
from anki.models import NoteType
|
from anki.models import NoteType
|
||||||
from anki.notes import NoteID
|
from anki.notes import NoteId
|
||||||
from anki.stats import CardStats
|
from anki.stats import CardStats
|
||||||
from anki.tags import MARKED_TAG
|
from anki.tags import MARKED_TAG
|
||||||
from anki.utils import ids2str, isMac, isWin
|
from anki.utils import ids2str, isMac, isWin
|
||||||
|
@ -96,7 +96,7 @@ class SearchContext:
|
||||||
browser: Browser
|
browser: Browser
|
||||||
order: Union[bool, str] = True
|
order: Union[bool, str] = True
|
||||||
# if set, provided card ids will be used instead of the regular search
|
# if set, provided card ids will be used instead of the regular search
|
||||||
card_ids: Optional[Sequence[CardID]] = None
|
card_ids: Optional[Sequence[CardId]] = None
|
||||||
|
|
||||||
|
|
||||||
# Data model
|
# Data model
|
||||||
|
@ -169,13 +169,13 @@ class DataModel(QAbstractTableModel):
|
||||||
self.activeCols: List[str] = self.col.get_config(
|
self.activeCols: List[str] = self.col.get_config(
|
||||||
"activeCols", ["noteFld", "template", "cardDue", "deck"]
|
"activeCols", ["noteFld", "template", "cardDue", "deck"]
|
||||||
)
|
)
|
||||||
self.cards: Sequence[CardID] = []
|
self.cards: Sequence[CardId] = []
|
||||||
self._rows: Dict[int, CellRow] = {}
|
self._rows: Dict[int, CellRow] = {}
|
||||||
self._last_refresh = 0.0
|
self._last_refresh = 0.0
|
||||||
# serve stale content to avoid hitting the DB?
|
# serve stale content to avoid hitting the DB?
|
||||||
self.block_updates = False
|
self.block_updates = False
|
||||||
|
|
||||||
def get_id(self, index: QModelIndex) -> CardID:
|
def get_id(self, index: QModelIndex) -> CardId:
|
||||||
return self.cards[index.row()]
|
return self.cards[index.row()]
|
||||||
|
|
||||||
def get_cell(self, index: QModelIndex) -> Cell:
|
def get_cell(self, index: QModelIndex) -> Cell:
|
||||||
|
@ -197,7 +197,7 @@ class DataModel(QAbstractTableModel):
|
||||||
self._rows[cid] = self._fetch_row_from_backend(cid)
|
self._rows[cid] = self._fetch_row_from_backend(cid)
|
||||||
return self._rows[cid]
|
return self._rows[cid]
|
||||||
|
|
||||||
def _fetch_row_from_backend(self, cid: CardID) -> CellRow:
|
def _fetch_row_from_backend(self, cid: CardId) -> CellRow:
|
||||||
try:
|
try:
|
||||||
row = CellRow(*self.col.browser_row_for_card(cid))
|
row = CellRow(*self.col.browser_row_for_card(cid))
|
||||||
except NotFoundError:
|
except NotFoundError:
|
||||||
|
@ -1051,13 +1051,13 @@ QTableView {{ gridline-color: {grid} }}
|
||||||
# Menu helpers
|
# Menu helpers
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
||||||
def selected_cards(self) -> List[CardID]:
|
def selected_cards(self) -> List[CardId]:
|
||||||
return [
|
return [
|
||||||
self.model.cards[idx.row()]
|
self.model.cards[idx.row()]
|
||||||
for idx in self.form.tableView.selectionModel().selectedRows()
|
for idx in self.form.tableView.selectionModel().selectedRows()
|
||||||
]
|
]
|
||||||
|
|
||||||
def selected_notes(self) -> List[NoteID]:
|
def selected_notes(self) -> List[NoteId]:
|
||||||
return self.col.db.list(
|
return self.col.db.list(
|
||||||
"""
|
"""
|
||||||
select distinct nid from cards
|
select distinct nid from cards
|
||||||
|
@ -1070,13 +1070,13 @@ where id in %s"""
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
def selectedNotesAsCards(self) -> List[CardID]:
|
def selectedNotesAsCards(self) -> List[CardId]:
|
||||||
return self.col.db.list(
|
return self.col.db.list(
|
||||||
"select id from cards where nid in (%s)"
|
"select id from cards where nid in (%s)"
|
||||||
% ",".join([str(s) for s in self.selected_notes()])
|
% ",".join([str(s) for s in self.selected_notes()])
|
||||||
)
|
)
|
||||||
|
|
||||||
def oneModelNotes(self) -> List[NoteID]:
|
def oneModelNotes(self) -> List[NoteId]:
|
||||||
sf = self.selected_notes()
|
sf = self.selected_notes()
|
||||||
if not sf:
|
if not sf:
|
||||||
return []
|
return []
|
||||||
|
@ -1613,7 +1613,7 @@ where id in %s"""
|
||||||
def onCardList(self) -> None:
|
def onCardList(self) -> None:
|
||||||
self.form.tableView.setFocus()
|
self.form.tableView.setFocus()
|
||||||
|
|
||||||
def focusCid(self, cid: CardID) -> None:
|
def focusCid(self, cid: CardId) -> None:
|
||||||
try:
|
try:
|
||||||
row = list(self.model.cards).index(cid)
|
row = list(self.model.cards).index(cid)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
|
@ -1627,7 +1627,7 @@ where id in %s"""
|
||||||
|
|
||||||
|
|
||||||
class ChangeModel(QDialog):
|
class ChangeModel(QDialog):
|
||||||
def __init__(self, browser: Browser, nids: List[NoteID]) -> None:
|
def __init__(self, browser: Browser, nids: List[NoteId]) -> None:
|
||||||
QDialog.__init__(self, browser)
|
QDialog.__init__(self, browser)
|
||||||
self.browser = browser
|
self.browser = browser
|
||||||
self.nids = nids
|
self.nids = nids
|
||||||
|
|
|
@ -5,14 +5,14 @@ from __future__ import annotations
|
||||||
|
|
||||||
from typing import Sequence
|
from typing import 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
|
||||||
|
|
||||||
|
|
||||||
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: AnkiQt, card_ids: Sequence[CardId], flag: int) -> None:
|
||||||
mw.perform_op(lambda: mw.col.set_user_flag_for_cards(flag, card_ids))
|
mw.perform_op(lambda: mw.col.set_user_flag_for_cards(flag, card_ids))
|
||||||
|
|
|
@ -5,7 +5,7 @@ from __future__ import annotations
|
||||||
|
|
||||||
from typing import Callable, Sequence
|
from typing import Callable, Sequence
|
||||||
|
|
||||||
from anki.decks import DeckID
|
from anki.decks import DeckId
|
||||||
from aqt import AnkiQt, QWidget
|
from aqt import AnkiQt, QWidget
|
||||||
from aqt.main import PerformOpOptionalSuccessCallback
|
from aqt.main import PerformOpOptionalSuccessCallback
|
||||||
from aqt.utils import getOnlyText, tooltip, tr
|
from aqt.utils import getOnlyText, tooltip, tr
|
||||||
|
@ -15,7 +15,7 @@ def remove_decks(
|
||||||
*,
|
*,
|
||||||
mw: AnkiQt,
|
mw: AnkiQt,
|
||||||
parent: QWidget,
|
parent: QWidget,
|
||||||
deck_ids: Sequence[DeckID],
|
deck_ids: Sequence[DeckId],
|
||||||
) -> None:
|
) -> None:
|
||||||
mw.perform_op(
|
mw.perform_op(
|
||||||
lambda: mw.col.decks.remove(deck_ids),
|
lambda: mw.col.decks.remove(deck_ids),
|
||||||
|
@ -26,7 +26,7 @@ def remove_decks(
|
||||||
|
|
||||||
|
|
||||||
def reparent_decks(
|
def reparent_decks(
|
||||||
*, mw: AnkiQt, parent: QWidget, deck_ids: Sequence[DeckID], new_parent: DeckID
|
*, mw: AnkiQt, parent: QWidget, deck_ids: Sequence[DeckId], new_parent: DeckId
|
||||||
) -> None:
|
) -> None:
|
||||||
mw.perform_op(
|
mw.perform_op(
|
||||||
lambda: mw.col.decks.reparent(deck_ids=deck_ids, new_parent=new_parent),
|
lambda: mw.col.decks.reparent(deck_ids=deck_ids, new_parent=new_parent),
|
||||||
|
@ -39,7 +39,7 @@ def reparent_decks(
|
||||||
def rename_deck(
|
def rename_deck(
|
||||||
*,
|
*,
|
||||||
mw: AnkiQt,
|
mw: AnkiQt,
|
||||||
deck_id: DeckID,
|
deck_id: DeckId,
|
||||||
new_name: str,
|
new_name: str,
|
||||||
after_rename: Callable[[], None] = None,
|
after_rename: Callable[[], None] = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
|
|
|
@ -9,7 +9,7 @@ from typing import Any
|
||||||
|
|
||||||
import aqt
|
import aqt
|
||||||
from anki.collection import OpChanges
|
from anki.collection import OpChanges
|
||||||
from anki.decks import DeckID, DeckTreeNode
|
from anki.decks import DeckId, DeckTreeNode
|
||||||
from anki.utils import intTime
|
from anki.utils import intTime
|
||||||
from aqt import AnkiQt, gui_hooks
|
from aqt import AnkiQt, gui_hooks
|
||||||
from aqt.deck_ops import add_deck_dialog, remove_decks, rename_deck, reparent_decks
|
from aqt.deck_ops import add_deck_dialog, remove_decks, rename_deck, reparent_decks
|
||||||
|
@ -40,7 +40,7 @@ class DeckBrowserContent:
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class RenderDeckNodeContext:
|
class RenderDeckNodeContext:
|
||||||
current_deck_id: DeckID
|
current_deck_id: DeckId
|
||||||
|
|
||||||
|
|
||||||
class DeckBrowser:
|
class DeckBrowser:
|
||||||
|
@ -99,9 +99,9 @@ class DeckBrowser:
|
||||||
self._on_create()
|
self._on_create()
|
||||||
elif cmd == "drag":
|
elif cmd == "drag":
|
||||||
source, target = arg.split(",")
|
source, target = arg.split(",")
|
||||||
self._handle_drag_and_drop(DeckID(int(source)), DeckID(int(target or 0)))
|
self._handle_drag_and_drop(DeckId(int(source)), DeckId(int(target or 0)))
|
||||||
elif cmd == "collapse":
|
elif cmd == "collapse":
|
||||||
self._collapse(DeckID(int(arg)))
|
self._collapse(DeckId(int(arg)))
|
||||||
elif cmd == "v2upgrade":
|
elif cmd == "v2upgrade":
|
||||||
self._confirm_upgrade()
|
self._confirm_upgrade()
|
||||||
elif cmd == "v2upgradeinfo":
|
elif cmd == "v2upgradeinfo":
|
||||||
|
@ -112,7 +112,7 @@ class DeckBrowser:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def _selDeck(self, did: str) -> None:
|
def _selDeck(self, did: str) -> None:
|
||||||
self.mw.col.decks.select(DeckID(int(did)))
|
self.mw.col.decks.select(DeckId(int(did)))
|
||||||
self.mw.onOverview()
|
self.mw.onOverview()
|
||||||
|
|
||||||
# HTML generation
|
# HTML generation
|
||||||
|
@ -251,20 +251,20 @@ class DeckBrowser:
|
||||||
def _showOptions(self, did: str) -> None:
|
def _showOptions(self, did: str) -> None:
|
||||||
m = QMenu(self.mw)
|
m = QMenu(self.mw)
|
||||||
a = m.addAction(tr.actions_rename())
|
a = m.addAction(tr.actions_rename())
|
||||||
qconnect(a.triggered, lambda b, did=did: self._rename(DeckID(int(did))))
|
qconnect(a.triggered, lambda b, did=did: self._rename(DeckId(int(did))))
|
||||||
a = m.addAction(tr.actions_options())
|
a = m.addAction(tr.actions_options())
|
||||||
qconnect(a.triggered, lambda b, did=did: self._options(DeckID(int(did))))
|
qconnect(a.triggered, lambda b, did=did: self._options(DeckId(int(did))))
|
||||||
a = m.addAction(tr.actions_export())
|
a = m.addAction(tr.actions_export())
|
||||||
qconnect(a.triggered, lambda b, did=did: self._export(DeckID(int(did))))
|
qconnect(a.triggered, lambda b, did=did: self._export(DeckId(int(did))))
|
||||||
a = m.addAction(tr.actions_delete())
|
a = m.addAction(tr.actions_delete())
|
||||||
qconnect(a.triggered, lambda b, did=did: self._delete(DeckID(int(did))))
|
qconnect(a.triggered, lambda b, did=did: self._delete(DeckId(int(did))))
|
||||||
gui_hooks.deck_browser_will_show_options_menu(m, int(did))
|
gui_hooks.deck_browser_will_show_options_menu(m, int(did))
|
||||||
m.exec_(QCursor.pos())
|
m.exec_(QCursor.pos())
|
||||||
|
|
||||||
def _export(self, did: DeckID) -> None:
|
def _export(self, did: DeckId) -> None:
|
||||||
self.mw.onExport(did=did)
|
self.mw.onExport(did=did)
|
||||||
|
|
||||||
def _rename(self, did: DeckID) -> None:
|
def _rename(self, did: DeckId) -> None:
|
||||||
deck = self.mw.col.decks.get(did)
|
deck = self.mw.col.decks.get(did)
|
||||||
current_name = deck["name"]
|
current_name = deck["name"]
|
||||||
new_name = getOnlyText(tr.decks_new_deck_name(), default=current_name)
|
new_name = getOnlyText(tr.decks_new_deck_name(), default=current_name)
|
||||||
|
@ -273,23 +273,23 @@ class DeckBrowser:
|
||||||
|
|
||||||
rename_deck(mw=self.mw, deck_id=did, new_name=new_name)
|
rename_deck(mw=self.mw, deck_id=did, new_name=new_name)
|
||||||
|
|
||||||
def _options(self, did: DeckID) -> None:
|
def _options(self, did: DeckId) -> None:
|
||||||
# select the deck first, because the dyn deck conf assumes the deck
|
# select the deck first, because the dyn deck conf assumes the deck
|
||||||
# we're editing is the current one
|
# we're editing is the current one
|
||||||
self.mw.col.decks.select(did)
|
self.mw.col.decks.select(did)
|
||||||
self.mw.onDeckConf()
|
self.mw.onDeckConf()
|
||||||
|
|
||||||
def _collapse(self, did: DeckID) -> None:
|
def _collapse(self, did: DeckId) -> None:
|
||||||
self.mw.col.decks.collapse(did)
|
self.mw.col.decks.collapse(did)
|
||||||
node = self.mw.col.decks.find_deck_in_tree(self._dueTree, did)
|
node = self.mw.col.decks.find_deck_in_tree(self._dueTree, did)
|
||||||
if node:
|
if node:
|
||||||
node.collapsed = not node.collapsed
|
node.collapsed = not node.collapsed
|
||||||
self._renderPage(reuse=True)
|
self._renderPage(reuse=True)
|
||||||
|
|
||||||
def _handle_drag_and_drop(self, source: DeckID, target: DeckID) -> None:
|
def _handle_drag_and_drop(self, source: DeckId, target: DeckId) -> None:
|
||||||
reparent_decks(mw=self.mw, parent=self.mw, deck_ids=[source], new_parent=target)
|
reparent_decks(mw=self.mw, parent=self.mw, deck_ids=[source], new_parent=target)
|
||||||
|
|
||||||
def _delete(self, did: DeckID) -> None:
|
def _delete(self, did: DeckId) -> None:
|
||||||
remove_decks(mw=self.mw, parent=self.mw, deck_ids=[did])
|
remove_decks(mw=self.mw, parent=self.mw, deck_ids=[did])
|
||||||
|
|
||||||
# Top buttons
|
# Top buttons
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from anki.decks import DEFAULT_DECK_ID, DeckID
|
from anki.decks import DEFAULT_DECK_ID, DeckId
|
||||||
from aqt import AnkiQt
|
from aqt import AnkiQt
|
||||||
from aqt.qt import *
|
from aqt.qt import *
|
||||||
from aqt.utils import HelpPage, shortcut, tr
|
from aqt.utils import HelpPage, shortcut, tr
|
||||||
|
@ -15,17 +15,17 @@ class DeckChooser(QHBoxLayout):
|
||||||
mw: AnkiQt,
|
mw: AnkiQt,
|
||||||
widget: QWidget,
|
widget: QWidget,
|
||||||
label: bool = True,
|
label: bool = True,
|
||||||
starting_deck_id: Optional[DeckID] = None,
|
starting_deck_id: Optional[DeckId] = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
QHBoxLayout.__init__(self)
|
QHBoxLayout.__init__(self)
|
||||||
self._widget = widget # type: ignore
|
self._widget = widget # type: ignore
|
||||||
self.mw = mw
|
self.mw = mw
|
||||||
self._setup_ui(show_label=label)
|
self._setup_ui(show_label=label)
|
||||||
|
|
||||||
self._selected_deck_id = DeckID(0)
|
self._selected_deck_id = DeckId(0)
|
||||||
# default to current deck if starting id not provided
|
# default to current deck if starting id not provided
|
||||||
if starting_deck_id is None:
|
if starting_deck_id is None:
|
||||||
starting_deck_id = DeckID(self.mw.col.get_config("curDeck", default=1) or 1)
|
starting_deck_id = DeckId(self.mw.col.get_config("curDeck", default=1) or 1)
|
||||||
self.selected_deck_id = starting_deck_id
|
self.selected_deck_id = starting_deck_id
|
||||||
|
|
||||||
def _setup_ui(self, show_label: bool) -> None:
|
def _setup_ui(self, show_label: bool) -> None:
|
||||||
|
@ -57,13 +57,13 @@ class DeckChooser(QHBoxLayout):
|
||||||
)
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def selected_deck_id(self) -> DeckID:
|
def selected_deck_id(self) -> DeckId:
|
||||||
self._ensure_selected_deck_valid()
|
self._ensure_selected_deck_valid()
|
||||||
|
|
||||||
return self._selected_deck_id
|
return self._selected_deck_id
|
||||||
|
|
||||||
@selected_deck_id.setter
|
@selected_deck_id.setter
|
||||||
def selected_deck_id(self, id: DeckID) -> None:
|
def selected_deck_id(self, id: DeckId) -> None:
|
||||||
if id != self._selected_deck_id:
|
if id != self._selected_deck_id:
|
||||||
self._selected_deck_id = id
|
self._selected_deck_id = id
|
||||||
self._ensure_selected_deck_valid()
|
self._ensure_selected_deck_valid()
|
||||||
|
@ -104,7 +104,7 @@ class DeckChooser(QHBoxLayout):
|
||||||
onDeckChange = choose_deck
|
onDeckChange = choose_deck
|
||||||
deckName = selected_deck_name
|
deckName = selected_deck_name
|
||||||
|
|
||||||
def selectedId(self) -> DeckID:
|
def selectedId(self) -> DeckId:
|
||||||
return self.selected_deck_id
|
return self.selected_deck_id
|
||||||
|
|
||||||
def cleanup(self) -> None:
|
def cleanup(self) -> None:
|
||||||
|
|
|
@ -8,7 +8,7 @@ from concurrent.futures import Future
|
||||||
from typing import Any, List
|
from typing import Any, List
|
||||||
|
|
||||||
import aqt
|
import aqt
|
||||||
from anki.cards import CardID
|
from anki.cards import CardId
|
||||||
from anki.collection import EmptyCardsReport
|
from anki.collection import EmptyCardsReport
|
||||||
from aqt import gui_hooks
|
from aqt import gui_hooks
|
||||||
from aqt.qt import QDialog, QDialogButtonBox, qconnect
|
from aqt.qt import QDialog, QDialogButtonBox, qconnect
|
||||||
|
@ -89,14 +89,14 @@ class EmptyCardsDialog(QDialog):
|
||||||
self.mw.taskman.run_in_background(delete, on_done)
|
self.mw.taskman.run_in_background(delete, on_done)
|
||||||
|
|
||||||
def _delete_cards(self, keep_notes: bool) -> int:
|
def _delete_cards(self, keep_notes: bool) -> int:
|
||||||
to_delete: List[CardID] = []
|
to_delete: List[CardId] = []
|
||||||
note: EmptyCardsReport.NoteWithEmptyCards
|
note: EmptyCardsReport.NoteWithEmptyCards
|
||||||
for note in self.report.notes:
|
for note in self.report.notes:
|
||||||
if keep_notes and note.will_delete_note:
|
if keep_notes and note.will_delete_note:
|
||||||
# leave first card
|
# leave first card
|
||||||
to_delete.extend([CardID(id) for id in note.card_ids[1:]])
|
to_delete.extend([CardId(id) for id in note.card_ids[1:]])
|
||||||
else:
|
else:
|
||||||
to_delete.extend([CardID(id) for id in note.card_ids])
|
to_delete.extend([CardId(id) for id in note.card_ids])
|
||||||
|
|
||||||
self.mw.col.remove_cards_and_orphaned_notes(to_delete)
|
self.mw.col.remove_cards_and_orphaned_notes(to_delete)
|
||||||
return len(to_delete)
|
return len(to_delete)
|
||||||
|
|
|
@ -11,8 +11,8 @@ from typing import List, Optional
|
||||||
|
|
||||||
import aqt
|
import aqt
|
||||||
from anki import hooks
|
from anki import hooks
|
||||||
from anki.cards import CardID
|
from anki.cards import CardId
|
||||||
from anki.decks import DeckID
|
from anki.decks import DeckId
|
||||||
from anki.exporting import Exporter, exporters
|
from anki.exporting import Exporter, exporters
|
||||||
from aqt.qt import *
|
from aqt.qt import *
|
||||||
from aqt.utils import (
|
from aqt.utils import (
|
||||||
|
@ -29,8 +29,8 @@ class ExportDialog(QDialog):
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
mw: aqt.main.AnkiQt,
|
mw: aqt.main.AnkiQt,
|
||||||
did: Optional[DeckID] = None,
|
did: Optional[DeckId] = None,
|
||||||
cids: Optional[List[CardID]] = None,
|
cids: Optional[List[CardId]] = None,
|
||||||
):
|
):
|
||||||
QDialog.__init__(self, mw, Qt.Window)
|
QDialog.__init__(self, mw, Qt.Window)
|
||||||
self.mw = mw
|
self.mw = mw
|
||||||
|
@ -43,7 +43,7 @@ class ExportDialog(QDialog):
|
||||||
self.setup(did)
|
self.setup(did)
|
||||||
self.exec_()
|
self.exec_()
|
||||||
|
|
||||||
def setup(self, did: Optional[DeckID]) -> None:
|
def setup(self, did: Optional[DeckId]) -> None:
|
||||||
self.exporters = exporters(self.col)
|
self.exporters = exporters(self.col)
|
||||||
# if a deck specified, start with .apkg type selected
|
# if a deck specified, start with .apkg type selected
|
||||||
idx = 0
|
idx = 0
|
||||||
|
|
|
@ -4,8 +4,8 @@
|
||||||
from typing import List, Optional, Tuple
|
from typing import List, Optional, Tuple
|
||||||
|
|
||||||
import aqt
|
import aqt
|
||||||
from anki.collection import OpChangesWithID, SearchNode
|
from anki.collection import OpChangesWithId, SearchNode
|
||||||
from anki.decks import DeckDict, DeckID, FilteredDeckConfig
|
from anki.decks import DeckDict, DeckId, FilteredDeckConfig
|
||||||
from anki.errors import SearchError
|
from anki.errors import SearchError
|
||||||
from anki.lang import without_unicode_isolation
|
from anki.lang import without_unicode_isolation
|
||||||
from anki.scheduler import FilteredDeckForUpdate
|
from anki.scheduler import FilteredDeckForUpdate
|
||||||
|
@ -34,7 +34,7 @@ class FilteredDeckConfigDialog(QDialog):
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
mw: AnkiQt,
|
mw: AnkiQt,
|
||||||
deck_id: DeckID = DeckID(0),
|
deck_id: DeckId = DeckId(0),
|
||||||
search: Optional[str] = None,
|
search: Optional[str] = None,
|
||||||
search_2: Optional[str] = None,
|
search_2: Optional[str] = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
|
@ -300,7 +300,7 @@ class FilteredDeckConfigDialog(QDialog):
|
||||||
if not self._update_deck():
|
if not self._update_deck():
|
||||||
return
|
return
|
||||||
|
|
||||||
def success(out: OpChangesWithID) -> None:
|
def success(out: OpChangesWithId) -> None:
|
||||||
gui_hooks.filtered_deck_dialog_did_add_or_update_deck(
|
gui_hooks.filtered_deck_dialog_did_add_or_update_deck(
|
||||||
self, self.deck, out.id
|
self, self.deck, out.id
|
||||||
)
|
)
|
||||||
|
|
|
@ -6,7 +6,7 @@ from __future__ import annotations
|
||||||
from typing import List, Optional, Sequence
|
from typing import List, Optional, Sequence
|
||||||
|
|
||||||
import aqt
|
import aqt
|
||||||
from anki.notes import NoteID
|
from anki.notes import NoteId
|
||||||
from aqt import AnkiQt, QWidget
|
from aqt import AnkiQt, QWidget
|
||||||
from aqt.qt import QDialog, Qt
|
from aqt.qt import QDialog, Qt
|
||||||
from aqt.utils import (
|
from aqt.utils import (
|
||||||
|
@ -31,7 +31,7 @@ def find_and_replace(
|
||||||
*,
|
*,
|
||||||
mw: AnkiQt,
|
mw: AnkiQt,
|
||||||
parent: QWidget,
|
parent: QWidget,
|
||||||
note_ids: Sequence[NoteID],
|
note_ids: Sequence[NoteId],
|
||||||
search: str,
|
search: str,
|
||||||
replacement: str,
|
replacement: str,
|
||||||
regex: bool,
|
regex: bool,
|
||||||
|
@ -83,7 +83,7 @@ class FindAndReplaceDialog(QDialog):
|
||||||
COMBO_NAME = "BrowserFindAndReplace"
|
COMBO_NAME = "BrowserFindAndReplace"
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self, parent: QWidget, *, mw: AnkiQt, note_ids: Sequence[NoteID]
|
self, parent: QWidget, *, mw: AnkiQt, note_ids: Sequence[NoteId]
|
||||||
) -> None:
|
) -> None:
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
self.mw = mw
|
self.mw = mw
|
||||||
|
|
|
@ -47,14 +47,14 @@ from anki.collection import (
|
||||||
Config,
|
Config,
|
||||||
OpChanges,
|
OpChanges,
|
||||||
OpChangesWithCount,
|
OpChangesWithCount,
|
||||||
OpChangesWithID,
|
OpChangesWithId,
|
||||||
ReviewUndo,
|
ReviewUndo,
|
||||||
UndoResult,
|
UndoResult,
|
||||||
UndoStatus,
|
UndoStatus,
|
||||||
)
|
)
|
||||||
from anki.decks import DeckDict, DeckID
|
from anki.decks import DeckDict, DeckId
|
||||||
from anki.hooks import runHook
|
from anki.hooks import runHook
|
||||||
from anki.notes import NoteID
|
from anki.notes import NoteId
|
||||||
from anki.sound import AVTag, SoundOrVideoTag
|
from anki.sound import AVTag, SoundOrVideoTag
|
||||||
from anki.types import assert_exhaustive
|
from anki.types import assert_exhaustive
|
||||||
from anki.utils import devMode, ids2str, intTime, isMac, isWin, splitFields
|
from anki.utils import devMode, ids2str, intTime, isMac, isWin, splitFields
|
||||||
|
@ -104,7 +104,7 @@ class HasChangesProperty(Protocol):
|
||||||
# either need to be added here, or cast at call time
|
# either need to be added here, or cast at call time
|
||||||
ResultWithChanges = TypeVar(
|
ResultWithChanges = TypeVar(
|
||||||
"ResultWithChanges",
|
"ResultWithChanges",
|
||||||
bound=Union[OpChanges, OpChangesWithCount, OpChangesWithID, HasChangesProperty],
|
bound=Union[OpChanges, OpChangesWithCount, OpChangesWithId, HasChangesProperty],
|
||||||
)
|
)
|
||||||
|
|
||||||
T = TypeVar("T")
|
T = TypeVar("T")
|
||||||
|
@ -1381,7 +1381,7 @@ title="%s" %s>%s</button>""" % (
|
||||||
|
|
||||||
aqt.importing.onImport(self)
|
aqt.importing.onImport(self)
|
||||||
|
|
||||||
def onExport(self, did: Optional[DeckID] = None) -> None:
|
def onExport(self, did: Optional[DeckId] = None) -> None:
|
||||||
import aqt.exporting
|
import aqt.exporting
|
||||||
|
|
||||||
aqt.exporting.ExportDialog(self, did=did)
|
aqt.exporting.ExportDialog(self, did=did)
|
||||||
|
@ -1534,7 +1534,7 @@ title="%s" %s>%s</button>""" % (
|
||||||
# Log note deletion
|
# Log note deletion
|
||||||
##########################################################################
|
##########################################################################
|
||||||
|
|
||||||
def onRemNotes(self, col: Collection, nids: Sequence[NoteID]) -> None:
|
def onRemNotes(self, col: Collection, nids: Sequence[NoteId]) -> None:
|
||||||
path = os.path.join(self.pm.profileFolder(), "deleted.txt")
|
path = os.path.join(self.pm.profileFolder(), "deleted.txt")
|
||||||
existed = os.path.exists(path)
|
existed = os.path.exists(path)
|
||||||
with open(path, "ab") as f:
|
with open(path, "ab") as f:
|
||||||
|
|
|
@ -8,7 +8,7 @@ from typing import List, Optional, Sequence
|
||||||
import aqt.clayout
|
import aqt.clayout
|
||||||
from anki import Collection, stdmodels
|
from anki import Collection, stdmodels
|
||||||
from anki.lang import without_unicode_isolation
|
from anki.lang import without_unicode_isolation
|
||||||
from anki.models import NoteType, NoteTypeID, NoteTypeNameIDUseCount
|
from anki.models import NoteType, NoteTypeId, NoteTypeNameIdUseCount
|
||||||
from anki.notes import Note
|
from anki.notes import Note
|
||||||
from aqt import AnkiQt, gui_hooks
|
from aqt import AnkiQt, gui_hooks
|
||||||
from aqt.qt import *
|
from aqt.qt import *
|
||||||
|
@ -32,7 +32,7 @@ class Models(QDialog):
|
||||||
mw: AnkiQt,
|
mw: AnkiQt,
|
||||||
parent: Optional[QWidget] = None,
|
parent: Optional[QWidget] = None,
|
||||||
fromMain: bool = False,
|
fromMain: bool = False,
|
||||||
selected_notetype_id: Optional[NoteTypeID] = None,
|
selected_notetype_id: Optional[NoteTypeId] = None,
|
||||||
):
|
):
|
||||||
self.mw = mw
|
self.mw = mw
|
||||||
parent = parent or mw
|
parent = parent or mw
|
||||||
|
@ -49,7 +49,7 @@ class Models(QDialog):
|
||||||
self.form.buttonBox.helpRequested,
|
self.form.buttonBox.helpRequested,
|
||||||
lambda: openHelp(HelpPage.ADDING_A_NOTE_TYPE),
|
lambda: openHelp(HelpPage.ADDING_A_NOTE_TYPE),
|
||||||
)
|
)
|
||||||
self.models: List[NoteTypeNameIDUseCount] = []
|
self.models: List[NoteTypeNameIdUseCount] = []
|
||||||
self.setupModels()
|
self.setupModels()
|
||||||
restoreGeom(self, "models")
|
restoreGeom(self, "models")
|
||||||
self.exec_()
|
self.exec_()
|
||||||
|
@ -109,7 +109,7 @@ class Models(QDialog):
|
||||||
self.saveAndRefresh(nt)
|
self.saveAndRefresh(nt)
|
||||||
|
|
||||||
def saveAndRefresh(self, nt: NoteType) -> None:
|
def saveAndRefresh(self, nt: NoteType) -> None:
|
||||||
def save() -> Sequence[NoteTypeNameIDUseCount]:
|
def save() -> Sequence[NoteTypeNameIdUseCount]:
|
||||||
self.mm.save(nt)
|
self.mm.save(nt)
|
||||||
return self.col.models.all_use_counts()
|
return self.col.models.all_use_counts()
|
||||||
|
|
||||||
|
@ -118,7 +118,7 @@ class Models(QDialog):
|
||||||
|
|
||||||
self.mw.taskman.with_progress(save, on_done, self)
|
self.mw.taskman.with_progress(save, on_done, self)
|
||||||
|
|
||||||
def updateModelsList(self, notetypes: List[NoteTypeNameIDUseCount]) -> None:
|
def updateModelsList(self, notetypes: List[NoteTypeNameIdUseCount]) -> None:
|
||||||
row = self.form.modelsList.currentRow()
|
row = self.form.modelsList.currentRow()
|
||||||
if row == -1:
|
if row == -1:
|
||||||
row = 0
|
row = 0
|
||||||
|
@ -133,7 +133,7 @@ class Models(QDialog):
|
||||||
|
|
||||||
def current_notetype(self) -> NoteType:
|
def current_notetype(self) -> NoteType:
|
||||||
row = self.form.modelsList.currentRow()
|
row = self.form.modelsList.currentRow()
|
||||||
return self.mm.get(NoteTypeID(self.models[row].id))
|
return self.mm.get(NoteTypeId(self.models[row].id))
|
||||||
|
|
||||||
def onAdd(self) -> None:
|
def onAdd(self) -> None:
|
||||||
m = AddModel(self.mw, self).get()
|
m = AddModel(self.mw, self).get()
|
||||||
|
@ -159,7 +159,7 @@ class Models(QDialog):
|
||||||
|
|
||||||
nt = self.current_notetype()
|
nt = self.current_notetype()
|
||||||
|
|
||||||
def save() -> Sequence[NoteTypeNameIDUseCount]:
|
def save() -> Sequence[NoteTypeNameIdUseCount]:
|
||||||
self.mm.rem(nt)
|
self.mm.rem(nt)
|
||||||
return self.col.models.all_use_counts()
|
return self.col.models.all_use_counts()
|
||||||
|
|
||||||
|
|
|
@ -5,8 +5,8 @@ from __future__ import annotations
|
||||||
|
|
||||||
from typing import Callable, Sequence
|
from typing import Callable, Sequence
|
||||||
|
|
||||||
from anki.decks import DeckID
|
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
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ def add_note(
|
||||||
*,
|
*,
|
||||||
mw: AnkiQt,
|
mw: AnkiQt,
|
||||||
note: Note,
|
note: Note,
|
||||||
target_deck_id: DeckID,
|
target_deck_id: DeckId,
|
||||||
success: PerformOpOptionalSuccessCallback = None,
|
success: PerformOpOptionalSuccessCallback = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
mw.perform_op(lambda: mw.col.add_note(note, target_deck_id), success=success)
|
mw.perform_op(lambda: mw.col.add_note(note, target_deck_id), success=success)
|
||||||
|
@ -31,7 +31,7 @@ def update_note(*, mw: AnkiQt, note: Note, after_hooks: Callable[[], None]) -> N
|
||||||
def remove_notes(
|
def remove_notes(
|
||||||
*,
|
*,
|
||||||
mw: AnkiQt,
|
mw: AnkiQt,
|
||||||
note_ids: Sequence[NoteID],
|
note_ids: Sequence[NoteId],
|
||||||
success: PerformOpOptionalSuccessCallback = None,
|
success: PerformOpOptionalSuccessCallback = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
mw.perform_op(lambda: mw.col.remove_notes(note_ids), success=success)
|
mw.perform_op(lambda: mw.col.remove_notes(note_ids), success=success)
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
# 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 List, Optional
|
from typing import List, Optional
|
||||||
|
|
||||||
from anki.models import NoteTypeID
|
from anki.models import NoteTypeId
|
||||||
from aqt import AnkiQt, gui_hooks
|
from aqt import AnkiQt, gui_hooks
|
||||||
from aqt.qt import *
|
from aqt.qt import *
|
||||||
from aqt.utils import HelpPage, shortcut, tr
|
from aqt.utils import HelpPage, shortcut, tr
|
||||||
|
@ -23,16 +23,16 @@ class NoteTypeChooser(QHBoxLayout):
|
||||||
deleted.
|
deleted.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_selected_notetype_id: NoteTypeID
|
_selected_notetype_id: NoteTypeId
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
*,
|
*,
|
||||||
mw: AnkiQt,
|
mw: AnkiQt,
|
||||||
widget: QWidget,
|
widget: QWidget,
|
||||||
starting_notetype_id: NoteTypeID,
|
starting_notetype_id: NoteTypeId,
|
||||||
on_button_activated: Optional[Callable[[], None]] = None,
|
on_button_activated: Optional[Callable[[], None]] = None,
|
||||||
on_notetype_changed: Optional[Callable[[NoteTypeID], None]] = None,
|
on_notetype_changed: Optional[Callable[[NoteTypeId], None]] = None,
|
||||||
show_prefix_label: bool = True,
|
show_prefix_label: bool = True,
|
||||||
) -> None:
|
) -> None:
|
||||||
QHBoxLayout.__init__(self)
|
QHBoxLayout.__init__(self)
|
||||||
|
@ -44,7 +44,7 @@ class NoteTypeChooser(QHBoxLayout):
|
||||||
self.on_button_activated = self.choose_notetype
|
self.on_button_activated = self.choose_notetype
|
||||||
self._setup_ui(show_label=show_prefix_label)
|
self._setup_ui(show_label=show_prefix_label)
|
||||||
gui_hooks.state_did_reset.append(self.reset_state)
|
gui_hooks.state_did_reset.append(self.reset_state)
|
||||||
self._selected_notetype_id = NoteTypeID(0)
|
self._selected_notetype_id = NoteTypeId(0)
|
||||||
# triggers UI update; avoid firing changed hook on startup
|
# triggers UI update; avoid firing changed hook on startup
|
||||||
self.on_notetype_changed = None
|
self.on_notetype_changed = None
|
||||||
self.selected_notetype_id = starting_notetype_id
|
self.selected_notetype_id = starting_notetype_id
|
||||||
|
@ -121,7 +121,7 @@ class NoteTypeChooser(QHBoxLayout):
|
||||||
self.selected_notetype_id = id
|
self.selected_notetype_id = id
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def selected_notetype_id(self) -> NoteTypeID:
|
def selected_notetype_id(self) -> NoteTypeId:
|
||||||
# theoretically this should not be necessary, as we're listening to
|
# theoretically this should not be necessary, as we're listening to
|
||||||
# resets
|
# resets
|
||||||
self._ensure_selected_notetype_valid()
|
self._ensure_selected_notetype_valid()
|
||||||
|
@ -129,7 +129,7 @@ class NoteTypeChooser(QHBoxLayout):
|
||||||
return self._selected_notetype_id
|
return self._selected_notetype_id
|
||||||
|
|
||||||
@selected_notetype_id.setter
|
@selected_notetype_id.setter
|
||||||
def selected_notetype_id(self, id: NoteTypeID) -> None:
|
def selected_notetype_id(self, id: NoteTypeId) -> None:
|
||||||
if id != self._selected_notetype_id:
|
if id != self._selected_notetype_id:
|
||||||
self._selected_notetype_id = id
|
self._selected_notetype_id = id
|
||||||
self._ensure_selected_notetype_valid()
|
self._ensure_selected_notetype_valid()
|
||||||
|
@ -142,7 +142,7 @@ class NoteTypeChooser(QHBoxLayout):
|
||||||
|
|
||||||
def _ensure_selected_notetype_valid(self) -> None:
|
def _ensure_selected_notetype_valid(self) -> None:
|
||||||
if not self.mw.col.models.get(self._selected_notetype_id):
|
if not self.mw.col.models.get(self._selected_notetype_id):
|
||||||
self.selected_notetype_id = NoteTypeID(
|
self.selected_notetype_id = NoteTypeId(
|
||||||
self.mw.col.models.all_names_and_ids()[0].id
|
self.mw.col.models.all_names_and_ids()[0].id
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ from typing import Any, Callable, List, Match, Optional, Sequence, Tuple, Union
|
||||||
from PyQt5.QtCore import Qt
|
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
|
||||||
from anki.tags import MARKED_TAG
|
from anki.tags import MARKED_TAG
|
||||||
from anki.utils import stripHTML
|
from anki.utils import stripHTML
|
||||||
|
@ -67,7 +67,7 @@ class Reviewer:
|
||||||
self.card: Optional[Card] = None
|
self.card: Optional[Card] = None
|
||||||
self.cardQueue: List[Card] = []
|
self.cardQueue: List[Card] = []
|
||||||
self.hadCardQueue = False
|
self.hadCardQueue = False
|
||||||
self._answeredIds: List[CardID] = []
|
self._answeredIds: List[CardId] = []
|
||||||
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
|
||||||
|
|
|
@ -6,10 +6,10 @@ from __future__ import annotations
|
||||||
from typing import List, Optional, Sequence
|
from typing import List, Optional, Sequence
|
||||||
|
|
||||||
import aqt
|
import aqt
|
||||||
from anki.cards import CardID
|
from anki.cards import CardId
|
||||||
from anki.collection import CARD_TYPE_NEW, Config
|
from anki.collection import CARD_TYPE_NEW, Config
|
||||||
from anki.decks import DeckID
|
from anki.decks import DeckId
|
||||||
from anki.notes import NoteID
|
from anki.notes import NoteId
|
||||||
from anki.scheduler import FilteredDeckForUpdate
|
from anki.scheduler import FilteredDeckForUpdate
|
||||||
from aqt import AnkiQt
|
from aqt import AnkiQt
|
||||||
from aqt.main import PerformOpOptionalSuccessCallback
|
from aqt.main import PerformOpOptionalSuccessCallback
|
||||||
|
@ -21,7 +21,7 @@ def set_due_date_dialog(
|
||||||
*,
|
*,
|
||||||
mw: aqt.AnkiQt,
|
mw: aqt.AnkiQt,
|
||||||
parent: QWidget,
|
parent: QWidget,
|
||||||
card_ids: List[CardID],
|
card_ids: List[CardId],
|
||||||
config_key: Optional[Config.String.Key.V],
|
config_key: Optional[Config.String.Key.V],
|
||||||
) -> None:
|
) -> None:
|
||||||
if not card_ids:
|
if not card_ids:
|
||||||
|
@ -54,7 +54,7 @@ def set_due_date_dialog(
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def forget_cards(*, mw: aqt.AnkiQt, parent: QWidget, card_ids: List[CardID]) -> None:
|
def forget_cards(*, mw: aqt.AnkiQt, parent: QWidget, card_ids: List[CardId]) -> None:
|
||||||
if not card_ids:
|
if not card_ids:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@ def forget_cards(*, mw: aqt.AnkiQt, parent: QWidget, card_ids: List[CardID]) ->
|
||||||
|
|
||||||
|
|
||||||
def reposition_new_cards_dialog(
|
def reposition_new_cards_dialog(
|
||||||
*, mw: AnkiQt, parent: QWidget, card_ids: Sequence[CardID]
|
*, mw: AnkiQt, parent: QWidget, card_ids: Sequence[CardId]
|
||||||
) -> None:
|
) -> None:
|
||||||
assert mw.col.db
|
assert mw.col.db
|
||||||
row = mw.col.db.first(
|
row = mw.col.db.first(
|
||||||
|
@ -112,7 +112,7 @@ def reposition_new_cards(
|
||||||
*,
|
*,
|
||||||
mw: AnkiQt,
|
mw: AnkiQt,
|
||||||
parent: QWidget,
|
parent: QWidget,
|
||||||
card_ids: Sequence[CardID],
|
card_ids: Sequence[CardId],
|
||||||
starting_from: int,
|
starting_from: int,
|
||||||
step_size: int,
|
step_size: int,
|
||||||
randomize: bool,
|
randomize: bool,
|
||||||
|
@ -135,7 +135,7 @@ def reposition_new_cards(
|
||||||
def suspend_cards(
|
def suspend_cards(
|
||||||
*,
|
*,
|
||||||
mw: AnkiQt,
|
mw: AnkiQt,
|
||||||
card_ids: Sequence[CardID],
|
card_ids: Sequence[CardId],
|
||||||
success: PerformOpOptionalSuccessCallback = None,
|
success: PerformOpOptionalSuccessCallback = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
mw.perform_op(lambda: mw.col.sched.suspend_cards(card_ids), success=success)
|
mw.perform_op(lambda: mw.col.sched.suspend_cards(card_ids), success=success)
|
||||||
|
@ -144,7 +144,7 @@ def suspend_cards(
|
||||||
def suspend_note(
|
def suspend_note(
|
||||||
*,
|
*,
|
||||||
mw: AnkiQt,
|
mw: AnkiQt,
|
||||||
note_id: NoteID,
|
note_id: NoteId,
|
||||||
success: PerformOpOptionalSuccessCallback = None,
|
success: PerformOpOptionalSuccessCallback = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
mw.taskman.run_in_background(
|
mw.taskman.run_in_background(
|
||||||
|
@ -153,14 +153,14 @@ def suspend_note(
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def unsuspend_cards(*, mw: AnkiQt, card_ids: Sequence[CardID]) -> None:
|
def unsuspend_cards(*, mw: AnkiQt, card_ids: Sequence[CardId]) -> None:
|
||||||
mw.perform_op(lambda: mw.col.sched.unsuspend_cards(card_ids))
|
mw.perform_op(lambda: mw.col.sched.unsuspend_cards(card_ids))
|
||||||
|
|
||||||
|
|
||||||
def bury_cards(
|
def bury_cards(
|
||||||
*,
|
*,
|
||||||
mw: AnkiQt,
|
mw: AnkiQt,
|
||||||
card_ids: Sequence[CardID],
|
card_ids: Sequence[CardId],
|
||||||
success: PerformOpOptionalSuccessCallback = None,
|
success: PerformOpOptionalSuccessCallback = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
mw.perform_op(lambda: mw.col.sched.bury_cards(card_ids), success=success)
|
mw.perform_op(lambda: mw.col.sched.bury_cards(card_ids), success=success)
|
||||||
|
@ -169,7 +169,7 @@ def bury_cards(
|
||||||
def bury_note(
|
def bury_note(
|
||||||
*,
|
*,
|
||||||
mw: AnkiQt,
|
mw: AnkiQt,
|
||||||
note_id: NoteID,
|
note_id: NoteId,
|
||||||
success: PerformOpOptionalSuccessCallback = None,
|
success: PerformOpOptionalSuccessCallback = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
mw.taskman.run_in_background(
|
mw.taskman.run_in_background(
|
||||||
|
@ -178,11 +178,11 @@ def bury_note(
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def rebuild_filtered_deck(*, mw: AnkiQt, deck_id: DeckID) -> None:
|
def rebuild_filtered_deck(*, mw: AnkiQt, deck_id: DeckId) -> None:
|
||||||
mw.perform_op(lambda: mw.col.sched.rebuild_filtered_deck(deck_id))
|
mw.perform_op(lambda: mw.col.sched.rebuild_filtered_deck(deck_id))
|
||||||
|
|
||||||
|
|
||||||
def empty_filtered_deck(*, mw: AnkiQt, deck_id: DeckID) -> None:
|
def empty_filtered_deck(*, mw: AnkiQt, deck_id: DeckId) -> None:
|
||||||
mw.perform_op(lambda: mw.col.sched.empty_filtered_deck(deck_id))
|
mw.perform_op(lambda: mw.col.sched.empty_filtered_deck(deck_id))
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,8 @@ from typing import Dict, Iterable, List, Optional, Tuple, cast
|
||||||
|
|
||||||
import aqt
|
import aqt
|
||||||
from anki.collection import Config, OpChanges, SearchJoiner, SearchNode
|
from anki.collection import Config, OpChanges, SearchJoiner, SearchNode
|
||||||
from anki.decks import DeckID, DeckTreeNode
|
from anki.decks import DeckId, DeckTreeNode
|
||||||
from anki.models import NoteTypeID
|
from anki.models import NoteTypeId
|
||||||
from anki.notes import Note
|
from anki.notes import Note
|
||||||
from anki.tags import TagTreeNode
|
from anki.tags import TagTreeNode
|
||||||
from anki.types import assert_exhaustive
|
from anki.types import assert_exhaustive
|
||||||
|
@ -594,14 +594,14 @@ class SidebarTreeView(QTreeView):
|
||||||
self, sources: List[SidebarItem], target: SidebarItem
|
self, sources: List[SidebarItem], target: SidebarItem
|
||||||
) -> bool:
|
) -> bool:
|
||||||
deck_ids = [
|
deck_ids = [
|
||||||
DeckID(source.id)
|
DeckId(source.id)
|
||||||
for source in sources
|
for source in sources
|
||||||
if source.item_type == SidebarItemType.DECK
|
if source.item_type == SidebarItemType.DECK
|
||||||
]
|
]
|
||||||
if not deck_ids:
|
if not deck_ids:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
new_parent = DeckID(target.id)
|
new_parent = DeckId(target.id)
|
||||||
|
|
||||||
reparent_decks(
|
reparent_decks(
|
||||||
mw=self.mw, parent=self.browser, deck_ids=deck_ids, new_parent=new_parent
|
mw=self.mw, parent=self.browser, deck_ids=deck_ids, new_parent=new_parent
|
||||||
|
@ -968,7 +968,7 @@ class SidebarTreeView(QTreeView):
|
||||||
for node in nodes:
|
for node in nodes:
|
||||||
|
|
||||||
def toggle_expand() -> Callable[[bool], None]:
|
def toggle_expand() -> Callable[[bool], None]:
|
||||||
did = DeckID(node.deck_id) # pylint: disable=cell-var-from-loop
|
did = DeckId(node.deck_id) # pylint: disable=cell-var-from-loop
|
||||||
return lambda _: self.mw.col.decks.collapseBrowser(did)
|
return lambda _: self.mw.col.decks.collapseBrowser(did)
|
||||||
|
|
||||||
item = SidebarItem(
|
item = SidebarItem(
|
||||||
|
@ -1148,7 +1148,7 @@ class SidebarTreeView(QTreeView):
|
||||||
###########################
|
###########################
|
||||||
|
|
||||||
def rename_deck(self, item: SidebarItem, new_name: str) -> None:
|
def rename_deck(self, item: SidebarItem, new_name: str) -> None:
|
||||||
deck = self.mw.col.decks.get(DeckID(item.id))
|
deck = self.mw.col.decks.get(DeckId(item.id))
|
||||||
if not new_name:
|
if not new_name:
|
||||||
return
|
return
|
||||||
new_name = item.name_prefix + new_name
|
new_name = item.name_prefix + new_name
|
||||||
|
@ -1157,7 +1157,7 @@ class SidebarTreeView(QTreeView):
|
||||||
|
|
||||||
rename_deck(
|
rename_deck(
|
||||||
mw=self.mw,
|
mw=self.mw,
|
||||||
deck_id=DeckID(item.id),
|
deck_id=DeckId(item.id),
|
||||||
new_name=new_name,
|
new_name=new_name,
|
||||||
after_rename=lambda: self.refresh(
|
after_rename=lambda: self.refresh(
|
||||||
lambda other: other.item_type == SidebarItemType.DECK
|
lambda other: other.item_type == SidebarItemType.DECK
|
||||||
|
@ -1284,11 +1284,11 @@ class SidebarTreeView(QTreeView):
|
||||||
self.mw,
|
self.mw,
|
||||||
parent=self.browser,
|
parent=self.browser,
|
||||||
fromMain=True,
|
fromMain=True,
|
||||||
selected_notetype_id=NoteTypeID(item.id),
|
selected_notetype_id=NoteTypeId(item.id),
|
||||||
)
|
)
|
||||||
|
|
||||||
def manage_template(self, item: SidebarItem) -> None:
|
def manage_template(self, item: SidebarItem) -> None:
|
||||||
note = Note(self.col, self.col.models.get(NoteTypeID(item._parent_item.id)))
|
note = Note(self.col, self.col.models.get(NoteTypeId(item._parent_item.id)))
|
||||||
CardLayout(self.mw, note, ord=item.id, parent=self, fill_empty=True)
|
CardLayout(self.mw, note, ord=item.id, parent=self, fill_empty=True)
|
||||||
|
|
||||||
# Helpers
|
# Helpers
|
||||||
|
@ -1297,9 +1297,9 @@ class SidebarTreeView(QTreeView):
|
||||||
def _selected_items(self) -> List[SidebarItem]:
|
def _selected_items(self) -> List[SidebarItem]:
|
||||||
return [self.model().item_for_index(idx) for idx in self.selectedIndexes()]
|
return [self.model().item_for_index(idx) for idx in self.selectedIndexes()]
|
||||||
|
|
||||||
def _selected_decks(self) -> List[DeckID]:
|
def _selected_decks(self) -> List[DeckId]:
|
||||||
return [
|
return [
|
||||||
DeckID(item.id)
|
DeckId(item.id)
|
||||||
for item in self._selected_items()
|
for item in self._selected_items()
|
||||||
if item.item_type == SidebarItemType.DECK
|
if item.item_type == SidebarItemType.DECK
|
||||||
]
|
]
|
||||||
|
|
|
@ -4,8 +4,8 @@
|
||||||
from typing import List, Optional
|
from typing import List, Optional
|
||||||
|
|
||||||
import aqt
|
import aqt
|
||||||
from anki.collection import OpChangesWithID
|
from anki.collection import OpChangesWithId
|
||||||
from anki.decks import DeckID
|
from anki.decks import DeckId
|
||||||
from aqt import gui_hooks
|
from aqt import gui_hooks
|
||||||
from aqt.deck_ops import add_deck_dialog
|
from aqt.deck_ops import add_deck_dialog
|
||||||
from aqt.qt import *
|
from aqt.qt import *
|
||||||
|
@ -166,8 +166,8 @@ class StudyDeck(QDialog):
|
||||||
else:
|
else:
|
||||||
default = self.names[self.form.list.currentRow()]
|
default = self.names[self.form.list.currentRow()]
|
||||||
|
|
||||||
def success(out: OpChangesWithID) -> None:
|
def success(out: OpChangesWithId) -> None:
|
||||||
deck = self.mw.col.decks.get(DeckID(out.id))
|
deck = self.mw.col.decks.get(DeckId(out.id))
|
||||||
self.name = deck["name"]
|
self.name = deck["name"]
|
||||||
|
|
||||||
# make sure we clean up reset hook when manually exiting
|
# make sure we clean up reset hook when manually exiting
|
||||||
|
|
|
@ -6,7 +6,7 @@ from __future__ import annotations
|
||||||
from typing import Callable, Sequence
|
from typing import Callable, Sequence
|
||||||
|
|
||||||
from anki.collection import OpChangesWithCount
|
from anki.collection import OpChangesWithCount
|
||||||
from anki.notes import NoteID
|
from anki.notes import NoteId
|
||||||
from aqt import AnkiQt, QWidget
|
from aqt import AnkiQt, QWidget
|
||||||
from aqt.main import PerformOpOptionalSuccessCallback
|
from aqt.main import PerformOpOptionalSuccessCallback
|
||||||
from aqt.utils import showInfo, tooltip, tr
|
from aqt.utils import showInfo, tooltip, tr
|
||||||
|
@ -15,7 +15,7 @@ from aqt.utils import showInfo, tooltip, tr
|
||||||
def add_tags(
|
def add_tags(
|
||||||
*,
|
*,
|
||||||
mw: AnkiQt,
|
mw: AnkiQt,
|
||||||
note_ids: Sequence[NoteID],
|
note_ids: Sequence[NoteId],
|
||||||
space_separated_tags: str,
|
space_separated_tags: str,
|
||||||
success: PerformOpOptionalSuccessCallback = None,
|
success: PerformOpOptionalSuccessCallback = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
|
@ -27,7 +27,7 @@ def add_tags(
|
||||||
def remove_tags_for_notes(
|
def remove_tags_for_notes(
|
||||||
*,
|
*,
|
||||||
mw: AnkiQt,
|
mw: AnkiQt,
|
||||||
note_ids: Sequence[NoteID],
|
note_ids: Sequence[NoteId],
|
||||||
space_separated_tags: str,
|
space_separated_tags: str,
|
||||||
success: PerformOpOptionalSuccessCallback = None,
|
success: PerformOpOptionalSuccessCallback = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
|
|
|
@ -50,7 +50,7 @@ message OpChangesWithCount {
|
||||||
OpChanges changes = 2;
|
OpChanges changes = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message OpChangesWithID {
|
message OpChangesWithId {
|
||||||
int64 id = 1;
|
int64 id = 1;
|
||||||
OpChanges changes = 2;
|
OpChanges changes = 2;
|
||||||
}
|
}
|
||||||
|
@ -58,31 +58,31 @@ message OpChangesWithID {
|
||||||
// IDs used in RPC calls
|
// IDs used in RPC calls
|
||||||
///////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////
|
||||||
|
|
||||||
message NoteTypeID {
|
message NoteTypeId {
|
||||||
int64 ntid = 1;
|
int64 ntid = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message NoteID {
|
message NoteId {
|
||||||
int64 nid = 1;
|
int64 nid = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message CardID {
|
message CardId {
|
||||||
int64 cid = 1;
|
int64 cid = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message CardIDs {
|
message CardIds {
|
||||||
repeated int64 cids = 1;
|
repeated int64 cids = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message DeckID {
|
message DeckId {
|
||||||
int64 did = 1;
|
int64 did = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message DeckIDs {
|
message DeckIds {
|
||||||
repeated int64 dids = 1;
|
repeated int64 dids = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message DeckConfigID {
|
message DeckConfigId {
|
||||||
int64 dcid = 1;
|
int64 dcid = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,18 +116,18 @@ service SchedulingService {
|
||||||
rpc StudiedTodayMessage(StudiedTodayMessageIn) returns (String);
|
rpc StudiedTodayMessage(StudiedTodayMessageIn) returns (String);
|
||||||
rpc UpdateStats(UpdateStatsIn) returns (Empty);
|
rpc UpdateStats(UpdateStatsIn) returns (Empty);
|
||||||
rpc ExtendLimits(ExtendLimitsIn) returns (Empty);
|
rpc ExtendLimits(ExtendLimitsIn) returns (Empty);
|
||||||
rpc CountsForDeckToday(DeckID) returns (CountsForDeckTodayOut);
|
rpc CountsForDeckToday(DeckId) returns (CountsForDeckTodayOut);
|
||||||
rpc CongratsInfo(Empty) returns (CongratsInfoOut);
|
rpc CongratsInfo(Empty) returns (CongratsInfoOut);
|
||||||
rpc RestoreBuriedAndSuspendedCards(CardIDs) returns (OpChanges);
|
rpc RestoreBuriedAndSuspendedCards(CardIds) returns (OpChanges);
|
||||||
rpc UnburyCardsInCurrentDeck(UnburyCardsInCurrentDeckIn) returns (Empty);
|
rpc UnburyCardsInCurrentDeck(UnburyCardsInCurrentDeckIn) returns (Empty);
|
||||||
rpc BuryOrSuspendCards(BuryOrSuspendCardsIn) returns (OpChanges);
|
rpc BuryOrSuspendCards(BuryOrSuspendCardsIn) returns (OpChanges);
|
||||||
rpc EmptyFilteredDeck(DeckID) returns (OpChanges);
|
rpc EmptyFilteredDeck(DeckId) returns (OpChanges);
|
||||||
rpc RebuildFilteredDeck(DeckID) returns (OpChangesWithCount);
|
rpc RebuildFilteredDeck(DeckId) returns (OpChangesWithCount);
|
||||||
rpc ScheduleCardsAsNew(ScheduleCardsAsNewIn) returns (OpChanges);
|
rpc ScheduleCardsAsNew(ScheduleCardsAsNewIn) returns (OpChanges);
|
||||||
rpc SetDueDate(SetDueDateIn) returns (OpChanges);
|
rpc SetDueDate(SetDueDateIn) returns (OpChanges);
|
||||||
rpc SortCards(SortCardsIn) returns (OpChangesWithCount);
|
rpc SortCards(SortCardsIn) returns (OpChangesWithCount);
|
||||||
rpc SortDeck(SortDeckIn) returns (OpChangesWithCount);
|
rpc SortDeck(SortDeckIn) returns (OpChangesWithCount);
|
||||||
rpc GetNextCardStates(CardID) returns (NextCardStates);
|
rpc GetNextCardStates(CardId) returns (NextCardStates);
|
||||||
rpc DescribeNextStates(NextCardStates) returns (StringList);
|
rpc DescribeNextStates(NextCardStates) returns (StringList);
|
||||||
rpc StateIsLeech(SchedulingState) returns (Bool);
|
rpc StateIsLeech(SchedulingState) returns (Bool);
|
||||||
rpc AnswerCard(AnswerCardIn) returns (OpChanges);
|
rpc AnswerCard(AnswerCardIn) returns (OpChanges);
|
||||||
|
@ -136,35 +136,35 @@ service SchedulingService {
|
||||||
}
|
}
|
||||||
|
|
||||||
service DecksService {
|
service DecksService {
|
||||||
rpc AddDeckLegacy(Json) returns (OpChangesWithID);
|
rpc AddDeckLegacy(Json) returns (OpChangesWithId);
|
||||||
rpc AddOrUpdateDeckLegacy(AddOrUpdateDeckLegacyIn) returns (DeckID);
|
rpc AddOrUpdateDeckLegacy(AddOrUpdateDeckLegacyIn) returns (DeckId);
|
||||||
rpc DeckTree(DeckTreeIn) returns (DeckTreeNode);
|
rpc DeckTree(DeckTreeIn) returns (DeckTreeNode);
|
||||||
rpc DeckTreeLegacy(Empty) returns (Json);
|
rpc DeckTreeLegacy(Empty) returns (Json);
|
||||||
rpc GetAllDecksLegacy(Empty) returns (Json);
|
rpc GetAllDecksLegacy(Empty) returns (Json);
|
||||||
rpc GetDeckIDByName(String) returns (DeckID);
|
rpc GetDeckIdByName(String) returns (DeckId);
|
||||||
rpc GetDeckLegacy(DeckID) returns (Json);
|
rpc GetDeckLegacy(DeckId) returns (Json);
|
||||||
rpc GetDeckNames(GetDeckNamesIn) returns (DeckNames);
|
rpc GetDeckNames(GetDeckNamesIn) returns (DeckNames);
|
||||||
rpc NewDeckLegacy(Bool) returns (Json);
|
rpc NewDeckLegacy(Bool) returns (Json);
|
||||||
rpc RemoveDecks(DeckIDs) returns (OpChangesWithCount);
|
rpc RemoveDecks(DeckIds) returns (OpChangesWithCount);
|
||||||
rpc ReparentDecks(ReparentDecksIn) returns (OpChangesWithCount);
|
rpc ReparentDecks(ReparentDecksIn) returns (OpChangesWithCount);
|
||||||
rpc RenameDeck(RenameDeckIn) returns (OpChanges);
|
rpc RenameDeck(RenameDeckIn) returns (OpChanges);
|
||||||
rpc GetOrCreateFilteredDeck(DeckID) returns (FilteredDeckForUpdate);
|
rpc GetOrCreateFilteredDeck(DeckId) returns (FilteredDeckForUpdate);
|
||||||
rpc AddOrUpdateFilteredDeck(FilteredDeckForUpdate) returns (OpChangesWithID);
|
rpc AddOrUpdateFilteredDeck(FilteredDeckForUpdate) returns (OpChangesWithId);
|
||||||
}
|
}
|
||||||
|
|
||||||
service NotesService {
|
service NotesService {
|
||||||
rpc NewNote(NoteTypeID) returns (Note);
|
rpc NewNote(NoteTypeId) returns (Note);
|
||||||
rpc AddNote(AddNoteIn) returns (AddNoteOut);
|
rpc AddNote(AddNoteIn) returns (AddNoteOut);
|
||||||
rpc DefaultsForAdding(DefaultsForAddingIn) returns (DeckAndNotetype);
|
rpc DefaultsForAdding(DefaultsForAddingIn) returns (DeckAndNotetype);
|
||||||
rpc DefaultDeckForNotetype(NoteTypeID) returns (DeckID);
|
rpc DefaultDeckForNotetype(NoteTypeId) returns (DeckId);
|
||||||
rpc UpdateNote(UpdateNoteIn) returns (OpChanges);
|
rpc UpdateNote(UpdateNoteIn) returns (OpChanges);
|
||||||
rpc GetNote(NoteID) returns (Note);
|
rpc GetNote(NoteId) returns (Note);
|
||||||
rpc RemoveNotes(RemoveNotesIn) returns (OpChanges);
|
rpc RemoveNotes(RemoveNotesIn) returns (OpChanges);
|
||||||
rpc ClozeNumbersInNote(Note) returns (ClozeNumbersInNoteOut);
|
rpc ClozeNumbersInNote(Note) returns (ClozeNumbersInNoteOut);
|
||||||
rpc AfterNoteUpdates(AfterNoteUpdatesIn) returns (OpChanges);
|
rpc AfterNoteUpdates(AfterNoteUpdatesIn) returns (OpChanges);
|
||||||
rpc FieldNamesForNotes(FieldNamesForNotesIn) returns (FieldNamesForNotesOut);
|
rpc FieldNamesForNotes(FieldNamesForNotesIn) returns (FieldNamesForNotesOut);
|
||||||
rpc NoteIsDuplicateOrEmpty(Note) returns (NoteIsDuplicateOrEmptyOut);
|
rpc NoteIsDuplicateOrEmpty(Note) returns (NoteIsDuplicateOrEmptyOut);
|
||||||
rpc CardsOfNote(NoteID) returns (CardIDs);
|
rpc CardsOfNote(NoteId) returns (CardIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
service SyncService {
|
service SyncService {
|
||||||
|
@ -194,13 +194,13 @@ service ConfigService {
|
||||||
}
|
}
|
||||||
|
|
||||||
service NoteTypesService {
|
service NoteTypesService {
|
||||||
rpc AddOrUpdateNotetype(AddOrUpdateNotetypeIn) returns (NoteTypeID);
|
rpc AddOrUpdateNotetype(AddOrUpdateNotetypeIn) returns (NoteTypeId);
|
||||||
rpc GetStockNotetypeLegacy(StockNoteType) returns (Json);
|
rpc GetStockNotetypeLegacy(StockNoteType) returns (Json);
|
||||||
rpc GetNotetypeLegacy(NoteTypeID) returns (Json);
|
rpc GetNotetypeLegacy(NoteTypeId) returns (Json);
|
||||||
rpc GetNotetypeNames(Empty) returns (NoteTypeNames);
|
rpc GetNotetypeNames(Empty) returns (NoteTypeNames);
|
||||||
rpc GetNotetypeNamesAndCounts(Empty) returns (NoteTypeUseCounts);
|
rpc GetNotetypeNamesAndCounts(Empty) returns (NoteTypeUseCounts);
|
||||||
rpc GetNotetypeIDByName(String) returns (NoteTypeID);
|
rpc GetNotetypeIdByName(String) returns (NoteTypeId);
|
||||||
rpc RemoveNotetype(NoteTypeID) returns (Empty);
|
rpc RemoveNotetype(NoteTypeId) returns (Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
service CardRenderingService {
|
service CardRenderingService {
|
||||||
|
@ -215,11 +215,11 @@ service CardRenderingService {
|
||||||
|
|
||||||
service DeckConfigService {
|
service DeckConfigService {
|
||||||
rpc AddOrUpdateDeckConfigLegacy(AddOrUpdateDeckConfigLegacyIn)
|
rpc AddOrUpdateDeckConfigLegacy(AddOrUpdateDeckConfigLegacyIn)
|
||||||
returns (DeckConfigID);
|
returns (DeckConfigId);
|
||||||
rpc AllDeckConfigLegacy(Empty) returns (Json);
|
rpc AllDeckConfigLegacy(Empty) returns (Json);
|
||||||
rpc GetDeckConfigLegacy(DeckConfigID) returns (Json);
|
rpc GetDeckConfigLegacy(DeckConfigId) returns (Json);
|
||||||
rpc NewDeckConfigLegacy(Empty) returns (Json);
|
rpc NewDeckConfigLegacy(Empty) returns (Json);
|
||||||
rpc RemoveDeckConfig(DeckConfigID) returns (Empty);
|
rpc RemoveDeckConfig(DeckConfigId) returns (Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
service TagsService {
|
service TagsService {
|
||||||
|
@ -230,8 +230,8 @@ service TagsService {
|
||||||
rpc TagTree(Empty) returns (TagTreeNode);
|
rpc TagTree(Empty) returns (TagTreeNode);
|
||||||
rpc ReparentTags(ReparentTagsIn) returns (OpChangesWithCount);
|
rpc ReparentTags(ReparentTagsIn) returns (OpChangesWithCount);
|
||||||
rpc RenameTags(RenameTagsIn) returns (OpChangesWithCount);
|
rpc RenameTags(RenameTagsIn) returns (OpChangesWithCount);
|
||||||
rpc AddNoteTags(NoteIDsAndTagsIn) returns (OpChangesWithCount);
|
rpc AddNoteTags(NoteIdsAndTagsIn) returns (OpChangesWithCount);
|
||||||
rpc RemoveNoteTags(NoteIDsAndTagsIn) returns (OpChangesWithCount);
|
rpc RemoveNoteTags(NoteIdsAndTagsIn) returns (OpChangesWithCount);
|
||||||
rpc FindAndReplaceTag(FindAndReplaceTagIn) returns (OpChangesWithCount);
|
rpc FindAndReplaceTag(FindAndReplaceTagIn) returns (OpChangesWithCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -242,11 +242,11 @@ service SearchService {
|
||||||
rpc JoinSearchNodes(JoinSearchNodesIn) returns (String);
|
rpc JoinSearchNodes(JoinSearchNodesIn) returns (String);
|
||||||
rpc ReplaceSearchNode(ReplaceSearchNodeIn) returns (String);
|
rpc ReplaceSearchNode(ReplaceSearchNodeIn) returns (String);
|
||||||
rpc FindAndReplace(FindAndReplaceIn) returns (OpChangesWithCount);
|
rpc FindAndReplace(FindAndReplaceIn) returns (OpChangesWithCount);
|
||||||
rpc BrowserRowForCard(CardID) returns (BrowserRow);
|
rpc BrowserRowForCard(CardId) returns (BrowserRow);
|
||||||
}
|
}
|
||||||
|
|
||||||
service StatsService {
|
service StatsService {
|
||||||
rpc CardStats(CardID) returns (String);
|
rpc CardStats(CardId) returns (String);
|
||||||
rpc Graphs(GraphsIn) returns (GraphsOut);
|
rpc Graphs(GraphsIn) returns (GraphsOut);
|
||||||
rpc GetGraphPreferences(Empty) returns (GraphPreferences);
|
rpc GetGraphPreferences(Empty) returns (GraphPreferences);
|
||||||
rpc SetGraphPreferences(GraphPreferences) returns (Empty);
|
rpc SetGraphPreferences(GraphPreferences) returns (Empty);
|
||||||
|
@ -278,7 +278,7 @@ service CollectionService {
|
||||||
}
|
}
|
||||||
|
|
||||||
service CardsService {
|
service CardsService {
|
||||||
rpc GetCard(CardID) returns (Card);
|
rpc GetCard(CardId) returns (Card);
|
||||||
rpc UpdateCard(UpdateCardIn) returns (OpChanges);
|
rpc UpdateCard(UpdateCardIn) returns (OpChanges);
|
||||||
rpc RemoveCards(RemoveCardsIn) returns (Empty);
|
rpc RemoveCards(RemoveCardsIn) returns (Empty);
|
||||||
rpc SetDeck(SetDeckIn) returns (OpChanges);
|
rpc SetDeck(SetDeckIn) returns (OpChanges);
|
||||||
|
@ -970,19 +970,19 @@ message StockNoteType {
|
||||||
}
|
}
|
||||||
|
|
||||||
message NoteTypeNames {
|
message NoteTypeNames {
|
||||||
repeated NoteTypeNameID entries = 1;
|
repeated NoteTypeNameId entries = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message NoteTypeUseCounts {
|
message NoteTypeUseCounts {
|
||||||
repeated NoteTypeNameIDUseCount entries = 1;
|
repeated NoteTypeNameIdUseCount entries = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message NoteTypeNameID {
|
message NoteTypeNameId {
|
||||||
int64 id = 1;
|
int64 id = 1;
|
||||||
string name = 2;
|
string name = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message NoteTypeNameIDUseCount {
|
message NoteTypeNameIdUseCount {
|
||||||
int64 id = 1;
|
int64 id = 1;
|
||||||
string name = 2;
|
string name = 2;
|
||||||
uint32 use_count = 3;
|
uint32 use_count = 3;
|
||||||
|
@ -1024,10 +1024,10 @@ message EmptyCardsReport {
|
||||||
}
|
}
|
||||||
|
|
||||||
message DeckNames {
|
message DeckNames {
|
||||||
repeated DeckNameID entries = 1;
|
repeated DeckNameId entries = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message DeckNameID {
|
message DeckNameId {
|
||||||
int64 id = 1;
|
int64 id = 1;
|
||||||
string name = 2;
|
string name = 2;
|
||||||
}
|
}
|
||||||
|
@ -1080,7 +1080,7 @@ message AfterNoteUpdatesIn {
|
||||||
bool generate_cards = 3;
|
bool generate_cards = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
message NoteIDsAndTagsIn {
|
message NoteIdsAndTagsIn {
|
||||||
repeated int64 note_ids = 1;
|
repeated int64 note_ids = 1;
|
||||||
string tags = 2;
|
string tags = 2;
|
||||||
}
|
}
|
||||||
|
|
|
@ -119,7 +119,7 @@ impl DecksService for Backend {
|
||||||
.map(Into::into)
|
.map(Into::into)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_decks(&self, input: pb::DeckIDs) -> Result<pb::OpChangesWithCount> {
|
fn remove_decks(&self, input: pb::DeckIds) -> Result<pb::OpChangesWithCount> {
|
||||||
self.with_col(|col| col.remove_decks_and_child_decks(&Into::<Vec<DeckId>>::into(input)))
|
self.with_col(|col| col.remove_decks_and_child_decks(&Into::<Vec<DeckId>>::into(input)))
|
||||||
.map(Into::into)
|
.map(Into::into)
|
||||||
}
|
}
|
||||||
|
@ -161,8 +161,8 @@ impl From<pb::DeckId> for DeckId {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<pb::DeckIDs> for Vec<DeckId> {
|
impl From<pb::DeckIds> for Vec<DeckId> {
|
||||||
fn from(dids: pb::DeckIDs) -> Self {
|
fn from(dids: pb::DeckIds) -> Self {
|
||||||
dids.dids.into_iter().map(DeckId).collect()
|
dids.dids.into_iter().map(DeckId).collect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,8 +51,8 @@ impl From<pb::CardId> for CardId {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<pb::CardIDs> for Vec<CardId> {
|
impl From<pb::CardIds> for Vec<CardId> {
|
||||||
fn from(c: pb::CardIDs) -> Self {
|
fn from(c: pb::CardIds) -> Self {
|
||||||
c.cids.into_iter().map(CardId).collect()
|
c.cids.into_iter().map(CardId).collect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -128,11 +128,11 @@ impl NotesService for Backend {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cards_of_note(&self, input: pb::NoteId) -> Result<pb::CardIDs> {
|
fn cards_of_note(&self, input: pb::NoteId) -> Result<pb::CardIds> {
|
||||||
self.with_col(|col| {
|
self.with_col(|col| {
|
||||||
col.storage
|
col.storage
|
||||||
.all_card_ids_of_note(NoteId(input.nid))
|
.all_card_ids_of_note(NoteId(input.nid))
|
||||||
.map(|v| pb::CardIDs {
|
.map(|v| pb::CardIds {
|
||||||
cids: v.into_iter().map(Into::into).collect(),
|
cids: v.into_iter().map(Into::into).collect(),
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -72,7 +72,7 @@ impl SchedulingService for Backend {
|
||||||
self.with_col(|col| col.congrats_info())
|
self.with_col(|col| col.congrats_info())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn restore_buried_and_suspended_cards(&self, input: pb::CardIDs) -> Result<pb::OpChanges> {
|
fn restore_buried_and_suspended_cards(&self, input: pb::CardIds) -> Result<pb::OpChanges> {
|
||||||
let cids: Vec<_> = input.into();
|
let cids: Vec<_> = input.into();
|
||||||
self.with_col(|col| col.unbury_or_unsuspend_cards(&cids).map(Into::into))
|
self.with_col(|col| col.unbury_or_unsuspend_cards(&cids).map(Into::into))
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,14 +56,14 @@ impl TagsService for Backend {
|
||||||
.map(Into::into)
|
.map(Into::into)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_note_tags(&self, input: pb::NoteIDsAndTagsIn) -> Result<pb::OpChangesWithCount> {
|
fn add_note_tags(&self, input: pb::NoteIdsAndTagsIn) -> Result<pb::OpChangesWithCount> {
|
||||||
self.with_col(|col| {
|
self.with_col(|col| {
|
||||||
col.add_tags_to_notes(&to_note_ids(input.note_ids), &input.tags)
|
col.add_tags_to_notes(&to_note_ids(input.note_ids), &input.tags)
|
||||||
.map(Into::into)
|
.map(Into::into)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_note_tags(&self, input: pb::NoteIDsAndTagsIn) -> Result<pb::OpChangesWithCount> {
|
fn remove_note_tags(&self, input: pb::NoteIdsAndTagsIn) -> Result<pb::OpChangesWithCount> {
|
||||||
self.with_col(|col| {
|
self.with_col(|col| {
|
||||||
col.remove_tags_from_notes(&to_note_ids(input.note_ids), &input.tags)
|
col.remove_tags_from_notes(&to_note_ids(input.note_ids), &input.tags)
|
||||||
.map(Into::into)
|
.map(Into::into)
|
||||||
|
|
|
@ -210,7 +210,7 @@ mod test {
|
||||||
assert_eq!(sorter.position(&c2), 1);
|
assert_eq!(sorter.position(&c2), 1);
|
||||||
assert_eq!(sorter.position(&c3), 2);
|
assert_eq!(sorter.position(&c3), 2);
|
||||||
|
|
||||||
// NoteID/step/starting
|
// NoteId/step/starting
|
||||||
let sorter = NewCardSorter::new(&cards, 3, 2, NewCardSortOrder::NoteId);
|
let sorter = NewCardSorter::new(&cards, 3, 2, NewCardSortOrder::NoteId);
|
||||||
assert_eq!(sorter.position(&c3), 3);
|
assert_eq!(sorter.position(&c3), 3);
|
||||||
assert_eq!(sorter.position(&c2), 5);
|
assert_eq!(sorter.position(&c2), 5);
|
||||||
|
|
Loading…
Reference in a new issue