Guest User

Untitled

a guest
Jan 23rd, 2026
101
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.28 KB | None | 0 0
  1. #!/usr/bin/env python3
  2. """
  3. Daily Routine Tracker - A Tkinter GUI application for tracking daily repetitive tasks.
  4. """
  5.  
  6. import tkinter as tk
  7. from tkinter import messagebox
  8. from datetime import datetime
  9. from pathlib import Path
  10. import yaml
  11. import os
  12.  
  13.  
  14. class RoutineDiary:
  15. def __init__(self, root):
  16. self.root = root
  17. self.root.title("Daily Routine Tracker")
  18. self.root.geometry("400x600")
  19.  
  20. self.tasks_file = Path("tasks.txt")
  21. self.diary_file = Path("diary.yaml")
  22.  
  23. self.tasks = []
  24. self.today_clicks = {} # {task_name: [datetime, datetime, ...]}
  25. self.buttons = {} # {task_name: button_widget}
  26.  
  27. self.load_tasks()
  28. self.load_today_clicks()
  29. self.create_gui()
  30.  
  31. def load_tasks(self):
  32. """Load tasks from tasks.txt file."""
  33. if not self.tasks_file.exists():
  34. messagebox.showerror("Error", "tasks.txt file not found!")
  35. self.root.destroy()
  36. return
  37.  
  38. with open(self.tasks_file, "r", encoding="utf-8") as f:
  39. self.tasks = [line.strip() for line in f if line.strip()]
  40.  
  41. self.tasks = sorted(self.tasks, key=str.lower)
  42.  
  43. def load_diary(self):
  44. """Load the entire diary from diary.yaml."""
  45. if not self.diary_file.exists():
  46. return []
  47.  
  48. with open(self.diary_file, "r", encoding="utf-8") as f:
  49. content = f.read()
  50. if not content.strip():
  51. return []
  52. try:
  53. data = yaml.safe_load(content)
  54. return data if data else []
  55. except yaml.YAMLError:
  56. return []
  57.  
  58. def load_today_clicks(self):
  59. """Load today's clicks from diary.yaml."""
  60. today_str = datetime.now().strftime("%Y-%m-%d")
  61. self.today_clicks = {}
  62.  
  63. diary = self.load_diary()
  64. if not diary:
  65. return
  66.  
  67. # Find today's section in the diary
  68. i = 0
  69. while i < len(diary):
  70. if diary[i] == today_str:
  71. # Found today's date, load all tasks until next date or end
  72. i += 1
  73. while i < len(diary):
  74. item = diary[i]
  75. if isinstance(item, dict):
  76. for task_name, timestamps in item.items():
  77. if isinstance(timestamps, list):
  78. self.today_clicks[task_name] = [
  79. datetime.strptime(ts, "%Y-%m-%d %H:%M")
  80. for ts in timestamps
  81. ]
  82. i += 1
  83. elif isinstance(item, str) and len(item) == 10 and item[4] == '-':
  84. # Next date found
  85. break
  86. else:
  87. i += 1
  88. break
  89. i += 1
  90.  
  91. def save_diary(self):
  92. """Save click to diary.yaml."""
  93. today_str = datetime.now().strftime("%Y-%m-%d")
  94. diary = self.load_diary()
  95.  
  96. # Find and remove today's section if it exists
  97. new_diary = []
  98. i = 0
  99. while i < len(diary):
  100. if diary[i] == today_str:
  101. # Skip today's date and all its tasks
  102. i += 1
  103. while i < len(diary):
  104. item = diary[i]
  105. if isinstance(item, str) and len(item) == 10 and item[4] == '-':
  106. # Next date found
  107. break
  108. i += 1
  109. else:
  110. new_diary.append(diary[i])
  111. i += 1
  112.  
  113. # Add today's section with updated data
  114. if self.today_clicks:
  115. new_diary.append(today_str)
  116. for task_name in sorted(self.today_clicks.keys(), key=str.lower):
  117. timestamps = [dt.strftime("%Y-%m-%d %H:%M") for dt in self.today_clicks[task_name]]
  118. new_diary.append({task_name: timestamps})
  119.  
  120. # Write to file
  121. with open(self.diary_file, "w", encoding="utf-8") as f:
  122. yaml.dump(new_diary, f, default_flow_style=None, allow_unicode=True, sort_keys=False)
  123.  
  124. def create_gui(self):
  125. """Create the main GUI."""
  126. # Title label
  127. title_label = tk.Label(
  128. self.root,
  129. text="Daily Routines",
  130. font=("Arial", 16, "bold"),
  131. pady=10
  132. )
  133. title_label.pack()
  134.  
  135. # Date label
  136. today_str = datetime.now().strftime("%Y-%m-%d")
  137. date_label = tk.Label(
  138. self.root,
  139. text=f"Today: {today_str}",
  140. font=("Arial", 12),
  141. pady=5
  142. )
  143. date_label.pack()
  144.  
  145. # Scrollable frame for buttons
  146. container = tk.Frame(self.root)
  147. container.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
  148.  
  149. canvas = tk.Canvas(container)
  150. scrollbar = tk.Scrollbar(container, orient="vertical", command=canvas.yview)
  151. self.scrollable_frame = tk.Frame(canvas)
  152.  
  153. self.scrollable_frame.bind(
  154. "<Configure>",
  155. lambda e: canvas.configure(scrollregion=canvas.bbox("all"))
  156. )
  157.  
  158. canvas.create_window((0, 0), window=self.scrollable_frame, anchor="nw")
  159. canvas.configure(yscrollcommand=scrollbar.set)
  160.  
  161. # Bind mouse wheel scrolling
  162. def on_mousewheel(event):
  163. canvas.yview_scroll(int(-1 * (event.delta / 120)), "units")
  164.  
  165. def on_mousewheel_linux(event):
  166. if event.num == 4:
  167. canvas.yview_scroll(-1, "units")
  168. elif event.num == 5:
  169. canvas.yview_scroll(1, "units")
  170.  
  171. canvas.bind_all("<MouseWheel>", on_mousewheel)
  172. canvas.bind_all("<Button-4>", on_mousewheel_linux)
  173. canvas.bind_all("<Button-5>", on_mousewheel_linux)
  174.  
  175. scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
  176. canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
  177.  
  178. self.canvas = canvas
  179. self.update_buttons()
  180.  
  181. def get_sorted_tasks(self):
  182. """Get tasks sorted according to the rules."""
  183. not_clicked = []
  184. clicked = []
  185.  
  186. for task in self.tasks:
  187. if task in self.today_clicks and len(self.today_clicks[task]) > 0:
  188. clicked.append(task)
  189. else:
  190. not_clicked.append(task)
  191.  
  192. not_clicked.sort(key=str.lower)
  193. clicked.sort(key=str.lower)
  194.  
  195. return not_clicked + clicked
  196.  
  197. def update_buttons(self):
  198. """Update the button display."""
  199. # Clear existing buttons
  200. for widget in self.scrollable_frame.winfo_children():
  201. widget.destroy()
  202.  
  203. self.buttons = {}
  204. sorted_tasks = self.get_sorted_tasks()
  205.  
  206. for task in sorted_tasks:
  207. click_count = len(self.today_clicks.get(task, []))
  208.  
  209. if click_count > 0:
  210. button_text = f"{task} ({click_count})"
  211. bg_color = "#90EE90" # Light green for clicked
  212. else:
  213. button_text = task
  214. bg_color = "#F0F0F0" # Default gray
  215.  
  216. btn = tk.Button(
  217. self.scrollable_frame,
  218. text=button_text,
  219. font=("Arial", 11),
  220. bg=bg_color,
  221. activebackground="#ADD8E6",
  222. anchor="w",
  223. padx=10,
  224. pady=5,
  225. command=lambda t=task: self.on_task_click(t)
  226. )
  227. btn.pack(fill=tk.X, pady=2)
  228. self.buttons[task] = btn
  229.  
  230. # Update scroll region
  231. self.scrollable_frame.update_idletasks()
  232. self.canvas.configure(scrollregion=self.canvas.bbox("all"))
  233.  
  234. def on_task_click(self, task_name):
  235. """Handle task button click."""
  236. now = datetime.now()
  237. # Round to minute (remove seconds/microseconds for cleaner timestamps)
  238. now = now.replace(second=0, microsecond=0)
  239.  
  240. if task_name not in self.today_clicks:
  241. self.today_clicks[task_name] = []
  242.  
  243. self.today_clicks[task_name].append(now)
  244.  
  245. self.save_diary()
  246. self.update_buttons()
  247.  
  248.  
  249. def main():
  250. root = tk.Tk()
  251. app = RoutineDiary(root)
  252. root.mainloop()
  253.  
  254.  
  255. if __name__ == "__main__":
  256. main()
Advertisement
Add Comment
Please, Sign In to add comment