mirror of
https://github.com/ankitects/anki.git
synced 2025-09-18 14:02:21 -04:00
Add auto-advance options to deck preset (#2765)
* Move stop-timer-on-answer strings to correct section * Add auto-advance options to deck preset * Implement answer actions * Fix error when last card is answered before timeout * Fix deserialization of answerAction * Add answerAction to reserved key list * Fix inverted boolean * Add option to wait for audio to finish * Add auto-advance toggle * Add shortcut * Disable auto-advance when main window state changes * Start auto-advance timer after option is toggled * Disable auto-advance when main window loses focus * Use existing translations * Add Answer Hard and Show Reminder
This commit is contained in:
parent
46890fbbaa
commit
ae7b14bf40
12 changed files with 311 additions and 7 deletions
|
@ -222,6 +222,17 @@ deck-config-maximum-answer-secs-tooltip =
|
|||
deck-config-show-answer-timer-tooltip =
|
||||
In the review screen, show a timer that counts the number of seconds you're
|
||||
taking to review each card.
|
||||
deck-config-stop-timer-on-answer = Stop timer on answer
|
||||
deck-config-stop-timer-on-answer-tooltip =
|
||||
Whether to stop the timer when the answer is revealed.
|
||||
This doesn't affect statistics.
|
||||
deck-config-seconds-to-show-question = Seconds to show question
|
||||
deck-config-seconds-to-show-question-tooltip = The number of seconds to wait before automatically advancing to the next question. Set to 0 to disable.
|
||||
deck-config-seconds-to-show-answer = Seconds to show answer
|
||||
deck-config-seconds-to-show-answer-tooltip = The number of seconds to wait before automatically revealing the answer. Set to 0 to disable.
|
||||
deck-config-answer-action = Answer action
|
||||
deck-config-answer-action-tooltip = The action to perform on the current card before automatically advancing to the next one.
|
||||
deck-config-wait-for-audio-tooltip = Wait for audio to finish before automatically revealing answer or next question
|
||||
|
||||
## Audio section
|
||||
|
||||
|
@ -234,11 +245,6 @@ deck-config-skip-question-when-replaying = Skip question when replaying answer
|
|||
deck-config-always-include-question-audio-tooltip =
|
||||
Whether the question audio should be included when the Replay action is
|
||||
used while looking at the answer side of a card.
|
||||
deck-config-stop-timer-on-answer = Stop timer on answer
|
||||
deck-config-stop-timer-on-answer-tooltip =
|
||||
Whether to stop the timer when the answer is revealed.
|
||||
This doesn't affect statistics.
|
||||
|
||||
## Advanced section
|
||||
|
||||
deck-config-advanced-title = Advanced
|
||||
|
|
|
@ -56,3 +56,4 @@ studying-minute =
|
|||
[one] { $count } minute.
|
||||
*[other] { $count } minutes.
|
||||
}
|
||||
studying-answer-time-elapsed = Answer time elapsed
|
||||
|
|
|
@ -91,6 +91,13 @@ message DeckConfig {
|
|||
LEECH_ACTION_SUSPEND = 0;
|
||||
LEECH_ACTION_TAG_ONLY = 1;
|
||||
}
|
||||
enum AnswerAction {
|
||||
ANSWER_ACTION_BURY_CARD = 0;
|
||||
ANSWER_ACTION_ANSWER_AGAIN = 1;
|
||||
ANSWER_ACTION_ANSWER_GOOD = 2;
|
||||
ANSWER_ACTION_ANSWER_HARD = 3;
|
||||
ANSWER_ACTION_SHOW_REMINDER = 4;
|
||||
}
|
||||
|
||||
repeated float learn_steps = 1;
|
||||
repeated float relearn_steps = 2;
|
||||
|
@ -133,6 +140,10 @@ message DeckConfig {
|
|||
uint32 cap_answer_time_to_secs = 24;
|
||||
bool show_timer = 25;
|
||||
bool stop_timer_on_answer = 38;
|
||||
float seconds_to_show_question = 41;
|
||||
float seconds_to_show_answer = 42;
|
||||
AnswerAction answer_action = 43;
|
||||
bool wait_for_audio = 44;
|
||||
bool skip_question_when_replaying_answer = 26;
|
||||
|
||||
bool bury_new = 27;
|
||||
|
|
|
@ -161,6 +161,11 @@ class MainWebView(AnkiWebView):
|
|||
self.mw.bottomWeb.hide_timer.start()
|
||||
return True
|
||||
|
||||
if evt.type() == QEvent.Type.FocusOut:
|
||||
self.mw._auto_advance_was_enabled = self.mw.reviewer.auto_advance_enabled
|
||||
self.mw.reviewer.auto_advance_enabled = False
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
|
@ -189,6 +194,7 @@ class AnkiQt(QMainWindow):
|
|||
self.app = app
|
||||
self.pm = profileManager
|
||||
self.fullscreen = False
|
||||
self._auto_advance_was_enabled = False
|
||||
# init rest of app
|
||||
self.safeMode = (
|
||||
bool(self.app.queryKeyboardModifiers() & Qt.KeyboardModifier.ShiftModifier)
|
||||
|
@ -822,6 +828,8 @@ class AnkiQt(QMainWindow):
|
|||
if new_focus and new_focus.window() == self:
|
||||
if self.state == "review":
|
||||
self.reviewer.refresh_if_needed()
|
||||
self.reviewer.auto_advance_enabled = self._auto_advance_was_enabled
|
||||
self.reviewer.auto_advance_if_enabled()
|
||||
elif self.state == "overview":
|
||||
self.overview.refresh_if_needed()
|
||||
elif self.state == "deckBrowser":
|
||||
|
@ -1021,6 +1029,7 @@ title="{}" {}>{}</button>""".format(
|
|||
from aqt.reviewer import Reviewer
|
||||
|
||||
self.reviewer = Reviewer(self)
|
||||
self._auto_advance_was_enabled = self.reviewer.auto_advance_enabled
|
||||
|
||||
# Syncing
|
||||
##########################################################################
|
||||
|
|
|
@ -129,6 +129,14 @@ class V3CardInfo:
|
|||
return CardAnswer.EASY
|
||||
|
||||
|
||||
class AnswerAction(Enum):
|
||||
BURY_CARD = 0
|
||||
ANSWER_AGAIN = 1
|
||||
ANSWER_GOOD = 2
|
||||
ANSWER_HARD = 3
|
||||
SHOW_REMINDER = 4
|
||||
|
||||
|
||||
class Reviewer:
|
||||
def __init__(self, mw: AnkiQt) -> None:
|
||||
self.mw = mw
|
||||
|
@ -147,6 +155,10 @@ class Reviewer:
|
|||
self._previous_card_info = PreviousReviewerCardInfo(self.mw)
|
||||
self._states_mutated = True
|
||||
self._reps: int = None
|
||||
self._show_question_timer: QTimer | None = None
|
||||
self._show_answer_timer: QTimer | None = None
|
||||
self.auto_advance_enabled = False
|
||||
gui_hooks.av_player_did_end_playing.append(self._on_av_player_did_end_playing)
|
||||
|
||||
def show(self) -> None:
|
||||
if self.mw.col.sched_ver() == 1 or not self.mw.col.v3_scheduler():
|
||||
|
@ -175,6 +187,7 @@ class Reviewer:
|
|||
def cleanup(self) -> None:
|
||||
gui_hooks.reviewer_will_end()
|
||||
self.card = None
|
||||
self.auto_advance_enabled = False
|
||||
|
||||
def refresh_if_needed(self) -> None:
|
||||
if self._refresh_needed is RefreshNeeded.QUEUES:
|
||||
|
@ -282,6 +295,21 @@ class Reviewer:
|
|||
replay_audio(self.card, False)
|
||||
gui_hooks.audio_will_replay(self.web, self.card, self.state == "question")
|
||||
|
||||
def _on_av_player_did_end_playing(self, *args) -> None:
|
||||
def task() -> None:
|
||||
if av_player.queue_is_empty():
|
||||
if self._show_question_timer and not sip.isdeleted(
|
||||
self._show_question_timer
|
||||
):
|
||||
self._on_show_question_timeout()
|
||||
elif self._show_answer_timer and not sip.isdeleted(
|
||||
self._show_answer_timer
|
||||
):
|
||||
self._on_show_answer_timeout()
|
||||
|
||||
# Allow time for audio queue to update
|
||||
self.mw.taskman.run_on_main(lambda: self.mw.progress.single_shot(100, task))
|
||||
|
||||
# Initializing the webview
|
||||
##########################################################################
|
||||
|
||||
|
@ -363,6 +391,35 @@ class Reviewer:
|
|||
self.mw.web.setFocus()
|
||||
# user hook
|
||||
gui_hooks.reviewer_did_show_question(c)
|
||||
self._auto_advance_to_answer_if_enabled()
|
||||
|
||||
def _auto_advance_to_answer_if_enabled(self) -> None:
|
||||
if self.auto_advance_enabled:
|
||||
conf = self.mw.col.decks.config_dict_for_deck_id(
|
||||
self.card.current_deck_id()
|
||||
)
|
||||
timer = None
|
||||
if conf["secondsToShowAnswer"]:
|
||||
timer = self._show_answer_timer = self.mw.progress.timer(
|
||||
int(conf["secondsToShowAnswer"] * 1000),
|
||||
lambda: self._on_show_answer_timeout(timer),
|
||||
repeat=False,
|
||||
parent=self.mw,
|
||||
)
|
||||
|
||||
def _on_show_answer_timeout(self, timer: QTimer | None = None) -> None:
|
||||
if self.card is None:
|
||||
return
|
||||
conf = self.mw.col.decks.config_dict_for_deck_id(self.card.current_deck_id())
|
||||
if (conf["waitForAudio"] and av_player.current_player) or (
|
||||
timer and self._show_answer_timer != timer
|
||||
):
|
||||
return
|
||||
if self._show_answer_timer is not None:
|
||||
self._show_answer_timer.deleteLater()
|
||||
if not self.auto_advance_enabled:
|
||||
return
|
||||
self._showAnswer()
|
||||
|
||||
def autoplay(self, card: Card) -> bool:
|
||||
print("use card.autoplay() instead of reviewer.autoplay(card)")
|
||||
|
@ -404,6 +461,48 @@ class Reviewer:
|
|||
self.mw.web.setFocus()
|
||||
# user hook
|
||||
gui_hooks.reviewer_did_show_answer(c)
|
||||
self._auto_advance_to_question_if_enabled()
|
||||
|
||||
def _auto_advance_to_question_if_enabled(self) -> None:
|
||||
if self.auto_advance_enabled:
|
||||
conf = self.mw.col.decks.config_dict_for_deck_id(
|
||||
self.card.current_deck_id()
|
||||
)
|
||||
timer = None
|
||||
if conf["secondsToShowQuestion"]:
|
||||
timer = self._show_question_timer = self.mw.progress.timer(
|
||||
int(conf["secondsToShowQuestion"] * 1000),
|
||||
lambda: self._on_show_question_timeout(timer),
|
||||
repeat=False,
|
||||
parent=self.mw,
|
||||
)
|
||||
|
||||
def _on_show_question_timeout(self, timer: QTimer | None = None) -> None:
|
||||
if self.card is None:
|
||||
return
|
||||
conf = self.mw.col.decks.config_dict_for_deck_id(self.card.current_deck_id())
|
||||
if (conf["waitForAudio"] and av_player.current_player) or (
|
||||
timer and self._show_question_timer != timer
|
||||
):
|
||||
return
|
||||
if self._show_question_timer is not None:
|
||||
self._show_question_timer.deleteLater()
|
||||
if not self.auto_advance_enabled:
|
||||
return
|
||||
try:
|
||||
answer_action = list(AnswerAction)[conf["answerAction"]]
|
||||
except IndexError:
|
||||
answer_action = AnswerAction.ANSWER_GOOD
|
||||
if answer_action == AnswerAction.BURY_CARD:
|
||||
self.bury_current_card()
|
||||
elif answer_action == AnswerAction.ANSWER_AGAIN:
|
||||
self._answerCard(1)
|
||||
elif answer_action == AnswerAction.ANSWER_HARD:
|
||||
self._answerCard(2)
|
||||
elif answer_action == AnswerAction.SHOW_REMINDER:
|
||||
tooltip(tr.studying_answer_time_elapsed())
|
||||
else:
|
||||
self._answerCard(3)
|
||||
|
||||
# Answering a card
|
||||
############################################################
|
||||
|
@ -507,6 +606,7 @@ class Reviewer:
|
|||
("5", self.on_pause_audio),
|
||||
("6", self.on_seek_backward),
|
||||
("7", self.on_seek_forward),
|
||||
("Shift+A", self.toggle_auto_advance),
|
||||
*self.korean_shortcuts(),
|
||||
]
|
||||
|
||||
|
@ -883,6 +983,12 @@ timerStopped = false;
|
|||
[tr.studying_audio_and5s(), "7", self.on_seek_forward],
|
||||
[tr.studying_record_own_voice(), "Shift+V", self.onRecordVoice],
|
||||
[tr.studying_replay_own_voice(), "V", self.onReplayRecorded],
|
||||
[
|
||||
tr.actions_auto_advance(),
|
||||
"Shift+A",
|
||||
self.toggle_auto_advance,
|
||||
dict(checked=self.auto_advance_enabled),
|
||||
],
|
||||
]
|
||||
return opts
|
||||
|
||||
|
@ -1039,6 +1145,16 @@ timerStopped = false;
|
|||
return
|
||||
av_player.play_file(self._recordedAudio)
|
||||
|
||||
def toggle_auto_advance(self) -> None:
|
||||
self.auto_advance_enabled = not self.auto_advance_enabled
|
||||
self.auto_advance_if_enabled()
|
||||
|
||||
def auto_advance_if_enabled(self) -> None:
|
||||
if self.state == "question":
|
||||
self._auto_advance_to_answer_if_enabled()
|
||||
elif self.state == "answer":
|
||||
self._auto_advance_to_question_if_enabled()
|
||||
|
||||
# legacy
|
||||
|
||||
onBuryCard = bury_current_card
|
||||
|
|
|
@ -155,7 +155,7 @@ class AVPlayer:
|
|||
self._play_next_if_idle()
|
||||
|
||||
def queue_is_empty(self) -> bool:
|
||||
return bool(self._enqueued)
|
||||
return not bool(self._enqueued)
|
||||
|
||||
def stop_and_clear_queue(self) -> None:
|
||||
self._enqueued = []
|
||||
|
|
|
@ -6,6 +6,7 @@ mod service;
|
|||
pub(crate) mod undo;
|
||||
mod update;
|
||||
|
||||
pub use anki_proto::deck_config::deck_config::config::AnswerAction;
|
||||
pub use anki_proto::deck_config::deck_config::config::LeechAction;
|
||||
pub use anki_proto::deck_config::deck_config::config::NewCardGatherPriority;
|
||||
pub use anki_proto::deck_config::deck_config::config::NewCardInsertOrder;
|
||||
|
@ -63,6 +64,10 @@ const DEFAULT_DECK_CONFIG_INNER: DeckConfigInner = DeckConfigInner {
|
|||
cap_answer_time_to_secs: 60,
|
||||
show_timer: false,
|
||||
stop_timer_on_answer: false,
|
||||
seconds_to_show_question: 0.0,
|
||||
seconds_to_show_answer: 0.0,
|
||||
answer_action: AnswerAction::BuryCard as i32,
|
||||
wait_for_audio: true,
|
||||
skip_question_when_replaying_answer: false,
|
||||
bury_new: false,
|
||||
bury_reviews: false,
|
||||
|
|
|
@ -24,6 +24,10 @@ use crate::serde::default_on_invalid;
|
|||
use crate::timestamp::TimestampSecs;
|
||||
use crate::types::Usn;
|
||||
|
||||
fn wait_for_audio_default() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DeckConfSchema11 {
|
||||
|
@ -72,6 +76,14 @@ pub struct DeckConfSchema11 {
|
|||
#[serde(default)]
|
||||
stop_timer_on_answer: bool,
|
||||
#[serde(default)]
|
||||
seconds_to_show_question: f32,
|
||||
#[serde(default)]
|
||||
seconds_to_show_answer: f32,
|
||||
#[serde(default)]
|
||||
answer_action: AnswerAction,
|
||||
#[serde(default = "wait_for_audio_default")]
|
||||
wait_for_audio: bool,
|
||||
#[serde(default)]
|
||||
reschedule_fsrs_cards: bool,
|
||||
#[serde(default)]
|
||||
sm2_retention: f32,
|
||||
|
@ -80,6 +92,18 @@ pub struct DeckConfSchema11 {
|
|||
other: HashMap<String, Value>,
|
||||
}
|
||||
|
||||
#[derive(Serialize_repr, Deserialize_repr, Debug, PartialEq, Eq, Clone)]
|
||||
#[repr(u8)]
|
||||
#[derive(Default)]
|
||||
pub enum AnswerAction {
|
||||
#[default]
|
||||
BuryCard = 0,
|
||||
AnswerAgain = 1,
|
||||
AnswerGood = 2,
|
||||
AnswerHard = 3,
|
||||
ShowReminder = 4,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct NewConfSchema11 {
|
||||
|
@ -249,6 +273,10 @@ impl Default for DeckConfSchema11 {
|
|||
autoplay: true,
|
||||
timer: 0,
|
||||
stop_timer_on_answer: false,
|
||||
seconds_to_show_question: 0.0,
|
||||
seconds_to_show_answer: 0.0,
|
||||
answer_action: AnswerAction::BuryCard,
|
||||
wait_for_audio: true,
|
||||
replayq: true,
|
||||
dynamic: false,
|
||||
new: Default::default(),
|
||||
|
@ -331,6 +359,10 @@ impl From<DeckConfSchema11> for DeckConfig {
|
|||
cap_answer_time_to_secs: c.max_taken.max(0) as u32,
|
||||
show_timer: c.timer != 0,
|
||||
stop_timer_on_answer: c.stop_timer_on_answer,
|
||||
seconds_to_show_question: c.seconds_to_show_question,
|
||||
seconds_to_show_answer: c.seconds_to_show_answer,
|
||||
answer_action: c.answer_action as i32,
|
||||
wait_for_audio: c.wait_for_audio,
|
||||
skip_question_when_replaying_answer: !c.replayq,
|
||||
bury_new: c.new.bury,
|
||||
bury_reviews: c.rev.bury,
|
||||
|
@ -385,6 +417,16 @@ impl From<DeckConfig> for DeckConfSchema11 {
|
|||
autoplay: !i.disable_autoplay,
|
||||
timer: i.show_timer.into(),
|
||||
stop_timer_on_answer: i.stop_timer_on_answer,
|
||||
seconds_to_show_question: i.seconds_to_show_question,
|
||||
seconds_to_show_answer: i.seconds_to_show_answer,
|
||||
answer_action: match i.answer_action {
|
||||
0 => AnswerAction::BuryCard,
|
||||
1 => AnswerAction::AnswerAgain,
|
||||
3 => AnswerAction::AnswerHard,
|
||||
4 => AnswerAction::ShowReminder,
|
||||
_ => AnswerAction::AnswerGood,
|
||||
},
|
||||
wait_for_audio: i.wait_for_audio,
|
||||
replayq: !i.skip_question_when_replaying_answer,
|
||||
dynamic: false,
|
||||
new: NewConfSchema11 {
|
||||
|
@ -459,6 +501,10 @@ static RESERVED_DECKCONF_KEYS: Set<&'static str> = phf_set! {
|
|||
"fsrsWeights",
|
||||
"desiredRetention",
|
||||
"stopTimerOnAnswer",
|
||||
"secondsToShowQuestion",
|
||||
"secondsToShowAnswer",
|
||||
"answerAction",
|
||||
"waitForAudio",
|
||||
"rescheduleFsrsCards",
|
||||
"sm2Retention",
|
||||
};
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
export let defaultValue: number;
|
||||
export let min = 0;
|
||||
export let max = 9999;
|
||||
export let step = 0.01;
|
||||
</script>
|
||||
|
||||
<Row --cols={13}>
|
||||
|
@ -21,7 +22,7 @@
|
|||
</Col>
|
||||
<Col --col-size={6} breakpoint="xs">
|
||||
<ConfigInput>
|
||||
<SpinBox bind:value {min} {max} step={0.01} />
|
||||
<SpinBox bind:value {min} {max} {step} />
|
||||
<RevertButton slot="revert" bind:value {defaultValue} />
|
||||
</ConfigInput>
|
||||
</Col>
|
||||
|
|
|
@ -9,13 +9,16 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
import type Modal from "bootstrap/js/dist/modal";
|
||||
|
||||
import DynamicallySlottable from "../components/DynamicallySlottable.svelte";
|
||||
import EnumSelectorRow from "../components/EnumSelectorRow.svelte";
|
||||
import HelpModal from "../components/HelpModal.svelte";
|
||||
import Item from "../components/Item.svelte";
|
||||
import SettingTitle from "../components/SettingTitle.svelte";
|
||||
import SwitchRow from "../components/SwitchRow.svelte";
|
||||
import TitledContainer from "../components/TitledContainer.svelte";
|
||||
import type { HelpItem } from "../components/types";
|
||||
import { answerChoices } from "./choices";
|
||||
import type { DeckOptionsState } from "./lib";
|
||||
import SpinBoxFloatRow from "./SpinBoxFloatRow.svelte";
|
||||
import SpinBoxRow from "./SpinBoxRow.svelte";
|
||||
import Warning from "./Warning.svelte";
|
||||
|
||||
|
@ -43,6 +46,22 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
title: tr.deckConfigStopTimerOnAnswer(),
|
||||
help: tr.deckConfigStopTimerOnAnswerTooltip(),
|
||||
},
|
||||
secondsToShowQuestion: {
|
||||
title: tr.deckConfigSecondsToShowQuestion(),
|
||||
help: tr.deckConfigSecondsToShowQuestionTooltip(),
|
||||
},
|
||||
secondsToShowAnswer: {
|
||||
title: tr.deckConfigSecondsToShowAnswer(),
|
||||
help: tr.deckConfigSecondsToShowAnswerTooltip(),
|
||||
},
|
||||
waitForAudio: {
|
||||
title: tr.deckConfigWaitForAudio(),
|
||||
help: tr.deckConfigWaitForAudioTooltip(),
|
||||
},
|
||||
answerAction: {
|
||||
title: tr.deckConfigAnswerAction(),
|
||||
help: tr.deckConfigAnswerActionTooltip(),
|
||||
},
|
||||
};
|
||||
const helpSections = Object.values(settings) as HelpItem[];
|
||||
|
||||
|
@ -125,5 +144,68 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
</SwitchRow>
|
||||
</div>
|
||||
</Item>
|
||||
|
||||
<Item>
|
||||
<SpinBoxFloatRow
|
||||
bind:value={$config.secondsToShowQuestion}
|
||||
defaultValue={defaults.secondsToShowQuestion}
|
||||
step={1}
|
||||
>
|
||||
<SettingTitle
|
||||
on:click={() =>
|
||||
openHelpModal(
|
||||
Object.keys(settings).indexOf("secondsToShowQuestion"),
|
||||
)}
|
||||
>
|
||||
{settings.secondsToShowQuestion.title}
|
||||
</SettingTitle>
|
||||
</SpinBoxFloatRow>
|
||||
</Item>
|
||||
|
||||
<Item>
|
||||
<SpinBoxFloatRow
|
||||
bind:value={$config.secondsToShowAnswer}
|
||||
defaultValue={defaults.secondsToShowAnswer}
|
||||
step={1}
|
||||
>
|
||||
<SettingTitle
|
||||
on:click={() =>
|
||||
openHelpModal(
|
||||
Object.keys(settings).indexOf("secondsToShowAnswer"),
|
||||
)}
|
||||
>
|
||||
{settings.secondsToShowAnswer.title}
|
||||
</SettingTitle>
|
||||
</SpinBoxFloatRow>
|
||||
</Item>
|
||||
|
||||
<Item>
|
||||
<SwitchRow
|
||||
bind:value={$config.waitForAudio}
|
||||
defaultValue={defaults.waitForAudio}
|
||||
>
|
||||
<SettingTitle
|
||||
on:click={() =>
|
||||
openHelpModal(Object.keys(settings).indexOf("waitForAudio"))}
|
||||
>
|
||||
{settings.waitForAudio.title}
|
||||
</SettingTitle>
|
||||
</SwitchRow>
|
||||
</Item>
|
||||
|
||||
<Item>
|
||||
<EnumSelectorRow
|
||||
bind:value={$config.answerAction}
|
||||
defaultValue={defaults.answerAction}
|
||||
choices={answerChoices()}
|
||||
>
|
||||
<SettingTitle
|
||||
on:click={() =>
|
||||
openHelpModal(Object.keys(settings).indexOf("answerAction"))}
|
||||
>
|
||||
{settings.answerAction.title}
|
||||
</SettingTitle>
|
||||
</EnumSelectorRow>
|
||||
</Item>
|
||||
</DynamicallySlottable>
|
||||
</TitledContainer>
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
|
||||
import {
|
||||
DeckConfig_Config_AnswerAction,
|
||||
DeckConfig_Config_LeechAction,
|
||||
DeckConfig_Config_NewCardGatherPriority,
|
||||
DeckConfig_Config_NewCardInsertOrder,
|
||||
|
@ -149,3 +150,28 @@ export function newInsertOrderChoices(): Choice<DeckConfig_Config_NewCardInsertO
|
|||
},
|
||||
];
|
||||
}
|
||||
|
||||
export function answerChoices(): Choice<DeckConfig_Config_AnswerAction>[] {
|
||||
return [
|
||||
{
|
||||
label: tr.studyingBuryCard(),
|
||||
value: DeckConfig_Config_AnswerAction.BURY_CARD,
|
||||
},
|
||||
{
|
||||
label: tr.deckConfigAnswerAgain(),
|
||||
value: DeckConfig_Config_AnswerAction.ANSWER_AGAIN,
|
||||
},
|
||||
{
|
||||
label: tr.deckConfigAnswerGood(),
|
||||
value: DeckConfig_Config_AnswerAction.ANSWER_GOOD,
|
||||
},
|
||||
{
|
||||
label: tr.deckConfigAnswerHard(),
|
||||
value: DeckConfig_Config_AnswerAction.ANSWER_HARD,
|
||||
},
|
||||
{
|
||||
label: tr.deckConfigShowReminder(),
|
||||
value: DeckConfig_Config_AnswerAction.SHOW_REMINDER,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ const i18n = setupI18n({
|
|||
ModuleName.ACTIONS,
|
||||
ModuleName.DECK_CONFIG,
|
||||
ModuleName.KEYBOARD,
|
||||
ModuleName.STUDYING,
|
||||
],
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in a new issue