Skip to content

Commit 1d08798

Browse files
author
mary
committed
Add the Alarm_Clock ap
1 parent 98d86cb commit 1d08798

File tree

9 files changed

+629
-0
lines changed

9 files changed

+629
-0
lines changed
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import time
2+
from datetime import datetime
3+
from threading import Event
4+
from typing import List
5+
from configuration import TIME_RELAPSE, TIME_SPEED
6+
7+
8+
def get_date_now() -> int:
9+
time_now: datetime = datetime.now()
10+
current_hour: int = time_now.hour
11+
current_minutes: int = time_now.minute
12+
current_seconds: int = time_now.second
13+
current_time: int = 3600 * current_hour + 60 * current_minutes + current_seconds
14+
15+
return current_time
16+
17+
18+
class AlarmClock:
19+
total_time: int
20+
days: List[str:]
21+
event: Event
22+
clock: str
23+
24+
def __init__(self, clock, event, days):
25+
self.clock = clock
26+
self.event = event
27+
self.days = days
28+
self.total_time = self.user_time()
29+
30+
self.start_alarm()
31+
32+
def user_time(self) -> int:
33+
"""
34+
It take the user time and it change to seconds
35+
"""
36+
user_hour_minutes = self.clock.split(':')
37+
hour = int(user_hour_minutes[0])
38+
minutes = int(user_hour_minutes[1])
39+
40+
return 3600 * hour + 60 * minutes
41+
42+
def check_day(self) -> None:
43+
"""
44+
It check the self.days if a item from the list is the current day it will remove
45+
46+
"""
47+
initial_day = time.strftime('%a')
48+
for day in self.days:
49+
if day == initial_day:
50+
self.days.remove(day)
51+
52+
def counter_timer(self) -> None:
53+
"""
54+
It counts the seconds for the alarm, if the alarm is done it will start again after 60 seconds to check for
55+
other alarm
56+
57+
"""
58+
current_time = get_date_now()
59+
if current_time >= self.total_time:
60+
time.sleep(TIME_RELAPSE)
61+
self.start_alarm()
62+
else:
63+
time.sleep(TIME_SPEED)
64+
65+
def start_alarm(self) -> None:
66+
while not self.event.is_set():
67+
if len(self.days) == 0:
68+
break
69+
else:
70+
self.check_day()
71+
while not self.event.is_set():
72+
self.counter_timer()
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Configuration for the app size and title
2+
from typing import Dict, Tuple, List
3+
4+
WIDTH: int = 600
5+
HEIGHT: int = 700
6+
ICON_PATH: str = 'media/image/empty.ico'
7+
TITLE_APP: str = ''
8+
THEME: str = 'darkly'
9+
10+
# Configuration for the top level
11+
LIST_DAY: tuple[str:] = ('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat',)
12+
TOP_LEVEL: dict[str, int] = dict(WIDTH = 300, HEIGHT = 300)
13+
14+
# Configuration for the backend of alarm
15+
TIME_RELAPSE = 60
16+
TIME_SPEED = 1
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
from threading import Thread, Event
2+
from configuration import LIST_DAY
3+
import ttkbootstrap as ttk
4+
from backend_alarm import AlarmClock
5+
6+
7+
def start_alarm(clock: str, event: Event, days: str) -> None:
8+
AlarmClock(clock = clock, event = event, days = days).start_alarm()
9+
10+
11+
class AlarmsFrame(ttk.Frame):
12+
def __init__(self, parent, text):
13+
super().__init__(master = parent, )
14+
15+
# set style
16+
self.style = ttk.Style()
17+
# styling the delete button
18+
self.style.configure(
19+
style = 'Delete.TButton',
20+
background = '#e74c3c',
21+
anchor = 'center',
22+
font = ('Helvetica', 14, 'bold')
23+
)
24+
25+
self.style.map(
26+
style = 'Delete.TButton',
27+
background = [('active', '#e74c3c')],
28+
bordercolor = '#e74c3c',
29+
)
30+
31+
# styling the time label for the alarm
32+
self.style.configure(
33+
style = 'Alarm_Set.TLabel',
34+
anchor = 'center',
35+
font = ('Helvetica', 18, 'bold')
36+
)
37+
38+
# set grid layout
39+
self.event = Event()
40+
self.rowconfigure((0, 1), weight = 1, uniform = 'a')
41+
self.columnconfigure(list(range(0, 7)), weight = 1, uniform = 'a')
42+
43+
# set data
44+
self.day_label = list(range(7))
45+
self.days_on = list()
46+
self.time_str = text
47+
self.variable_checkbutton = ttk.BooleanVar()
48+
49+
# set widgets
50+
self.time_label = ttk.Label(
51+
style = 'Alarm_Set.TLabel',
52+
master = self,
53+
text = self.time_str,
54+
)
55+
56+
self.checkbutton = ttk.Checkbutton(
57+
master = self,
58+
variable = self.variable_checkbutton,
59+
command = self.set_alarm
60+
)
61+
62+
self.delete_button = ttk.Button(
63+
master = self,
64+
style = 'Delete.TButton',
65+
text = 'Delete',
66+
command = self.delete_alarm
67+
)
68+
69+
# set layout
70+
self.time_label.grid(row = 0, column = 0, sticky = 'news')
71+
self.checkbutton.grid(row = 0, column = 5, sticky = 'nse')
72+
self.delete_button.grid(row = 0, column = 6, sticky = 'news')
73+
74+
# add the layer of day
75+
for index, day in enumerate(LIST_DAY):
76+
self.day_label[index] = DayButton(
77+
parent = self,
78+
day_name = day,
79+
row = 1,
80+
column = index,
81+
)
82+
83+
def set_alarm(self):
84+
85+
self.select_days()
86+
alarm_test = Thread(
87+
target = start_alarm,
88+
args = (self.time_str, self.event, self.days_on),
89+
daemon = True
90+
)
91+
92+
if self.variable_checkbutton.get():
93+
self.event.clear()
94+
alarm_test.start()
95+
else:
96+
self.event.set()
97+
98+
def delete_alarm(self):
99+
self.event.set()
100+
self.destroy()
101+
102+
def select_days(self):
103+
104+
self.days_on.clear()
105+
for i in range(7):
106+
if not self.day_label[i].state.get():
107+
self.days_on.append(self.day_label[i]['text'])
108+
109+
110+
class DayButton(ttk.Label):
111+
112+
def __init__(self, parent, day_name, row, column):
113+
self.style = ttk.Style()
114+
self.style.configure(
115+
style = 'Day.TLabel',
116+
font = ('Helvetica', 16),
117+
)
118+
super().__init__(
119+
master = parent,
120+
text = day_name,
121+
style = 'Day.TLabel',
122+
anchor = 'center',
123+
background = '#303030'
124+
)
125+
self.state = ttk.BooleanVar(value = True)
126+
self.grid(
127+
row = row,
128+
column = column,
129+
sticky = 'news',
130+
padx = 2,
131+
pady = 2
132+
)
133+
self.bind('<Enter>', self.enter_alarm)
134+
self.bind('<Leave>', self.leave_alarm)
135+
self.bind('<Button-1>', self.select_alarm)
136+
137+
def enter_alarm(self, event = None):
138+
if self.state.get():
139+
self.configure(background = '#526170')
140+
141+
def leave_alarm(self, event = None):
142+
if self.state.get():
143+
self.configure(background = '#303030')
144+
145+
def select_alarm(self, event = None):
146+
if self.state.get():
147+
self.configure(background = '#00bc8c')
148+
self.state.set(False)
149+
else:
150+
self.configure(background = '#303030')
151+
self.state.set(True)

