Skip to content

Commit

Permalink
Merge pull request #3 from YanivDorGalron/colored_calendar
Browse files Browse the repository at this point in the history
Colored calendar
  • Loading branch information
YanivDorGalron authored Nov 26, 2024
2 parents ac0e634 + 48607ab commit bfe6919
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 20 deletions.
106 changes: 89 additions & 17 deletions FocusApp.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import datetime
import json
import threading

import tkinter as tk
from tkinter import messagebox
import customtkinter as ctk
Expand All @@ -9,7 +10,7 @@
from playsound import playsound

from utils import add_focus_session_to_calendar, get_resource_path

from consts import COLORS

class FocusApp(ctk.CTk):
def __init__(self):
Expand Down Expand Up @@ -58,26 +59,38 @@ def create_widgets(self):

# Timer Frame
timer_frame = ctk.CTkFrame(main_frame, fg_color="#2a2d2e", corner_radius=15)
timer_frame.grid(row=0, column=0, pady=(0, 20), sticky="ew")
timer_frame.grid(row=0, column=0, pady=(0, 10), sticky="ew")
timer_frame.grid_columnconfigure(0, weight=1)

self.focus_timer_label = ctk.CTkLabel(timer_frame, text="00:00",
font=ctk.CTkFont(size=60, weight="bold"),
font=ctk.CTkFont(size=40, weight="bold"),
text_color="#4CAF50")
self.focus_timer_label.grid(row=0, column=0, pady=(20, 10))
self.focus_timer_label.grid(row=0, column=0, pady=(10, 10))

self.break_timer_label = ctk.CTkLabel(timer_frame, text="00:00",
font=ctk.CTkFont(size=60, weight="bold"),
font=ctk.CTkFont(size=40, weight="bold"),
text_color="#4CAF50")
self.break_timer_label.grid(row=0, column=0, pady=(20, 10))
self.break_timer_label.grid(row=0, column=0, pady=(10, 10))

self.task_label = ctk.CTkLabel(timer_frame, text="Current Task: None",
font=ctk.CTkFont(size=16))
self.task_label.grid(row=1, column=0, pady=(0, 20))
self.task_label.grid(row=1, column=0, pady=(0, 10))

self.setted_focus_time_label = ctk.CTkLabel(timer_frame, text="Setted Focus Time: 0 min",
font=ctk.CTkFont(size=16))
self.setted_focus_time_label.grid(row=2, column=0, pady=(0, 10))

plus_minus_frame = ctk.CTkFrame(timer_frame)
plus_minus_frame.grid(row=3, column=0, padx=5, pady=5)

self.plus_5min_button = ctk.CTkButton(plus_minus_frame, text="+5 min", command=self.add_5_minutes, font=ctk.CTkFont(size=12),width =10)
self.plus_5min_button.grid(row=0, column=1, pady=(0, 10),padx=10)
self.minus_5min_button = ctk.CTkButton(plus_minus_frame, text="-5 min", command=self.minus_5_minutes, font=ctk.CTkFont(size=12),width =10)
self.minus_5min_button.grid(row=0, column=0, pady=(0, 10),padx=10)

# Input Frame
input_frame = ctk.CTkFrame(main_frame)
input_frame.grid(row=1, column=0, pady=(0, 20), sticky="ew")
input_frame.grid(row=1, column=0, pady=(0, 10), sticky="ew")
input_frame.grid_columnconfigure(1, weight=1)

# Task Entry
Expand Down Expand Up @@ -135,6 +148,10 @@ def create_widgets(self):
fg_color="#607D8B", hover_color="#455A64")
self.reset_stats_button.grid(row=0, column=0, padx=5)

self.freq_sound_var = tk.BooleanVar(value=True)
self.freq_sound_toggle = ctk.CTkSwitch(options_frame, text="Enable Frequent Sounds", variable=self.freq_sound_var)
self.freq_sound_toggle.grid(row=0, column=2, padx=5)

self.sound_var = tk.BooleanVar(value=True)
self.sound_toggle = ctk.CTkSwitch(options_frame, text="Enable Sounds", variable=self.sound_var)
self.sound_toggle.grid(row=0, column=1, padx=5)
Expand All @@ -147,6 +164,43 @@ def create_widgets(self):

self.update_productivity_graph()

# Dropdown label
label = ctk.CTkLabel(input_frame, text="Color:", font=("Arial", 14))
label.grid(row=3, column=0, padx=(10, 5), pady=5, sticky="w")

# Dropdown menu for selecting colors
self.color_var = ctk.StringVar(value="1: Light Blue") # Default selection
self.selected_color_id = 1
color_info = COLORS[self.selected_color_id]

self.color_dropdown = ctk.CTkOptionMenu(
input_frame,
variable=self.color_var,
values=[f"{color_id}: {color_info['name']}" for color_id, color_info in COLORS.items()],
command=self.on_color_select, # Called when a selection is made
fg_color=color_info["background"],
text_color="#000000", # Set the text color to black
button_color=color_info["background"],
)

self.color_dropdown.grid(row=3, column=1, pady=(0, 10), sticky="ew")

def add_5_minutes(self, force=False):
if self.focus_duration == 0 and not force:
messagebox.showwarning("Warning", "Please Start a session first.")
else:
self.focus_duration += 5
self.setted_focus_time_label.configure(text=f"Setted Focus Time: {self.focus_duration} min")

def minus_5_minutes(self):
if self.focus_duration == 0:
messagebox.showwarning("Warning", "Please Start a session first.")
elif self.focus_duration > 5:
self.focus_duration -= 5
else:
self.focus_duration = 0
self.setted_focus_time_label.configure(text=f"Setted Focus Time: {self.focus_duration} min")

