Untitled

Gym progress with functioning table and edit. Needs colors
mail@pastecode.io avatar
unknown
plain_text
13 days ago
56 kB
1
Indexable
Never
import sqlite3
import sys

import matplotlib.dates as mdates
import numpy as np
from PyQt5.QtCore import Qt, pyqtSignal, QTimer
from PyQt5.QtGui import QColor
from PyQt5.QtWidgets import QApplication, QWidget, QDialog, QVBoxLayout, QHBoxLayout, QPushButton, QFormLayout, \
    QLineEdit, QTableWidget, QTableWidgetItem, QTabWidget, QMenu, QAction, QComboBox, QButtonGroup, QLabel, \
    QRadioButton, QSizePolicy
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure


def create_connection():
    try:
        return sqlite3.connect('nutrition.db')
    except sqlite3.Error as e:
        print(e)
        return None


def create_table(conn):
    try:
        cursor = conn.cursor()
        cursor.execute("""CREATE TABLE IF NOT EXISTS foods (
                            name TEXT NOT NULL,
                            calories REAL,
                            lipids REAL,
                            carbohydrates REAL,
                            protein REAL,
                            price REAL
                        );""")
        conn.commit()
    except sqlite3.Error as e:
        print(e)


def insert_food(conn, food):
    try:
        cursor = conn.cursor()
        cursor.execute(
            "INSERT INTO foods(name, calories, lipids, carbohydrates, protein, price) VALUES (?, ?, ?, ?, ?, ?)", food)
        conn.commit()
    except sqlite3.Error as e:
        print(e)


def get_foods(conn):
    try:
        cursor = conn.cursor()
        cursor.execute("SELECT * FROM foods ORDER BY name ASC")
        return cursor.fetchall()
    except sqlite3.Error as e:
        print(e)
        return []


def delete_food(conn, food_name):
    try:
        cursor = conn.cursor()
        cursor.execute("DELETE FROM foods WHERE name = ?", (food_name,))
        conn.commit()
    except sqlite3.Error as e:
        print(e)


def update_food(conn, old_name, new_food):
    try:
        cursor = conn.cursor()
        cursor.execute("""UPDATE foods
                          SET name = ?, calories = ?, lipids = ?, carbohydrates = ?, protein = ?, price = ?
                          WHERE name = ?""",
                       (*new_food, old_name))
        conn.commit()
    except sqlite3.Error as e:
        print(e)


def create_progress_table(conn):
    try:
        cursor = conn.cursor()
        cursor.execute("""
            CREATE TABLE IF NOT EXISTS progress (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                date TEXT NOT NULL,
                weight REAL,
                body_fat REAL,
                muscle_mass REAL,
                waist_size REAL,  -- Add waist_size column
                chest_size REAL,
                thigh_size REAL,
                biceps_size REAL,
                notes TEXT
            );
        """)
        conn.commit()
    except sqlite3.Error as e:
        print(e)


def insert_progress(conn, progress):
    try:
        cursor = conn.cursor()
        cursor.execute(
            "INSERT INTO progress(date, weight, body_fat, muscle_mass, waist_size, chest_size, thigh_size, biceps_size,  notes) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",
            progress)
        conn.commit()
    except sqlite3.Error as e:
        print(e)


def get_progress(conn):
    try:
        cursor = conn.cursor()
        cursor.execute("SELECT * FROM progress ORDER BY date ASC")
        return cursor.fetchall()
    except sqlite3.Error as e:
        print(e)
        return []


def delete_progress(conn, progress_id):
    try:
        cursor = conn.cursor()
        cursor.execute("DELETE FROM progress WHERE id = ?", (progress_id,))
        conn.commit()
    except sqlite3.Error as e:
        print(e)


def update_progress(conn, progress_id, progress):
    try:
        cursor = conn.cursor()
        cursor.execute("""
            UPDATE progress 
            SET date = ?, weight = ?, body_fat = ?, muscle_mass = ?, waist_size = ?, chest_size = ?, Thigh_size = ?, Biceps_size = ?, notes = ? 
            WHERE id = ?
        """, (*progress, progress_id))
        conn.commit()
    except sqlite3.Error as e:
        print(e)


def create_gym_progress_table(conn):
    try:
        cursor = conn.cursor()
        cursor.execute("""CREATE TABLE IF NOT EXISTS gym_progress (
                            id INTEGER PRIMARY KEY AUTOINCREMENT,
                            date TEXT NOT NULL,
                            session TEXT NOT NULL,
                            program TEXT,
                            exercise TEXT NOT NULL,
                            sets INTEGER,
                            reps INTEGER,
                            rest REAL,
                            rpe REAL,
                            notes TEXT
                        );""")
        conn.commit()
    except sqlite3.Error as e:
        print(e)


def insert_gym_progress(conn, progress):
    try:
        cursor = conn.cursor()
        cursor.execute("INSERT INTO gym_progress(date, session, program, exercise, sets, reps, rest, rpe, notes) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", progress)
        conn.commit()
    except sqlite3.Error as e:
        print(e)


def get_gym_progress(conn):
    try:
        cursor = conn.cursor()
        cursor.execute("SELECT * FROM gym_progress")  # Order by date or any other desired column
        return cursor.fetchall()
    except sqlite3.Error as e:
        print(e)
        return []


def delete_gym_progress(conn, progress_id):
    try:
        cursor = conn.cursor()
        cursor.execute("DELETE FROM gym_progress WHERE id = ?", (progress_id,))
        conn.commit()
    except sqlite3.Error as e:
        print(e)


def update_gym_progress(conn, progress_id, progress):
    try:
        cursor = conn.cursor()
        cursor.execute("""UPDATE gym_progress 
                          SET date = ?, session = ?, program = ?, exercise = ?, sets = ?, reps = ?, rest = ?, rpe = ?, notes = ? 
                          WHERE id = ?""",
                       (*progress, progress_id))
        conn.commit()
    except sqlite3.Error as e:
        print(e)


