From 50660f634fe01a1d7944cf62975964728e4e2bfe Mon Sep 17 00:00:00 2001 From: dadaloop82 Date: Tue, 26 May 2026 14:59:17 +0000 Subject: [PATCH] fix: TTS test ask user if heard + PHP 8 end() ref bug + DB migration guard for fresh volumes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - app.js: TTS kiosk timeout 4s → 10s; fires interactive 'Hai sentito?' YES/NO prompt instead of showing error (TTS can take 6-8s; UtteranceProgressListener may not fire on all firmware); YES → success, NO → troubleshooting steps - translations: add heard_question/heard_yes/heard_no/test_ok_kiosk/test_fail_steps to all 5 languages (it/en/de/fr/es) under settings.tts - api/index.php: fix end() PHP 8.0+ reference error in _offFetchProduct() (categories_hierarchy stored in temp var before calling end()) (fixes #130) - api/database.php: migrateDB() now checks sqlite_master for 'products' table; if missing, calls initializeDB() and returns — no ALTER on nonexistent table (fixes #133, covers #131) - api/index.php: health_check db_row_count query guarded against missing inventory table (fixes #131) --- api/database.php | 10 ++++++++++ api/index.php | 13 +++++++++---- assets/js/app.js | 25 +++++++++++++++++++++---- translations/de.json | 7 ++++++- translations/en.json | 7 ++++++- translations/es.json | 7 ++++++- translations/fr.json | 7 ++++++- translations/it.json | 7 ++++++- 8 files changed, 70 insertions(+), 13 deletions(-) diff --git a/api/database.php b/api/database.php index e8cccda..7805fd0 100644 --- a/api/database.php +++ b/api/database.php @@ -126,6 +126,16 @@ function initializeDB(PDO $db): void { } function migrateDB(PDO $db): void { + // Guard: if core tables don't exist yet (e.g. DB file present but empty / partial init), + // run initializeDB first so all tables are created, then return — no ALTER TABLE needed. + $productsExists = $db->query( + "SELECT name FROM sqlite_master WHERE type='table' AND name='products'" + )->fetchColumn(); + if (!$productsExists) { + initializeDB($db); + return; + } + // Add package_unit column if missing $cols = $db->query("PRAGMA table_info(products)")->fetchAll(); $colNames = array_column($cols, 'name'); diff --git a/api/index.php b/api/index.php index 254c1bb..7b5d916 100644 --- a/api/index.php +++ b/api/index.php @@ -477,9 +477,13 @@ if (($_GET['action'] ?? '') === 'health_check') { 'hint' => $wal !== 'wal' ? 'Journal mode not optimal — will be corrected automatically on next startup' : null]; // Size & rows - $checks['db_size'] = ['ok' => true, 'value' => round(filesize($dbPath)/1024).' KB', 'optional' => true]; - $cnt = $pdo->query("SELECT COUNT(*) FROM inventory WHERE quantity > 0")->fetchColumn(); - $checks['db_row_count'] = ['ok' => true, 'value' => $cnt.' prodotti in inventario', 'optional' => true]; + $checks['db_size'] = ['ok' => true, 'value' => round(filesize($dbPath)/1024).' KB', 'optional' => true]; + if (empty($missing) || !in_array('inventory', $missing)) { + $cnt = $pdo->query("SELECT COUNT(*) FROM inventory WHERE quantity > 0")->fetchColumn(); + $checks['db_row_count'] = ['ok' => true, 'value' => $cnt.' prodotti in inventario', 'optional' => true]; + } else { + $checks['db_row_count'] = ['ok' => true, 'value' => '0 prodotti in inventario', 'optional' => true]; + } } else { foreach (['db_tables', 'db_integrity'] as $k) $checks[$k] = ['ok' => false, 'hint' => 'Cannot verify — DB connection failed']; @@ -2185,7 +2189,8 @@ function _offFetchProduct(string $barcode): ?array { } $ingredients = $p['ingredients_text_it'] ?? $p['ingredients_text'] ?? ''; - $category = $p['categories_tags'][0] ?? end($p['categories_hierarchy'] ?? []) ?? $p['categories'] ?? ''; + $catHierarchy = $p['categories_hierarchy'] ?? []; + $category = $p['categories_tags'][0] ?? (empty($catHierarchy) ? null : end($catHierarchy)) ?? $p['categories'] ?? ''; $allergens = ''; if (!empty($p['allergens_tags'])) { $allergens = implode(', ', array_map(fn($a) => str_replace('en:', '', $a), $p['allergens_tags'])); diff --git a/assets/js/app.js b/assets/js/app.js index 78dad45..272382e 100644 --- a/assets/js/app.js +++ b/assets/js/app.js @@ -14186,7 +14186,7 @@ async function testTTS() { window._kioskTtsDone = (uid) => { clearTimeout(_ttsTestTimer); window._kioskTtsDone = null; window._kioskTtsError = null; - if (statusEl) { statusEl.className = 'settings-status success'; statusEl.textContent = '✅ Voce riprodotta correttamente.'; } + if (statusEl) { statusEl.className = 'settings-status success'; statusEl.textContent = '✅ ' + t('settings.tts.test_ok_kiosk'); } }; window._kioskTtsError = (uid, code) => { clearTimeout(_ttsTestTimer); @@ -14194,11 +14194,28 @@ async function testTTS() { const msg = code == -1 ? 'sintesi non riuscita' : code == -2 ? 'lingua non supportata' : code == -3 ? 'servizio non disponibile' : ('codice ' + code); if (statusEl) { statusEl.className = 'settings-status error'; statusEl.textContent = '❌ Errore TTS Android (' + msg + ') — installa o aggiorna Google Text-to-Speech dal Play Store.'; } }; - // Timeout: if Android doesn't callback within 4s, warn about media volume + // Timeout: if Android doesn't callback within 10s, ask user if they heard the voice + // (speech can take 6-8 s; UtteranceProgressListener may not fire on all firmware) _ttsTestTimer = setTimeout(() => { window._kioskTtsDone = null; window._kioskTtsError = null; - if (statusEl) { statusEl.className = 'settings-status error'; statusEl.textContent = '⚠️ Nessun feedback ricevuto. Controlla: 1) volume media del dispositivo non sia 0; 2) Google Text-to-Speech installato e aggiornato; 3) pacchetto vocale italiano scaricato.'; } - }, 4000); + if (!statusEl) return; + statusEl.className = 'settings-status'; + statusEl.style.display = 'block'; + statusEl.innerHTML = + '🔊 ' + t('settings.tts.heard_question') + '
' + + '
' + + '' + + '' + + '
'; + window._ttsTestYes = () => { + window._ttsTestYes = null; window._ttsTestNo = null; + if (statusEl) { statusEl.className = 'settings-status success'; statusEl.innerHTML = '✅ ' + t('settings.tts.test_ok'); } + }; + window._ttsTestNo = () => { + window._ttsTestYes = null; window._ttsTestNo = null; + if (statusEl) { statusEl.className = 'settings-status error'; statusEl.innerHTML = '❌ ' + t('settings.tts.test_fail_steps'); } + }; + }, 10000); _speakBrowser('Test vocale EverShelf. La sintesi vocale funziona correttamente.'); return; } diff --git a/translations/de.json b/translations/de.json index b631603..24501f1 100644 --- a/translations/de.json +++ b/translations/de.json @@ -701,7 +701,12 @@ "voices_hint": "Verfügbare Stimmen hängen vom Betriebssystem und Browser ab. Auf macOS/iOS ist die Stimme Paola (Italienisch) verfügbar. Drücken Sie ↺ wenn die Liste nicht lädt.", "url_missing": "⚠️ Endpunkt-URL fehlt.", "test_sending": "⏳ Wird gesendet…", - "test_ok": "✅ Antwort {code} — prüfe ob der Lautsprecher gesprochen hat." + "test_ok": "✅ Antwort {code} — prüfe ob der Lautsprecher gesprochen hat.", + "heard_question": "Hast du die Stimme gehört?", + "heard_yes": "Ja, ich habe es gehört", + "heard_no": "Nein, ich habe nichts gehört", + "test_ok_kiosk": "TTS funktioniert.", + "test_fail_steps": "Prüfe: 1) Medienvolume ist nicht 0; 2) Google Text-to-Speech installiert und aktualisiert; 3) Deutsches Sprachpaket in den Android TTS-Einstellungen heruntergeladen." }, "language": { "title": "🌐 Sprache", diff --git a/translations/en.json b/translations/en.json index b33856f..b5f1228 100644 --- a/translations/en.json +++ b/translations/en.json @@ -701,7 +701,12 @@ "voices_hint": "Available voices depend on the OS and browser. On macOS/iOS the Paola (Italian) voice is available. Press ↺ if the list does not load.", "url_missing": "⚠️ Endpoint URL missing.", "test_sending": "⏳ Sending…", - "test_ok": "✅ Response {code} — check that the speaker has spoken." + "test_ok": "✅ Response {code} — check that the speaker has spoken.", + "heard_question": "Did you hear the voice?", + "heard_yes": "Yes, I heard it", + "heard_no": "No, I didn't hear it", + "test_ok_kiosk": "TTS is working.", + "test_fail_steps": "Check: 1) media volume is not 0; 2) Google Text-to-Speech is installed and updated; 3) Italian voice package is downloaded in Android TTS settings." }, "language": { "title": "🌐 Language", diff --git a/translations/es.json b/translations/es.json index d8c9b55..4216b01 100644 --- a/translations/es.json +++ b/translations/es.json @@ -694,7 +694,12 @@ "voices_hint": "Las voces disponibles dependen del SO y el navegador. Pulsa ↺ si la lista no carga.", "url_missing": "⚠️ URL del endpoint faltante.", "test_sending": "⏳ Enviando…", - "test_ok": "✅ Respuesta {code} — comprueba que el altavoz haya hablado." + "test_ok": "✅ Respuesta {code} — comprueba que el altavoz haya hablado.", + "heard_question": "¿Has escuchado la voz?", + "heard_yes": "Sí, la escuché", + "heard_no": "No, no escuché nada", + "test_ok_kiosk": "TTS funcionando.", + "test_fail_steps": "Comprueba: 1) el volumen del multimedia no es 0; 2) Google Text-to-Speech está instalado y actualizado; 3) el paquete de voz español está descargado en la configuración TTS de Android." }, "language": { "title": "🌐 Idioma", diff --git a/translations/fr.json b/translations/fr.json index 4d98c08..6fe373a 100644 --- a/translations/fr.json +++ b/translations/fr.json @@ -694,7 +694,12 @@ "voices_hint": "Les voix disponibles dépendent du système d'exploitation et du navigateur. Appuyez sur ↺ si la liste ne se charge pas.", "url_missing": "⚠️ URL de l'endpoint manquante.", "test_sending": "⏳ Envoi…", - "test_ok": "✅ Réponse {code} — vérifiez que le haut-parleur a parlé." + "test_ok": "✅ Réponse {code} — vérifiez que le haut-parleur a parlé.", + "heard_question": "Avez-vous entendu la voix ?", + "heard_yes": "Oui, je l'ai entendu", + "heard_no": "Non, je n'ai rien entendu", + "test_ok_kiosk": "TTS fonctionne.", + "test_fail_steps": "Vérifiez : 1) le volume média n'est pas 0 ; 2) Google Text-to-Speech est installé et mis à jour ; 3) le pack vocal français est téléchargé dans les paramètres TTS Android." }, "language": { "title": "🌐 Langue", diff --git a/translations/it.json b/translations/it.json index 3bbdb82..c24bc2f 100644 --- a/translations/it.json +++ b/translations/it.json @@ -701,7 +701,12 @@ "voices_hint": "Le voci disponibili dipendono dal sistema operativo e dal browser. Su macOS/iOS è disponibile la voce Paola (italiano). Premi ↺ se la lista non si carica.", "url_missing": "⚠️ URL endpoint mancante.", "test_sending": "⏳ Invio in corso…", - "test_ok": "✅ Risposta {code} — controlla che l'altoparlante abbia parlato." + "test_ok": "✅ Risposta {code} — controlla che l'altoparlante abbia parlato.", + "heard_question": "Hai sentito la voce?", + "heard_yes": "Sì, ho sentito", + "heard_no": "No, non ho sentito", + "test_ok_kiosk": "TTS funzionante.", + "test_fail_steps": "Controlla: 1) volume media del dispositivo non sia 0; 2) Google Text-to-Speech installato e aggiornato; 3) pacchetto vocale italiano scaricato nelle impostazioni TTS Android." }, "language": { "title": "🌐 Lingua / Language",