Remove manual food item addition and barcode scanning

Deleted routes and templates related to manual food item entry and barcode scanning, including add_food_item, add_food_item_manual, food_item, log_food, and related session-based selection routes. Updated navigation in base.html to remove links to these features and added links to overview, daily log, and dashboard. Simplified daily_log.html to format log amounts, and removed unused imports and forms from routes.py.
This commit is contained in:
2025-08-07 17:09:47 +02:00
parent c552a4571e
commit b282f333fd
8 changed files with 11 additions and 395 deletions

View File

@@ -21,10 +21,13 @@
<div class="collapse navbar-collapse" id="navbarNav"> <div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav"> <ul class="navbar-nav">
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="{{ url_for('scan') }}">Scan</a> <a class="nav-link" href="{{ url_for('user.overview') }}">Overview</a>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="{{ url_for('user.add_food_item_manual') }}">Add Manually</a> <a class="nav-link" href="{{ url_for('user.daily_log') }}">Daily Log</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ url_for('user.dashboard') }}">Dashboard</a>
</li> </li>
</ul> </ul>
<ul class="navbar-nav ms-auto"> <ul class="navbar-nav ms-auto">

View File

@@ -4,14 +4,11 @@ from flask import (
url_for, url_for,
render_template, render_template,
flash, flash,
session,
jsonify,
abort,
) )
from flask_login import current_user from flask_login import current_user
from application import db from application import db
from forms import FoodItemForm, FoodLogForm from forms import FoodItemForm
from models import FoodItem, FoodLog from models import FoodItem
from datetime import datetime, timezone from datetime import datetime, timezone
user_bp = Blueprint( user_bp = Blueprint(
@@ -47,46 +44,6 @@ def delete_food_item(id: int):
return redirect(url_for("user.dashboard")) return redirect(url_for("user.dashboard"))
@user_bp.route("/add_food_item/<string:barcode>", methods=["GET", "POST"])
def add_food_item(barcode):
form = FoodItemForm(barcode=barcode)
print(form)
if form.validate_on_submit():
print("[DEBUG] Valid form")
if FoodItem.query.filter_by(barcode=form.barcode.data).first() is None:
assert form.name.data is not None
assert form.energy.data is not None
assert form.protein.data is not None
assert form.carbs.data is not None
assert form.fat.data is not None
db.session.add(
FoodItem(
name=form.name.data,
owner_id=current_user.id,
energy=form.energy.data,
protein=form.protein.data,
carbs=form.carbs.data,
fat=form.fat.data,
barcode=form.barcode.data,
saturated_fat=form.saturated_fat.data,
sugar=form.sugar.data,
)
)
db.session.commit()
print("[DEBUG] New item added")
return redirect(
url_for("user.food_item", barcode=form.barcode.data)
)
else:
print("[DEBUG] Invalid form")
if form.barcode.data:
print("1")
return render_template("add_food_item.html", form=form)
else:
return redirect("/")
@user_bp.route("/edit_food_item/<int:id>", methods=["GET", "POST"]) @user_bp.route("/edit_food_item/<int:id>", methods=["GET", "POST"])
def edit_food_item(id: int): def edit_food_item(id: int):
item = FoodItem.query.get(id) item = FoodItem.query.get(id)
@@ -109,103 +66,11 @@ def edit_food_item(id: int):
return redirect(url_for("user.dashboard")) return redirect(url_for("user.dashboard"))
@user_bp.route("/food_item/<string:barcode>", methods=["GET"])
def food_item(barcode):
food = FoodItem.query.filter_by(barcode=barcode).first()
if food:
return redirect(url_for("user.log_food", item_id=food.id))
else:
return render_template(
"add_food_item.html",
barcode=barcode,
form=FoodItemForm(barcode=barcode),
)
@user_bp.route("/add_food_item_manual", methods=["GET", "POST"])
def add_food_item_manual():
form = FoodItemForm()
for item in form:
print(item)
if form.validate_on_submit():
assert form.name.data is not None
assert form.energy.data is not None
assert form.protein.data is not None
assert form.carbs.data is not None
assert form.fat.data is not None
db.session.add(
FoodItem(
name=form.name.data,
owner_id=current_user.id,
energy=form.energy.data,
protein=form.protein.data,
carbs=form.carbs.data,
fat=form.fat.data,
barcode=form.barcode.data,
saturated_fat=form.saturated_fat.data,
sugar=form.sugar.data,
)
)
db.session.commit()
return redirect(url_for("user.dashboard"))
return render_template("add_food_item_manual.html", form=form)
@user_bp.route("/log_food", methods=["GET", "POST"])
def log_food():
form = FoodLogForm()
item_id = session["item_id"]
meal_type = session["meal_type"]
if item_id is None or meal_type is None:
return redirect("/")
if db.session.get(FoodItem, item_id):
if form.validate_on_submit():
assert form.amount.data is not None
db.session.add(
FoodLog(
item_id,
current_user.id,
form.amount.data,
part_of_day=meal_type,
)
)
db.session.commit()
return redirect(url_for("user.dashboard"))
return render_template("log_food.html", form=form)
@user_bp.route("/overview", methods=["GET"]) @user_bp.route("/overview", methods=["GET"])
def overview(): def overview():
return render_template("overview.html") return render_template("overview.html")
@user_bp.route("/select_meal/<int:meal_type>", methods=["GET"])
def select_meal(meal_type: int):
assert type(meal_type) is int
session["meal_type"] = meal_type
return redirect(url_for("user.scan_product"))
@user_bp.route("/select_item/<int:item_id>", methods=["GET"])
def select_item(item_id: int):
assert type(item_id) is int
session["item_id"] = item_id
return redirect(url_for("user.log_food"))
@user_bp.route("/get_foodid", methods=["GET"])
def scan_product():
return render_template("get_item.html")
@user_bp.route("/add_meal", methods=["GET"])
def add_meal():
meal_type = session["meal_type"]
if meal_type is None:
return redirect("/")
return render_template("scan.html")
@user_bp.route("/", methods=["GET"]) @user_bp.route("/", methods=["GET"])
def daily_log(): def daily_log():
today = datetime.now(timezone.utc).date() today = datetime.now(timezone.utc).date()
@@ -217,17 +82,3 @@ def daily_log():
return render_template( return render_template(
"daily_log.html", date=(today.strftime("%d/%m/%y")), logs=logs "daily_log.html", date=(today.strftime("%d/%m/%y")), logs=logs
) )
@user_bp.route("/foodId_from_barcode/<string:barcode>", methods=["GET"])
def foodId_from_barcode(barcode: str):
# Check if barcode contains only digits
if not barcode.isdigit():
return abort(
400, description="Invalid barcode: must contain only digits"
)
item = current_user.food_items.filter_by(barcode=barcode).first()
if item is None:
return redirect(url_for("user.add_food_item", barcode=barcode))
return jsonify({"item_id": item.id})

View File

@@ -1,49 +0,0 @@
{% extends "base.html" %}
{% block content %}
<form method="POST">
{{ form.hidden_tag() }}
<div class="mb-3">
{{ form.barcode.label(class="form-label") }}
{{ form.barcode(class="form-control-plaintext", readonly=true) }}
</div>
<div class="mb-3">
{{ form.name.label(class="form-label") }}
{{ form.name(class="form-control") }}
</div>
<div class="mb-3">
{{ form.energy.label(class="form-label") }}
{{ form.energy(class="form-control") }}
</div>
<div class="mb-3">
{{ form.protein.label(class="form-label") }}
{{ form.protein(class="form-control") }}
</div>
<div class="mb-3">
{{ form.carbs.label(class="form-label") }}
{{ form.carbs(class="form-control") }}
</div>
<div class="mb-3">
{{ form.sugar.label(class="form-label") }}
{{ form.sugar(class="form-control") }}
</div>
<div class="mb-3">
{{ form.fat.label(class="form-label") }}
{{ form.fat(class="form-control") }}
</div>
<div class="mb-3">
{{ form.saturated_fat.label(class="form-label") }}
{{ form.saturated_fat(class="form-control") }}
</div>
{{ form.submit(class="btn btn-primary") }}
</form>
{% endblock%}

View File

@@ -1,49 +0,0 @@
{% extends "base.html" %}
{% block content %}
<form method="POST">
{{ form.hidden_tag() }}
<div class="mb-3">
{{ form.barcode.label(class="form-label") }}
{{ form.barcode(class="form-control") }}
</div>
<div class="mb-3">
{{ form.name.label(class="form-label") }}
{{ form.name(class="form-control") }}
</div>
<div class="mb-3">
{{ form.energy.label(class="form-label") }}
{{ form.energy(class="form-control") }}
</div>
<div class="mb-3">
{{ form.protein.label(class="form-label") }}
{{ form.protein(class="form-control") }}
</div>
<div class="mb-3">
{{ form.carbs.label(class="form-label") }}
{{ form.carbs(class="form-control") }}
</div>
<div class="mb-3">
{{ form.sugar.label(class="form-label") }}
{{ form.sugar(class="form-control") }}
</div>
<div class="mb-3">
{{ form.fat.label(class="form-label") }}
{{ form.fat(class="form-control") }}
</div>
<div class="mb-3">
{{ form.saturated_fat.label(class="form-label") }}
{{ form.saturated_fat(class="form-control") }}
</div>
{{ form.submit(class="btn btn-primary") }}
</form>
{% endblock%}

View File

@@ -29,7 +29,7 @@ Food Nutritional Info
</div> </div>
<div> <div>
{% for log in logs[0] %} {% for log in logs[0] %}
<p class="p-0 mb-0">{{log.food_item.name}} - {{log.amount}}</p> <p class="p-0 mb-0">{{log.food_item.name}} - {{"{:g}".format(log.amount)}}</p>
{% endfor %} {% endfor %}
</div> </div>
</div> </div>
@@ -41,7 +41,7 @@ Food Nutritional Info
</div> </div>
<div> <div>
{% for log in logs[1] %} {% for log in logs[1] %}
<p class="p-0 mb-0">{{log.food_item.name}} - {{log.amount}}</p> <p class="p-0 mb-0">{{log.food_item.name}} - {{"{:g}".format(log.amount)}}</p>
{% endfor %} {% endfor %}
</div> </div>
</div> </div>
@@ -52,7 +52,7 @@ Food Nutritional Info
</div> </div>
<div> <div>
{% for log in logs[2] %} {% for log in logs[2] %}
<p class="p-0 mb-0">{{log.food_item.name}} - {{log.amount}}</p> <p class="p-0 mb-0">{{log.food_item.name}} - {{"{:g}".format(log.amount)}}</p>
{% endfor %} {% endfor %}
</div> </div>
</div> </div>
@@ -63,7 +63,7 @@ Food Nutritional Info
</div> </div>
<div> <div>
{% for log in logs[3] %} {% for log in logs[3] %}
<p class="p-0 mb-0">{{log.food_item.name}} - {{log.amount}}</p> <p class="p-0 mb-0">{{log.food_item.name}} - {{"{:g}".format(log.amount)}}</p>
{% endfor %} {% endfor %}
</div> </div>
</div> </div>

View File

@@ -1,44 +0,0 @@
{% extends "base.html" %}
{% block content %}
<div class="card mb-4" style="max-width: 600px;">
<div class="card-header">
<h5 class="card-title mb-0">{{ item.name }}</h5>
<small class="text-muted">Barcode: {{ item.barcode }}</small>
</div>
<div class="card-body">
<dl class="row">
<dt class="col-sm-5">Energy per 100g</dt>
<dd class="col-sm-7">{{ item.energy_100 }} kcal</dd>
<dt class="col-sm-5">Protein per 100g</dt>
<dd class="col-sm-7">{{ "%.1f"|format(item.protein_100) }} g</dd>
<dt class="col-sm-5">Carbohydrates per 100g</dt>
<dd class="col-sm-7">{{ "%.1f"|format(item.carbs_100) }} g</dd>
<dt class="col-sm-5">Sugar per 100g</dt>
<dd class="col-sm-7">
{% if item.sugar_100 is not none %}
{{ "%.1f"|format(item.sugar_100) }} g
{% else %}
<span class="text-muted">N/A</span>
{% endif %}
</dd>
<dt class="col-sm-5">fat per 100g</dt>
<dd class="col-sm-7">{{ "%.1f"|format(item.fat_100) }} g</dd>
<dt class="col-sm-5">Saturated fat per 100g</dt>
<dd class="col-sm-7">
{% if item.saturated_fat_100 is not none %}
{{ "%.1f"|format(item.saturated_fat_100) }} g
{% else %}
<span class="text-muted">N/A</span>
{% endif %}
</dd>
</dl>
</div>
</div>
{% endblock%}

View File

@@ -1,76 +0,0 @@
{% extends "base.html" %}
{% block content %}
<div class="container py-5">
<div class="text-center mb-4">
<h1 class="fw-bold">Barcode Scanner</h1>
<p class="text-muted">Use your camera to scan barcodes</p>
</div>
<div class="d-flex justify-content-center mb-4">
<video id="video" class="border rounded shadow-sm" style="width: 100%; max-width: 500px;" autoplay
muted></video>
</div>
<div class="d-flex justify-content-center">
<button id="startButton" class="btn btn-primary px-4">Start Scanning</button>
<button id="stopButton" class="btn btn-danger px-4 ms-3">Stop</button>
</div>
</div>
<script type="module">
import { BrowserMultiFormatReader } from 'https://cdn.jsdelivr.net/npm/@zxing/library@0.21.3/+esm';
// constants
const codeReader = new BrowserMultiFormatReader();
const videoElement = document.getElementById('video');
// Start scanning for barcode
document.getElementById('startButton').addEventListener('click', async () => {
console.log('[DEBUG] Start button clicked')
try {
await navigator.mediaDevices.getUserMedia({ video: true });
} catch (err) {
alert("No camera found or no camera permission");
console.error("Could not access the camera:", err);
return;
}
console.log('[DEBUG] Permission given and at least one device present');
const devices = await codeReader.listVideoInputDevices();
console.log('[DEBUG] Cameras found:', devices);
const rearCamera = devices.find(device => device.label.toLowerCase().includes('back'))
|| devices.find(device => device.label.toLowerCase().includes('rear'))
|| devices[0]; // fallback
const selectedDeviceId = rearCamera?.deviceId;
await codeReader.decodeFromVideoDevice(selectedDeviceId, videoElement, async (result, err) => {
if (result) {
// Result found, this should post the barcode
const codeText = result.getText();
const baseURL = "{{url_for('user.foodId_from_barcode', barcode='!')}}"
fetch(baseURL.replace("!", encodeURIComponent(codeText)))
.then(response => {
if (!response.ok) {
throw new Error('Network response was not OK');
}
return response.json();
})
.then(data => {
const baseURL2 = "{{url_for('user.select_item', item_id='0')}}"
window.location.href = baseURL2.replace("0", encodeURIComponent(data["item_id"]))
})
.catch(error => {
console.error('Fetch error:', error);
});
}
});
});
document.getElementById('stopButton').addEventListener('click', () => {
codeReader.reset();
});
</script>
{% endblock %}

View File

@@ -1,20 +0,0 @@
{% extends "base.html" %}
{% block content %}
<form method="POST">
{{ form.hidden_tag() }}
<div class="mb-3">
<div class="form-control-plaintext">
{{item_id}}
</div>
</div>
<div class="mb-3">
{{ form.amount.label(class="form-label") }}
{{ form.amount(class="form-control") }}
</div>
{{ form.submit(class="btn btn-primary") }}
</form>
{% endblock%}