mirror of
https://github.com/ankitects/anki.git
synced 2026-01-09 03:53:55 -05:00
add timer
This commit is contained in:
parent
1eba72a1e2
commit
29691d38d4
2 changed files with 76 additions and 2 deletions
|
|
@ -139,3 +139,55 @@ class FlexibleBottomBar(FlexibleHorizontalBar):
|
||||||
self.add_widget(self.middle_bucket)
|
self.add_widget(self.middle_bucket)
|
||||||
self.add_stretch()
|
self.add_stretch()
|
||||||
self.add_widget(self.right_bucket)
|
self.add_widget(self.right_bucket)
|
||||||
|
|
||||||
|
|
||||||
|
class FlexibleTimerLabel(QLabel):
|
||||||
|
def __init__(self, parent=None):
|
||||||
|
super().__init__(parent)
|
||||||
|
self._time = 0 # current time (seconds)
|
||||||
|
self._max_time = 0 # maximum time (seconds); 0 means hidden
|
||||||
|
self._qtimer = QTimer(self)
|
||||||
|
self._qtimer.setInterval(1000)
|
||||||
|
qconnect(self._qtimer.timeout, self._on_tick)
|
||||||
|
self.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||||
|
self.setHidden(True)
|
||||||
|
|
||||||
|
def start(self, max_time: int):
|
||||||
|
self._time = 0
|
||||||
|
self._max_time = max_time
|
||||||
|
self._update_display()
|
||||||
|
if self._qtimer.isActive():
|
||||||
|
self._qtimer.stop()
|
||||||
|
self._qtimer.start()
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
if self._qtimer.isActive():
|
||||||
|
self._qtimer.stop()
|
||||||
|
|
||||||
|
# Internal tick handler
|
||||||
|
def _on_tick(self):
|
||||||
|
self._time += 1
|
||||||
|
# clamp to max_time if set (mirrors TS: time = Math.min(maxTime, time))
|
||||||
|
if self._time > self._max_time > 0:
|
||||||
|
self._time = self._max_time
|
||||||
|
self._update_display()
|
||||||
|
# if reached max, keep ticking but display in red (TS continues interval)
|
||||||
|
|
||||||
|
def _update_display(self):
|
||||||
|
if self._max_time <= 0:
|
||||||
|
super().setText("") # hide when max_time == 0
|
||||||
|
self.setHidden(True)
|
||||||
|
return
|
||||||
|
|
||||||
|
self.setHidden(False)
|
||||||
|
t = min(self._max_time, self._time) if self._max_time > 0 else self._time
|
||||||
|
m = t // 60
|
||||||
|
s = t % 60
|
||||||
|
s_str = f"{s:02d}"
|
||||||
|
time_string = f"{m}:{s_str}"
|
||||||
|
|
||||||
|
if t >= self._max_time > 0:
|
||||||
|
# display red when time == maxTime (using simple HTML)
|
||||||
|
super().setText(f"<font color='red'>{time_string}</font>")
|
||||||
|
else:
|
||||||
|
super().setText(time_string)
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ from collections.abc import Generator, Sequence
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from enum import Enum, auto
|
from enum import Enum, auto
|
||||||
from functools import partial
|
from functools import partial
|
||||||
from typing import Any, Literal, Match, cast
|
from typing import Any, Literal, Match, Optional, cast
|
||||||
|
|
||||||
import aqt
|
import aqt
|
||||||
import aqt.browser
|
import aqt.browser
|
||||||
|
|
@ -38,7 +38,7 @@ from aqt.flexible_grading_reviewer.utils import (
|
||||||
ease_to_answer_key_short,
|
ease_to_answer_key_short,
|
||||||
studied_today_count,
|
studied_today_count,
|
||||||
)
|
)
|
||||||
from aqt.flexible_grading_reviewer.widgets import FlexiblePushButton
|
from aqt.flexible_grading_reviewer.widgets import FlexiblePushButton, FlexibleTimerLabel
|
||||||
from aqt.operations.card import set_card_flag
|
from aqt.operations.card import set_card_flag
|
||||||
from aqt.operations.note import remove_notes
|
from aqt.operations.note import remove_notes
|
||||||
from aqt.operations.scheduling import (
|
from aqt.operations.scheduling import (
|
||||||
|
|
@ -1257,8 +1257,11 @@ class FlexibleReviewer(Reviewer):
|
||||||
QueuedCards.REVIEW: "ForestGreen",
|
QueuedCards.REVIEW: "ForestGreen",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
timer: Optional[FlexibleTimerLabel] = None
|
||||||
|
|
||||||
def __init__(self, mw: AnkiQt) -> None:
|
def __init__(self, mw: AnkiQt) -> None:
|
||||||
super().__init__(mw)
|
super().__init__(mw)
|
||||||
|
self.timer = None
|
||||||
|
|
||||||
def cleanup(self) -> None:
|
def cleanup(self) -> None:
|
||||||
super().cleanup()
|
super().cleanup()
|
||||||
|
|
@ -1282,6 +1285,8 @@ class FlexibleReviewer(Reviewer):
|
||||||
FlexiblePushButton(text=tr.studying_more()),
|
FlexiblePushButton(text=tr.studying_more()),
|
||||||
on_clicked=partial(self.showContextMenu),
|
on_clicked=partial(self.showContextMenu),
|
||||||
)
|
)
|
||||||
|
# Right side: add timer
|
||||||
|
self.timer = self.mw.bottomWidget.right_bucket.add_widget(FlexibleTimerLabel())
|
||||||
|
|
||||||
def browse_queue(self, queue_type: Union[str, Any]) -> None:
|
def browse_queue(self, queue_type: Union[str, Any]) -> None:
|
||||||
if queue_type == QueuedCards.LEARNING:
|
if queue_type == QueuedCards.LEARNING:
|
||||||
|
|
@ -1354,11 +1359,24 @@ class FlexibleReviewer(Reviewer):
|
||||||
def _clear_bottom_web(self) -> None:
|
def _clear_bottom_web(self) -> None:
|
||||||
self.bottom.web.setHtml("<style>body {margin:0;} html {height:0;}</style>")
|
self.bottom.web.setHtml("<style>body {margin:0;} html {height:0;}</style>")
|
||||||
|
|
||||||
|
def _max_time(self) -> int:
|
||||||
|
if self.card.should_show_timer():
|
||||||
|
return self.card.time_limit() // 1000
|
||||||
|
else:
|
||||||
|
return 0
|
||||||
|
|
||||||
def _showAnswerButton(self) -> None:
|
def _showAnswerButton(self) -> None:
|
||||||
self._add_side_buttons()
|
self._add_side_buttons()
|
||||||
self._add_middle_buttons_for_question_side()
|
self._add_middle_buttons_for_question_side()
|
||||||
self._clear_bottom_web()
|
self._clear_bottom_web()
|
||||||
|
|
||||||
|
assert self.timer, "timer should exist."
|
||||||
|
self.timer.start(max_time=self._max_time())
|
||||||
|
|
||||||
|
def _should_stop_timer_on_answer(self) -> bool:
|
||||||
|
conf = self.mw.col.decks.config_dict_for_deck_id(self.card.current_deck_id())
|
||||||
|
return bool(conf["stopTimerOnAnswer"])
|
||||||
|
|
||||||
def _showEaseButtons(self) -> None:
|
def _showEaseButtons(self) -> None:
|
||||||
if not self._states_mutated:
|
if not self._states_mutated:
|
||||||
self.mw.progress.single_shot(50, self._showEaseButtons)
|
self.mw.progress.single_shot(50, self._showEaseButtons)
|
||||||
|
|
@ -1367,6 +1385,10 @@ class FlexibleReviewer(Reviewer):
|
||||||
self._add_middle_buttons_for_answer_side()
|
self._add_middle_buttons_for_answer_side()
|
||||||
self._clear_bottom_web()
|
self._clear_bottom_web()
|
||||||
|
|
||||||
|
assert self.timer, "timer should exist."
|
||||||
|
if self._should_stop_timer_on_answer():
|
||||||
|
self.timer.stop()
|
||||||
|
|
||||||
def onEnterKey(self) -> None:
|
def onEnterKey(self) -> None:
|
||||||
if self.state == "question":
|
if self.state == "question":
|
||||||
self._getTypedAnswer()
|
self._getTypedAnswer()
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue