add timer

This commit is contained in:
Ren Tatsumoto 2025-11-30 03:32:10 +03:00
parent 1eba72a1e2
commit 29691d38d4
2 changed files with 76 additions and 2 deletions

View file

@ -139,3 +139,55 @@ class FlexibleBottomBar(FlexibleHorizontalBar):
self.add_widget(self.middle_bucket)
self.add_stretch()
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)

View file

@ -10,7 +10,7 @@ from collections.abc import Generator, Sequence
from dataclasses import dataclass
from enum import Enum, auto
from functools import partial
from typing import Any, Literal, Match, cast
from typing import Any, Literal, Match, Optional, cast
import aqt
import aqt.browser
@ -38,7 +38,7 @@ from aqt.flexible_grading_reviewer.utils import (
ease_to_answer_key_short,
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.note import remove_notes
from aqt.operations.scheduling import (
@ -1257,8 +1257,11 @@ class FlexibleReviewer(Reviewer):
QueuedCards.REVIEW: "ForestGreen",
}
timer: Optional[FlexibleTimerLabel] = None
def __init__(self, mw: AnkiQt) -> None:
super().__init__(mw)
self.timer = None
def cleanup(self) -> None:
super().cleanup()
@ -1282,6 +1285,8 @@ class FlexibleReviewer(Reviewer):
FlexiblePushButton(text=tr.studying_more()),
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:
if queue_type == QueuedCards.LEARNING:
@ -1354,11 +1359,24 @@ class FlexibleReviewer(Reviewer):
def _clear_bottom_web(self) -> None:
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:
self._add_side_buttons()
self._add_middle_buttons_for_question_side()
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:
if not self._states_mutated:
self.mw.progress.single_shot(50, self._showEaseButtons)
@ -1367,6 +1385,10 @@ class FlexibleReviewer(Reviewer):
self._add_middle_buttons_for_answer_side()
self._clear_bottom_web()
assert self.timer, "timer should exist."
if self._should_stop_timer_on_answer():
self.timer.stop()
def onEnterKey(self) -> None:
if self.state == "question":
self._getTypedAnswer()