diff --git a/proto/anki/scheduler.proto b/proto/anki/scheduler.proto index 87a052e79..69430c070 100644 --- a/proto/anki/scheduler.proto +++ b/proto/anki/scheduler.proto @@ -327,6 +327,13 @@ message NextCardDataResponse { repeated card_rendering.AVTag question_av_tags = 8; repeated card_rendering.AVTag answer_av_tags = 9; + float autoAdvanceQuestionSeconds = 16; + float autoAdvanceAnswerSeconds = 17; + bool autoAdvanceWaitForAudio = 20; + + deck_config.DeckConfig.Config.QuestionAction autoAdvanceQuestionAction = 18; + deck_config.DeckConfig.Config.AnswerAction autoAdvanceAnswerAction = 19; + // TODO: We can probably make this a little faster by using oneof and // preventing the partial_front and back being sent to svelte where it isn't // used. Alternatively we can use a completely different message for both diff --git a/rslib/src/scheduler/service/mod.rs b/rslib/src/scheduler/service/mod.rs index e5c9355c9..07a99cf91 100644 --- a/rslib/src/scheduler/service/mod.rs +++ b/rslib/src/scheduler/service/mod.rs @@ -500,6 +500,13 @@ impl crate::services::SchedulerService for Collection { marked, timer, + auto_advance_answer_seconds: deck_config.seconds_to_show_answer, + auto_advance_question_seconds: deck_config.seconds_to_show_question, + auto_advance_wait_for_audio: deck_config.wait_for_audio, + + auto_advance_answer_action: deck_config.answer_action, + auto_advance_question_action: deck_config.question_action, + // Filled by python accept_enter: true, front: "".to_string(), diff --git a/ts/routes/reviewer/reviewer-bottom/More.svelte b/ts/routes/reviewer/reviewer-bottom/More.svelte index a0c498be5..980dc1d81 100644 --- a/ts/routes/reviewer/reviewer-bottom/More.svelte +++ b/ts/routes/reviewer/reviewer-bottom/More.svelte @@ -24,10 +24,6 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html { colour: tr.actionsFlagPurple(), shortcut: "Ctrl+7" }, ]; - function todo() { - alert("Not yet implemented in new reviewer."); - } - const shortcuts: MoreMenuItemInfo[] = [ { name: tr.studyingBuryCard(), @@ -128,11 +124,13 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html { name: tr.actionsAutoAdvance(), shortcut: "Shift+A", - onClick: todo /* checked: autoAdvanceEnabled */, + onClick: () => state.toggleAutoAdvance(), }, ]; $: current_flag = state.flag; + // TOOD: Fix above capitals + $: autoAdvance = state.autoAdvance; function prepKeycodeForShortcut(keycode: string) { return keycode.replace("Ctrl", "Control"); @@ -212,11 +210,8 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html {#if shortcut == "hr"}
{:else} -
+ {@const highlighted = shortcut.shortcut == "Shift+A" && $autoAdvance} +
| undefined; + autoAdvanceAnswerTimeout: ReturnType | undefined; iframe: HTMLIFrameElement | undefined = undefined; + constructor() { + this.autoAdvance.subscribe($autoAdvance => { + if (this._answerShown) { + this.updateAutoAdvanceAnswer(); + } else { + this.updateAutoAdvanceQuestion(); + } + if (!$autoAdvance) { + clearInterval(this.autoAdvanceQuestionTimeout); + clearInterval(this.autoAdvanceAnswerTimeout); + } + }); + } + + public toggleAutoAdvance() { + this.autoAdvance.update(($autoAdvance) => { + // Reversed because the $autoAdvance will be flipped by the return. + this.showTooltip($autoAdvance ? tr.actionsAutoAdvanceDeactivated() : tr.actionsAutoAdvanceActivated()); + return !$autoAdvance; + }); + } + async onReady() { const { json } = await getConfigJson({ val: "reviewerStorage" }); this.sendInnerRequest({ type: "setstorage", json_buffer: json }); @@ -323,6 +349,47 @@ export class ReviewerState { this.sendInnerRequest({ type: "html", value: htmlString, css, bodyclass }); } + updateAutoAdvanceQuestion() { + clearTimeout(this.autoAdvanceAnswerTimeout); + if (get(this.autoAdvance) && this._cardData!.autoAdvanceQuestionSeconds) { + const action = ({ + [DeckConfig_Config_QuestionAction.SHOW_ANSWER]: () => { + this.showAnswer(); + }, + [DeckConfig_Config_QuestionAction.SHOW_REMINDER]: () => { + this.showTooltip(tr.studyingQuestionTimeElapsed()); + }, + })[this._cardData!.autoAdvanceQuestionAction]; + + this.autoAdvanceQuestionTimeout = setTimeout(action, this._cardData!.autoAdvanceQuestionSeconds * 1000); + } + } + + updateAutoAdvanceAnswer() { + clearTimeout(this.autoAdvanceQuestionTimeout); + if (get(this.autoAdvance) && this._cardData?.autoAdvanceAnswerSeconds) { + const action = ({ + [DeckConfig_Config_AnswerAction.ANSWER_AGAIN]: () => { + this.easeButtonPressed(0); + }, + [DeckConfig_Config_AnswerAction.ANSWER_HARD]: () => { + this.easeButtonPressed(1); + }, + [DeckConfig_Config_AnswerAction.ANSWER_GOOD]: () => { + this.easeButtonPressed(2); + }, + [DeckConfig_Config_AnswerAction.BURY_CARD]: () => { + this.buryOrSuspendCurrentCard(false); + }, + [DeckConfig_Config_AnswerAction.SHOW_REMINDER]: () => { + this.showTooltip(tr.studyingAnswerTimeElapsed()); + }, + })[this._cardData.autoAdvanceAnswerAction]; + + this.autoAdvanceAnswerTimeout = setTimeout(action, this._cardData.autoAdvanceAnswerSeconds * 1000); + } + } + async showQuestion(answer: CardAnswer | null) { if (answer !== null) { this.setUndo(tr.actionsAnswerCard()); @@ -352,6 +419,7 @@ export class ReviewerState { this.beginAnsweringMs = Date.now(); this.answerMs = undefined; + this.updateAutoAdvanceQuestion(); } get currentCard() { @@ -382,6 +450,7 @@ export class ReviewerState { } this.answerMs = Date.now(); this.updateHtml(await this.showTypedAnswer(this._cardData?.back || "")); + this.updateAutoAdvanceAnswer(); } get _answerShown() {