-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtimer_controller.py
More file actions
134 lines (109 loc) · 4.6 KB
/
Copy pathtimer_controller.py
File metadata and controls
134 lines (109 loc) · 4.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
from __future__ import annotations
import random
from enum import Enum, auto
from PySide6.QtCore import QObject, QTimer, Signal
from config_manager import TimeConfig
class TimerState(Enum):
IDLE = auto()
STUDYING = auto()
RESTING = auto()
PAUSED = auto()
class TimerController(QObject):
"""统一管理学习 / 休息计时逻辑"""
stateChanged = Signal(object) # TimerState
studyProgress = Signal(int, int) # elapsed, total (seconds)
restProgress = Signal(int, int)
microBreakHint = Signal(int) # 第几次微休
wrapupHint = Signal()
sessionEnd = Signal()
restEnd = Signal()
def __init__(self, time_config: TimeConfig, parent: QObject = None):
super().__init__(parent)
self._timer = QTimer(self)
self._timer.setInterval(1000)
self._timer.timeout.connect(self._on_tick)
self.time_config = time_config
self.state = TimerState.IDLE
self._last_active_state: TimerState | None = None
self.study_elapsed = 0
self.rest_elapsed = 0
self._next_micro_break_target = 0
self._micro_break_count = 0
self._wrapup_triggered = False
self._recalculate_micro_break_target()
def update_time_config(self, time_config: TimeConfig):
self.time_config = time_config
if self.state == TimerState.IDLE:
self._reset_counters()
def start_study(self):
self._reset_counters()
self.state = TimerState.STUDYING
self.stateChanged.emit(self.state)
self._timer.start()
def start_rest(self):
self.rest_elapsed = 0
self.state = TimerState.RESTING
self.stateChanged.emit(self.state)
if not self._timer.isActive():
self._timer.start()
def pause(self):
if self.state in (TimerState.STUDYING, TimerState.RESTING):
self._last_active_state = self.state
self.state = TimerState.PAUSED
self.stateChanged.emit(self.state)
self._timer.stop()
def resume(self):
if self.state == TimerState.PAUSED and self._last_active_state:
self.state = self._last_active_state
self.stateChanged.emit(self.state)
self._timer.start()
def stop(self):
self._timer.stop()
self.state = TimerState.IDLE
self.stateChanged.emit(self.state)
def _reset_counters(self):
self.study_elapsed = 0
self.rest_elapsed = 0
self._micro_break_count = 0
self._wrapup_triggered = False
self._recalculate_micro_break_target()
def _recalculate_micro_break_target(self):
"""生成下一次微休提示时间点(相对于当前 study_elapsed)"""
interval_min = self.time_config.micro_break_interval_min * 60
interval_max = self.time_config.micro_break_interval_max * 60
if interval_max <= 0 or interval_max < interval_min:
self._next_micro_break_target = 0
return
base = self.study_elapsed
delta = random.randint(interval_min, interval_max)
target = base + delta
if target >= self.time_config.wrapup_time * 60:
self._next_micro_break_target = 0
else:
self._next_micro_break_target = target
def _on_tick(self):
if self.state == TimerState.STUDYING:
self.study_elapsed += 1
total = self.time_config.study_duration * 60
self.studyProgress.emit(self.study_elapsed, total)
# 微休提示:不暂停倒计时
if self._next_micro_break_target and self.study_elapsed >= self._next_micro_break_target:
self._micro_break_count += 1
self.microBreakHint.emit(self._micro_break_count)
self._recalculate_micro_break_target()
# 收尾提示:不暂停倒计时
if (not self._wrapup_triggered and
self.study_elapsed >= self.time_config.wrapup_time * 60):
self._wrapup_triggered = True
self.wrapupHint.emit()
# 学习结束
if self.study_elapsed >= total:
self._timer.stop()
self.sessionEnd.emit()
elif self.state == TimerState.RESTING:
self.rest_elapsed += 1
total = self.time_config.rest_duration * 60
self.restProgress.emit(self.rest_elapsed, total)
if self.rest_elapsed >= total:
self._timer.stop()
self.restEnd.emit()