mirror of
https://github.com/StefBuwalda/cal_counter.git
synced 2025-10-30 11:19:59 +00:00
Introduces a new /scan route and template for barcode scanning using ZXing in the browser. Adds a /nutri/<barcode> API endpoint to fetch food item nutrition data by barcode. Updates the FoodItem model to include a barcode field and a to_dict method for JSON serialization. Also updates seed data to include a barcode.
108 lines
4.1 KiB
HTML
108 lines
4.1 KiB
HTML
{% extends "base.html" %}
|
|
|
|
{% block content %}
|
|
<div id="main" class="container text-center">
|
|
</div>
|
|
|
|
<template id="scan_result">
|
|
<div>
|
|
<h5>Result:</h5>
|
|
<p id="result" class="fw-bold text-success"></p>
|
|
</div>
|
|
|
|
<div id="product-info"></div>
|
|
</template>
|
|
|
|
<template id="template_Reader">
|
|
<h1 class="mb-4">📷 ZXing Barcode Scanner</h1>
|
|
|
|
<div class="mb-3">
|
|
<video id="video" class="border rounded shadow-sm" width="100%" style="max-width: 500px;"></video>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<button id="startButton" class="btn btn-primary">Start Scanning</button>
|
|
<button id="stopButton" class="btn btn-danger ms-2">Stop</button>
|
|
</div>
|
|
</template>
|
|
|
|
<script type="module">
|
|
import { BrowserMultiFormatReader } from 'https://cdn.jsdelivr.net/npm/@zxing/library@0.21.3/+esm';
|
|
|
|
const mainElement = document.getElementById('main');
|
|
const readerTemplate = document.getElementById('template_Reader')
|
|
const readerClone = readerTemplate.content.cloneNode(true);
|
|
const resultTemplate = document.getElementById('scan_result')
|
|
const resultClone = resultTemplate.content.cloneNode(true);
|
|
mainElement.appendChild(readerClone);
|
|
|
|
// constants
|
|
const codeReader = new BrowserMultiFormatReader();
|
|
const videoElement = document.getElementById('video');
|
|
|
|
|
|
async function fetchProductData(barcode) {
|
|
// Step 1: GET Data
|
|
const response = await fetch(`/nutri/${barcode}`);
|
|
// Step 2: Check if response wasn't ok
|
|
if (!response.ok) throw new Error('Network response was not ok');
|
|
// Step 3: Convert response to json and check if empty
|
|
const nutritionData = await response.json();
|
|
mainElement.innerHTML = '';
|
|
mainElement.appendChild(resultClone);
|
|
const resultElement = document.getElementById('result');
|
|
resultElement.textContent = barcode;
|
|
const container = document.getElementById('product-info');
|
|
if (Object.keys(nutritionData).length === 0) {
|
|
// No data, enter new data
|
|
}
|
|
else {
|
|
container.innerHTML = `
|
|
<h2>${nutritionData.name}</h2>
|
|
<p><strong>Barcode:</strong> ${nutritionData.barcode}</p>
|
|
<p><strong>Energy:</strong> ${nutritionData.energy_100g} kcal per 100g</p>
|
|
<p><strong>Carbs:</strong> ${nutritionData.carbs_100g} g</p>
|
|
<p><strong>Sugar:</strong> ${nutritionData.sugar_100g} g</p>
|
|
<p><strong>Fats:</strong> ${nutritionData.fats_100g} g</p>
|
|
<p><strong>Saturated Fats:</strong> ${nutritionData.saturated_fats_100g} g</p>
|
|
<p><strong>Protein:</strong> ${nutritionData.protein_100g} g</p>
|
|
`;
|
|
}
|
|
}
|
|
|
|
|
|
// Start scanning for barcode
|
|
document.getElementById('startButton').addEventListener('click', async () => {
|
|
console.log('[DEBUG] Start button clicked')
|
|
try {
|
|
await navigator.mediaDevices.getUserMedia({ video: true });
|
|
// Use stream with video.srcObject = stream
|
|
} 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 selectedDeviceId = devices[0]?.deviceId;
|
|
await codeReader.decodeFromVideoDevice(selectedDeviceId, videoElement, async (result, err) => {
|
|
if (result) {
|
|
const codeText = result.getText();
|
|
try {
|
|
await fetchProductData(codeText)
|
|
codeReader.reset();
|
|
} catch (error) {
|
|
console.error('Error fetching nutrition data:', error);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
document.getElementById('stopButton').addEventListener('click', () => {
|
|
codeReader.reset();
|
|
resultElement.textContent = '';
|
|
container.innerHTML = ""
|
|
});
|
|
</script>
|
|
{% endblock %} |