-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path__init__.py
159 lines (134 loc) · 5.03 KB
/
__init__.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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
from typing import *
from anki.cards import Card
from aqt import gui_hooks
from aqt import mw, operations
from aqt import qconnect
from aqt.qt import QAction, QMessageBox
from aqt.utils import showInfo, tooltip
from .qwerty import *
import subprocess as sp
def error_times_to_ease(error_times: int, thresholds: List[int]) -> Literal[1, 2, 3, 4]:
ease: Literal[1, 2, 3, 4]
for threshold, ease in zip(thresholds, [1, 2, 3]):
if error_times >= threshold:
return ease
return 4
class Config:
thresholds: List[int]
command: Optional[str]
answer_field: str
def __init__(self, thresholds: List[int], command: str, answer_field: str):
if self.are_thresholds_valid(thresholds):
self.thresholds = thresholds
else:
raise ValueError
self.command = command
self.answer_field = answer_field
@staticmethod
def are_thresholds_valid(thresholds: List[int]) -> bool:
if len(thresholds) != 3:
return False
return thresholds[0] >= thresholds[1] >= thresholds[2]
class State:
config: Config
con: Optional[Connection]
is_enabled: bool
action: QAction
def __init__(self, config: Config):
self.is_enabled = False
self.config = config
self.action = QAction("Enable qwerty", mw)
self.con = None
def add_to_menu(self):
qconnect(self.action.triggered, lambda: State.toggle_enable(self))
mw.form.menuTools.addSeparator()
mw.form.menuTools.addAction(self.action)
def disable(self):
self.is_enabled = False
self.action.setText("Enable qwerty")
self.con.close()
self.con = None
gui_hooks.reviewer_did_show_question.remove(self.prompt_a_word)
def toggle_enable(self):
if not self.is_enabled:
try:
if self.con is None:
self.con = Connection()
self.is_enabled = True
self.action.setText("Enable qwerty ✓")
gui_hooks.reviewer_did_show_question.append(self.prompt_a_word)
gui_hooks.profile_will_close.append(self.con.close)
except (ConnectionRefusedError, FileNotFoundError):
open_button = QMessageBox.StandardButton(QMessageBox.Open)
cancel_button = QMessageBox.StandardButton(QMessageBox.Cancel)
result = showInfo(
"Cannot connect to qwerty. Open qwerty?",
title="qwerty addon",
customBtns=[open_button, cancel_button]
)
if result == QMessageBox.Open:
self.open_qwerty()
else:
self.disable()
def open_qwerty(self):
command = self.config.command
if command:
def toggle_after_some_time():
time.sleep(0.5)
self.toggle_enable()
try:
sp.Popen(command, shell=True)
op = operations.QueryOp(
op=lambda _: toggle_after_some_time(),
parent=mw.app.activeWindow(),
success=lambda _: tooltip("Connected.")
)
op.with_progress("Connecting...")
op.run_in_background()
except OSError:
showInfo("Failed to execute:\n"
f"{command}\n"
"Check your configuration.")
def communicate(self, word: str, _c: Collection):
self.con.send_word(word)
return self.con.receive_error_times()
def prompt_a_word(self, card: Card):
answer_field = self.config.answer_field
items = card.note().items()
for (k, v) in items:
if k == answer_field:
word = v
op = operations.QueryOp(op=lambda col: self.communicate(word, col),
success=self.answer_the_card,
parent=mw.app.activeWindow())
op.failure(self.on_failure)
op.run_in_background()
break
def on_failure(self, err):
msg = ""
if isinstance(err, OSError):
msg = "Failed to connect to qwerty.\n" \
"Maybe qwerty isn't running anymore."
if isinstance(err, ValueError):
msg = "Qwerty quits."
if self.is_enabled:
self.disable()
showInfo(
msg
+ "\nQwerty addon disabled."
"\nReturning to deck browser.",
title="qwerty addon",
)
mw.deckBrowser.show()
def answer_the_card(self, error_times):
mw.reviewer._showAnswer()
ease = error_times_to_ease(error_times, self.config.thresholds)
tooltip(f"Misspell times: {str(error_times)}\n"
f"Ease: {ease}")
mw.reviewer._answerCard(ease)
pass
def main():
config = Config(**mw.addonManager.getConfig(__name__))
state = State(config)
state.add_to_menu()
main()