-
-
Notifications
You must be signed in to change notification settings - Fork 5
/
top_toolbar.py
139 lines (115 loc) · 3.88 KB
/
top_toolbar.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# Copyright: Ren Tatsumoto <tatsu at autistici.org>
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
import time
from gettext import gettext as _
import aqt
from anki.cards import Card
from aqt import gui_hooks, mw
from aqt.reviewer import Reviewer
from aqt.toolbar import Toolbar
from .config import config
def handle_due(card: Card) -> str:
days = card.ivl
months = days / (365 / 12)
years = days / 365
if years >= 1:
return f"{years:.2f}y"
elif months >= 1:
return f"{months:.2f}mo"
else:
return f"{days:.0f}d"
def handle_learn(card: Card) -> str:
minutes = (card.due - time.time()) / 60
hours = minutes / 60
if minutes < 0:
return "unknown"
elif hours >= 1:
return f"{hours:.1f}h"
else:
return f"{minutes:.0f}m"
def human_ivl(card: Card) -> str:
# https://github.com/ankidroid/Anki-Android/wiki/Database-Structure
if card.queue <= -2:
return "buried"
elif card.queue == -1:
return "suspended"
elif card.queue == 1 and (card.type == 3 or card.type == 1):
return handle_learn(card)
elif card.queue == 3 and (card.type == 3 or card.type == 1):
return "tomorrow"
elif card.queue == 4:
return "preview"
elif card.type == 2:
return handle_due(card)
else:
return "unknown"
class LastEase:
_html_link_id = "last_ease"
_browser_query = ""
_last_default_ease = 0
@classmethod
def set_last_default_ease(cls, _: Card) -> None:
# noinspection PyProtectedMember
cls._last_default_ease = mw.reviewer._defaultEase()
@classmethod
def open_last_card(cls) -> None:
browser: aqt.browser = aqt.dialogs.open("Browser", mw)
browser.activateWindow()
browser.form.searchEdit.lineEdit().setText(cls._browser_query) # search_for
if hasattr(browser, "onSearch"):
browser.onSearch()
else:
browser.onSearchActivated()
@classmethod
def append_link(cls, links: list, toolbar: Toolbar) -> None:
link = toolbar.create_link(
cls._html_link_id,
"Last Ease",
cls.open_last_card,
id=cls._html_link_id,
tip="Last Ease",
)
links.insert(0, link)
@classmethod
def update(cls, reviewer: Reviewer, card: Card, ease: int) -> None:
"""Called after a card was answered."""
if config.show_last_review is False:
return
label = config.get_label(ease, cls._last_default_ease)
color = config.get_label_color(label)
status = f"{_(label)[:1]}: {human_ivl(card)}"
reviewer.mw.toolbar.web.eval(
"""\
{{
const elem = document.getElementById("{}");
elem.innerHTML = "{}";
elem.style.color = "{}";
elem.style.display = "inline";
}};
""".format(
cls._html_link_id, status, color
)
)
cls._browser_query = f"cid:{card.id}"
@classmethod
def hide(cls, _=None) -> None:
mw.toolbar.web.eval(
"""\
{
const elem = document.getElementById("%s");
elem.innerHTML = "";
elem.style.color = "";
elem.style.display = "none";
};
"""
% cls._html_link_id
)
def main():
# Remember if all 4 buttons are shown for the card.
gui_hooks.reviewer_did_show_question.append(LastEase.set_last_default_ease)
# When Reviewer is open, print the last card's stats on the top toolbar.
gui_hooks.top_toolbar_did_init_links.append(LastEase.append_link)
gui_hooks.reviewer_did_answer_card.append(LastEase.update)
# Don't show the last card's stats when Reviewer is not open.
gui_hooks.collection_did_load.append(LastEase.hide)
gui_hooks.reviewer_will_end.append(LastEase.hide)