mirror of
https://github.com/StefBuwalda/cal_counter.git
synced 2025-10-30 11:19:59 +00:00
Add barcode-based meal logging workflow
Introduces a new add_meal blueprint with routes and templates for scanning barcodes, adding new food items, and logging meals. Updates FoodItemForm and FoodLogForm validation, changes FoodLog.amount to float, and integrates the new workflow into the daily log UI. Refactors user routes and templates to support the new meal logging process.
This commit is contained in:
49
application/add_meal/templates/add_item.html
Normal file
49
application/add_meal/templates/add_item.html
Normal file
@@ -0,0 +1,49 @@
|
||||
{% 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%}
|
||||
62
application/add_meal/templates/scan_barcode.html
Normal file
62
application/add_meal/templates/scan_barcode.html
Normal file
@@ -0,0 +1,62 @@
|
||||
{% 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('add_meal.step3', barcode='!')}}";
|
||||
window.location.href = baseURL.replace("!", encodeURIComponent(codeText));
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
document.getElementById('stopButton').addEventListener('click', () => {
|
||||
codeReader.reset();
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
23
application/add_meal/templates/step4.html
Normal file
23
application/add_meal/templates/step4.html
Normal file
@@ -0,0 +1,23 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<p>{{ tod }}</p>
|
||||
<p>{{ item.name }}</p>
|
||||
|
||||
<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%}
|
||||
Reference in New Issue
Block a user