Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions taskon/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,44 @@ def __init__(self, work_min=20, short_break_min=5, long_break_min=20,
self.WORK_REPS = work_reps
self.COUNTER_SECOND = counter_second
self.INITIAL_VALUE = initial_value

@property
def work_min(self):
return self.WORK_MIN

@work_min.setter
def work_min(self, value):
if value < 0:
raise ValueError("Work minutes must be non-negative.")
self.WORK_MIN = value

@property
def short_break_min(self):
return self.SHORT_BREAK_MIN

@short_break_min.setter
def short_break_min(self, value):
if value < 0:
raise ValueError("Short break must be non-negative.")
self.SHORT_BREAK_MIN = value

@property
def long_break_min(self):
return self.LONG_BREAK_MIN

@long_break_min.setter
def long_break_min(self, value):
if value < 0:
raise ValueError("Long break must be non-negative.")
self.LONG_BREAK_MIN = value

@property
def work_reps(self):
return self.WORK_REPS

@work_reps.setter
def work_reps(self, value):
if value < 0:
raise ValueError("Work repetitions must be non-negative.")
self.WORK_REPS = value

32 changes: 27 additions & 5 deletions taskon/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from tkinter import Tk

from taskon.app import TaskOnApp
from taskon.messagebox import CustomInputDialog
from taskon.resources import ResourceLoader
from taskon.audio_service import PygameAudionService
from taskon.config import TaskConfig
Expand All @@ -17,8 +18,10 @@ def main():
"""
Initialize and run the TaskOn application.
"""
# Create the main application window
# Create the main application window and hide
root = Tk()
root.withdraw()

root.title("TaskOn")
root.geometry("250x350")
root.config(padx=5, pady=5, bg="#fdfdfd")
Expand All @@ -29,6 +32,7 @@ def main():
icon_path = loader.get_resource_path("growing-seed.ico")
root.iconbitmap(icon_path)


images = {
"moon": loader.load_image("clock-green.png"),
"oak": loader.load_image("growing-seed.png"),
Expand All @@ -44,11 +48,29 @@ def main():
audio = PygameAudionService()
config = TaskConfig()

# Start the TaskOn application
TaskOnApp(root, images, audio, config)
# Ask for user input
dialog = CustomInputDialog(root, prompt="Enter number of study minutes:", icon_path=icon_path)
root.wait_window(dialog)

value = dialog.result

if value is not None:
try:
minutes = int(value)
config.work_min = minutes

# Show main window
root.deiconify()

# Start the TaskOn application
TaskOnApp(root, images, audio, config)

# Run the Tkinter main loop
root.mainloop()
# Run the Tkinter main loop
root.mainloop()
except ValueError:
raise ValueError("Invalid input. Please enter a valid number.")
else:
root.destroy()


if __name__ == "__main__":
Expand Down
73 changes: 73 additions & 0 deletions taskon/messagebox.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import tkinter as tk

class CustomInputDialog(tk.Toplevel):
"""
Custom input dialog that accepts an integer value.

Args:
parent (tk.Widget): Parent widget.
prompt (str): Prompt text to display.
default (str): Default value in the entry field (default "20").
icon_path (str, optional): Path to icon file for the window.
"""

def __init__(self, parent, prompt, default="20", icon_path=None):
super().__init__(parent)
self.title("TaskOn")
self.geometry("220x100")
self.result = None


if icon_path:
try:
self.iconbitmap(icon_path)
except Exception as e:
print("Failed to set icon:", e)

# Prompt label
tk.Label(self, text=prompt).pack(pady=3)

# Entry field
self.entry = tk.Entry(self, width=30)
self.entry.insert(0, default)
self.entry.pack(pady=5, padx=10)
self.entry.focus_set()

# Button frame
btn_frame = tk.Frame(self)
btn_frame.pack(pady=10)

# Button style configuration
button_style = {
"width": 10,
"height": 1,
"bg": "#4CAF50",
"fg": "white",
"activebackground": "#45a049",
"activeforeground": "white",
"bd": 0,
"font": ("Arial", 9, "bold")
}

cancel_style = button_style.copy()
cancel_style["bg"] = "#f44336"
cancel_style["activebackground"] = "#d32f2f"

# OK and Cancel buttons
tk.Button(btn_frame, text="OK", command=self.on_ok, **button_style).pack(side="left", padx=5)
tk.Button(btn_frame, text="Cancel", command=self.on_cancel, **cancel_style).pack(side="left", padx=5)

# Key bindings
self.bind("<Return>", lambda event: self.on_ok())
self.bind("<Escape>", lambda event: self.on_cancel())

def on_ok(self):
value = self.entry.get()
if not value.isdigit():
raise ValueError("Work minutes must be an integer.")
self.result = int(value)
self.destroy()

def on_cancel(self):
self.result = None
self.destroy()