mirror of
https://github.com/ankitects/anki.git
synced 2025-09-24 00:36:38 -04:00
Allow the user to configure answer keys (#2502)
* add methods that allow the user to configure answer keys * allow editing answer buttons in preferences * import optional * Give the layout referenced in code a clearer name (dae) * Update placeholder text and make it translatable (dae) The other items in the preferences screen don't have tooltips, so placeholder text may be easier for the user to discover than a tooltip.
This commit is contained in:
parent
f4f5844ca3
commit
a378e2923e
5 changed files with 50 additions and 10 deletions
|
@ -58,6 +58,7 @@ preferences-appearance = Appearance
|
||||||
preferences-general = General
|
preferences-general = General
|
||||||
preferences-style = Style
|
preferences-style = Style
|
||||||
preferences-review = Review
|
preferences-review = Review
|
||||||
|
preferences-answer-keys = Answer keys
|
||||||
preferences-distractions = Distractions
|
preferences-distractions = Distractions
|
||||||
preferences-minimalist-mode = Minimalist mode
|
preferences-minimalist-mode = Minimalist mode
|
||||||
preferences-editing = Editing
|
preferences-editing = Editing
|
||||||
|
@ -71,6 +72,7 @@ preferences-import-export = Import/Export
|
||||||
preferences-network-timeout = Network timeout
|
preferences-network-timeout = Network timeout
|
||||||
preferences-reset-window-sizes = Reset Window Sizes
|
preferences-reset-window-sizes = Reset Window Sizes
|
||||||
preferences-reset-window-sizes-complete = Window sizes and locations have been reset.
|
preferences-reset-window-sizes-complete = Window sizes and locations have been reset.
|
||||||
|
preferences-shortcut-placeholder = Enter an unused shortcut key, or leave empty to disable.
|
||||||
|
|
||||||
## NO NEED TO TRANSLATE. This text is no longer used by Anki, and will be removed in the future.
|
## NO NEED TO TRANSLATE. This text is no longer used by Anki, and will be removed in the future.
|
||||||
|
|
||||||
|
|
|
@ -245,7 +245,7 @@
|
||||||
<attribute name="title">
|
<attribute name="title">
|
||||||
<string>preferences_review</string>
|
<string>preferences_review</string>
|
||||||
</attribute>
|
</attribute>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_6">
|
<layout class="QVBoxLayout" name="review_options_layout">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QGroupBox" name="schedulerGroup">
|
<widget class="QGroupBox" name="schedulerGroup">
|
||||||
<property name="title">
|
<property name="title">
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
# Copyright: Ankitects Pty Ltd and contributors
|
# Copyright: Ankitects Pty Ltd and contributors
|
||||||
# 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
|
||||||
|
|
||||||
|
import functools
|
||||||
import re
|
import re
|
||||||
from typing import Any, cast
|
from typing import Any, cast
|
||||||
|
|
||||||
|
@ -47,8 +48,39 @@ class Preferences(QDialog):
|
||||||
self.setup_collection()
|
self.setup_collection()
|
||||||
self.setup_profile()
|
self.setup_profile()
|
||||||
self.setup_global()
|
self.setup_global()
|
||||||
|
self.setup_configurable_answer_keys()
|
||||||
self.show()
|
self.show()
|
||||||
|
|
||||||
|
def setup_configurable_answer_keys(self):
|
||||||
|
"""
|
||||||
|
Create a group box in Preferences with widgets that let the user edit answer keys.
|
||||||
|
"""
|
||||||
|
ease_labels = (
|
||||||
|
(1, tr.studying_again()),
|
||||||
|
(2, tr.studying_hard()),
|
||||||
|
(3, tr.studying_good()),
|
||||||
|
(4, tr.studying_easy()),
|
||||||
|
)
|
||||||
|
self.form.review_options_layout.addWidget(
|
||||||
|
group := QGroupBox(tr.preferences_answer_keys())
|
||||||
|
)
|
||||||
|
group.setLayout(layout := QFormLayout())
|
||||||
|
for ease, label in ease_labels:
|
||||||
|
layout.addRow(
|
||||||
|
label,
|
||||||
|
line_edit := QLineEdit(self.mw.pm.get_answer_key(ease) or ""),
|
||||||
|
)
|
||||||
|
qconnect(
|
||||||
|
line_edit.textChanged,
|
||||||
|
functools.partial(self.mw.pm.set_answer_key, ease),
|
||||||
|
)
|
||||||
|
line_edit.setValidator(
|
||||||
|
QRegularExpressionValidator(
|
||||||
|
QRegularExpression(r"^[a-z0-9\]\[=,./;\'\\-]$")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
line_edit.setPlaceholderText(tr.preferences_shortcut_placeholder())
|
||||||
|
|
||||||
def accept(self) -> None:
|
def accept(self) -> None:
|
||||||
# avoid exception if main window is already closed
|
# avoid exception if main window is already closed
|
||||||
if not self.mw.col:
|
if not self.mw.col:
|
||||||
|
|
|
@ -10,7 +10,7 @@ import shutil
|
||||||
import traceback
|
import traceback
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import TYPE_CHECKING, Any
|
from typing import TYPE_CHECKING, Any, Optional
|
||||||
|
|
||||||
import anki.lang
|
import anki.lang
|
||||||
import aqt.forms
|
import aqt.forms
|
||||||
|
@ -116,6 +116,8 @@ class LoadMetaResult:
|
||||||
|
|
||||||
|
|
||||||
class ProfileManager:
|
class ProfileManager:
|
||||||
|
default_answer_keys = {ease_num: str(ease_num) for ease_num in range(1, 5)}
|
||||||
|
|
||||||
def __init__(self, base: Path) -> None: #
|
def __init__(self, base: Path) -> None: #
|
||||||
"base should be retrieved via ProfileMangager.get_created_base_folder"
|
"base should be retrieved via ProfileMangager.get_created_base_folder"
|
||||||
## Settings which should be forgotten each Anki restart
|
## Settings which should be forgotten each Anki restart
|
||||||
|
@ -537,6 +539,12 @@ create table if not exists profiles
|
||||||
def set_spacebar_rates_card(self, on: bool) -> None:
|
def set_spacebar_rates_card(self, on: bool) -> None:
|
||||||
self.meta["spacebar_rates_card"] = on
|
self.meta["spacebar_rates_card"] = on
|
||||||
|
|
||||||
|
def get_answer_key(self, ease: int) -> Optional[str]:
|
||||||
|
return self.meta.setdefault("answer_keys", self.default_answer_keys).get(ease)
|
||||||
|
|
||||||
|
def set_answer_key(self, ease: int, key: str):
|
||||||
|
self.meta.setdefault("answer_keys", self.default_answer_keys)[ease] = key
|
||||||
|
|
||||||
def hide_top_bar(self) -> bool:
|
def hide_top_bar(self) -> bool:
|
||||||
return self.meta.get("hide_top_bar", False)
|
return self.meta.get("hide_top_bar", False)
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import functools
|
||||||
import json
|
import json
|
||||||
import random
|
import random
|
||||||
import re
|
import re
|
||||||
|
@ -507,14 +508,11 @@ class Reviewer:
|
||||||
("o", self.onOptions),
|
("o", self.onOptions),
|
||||||
("i", self.on_card_info),
|
("i", self.on_card_info),
|
||||||
("Ctrl+Alt+i", self.on_previous_card_info),
|
("Ctrl+Alt+i", self.on_previous_card_info),
|
||||||
("1", lambda: self._answerCard(1)),
|
*(
|
||||||
("2", lambda: self._answerCard(2)),
|
(key, functools.partial(self._answerCard, ease))
|
||||||
("3", lambda: self._answerCard(3)),
|
for ease in aqt.mw.pm.default_answer_keys
|
||||||
("4", lambda: self._answerCard(4)),
|
if (key := aqt.mw.pm.get_answer_key(ease))
|
||||||
("h", lambda: self._answerCard(1)),
|
),
|
||||||
("j", lambda: self._answerCard(2)),
|
|
||||||
("k", lambda: self._answerCard(3)),
|
|
||||||
("l", lambda: self._answerCard(4)),
|
|
||||||
("u", self.mw.undo),
|
("u", self.mw.undo),
|
||||||
("5", self.on_pause_audio),
|
("5", self.on_pause_audio),
|
||||||
("6", self.on_seek_backward),
|
("6", self.on_seek_backward),
|
||||||
|
|
Loading…
Reference in a new issue