Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/env python3
- """
- Daily Routine Tracker - A Tkinter GUI application for tracking daily repetitive tasks.
- """
- import tkinter as tk
- from tkinter import messagebox
- from datetime import datetime
- from pathlib import Path
- import yaml
- import os
- class RoutineDiary:
- def __init__(self, root):
- self.root = root
- self.root.title("Daily Routine Tracker")
- self.root.geometry("400x600")
- self.tasks_file = Path("tasks.txt")
- self.diary_file = Path("diary.yaml")
- self.tasks = []
- self.today_clicks = {} # {task_name: [datetime, datetime, ...]}
- self.buttons = {} # {task_name: button_widget}
- self.load_tasks()
- self.load_today_clicks()
- self.create_gui()
- def load_tasks(self):
- """Load tasks from tasks.txt file."""
- if not self.tasks_file.exists():
- messagebox.showerror("Error", "tasks.txt file not found!")
- self.root.destroy()
- return
- with open(self.tasks_file, "r", encoding="utf-8") as f:
- self.tasks = [line.strip() for line in f if line.strip()]
- self.tasks = sorted(self.tasks, key=str.lower)
- def load_diary(self):
- """Load the entire diary from diary.yaml."""
- if not self.diary_file.exists():
- return []
- with open(self.diary_file, "r", encoding="utf-8") as f:
- content = f.read()
- if not content.strip():
- return []
- try:
- data = yaml.safe_load(content)
- return data if data else []
- except yaml.YAMLError:
- return []
- def load_today_clicks(self):
- """Load today's clicks from diary.yaml."""
- today_str = datetime.now().strftime("%Y-%m-%d")
- self.today_clicks = {}
- diary = self.load_diary()
- if not diary:
- return
- # Find today's section in the diary
- i = 0
- while i < len(diary):
- if diary[i] == today_str:
- # Found today's date, load all tasks until next date or end
- i += 1
- while i < len(diary):
- item = diary[i]
- if isinstance(item, dict):
- for task_name, timestamps in item.items():
- if isinstance(timestamps, list):
- self.today_clicks[task_name] = [
- datetime.strptime(ts, "%Y-%m-%d %H:%M")
- for ts in timestamps
- ]
- i += 1
- elif isinstance(item, str) and len(item) == 10 and item[4] == '-':
- # Next date found
- break
- else:
- i += 1
- break
- i += 1
- def save_diary(self):
- """Save click to diary.yaml."""
- today_str = datetime.now().strftime("%Y-%m-%d")
- diary = self.load_diary()
- # Find and remove today's section if it exists
- new_diary = []
- i = 0
- while i < len(diary):
- if diary[i] == today_str:
- # Skip today's date and all its tasks
- i += 1
- while i < len(diary):
- item = diary[i]
- if isinstance(item, str) and len(item) == 10 and item[4] == '-':
- # Next date found
- break
- i += 1
- else:
- new_diary.append(diary[i])
- i += 1
- # Add today's section with updated data
- if self.today_clicks:
- new_diary.append(today_str)
- for task_name in sorted(self.today_clicks.keys(), key=str.lower):
- timestamps = [dt.strftime("%Y-%m-%d %H:%M") for dt in self.today_clicks[task_name]]
- new_diary.append({task_name: timestamps})
- # Write to file
- with open(self.diary_file, "w", encoding="utf-8") as f:
- yaml.dump(new_diary, f, default_flow_style=None, allow_unicode=True, sort_keys=False)
- def create_gui(self):
- """Create the main GUI."""
- # Title label
- title_label = tk.Label(
- self.root,
- text="Daily Routines",
- font=("Arial", 16, "bold"),
- pady=10
- )
- title_label.pack()
- # Date label
- today_str = datetime.now().strftime("%Y-%m-%d")
- date_label = tk.Label(
- self.root,
- text=f"Today: {today_str}",
- font=("Arial", 12),
- pady=5
- )
- date_label.pack()
- # Scrollable frame for buttons
- container = tk.Frame(self.root)
- container.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
- canvas = tk.Canvas(container)
- scrollbar = tk.Scrollbar(container, orient="vertical", command=canvas.yview)
- self.scrollable_frame = tk.Frame(canvas)
- self.scrollable_frame.bind(
- "<Configure>",
- lambda e: canvas.configure(scrollregion=canvas.bbox("all"))
- )
- canvas.create_window((0, 0), window=self.scrollable_frame, anchor="nw")
- canvas.configure(yscrollcommand=scrollbar.set)
- # Bind mouse wheel scrolling
- def on_mousewheel(event):
- canvas.yview_scroll(int(-1 * (event.delta / 120)), "units")
- def on_mousewheel_linux(event):
- if event.num == 4:
- canvas.yview_scroll(-1, "units")
- elif event.num == 5:
- canvas.yview_scroll(1, "units")
- canvas.bind_all("<MouseWheel>", on_mousewheel)
- canvas.bind_all("<Button-4>", on_mousewheel_linux)
- canvas.bind_all("<Button-5>", on_mousewheel_linux)
- scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
- canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
- self.canvas = canvas
- self.update_buttons()
- def get_sorted_tasks(self):
- """Get tasks sorted according to the rules."""
- not_clicked = []
- clicked = []
- for task in self.tasks:
- if task in self.today_clicks and len(self.today_clicks[task]) > 0:
- clicked.append(task)
- else:
- not_clicked.append(task)
- not_clicked.sort(key=str.lower)
- clicked.sort(key=str.lower)
- return not_clicked + clicked
- def update_buttons(self):
- """Update the button display."""
- # Clear existing buttons
- for widget in self.scrollable_frame.winfo_children():
- widget.destroy()
- self.buttons = {}
- sorted_tasks = self.get_sorted_tasks()
- for task in sorted_tasks:
- click_count = len(self.today_clicks.get(task, []))
- if click_count > 0:
- button_text = f"{task} ({click_count})"
- bg_color = "#90EE90" # Light green for clicked
- else:
- button_text = task
- bg_color = "#F0F0F0" # Default gray
- btn = tk.Button(
- self.scrollable_frame,
- text=button_text,
- font=("Arial", 11),
- bg=bg_color,
- activebackground="#ADD8E6",
- anchor="w",
- padx=10,
- pady=5,
- command=lambda t=task: self.on_task_click(t)
- )
- btn.pack(fill=tk.X, pady=2)
- self.buttons[task] = btn
- # Update scroll region
- self.scrollable_frame.update_idletasks()
- self.canvas.configure(scrollregion=self.canvas.bbox("all"))
- def on_task_click(self, task_name):
- """Handle task button click."""
- now = datetime.now()
- # Round to minute (remove seconds/microseconds for cleaner timestamps)
- now = now.replace(second=0, microsecond=0)
- if task_name not in self.today_clicks:
- self.today_clicks[task_name] = []
- self.today_clicks[task_name].append(now)
- self.save_diary()
- self.update_buttons()
- def main():
- root = tk.Tk()
- app = RoutineDiary(root)
- root.mainloop()
- if __name__ == "__main__":
- main()
Advertisement
Add Comment
Please, Sign In to add comment