import customtkinter as ctk from database import Database import matplotlib.pyplot as plt from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg import datetime class StatsFrame(ctk.CTkFrame): def __init__(self, master, db: Database): super().__init__(master) self.db = db self.setup_ui() def setup_ui(self): self.grid_columnconfigure(0, weight=1) self.header = ctk.CTkLabel(self, text="Progress & Motivation", font=ctk.CTkFont(size=20, weight="bold")) self.header.grid(row=0, column=0, pady=10, sticky="w") # Stats Summary (Streaks, etc.) self.summary_frame = ctk.CTkFrame(self) self.summary_frame.grid(row=1, column=0, sticky="ew", pady=10) logs = self.db.get_log_history(30) streak = self.calculate_streak(logs) self.streak_label = ctk.CTkLabel(self.summary_frame, text=f"🔥 Current Streak: {streak} Days", font=ctk.CTkFont(size=16)) self.streak_label.pack(side="left", padx=20, pady=10) # Chart Section self.chart_frame = ctk.CTkFrame(self) self.chart_frame.grid(row=2, column=0, sticky="nsew", pady=10) self.chart_frame.grid_columnconfigure(0, weight=1) self.plot_weight_waist(logs) def calculate_streak(self, logs): if not logs: return 0 streak = 0 today = datetime.date.today() # Simple streak calculation based on existing logs # Checks if logs are consecutive log_dates = [datetime.datetime.strptime(l['date'], "%Y-%m-%d").date() for l in logs] log_dates.sort(reverse=True) current = today if log_dates and log_dates[0] < today - datetime.timedelta(days=1): return 0 # Missed yesterday and today for d in log_dates: if d == current or d == current - datetime.timedelta(days=1): streak += 1 current = d else: break return streak def plot_weight_waist(self, logs): if not logs or len(logs) < 2: ctk.CTkLabel(self.chart_frame, text="Log data for at least 2 days to see charts.").pack(pady=50) return # Prepare data logs.reverse() # Chronological dates = [l['date'][5:] for l in logs if l['weight'] or l['waist']] # MM-DD weights = [l['weight'] for l in logs if l['weight'] or l['waist']] waists = [l['waist'] for l in logs if l['weight'] or l['waist']] if not weights: return # Create plot fig, ax1 = plt.subplots(figsize=(6, 4), dpi=100) fig.patch.set_facecolor('#2b2b2b') # Matches dark mode ax1.set_facecolor('#2b2b2b') color = 'tab:blue' ax1.set_xlabel('Date') ax1.set_ylabel('Weight (kg)', color=color) ax1.plot(dates, weights, color=color, marker='o', label='Weight') ax1.tick_params(axis='y', labelcolor=color) ax1.tick_params(axis='x', rotation=45, colors='white') ax1.spines['bottom'].set_color('white') ax1.spines['top'].set_color('none') ax1.spines['left'].set_color('white') ax1.spines['right'].set_color('none') # Second axis for Waist ax2 = ax1.twinx() color = 'tab:red' ax2.set_ylabel('Waist (cm)', color=color) ax2.plot(dates, waists, color=color, marker='x', linestyle='--', label='Waist') ax2.tick_params(axis='y', labelcolor=color) ax2.spines['right'].set_color('white') fig.tight_layout() canvas = FigureCanvasTkAgg(fig, master=self.chart_frame) canvas.draw() canvas.get_tk_widget().pack(fill="both", expand=True)