]> Nutra Git (v2) - nutratech/gui.git/commitdiff
add daily log (wip), and fix ubuntu 20.04 build
authorShane Jaroch <chown_tee@proton.me>
Wed, 21 Jan 2026 19:27:46 +0000 (14:27 -0500)
committerShane Jaroch <chown_tee@proton.me>
Wed, 21 Jan 2026 19:27:46 +0000 (14:27 -0500)
include/mainwindow.h
include/widgets/dailylogwidget.h [new file with mode: 0644]
include/widgets/mealwidget.h
src/db/mealrepository.cpp
src/mainwindow.cpp
src/widgets/dailylogwidget.cpp [new file with mode: 0644]
src/widgets/mealwidget.cpp

index 666851365001104e64557ce644ea802a117b2924..68f1524a78bee7547ce7a194281af440785d2275 100644 (file)
@@ -6,6 +6,7 @@
 #include <QTabWidget>
 #include <array>
 
+#include "widgets/dailylogwidget.h"
 #include "widgets/detailswidget.h"
 #include "widgets/mealwidget.h"
 #include "widgets/searchwidget.h"
@@ -32,6 +33,7 @@ private:
     SearchWidget* searchWidget;
     DetailsWidget* detailsWidget;
     MealWidget* mealWidget;
+    DailyLogWidget* dailyLogWidget;
     FoodRepository repository;
 
     QMenu* recentFilesMenu;
diff --git a/include/widgets/dailylogwidget.h b/include/widgets/dailylogwidget.h
new file mode 100644 (file)
index 0000000..98a0b34
--- /dev/null
@@ -0,0 +1,30 @@
+#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
index 041a4ba4251443422929908f37a020fd2c3d8d1b..e6c83dfe4501a10669338b53ea095e32d84eaf64 100644 (file)
@@ -24,8 +24,12 @@ public:
 
     void addFood(int foodId, const QString& foodName, double grams);
 
+signals:
+    void logUpdated();
+
 private slots:
     void clearMeal();
+    void onAddToLog();
 
 private:
     void updateTotals();
index 3fe9bfceafeb9b0b09a226fa6cebce1e8e0b3a62..eba807817ef254af8e4dad949853bbfa61710ba8 100644 (file)
@@ -36,7 +36,7 @@ void MealRepository::addFoodLog(int foodId, double grams, int mealId, QDate date
     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);
@@ -62,8 +62,8 @@ std::vector<MealLogItem> MealRepository::getDailyLogs(QDate date) {
 
     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(
@@ -128,8 +128,8 @@ void MealRepository::clearDailyLogs(QDate date) {
     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");
index 0dfdf31d0d21bcea74cc89271f1f30770dbacc6b..c03a20bb4b76078e4833f87b1677e611c473939d 100644 (file)
@@ -89,9 +89,13 @@ void MainWindow::setupUi() {
     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,
@@ -101,6 +105,9 @@ void MainWindow::setupUi() {
                 // 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);
diff --git a/src/widgets/dailylogwidget.cpp b/src/widgets/dailylogwidget.cpp
new file mode 100644 (file)
index 0000000..978d11e
--- /dev/null
@@ -0,0 +1,61 @@
+#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"));
+    }
+}
index 2921932591a436d54b684c1af9a53fab5996afb7..03452bf4e88b5e6a625980715b1dcbc4348174c7 100644 (file)
@@ -4,13 +4,14 @@
 #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"});
@@ -18,53 +19,71 @@ MealWidget::MealWidget(QWidget* parent) : QWidget(parent) {
     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;
@@ -77,8 +96,16 @@ void MealWidget::refresh() {
 }
 
 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() {