#include <QTabWidget>
#include <array>
+#include "widgets/dailylogwidget.h"
#include "widgets/detailswidget.h"
#include "widgets/mealwidget.h"
#include "widgets/searchwidget.h"
SearchWidget* searchWidget;
DetailsWidget* detailsWidget;
MealWidget* mealWidget;
+ DailyLogWidget* dailyLogWidget;
FoodRepository repository;
QMenu* recentFilesMenu;
--- /dev/null
+#ifndef DAILYLOGWIDGET_H
+#define DAILYLOGWIDGET_H
+
+#include <QDate>
+#include <QTableWidget>
+#include <QVBoxLayout>
+#include <QWidget>
+
+#include "db/foodrepository.h"
+#include "db/mealrepository.h"
+
+class DailyLogWidget : public QWidget {
+ Q_OBJECT
+
+public:
+ explicit DailyLogWidget(QWidget* parent = nullptr);
+
+public slots:
+ void refresh();
+
+private:
+ void setupUi();
+ void updateTable();
+
+ QTableWidget* logTable;
+ MealRepository m_mealRepo;
+ FoodRepository m_foodRepo;
+};
+
+#endif // DAILYLOGWIDGET_H
void addFood(int foodId, const QString& foodName, double grams);
+signals:
+ void logUpdated();
+
private slots:
void clearMeal();
+ void onAddToLog();
private:
void updateTotals();
if (date == QDate::currentDate()) {
timestamp = QDateTime::currentSecsSinceEpoch();
} else {
- timestamp = date.startOfDay().toSecsSinceEpoch() + 43200; // Noon
+ timestamp = QDateTime(date, QTime(0, 0, 0)).toSecsSinceEpoch() + 43200; // Noon
}
QSqlQuery query(db);
ensureMealNamesLoaded();
- qint64 startOfDay = date.startOfDay().toSecsSinceEpoch();
- qint64 endOfDay = date.endOfDay().toSecsSinceEpoch();
+ qint64 startOfDay = QDateTime(date, QTime(0, 0, 0)).toSecsSinceEpoch();
+ qint64 endOfDay = QDateTime(date, QTime(23, 59, 59)).toSecsSinceEpoch();
QSqlQuery query(userDb);
query.prepare(
QSqlDatabase db = DatabaseManager::instance().userDatabase();
if (!db.isOpen()) return;
- qint64 startOfDay = date.startOfDay().toSecsSinceEpoch();
- qint64 endOfDay = date.endOfDay().toSecsSinceEpoch();
+ qint64 startOfDay = QDateTime(date, QTime(0, 0, 0)).toSecsSinceEpoch();
+ qint64 endOfDay = QDateTime(date, QTime(23, 59, 59)).toSecsSinceEpoch();
QSqlQuery query(db);
query.prepare("DELETE FROM log_food WHERE date >= ? AND date <= ? AND profile_id = 1");
detailsWidget = new DetailsWidget(this);
tabs->addTab(detailsWidget, "Analyze");
- // Meal Tab
+ // Meal Tab (Builder)
mealWidget = new MealWidget(this);
- tabs->addTab(mealWidget, "Meal Tracker");
+ tabs->addTab(mealWidget, "Meal Builder");
+
+ // Daily Log Tab
+ dailyLogWidget = new DailyLogWidget(this);
+ tabs->addTab(dailyLogWidget, "Daily Log");
// Connect Analysis -> Meal
connect(detailsWidget, &DetailsWidget::addToMeal, this,
// tabs->setCurrentWidget(mealWidget);
});
+ // Connect Meal Builder -> Daily Log
+ connect(mealWidget, &MealWidget::logUpdated, dailyLogWidget, &DailyLogWidget::refresh);
+
// Status Bar
dbStatusLabel = new QLabel(this);
dbStatusLabel->setFrameStyle(QFrame::Panel | QFrame::Sunken);
--- /dev/null
+#include "widgets/dailylogwidget.h"
+
+#include <QDebug>
+#include <QHeaderView>
+#include <QLabel>
+
+DailyLogWidget::DailyLogWidget(QWidget* parent) : QWidget(parent) {
+ setupUi();
+ refresh();
+}
+
+void DailyLogWidget::setupUi() {
+ auto* layout = new QVBoxLayout(this);
+
+ layout->addWidget(new QLabel("Today's Food Log", this));
+
+ logTable = new QTableWidget(this);
+ logTable->setColumnCount(4);
+ logTable->setHorizontalHeaderLabels({"Meal", "Food", "Amount", "Calories"});
+ logTable->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Stretch);
+
+ layout->addWidget(logTable);
+}
+
+void DailyLogWidget::refresh() {
+ updateTable();
+}
+
+void DailyLogWidget::updateTable() {
+ logTable->setRowCount(0);
+
+ // Get logs for today
+ auto logs = m_mealRepo.getDailyLogs(QDate::currentDate());
+
+ for (const auto& log : logs) {
+ int row = logTable->rowCount();
+ logTable->insertRow(row);
+
+ // Meal Name
+ logTable->setItem(row, 0, new QTableWidgetItem(log.mealName));
+
+ // Food Name
+ logTable->setItem(row, 1, new QTableWidgetItem(log.foodName));
+
+ // Amount
+ logTable->setItem(row, 2, new QTableWidgetItem(QString::number(log.grams, 'f', 1) + " g"));
+
+ // Calories Calculation
+ // TODO: optimize by fetching in batch or using repository better?
+ // For now, simple fetch is fine for valid DBs
+ auto nutrients = m_foodRepo.getFoodNutrients(log.foodId);
+ double kcal = 0;
+ for (const auto& nut : nutrients) {
+ if (nut.id == 208) { // KCAL
+ kcal = (nut.amount * log.grams) / 100.0;
+ break;
+ }
+ }
+ logTable->setItem(row, 3, new QTableWidgetItem(QString::number(kcal, 'f', 0) + " kcal"));
+ }
+}
#include <QHBoxLayout>
#include <QHeaderView>
#include <QLabel>
+#include <QMessageBox>
#include <QVBoxLayout>
MealWidget::MealWidget(QWidget* parent) : QWidget(parent) {
auto* layout = new QVBoxLayout(this);
// Items List
- layout->addWidget(new QLabel("Meal Composition", this));
+ layout->addWidget(new QLabel("Meal Composition (Builder)", this));
itemsTable = new QTableWidget(this);
itemsTable->setColumnCount(3);
itemsTable->setHorizontalHeaderLabels({"Food", "Grams", "Calories"});
layout->addWidget(itemsTable);
// Controls
- clearButton = new QPushButton("Clear Meal", this);
+ auto* buttonLayout = new QHBoxLayout();
+
+ auto* addToLogButton = new QPushButton("Add to Log", this);
+ connect(addToLogButton, &QPushButton::clicked, this, &MealWidget::onAddToLog);
+ buttonLayout->addWidget(addToLogButton);
+
+ clearButton = new QPushButton("Clear Builder", this);
connect(clearButton, &QPushButton::clicked, this, &MealWidget::clearMeal);
- layout->addWidget(clearButton);
+ buttonLayout->addWidget(clearButton);
+
+ layout->addLayout(buttonLayout);
// Totals
- layout->addWidget(new QLabel("Total Nutrition", this));
+ layout->addWidget(new QLabel("Predicted Nutrition", this));
totalsTable = new QTableWidget(this);
totalsTable->setColumnCount(3);
totalsTable->setHorizontalHeaderLabels({"Nutrient", "Total", "Unit"});
totalsTable->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch);
layout->addWidget(totalsTable);
- refresh(); // Load initial state
+ refresh();
}
void MealWidget::addFood(int foodId, const QString& foodName, double grams) {
- // Default to meal_id 1 (e.g. Breakfast/General) for now
- // TODO: Add UI to select meal
- m_mealRepo.addFoodLog(foodId, grams, 1);
+ std::vector<Nutrient> baseNutrients = repository.getFoodNutrients(foodId);
+
+ MealItem item;
+ item.foodId = foodId;
+ item.name = foodName;
+ item.grams = grams;
+ item.nutrients_100g = baseNutrients;
+ mealItems.push_back(item);
+
refresh();
}
-void MealWidget::refresh() {
- mealItems.clear();
- itemsTable->setRowCount(0);
+void MealWidget::onAddToLog() {
+ if (mealItems.empty()) return;
- auto logs = m_mealRepo.getDailyLogs(); // defaults to today
+ // TODO: Add meal selection dialog? For now default to Breakfast/General (1)
+ int mealId = 1;
- for (const auto& log : logs) {
- std::vector<Nutrient> baseNutrients = repository.getFoodNutrients(log.foodId);
+ for (const auto& item : mealItems) {
+ m_mealRepo.addFoodLog(item.foodId, item.grams, mealId);
+ }
- MealItem item;
- item.foodId = log.foodId;
- item.name = log.foodName;
- item.grams = log.grams;
- item.nutrients_100g = baseNutrients;
- mealItems.push_back(item);
+ emit logUpdated();
- // Update Items Table
+ mealItems.clear();
+ refresh();
+
+ QMessageBox::information(this, "Logged", "Meal added to daily log.");
+}
+
+void MealWidget::refresh() {
+ itemsTable->setRowCount(0);
+
+ for (const auto& item : mealItems) {
int row = itemsTable->rowCount();
itemsTable->insertRow(row);
itemsTable->setItem(row, 0, new QTableWidgetItem(item.name));
itemsTable->setItem(row, 1, new QTableWidgetItem(QString::number(item.grams)));
- // Calculate Calories (ID 208)
double kcal = 0;
- for (const auto& nut : baseNutrients) {
+ for (const auto& nut : item.nutrients_100g) {
if (nut.id == 208) {
kcal = (nut.amount * item.grams) / 100.0;
break;
}
void MealWidget::clearMeal() {
- m_mealRepo.clearDailyLogs();
- refresh();
+ if (mealItems.empty()) return;
+
+ auto reply = QMessageBox::question(this, "Clear Builder",
+ "Are you sure you want to clear the current meal builder?",
+ QMessageBox::Yes | QMessageBox::No);
+
+ if (reply == QMessageBox::Yes) {
+ mealItems.clear();
+ refresh();
+ }
}
void MealWidget::updateTotals() {