Added: Show Timer + Stop timer on answer

This commit is contained in:
Luc Mcgrady 2025-11-14 18:45:16 +00:00
parent 312cbc2fba
commit f5cdf0f22f
No known key found for this signature in database
GPG key ID: 4F3D7A0B17CC3D9C
5 changed files with 29 additions and 9 deletions

View file

@ -302,6 +302,11 @@ message NextCardDataResponse {
string args = 2;
}
message TimerPreferences {
uint32 max_time_ms = 1;
bool stop_on_answer = 2;
}
message NextCardData {
QueuedCards queue = 1;
repeated AnswerButton answer_buttons = 2;
@ -313,7 +318,7 @@ message NextCardDataResponse {
bool autoplay = 7;
bool marked = 13;
optional TypedAnswer typed_answer = 12;
uint32 max_time_ms = 14;
optional TimerPreferences timer = 14;
repeated card_rendering.AVTag question_av_tags = 8;
repeated card_rendering.AVTag answer_av_tags = 9;

View file

@ -11,6 +11,7 @@ use anki_proto::generic;
use anki_proto::scheduler;
use anki_proto::scheduler::next_card_data_response::AnswerButton;
use anki_proto::scheduler::next_card_data_response::NextCardData;
use anki_proto::scheduler::next_card_data_response::TimerPreferences;
use anki_proto::scheduler::next_card_data_response::TypedAnswer;
use anki_proto::scheduler::ComputeFsrsParamsResponse;
use anki_proto::scheduler::ComputeMemoryStateResponse;
@ -403,7 +404,7 @@ impl crate::services::SchedulerService for Collection {
let next_card = queue.cards.first();
if let Some(next_card) = next_card {
let cid = next_card.card.id;
let deck_config = self.deck_config_for_card(&next_card.card)?;
let deck_config = self.deck_config_for_card(&next_card.card)?.inner;
let note = self.get_note(next_card.card.note_id.into())?;
let render = self.render_existing_card(cid, false, true)?;
@ -477,6 +478,11 @@ impl crate::services::SchedulerService for Collection {
queue.new_count = 0;
}
let timer = deck_config.show_timer.then_some(TimerPreferences {
max_time_ms: deck_config.cap_answer_time_to_secs * 1000,
stop_on_answer: deck_config.stop_timer_on_answer,
});
Ok(NextCardDataResponse {
next_card: Some(NextCardData {
queue: Some(queue.into()),
@ -486,13 +492,13 @@ impl crate::services::SchedulerService for Collection {
partial_back: rendered_nodes_to_proto(render.anodes),
answer_buttons,
autoplay: !deck_config.inner.disable_autoplay,
autoplay: !deck_config.disable_autoplay,
typed_answer: typed_answer.map(|answer| TypedAnswer {
text: answer.1,
args: answer.0,
}),
marked,
max_time_ms: deck_config.inner.cap_answer_time_to_secs * 1000,
timer,
// Filled by python
front: "".to_string(),

View file

@ -52,7 +52,9 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
</button>
{/if}
<div class="disappearing more">
<Timer {state}></Timer>
{#if $cardData?.timer}
<Timer {state}></Timer>
{/if}
</div>
<div class="disappearing more">
<More {state}></More>
@ -82,7 +84,6 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
}
.more {
// text-align: right;
direction: rtl;
}

View file

@ -12,14 +12,20 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
let cls = "";
function step() {
let time = Date.now() - state.beginAnsweringMs;
const maxTime = state._cardData?.maxTimeMs ?? 0;
const timerPreferences = state._cardData?.timer;
let time = Date.now();
if (timerPreferences?.stopOnAnswer && state.answerMs !== undefined) {
time = state.answerMs;
}
time -= state.beginAnsweringMs;
const maxTime = state._cardData?.timer?.maxTimeMs ?? 0;
if (time >= maxTime) {
time = maxTime;
cls = "overtime";
} else {
cls = "";
}
text = formatTime(time);
}
@ -37,7 +43,6 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
onDestroy(() => {
clearInterval(interval);
});
step();
function formatTime(time: number) {
const seconds = time / 1000;

View file

@ -53,6 +53,7 @@ export class ReviewerState {
currentTypedAnswer = "";
_cardData: NextCardDataResponse_NextCardData | undefined = undefined;
beginAnsweringMs = Date.now();
answerMs: number | undefined = undefined;
readonly cardClass = writable("");
readonly answerShown = writable(false);
readonly cardData = writable<NextCardDataResponse_NextCardData | undefined>(undefined);
@ -310,6 +311,7 @@ export class ReviewerState {
}
this.beginAnsweringMs = Date.now();
this.answerMs = undefined;
}
get currentCard() {
@ -338,6 +340,7 @@ export class ReviewerState {
if (this._cardData?.autoplay) {
playAvtags({ tags: this._cardData!.answerAvTags });
}
this.answerMs = Date.now();
this.updateHtml(await this.showTypedAnswer(this._cardData?.back || ""));
}