feat(kiosk-wizard): step Features con screensaver, prezzi, piano pasti, zero-waste tips

Step 5 del wizard ora mostra 4 toggle (pre-compilati se già configurati):
  - Salvaschermo orologio (screensaver_enabled)
  - Prezzi lista spesa (price_enabled)
  - Piano pasti (meal_plan_enabled)
  - Suggerimenti zero-waste durante cottura (zerowaste_tips_enabled)

Solo i toggle NON ancora impostati in prefs partono da false (fresh install).
Tutti e 4 vengono salvati in SharedPreferences e inviati al server via
save_settings al completamento del wizard.

PHP/JS: zerowaste_tips_enabled aggiunto come impostazione server-side
(ZEROWASTE_TIPS_ENABLED in .env), sincronizzata nel WebView via
_applySyncedSettings() al caricamento.
This commit is contained in:
dadaloop82
2026-05-17 15:40:01 +00:00
parent d26dce283d
commit 8360f5a0a0
5 changed files with 184 additions and 42 deletions
+2
View File
@@ -2652,6 +2652,7 @@ function getServerSettings(): void {
'meal_plan_enabled' => env('MEAL_PLAN_ENABLED', 'false') === 'true',
'screensaver_enabled' => env('SCREENSAVER_ENABLED', 'false') === 'true',
'screensaver_timeout' => (int)env('SCREENSAVER_TIMEOUT', '5'),
'zerowaste_tips_enabled' => env('ZEROWASTE_TIPS_ENABLED', 'false') === 'true',
'price_enabled' => env('PRICE_ENABLED', 'false') === 'true',
'price_country' => env('PRICE_COUNTRY', 'Italia'),
'price_currency' => env('PRICE_CURRENCY', 'EUR'),
@@ -2709,6 +2710,7 @@ function saveSettings(): void {
'meal_plan_enabled' => 'MEAL_PLAN_ENABLED',
'screensaver_enabled' => 'SCREENSAVER_ENABLED',
'price_enabled' => 'PRICE_ENABLED',
'zerowaste_tips_enabled' => 'ZEROWASTE_TIPS_ENABLED',
];
// Integer keys
$intMap = [
+2 -1
View File
@@ -2185,7 +2185,8 @@ function _applySyncedSettings(serverSettings) {
'tts_method','tts_auth_type','tts_content_type','tts_payload_key',
'tts_engine','tts_rate','tts_pitch','tts_auth_header_name','tts_auth_header_value','tts_extra_fields',
'screensaver_enabled','screensaver_timeout',
'price_enabled','price_country','price_currency','price_update_months'];
'price_enabled','price_country','price_currency','price_update_months',
'zerowaste_tips_enabled'];
let changed = false;
for (const key of serverKeys) {
if (serverSettings[key] !== undefined && serverSettings[key] !== null && serverSettings[key] !== '') {
@@ -110,6 +110,9 @@ class SetupActivity : AppCompatActivity() {
// Screensaver step
private lateinit var setupSwitchScreensaver: SwitchMaterial
private lateinit var setupSwitchPrices: SwitchMaterial
private lateinit var setupSwitchMealPlan: SwitchMaterial
private lateinit var setupSwitchZeroWaste: SwitchMaterial
// Done step
private lateinit var summaryText: TextView
@@ -128,6 +131,9 @@ class SetupActivity : AppCompatActivity() {
private const val KEY_HAS_SCALE = "has_scale"
private const val KEY_LANGUAGE = "kiosk_language"
private const val KEY_SCREENSAVER = "screensaver_enabled"
private const val KEY_PRICE_ENABLED = "price_enabled"
private const val KEY_MEAL_PLAN = "meal_plan_enabled"
private const val KEY_ZEROWASTE_TIPS = "zerowaste_tips_enabled"
private const val PERMISSION_REQUEST_CODE = 2004
private const val BLE_PERMISSION_REQUEST = 2006
@@ -238,10 +244,17 @@ class SetupActivity : AppCompatActivity() {
tvTestWeight = findViewById(R.id.tvTestWeight)
testWeightBox = findViewById(R.id.testWeightBox)
// Screensaver step
// Features step — bind all four toggles
setupSwitchScreensaver = findViewById(R.id.setupSwitchScreensaver)
// Pre-fill saved screensaver pref
setupSwitchScreensaver.isChecked = prefs.getBoolean(KEY_SCREENSAVER, false)
setupSwitchPrices = findViewById(R.id.setupSwitchPrices)
setupSwitchMealPlan = findViewById(R.id.setupSwitchMealPlan)
setupSwitchZeroWaste = findViewById(R.id.setupSwitchZeroWaste)
// Pre-fill from saved prefs only if each key was previously configured
// ("se non sono impostati, chiedi!" — fresh install → all start at false)
setupSwitchScreensaver.isChecked = if (prefs.contains(KEY_SCREENSAVER)) prefs.getBoolean(KEY_SCREENSAVER, false) else false
setupSwitchPrices.isChecked = if (prefs.contains(KEY_PRICE_ENABLED)) prefs.getBoolean(KEY_PRICE_ENABLED, false) else false
setupSwitchMealPlan.isChecked = if (prefs.contains(KEY_MEAL_PLAN)) prefs.getBoolean(KEY_MEAL_PLAN, false) else false
setupSwitchZeroWaste.isChecked = if (prefs.contains(KEY_ZEROWASTE_TIPS)) prefs.getBoolean(KEY_ZEROWASTE_TIPS, false) else false
// Done step
summaryText = findViewById(R.id.setupSummaryText)
@@ -381,10 +394,15 @@ class SetupActivity : AppCompatActivity() {
findViewById<MaterialButton>(R.id.btnScaleNext).isEnabled = true
}
// ── Screensaver ───────────────────────────────────────────────────
// ── Features step (screensaver / prices / meal plan / zero-waste) ────
findViewById<MaterialButton>(R.id.btnScreensaverBack).setOnClickListener { showStep(4) }
findViewById<MaterialButton>(R.id.btnScreensaverNext).setOnClickListener {
prefs.edit().putBoolean(KEY_SCREENSAVER, setupSwitchScreensaver.isChecked).apply()
prefs.edit()
.putBoolean(KEY_SCREENSAVER, setupSwitchScreensaver.isChecked)
.putBoolean(KEY_PRICE_ENABLED, setupSwitchPrices.isChecked)
.putBoolean(KEY_MEAL_PLAN, setupSwitchMealPlan.isChecked)
.putBoolean(KEY_ZEROWASTE_TIPS, setupSwitchZeroWaste.isChecked)
.apply()
showStep(6)
}
@@ -974,6 +992,9 @@ class SetupActivity : AppCompatActivity() {
val url = prefs.getString(KEY_URL, "") ?: ""
val hasScale = prefs.getBoolean(KEY_HAS_SCALE, false)
val screensOn = setupSwitchScreensaver.isChecked
val pricesOn = setupSwitchPrices.isChecked
val mealPlanOn = setupSwitchMealPlan.isChecked
val zeroWasteOn = setupSwitchZeroWaste.isChecked
val scaleName = bleManager?.getSavedDeviceName()
val scaleOk = hasScale && scaleName != null
val lang = prefs.getString(KEY_LANGUAGE, "it") ?: "it"
@@ -986,7 +1007,10 @@ class SetupActivity : AppCompatActivity() {
hasScale -> "⚠️ Bilancia: da configurare"
else -> "${getString(R.string.summary_scale_skip)}"
})
sb.appendLine(if (screensOn) "🌙 ${getString(R.string.summary_screensaver_on)}" else "💡 ${getString(R.string.summary_screensaver_off)}")
sb.appendLine(if (screensOn) getString(R.string.summary_screensaver_on) else getString(R.string.summary_screensaver_off))
if (pricesOn) sb.appendLine(getString(R.string.summary_prices_on))
if (mealPlanOn) sb.appendLine(getString(R.string.summary_mealplan_on))
if (zeroWasteOn) sb.appendLine(getString(R.string.summary_zerowaste_on))
summaryText.text = sb.toString().trimEnd()
}
@@ -996,14 +1020,18 @@ class SetupActivity : AppCompatActivity() {
if (baseUrl.isNotEmpty()) {
val hasScale = prefs.getBoolean(KEY_HAS_SCALE, false) && (bleManager?.getSavedDeviceAddress() != null)
val screensaver = prefs.getBoolean(KEY_SCREENSAVER, false)
val priceEnabled = prefs.getBoolean(KEY_PRICE_ENABLED, false)
val mealPlan = prefs.getBoolean(KEY_MEAL_PLAN, false)
val zeroWaste = prefs.getBoolean(KEY_ZEROWASTE_TIPS, false)
Thread {
try {
val url = "$baseUrl/api/index.php?action=save_settings"
val body = buildString {
append("{\"screensaver_enabled\":$screensaver")
append(",\"price_enabled\":$priceEnabled")
append(",\"meal_plan_enabled\":$mealPlan")
append(",\"zerowaste_tips_enabled\":$zeroWaste")
if (hasScale) {
// Use the tablet's actual LAN IP so the EverShelf server
// (potentially on a different machine) can reach the gateway.
val lanIp = getDeviceLanIp() ?: "127.0.0.1"
append(",\"scale_enabled\":true,\"scale_gateway_url\":\"ws://$lanIp:8765\"")
}
@@ -1050,7 +1050,7 @@
</LinearLayout>
<!-- ════════════════════════════════════════════
STEP 5 — Screensaver
STEP 5 — Features
════════════════════════════════════════════ -->
<LinearLayout
android:id="@+id/stepScreensaver"
@@ -1063,66 +1063,58 @@
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="🌙"
android:text=""
android:textSize="52sp"
android:layout_marginBottom="12dp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/tvScreensaverTitle"
android:text="@string/setup_screensaver_title"
android:text="@string/setup_features_title"
android:textColor="#f1f5f9"
android:textSize="24sp"
android:textStyle="bold"
android:layout_marginBottom="8dp" />
<TextView
android:id="@+id/tvScreensaverDesc"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Dopo 5 minuti di inattività mostra un overlay con l&#39;orologio e informazioni utili (statistiche, piano pasti). Lo schermo rimane SEMPRE acceso — questa opzione riguarda solo l&#39;overlay visivo in-app."
android:text="@string/setup_features_desc"
android:textColor="#94a3b8"
android:textSize="15sp"
android:gravity="center"
android:lineSpacingExtra="4dp"
android:layout_marginBottom="28dp" />
android:layout_marginBottom="20dp" />
<!-- Toggle card -->
<!-- Toggle: Screensaver -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:background="@drawable/card_background"
android:padding="20dp"
android:padding="16dp"
android:gravity="center_vertical"
android:layout_marginBottom="32dp">
android:layout_marginBottom="10dp">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:id="@+id/tvScreensaverToggleLabel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/setup_screensaver_toggle_label"
android:textColor="#f1f5f9"
android:textSize="16sp"
android:textSize="15sp"
android:textStyle="bold"
android:layout_marginBottom="4dp" />
android:layout_marginBottom="3dp" />
<TextView
android:id="@+id/tvScreensaverToggleHint"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/setup_screensaver_toggle_hint"
android:textColor="#64748b"
android:textSize="13sp" />
android:textSize="12sp" />
</LinearLayout>
<com.google.android.material.switchmaterial.SwitchMaterial
android:id="@+id/setupSwitchScreensaver"
android:layout_width="wrap_content"
@@ -1130,6 +1122,114 @@
android:checked="false" />
</LinearLayout>
<!-- Toggle: Prezzi lista spesa -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:background="@drawable/card_background"
android:padding="16dp"
android:gravity="center_vertical"
android:layout_marginBottom="10dp">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/setup_prices_toggle_label"
android:textColor="#f1f5f9"
android:textSize="15sp"
android:textStyle="bold"
android:layout_marginBottom="3dp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/setup_prices_toggle_hint"
android:textColor="#64748b"
android:textSize="12sp" />
</LinearLayout>
<com.google.android.material.switchmaterial.SwitchMaterial
android:id="@+id/setupSwitchPrices"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="false" />
</LinearLayout>
<!-- Toggle: Piano pasti -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:background="@drawable/card_background"
android:padding="16dp"
android:gravity="center_vertical"
android:layout_marginBottom="10dp">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/setup_mealplan_toggle_label"
android:textColor="#f1f5f9"
android:textSize="15sp"
android:textStyle="bold"
android:layout_marginBottom="3dp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/setup_mealplan_toggle_hint"
android:textColor="#64748b"
android:textSize="12sp" />
</LinearLayout>
<com.google.android.material.switchmaterial.SwitchMaterial
android:id="@+id/setupSwitchMealPlan"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="false" />
</LinearLayout>
<!-- Toggle: Suggerimenti zero-waste -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:background="@drawable/card_background"
android:padding="16dp"
android:gravity="center_vertical"
android:layout_marginBottom="24dp">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/setup_zerowaste_toggle_label"
android:textColor="#f1f5f9"
android:textSize="15sp"
android:textStyle="bold"
android:layout_marginBottom="3dp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/setup_zerowaste_toggle_hint"
android:textColor="#64748b"
android:textSize="12sp" />
</LinearLayout>
<com.google.android.material.switchmaterial.SwitchMaterial
android:id="@+id/setupSwitchZeroWaste"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="false" />
</LinearLayout>
<!-- Navigation -->
<LinearLayout
android:layout_width="match_parent"
@@ -58,15 +58,26 @@
<string name="wizard_server_ok_detail">Error reporting is active — install failures will be sent to GitHub Issues automatically.</string>
<string name="wizard_server_error">Server not reachable ⚠️</string>
<string name="wizard_server_error_detail">Install errors won\'t reach GitHub Issues. Check the URL entered in step 2.</string>
<!-- Screensaver step -->
<!-- Features step (step 5) -->
<string name="setup_features_title">Funzionalità</string>
<string name="setup_features_desc">Attiva le funzioni che vuoi usare. Puoi sempre cambiarle in seguito dalle impostazioni del server.</string>
<string name="setup_screensaver_title">Salvaschermo in-app</string>
<string name="setup_screensaver_desc">Shows a clock with useful facts after 5 minutes of inactivity. Off by default (screen stays always on).</string>
<string name="setup_screensaver_toggle_label">Abilita salvaschermo orologio</string>
<string name="setup_screensaver_toggle_hint">Mostra l\'overlay orologio dopo 5 min. Lo schermo resta sempre acceso.</string>
<string name="setup_screensaver_toggle_label">Salvaschermo orologio</string>
<string name="setup_screensaver_toggle_hint">Mostra l\'overlay orologio dopo 5 min di inattività.</string>
<string name="setup_prices_toggle_label">Prezzi lista spesa</string>
<string name="setup_prices_toggle_hint">Stima automatica del costo di ogni articolo in lista tramite AI.</string>
<string name="setup_mealplan_toggle_label">Piano pasti</string>
<string name="setup_mealplan_toggle_hint">Pianifica i pasti della settimana suggerendo ricette basate sulla dispensa.</string>
<string name="setup_zerowaste_toggle_label">Suggerimenti zero-waste</string>
<string name="setup_zerowaste_toggle_hint">Durante la cottura mostra consigli per riutilizzare scarti (bucce, acqua di cottura, ecc.).</string>
<!-- Summary -->
<string name="summary_lang">Language</string>
<string name="summary_scale_skip">Scale: not configured</string>
<string name="summary_screensaver_on">Screensaver: enabled</string>
<string name="summary_screensaver_off">Screen always on (screensaver disabled)</string>
<string name="summary_screensaver_on">Screensaver: abilitato</string>
<string name="summary_screensaver_off">Screensaver: disabilitato</string>
<string name="summary_prices_on">Prezzi lista spesa: abilitati</string>
<string name="summary_mealplan_on">Piano pasti: abilitato</string>
<string name="summary_zerowaste_on">Suggerimenti zero-waste: abilitati</string>
</resources>