mirror of
https://github.com/ankitects/anki.git
synced 2025-09-18 14:02:21 -04:00
switch to new deck tree in deck browser
Saves us having to look up collapsed/filtered as we render, and gives us type completion.
This commit is contained in:
parent
75d3eebafe
commit
f2086fc2e3
5 changed files with 69 additions and 44 deletions
|
@ -264,6 +264,8 @@ message DeckTreeNode {
|
|||
uint32 review_count = 6;
|
||||
uint32 learn_count = 7;
|
||||
uint32 new_count = 8;
|
||||
|
||||
bool filtered = 16;
|
||||
}
|
||||
|
||||
message RenderExistingCardIn {
|
||||
|
|
|
@ -15,7 +15,7 @@ from anki import hooks
|
|||
from anki.cards import Card
|
||||
from anki.consts import *
|
||||
from anki.lang import _
|
||||
from anki.rsbackend import FormatTimeSpanContext, SchedTimingToday
|
||||
from anki.rsbackend import DeckTreeNode, FormatTimeSpanContext, SchedTimingToday
|
||||
from anki.utils import ids2str, intTime
|
||||
|
||||
# card types: 0=new, 1=lrn, 2=rev, 3=relrn
|
||||
|
@ -232,6 +232,10 @@ order by due"""
|
|||
"List of (base name, did, rev, lrn, new, children)"
|
||||
return self.col.backend.legacy_deck_tree()
|
||||
|
||||
def deck_due_tree(self) -> DeckTreeNode:
|
||||
"Returns a tree of decks with counts."
|
||||
return self.col.backend.deck_tree(include_counts=True)
|
||||
|
||||
# Getting the next card
|
||||
##########################################################################
|
||||
|
||||
|
|
|
@ -6,12 +6,11 @@ from __future__ import annotations
|
|||
|
||||
from copy import deepcopy
|
||||
from dataclasses import dataclass
|
||||
from typing import Any
|
||||
|
||||
import aqt
|
||||
from anki.errors import DeckRenameError
|
||||
from anki.lang import _, ngettext
|
||||
from anki.rsbackend import TR
|
||||
from anki.rsbackend import TR, DeckTreeNode
|
||||
from anki.utils import ids2str
|
||||
from aqt import AnkiQt, gui_hooks
|
||||
from aqt.qt import *
|
||||
|
@ -39,8 +38,13 @@ class DeckBrowserContent:
|
|||
stats: str
|
||||
|
||||
|
||||
@dataclass
|
||||
class RenderDeckNodeContext:
|
||||
current_deck_id: int
|
||||
|
||||
|
||||
class DeckBrowser:
|
||||
_dueTree: Any
|
||||
_dueTree: DeckTreeNode
|
||||
|
||||
def __init__(self, mw: AnkiQt) -> None:
|
||||
self.mw = mw
|
||||
|
@ -83,7 +87,7 @@ class DeckBrowser:
|
|||
draggedDeckDid, ontoDeckDid = arg.split(",")
|
||||
self._dragDeckOnto(draggedDeckDid, ontoDeckDid)
|
||||
elif cmd == "collapse":
|
||||
self._collapse(arg)
|
||||
self._collapse(int(arg))
|
||||
return False
|
||||
|
||||
def _selDeck(self, did):
|
||||
|
@ -106,7 +110,7 @@ class DeckBrowser:
|
|||
|
||||
def _renderPage(self, reuse=False):
|
||||
if not reuse:
|
||||
self._dueTree = self.mw.col.sched.deckDueTree()
|
||||
self._dueTree = self.mw.col.sched.deck_due_tree()
|
||||
self.__renderPage(None)
|
||||
return
|
||||
self.web.evalWithCallback("window.pageYOffset", self.__renderPage)
|
||||
|
@ -143,53 +147,49 @@ where id > ?""",
|
|||
buf = self.mw.col.backend.studied_today(cards, float(thetime))
|
||||
return buf
|
||||
|
||||
def _renderDeckTree(self, nodes, depth=0):
|
||||
if not nodes:
|
||||
return ""
|
||||
if depth == 0:
|
||||
buf = """
|
||||
def _renderDeckTree(self, top: DeckTreeNode) -> str:
|
||||
buf = """
|
||||
<tr><th colspan=5 align=left>%s</th><th class=count>%s</th>
|
||||
<th class=count>%s</th><th class=optscol></th></tr>""" % (
|
||||
_("Deck"),
|
||||
tr(TR.STATISTICS_DUE_COUNT),
|
||||
_("New"),
|
||||
)
|
||||
buf += self._topLevelDragRow()
|
||||
else:
|
||||
buf = ""
|
||||
for node in nodes:
|
||||
buf += self._deckRow(node, depth)
|
||||
if depth == 0:
|
||||
buf += self._topLevelDragRow()
|
||||
_("Deck"),
|
||||
tr(TR.STATISTICS_DUE_COUNT),
|
||||
_("New"),
|
||||
)
|
||||
buf += self._topLevelDragRow()
|
||||
|
||||
ctx = RenderDeckNodeContext(current_deck_id=self.mw.col.conf["curDeck"])
|
||||
|
||||
for child in top.children:
|
||||
buf += self._render_deck_node(child, ctx)
|
||||
|
||||
return buf
|
||||
|
||||
def _deckRow(self, node, depth):
|
||||
name, did, due, lrn, new, children = node
|
||||
deck = self.mw.col.decks.get(did)
|
||||
collapsed = self.mw.col.decks.get(did)["collapsed"]
|
||||
if collapsed:
|
||||
def _render_deck_node(self, node: DeckTreeNode, ctx: RenderDeckNodeContext) -> str:
|
||||
if node.collapsed:
|
||||
prefix = "+"
|
||||
else:
|
||||
prefix = "-"
|
||||
due += lrn
|
||||
|
||||
due = node.review_count + node.learn_count
|
||||
|
||||
def indent():
|
||||
return " " * 6 * depth
|
||||
return " " * 6 * (node.level - 1)
|
||||
|
||||
if did == self.mw.col.conf["curDeck"]:
|
||||
if node.deck_id == ctx.current_deck_id:
|
||||
klass = "deck current"
|
||||
else:
|
||||
klass = "deck"
|
||||
buf = "<tr class='%s' id='%d'>" % (klass, did)
|
||||
|
||||
buf = "<tr class='%s' id='%d'>" % (klass, node.deck_id)
|
||||
# deck link
|
||||
if children:
|
||||
if node.children:
|
||||
collapse = (
|
||||
"<a class=collapse href=# onclick='return pycmd(\"collapse:%d\")'>%s</a>"
|
||||
% (did, prefix)
|
||||
% (node.deck_id, prefix)
|
||||
)
|
||||
else:
|
||||
collapse = "<span class=collapse></span>"
|
||||
if deck["dyn"]:
|
||||
if node.filtered:
|
||||
extraclass = "filtered"
|
||||
else:
|
||||
extraclass = ""
|
||||
|
@ -200,8 +200,8 @@ where id > ?""",
|
|||
indent(),
|
||||
collapse,
|
||||
extraclass,
|
||||
did,
|
||||
name,
|
||||
node.deck_id,
|
||||
node.name,
|
||||
)
|
||||
# due counts
|
||||
def nonzeroColour(cnt, klass):
|
||||
|
@ -211,16 +211,17 @@ where id > ?""",
|
|||
|
||||
buf += "<td align=right>%s</td><td align=right>%s</td>" % (
|
||||
nonzeroColour(due, "review-count"),
|
||||
nonzeroColour(new, "new-count"),
|
||||
nonzeroColour(node.new_count, "new-count"),
|
||||
)
|
||||
# options
|
||||
buf += (
|
||||
"<td align=center class=opts><a onclick='return pycmd(\"opts:%d\");'>"
|
||||
"<img src='/_anki/imgs/gears.svg' class=gears></a></td></tr>" % did
|
||||
"<img src='/_anki/imgs/gears.svg' class=gears></a></td></tr>" % node.deck_id
|
||||
)
|
||||
# children
|
||||
if not collapsed:
|
||||
buf += self._renderDeckTree(children, depth + 1)
|
||||
if not node.collapsed:
|
||||
for child in node.children:
|
||||
buf += self._render_deck_node(child, ctx)
|
||||
return buf
|
||||
|
||||
def _topLevelDragRow(self):
|
||||
|
@ -265,10 +266,21 @@ where id > ?""",
|
|||
self.mw.col.decks.select(did)
|
||||
self.mw.onDeckConf()
|
||||
|
||||
def _collapse(self, did):
|
||||
def _collapse(self, did: int) -> None:
|
||||
self.mw.col.decks.collapse(did)
|
||||
self._toggle_collapsed_in_node(did, self._dueTree)
|
||||
self._renderPage(reuse=True)
|
||||
|
||||
def _toggle_collapsed_in_node(self, deck_id: int, node: DeckTreeNode) -> bool:
|
||||
"Toggle collapsed on deck in tree. Returns true if found."
|
||||
if node.deck_id == deck_id:
|
||||
node.collapsed = not node.collapsed
|
||||
return True
|
||||
for child in node.children:
|
||||
if self._toggle_collapsed_in_node(deck_id, child):
|
||||
return True
|
||||
return False
|
||||
|
||||
def _dragDeckOnto(self, draggedDeckDid, ontoDeckDid):
|
||||
try:
|
||||
self.mw.col.decks.renameForDragAndDrop(draggedDeckDid, ontoDeckDid)
|
||||
|
|
|
@ -62,3 +62,5 @@ check_untyped_defs=true
|
|||
check_untyped_defs=true
|
||||
[mypy-aqt.preferences]
|
||||
check_untyped_defs=true
|
||||
[mypy-aqt.deckbrowser]
|
||||
check_untyped_defs=true
|
||||
|
|
|
@ -62,16 +62,21 @@ fn add_child_nodes(
|
|||
}
|
||||
}
|
||||
|
||||
fn add_collapsed(node: &mut DeckTreeNode, decks: &HashMap<DeckID, Deck>, browser: bool) {
|
||||
fn add_collapsed_and_filtered(
|
||||
node: &mut DeckTreeNode,
|
||||
decks: &HashMap<DeckID, Deck>,
|
||||
browser: bool,
|
||||
) {
|
||||
if let Some(deck) = decks.get(&DeckID(node.deck_id)) {
|
||||
node.collapsed = if browser {
|
||||
deck.common.browser_collapsed
|
||||
} else {
|
||||
deck.common.study_collapsed
|
||||
};
|
||||
node.filtered = deck.is_filtered();
|
||||
}
|
||||
for child in &mut node.children {
|
||||
add_collapsed(child, decks, browser);
|
||||
add_collapsed_and_filtered(child, decks, browser);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -201,7 +206,7 @@ impl Collection {
|
|||
.map(|d| (d.id, d))
|
||||
.collect();
|
||||
|
||||
add_collapsed(&mut tree, &decks_map, !counts);
|
||||
add_collapsed_and_filtered(&mut tree, &decks_map, !counts);
|
||||
if self.default_deck_is_empty()? {
|
||||
hide_default_deck(&mut tree);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue