KacperM33's picture
Poprawa UI dla smartfonów
a7e6544
Raw
History Blame Contribute Delete
10.1 kB
// 1. ZDJĘCIA Z DATASETU
const hardcodedMeals = [
{ name: "Stek z warzywami", image: "/test_images/stek_z_warzywami.jpg", macros: { kcal: 525, p: 48, f: 35, c: 6 } },
{ name: "Mini pizza salami", image: "/test_images/mini_pizza_salami.jpg", macros: { kcal: 132, p: 6, f: 6, c: 15 } },
{ name: "Jajecznica z brokułem", image: "/test_images/jajecznica_z_brokulem.jpg", macros: { kcal: 296, p: 19, f: 21, c: 7 } },
{ name: "Mix sałat", image: "/test_images/miska_salaty.jpg", macros: { kcal: 20, p: 1, f: 0, c: 4 } },
{ name: "Bekon", image: "/test_images/bekon.jpg", macros: { kcal: 470, p: 32, f: 36, c: 1 } },
{ name: "Owsianka z owocami", image: "/test_images/owsianka_z_owocami.jpg", macros: { kcal: 155, p: 5, f: 3, c: 29 } }
];
// 2. ZDJĘCIA SPOZA DATASETU
const externalMeals = [
{ name: "Burger drwala", image: "/test_images/burger_drwala.png", macros: { kcal: 915, p: 39, f: 52, c: 70 } },
{ name: "Kotelty drobiowe z ziemniakami i sałatą", image: "/test_images/kotelty_z_ziemniakami.jpeg", macros: { kcal: 590, p: 61, f: 11, c: 63 } },
{ name: "Spaghetti bolognese", image: "/test_images/spaghetti-bolognese.jpg", macros: { kcal: 405, p: 21, f: 17, c: 43 } },
{ name: "SUPER bowl", image: "/test_images/super_bowl.png", macros: { kcal: 716, p: 33, f: 42, c: 60 } }
];
// 3. POSIŁKI UŻYTKOWNIKÓW
let userMeals = JSON.parse(localStorage.getItem('savedUserMeals')) || [];
let currentFile = null;
let currentTruth = null;
let activeTab = null;
// Słownik do przywracania oryginalnych nazw przycisków
const btnOriginalText = {
test: "🗂️ Dataset",
external: "🌍 Spoza Datasetu",
user: "👤 Użytkownik"
};
window.onload = () => {};
function openSidebar(tab) {
const sidebar = document.getElementById('sidebar');
const btns = {
test: document.getElementById('btnTest'),
external: document.getElementById('btnExternal'),
user: document.getElementById('btnUser')
};
// Resetujemy wszystkie przyciski do stanu domyślnego
for (let key in btns) {
btns[key].classList.remove('open');
btns[key].classList.remove('shifted'); // Usuwamy przesunięcie
btns[key].style.backgroundColor = "#333";
btns[key].style.color = "white";
btns[key].innerText = btnOriginalText[key];
}
// Jeśli kliknięto aktywny panel -> zamknij i przerwij (wszystko wraca na prawo)
if (activeTab === tab && sidebar.classList.contains('open')) {
sidebar.classList.remove('open');
activeTab = null;
return;
}
// Otwarcie nowego panelu
sidebar.classList.add('open');
activeTab = tab;
// Otwarcie nowego panelu
sidebar.classList.add('open');
activeTab = tab;
// JEŚLI TO TELEFON - ZAMKNIJ PRZYCISKI PO WYBORZE
if (window.innerWidth <= 800) {
document.getElementById('menuContainer').classList.remove('show');
}
// Przesuwamy WSZYSTKIE przyciski na lewo (do krawędzi panelu)
for (let key in btns) {
btns[key].classList.add('shifted');
}
// Stylizacja TYLKO aktywnego przycisku i zmiana tekstu na emotkę
btns[tab].classList.add('open');
btns[tab].style.backgroundColor = "#00ff88";
btns[tab].style.color = "#121212";
btns[tab].innerText = "▶︎▶︎▶︎"; // Emotka zastępująca ">>> Zamknij"
// Wybór odpowiedniej zawartości do wyświetlenia
if (tab === 'test') {
renderList(hardcodedMeals, 'test');
} else if (tab === 'external') {
renderList(externalMeals, 'external');
} else {
renderList(userMeals, 'user');
}
}
function renderList(mealsArray, type) {
const list = document.getElementById('mealsList');
const form = document.getElementById('addMealForm');
const title = document.getElementById('sidebarTitle');
const desc = document.getElementById('sidebarDesc');
list.innerHTML = "";
if (type === 'test') {
title.innerText = "Baza Datasetu";
desc.innerText = "Oryginalne posiłki wycięte ze zbioru testowego.";
form.style.display = 'none';
if(mealsArray.length === 0) list.innerHTML = "<p style='color:#555;'>Brak zdjęć w skrypcie.</p>";
} else if (type === 'external') {
title.innerText = "Spoza Datasetu";
desc.innerText = "Testy na zdjęciach spoza zbioru.";
form.style.display = 'none';
if(mealsArray.length === 0) list.innerHTML = "<p style='color:#555;'>Brak zewnętrznych zdjęć.</p>";
} else {
title.innerText = "Posiłki Użytkownika";
desc.innerText = "Zapisywane lokalnie w przeglądarce.";
form.style.display = 'block';
if(mealsArray.length === 0) list.innerHTML = "<p style='color:#555; text-align:center;'>Dodaj pierwszy posiłek poniżej!</p>";
}
mealsArray.forEach((meal, index) => {
list.innerHTML += `
<div class="meal-card" onclick="loadMealIntoAnalyzer(${index}, '${type}')">
<img src="${meal.image}" alt="Zdjęcie">
<div class="meal-card-title">${meal.name}</div>
<div class="meal-card-macro">
🔥 ${meal.macros.kcal} kcal | 🍗 ${meal.macros.p}g | 🥑 ${meal.macros.f}g | 🍞 ${meal.macros.c}g
</div>
</div>
`;
});
}
function previewNewImage(event) {
if(event.target.files.length === 0) return;
currentFile = event.target.files[0];
currentTruth = null;
setupPreview(URL.createObjectURL(currentFile), "Tryb: Nieznane zdjęcie (Z dysku)");
}
async function loadMealIntoAnalyzer(index, type) {
let meal;
if (type === 'test') meal = hardcodedMeals[index];
else if (type === 'external') meal = externalMeals[index];
else meal = userMeals[index];
currentTruth = meal.macros;
try {
const res = await fetch(meal.image);
const blob = await res.blob();
currentFile = new File([blob], "test_image.jpg", { type: "image/jpeg" });
setupPreview(meal.image, `Tryb: Ground Truth (${meal.name})`);
if(window.innerWidth < 800) openSidebar(activeTab);
} catch (err) {
alert("Błąd ładowania! Upewnij się, że zdjęcie jest fizycznie w folderze.");
}
}
function setupPreview(imageSrc, modeText) {
const preview = document.getElementById('preview');
const modeInd = document.getElementById('modeIndicator');
preview.src = imageSrc;
preview.style.display = 'block';
document.getElementById('analyzeBtn').disabled = false;
document.getElementById('resultsPanel').style.display = 'none';
modeInd.innerText = modeText;
modeInd.style.color = currentTruth ? "#ffaa00" : "#aaa";
}
async function analyzeImage() {
if (!currentFile) return;
const btn = document.getElementById('analyzeBtn');
btn.disabled = true;
btn.innerText = "⏳ ONNX analizuje...";
const formData = new FormData();
formData.append("file", currentFile);
try {
const response = await fetch('/predict-macro', {
method: 'POST',
body: formData
});
const data = await response.json();
displayResults(data.predictions);
} catch (error) {
alert("Błąd serwera! Upewnij się, że FastAPI działa.");
console.error(error);
} finally {
btn.disabled = false;
btn.innerText = "Analizuj Makro";
}
}
function displayResults(preds) {
document.getElementById('res-kcal').innerText = preds.kcal + " kcal";
document.getElementById('res-protein').innerText = preds.protein_g + " g";
document.getElementById('res-fat').innerText = preds.fat_g + " g";
document.getElementById('res-carb').innerText = preds.carb_g + " g";
const truthCols = document.querySelectorAll('.truth-col');
if (currentTruth) {
truthCols.forEach(col => col.style.display = 'table-cell');
document.getElementById('truth-kcal').innerText = currentTruth.kcal + " kcal";
document.getElementById('truth-protein').innerText = currentTruth.p + " g";
document.getElementById('truth-fat').innerText = currentTruth.f + " g";
document.getElementById('truth-carb').innerText = currentTruth.c + " g";
document.getElementById('diff-kcal').innerText = Math.abs((preds.kcal - currentTruth.kcal).toFixed(1)) + " kcal";
document.getElementById('diff-protein').innerText = Math.abs((preds.protein_g - currentTruth.p).toFixed(1)) + " g";
document.getElementById('diff-fat').innerText = Math.abs((preds.fat_g - currentTruth.f).toFixed(1)) + " g";
document.getElementById('diff-carb').innerText = Math.abs((preds.carb_g - currentTruth.c).toFixed(1)) + " g";
} else {
truthCols.forEach(col => col.style.display = 'none');
}
document.getElementById('resultsPanel').style.display = 'block';
}
function addUserMeal() {
const fileInput = document.getElementById('newMealImage');
const name = document.getElementById('newMealName').value;
const kcal = document.getElementById('newMealKcal').value;
const p = document.getElementById('newMealP').value;
const f = document.getElementById('newMealF').value;
const c = document.getElementById('newMealC').value;
if(!fileInput.files[0] || !name || !kcal) {
alert("Wypełnij nazwę, zdjęcie i chociaż kalorie!");
return;
}
const reader = new FileReader();
reader.onload = function(e) {
const newMeal = {
name: name,
image: e.target.result,
macros: { kcal: kcal, p: p||0, f: f||0, c: c||0 }
};
userMeals.push(newMeal);
localStorage.setItem('savedUserMeals', JSON.stringify(userMeals));
document.getElementById('newMealName').value = "";
fileInput.value = "";
renderList(userMeals, 'user');
};
reader.readAsDataURL(fileInput.files[0]);
}
// Obsługa menu na telefonach
function toggleMobileMenu() {
document.getElementById('menuContainer').classList.toggle('show');
}