|
1 | | -import datetime |
| 1 | +from asyncio.events import get_event_loop |
| 2 | +from datetime import datetime |
2 | 3 | import os |
3 | | -import threading |
| 4 | +import enum |
| 5 | +import asyncio |
4 | 6 | from time import sleep |
5 | 7 |
|
6 | 8 | from devdeck_core.controls.deck_control import DeckControl |
7 | 9 |
|
8 | 10 |
|
| 11 | +class TimerState(enum.Enum): |
| 12 | + RUNNING = 1 |
| 13 | + STOPPED = 2 |
| 14 | + RESET = 3 |
| 15 | + |
| 16 | + |
9 | 17 | class TimerControl(DeckControl): |
10 | 18 |
|
11 | 19 | def __init__(self, key_no, **kwargs): |
12 | | - self.start_time = None |
13 | | - self.end_time = None |
14 | | - self.thread = None |
15 | | - super().__init__(key_no, **kwargs) |
| 20 | + self.loop = get_event_loop() |
| 21 | + self.start_time: datetime = None |
| 22 | + self.end_time: datetime = None |
| 23 | + self.state = TimerState.RESET |
| 24 | + super().__init__(key_no, ** kwargs) |
16 | 25 |
|
17 | 26 | def initialize(self): |
| 27 | + self.loop.create_task(self._update_display()) |
18 | 28 | with self.deck_context() as context: |
19 | 29 | with context.renderer() as r: |
20 | | - r.image(os.path.join(os.path.dirname(__file__), "../assets/font-awesome", 'stopwatch.png')).end() |
| 30 | + r.image(os.path.join(os.path.dirname(__file__), |
| 31 | + "../assets/font-awesome", 'stopwatch.png')).end() |
21 | 32 |
|
22 | 33 | def pressed(self): |
23 | | - if self.start_time is None: |
24 | | - self.start_time = datetime.datetime.now() |
25 | | - self.thread = threading.Thread(target=self._update_display) |
26 | | - self.thread.start() |
27 | | - elif self.end_time is None: |
28 | | - self.end_time = datetime.datetime.now() |
29 | | - self.thread.join() |
30 | | - with self.deck_context() as context: |
31 | | - with context.renderer() as r: |
32 | | - r.text(TimerControl.time_diff_to_str(self.end_time - self.start_time))\ |
33 | | - .font_size(120)\ |
34 | | - .color('red')\ |
35 | | - .center_vertically().center_horizontally().end() |
36 | | - else: |
37 | | - self.start_time = None |
38 | | - self.end_time = None |
39 | | - with self.deck_context() as context: |
40 | | - with context.renderer() as r: |
41 | | - r.image(os.path.join( |
42 | | - os.path.join(os.path.dirname(__file__), "../assets/font-awesome", 'stopwatch.png'))).end() |
43 | | - |
44 | | - def _update_display(self): |
45 | | - while self.end_time is None: |
46 | | - if self.start_time is None: |
47 | | - sleep(1) |
48 | | - continue |
49 | | - cutoff = datetime.datetime.now() if self.end_time is None else self.end_time |
| 34 | + match self.state: |
| 35 | + case TimerState.RESET: |
| 36 | + self.start_time = datetime.now() |
| 37 | + self.end_time = None |
| 38 | + self.state = TimerState.RUNNING |
| 39 | + case TimerState.RUNNING: |
| 40 | + if not self.start_time: |
| 41 | + raise Exception("how did you get here?") |
| 42 | + self.end_time = datetime.now() |
| 43 | + self.state = TimerState.STOPPED |
| 44 | + case TimerState.STOPPED: |
| 45 | + self.start_time = self.end_time = None |
| 46 | + self.state = TimerState.RESET |
| 47 | + |
| 48 | + async def _update_display(self, repeat=True): |
| 49 | + while True: |
50 | 50 | with self.deck_context() as context: |
51 | 51 | with context.renderer() as r: |
52 | | - r.text(TimerControl.time_diff_to_str(cutoff - self.start_time)) \ |
53 | | - .font_size(120) \ |
54 | | - .center_vertically().center_horizontally().end() |
55 | | - sleep(1) |
| 52 | + match self.state: |
| 53 | + case TimerState.RUNNING: |
| 54 | + r.text(TimerControl.time_diff_to_str(datetime.now() - self.start_time))\ |
| 55 | + .font_size(120)\ |
| 56 | + .color('red')\ |
| 57 | + .center_vertically().center_horizontally().end() |
| 58 | + case TimerState.STOPPED: |
| 59 | + r.text(TimerControl.time_diff_to_str(self.end_time - self.start_time))\ |
| 60 | + .font_size(120)\ |
| 61 | + .color('yellow')\ |
| 62 | + .center_vertically().center_horizontally().end() |
| 63 | + case _: |
| 64 | + r.image(os.path.join( |
| 65 | + os.path.join(os.path.dirname(__file__), "../assets/font-awesome", 'stopwatch.png'))).end() |
| 66 | + if repeat: |
| 67 | + await asyncio.sleep(0.1) |
| 68 | + else: |
| 69 | + return |
56 | 70 |
|
57 | 71 | @staticmethod |
58 | 72 | def time_diff_to_str(diff): |
59 | | - seconds = diff.total_seconds() |
60 | | - minutes, seconds = divmod(seconds, 60) |
| 73 | + total_seconds = diff.total_seconds() |
| 74 | + minutes, seconds = divmod(total_seconds, 60) |
61 | 75 | hours, minutes = divmod(minutes, 60) |
| 76 | + if total_seconds < 60: |
| 77 | + return f'{int(seconds):02d}' |
| 78 | + elif total_seconds < 3600: |
| 79 | + return f'{int(minutes):02d}:{int(seconds):02d}' |
62 | 80 | return f'{int(hours):02d}:{int(minutes):02d}:{int(seconds):02d}' |
0 commit comments