pysfi 0.1.0__py3-none-any.whl → 0.1.4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,367 +1,367 @@
1
- from __future__ import annotations
2
-
3
- import argparse
4
- import logging
5
- import random
6
- import sys
7
- from datetime import datetime, timedelta, timezone
8
- from functools import partial
9
- from typing import ClassVar
10
-
11
- import qdarkstyle
12
- from PySide2.QtCore import QSize, Qt, QTime, QTimer
13
- from PySide2.QtGui import QCloseEvent
14
- from PySide2.QtWidgets import (
15
- QApplication,
16
- QCheckBox,
17
- QDialog,
18
- QHBoxLayout,
19
- QLabel,
20
- QMainWindow,
21
- QPushButton,
22
- QTimeEdit,
23
- QVBoxLayout,
24
- QWidget,
25
- )
26
-
27
- __version__ = "0.1.2"
28
- __build_date__ = "2025-09-16"
29
-
30
-
31
- class AlarmClockConfig:
32
- """Alarm clock configuration."""
33
-
34
- ALARM_CLOCK_TITLE = "Digital Alarm Clock"
35
-
36
- DIGITAL_FONT: str = "bold italic 81px 'Consolas'"
37
- DIGITAL_COLOR: str = "#ccee00"
38
- DIGITAL_BORDER_COLORS: ClassVar[list[str]] = [
39
- "#00aa00",
40
- "#eecc00",
41
- "#aa00aa",
42
- "#c0e0b0",
43
- ]
44
- DIGITAL_TIMER_FORMAT: str = "%H:%M:%S"
45
- DIGITAL_UPDATE_INTERVAL: int = 1000
46
-
47
- BLINK_TITLE: str = "Alarm Reminder!"
48
- BLINK_CONTENT: str = "⏰ Time's Up!"
49
- BLINK_TYPE: str = "color" # Options: 'color' or 'opacity'
50
- BLINK_BG_COLORS: ClassVar[list[str]] = [
51
- "#baf1ba",
52
- "#f8ccc3",
53
- "#aab4f0",
54
- "#efaec0",
55
- ]
56
- BLINK_INTERVAL: ClassVar[int] = 300 # ms
57
- DELAY_STEPS: ClassVar[list[int]] = [1, 5, 10, 15, 30, 60] # minutes
58
-
59
-
60
- logging.basicConfig(level=logging.INFO, format="%(message)s")
61
-
62
- conf = AlarmClockConfig()
63
- logger = logging.getLogger(__name__)
64
-
65
-
66
- class DigitalClock(QLabel):
67
- """Cool digital clock display."""
68
-
69
- def __init__(self, parent: QWidget | None = None) -> None:
70
- super().__init__(parent)
71
-
72
- self.setAlignment(Qt.AlignCenter) # type: ignore
73
-
74
- self._color = conf.DIGITAL_BORDER_COLORS[0]
75
-
76
- # Timer to update current time
77
- self._timer = QTimer()
78
- self._timer.timeout.connect(self.update_time) # type: ignore
79
- self._timer.start(conf.DIGITAL_UPDATE_INTERVAL) # Update every second
80
-
81
- self.update_time()
82
-
83
- def update_time(self) -> None:
84
- """Update current time display."""
85
- current = datetime.now(timezone.utc) + timedelta(hours=8) # Beijing time
86
- self.setText(current.strftime(conf.DIGITAL_TIMER_FORMAT))
87
- logger.debug(f"Updated time: {current}")
88
-
89
- # Add blink effect
90
- self._color = random.choice(
91
- [_ for _ in conf.DIGITAL_BORDER_COLORS if _ != self._color],
92
- )
93
- self.setStyleSheet(f"""
94
- font: {conf.DIGITAL_FONT};
95
- color: {conf.DIGITAL_COLOR};
96
- background-color: black;
97
- border: 2px dashed {self._color};
98
- border-radius: 10px;
99
- padding: 10px;
100
- """)
101
-
102
-
103
- class BlinkDialog(QDialog):
104
- """Alarm reminder dialog."""
105
-
106
- def __init__(self) -> None:
107
- super().__init__()
108
-
109
- self.setWindowTitle(conf.BLINK_TITLE)
110
- self.setModal(True)
111
- self.setWindowFlags(
112
- self.windowFlags() | Qt.WindowStaysOnTopHint | Qt.WindowType.Dialog, # type: ignore
113
- )
114
- self.setFixedSize(QSize(400, 240))
115
-
116
- layout = QVBoxLayout()
117
- msg_label = QLabel(conf.BLINK_CONTENT)
118
- msg_label.setStyleSheet("""
119
- color: red;
120
- font-size: 24px;
121
- """)
122
- msg_label.setAlignment(Qt.AlignmentFlag.AlignCenter) # type: ignore
123
-
124
- close_button = QPushButton("Close Alarm")
125
- close_button.clicked.connect(self.accept) # type: ignore
126
-
127
- layout.addWidget(msg_label)
128
- layout.addWidget(close_button)
129
- self.setLayout(layout)
130
-
131
- # Prevent user from closing dialog by other means, ensure button click only
132
- self.setWindowFlag(Qt.WindowCloseButtonHint, False) # type: ignore
133
-
134
- # Blink control variables and timer
135
- self.blink_timer = QTimer(self)
136
- self.blink_timer.timeout.connect(self.update_blink) # type: ignore
137
- self.blink_state = False
138
- self.blink_type = conf.BLINK_TYPE
139
-
140
- # Initialize style
141
- self.bg_color = random.choice(conf.BLINK_BG_COLORS)
142
- self.origin_style = self.styleSheet()
143
- self.blink_timer.start(conf.BLINK_INTERVAL)
144
-
145
- def update_blink(self) -> None:
146
- """Timer timeout, update blink state."""
147
- if self.blink_type == "color":
148
- # Color blink logic
149
- colors = [_ for _ in conf.BLINK_BG_COLORS[:] if _ != self.bg_color]
150
- self.setStyleSheet(f"background-color: {random.choice(colors)}")
151
- elif self.blink_type == "opacity":
152
- # Opacity blink logic - Note: Some systems may not fully support window opacity
153
- new_opacity = 0.3 if self.blink_state else 1.0
154
- self.setWindowOpacity(new_opacity)
155
-
156
- self.blink_state = not self.blink_state # Toggle state
157
-
158
- def stop_blinking(self) -> None:
159
- """Stop blinking, restore original style."""
160
- self.blink_timer.stop()
161
- self.setStyleSheet(self.origin_style) # Restore original style
162
- self.setWindowOpacity(1.0) # Ensure opacity is restored
163
-
164
- def closeEvent(self, event: QCloseEvent) -> None: # noqa: N802
165
- """Override close event, ensure timer stops."""
166
- self.stop_blinking()
167
- super().closeEvent(event)
168
-
169
-
170
- class AlarmClock(QMainWindow):
171
- """Digital alarm clock GUI."""
172
-
173
- def __init__(self) -> None:
174
- super().__init__()
175
- self.setWindowTitle(f"{conf.ALARM_CLOCK_TITLE} v{__version__}")
176
- self.setGeometry(
177
- QApplication.desktop().screenGeometry().center().x() - self.width() // 4,
178
- QApplication.desktop().screenGeometry().center().y() - self.height() // 2,
179
- self.width(),
180
- self.height(),
181
- )
182
- self.adjustSize()
183
-
184
- # Set window style
185
- self.setStyleSheet("""
186
- QMainWindow {
187
- background-color: #2b2b2b;
188
- }
189
- QLabel {
190
- color: #ffffff;
191
- font-size: 14px;
192
- }
193
- QPushButton {
194
- background-color: #3a3a3a;
195
- color: white;
196
- border: 1px solid #5a5a5a;
197
- padding: 8px;
198
- border-radius: 4px;
199
- font-size: 14px;
200
- }
201
- QPushButton:hover {
202
- background-color: #4a4a4a;
203
- }
204
- QPushButton:disabled {
205
- background-color: #2a2a2a;
206
- color: #6a6a6a;
207
- }
208
- QCheckBox {
209
- color: white;
210
- font-size: 14px;
211
- }
212
- QTimeEdit {
213
- background-color: #3a3a3a;
214
- color: white;
215
- border: 1px solid #5a5a5a;
216
- padding: 5px;
217
- font-size: 14px;
218
- }
219
- """)
220
-
221
- # Create central widget
222
- central_widget = QWidget()
223
- self.setCentralWidget(central_widget)
224
-
225
- # Create layout
226
- main_layout = QVBoxLayout()
227
- main_layout.setSpacing(20)
228
- central_widget.setLayout(main_layout)
229
-
230
- # Cool digital clock display
231
- self.digital_clock = DigitalClock(parent=self)
232
- main_layout.addWidget(self.digital_clock)
233
-
234
- # Alarm time setting
235
- time_layout = QHBoxLayout()
236
- time_label = QLabel("Alarm Time:")
237
- time_label.setStyleSheet("color: white; font-size: 16px;")
238
- self.alarm_time_edit = QTimeEdit()
239
- self.alarm_time_edit.setDisplayFormat("HH:mm:ss")
240
- self.alarm_time_edit.setTime(
241
- QTime.currentTime().addSecs(conf.DELAY_STEPS[0] * 60),
242
- )
243
-
244
- time_layout.addWidget(time_label)
245
- time_layout.addWidget(self.alarm_time_edit)
246
- main_layout.addLayout(time_layout)
247
-
248
- delay_layout = QHBoxLayout()
249
- delay_label = QLabel("Delay (min):")
250
- delay_label.setStyleSheet("color: white; font-size: 16px;")
251
- delay_layout.addWidget(delay_label)
252
- for minutes in conf.DELAY_STEPS:
253
- button = QPushButton(str(minutes))
254
- button.setStyleSheet("color: white; font-size: 16px;")
255
- button.clicked.connect(partial(self.set_delay, minutes)) # type: ignore
256
- delay_layout.addWidget(button)
257
- main_layout.addLayout(delay_layout)
258
-
259
- # Repeat option
260
- self.repeat_checkbox = QCheckBox("Repeat")
261
- main_layout.addWidget(self.repeat_checkbox)
262
-
263
- # Control buttons
264
- button_layout = QHBoxLayout()
265
- self.set_alarm_button = QPushButton("Set Alarm")
266
- self.set_alarm_button.clicked.connect(self.set_alarm) # type: ignore
267
- self.cancel_alarm_button = QPushButton("Cancel Alarm")
268
- self.cancel_alarm_button.clicked.connect(self.cancel_alarm) # type: ignore
269
- self.cancel_alarm_button.setEnabled(False)
270
- button_layout.addWidget(self.set_alarm_button)
271
- button_layout.addWidget(self.cancel_alarm_button)
272
- main_layout.addLayout(button_layout)
273
-
274
- # Status display
275
- self.status_label = QLabel("Alarm not set")
276
- self.status_label.setAlignment(Qt.AlignCenter) # type: ignore
277
- self.status_label.setStyleSheet("color: #aaaaaa; font-size: 16px;")
278
- main_layout.addWidget(self.status_label)
279
-
280
- # Alarm timer
281
- self.alarm_timer = QTimer()
282
- self.alarm_timer.timeout.connect(self.check_alarm) # type: ignore
283
-
284
- # Alarm state
285
- self.alarm_set = False
286
- self.alarm_time: QTime = QTime() # Explicit type
287
-
288
- def set_delay(self, minutes: int) -> None:
289
- """Set delay alarm."""
290
- self.alarm_time_edit.setTime(
291
- QTime.currentTime().addSecs(minutes * 60),
292
- )
293
-
294
- def set_alarm(self) -> None:
295
- """Set alarm."""
296
- self.alarm_time = self.alarm_time_edit.time()
297
- self.alarm_set = True
298
- self.alarm_timer.start(1000) # Check every second
299
- self.set_alarm_button.setEnabled(False)
300
- self.cancel_alarm_button.setEnabled(True)
301
- self.status_label.setText(
302
- f"Alarm set: {self.alarm_time.toString('HH:mm:ss')}",
303
- )
304
- self.status_label.setStyleSheet(
305
- "color: #00ff00; font-size: 16px; font-weight: bold;",
306
- )
307
-
308
- def cancel_alarm(self) -> None:
309
- """Cancel alarm."""
310
- self.alarm_set = False
311
- self.alarm_timer.stop()
312
- self.set_alarm_button.setEnabled(True)
313
- self.cancel_alarm_button.setEnabled(False)
314
- self.status_label.setText("Alarm cancelled")
315
- self.status_label.setStyleSheet("color: #aaaaaa; font-size: 16px;")
316
-
317
- def check_alarm(self) -> None:
318
- """Check if alarm time has arrived."""
319
- if not self.alarm_set:
320
- return
321
-
322
- current_time = QTime.currentTime()
323
- if (
324
- current_time.hour() == self.alarm_time.hour()
325
- and current_time.minute() == self.alarm_time.minute()
326
- and current_time.second() == self.alarm_time.second()
327
- ):
328
- # Show reminder message
329
- dialog = BlinkDialog()
330
- dialog.exec_()
331
-
332
- self.status_label.setText("⏰ Alarm Rang! ⏰")
333
- self.status_label.setStyleSheet(
334
- "color: #ff5555; font-size: 18px; font-weight: bold;",
335
- )
336
-
337
- # Add blink effect
338
- self.status_label.setStyleSheet("""
339
- color: #ff0000;
340
- font-size: 18px;
341
- font-weight: bold;
342
- background-color: #330000;
343
- border-radius: 5px;
344
- padding: 5px;
345
- """)
346
-
347
- # Cancel alarm if not repeating
348
- if not self.repeat_checkbox.isChecked():
349
- self.cancel_alarm()
350
-
351
-
352
- def main() -> None:
353
- parser = argparse.ArgumentParser(
354
- prog="alarmclock", description="Digital Alarm Clock"
355
- )
356
- parser.add_argument("-d", "--debug", action="store_true", help="Enable debug mode")
357
- parser.add_argument("-v", "--version", action="version", version=f"{__version__}")
358
-
359
- args = parser.parse_args()
360
- if args.debug:
361
- logger.setLevel(logging.DEBUG)
362
-
363
- app = QApplication(sys.argv)
364
- app.setStyleSheet(qdarkstyle.load_stylesheet_pyside2())
365
- window = AlarmClock()
366
- window.show()
367
- sys.exit(app.exec_())
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+ import logging
5
+ import random
6
+ import sys
7
+ from datetime import datetime, timedelta, timezone
8
+ from functools import partial
9
+ from typing import ClassVar
10
+
11
+ import qdarkstyle
12
+ from PySide2.QtCore import QSize, Qt, QTime, QTimer
13
+ from PySide2.QtGui import QCloseEvent
14
+ from PySide2.QtWidgets import (
15
+ QApplication,
16
+ QCheckBox,
17
+ QDialog,
18
+ QHBoxLayout,
19
+ QLabel,
20
+ QMainWindow,
21
+ QPushButton,
22
+ QTimeEdit,
23
+ QVBoxLayout,
24
+ QWidget,
25
+ )
26
+
27
+ __version__ = "0.1.2"
28
+ __build_date__ = "2025-09-16"
29
+
30
+
31
+ class AlarmClockConfig:
32
+ """Alarm clock configuration."""
33
+
34
+ ALARM_CLOCK_TITLE = "Digital Alarm Clock"
35
+
36
+ DIGITAL_FONT: str = "bold italic 81px 'Consolas'"
37
+ DIGITAL_COLOR: str = "#ccee00"
38
+ DIGITAL_BORDER_COLORS: ClassVar[list[str]] = [
39
+ "#00aa00",
40
+ "#eecc00",
41
+ "#aa00aa",
42
+ "#c0e0b0",
43
+ ]
44
+ DIGITAL_TIMER_FORMAT: str = "%H:%M:%S"
45
+ DIGITAL_UPDATE_INTERVAL: int = 1000
46
+
47
+ BLINK_TITLE: str = "Alarm Reminder!"
48
+ BLINK_CONTENT: str = "⏰ Time's Up!"
49
+ BLINK_TYPE: str = "color" # Options: 'color' or 'opacity'
50
+ BLINK_BG_COLORS: ClassVar[list[str]] = [
51
+ "#baf1ba",
52
+ "#f8ccc3",
53
+ "#aab4f0",
54
+ "#efaec0",
55
+ ]
56
+ BLINK_INTERVAL: ClassVar[int] = 300 # ms
57
+ DELAY_STEPS: ClassVar[list[int]] = [1, 5, 10, 15, 30, 60] # minutes
58
+
59
+
60
+ logging.basicConfig(level=logging.INFO, format="%(message)s")
61
+
62
+ conf = AlarmClockConfig()
63
+ logger = logging.getLogger(__name__)
64
+
65
+
66
+ class DigitalClock(QLabel):
67
+ """Cool digital clock display."""
68
+
69
+ def __init__(self, parent: QWidget | None = None) -> None:
70
+ super().__init__(parent)
71
+
72
+ self.setAlignment(Qt.AlignCenter) # type: ignore
73
+
74
+ self._color = conf.DIGITAL_BORDER_COLORS[0]
75
+
76
+ # Timer to update current time
77
+ self._timer = QTimer()
78
+ self._timer.timeout.connect(self.update_time) # type: ignore
79
+ self._timer.start(conf.DIGITAL_UPDATE_INTERVAL) # Update every second
80
+
81
+ self.update_time()
82
+
83
+ def update_time(self) -> None:
84
+ """Update current time display."""
85
+ current = datetime.now(timezone.utc) + timedelta(hours=8) # Beijing time
86
+ self.setText(current.strftime(conf.DIGITAL_TIMER_FORMAT))
87
+ logger.debug(f"Updated time: {current}")
88
+
89
+ # Add blink effect
90
+ self._color = random.choice(
91
+ [_ for _ in conf.DIGITAL_BORDER_COLORS if _ != self._color],
92
+ )
93
+ self.setStyleSheet(f"""
94
+ font: {conf.DIGITAL_FONT};
95
+ color: {conf.DIGITAL_COLOR};
96
+ background-color: black;
97
+ border: 2px dashed {self._color};
98
+ border-radius: 10px;
99
+ padding: 10px;
100
+ """)
101
+
102
+
103
+ class BlinkDialog(QDialog):
104
+ """Alarm reminder dialog."""
105
+
106
+ def __init__(self) -> None:
107
+ super().__init__()
108
+
109
+ self.setWindowTitle(conf.BLINK_TITLE)
110
+ self.setModal(True)
111
+ self.setWindowFlags(
112
+ self.windowFlags() | Qt.WindowStaysOnTopHint | Qt.WindowType.Dialog, # type: ignore
113
+ )
114
+ self.setFixedSize(QSize(400, 240))
115
+
116
+ layout = QVBoxLayout()
117
+ msg_label = QLabel(conf.BLINK_CONTENT)
118
+ msg_label.setStyleSheet("""
119
+ color: red;
120
+ font-size: 24px;
121
+ """)
122
+ msg_label.setAlignment(Qt.AlignmentFlag.AlignCenter) # type: ignore
123
+
124
+ close_button = QPushButton("Close Alarm")
125
+ close_button.clicked.connect(self.accept) # type: ignore
126
+
127
+ layout.addWidget(msg_label)
128
+ layout.addWidget(close_button)
129
+ self.setLayout(layout)
130
+
131
+ # Prevent user from closing dialog by other means, ensure button click only
132
+ self.setWindowFlag(Qt.WindowCloseButtonHint, False) # type: ignore
133
+
134
+ # Blink control variables and timer
135
+ self.blink_timer = QTimer(self)
136
+ self.blink_timer.timeout.connect(self.update_blink) # type: ignore
137
+ self.blink_state = False
138
+ self.blink_type = conf.BLINK_TYPE
139
+
140
+ # Initialize style
141
+ self.bg_color = random.choice(conf.BLINK_BG_COLORS)
142
+ self.origin_style = self.styleSheet()
143
+ self.blink_timer.start(conf.BLINK_INTERVAL)
144
+
145
+ def update_blink(self) -> None:
146
+ """Timer timeout, update blink state."""
147
+ if self.blink_type == "color":
148
+ # Color blink logic
149
+ colors = [_ for _ in conf.BLINK_BG_COLORS[:] if _ != self.bg_color]
150
+ self.setStyleSheet(f"background-color: {random.choice(colors)}")
151
+ elif self.blink_type == "opacity":
152
+ # Opacity blink logic - Note: Some systems may not fully support window opacity
153
+ new_opacity = 0.3 if self.blink_state else 1.0
154
+ self.setWindowOpacity(new_opacity)
155
+
156
+ self.blink_state = not self.blink_state # Toggle state
157
+
158
+ def stop_blinking(self) -> None:
159
+ """Stop blinking, restore original style."""
160
+ self.blink_timer.stop()
161
+ self.setStyleSheet(self.origin_style) # Restore original style
162
+ self.setWindowOpacity(1.0) # Ensure opacity is restored
163
+
164
+ def closeEvent(self, event: QCloseEvent) -> None: # noqa: N802
165
+ """Override close event, ensure timer stops."""
166
+ self.stop_blinking()
167
+ super().closeEvent(event)
168
+
169
+
170
+ class AlarmClock(QMainWindow):
171
+ """Digital alarm clock GUI."""
172
+
173
+ def __init__(self) -> None:
174
+ super().__init__()
175
+ self.setWindowTitle(f"{conf.ALARM_CLOCK_TITLE} v{__version__}")
176
+ self.setGeometry(
177
+ QApplication.desktop().screenGeometry().center().x() - self.width() // 4,
178
+ QApplication.desktop().screenGeometry().center().y() - self.height() // 2,
179
+ self.width(),
180
+ self.height(),
181
+ )
182
+ self.adjustSize()
183
+
184
+ # Set window style
185
+ self.setStyleSheet("""
186
+ QMainWindow {
187
+ background-color: #2b2b2b;
188
+ }
189
+ QLabel {
190
+ color: #ffffff;
191
+ font-size: 14px;
192
+ }
193
+ QPushButton {
194
+ background-color: #3a3a3a;
195
+ color: white;
196
+ border: 1px solid #5a5a5a;
197
+ padding: 8px;
198
+ border-radius: 4px;
199
+ font-size: 14px;
200
+ }
201
+ QPushButton:hover {
202
+ background-color: #4a4a4a;
203
+ }
204
+ QPushButton:disabled {
205
+ background-color: #2a2a2a;
206
+ color: #6a6a6a;
207
+ }
208
+ QCheckBox {
209
+ color: white;
210
+ font-size: 14px;
211
+ }
212
+ QTimeEdit {
213
+ background-color: #3a3a3a;
214
+ color: white;
215
+ border: 1px solid #5a5a5a;
216
+ padding: 5px;
217
+ font-size: 14px;
218
+ }
219
+ """)
220
+
221
+ # Create central widget
222
+ central_widget = QWidget()
223
+ self.setCentralWidget(central_widget)
224
+
225
+ # Create layout
226
+ main_layout = QVBoxLayout()
227
+ main_layout.setSpacing(20)
228
+ central_widget.setLayout(main_layout)
229
+
230
+ # Cool digital clock display
231
+ self.digital_clock = DigitalClock(parent=self)
232
+ main_layout.addWidget(self.digital_clock)
233
+
234
+ # Alarm time setting
235
+ time_layout = QHBoxLayout()
236
+ time_label = QLabel("Alarm Time:")
237
+ time_label.setStyleSheet("color: white; font-size: 16px;")
238
+ self.alarm_time_edit = QTimeEdit()
239
+ self.alarm_time_edit.setDisplayFormat("HH:mm:ss")
240
+ self.alarm_time_edit.setTime(
241
+ QTime.currentTime().addSecs(conf.DELAY_STEPS[0] * 60),
242
+ )
243
+
244
+ time_layout.addWidget(time_label)
245
+ time_layout.addWidget(self.alarm_time_edit)
246
+ main_layout.addLayout(time_layout)
247
+
248
+ delay_layout = QHBoxLayout()
249
+ delay_label = QLabel("Delay (min):")
250
+ delay_label.setStyleSheet("color: white; font-size: 16px;")
251
+ delay_layout.addWidget(delay_label)
252
+ for minutes in conf.DELAY_STEPS:
253
+ button = QPushButton(str(minutes))
254
+ button.setStyleSheet("color: white; font-size: 16px;")
255
+ button.clicked.connect(partial(self.set_delay, minutes)) # type: ignore
256
+ delay_layout.addWidget(button)
257
+ main_layout.addLayout(delay_layout)
258
+
259
+ # Repeat option
260
+ self.repeat_checkbox = QCheckBox("Repeat")
261
+ main_layout.addWidget(self.repeat_checkbox)
262
+
263
+ # Control buttons
264
+ button_layout = QHBoxLayout()
265
+ self.set_alarm_button = QPushButton("Set Alarm")
266
+ self.set_alarm_button.clicked.connect(self.set_alarm) # type: ignore
267
+ self.cancel_alarm_button = QPushButton("Cancel Alarm")
268
+ self.cancel_alarm_button.clicked.connect(self.cancel_alarm) # type: ignore
269
+ self.cancel_alarm_button.setEnabled(False)
270
+ button_layout.addWidget(self.set_alarm_button)
271
+ button_layout.addWidget(self.cancel_alarm_button)
272
+ main_layout.addLayout(button_layout)
273
+
274
+ # Status display
275
+ self.status_label = QLabel("Alarm not set")
276
+ self.status_label.setAlignment(Qt.AlignCenter) # type: ignore
277
+ self.status_label.setStyleSheet("color: #aaaaaa; font-size: 16px;")
278
+ main_layout.addWidget(self.status_label)
279
+
280
+ # Alarm timer
281
+ self.alarm_timer = QTimer()
282
+ self.alarm_timer.timeout.connect(self.check_alarm) # type: ignore
283
+
284
+ # Alarm state
285
+ self.alarm_set = False
286
+ self.alarm_time: QTime = QTime() # Explicit type
287
+
288
+ def set_delay(self, minutes: int) -> None:
289
+ """Set delay alarm."""
290
+ self.alarm_time_edit.setTime(
291
+ QTime.currentTime().addSecs(minutes * 60),
292
+ )
293
+
294
+ def set_alarm(self) -> None:
295
+ """Set alarm."""
296
+ self.alarm_time = self.alarm_time_edit.time()
297
+ self.alarm_set = True
298
+ self.alarm_timer.start(1000) # Check every second
299
+ self.set_alarm_button.setEnabled(False)
300
+ self.cancel_alarm_button.setEnabled(True)
301
+ self.status_label.setText(
302
+ f"Alarm set: {self.alarm_time.toString('HH:mm:ss')}",
303
+ )
304
+ self.status_label.setStyleSheet(
305
+ "color: #00ff00; font-size: 16px; font-weight: bold;",
306
+ )
307
+
308
+ def cancel_alarm(self) -> None:
309
+ """Cancel alarm."""
310
+ self.alarm_set = False
311
+ self.alarm_timer.stop()
312
+ self.set_alarm_button.setEnabled(True)
313
+ self.cancel_alarm_button.setEnabled(False)
314
+ self.status_label.setText("Alarm cancelled")
315
+ self.status_label.setStyleSheet("color: #aaaaaa; font-size: 16px;")
316
+
317
+ def check_alarm(self) -> None:
318
+ """Check if alarm time has arrived."""
319
+ if not self.alarm_set:
320
+ return
321
+
322
+ current_time = QTime.currentTime()
323
+ if (
324
+ current_time.hour() == self.alarm_time.hour()
325
+ and current_time.minute() == self.alarm_time.minute()
326
+ and current_time.second() == self.alarm_time.second()
327
+ ):
328
+ # Show reminder message
329
+ dialog = BlinkDialog()
330
+ dialog.exec_()
331
+
332
+ self.status_label.setText("⏰ Alarm Rang! ⏰")
333
+ self.status_label.setStyleSheet(
334
+ "color: #ff5555; font-size: 18px; font-weight: bold;",
335
+ )
336
+
337
+ # Add blink effect
338
+ self.status_label.setStyleSheet("""
339
+ color: #ff0000;
340
+ font-size: 18px;
341
+ font-weight: bold;
342
+ background-color: #330000;
343
+ border-radius: 5px;
344
+ padding: 5px;
345
+ """)
346
+
347
+ # Cancel alarm if not repeating
348
+ if not self.repeat_checkbox.isChecked():
349
+ self.cancel_alarm()
350
+
351
+
352
+ def main() -> None:
353
+ parser = argparse.ArgumentParser(
354
+ prog="alarmclock", description="Digital Alarm Clock"
355
+ )
356
+ parser.add_argument("-d", "--debug", action="store_true", help="Enable debug mode")
357
+ parser.add_argument("-v", "--version", action="version", version=f"{__version__}")
358
+
359
+ args = parser.parse_args()
360
+ if args.debug:
361
+ logger.setLevel(logging.DEBUG)
362
+
363
+ app = QApplication(sys.argv)
364
+ app.setStyleSheet(qdarkstyle.load_stylesheet_pyside2())
365
+ window = AlarmClock()
366
+ window.show()
367
+ sys.exit(app.exec_())