class AddFoodDialog(QDialog):
    def __init__(self, parent=None, food=None):
        super(AddFoodDialog, self).__init__(parent)
        self.setWindowTitle('Add Food Item' if food is None else 'Edit Food Item')
        self.layout = QFormLayout(self)
        self.food = food

        self.nameEdit = QLineEdit(self)
        self.caloriesEdit = QLineEdit(self)
        self.lipidsEdit = QLineEdit(self)
        self.carbsEdit = QLineEdit(self)
        self.proteinEdit = QLineEdit(self)
        self.priceEdit = QLineEdit(self)
        self.nameEdit.setStyleSheet("background-color: lightyellow; font-weight: bold;")

        if food:
            self.nameEdit.setText(food[0])
            self.caloriesEdit.setText(str(food[1]))
            self.lipidsEdit.setText(str(food[2]))
            self.carbsEdit.setText(str(food[3]))
            self.proteinEdit.setText(str(food[4]))
            self.priceEdit.setText(str(food[5]))

        self.layout.addRow('Name:', self.nameEdit)
        self.layout.addRow('Calories:', self.caloriesEdit)
        self.layout.addRow('Lipids:', self.lipidsEdit)
        self.layout.addRow('Carbohydrates:', self.carbsEdit)
        self.layout.addRow('Protein:', self.proteinEdit)
        self.layout.addRow('Price:', self.priceEdit)

        self.addButton = QPushButton('Add' if food is None else 'Update', self)
        self.cancelButton = QPushButton('Cancel', self)
        self.addButton.clicked.connect(self.add_food)
        self.cancelButton.clicked.connect(self.reject)
        buttonLayout = QHBoxLayout()
        buttonLayout.addWidget(self.addButton)
        buttonLayout.addWidget(self.cancelButton)
        self.layout.addRow(buttonLayout)

    def add_food(self):
        try:
            name = self.nameEdit.text()
            calories = float(self.caloriesEdit.text())
            lipids = float(self.lipidsEdit.text())
            carbs = float(self.carbsEdit.text())
            protein = float(self.proteinEdit.text())
            price = float(self.priceEdit.text())
            food = (name, calories, lipids, carbs, protein, price)
            if self.food:
                old_name = self.food[0]
                update_food(conn, old_name, food)
            else:
                insert_food(conn, food)
            self.accept()  # Close the dialog on success
        except ValueError:
            # Handle invalid input
            pass


class FoodDatabaseDialog(QDialog):
    foodAdded = pyqtSignal()  # Signal to emit when food is added or updated
    foodDeleted = pyqtSignal()  # New signal for when a food is deleted

    def __init__(self, parent=None):
        super(FoodDatabaseDialog, self).__init__(parent)
        self.setWindowTitle('Food Database')
        self.setGeometry(300, 300, 500, 400)
        self.layout = QVBoxLayout(self)

        addButton = QPushButton('Add Food', self)
        deleteButton = QPushButton('Delete Selected Food', self)
        addButton.setStyleSheet("background-color: navy; color: white;")
        deleteButton.setStyleSheet("background-color: red; color: white;")
        addButton.clicked.connect(self.open_add_dialog)
        deleteButton.clicked.connect(self.delete_food)

        buttonLayout = QHBoxLayout()
        buttonLayout.addWidget(addButton)
        buttonLayout.addWidget(deleteButton)
        self.layout.addLayout(buttonLayout)

        self.table = QTableWidget(self)
        self.table.setColumnCount(6)
        self.table.setHorizontalHeaderLabels(['Name', 'Calories', 'Lipids', 'Carbohydrates', 'Protein', 'Price'])
        self.table.setContextMenuPolicy(Qt.CustomContextMenu)
        self.table.customContextMenuRequested.connect(self.show_context_menu)
        self.update_table()
        self.layout.addWidget(self.table)

    def show_context_menu(self, position):
        menu = QMenu(self)
        edit_action = QAction("Edit", self)
        edit_action.triggered.connect(self.edit_progress)
        menu.addAction(edit_action)
        menu.exec_(self.table.mapToGlobal(position))

    def edit_food(self):
        selected_row = self.table.currentRow()
        if selected_row >= 0:
            name = self.table.item(selected_row, 0).text()
            calories = float(self.table.item(selected_row, 1).text())
            lipids = float(self.table.item(selected_row, 2).text())
            carbs = float(self.table.item(selected_row, 3).text())
            protein = float(self.table.item(selected_row, 4).text())
            price = float(self.table.item(selected_row, 5).text())
            food = (name, calories, lipids, carbs, protein, price)
            dialog = AddFoodDialog(self, food)
            if dialog.exec_():
                self.update_table()
                self.foodAdded.emit()  # Emit the signal after the dialog has successfully added or edited a food

    def open_add_dialog(self):
        dialog = AddFoodDialog(self)
        if dialog.exec_():
            self.update_table()
            self.foodAdded.emit()  # Emit the signal after the dialog has successfully added a food

    def delete_food(self):
        selected_row = self.table.currentRow()
        if selected_row >= 0:
            food_name = self.table.item(selected_row, 0).text()
            delete_food(conn, food_name)
            self.update_table()
            self.foodDeleted.emit()  # Emit the signal after the food is deleted

    def update_table(self):
        foods = get_foods(conn)
        self.table.setRowCount(len(foods))
        for i, (name, calories, lipids, carbs, protein, price) in enumerate(foods):
            nameItem = QTableWidgetItem(name)
            nameItem.setBackground(QColor(173, 216, 230))
            self.table.setItem(i, 0, nameItem)
            self.table.setItem(i, 1, QTableWidgetItem(str(calories)))
            self.table.setItem(i, 2, QTableWidgetItem(str(lipids)))
            self.table.setItem(i, 3, QTableWidgetItem(str(carbs)))
            self.table.setItem(i, 4, QTableWidgetItem(str(protein)))
            self.table.setItem(i, 5, QTableWidgetItem(str(price)))