PYTHON APPS/Alarm_Clock/main.py

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
from tkinter import IntVar
2+
3+
from toplevel import TopLevel
4+
import ttkbootstrap as ttk
5+
from configuration import (
6+
WIDTH, HEIGHT,
7+
ICON_PATH, TITLE_APP,
8+
THEME,
9+
)
10+
from widgets import (
11+
ClockFrame, AlarmClockPanel,
12+
AddAlarmClock, AlarmsFrame,
13+
)
14+
15+
# Import the libraries for changing the title bar color, it works only on windows :/
16+
try:
17+
from ctypes import windll, byref, sizeof, c_int
18+
except ImportError:
19+
pass
20+
21+
22+
class App(ttk.Window):
23+
hour_int: IntVar
24+
minute_int: IntVar
25+
26+
alarm_panel: AlarmClockPanel
27+
button_top_level: AddAlarmClock
28+
clock_frame: ClockFrame
29+
30+
def __init__(self):
31+
super().__init__(themename = THEME)
32+
self.bind('<Alt-s>', lambda even: self.destroy())
33+
self.set_geometry(height = HEIGHT, width = WIDTH)
34+
self.title(TITLE_APP)
35+
self.set_icon(path_image = ICON_PATH)
36+
self.set_title_color()
37+
38+
# set data
39+
40+
self.hour_int = ttk.IntVar(value = 0)
41+
self.minute_int = ttk.IntVar(value = 0)
42+
self.top_level = None
43+
44+
# create widgets
45+
self.clock_frame = ClockFrame(self)
46+
self.alarm_panel = AlarmClockPanel(parent = self)
47+
self.button_top_level = AddAlarmClock(parent = self, button_function = self.start_top_level)
48+
49+
# set layout for widgets(place method)
50+
self.clock_frame.place(
51+
relx = 0,
52+
rely = 0,
53+
relwidth = 1,
54+
relheight = 0.3,
55+
anchor = 'nw'
56+
)
57+
self.alarm_panel.place(
58+
relx = 0,
59+
rely = 0.3,
60+
relwidth = 1,
61+
relheight = 0.6,
62+
anchor = 'nw'
63+
)
64+
self.button_top_level.place(
65+
relx = 0.5,
66+
rely = 0.95,
67+
anchor = 'center'
68+
)
69+
70+
# Set a model for the alarm :), you can eliminate if you don t like it
71+
# Start here
72+
alarm = AlarmsFrame(
73+
parent = self.alarm_panel,
74+
text = '12:00',
75+
)
76+
self.alarm_panel.add_alarm(alarm)
77+
# Stop here
78+
79+
# run the window
80+
self.mainloop()
81+
82+
def set_icon(self, path_image: str) -> None:
83+
try:
84+
self.iconbitmap(path_image)
85+
except Exception:
86+
pass
87+
88+
def set_geometry(self, width: int, height: int) -> None:
89+
"""
90+
It make the windows to be in the center of your desktop.
91+
The formula is down and you could found on the internet explained very well :)
92+
"""
93+
desktop_height = self.winfo_screenheight() # it take your desktop height
94+
desktop_width = self.winfo_screenwidth() # it take your desktop width
95+
window_top = int((desktop_height - height) / 2)
96+
window_left = int((desktop_width - width) / 2)
97+
self.geometry(f'{width}x{height}+{window_left}+{window_top}')
98+
99+
def set_title_color(self) -> None:
100+
try:
101+
HWND: int = windll.user32.GetParent(self.winfo_id())
102+
DWMWA_ATTRIBUTE: int = 35
103+
color: int = 0x00000000
104+
windll.dwmapi.DwmSetWindowAttribute(HWND, DWMWA_ATTRIBUTE, byref(c_int(color)), sizeof(c_int))
105+
106+
except Exception:
107+
pass
108+
109+
def start_top_level(self) -> None:
110+
"""
111+
It show the windows to set your alarm
112+
"""
113+
self.top_level = TopLevel(
114+
parent = self,
115+
hour_int = self.hour_int,
116+
minute_int = self.minute_int,
117+
ok_function = self.ok_button,
118+
cancel_function = self.cancel_button
119+
)
120+
121+
def ok_button(self) -> None:
122+
"""
123+
It take to input from the top level and paste the time of the alarm
124+
125+
"""
126+
if self.hour_int.get() or self.minute_int.get():
127+
128+
hour, minute = self.hour_int.get(), self.minute_int.get()
129+
hour_str = str(hour) if hour >= 10 else f'0{hour}'
130+
minutes_str = str(minute) if minute >= 10 else f'0{minute}'
131+
132+
text_label = f'{hour_str}:{minutes_str}'
133+
alarm_frame = AlarmsFrame(parent = self.alarm_panel, text = text_label)
134+
135+
self.alarm_panel.add_alarm(alarm_frame)
136+
self.hour_int.set(value = 0)
137+
self.minute_int.set(value = 0)
138+
self.top_level.destroy()
139+
140+
def cancel_button(self) -> None:
141+
142+
self.hour_int.set(value = 0)
143+
self.minute_int.set(value = 0)
144+
self.top_level.destroy()
145+
146+
147+
if __name__ == '__main__':
148+
App()
8.91 KB
Loading
4.19 KB
Binary file not shown.
82 KB
Binary file not shown.

0 commit comments

Comments
 (0)