diff --git a/assets/js/app.js b/assets/js/app.js index 69a682e..a2c72d4 100644 --- a/assets/js/app.js +++ b/assets/js/app.js @@ -112,6 +112,9 @@ function _updateGeminiButtonState() { function _applyDemoModeUI() { if (!_demoMode) return; + // In demo mode Gemini is always "available" — no real key needed + _geminiAvailable = true; + _updateGeminiButtonState(); // Hide the settings ⚙️ nav button document.querySelectorAll('.nav-btn[data-page="settings"]').forEach(btn => { btn.style.display = 'none'; @@ -119,7 +122,7 @@ function _applyDemoModeUI() { // Prevent the setup wizard from showing const wizard = document.getElementById('setup-wizard'); if (wizard) wizard.style.display = 'none'; - // Optionally show a small demo badge in the header + // Show a small demo badge in the header const headerLeft = document.getElementById('header-left'); if (headerLeft && !document.getElementById('_demo_badge')) { const badge = document.createElement('span'); @@ -2233,6 +2236,17 @@ function togglePasswordVisibility(inputId) { // ===== API HELPER ===== async function api(action, params = {}, method = 'GET', body = null, extraHeaders = {}) { + // In demo mode, all Bring! write operations are no-ops + if (_demoMode) { + const BRING_WRITE_ACTIONS = ['bring_add', 'bring_remove', 'bring_migrate_names', 'bring_set_spec']; + if (BRING_WRITE_ACTIONS.includes(action)) { + return { success: true, added: 0, removed: 0, skipped: 0, _demo: true }; + } + // bring_list returns the in-memory demo list + if (action === 'bring_list') { + return { success: true, purchase: shoppingItems, listUUID: 'demo-list', _demo: true }; + } + } let url = `${API_BASE}?action=${action}`; if (method === 'GET') { Object.entries(params).forEach(([k, v]) => { @@ -8636,6 +8650,28 @@ async function loadShoppingList() { statusEl.innerHTML = `
${t('shopping.bring_loading')}
`; currentEl.style.display = 'none'; suggestionsEl.style.display = 'none'; + + // ── Demo mode: show placeholder list, skip all Bring! API calls ────────── + if (_demoMode) { + statusEl.style.display = 'none'; + shoppingListUUID = 'demo-list'; + shoppingItems = [ + { name: 'Latte', specification: '🟠 presto · 1L', rawName: 'Latte' }, + { name: 'Pane', specification: '', rawName: 'Pane' }, + { name: 'Uova', specification: '⚡ urgente', rawName: 'Uova' }, + { name: 'Pasta', specification: '500g', rawName: 'Pasta' }, + { name: 'Pomodori', specification: '1kg', rawName: 'Pomodori' }, + ]; + renderShoppingItems(); + currentEl.style.display = 'block'; + loadSmartShopping().then(() => { + _syncOnBringFlags(); + renderSmartShopping(); + updateShoppingTabCounts(); + renderShoppingItems(); + }); + return; + } try { const data = await api('bring_list'); @@ -8643,7 +8679,12 @@ async function loadShoppingList() { if (!data.success) { statusEl.style.display = 'block'; - statusEl.innerHTML = `
⚠️ ${escapeHtml(data.error || t('error.bring_connection'))}
`; + const isMissingCreds = data.error && data.error.toLowerCase().includes('credenziali bring'); + if (isMissingCreds) { + statusEl.innerHTML = `
🔑 ${t('shopping.bring_not_configured') || 'Bring! non è configurato. Aggiungi email e password nelle impostazioni.'}
`; + } else { + statusEl.innerHTML = `
⚠️ ${escapeHtml(data.error || t('error.bring_connection'))}
`; + } return; } diff --git a/index.html b/index.html index 88154f4..548eef9 100644 --- a/index.html +++ b/index.html @@ -1089,14 +1089,15 @@
-

🌑 Salvaschermo

-

Mostra un orologio con fatti utili dopo 5 minuti di inattività. Di default è disattivato.

+

🌙 Salvaschermo

+

Mostra un orologio con fatti utili dopo 5 minuti di inattività. Di default è disattivato.

-
@@ -1317,6 +1318,6 @@ - + diff --git a/translations/de.json b/translations/de.json index 89a8afc..ce247f3 100644 --- a/translations/de.json +++ b/translations/de.json @@ -326,6 +326,7 @@ "shopping": { "title": "🛒 Einkaufsliste", "bring_loading": "Verbindung zu Bring!...", + "bring_not_configured": "Bring! ist nicht konfiguriert. Füge E-Mail und Passwort in den Einstellungen hinzu.", "tab_to_buy": "🛍️ Zu kaufen", "tab_forecast": "🧠 Vorhersage", "total_label": "💰 Geschätzter Gesamtbetrag", @@ -596,7 +597,9 @@ "restart_notice": "Die Seite wird neu geladen, um die neue Sprache anzuwenden." }, "screensaver": { - "label": "Bildschirmschoner aktivieren" + "label": "Bildschirmschoner aktivieren", + "card_title": "🌙 Bildschirmschoner", + "card_hint": "Zeigt nach 5 Minuten Inaktivität eine Uhr mit nützlichen Fakten. Standardmäßig deaktiviert." }, "scale": { "title": "⚖️ Smart-Waage", diff --git a/translations/en.json b/translations/en.json index 44140dc..58d3a74 100644 --- a/translations/en.json +++ b/translations/en.json @@ -325,6 +325,7 @@ "shopping": { "title": "🛒 Shopping List", "bring_loading": "Connecting to Bring!...", + "bring_not_configured": "Bring! is not configured. Add your email and password in settings.", "tab_to_buy": "🛍️ To buy", "tab_forecast": "🧠 Forecast", "total_label": "💰 Estimated total", @@ -595,7 +596,9 @@ "restart_notice": "The page will reload to apply the new language." }, "screensaver": { - "label": "Enable screensaver" + "label": "Enable screensaver", + "card_title": "🌙 Screensaver", + "card_hint": "Shows a clock with useful facts after 5 minutes of inactivity. Disabled by default." }, "scale": { "title": "⚖️ Smart Scale", diff --git a/translations/it.json b/translations/it.json index 9aee3b5..0b3897c 100644 --- a/translations/it.json +++ b/translations/it.json @@ -325,6 +325,7 @@ "shopping": { "title": "🛒 Lista della Spesa", "bring_loading": "Connessione a Bring!...", + "bring_not_configured": "Bring! non è configurato. Aggiungi email e password nelle impostazioni.", "tab_to_buy": "🛍️ Da comprare", "tab_forecast": "🧠 In previsione", "total_label": "💰 Totale stimato", @@ -595,7 +596,9 @@ "restart_notice": "La pagina verrà ricaricata per applicare la nuova lingua." }, "screensaver": { - "label": "Attiva salvaschermo" + "label": "Attiva salvaschermo", + "card_title": "🌙 Salvaschermo", + "card_hint": "Mostra un orologio con fatti utili dopo 5 minuti di inattività. Di default è disattivato." }, "scale": { "title": "⚖️ Bilancia Smart",