class MealPlannerDialog(QDialog):
    def __init__(self, parent=None):
        super(MealPlannerDialog, self).__init__(parent)
        self.setWindowTitle('Meal Planner')
        self.setGeometry(300, 300, 600, 500)
        self.layout = QVBoxLayout(self)

        self.conn = create_connection()

        self.genderCombo = QComboBox(self)
        self.genderCombo.addItems(['Male', 'Female'])
        self.weightEdit = QLineEdit(self)
        self.heightEdit = QLineEdit(self)
        self.ageEdit = QLineEdit(self)
        self.bodyFatEdit = QLineEdit(self)
        self.activityCombo = QComboBox(self)
        self.activityCombo.addItems([
            'Sedentary (little or no exercise)',
            'Lightly active (exercise 1-3 times/week)',
            'Active (daily exercise or intense exercise 3-4 times/week)',
            'Very active (intense exercise 6-7 times/week)',
            'Super active (very intense exercise daily, or physical job)'
        ])
        self.primaryGoalCombo = QComboBox(self)
        self.primaryGoalCombo.addItems([
            'Build Muscle (Male - Body Fat % ≤ 8-12, Female - Body Fat % ≤ 18-22)',
            'Lose Fat & Build Muscle Equally (Male - Body Fat % ≈ 12-18, Female - Body Fat % ≈ 22-28)',
            'Lose Fat (Male - Body Fat % ≥ 18-20+, Female - Body Fat % ≥ 28-30+)'
        ])
        self.trainingExperienceGroup = QButtonGroup(self)
        self.beginnerRadio = QRadioButton("Beginner (0-2 years of lifting)")
        self.intermediateRadio = QRadioButton("Intermediate (2-5 years of lifting)")
        self.advancedRadio = QRadioButton("Advanced (5+ years of lifting)")
        self.trainingExperienceGroup.addButton(self.beginnerRadio)
        self.trainingExperienceGroup.addButton(self.intermediateRadio)
        self.trainingExperienceGroup.addButton(self.advancedRadio)

        calculatorLayout = QFormLayout()
        calculatorLayout.addRow('Gender:', self.genderCombo)
        calculatorLayout.addRow('Weight (kg):', self.weightEdit)
        calculatorLayout.addRow('Height (cm):', self.heightEdit)
        calculatorLayout.addRow('Age (years):', self.ageEdit)
        calculatorLayout.addRow('Body Fat %:', self.bodyFatEdit)
        calculatorLayout.addRow('Activity Level:', self.activityCombo)
        calculatorLayout.addRow('Primary Goal:', self.primaryGoalCombo)
        calculatorLayout.addRow("Training Experience:", self.beginnerRadio)
        calculatorLayout.addRow("", self.intermediateRadio)
        calculatorLayout.addRow("", self.advancedRadio)

        self.layout.addLayout(calculatorLayout)

        self.totalPriceLabel = QLabel('Total Price: €0.00', self)  # Add this line
        self.layout.addWidget(self.totalPriceLabel)  # Add this line
        self.needsDisplay = QLabel('Daily Needs: ', self)
        calculatorLayout.addRow(self.needsDisplay)

        self.mealTypeCombo = QComboBox(self)
        self.mealTypeCombo.addItems(['Breakfast', 'Lunch', 'Snack', 'Dinner'])

        self.foodCombo = QComboBox(self)
        self.foodCombo.setMinimumWidth(200)  # Set the minimum width to 200 pixels or another value that fits your needs
        self.quantityEdit = QLineEdit(self)
        self.addButton = QPushButton('Add Meal', self)
        self.clearAllButton = QPushButton('Clear All', self)
        self.deleteMealButton = QPushButton('Delete Meal', self)
        self.clearAllButton.clicked.connect(self.clear_meals)
        self.clearAllButton.setFixedSize(100, 30)
        self.addButton.clicked.connect(self.add_food_to_meal)
        self.deleteMealButton.clicked.connect(self.delete_selected_meal)

        self.mealTable = QTableWidget(self)
        self.mealTable.setColumnCount(8)  # Adjusted for detailed nutritional info
        self.mealTable.setHorizontalHeaderLabels(
            ['Meal', 'Food', 'Quantity (g)', 'Calories (kcal)', 'Proteins (g)', 'Carbs (g)', 'Fats (g)', 'Price (€)'])

        # Layout for Meal Creation
        mealCreationLayout = QHBoxLayout()
        mealCreationLayout.addWidget(self.mealTypeCombo)
        mealCreationLayout.addWidget(self.foodCombo, 1)  # Stretch factor for better spacing
        mealCreationLayout.addWidget(self.quantityEdit)
        mealCreationLayout.addWidget(self.addButton)
        mealCreationLayout.addWidget(self.deleteMealButton)  # Add the delete button to the layout
        mealCreationLayout.addWidget(self.clearAllButton)

        self.layout.addLayout(mealCreationLayout)
        self.layout.addWidget(self.mealTable)

        # Ensure this is called to fetch database information
        self.populate_food_combo()

        self.total_calories = 0.0
        self.total_proteins = 0.0
        self.total_carbs = 0.0
        self.total_fats = 0.0
        self.daily_caloric_needs = 0.0

        self.layout.addLayout(mealCreationLayout)
        self.layout.addWidget(self.mealTable)

        # Connect signals to slots
        self.connect_signals()

    def connect_signals(self):
        # Connect signals from input widgets to the calculate_needs method
        self.genderCombo.currentIndexChanged.connect(self.calculate_needs)
        self.weightEdit.textChanged.connect(self.calculate_needs)
        self.heightEdit.textChanged.connect(self.calculate_needs)
        self.ageEdit.textChanged.connect(self.calculate_needs)
        self.bodyFatEdit.textChanged.connect(self.calculate_needs)
        self.activityCombo.currentIndexChanged.connect(self.calculate_needs)
        self.primaryGoalCombo.currentIndexChanged.connect(self.calculate_needs)
        self.trainingExperienceGroup.buttonClicked.connect(self.calculate_needs)

    def populate_food_combo(self):
        foods = get_foods(self.conn)
        self.foodCombo.clear()  # Clear existing items before adding new ones
        for food in foods:
            self.foodCombo.addItem(food[0])

    def add_food_to_meal(self):
        try:
            meal_type = self.mealTypeCombo.currentText()
            food_name = self.foodCombo.currentText()

            # Check if quantity input is empty
            if self.quantityEdit.text().strip() == '':
                raise ValueError("Quantity cannot be empty")

            quantity = float(self.quantityEdit.text())
            food_nutrition = self.get_nutritional_values(food_name, quantity)

            # Calculate total price
            total_price = food_nutrition['price'] * quantity

            # Update total nutritional values and total price
            self.total_calories += food_nutrition['calories']
            self.total_proteins += food_nutrition['proteins']
            self.total_carbs += food_nutrition['carbs']
            self.total_fats += food_nutrition['fats']
            self.update_intake_ratio_display()

            # Add meal data to the table
            row_position = self.mealTable.rowCount()
            self.mealTable.insertRow(row_position)
            self.mealTable.setItem(row_position, 0, QTableWidgetItem(meal_type))
            self.mealTable.setItem(row_position, 1, QTableWidgetItem(food_name))
            self.mealTable.setItem(row_position, 2, QTableWidgetItem(str(quantity)))
            self.mealTable.setItem(row_position, 3, QTableWidgetItem(str(food_nutrition['calories'])))
            self.mealTable.setItem(row_position, 4, QTableWidgetItem(str(food_nutrition['proteins'])))
            self.mealTable.setItem(row_position, 5, QTableWidgetItem(str(food_nutrition['carbs'])))
            self.mealTable.setItem(row_position, 6, QTableWidgetItem(str(food_nutrition['fats'])))
            self.mealTable.setItem(row_position, 7, QTableWidgetItem(str(total_price)))  # Display total price

            # Recalculate nutritional needs
            self.calculate_needs()

            # Update total price label
            self.update_total_price()

        except ValueError as ve:
            print(f"Error adding food to meal: {ve}")

    def update_total_price(self):
        total_price = sum(float(self.mealTable.item(row, 7).text()) for row in range(self.mealTable.rowCount()))
        self.totalPriceLabel.setText(f'Total Price: €{total_price:.2f}')  # Update the label here

    def get_nutritional_values(self, food_name, quantity):
        food_data = next((food for food in get_foods(self.conn) if food[0] == food_name), None)
        if food_data:
            return {
                'calories': food_data[1] * quantity,
                'proteins': food_data[4] * quantity,
                'carbs': food_data[3] * quantity,
                'fats': food_data[2] * quantity,
                'price': food_data[5]  # Fetch price from database
            }
        else:
            return {'calories': 0, 'proteins': 0, 'carbs': 0, 'fats': 0, 'price': 0}

    def update_intake_ratio_display(self):
        if self.daily_caloric_needs > 0:
            # Assuming self.daily_protein_needs, self.daily_carbs_needs, and self.daily_fats_needs are also calculated and stored
            caloric_ratio = self.total_calories / self.daily_caloric_needs
            protein_ratio = self.total_proteins / self.daily_protein_needs if self.daily_protein_needs > 0 else 0
            carbs_ratio = self.total_carbs / self.daily_carbs_needs if self.daily_carbs_needs > 0 else 0
            fats_ratio = self.total_fats / self.daily_fats_needs if self.daily_fats_needs > 0 else 0

            self.needsDisplay.setText(f"Daily Nutritional Needs:\n"
                                      f"Calories: {self.total_calories:.2f} kcal / {self.daily_caloric_needs:.2f} kcal\n"
                                      f"Protein: {self.total_proteins:.2f} g / {self.daily_protein_needs:.2f} g\n"
                                      f"Carbs: {self.total_carbs:.2f} g / {self.daily_carbs_needs:.2f} g\n"
                                      f"Fats: {self.total_fats:.2f} g / {self.daily_fats_needs:.2f} g")
        else:
            self.needsDisplay.setText("Daily Nutritional Needs: N/A")

    def calculate_needs(self):
        try:
            gender = self.genderCombo.currentText()
            weight = float(self.weightEdit.text())  # Weight in kilograms
            height = float(self.heightEdit.text())  # Height in centimeters
            age = int(self.ageEdit.text())
            activity_level = self.activityCombo.currentText()
            primary_goal = self.primaryGoalCombo.currentText()
            training_experience = self.get_selected_training_experience()

            # Calculate BMR using Mifflin-St Jeor formula
            bmr = 10 * weight + 6.25 * height - 5 * age + (5 if gender == 'Male' else -161)

            # Adjust for activity level
            activity_factors = {
                'Sedentary (little or no exercise)': 1.2,
                'Lightly active (exercise 1-3 times/week)': 1.375,
                'Active (daily exercise or intense exercise 3-4 times/week)': 1.55,
                'Very active (intense exercise 6-7 times/week)': 1.725,
                'Super active (very intense exercise daily, or physical job)': 1.9
            }
            maintenance_calories = bmr * activity_factors[activity_level]

            # Adjust caloric needs based on primary goal and training experience
            if 'Lose Fat & Build Muscle Equally' in primary_goal:
                self.daily_caloric_needs = maintenance_calories
            elif 'Build Muscle' in primary_goal:
                if training_experience == 'Beginner (0-2 years of lifting)':
                    self.daily_caloric_needs = maintenance_calories * 1.25
                elif training_experience == 'Intermediate (2-5 years of lifting)':
                    self.daily_caloric_needs = maintenance_calories * 1.175
                else:  # Advanced (5+ years of lifting)
                    self.daily_caloric_needs = maintenance_calories * 1.15
            else:  # 'Lose Fat'
                self.daily_caloric_needs = maintenance_calories * 0.85  # Adjust as needed

            # Example calculations for protein, carbs, and fat needs
            self.daily_protein_needs = weight * 1.6  # Example: 1.6g per kg of body weight
            self.daily_carbs_needs = (self.daily_caloric_needs * 0.5) / 4  # Example: 50% of calories from carbs
            self.daily_fats_needs = (self.daily_caloric_needs * 0.25) / 9  # Example: 25% of calories from fats

            self.needsDisplay.setText(f"Daily Nutritional Needs:\n"
                                      f"Calories: {self.daily_caloric_needs:.2f} kcal\n"
                                      f"Protein: {self.daily_protein_needs:.2f} g\n"
                                      f"Carbs: {self.daily_carbs_needs:.2f} g\n"
                                      f"Fats: {self.daily_fats_needs:.2f} g")
            self.update_intake_ratio_display()
        except ValueError:
            self.needsDisplay.setText("Invalid input. Please enter correct values.")

    def get_selected_training_experience(self):
        selected_button = self.trainingExperienceGroup.checkedButton()
        if selected_button:
            return selected_button.text()
        return "Unknown"

    def delete_selected_meal(self):
        selected_row = self.mealTable.currentRow()
        if selected_row != -1:  # -1 means no row is selected
            # Update total price by subtracting the price of the deleted meal
            deleted_price = float(self.mealTable.item(selected_row, 7).text())
            self.total_calories -= float(self.mealTable.item(selected_row, 3).text())
            self.total_proteins -= float(self.mealTable.item(selected_row, 4).text())
            self.total_carbs -= float(self.mealTable.item(selected_row, 5).text())
            self.total_fats -= float(self.mealTable.item(selected_row, 6).text())
            self.mealTable.removeRow(selected_row)
            self.update_total_price()  # Update the total price after deletion
            # Recalculate nutritional needs
            self.calculate_needs()

    def clear_meals(self):
        # Clear the meal table
        self.mealTable.setRowCount(0)

        # Reset total nutritional values
        self.total_calories = 0.0
        self.total_proteins = 0.0
        self.total_carbs = 0.0
        self.total_fats = 0.0

        # Update the display
        self.update_intake_ratio_display()

        # Update the total price label
        self.update_total_price()

    def update_food_combo(self):
        self.foodCombo.clear()  # Clear the existing items
        self.populate_food_combo()  # Repopulate the combo box

    def update_total_nutrition(self):
        # Reset total nutritional values
        self.total_calories = 0.0
        self.total_proteins = 0.0
        self.total_carbs = 0.0
        self.total_fats = 0.0

        # Recalculate totals based on remaining items in the table
        for row in range(self.mealTable.rowCount()):
            # Assuming calories, proteins, carbs, and fats are in columns 3, 4, 5, and 6
            self.total_calories += float(self.mealTable.item(row, 3).text())
            self.total_proteins += float(self.mealTable.item(row, 4).text())
            self.total_carbs += float(self.mealTable.item(row, 5).text())
            self.total_fats += float(self.mealTable.item(row, 6).text())

        # Update display of totals
        self.update_intake_ratio_display()


class AddProgressDialog(QDialog):
    def __init__(self, parent=None, progress=None):
        super(AddProgressDialog, self).__init__(parent)
        self.setWindowTitle('Add Measurement Entry' if progress is None else 'Edit Measurement Entry')
        self.layout = QFormLayout(self)
        self.progress = progress

        self.dateEdit = QLineEdit(self)
        self.weightEdit = QLineEdit(self)
        self.bodyFatEdit = QLineEdit(self)
        self.muscleMassEdit = QLineEdit(self)
        self.waistSizeEdit = QLineEdit(self)
        self.chestSizeEdit = QLineEdit(self)
        self.thighSizeEdit = QLineEdit(self)
        self.bicepsSizeEdit = QLineEdit(self)
        self.notesEdit = QLineEdit(self)  # Define notesEdit

        if progress:
            self.dateEdit.setText(progress[1])
            self.weightEdit.setText(str(progress[2]))
            self.bodyFatEdit.setText(str(progress[3]))
            self.muscleMassEdit.setText(str(progress[4]))
            self.waistSizeEdit.setText(str(progress[5]))
            self.chestSizeEdit.setText(str(progress[6]))
            self.thighSizeEdit.setText(str(progress[7]))
            self.bicepsSizeEdit.setText(str(progress[8]))
            self.notesEdit.setText(progress[9])  # Set text for notesEdit

        self.layout.addRow('Date:', self.dateEdit)
        self.layout.addRow('Weight (kg):', self.weightEdit)
        self.layout.addRow('Body Fat (%):', self.bodyFatEdit)
        self.layout.addRow('Muscle Mass (%):', self.muscleMassEdit)
        self.layout.addRow('Waist Size (cm) :', self.waistSizeEdit)
        self.layout.addRow('Chest Size (cm) :', self.chestSizeEdit)
        self.layout.addRow('Thigh Size (cm) :', self.thighSizeEdit)
        self.layout.addRow('Biceps Size (cm) :', self.bicepsSizeEdit)
        self.layout.addRow('Notes:', self.notesEdit)  # Add notesEdit to layout

        self.addButton = QPushButton('Add' if progress is None else 'Update', self)
        self.cancelButton = QPushButton('Cancel', self)
        self.addButton.clicked.connect(self.add_progress)
        self.cancelButton.clicked.connect(self.reject)
        buttonLayout = QHBoxLayout()
        buttonLayout.addWidget(self.addButton)
        buttonLayout.addWidget(self.cancelButton)
        self.layout.addRow(buttonLayout)

    def add_progress(self):
        try:
            date = self.dateEdit.text()
            weight = float(self.weightEdit.text())
            body_fat = float(self.bodyFatEdit.text())
            muscle_mass = float(self.muscleMassEdit.text())
            waist_size = float(self.waistSizeEdit.text())
            chest_size = float(self.chestSizeEdit.text())
            thigh_size = float(self.thighSizeEdit.text())
            biceps_size = float(self.bicepsSizeEdit.text())
            notes = self.notesEdit.text()
            progress = (date, weight, body_fat, muscle_mass, waist_size, chest_size, thigh_size, biceps_size, notes)
            if self.progress:
                update_progress(conn, self.progress[0], progress)
            else:
                insert_progress(conn, progress)
            self.accept()
        except ValueError:
            pass


class ProgressDialog(QDialog):
    def __init__(self, parent=None):
        super(ProgressDialog, self).__init__(parent)
        self.setWindowTitle('Body Metrics Tracker')
        self.setGeometry(300, 300, 600, 400)
        self.layout = QVBoxLayout(self)

        addButton = QPushButton('Add Measurement Entry', self)
        deleteButton = QPushButton('Delete Selected Entry', self)
        bodyCompChartsButton = QPushButton('Body Composition Charts', self)
        bodyMeasurementsChartsButton = QPushButton('Body Measurements Charts', self)

        addButton.clicked.connect(self.open_add_dialog)
        deleteButton.clicked.connect(self.delete_progress)
        bodyCompChartsButton.clicked.connect(self.show_body_composition_charts)
        bodyMeasurementsChartsButton.clicked.connect(self.show_body_measurements_charts)

        buttonLayout = QHBoxLayout()
        buttonLayout.addWidget(addButton)
        buttonLayout.addWidget(deleteButton)
        self.layout.addLayout(buttonLayout)

        chartsButtonLayout = QHBoxLayout()
        chartsButtonLayout.addWidget(bodyCompChartsButton)
        chartsButtonLayout.addWidget(bodyMeasurementsChartsButton)
        self.layout.addLayout(chartsButtonLayout)

        self.table = QTableWidget(self)
        self.table.setColumnCount(10)  # Adjust column count to match the number of columns
        self.table.setHorizontalHeaderLabels(
            ['ID', 'Date', 'Weight', 'Body Fat', 'Muscle Mass', 'Waist Size', 'Chest Size', 'Thigh Size', 'Biceps Size',
             'Notes'])
        self.table.setContextMenuPolicy(Qt.CustomContextMenu)
        self.table.customContextMenuRequested.connect(self.show_context_menu)
        self.update_table()
        self.layout.addWidget(self.table)

    def show_context_menu(self, position):
        menu = QMenu(self)
        edit_action = QAction("Edit", self)
        edit_action.triggered.connect(self.edit_progress)
        menu.addAction(edit_action)
        menu.exec_(self.table.mapToGlobal(position))

    def edit_progress(self):
        selected_row = self.table.currentRow()
        if (selected_row >= 0):
            progress_id = int(self.table.item(selected_row, 0).text())
            date = self.table.item(selected_row, 1).text()
            weight = float(self.table.item(selected_row, 2).text())
            body_fat = float(self.table.item(selected_row, 3).text())
            muscle_mass = float(self.table.item(selected_row, 4).text())
            waist_size = float(self.table.item(selected_row, 5).text())
            chest_size = float(self.table.item(selected_row, 6).text())
            thigh_size = float(self.table.item(selected_row, 7).text())
            biceps_size = float(self.table.item(selected_row, 8).text())
            notes = self.table.item(selected_row, 9).text()
            progress = (
            progress_id, date, weight, body_fat, muscle_mass, waist_size, chest_size, thigh_size, biceps_size, notes)
            dialog = AddProgressDialog(self, progress)
            if dialog.exec_():
                self.update_table()

    def open_add_dialog(self):
        dialog = AddProgressDialog(self)
        if dialog.exec_():
            self.update_table()

    def delete_progress(self):
        selected_row = self.table.currentRow()
        if (selected_row >= 0):
            progress_id = int(self.table.item(selected_row, 0).text())
            delete_progress(conn, progress_id)
            self.update_table()

    def update_table(self):
        progress_data = get_progress(conn)
        self.table.setRowCount(len(progress_data))
        for i, (progress_id, date, weight, body_fat, muscle_mass, waist_size, chest_size, thigh_size, biceps_size,
                notes) in enumerate(progress_data):
            self.table.setItem(i, 0, QTableWidgetItem(str(progress_id)))
            self.table.setItem(i, 1, QTableWidgetItem(date))
            self.table.setItem(i, 2, QTableWidgetItem(str(weight)))
            self.table.setItem(i, 3, QTableWidgetItem(str(body_fat)))
            self.table.setItem(i, 4, QTableWidgetItem(str(muscle_mass)))
            self.table.setItem(i, 5, QTableWidgetItem(str(waist_size)))
            self.table.setItem(i, 6, QTableWidgetItem(str(chest_size)))
            self.table.setItem(i, 7, QTableWidgetItem(str(thigh_size)))
            self.table.setItem(i, 8, QTableWidgetItem(str(biceps_size)))
            self.table.setItem(i, 9, QTableWidgetItem(notes))
        self.table.hideColumn(0)

    def show_body_composition_charts(self):
        data = self.get_table_data()
        dialog = BodyCompositionChartsDialog(data)
        dialog.exec_()

    def show_body_measurements_charts(self):
        data = self.get_table_data()
        dialog = BodyMeasurementsChartsDialog(data)
        dialog.exec_()

    def get_table_data(self):
        rows = self.table.rowCount()
        data = []
        for row in range(rows):
            date = self.table.item(row, 1).text()
            weight = float(self.table.item(row, 2).text())
            body_fat = float(self.table.item(row, 3).text())
            muscle_mass = float(self.table.item(row, 4).text())
            waist_size = float(self.table.item(row, 5).text())
            chest_size = float(self.table.item(row, 6).text())
            thigh_size = float(self.table.item(row, 7).text())
            biceps_size = float(self.table.item(row, 8).text())
            data.append((date, weight, body_fat, muscle_mass, waist_size, chest_size, thigh_size, biceps_size))
        return data


class BodyCompositionChartsDialog(QDialog):
    def __init__(self, data, parent=None):
        super(BodyCompositionChartsDialog, self).__init__(parent)
        self.setWindowTitle('Body Composition Charts')
        self.layout = QVBoxLayout(self)

        self.fig = Figure()
        self.canvas = FigureCanvas(self.fig)
        self.canvas.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.canvas.updateGeometry()
        self.layout.addWidget(self.canvas)

        self.data = data

        self.plot_data()
        self.add_vertical_line()

        # Create a QLabel to display hover information
        self.hover_info_label = QLabel()
        self.layout.addWidget(self.hover_info_label)

        # Timer for throttling hover events
        self.hover_timer = QTimer()
        self.hover_timer.setSingleShot(True)
        self.hover_timer.timeout.connect(self.process_hover_event)

        self.last_event = None

    def plot_data(self):
        self.dates, self.weights, self.body_fats, self.muscle_masses = zip(
            *[(entry[0], entry[1], entry[2], entry[3]) for entry in self.data])
        self.dates = np.array([mdates.datestr2num(date) for date in self.dates])  # Convert dates to numerical format
        self.weights = np.array(self.weights)
        self.body_fats = np.array(self.body_fats)
        self.muscle_masses = np.array(self.muscle_masses)

        self.ax1 = self.fig.add_subplot(211)
        self.ax2 = self.fig.add_subplot(212)

        # Plot body fat and muscle mass
        self.ax1.plot(self.dates, self.body_fats, 'ro-', label='Body Fat (%)')
        self.ax1.plot(self.dates, self.muscle_masses, 'go-', label='Muscle Mass (%)')
        self.ax1.legend(loc='center left', bbox_to_anchor=(1, 0.5))
        self.ax1.set_xticks([self.dates[0], self.dates[-1]])
        self.ax1.set_xticklabels([mdates.num2date(self.dates[0]).strftime('%Y-%m-%d'),
                                  mdates.num2date(self.dates[-1]).strftime('%Y-%m-%d')])
        self.ax1.set_title('Body Fat and Muscle Mass over Time')
        self.ax1.set_xlabel('Date')
        self.ax1.set_ylim(0, 100)  # Ensure y-axis goes from 0 to 100%

        # Plot weight
        self.ax2.plot(self.dates, self.weights, 'bo-', label='Weight (kg)')
        self.ax2.legend(loc='center left', bbox_to_anchor=(1, 0.5))
        self.ax2.set_xticks([self.dates[0], self.dates[-1]])
        self.ax2.set_xticklabels([mdates.num2date(self.dates[0]).strftime('%Y-%m-%d'),
                                  mdates.num2date(self.dates[-1]).strftime('%Y-%m-%d')])
        self.ax2.set_title('Weight over Time')
        self.ax2.set_xlabel('Date')
        max_weight = max(self.weights)
        self.ax2.set_ylim(0, max_weight * 1.2)  # Set y-axis to 20% higher than the maximum weight

        self.fig.tight_layout()
        self.canvas.draw()

    def add_vertical_line(self):
        self.vertical_line = None
        self.vertical_line2 = None
        self.previous_xdata = None
        self.canvas.mpl_connect('motion_notify_event', self.on_mouse_move)

    def on_mouse_move(self, event):
        self.last_event = event
        if not self.hover_timer.isActive():
            self.hover_timer.start(20)  # Adjust the delay as needed

    def process_hover_event(self):
        event = self.last_event
        if event.inaxes:
            xdata = event.xdata
            if self.vertical_line:
                # Only update if the difference is significant
                if self.previous_xdata is None or abs(self.previous_xdata - xdata) > 0.1:
                    self.previous_xdata = xdata
                    self.vertical_line.set_xdata([xdata])
                    self.vertical_line2.set_xdata([xdata])
                    self.canvas.draw_idle()  # Draw only when necessary
            else:
                self.vertical_line = self.ax1.axvline(x=xdata, color='k', linestyle='--')
                self.vertical_line2 = self.ax2.axvline(x=xdata, color='k', linestyle='--')
                self.previous_xdata = xdata
                self.canvas.draw_idle()  # Draw only when necessary

            # Update hover text only when moving to a new data point
            hover_text = self.get_hover_text(xdata)
            self.hover_info_label.setText(hover_text)
        else:
            if self.vertical_line:
                self.vertical_line.remove()
                self.vertical_line2.remove()
                self.vertical_line = None
                self.vertical_line2 = None
                self.previous_xdata = None
                self.canvas.draw_idle()  # Draw only when necessary

    def get_hover_text(self, xdata):
        date_idx = np.argmin(np.abs(self.dates - xdata))
        hover_text = (
            f'Date: {mdates.num2date(self.dates[date_idx]).strftime("%Y-%m-%d")}\n'
            f'Weight: {self.weights[date_idx]:.1f} kg\n'
            f'Body Fat: {self.body_fats[date_idx]:.1f} %\n'
            f'Muscle Mass: {self.muscle_masses[date_idx]:.1f} %'
        )
        return hover_text


class BodyMeasurementsChartsDialog(QDialog):
    def __init__(self, data, parent=None):
        super(BodyMeasurementsChartsDialog, self).__init__(parent)
        self.setWindowTitle('Body Measurements Charts')
        self.layout = QVBoxLayout(self)

        self.fig = Figure()
        self.canvas = FigureCanvas(self.fig)
        self.canvas.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.canvas.updateGeometry()
        self.layout.addWidget(self.canvas)

        self.data = data

        self.plot_data()
        self.add_vertical_line()

        # Create a QLabel to display hover information
        self.hover_info_label = QLabel()
        self.layout.addWidget(self.hover_info_label)

        # Timer for throttling hover events
        self.hover_timer = QTimer()
        self.hover_timer.setSingleShot(True)
        self.hover_timer.timeout.connect(self.process_hover_event)

        self.last_event = None

    def plot_data(self):
        self.dates, self.weights, _, _, self.waist_sizes, self.chest_sizes, self.thigh_sizes, self.biceps_sizes = zip(
            *self.data)
        self.dates = np.array([mdates.datestr2num(date) for date in
                               self.dates])  # Convert dates to numerical format
        self.weights = np.array(self.weights)
        self.waist_sizes = np.array(self.waist_sizes)
        self.chest_sizes = np.array(self.chest_sizes)
        self.thigh_sizes = np.array(self.thigh_sizes)
        self.biceps_sizes = np.array(self.biceps_sizes)

        self.ax1 = self.fig.add_subplot(211)
        self.ax2 = self.fig.add_subplot(212)

        # Plot body measurements
        self.ax1.plot(self.dates, self.waist_sizes, 'ro-', label='Waist Size (cm)')
        self.ax1.plot(self.dates, self.chest_sizes, 'go-', label='Chest Size (cm)')
        self.ax1.plot(self.dates, self.thigh_sizes, 'bo-', label='Thigh Size (cm)')
        self.ax1.plot(self.dates, self.biceps_sizes, 'yo-', label='Biceps Size (cm)')
        self.ax1.legend(loc='center left', bbox_to_anchor=(1, 0.5))
        self.ax1.set_xticks([self.dates[0], self.dates[-1]])
        self.ax1.set_xticklabels([mdates.num2date(self.dates[0]).strftime('%Y-%m-%d'),
                                  mdates.num2date(self.dates[-1]).strftime('%Y-%m-%d')])
        self.ax1.set_title('Body Measurements over Time')
        self.ax1.set_xlabel('Date')

        max_size = max(max(self.waist_sizes), max(self.chest_sizes), max(self.thigh_sizes), max(self.biceps_sizes))
        self.ax1.set_ylim(0, max_size * 1.2)  # Set y-axis to 20% higher than the maximum measurement

        # Plot weight
        self.ax2.plot(self.dates, self.weights, 'bo-', label='Weight (kg)')
        self.ax2.legend(loc='center left', bbox_to_anchor=(1, 0.5))
        self.ax2.set_xticks([self.dates[0], self.dates[-1]])
        self.ax2.set_xticklabels([mdates.num2date(self.dates[0]).strftime('%Y-%m-%d'),
                                  mdates.num2date(self.dates[-1]).strftime('%Y-%m-%d')])
        self.ax2.set_title('Weight over Time')
        self.ax2.set_xlabel('Date')
        max_weight = max(self.weights)
        self.ax2.set_ylim(0, max_weight * 1.2)  # Set y-axis to 20% higher than the maximum weight

        self.fig.tight_layout()
        self.canvas.draw()

    def add_vertical_line(self):
        self.vertical_line1 = None
        self.vertical_line2 = None
        self.previous_xdata = None
        self.canvas.mpl_connect('motion_notify_event', self.on_mouse_move)

    def on_mouse_move(self, event):
        self.last_event = event
        if not self.hover_timer.isActive():
            self.hover_timer.start(20)  # Adjust the delay as needed

    def process_hover_event(self):
        event = self.last_event
        if event.inaxes:
            xdata = event.xdata
            if self.vertical_line1:
                # Only update if the difference is significant
                if self.previous_xdata is None or abs(self.previous_xdata - xdata) > 0.1:
                    self.previous_xdata = xdata
                    self.vertical_line1.set_xdata([xdata])
                    self.vertical_line2.set_xdata([xdata])
                    self.canvas.draw_idle()  # Draw only when necessary
            else:
                self.vertical_line1 = self.ax1.axvline(x=xdata, color='k', linestyle='--')
                self.vertical_line2 = self.ax2.axvline(x=xdata, color='k', linestyle='--')
                self.previous_xdata = xdata
                self.canvas.draw_idle()  # Draw only when necessary

            # Update hover text only when moving to a new data point
            hover_text = self.get_hover_text(xdata)
            self.hover_info_label.setText(hover_text)
        else:
            if self.vertical_line1:
                self.vertical_line1.remove()
                self.vertical_line2.remove()
                self.vertical_line1 = None
                self.vertical_line2 = None
                self.previous_xdata = None
                self.canvas.draw_idle()  # Draw only when necessary

    def get_hover_text(self, xdata):
        date_idx = np.argmin(np.abs(self.dates - xdata))
        hover_text = (
            f'Date: {mdates.num2date(self.dates[date_idx]).strftime("%Y-%m-%d")}\n'
            f'Weight: {self.weights[date_idx]:.1f} kg\n'
            f'Waist Size: {self.waist_sizes[date_idx]:.1f} cm\n'
            f'Chest Size: {self.chest_sizes[date_idx]:.1f} cm\n'
            f'Thigh Size: {self.thigh_sizes[date_idx]:.1f} cm\n'
            f'Biceps Size: {self.biceps_sizes[date_idx]:.1f} cm'
        )
        return hover_text


class GymProgressDialog(QDialog):
    def __init__(self, parent=None):
        super(GymProgressDialog, self).__init__(parent)
        self.setWindowTitle('Gym Progress Tracker')
        self.setGeometry(300, 300, 600, 400)
        self.layout = QVBoxLayout(self)

        addButton = QPushButton('Add Workout Entry', self)
        deleteButton = QPushButton('Delete Selected Entry', self)

        addButton.clicked.connect(self.open_add_dialog)
        deleteButton.clicked.connect(self.delete_progress)

        buttonLayout = QHBoxLayout()
        buttonLayout.addWidget(addButton)
        buttonLayout.addWidget(deleteButton)
        self.layout.addLayout(buttonLayout)

        self.table = QTableWidget(self)
        self.table.setColumnCount(10)  # Include Notes column
        self.table.setHorizontalHeaderLabels(['ID', 'Date', 'Session', 'Program', 'Exercise', 'Sets', 'Reps', 'Rest', 'RPE', 'Notes'])
        self.table.setContextMenuPolicy(Qt.CustomContextMenu)
        self.table.customContextMenuRequested.connect(self.show_context_menu)
        self.update_table()
        self.layout.addWidget(self.table)

    def show_context_menu(self, position):
        menu = QMenu(self)
        edit_action = QAction("Edit", self)
        edit_action.triggered.connect(self.edit_progress)
        menu.addAction(edit_action)
        menu.exec_(self.table.mapToGlobal(position))

    def edit_progress(self):
        selected_row = self.table.currentRow()
        if selected_row >= 0:
            progress_id = int(self.table.item(selected_row, 0).text())
            progress = get_gym_progress(conn)
            for p in progress:
                if p[0] == progress_id:
                    dialog = AddGymProgressDialog(self, progress=p)
                    if dialog.exec_():
                        self.update_table()
                    break

    def open_add_dialog(self):
        dialog = AddGymProgressDialog(self)
        if dialog.exec_():
            self.update_table()

    def delete_progress(self):
        selected_row = self.table.currentRow()
        if selected_row >= 0:
            progress_id = int(self.table.item(selected_row, 0).text())
            delete_gym_progress(conn, progress_id)
            self.update_table()

    def update_table(self):
        progress_data = get_gym_progress(conn)
        self.table.setRowCount(len(progress_data))
        for i, (progress_id, date, session, program, exercise, sets, reps, rest, rpe, notes) in enumerate(progress_data):
            self.table.setItem(i, 0, QTableWidgetItem(str(progress_id)))
            self.table.setItem(i, 1, QTableWidgetItem(date))
            self.table.setItem(i, 2, QTableWidgetItem(session))
            self.table.setItem(i, 3, QTableWidgetItem(program))
            self.table.setItem(i, 4, QTableWidgetItem(exercise))
            self.table.setItem(i, 5, QTableWidgetItem(str(sets)))
            self.table.setItem(i, 6, QTableWidgetItem(str(reps)))
            self.table.setItem(i, 7, QTableWidgetItem(str(rest)))
            self.table.setItem(i, 8, QTableWidgetItem(str(rpe)))
            self.table.setItem(i, 9, QTableWidgetItem(notes))
        self.table.hideColumn(0)


class AddGymProgressDialog(QDialog):
    def __init__(self, parent=None, progress=None):
        super(AddGymProgressDialog, self).__init__(parent)
        self.setWindowTitle('Add Workout Entry' if progress is None else 'Edit Workout Entry')
        self.layout = QFormLayout(self)
        self.progress = progress

        self.dateEdit = QLineEdit(self)
        self.sessionEdit = QLineEdit(self)
        self.programEdit = QLineEdit(self)
        self.exerciseEdit = QLineEdit(self)
        self.setsEdit = QLineEdit(self)
        self.repsEdit = QLineEdit(self)
        self.restEdit = QLineEdit(self)
        self.rpeEdit = QLineEdit(self)
        self.notesEdit = QLineEdit(self)

        if progress:
            self.dateEdit.setText(progress[1])
            self.sessionEdit.setText(progress[2])
            self.programEdit.setText(progress[3])
            self.exerciseEdit.setText(progress[4])
            self.setsEdit.setText(str(progress[5]))
            self.repsEdit.setText(str(progress[6]))
            self.restEdit.setText(str(progress[7]))
            self.rpeEdit.setText(str(progress[8]))
            self.notesEdit.setText(progress[9])

        self.layout.addRow('Date:', self.dateEdit)
        self.layout.addRow('Session:', self.sessionEdit)
        self.layout.addRow('Program:', self.programEdit)
        self.layout.addRow('Exercise:', self.exerciseEdit)
        self.layout.addRow('Sets:', self.setsEdit)
        self.layout.addRow('Reps:', self.repsEdit)
        self.layout.addRow('Rest:', self.restEdit)
        self.layout.addRow('RPE:', self.rpeEdit)
        self.layout.addRow('Notes:', self.notesEdit)

        self.addButton = QPushButton('Add' if progress is None else 'Update', self)
        self.cancelButton = QPushButton('Cancel', self)
        self.addButton.clicked.connect(self.add_progress)
        self.cancelButton.clicked.connect(self.reject)
        buttonLayout = QHBoxLayout()
        buttonLayout.addWidget(self.addButton)
        buttonLayout.addWidget(self.cancelButton)
        self.layout.addRow(buttonLayout)

    def add_progress(self):
        try:
            date = self.dateEdit.text()
            session = self.sessionEdit.text()
            program = self.programEdit.text()
            exercise = self.exerciseEdit.text()
            sets = int(self.setsEdit.text())
            reps = int(self.repsEdit.text())
            rest = float(self.restEdit.text())
            rpe = float(self.rpeEdit.text())
            notes = self.notesEdit.text()
            progress = (date, session, program, exercise, sets, reps, rest, rpe, notes)
            if self.progress:
                update_gym_progress(conn, self.progress[0], progress)
            else:
                insert_gym_progress(conn, progress)
            self.accept()
        except ValueError:
            pass


class App(QWidget):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        self.setGeometry(300, 300, 800, 600)
        self.setWindowTitle('NutriGeniePro')

        # Create the tab widget
        tabWidget = QTabWidget(self)
        foodDatabaseTab = FoodDatabaseDialog()
        mealPlannerTab = MealPlannerDialog()
        progressTab = ProgressDialog()
        gymProgressTab = GymProgressDialog()  # New Gym Progress Tab

        # Connect signals to slots if necessary
        foodDatabaseTab.foodAdded.connect(mealPlannerTab.update_food_combo)
        foodDatabaseTab.foodDeleted.connect(mealPlannerTab.update_food_combo)

        # Add tabs to the tab widget
        tabWidget.addTab(foodDatabaseTab, "Food Database")
        tabWidget.addTab(mealPlannerTab, "Meal Planner")
        tabWidget.addTab(progressTab, "Body Metrics Tracker")
        tabWidget.addTab(gymProgressTab, "Gym Progress")  # Add the new tab here

        # Set the layout
        layout = QVBoxLayout(self)
        layout.addWidget(tabWidget)
        self.setLayout(layout)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    conn = create_connection()
    create_table(conn)
    create_progress_table(conn)
    create_gym_progress_table(conn)  # Ensure the gym_progress table is created
    mainApp = App()
    mainApp.show()
    sys.exit(app.exec_())
Leave a Comment