anki/qt/aqt/overview.py

292 lines
8.6 KiB
Python
Raw Normal View History

# -*- coding: utf-8 -*-
2019-02-05 04:59:03 +01:00
# Copyright: Ankitects Pty Ltd and contributors
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
from __future__ import annotations
2020-02-17 16:49:21 +01:00
from dataclasses import dataclass
from typing import Optional
2020-02-17 16:49:21 +01:00
import aqt
2019-03-04 02:58:34 +01:00
from anki.lang import _
from aqt import gui_hooks
from aqt.qt import QUrl
2020-01-20 11:10:38 +01:00
from aqt.sound import av_player
from aqt.theme import theme_manager
from aqt.toolbar import BottomBar
2019-12-20 10:19:03 +01:00
from aqt.utils import askUserDialog, openLink, shortcut, tooltip
class OverviewBottomBar:
def __init__(self, overview: Overview):
self.overview = overview
2020-02-17 16:49:21 +01:00
@dataclass
class OverviewContent:
2020-02-17 16:53:47 +01:00
"""Stores sections of HTML content that the overview will be
populated with.
Attributes:
deck {str} -- Plain text deck name
shareLink {str} -- HTML of the share link section
desc {str} -- HTML of the deck description section
table {str} -- HTML of the deck stats table section
"""
2020-02-17 16:49:21 +01:00
deck: str
shareLink: str
desc: str
table: str
class Overview:
"Deck overview."
def __init__(self, mw: aqt.AnkiQt) -> None:
self.mw = mw
self.web = mw.web
self.bottom = BottomBar(mw, mw.bottomWeb)
def show(self):
2020-01-20 11:10:38 +01:00
av_player.stop_and_clear_queue()
self.web.set_bridge_command(self._linkHandler, self)
self.mw.setStateShortcuts(self._shortcutKeys())
self.refresh()
def refresh(self):
self.mw.col.reset()
self._renderPage()
self._renderBottom()
self.mw.web.setFocus()
gui_hooks.overview_did_refresh(self)
# Handlers
############################################################
def _linkHandler(self, url):
if url == "study":
self.mw.col.startTimebox()
self.mw.moveToState("review")
2013-04-11 07:57:03 +02:00
if self.mw.state == "overview":
tooltip(_("No cards are due yet."))
elif url == "anki":
print("anki menu")
elif url == "opts":
self.mw.onDeckConf()
elif url == "cram":
deck = self.mw.col.decks.current()
2019-12-23 01:34:10 +01:00
self.mw.onCram("'deck:%s'" % deck["name"])
elif url == "refresh":
self.mw.col.sched.rebuildDyn()
self.mw.reset()
elif url == "empty":
self.mw.col.sched.emptyDyn(self.mw.col.decks.selected())
self.mw.reset()
elif url == "decks":
self.mw.moveToState("deckBrowser")
elif url == "review":
2019-12-23 01:34:10 +01:00
openLink(aqt.appShared + "info/%s?v=%s" % (self.sid, self.sidVer))
elif url == "studymore" or url == "customStudy":
self.onStudyMore()
elif url == "unbury":
self.onUnbury()
elif url.lower().startswith("http"):
openLink(url)
return False
def _shortcutKeys(self):
return [
("o", self.mw.onDeckConf),
("r", self.onRebuildKey),
("e", self.onEmptyKey),
("c", self.onCustomStudyKey),
2019-12-23 01:34:10 +01:00
("u", self.onUnbury),
]
def _filteredDeck(self):
2019-12-23 01:34:10 +01:00
return self.mw.col.decks.current()["dyn"]
def onRebuildKey(self):
if self._filteredDeck():
self.mw.col.sched.rebuildDyn()
self.mw.reset()
def onEmptyKey(self):
if self._filteredDeck():
self.mw.col.sched.emptyDyn(self.mw.col.decks.selected())
self.mw.reset()
def onCustomStudyKey(self):
if not self._filteredDeck():
self.onStudyMore()
def onUnbury(self):
2018-01-26 10:04:02 +01:00
if self.mw.col.schedVer() == 1:
self.mw.col.sched.unburyCardsForDeck()
self.mw.reset()
return
sibs = self.mw.col.sched.haveBuriedSiblings()
man = self.mw.col.sched.haveManuallyBuried()
if sibs and man:
2019-12-23 01:34:10 +01:00
opts = [
_("Manually Buried Cards"),
_("Buried Siblings"),
_("All Buried Cards"),
_("Cancel"),
]
diag = askUserDialog(_("What would you like to unbury?"), opts)
diag.setDefault(0)
ret = diag.run()
if ret == opts[0]:
self.mw.col.sched.unburyCardsForDeck(type="manual")
elif ret == opts[1]:
self.mw.col.sched.unburyCardsForDeck(type="siblings")
elif ret == opts[2]:
self.mw.col.sched.unburyCardsForDeck(type="all")
else:
self.mw.col.sched.unburyCardsForDeck(type="all")
self.mw.reset()
# HTML
############################################################
def _renderPage(self):
but = self.mw.button
deck = self.mw.col.decks.current()
self.sid = deck.get("sharedFrom")
if self.sid:
self.sidVer = deck.get("ver", None)
shareLink = '<a class=smallLink href="review">Reviews and Updates</a>'
else:
shareLink = ""
table_text = self._table()
if not table_text:
# deck is finished
self._show_finished_screen()
return
2020-02-17 16:49:21 +01:00
content = OverviewContent(
deck=deck["name"],
shareLink=shareLink,
desc=self._desc(deck),
table=self._table(),
)
gui_hooks.overview_will_render_content(self, content)
2019-12-23 01:34:10 +01:00
self.web.stdHtml(
2020-02-17 16:49:21 +01:00
self._body % content.__dict__,
css=["overview.css"],
js=["jquery.js", "overview.js"],
context=self,
2019-12-23 01:34:10 +01:00
)
def _show_finished_screen(self):
self.web.set_open_links_externally(False)
if theme_manager.night_mode:
extra = "#night"
else:
extra = ""
self.web.hide_while_preserving_layout()
self.web.load(QUrl(f"{self.mw.serverURL()}_anki/congrats.html" + extra))
self.web.inject_dynamic_style_and_show()
def _desc(self, deck):
2019-12-23 01:34:10 +01:00
if deck["dyn"]:
desc = _(
"""\
This is a special deck for studying outside of the normal schedule."""
)
desc += " " + _(
"""\
Cards will be automatically returned to their original decks after you review \
2019-12-23 01:34:10 +01:00
them."""
)
desc += " " + _(
"""\
Deleting this deck from the deck list will return all remaining cards \
2019-12-23 01:34:10 +01:00
to their original deck."""
)
else:
desc = deck.get("desc", "")
if not desc:
return "<p>"
2019-12-23 01:34:10 +01:00
if deck["dyn"]:
dyn = "dyn"
else:
dyn = ""
2019-12-23 01:34:10 +01:00
return '<div class="descfont descmid description %s">%s</div>' % (dyn, desc)
def _table(self) -> Optional[str]:
"Return table text if deck is not finished."
counts = list(self.mw.col.sched.counts())
finished = not sum(counts)
but = self.mw.button
if finished:
return None
else:
2019-12-23 01:34:10 +01:00
return """
<table width=400 cellpadding=5>
<tr><td align=center valign=top>
<table cellspacing=5>
<tr><td>%s:</td><td><b><span class=new-count>%s</span></b></td></tr>
<tr><td>%s:</td><td><b><span class=learn-count>%s</span></b></td></tr>
<tr><td>%s:</td><td><b><span class=review-count>%s</span></b></td></tr>
</table>
</td><td align=center>
2019-12-23 01:34:10 +01:00
%s</td></tr></table>""" % (
_("New"),
counts[0],
_("Learning"),
counts[1],
_("To Review"),
counts[2],
but("study", _("Study Now"), id="study", extra=" autofocus"),
)
_body = """
<center>
<h3>%(deck)s</h3>
%(shareLink)s
%(desc)s
%(table)s
</center>
"""
# Bottom area
######################################################################
def _renderBottom(self):
links = [
2013-02-20 07:27:42 +01:00
["O", "opts", _("Options")],
]
2019-12-23 01:34:10 +01:00
if self.mw.col.decks.current()["dyn"]:
links.append(["R", "refresh", _("Rebuild")])
links.append(["E", "empty", _("Empty")])
else:
links.append(["C", "studymore", _("Custom Study")])
2019-12-23 01:34:10 +01:00
# links.append(["F", "cram", _("Filter/Cram")])
if self.mw.col.sched.haveBuried():
links.append(["U", "unbury", _("Unbury")])
buf = ""
for b in links:
if b[0]:
b[0] = _("Shortcut key: %s") % shortcut(b[0])
buf += """
2019-12-23 01:34:10 +01:00
<button title="%s" onclick='pycmd("%s")'>%s</button>""" % tuple(
b
)
self.bottom.draw(
buf=buf, link_handler=self._linkHandler, web_context=OverviewBottomBar(self)
)
# Studying more
######################################################################
def onStudyMore(self):
import aqt.customstudy
2019-12-23 01:34:10 +01:00
aqt.customstudy.CustomStudy(self.mw)