mirror of
https://github.com/ankitects/anki.git
synced 2026-01-09 03:53:55 -05:00
Added: Show Timer + Stop timer on answer
This commit is contained in:
parent
312cbc2fba
commit
f5cdf0f22f
5 changed files with 29 additions and 9 deletions
|
|
@ -302,6 +302,11 @@ message NextCardDataResponse {
|
||||||
string args = 2;
|
string args = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message TimerPreferences {
|
||||||
|
uint32 max_time_ms = 1;
|
||||||
|
bool stop_on_answer = 2;
|
||||||
|
}
|
||||||
|
|
||||||
message NextCardData {
|
message NextCardData {
|
||||||
QueuedCards queue = 1;
|
QueuedCards queue = 1;
|
||||||
repeated AnswerButton answer_buttons = 2;
|
repeated AnswerButton answer_buttons = 2;
|
||||||
|
|
@ -313,7 +318,7 @@ message NextCardDataResponse {
|
||||||
bool autoplay = 7;
|
bool autoplay = 7;
|
||||||
bool marked = 13;
|
bool marked = 13;
|
||||||
optional TypedAnswer typed_answer = 12;
|
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 question_av_tags = 8;
|
||||||
repeated card_rendering.AVTag answer_av_tags = 9;
|
repeated card_rendering.AVTag answer_av_tags = 9;
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ use anki_proto::generic;
|
||||||
use anki_proto::scheduler;
|
use anki_proto::scheduler;
|
||||||
use anki_proto::scheduler::next_card_data_response::AnswerButton;
|
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::NextCardData;
|
||||||
|
use anki_proto::scheduler::next_card_data_response::TimerPreferences;
|
||||||
use anki_proto::scheduler::next_card_data_response::TypedAnswer;
|
use anki_proto::scheduler::next_card_data_response::TypedAnswer;
|
||||||
use anki_proto::scheduler::ComputeFsrsParamsResponse;
|
use anki_proto::scheduler::ComputeFsrsParamsResponse;
|
||||||
use anki_proto::scheduler::ComputeMemoryStateResponse;
|
use anki_proto::scheduler::ComputeMemoryStateResponse;
|
||||||
|
|
@ -403,7 +404,7 @@ impl crate::services::SchedulerService for Collection {
|
||||||
let next_card = queue.cards.first();
|
let next_card = queue.cards.first();
|
||||||
if let Some(next_card) = next_card {
|
if let Some(next_card) = next_card {
|
||||||
let cid = next_card.card.id;
|
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 note = self.get_note(next_card.card.note_id.into())?;
|
||||||
|
|
||||||
let render = self.render_existing_card(cid, false, true)?;
|
let render = self.render_existing_card(cid, false, true)?;
|
||||||
|
|
@ -477,6 +478,11 @@ impl crate::services::SchedulerService for Collection {
|
||||||
queue.new_count = 0;
|
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 {
|
Ok(NextCardDataResponse {
|
||||||
next_card: Some(NextCardData {
|
next_card: Some(NextCardData {
|
||||||
queue: Some(queue.into()),
|
queue: Some(queue.into()),
|
||||||
|
|
@ -486,13 +492,13 @@ impl crate::services::SchedulerService for Collection {
|
||||||
partial_back: rendered_nodes_to_proto(render.anodes),
|
partial_back: rendered_nodes_to_proto(render.anodes),
|
||||||
|
|
||||||
answer_buttons,
|
answer_buttons,
|
||||||
autoplay: !deck_config.inner.disable_autoplay,
|
autoplay: !deck_config.disable_autoplay,
|
||||||
typed_answer: typed_answer.map(|answer| TypedAnswer {
|
typed_answer: typed_answer.map(|answer| TypedAnswer {
|
||||||
text: answer.1,
|
text: answer.1,
|
||||||
args: answer.0,
|
args: answer.0,
|
||||||
}),
|
}),
|
||||||
marked,
|
marked,
|
||||||
max_time_ms: deck_config.inner.cap_answer_time_to_secs * 1000,
|
timer,
|
||||||
|
|
||||||
// Filled by python
|
// Filled by python
|
||||||
front: "".to_string(),
|
front: "".to_string(),
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,9 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
</button>
|
</button>
|
||||||
{/if}
|
{/if}
|
||||||
<div class="disappearing more">
|
<div class="disappearing more">
|
||||||
<Timer {state}></Timer>
|
{#if $cardData?.timer}
|
||||||
|
<Timer {state}></Timer>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
<div class="disappearing more">
|
<div class="disappearing more">
|
||||||
<More {state}></More>
|
<More {state}></More>
|
||||||
|
|
@ -82,7 +84,6 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
}
|
}
|
||||||
|
|
||||||
.more {
|
.more {
|
||||||
// text-align: right;
|
|
||||||
direction: rtl;
|
direction: rtl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,14 +12,20 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
let cls = "";
|
let cls = "";
|
||||||
|
|
||||||
function step() {
|
function step() {
|
||||||
let time = Date.now() - state.beginAnsweringMs;
|
const timerPreferences = state._cardData?.timer;
|
||||||
const maxTime = state._cardData?.maxTimeMs ?? 0;
|
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) {
|
if (time >= maxTime) {
|
||||||
time = maxTime;
|
time = maxTime;
|
||||||
cls = "overtime";
|
cls = "overtime";
|
||||||
} else {
|
} else {
|
||||||
cls = "";
|
cls = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
text = formatTime(time);
|
text = formatTime(time);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -37,7 +43,6 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
onDestroy(() => {
|
onDestroy(() => {
|
||||||
clearInterval(interval);
|
clearInterval(interval);
|
||||||
});
|
});
|
||||||
step();
|
|
||||||
|
|
||||||
function formatTime(time: number) {
|
function formatTime(time: number) {
|
||||||
const seconds = time / 1000;
|
const seconds = time / 1000;
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,7 @@ export class ReviewerState {
|
||||||
currentTypedAnswer = "";
|
currentTypedAnswer = "";
|
||||||
_cardData: NextCardDataResponse_NextCardData | undefined = undefined;
|
_cardData: NextCardDataResponse_NextCardData | undefined = undefined;
|
||||||
beginAnsweringMs = Date.now();
|
beginAnsweringMs = Date.now();
|
||||||
|
answerMs: number | undefined = undefined;
|
||||||
readonly cardClass = writable("");
|
readonly cardClass = writable("");
|
||||||
readonly answerShown = writable(false);
|
readonly answerShown = writable(false);
|
||||||
readonly cardData = writable<NextCardDataResponse_NextCardData | undefined>(undefined);
|
readonly cardData = writable<NextCardDataResponse_NextCardData | undefined>(undefined);
|
||||||
|
|
@ -310,6 +311,7 @@ export class ReviewerState {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.beginAnsweringMs = Date.now();
|
this.beginAnsweringMs = Date.now();
|
||||||
|
this.answerMs = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
get currentCard() {
|
get currentCard() {
|
||||||
|
|
@ -338,6 +340,7 @@ export class ReviewerState {
|
||||||
if (this._cardData?.autoplay) {
|
if (this._cardData?.autoplay) {
|
||||||
playAvtags({ tags: this._cardData!.answerAvTags });
|
playAvtags({ tags: this._cardData!.answerAvTags });
|
||||||
}
|
}
|
||||||
|
this.answerMs = Date.now();
|
||||||
this.updateHtml(await this.showTypedAnswer(this._cardData?.back || ""));
|
this.updateHtml(await this.showTypedAnswer(this._cardData?.back || ""));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue