Untitled
unknown
plain_text
a year ago
38 kB
3
Indexable
import sqlite3 import sys import numpy as np from PyQt5.QtCore import Qt, pyqtSignal 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 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) 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_food) 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 Measurements 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): # Code to display body measurements charts pass 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()) data.append((date, weight, body_fat, muscle_mass)) 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) fig = Figure() self.canvas = FigureCanvas(fig) self.layout.addWidget(self.canvas) self.plot_data(fig, data) def plot_data(self, fig, data): dates, weights, body_fats, muscle_masses = zip(*data) dates = np.array(dates) weights = np.array(weights) body_fats = np.array(body_fats) muscle_masses = np.array(muscle_masses) ax1 = fig.add_subplot(211) ax2 = fig.add_subplot(212) # Plot body fat and muscle mass ax1.plot(dates, body_fats, 'ro-', label='Body Fat (%)') ax1.plot(dates, muscle_masses, 'go-', label='Muscle Mass (%)') ax1.legend(loc='center left', bbox_to_anchor=(1, 0.5)) ax1.set_xticks([dates[0], dates[-1]]) ax1.set_xticklabels([dates[0], dates[-1]]) ax1.set_title('Body Fat and Muscle Mass over Time') ax1.set_xlabel('Date') ax1.set_ylim(0, 100) # Ensure y-axis goes from 0 to 100% # Plot weight ax2.plot(dates, weights, 'bo-', label='Weight (kg)') ax2.legend(loc='center left', bbox_to_anchor=(1, 0.5)) ax2.set_xticks([dates[0], dates[-1]]) ax2.set_xticklabels([dates[0], dates[-1]]) ax2.set_title('Weight over Time') ax2.set_xlabel('Date') max_weight = max(weights) ax2.set_ylim(0, max_weight * 1.2) # Set y-axis to 20% higher than the maximum weight fig.tight_layout() self.canvas.draw() 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() # 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 Measurements Tracker") # 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) mainApp = App() mainApp.show() sys.exit(app.exec_())
Editor is loading...
Leave a Comment