def start_focus_session(self):
if not self.is_focus_running:
try:
Expand All @@ -165,6 +219,7 @@ def start_focus_session(self):
self.is_break_running = False
self.break_timer_label.configure(text="")
threading.Thread(target=self.run_timer, daemon=True).start()
self.setted_focus_time_label.configure(text=f"Setted Focus Time: {self.focus_duration} min")
except ValueError:
messagebox.showerror("Error", "Please enter a valid number for focus duration.")

Expand Down Expand Up @@ -203,7 +258,14 @@ def log_focus_to_calendar(self):
if self.start_time:
elapsed_minutes = self.elapsed_time // 60
cc_email = self.cc_email_entry.get()
add_focus_session_to_calendar(self.start_time, elapsed_minutes, self.task, cc_email if cc_email else None)
add_focus_session_to_calendar(self.start_time, elapsed_minutes, self.task, cc_email if cc_email else None, self.selected_color_id)

def focus_session_complete(self):
# Ask the user whether to add 5 more minutes
add_more_time = messagebox.askyesno("Add More Time", "Focus Session Complete! Would you like to add 5 more minutes?")
if add_more_time:
self.add_5_minutes(force=True)
return add_more_time

def run_timer(self):
self.start_time = datetime.datetime.utcnow()
Expand All @@ -218,17 +280,20 @@ def update_timers(self):
self.update_focus_timer()

# Play sound every 15 minutes
if self.elapsed_time - self.last_notification >= 900: # 900 seconds = 15 minutes
self.play_sound(get_resource_path("sounds/wow-171498.mp3"))
if self.elapsed_time - self.last_notification >= 900 and self.freq_sound_var.get(): # 900 seconds = 15 minutes
asyncio.run(self.play_sound(get_resource_path("sounds/wow-171498.mp3")))
self.last_notification = self.elapsed_time

if self.elapsed_time >= self.focus_duration * 60:
self.is_focus_running = False
self.play_sound(get_resource_path("sounds/success-fanfare-trumpets-6185.mp3"))
self.log_focus_to_calendar()
self.update_stats()
self.reset_focus_timer()
self.start_break_timer()
asyncio.run(self.play_sound(get_resource_path("sounds/success-fanfare-trumpets-6185.mp3")))
if self.focus_session_complete():
self.after(1000, self.update_timers)
else:
self.is_focus_running = False
self.log_focus_to_calendar()
self.update_stats()
self.reset_focus_timer()
self.start_break_timer()
else:
self.after(1000, self.update_timers)
elif self.is_break_running:
Expand Down Expand Up @@ -331,6 +396,13 @@ def update_productivity_graph(self):
self.fig.tight_layout()
self.canvas.draw()

def on_color_select(self, event):
"""Update the preview label with the selected color."""
self.selected_color_id = int(self.color_var.get().split(':')[0])
color_info = COLORS[self.selected_color_id]
self.color_dropdown.configure(fg_color=color_info["background"],
button_color = color_info["background"],) # Update background color

if __name__ == "__main__":
app = FocusApp()
app.mainloop()
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ To create an executable file using PyInstaller, follow these steps:

2. Command to create executable:
```
pyinstaller --add-data "sounds;sounds" FocusApp.py --name FocusApp --noconsole --add-data "cred.json;." --onefile"
pyinstaller --add-data "sounds;sounds" FocusApp.py --name FocusApp --noconsole --add-data "cred.json;." --onefile
```
3. The executable file will be generated in the `dist` folder.
Expand Down
14 changes: 14 additions & 0 deletions consts.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Predefined Google Calendar colors
COLORS = {
1: {"name": "Light Blue", "background": "#A4BDFC", "foreground": "#1D1D1D"},
2: {"name": "Light Green", "background": "#7AE7BF", "foreground": "#1D1D1D"},
3: {"name": "Light Purple", "background": "#DBADFF", "foreground": "#1D1D1D"},
4: {"name": "Light Red", "background": "#FF887C", "foreground": "#1D1D1D"},
5: {"name": "Light Yellow", "background": "#FBD75B", "foreground": "#1D1D1D"},
6: {"name": "Orange", "background": "#FFB878", "foreground": "#1D1D1D"},
7: {"name": "Turquoise", "background": "#46D6DB", "foreground": "#1D1D1D"},
8: {"name": "Gray", "background": "#E1E1E1", "foreground": "#1D1D1D"},
9: {"name": "Bold Blue", "background": "#5484ED", "foreground": "#FFFFFF"},
10: {"name": "Bold Green", "background": "#51B749", "foreground": "#FFFFFF"},
11: {"name": "Bold Red", "background": "#DC2127", "foreground": "#FFFFFF"},
}
6 changes: 4 additions & 2 deletions utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def authenticate_google_calendar():
return build('calendar', 'v3', credentials=creds)


def add_focus_session_to_calendar(start_time, focus_duration, task, cc_email=None):
def add_focus_session_to_calendar(start_time, focus_duration, task, cc_email=None,color_id=1):
service = authenticate_google_calendar()
event = {
'summary': f'Focus Session: {task}',
Expand All @@ -39,10 +39,12 @@ def add_focus_session_to_calendar(start_time, focus_duration, task, cc_email=Non
'end': {
'dateTime': (start_time + datetime.timedelta(minutes=focus_duration)).isoformat() + 'Z',
'timeZone': 'UTC',
}
},
'colorId': color_id,
}
if cc_email:
event['attendees'] = [{'email': cc_email}]

service.events().insert(calendarId='primary', body=event).execute()


Expand Down

0 comments on commit bfe6919

Please sign in to comment.