fix: scale indicator, logo crop, gateway LAN IP, setup spacing

webapp:
- Scale indicator: replace plain green dot with ⚖️ emoji + colored
  status badge (green/amber/grey/red); icon fades out when disconnected;
  tap shows a toast with device name + battery level
- Logo images: crop excess transparent padding from logo.png and
  logo_icon.png so content fills the frame at small display sizes
- style.css: reworked .scale-status-indicator CSS for emoji+badge

kiosk:
- SetupActivity: use device's real LAN IP for scale_gateway_url
  (was hardcoded 127.0.0.1 — only worked if server and kiosk run on
  the same machine); added getDeviceLanIp() helper (prefers wlan/eth)
- activity_setup.xml: reduce welcome step padding/margins so step 1
  fits on screen without scrolling; text sizes slightly reduced
- activity_setup.xml: fix feature bullet 'Bilancia Bluetooth via
  Gateway app' → 'Bilancia BLE integrata (nessuna app esterna)'
- strings.xml (en + it): rewrite all wizard_gateway_* strings to
  reflect integrated BLE service instead of external gateway APK
- ic_logo.png: regenerated at all densities from cropped source
This commit is contained in:
dadaloop82
2026-05-05 17:47:54 +00:00
parent a5094920bf
commit 7ea5505a0d
14 changed files with 126 additions and 55 deletions
+36 -16
View File
@@ -260,26 +260,46 @@ body {
} }
/* ── Smart Scale status indicator ───────────────────────────────────── */ /* ── Smart Scale status indicator ───────────────────────────────────── */
/* Same shape as .header-btn but non-interactive — shows colored dot */ /* Scale emoji with a small colored status dot in the lower-right corner */
.scale-status-indicator { .scale-status-indicator {
cursor: default; cursor: pointer;
}
.scale-icon-wrapper {
position: relative;
display: flex;
align-items: center;
justify-content: center;
width: 28px;
height: 28px;
}
.scale-icon-emoji {
font-size: 20px;
line-height: 1;
transition: filter 0.3s, opacity 0.3s;
}
.scale-status-dot {
position: absolute;
bottom: 1px;
right: 0px;
width: 9px;
height: 9px;
border-radius: 50%;
border: 1.5px solid #0f172a;
background: #475569;
transition: background 0.4s, box-shadow 0.4s;
pointer-events: none; pointer-events: none;
} }
.scale-dot { .scale-status-connected .scale-status-dot { background: #22c55e; box-shadow: 0 0 5px #22c55eaa; }
width: 12px; .scale-status-connected .scale-icon-emoji { filter: none; opacity: 1; }
height: 12px; .scale-status-searching .scale-status-dot { background: #f59e0b; animation: scaleStatusPulse 1.4s infinite; }
border-radius: 50%; .scale-status-searching .scale-icon-emoji { filter: none; opacity: 0.85; }
background: rgba(255,255,255,0.3); .scale-status-disconnected .scale-status-dot { background: #475569; }
transition: background 0.4s, box-shadow 0.4s; .scale-status-disconnected .scale-icon-emoji { filter: grayscale(0.5); opacity: 0.55; }
flex-shrink: 0; .scale-status-error .scale-status-dot { background: #ef4444; box-shadow: 0 0 5px #ef4444aa; }
} .scale-status-error .scale-icon-emoji { filter: none; opacity: 1; }
.scale-status-connected .scale-dot { background: #22c55e; box-shadow: 0 0 6px #22c55eaa; }
.scale-status-searching .scale-dot { background: #f59e0b; animation: scaleStatusPulse 1.4s infinite; }
.scale-status-disconnected .scale-dot { background: rgba(255,255,255,0.25); }
.scale-status-error .scale-dot { background: #ef4444; box-shadow: 0 0 4px #ef4444aa; }
@keyframes scaleStatusPulse { @keyframes scaleStatusPulse {
0%, 100% { box-shadow: 0 0 4px #f59e0b88; } 0%, 100% { box-shadow: 0 0 3px #f59e0b88; }
50% { box-shadow: 0 0 10px #f59e0bcc; } 50% { box-shadow: 0 0 9px #f59e0bcc; }
} }
/* ── Scale read button (add/use forms) ──────────────────────────────── */ /* ── Scale read button (add/use forms) ──────────────────────────────── */
Binary file not shown.

Before

Width:  |  Height:  |  Size: 319 KiB

After

Width:  |  Height:  |  Size: 289 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 261 KiB

After

Width:  |  Height:  |  Size: 238 KiB

+17
View File
@@ -805,6 +805,23 @@ function _scaleUpdateStatus(state) {
el.title = labels[state] || ''; el.title = labels[state] || '';
} }
/**
* Show a brief toast with the current scale connection status when the icon is tapped.
*/
function _scaleShowInfo() {
const state = _scaleConnected ? 'connected' : 'disconnected';
const msgs = {
connected: `⚖️ ${t('scale.status_connected')}${_scaleDevice ? ': ' + _scaleDevice : ''}${_scaleBattery != null ? ' 🔋' + _scaleBattery + '%' : ''}`,
searching: `⚖️ ${t('scale.status_searching')}`,
disconnected: `⚖️ ${t('scale.status_disconnected')}`,
error: `⚖️ ${t('scale.status_error')}`,
};
const el = document.getElementById('scale-status-indicator');
const cls = el ? [...el.classList].find(c => c.startsWith('scale-status-') && c !== 'scale-status-indicator') : null;
const key = cls ? cls.replace('scale-status-', '') : state;
showToast(msgs[key] || msgs[state], key === 'connected' ? 'success' : 'info');
}
/** /**
* Show the scale reading modal and wait for a stable weight, then populate the input. * Show the scale reading modal and wait for a stable weight, then populate the input.
* @param {string} targetInputId ID of the <input> to fill * @param {string} targetInputId ID of the <input> to fill
@@ -866,7 +866,10 @@ class SetupActivity : AppCompatActivity() {
val body = buildString { val body = buildString {
append("{\"screensaver_enabled\":$screensaver") append("{\"screensaver_enabled\":$screensaver")
if (hasScale) { if (hasScale) {
append(",\"scale_enabled\":true,\"scale_gateway_url\":\"ws://127.0.0.1:8765\"") // 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\"")
} }
append("}") append("}")
} }
@@ -886,4 +889,32 @@ class SetupActivity : AppCompatActivity() {
setResult(RESULT_OK) setResult(RESULT_OK)
finish() finish()
} }
/**
* Returns the device's best LAN IPv4 address (Wi-Fi/Ethernet preferred).
* Skips loopback, VPN tunnels, and cellular interfaces.
*/
private fun getDeviceLanIp(): String? {
val skipPrefixes = listOf("tun", "ppp", "rmnet", "pdp", "v4-", "v6-", "ccmni", "sit", "gre")
var fallback: String? = null
try {
val ifaces = NetworkInterface.getNetworkInterfaces() ?: return null
while (ifaces.hasMoreElements()) {
val intf = ifaces.nextElement()
if (!intf.isUp || intf.isLoopback) continue
val name = intf.name.lowercase()
if (skipPrefixes.any { name.startsWith(it) }) continue
for (addr in intf.interfaceAddresses) {
val ip = addr.address
if (ip is java.net.Inet4Address && !ip.isLoopbackAddress) {
val ipStr = ip.hostAddress ?: continue
// Wi-Fi/Ethernet first
if (name.startsWith("wlan") || name.startsWith("eth")) return ipStr
if (fallback == null) fallback = ipStr
}
}
}
} catch (_: Exception) {}
return fallback
}
} }
Binary file not shown.

Before

Width:  |  Height:  |  Size: 91 KiB

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 132 KiB

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 227 KiB

After

Width:  |  Height:  |  Size: 243 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 227 KiB

After

Width:  |  Height:  |  Size: 386 KiB

@@ -55,8 +55,8 @@
android:gravity="center_horizontal" android:gravity="center_horizontal"
android:paddingStart="28dp" android:paddingStart="28dp"
android:paddingEnd="28dp" android:paddingEnd="28dp"
android:paddingTop="32dp" android:paddingTop="16dp"
android:paddingBottom="40dp"> android:paddingBottom="24dp">
<!-- ════════════════════════════════════════════ <!-- ════════════════════════════════════════════
STEP 0 — Language selection STEP 0 — Language selection
@@ -139,7 +139,7 @@
android:src="@drawable/ic_logo" android:src="@drawable/ic_logo"
android:adjustViewBounds="true" android:adjustViewBounds="true"
android:scaleType="fitCenter" android:scaleType="fitCenter"
android:layout_marginBottom="20dp" android:layout_marginBottom="10dp"
android:contentDescription="EverShelf" /> android:contentDescription="EverShelf" />
<TextView <TextView
@@ -147,19 +147,19 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="EverShelf Kiosk" android:text="EverShelf Kiosk"
android:textColor="#f1f5f9" android:textColor="#f1f5f9"
android:textSize="30sp" android:textSize="28sp"
android:textStyle="bold" android:textStyle="bold"
android:gravity="center" android:gravity="center"
android:layout_marginBottom="8dp" /> android:layout_marginBottom="4dp" />
<TextView <TextView
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="La tua dispensa smart in cucina" android:text="La tua dispensa smart in cucina"
android:textColor="#7c3aed" android:textColor="#7c3aed"
android:textSize="16sp" android:textSize="15sp"
android:gravity="center" android:gravity="center"
android:layout_marginBottom="28dp" /> android:layout_marginBottom="16dp" />
<!-- What is EverShelf --> <!-- What is EverShelf -->
<TextView <TextView
@@ -167,10 +167,10 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="Trasforma il tuo tablet in un pannello da cucina sempre attivo. Gestisci la dispensa, scansiona i prodotti, ricevi suggerimenti intelligenti — tutto dal tuo server di casa." android:text="Trasforma il tuo tablet in un pannello da cucina sempre attivo. Gestisci la dispensa, scansiona i prodotti, ricevi suggerimenti intelligenti — tutto dal tuo server di casa."
android:textColor="#94a3b8" android:textColor="#94a3b8"
android:textSize="15sp" android:textSize="14sp"
android:gravity="center" android:gravity="center"
android:lineSpacingExtra="4dp" android:lineSpacingExtra="3dp"
android:layout_marginBottom="28dp" /> android:layout_marginBottom="16dp" />
<!-- Privacy card (highlighted) --> <!-- Privacy card (highlighted) -->
<LinearLayout <LinearLayout
@@ -178,8 +178,8 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical" android:orientation="vertical"
android:background="@drawable/card_background" android:background="@drawable/card_background"
android:padding="20dp" android:padding="16dp"
android:layout_marginBottom="24dp"> android:layout_marginBottom="16dp">
<TextView <TextView
android:layout_width="wrap_content" android:layout_width="wrap_content"
@@ -265,9 +265,8 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical" android:orientation="vertical"
android:background="@drawable/tip_background" android:background="@drawable/tip_background"
android:padding="16dp" android:padding="14dp"
android:layout_marginBottom="32dp"> android:layout_marginBottom="16dp">
<TextView <TextView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@@ -289,7 +288,7 @@
<TextView <TextView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="⚖️ Bilancia Bluetooth via Gateway app" android:text="⚖️ Bilancia BLE integrata (nessuna app esterna)"
android:textColor="#cbd5e1" android:textColor="#cbd5e1"
android:textSize="14sp" android:textSize="14sp"
android:paddingTop="4dp" android:paddingTop="4dp"
@@ -17,21 +17,21 @@
<string name="setup_exit_cancel">Continua</string> <string name="setup_exit_cancel">Continua</string>
<!-- Wizard Step 3: Bilancia smart --> <!-- Wizard Step 3: Bilancia smart -->
<string name="wizard_step3_title">Bilancia Smart (Opzionale)</string> <string name="wizard_step3_title">Bilancia Smart</string>
<string name="wizard_step3_description">Per usare una bilancia da cucina Bluetooth, devi installare l\'app EverShelf Scale Gateway separatamente.</string> <string name="wizard_step3_description">EverShelf Kiosk include un gateway Bluetooth integrato — nessuna app esterna necessaria. Seleziona la tua bilancia qui sotto.</string>
<string name="wizard_step3_question">Hai una bilancia smart Bluetooth?</string> <string name="wizard_step3_question">Hai una bilancia smart Bluetooth?</string>
<string name="wizard_step3_yes">✅ Sì, ho una bilancia</string> <string name="wizard_step3_yes">✅ Sì, ho una bilancia</string>
<string name="wizard_step3_no">➡️ No, salta questo passaggio</string> <string name="wizard_step3_no">➡️ No, salta questo passaggio</string>
<!-- Messaggi stato gateway --> <!-- Messaggi stato gateway -->
<string name="wizard_gateway_installed">Scale Gateway installato</string> <string name="wizard_gateway_installed">Bilancia salvata</string>
<string name="wizard_gateway_installed_detail">Verrà avviato in background quando procedi.</string> <string name="wizard_gateway_installed_detail">Il gateway BLE integrato si collegherà automaticamente all\'avvio.</string>
<string name="wizard_gateway_not_installed">Scale Gateway non installato</string> <string name="wizard_gateway_not_installed">Nessuna bilancia selezionata</string>
<string name="wizard_gateway_not_installed_detail">Installa l\'app Scale Gateway per usare una bilancia Bluetooth.</string> <string name="wizard_gateway_not_installed_detail">Scansiona le bilance BLE nelle vicinanze e tocca una per selezionarla.</string>
<string name="wizard_gateway_checking">Controllo aggiornamenti</string> <string name="wizard_gateway_checking">Scansione bilance BLE in corso</string>
<string name="wizard_gateway_up_to_date">Scale Gateway è aggiornato.</string> <string name="wizard_gateway_up_to_date">Servizio BLE bilancia pronto.</string>
<string name="wizard_gateway_update_available">Aggiornamento disponibile per Scale Gateway</string> <string name="wizard_gateway_update_available">Bilancia BLE trovata</string>
<string name="wizard_gateway_update_detail">Tocca il pulsante qui sotto per aggiornarlo ora.</string> <string name="wizard_gateway_update_detail">Tocca la bilancia nell\'elenco per connettersi.</string>
<!-- Stati scaricamento / installazione --> <!-- Stati scaricamento / installazione -->
<string name="install_downloading">Scaricamento in corso…</string> <string name="install_downloading">Scaricamento in corso…</string>
@@ -16,21 +16,21 @@
<string name="setup_exit_cancel">Continue</string> <string name="setup_exit_cancel">Continue</string>
<!-- Wizard Step 3: Smart scale --> <!-- Wizard Step 3: Smart scale -->
<string name="wizard_step3_title">Smart Scale (Optional)</string> <string name="wizard_step3_title">Smart Scale</string>
<string name="wizard_step3_description">To use a Bluetooth kitchen scale, you need the EverShelf Scale Gateway app installed separately.</string> <string name="wizard_step3_description">EverShelf Kiosk includes a built-in Bluetooth gateway — no external app needed. Select your scale below.</string>
<string name="wizard_step3_question">Do you have a Bluetooth smart scale?</string> <string name="wizard_step3_question">Do you have a Bluetooth smart scale?</string>
<string name="wizard_step3_yes">✅ Yes, I have a scale</string> <string name="wizard_step3_yes">✅ Yes, I have a scale</string>
<string name="wizard_step3_no">➡️ No, skip this step</string> <string name="wizard_step3_no">➡️ No, skip this step</string>
<!-- Gateway status messages --> <!-- Gateway status messages -->
<string name="wizard_gateway_installed">Scale Gateway installed ✅</string> <string name="wizard_gateway_installed">Scale device saved ✅</string>
<string name="wizard_gateway_installed_detail">Will be launched in the background when you proceed.</string> <string name="wizard_gateway_installed_detail">The integrated BLE gateway will connect automatically on startup.</string>
<string name="wizard_gateway_not_installed">Scale Gateway not installed</string> <string name="wizard_gateway_not_installed">No scale selected</string>
<string name="wizard_gateway_not_installed_detail">Install the Scale Gateway app to use a Bluetooth scale.</string> <string name="wizard_gateway_not_installed_detail">Scan for nearby BLE scales and tap one to select it.</string>
<string name="wizard_gateway_checking">Checking for updates…</string> <string name="wizard_gateway_checking">Scanning for BLE scales…</string>
<string name="wizard_gateway_up_to_date">Scale Gateway is up to date.</string> <string name="wizard_gateway_up_to_date">Scale BLE service ready.</string>
<string name="wizard_gateway_update_available">Update available for Scale Gateway</string> <string name="wizard_gateway_update_available">BLE scale found</string>
<string name="wizard_gateway_update_detail">Tap the button below to update it now.</string> <string name="wizard_gateway_update_detail">Tap the scale in the list to connect.</string>
<!-- Install / download progress states --> <!-- Install / download progress states -->
<string name="install_downloading">Scaricamento in corso…</string> <string name="install_downloading">Scaricamento in corso…</string>
+6 -2
View File
@@ -76,8 +76,12 @@
<!-- Actions — fixed set of icon buttons, all same size --> <!-- Actions — fixed set of icon buttons, all same size -->
<div class="header-actions"> <div class="header-actions">
<button id="scale-status-indicator" class="header-btn scale-status-indicator scale-status-disconnected" <button id="scale-status-indicator" class="header-btn scale-status-indicator scale-status-disconnected"
style="display:none" data-i18n-title="scale.status_disconnected" title="⚖️ Bilancia"> style="display:none" data-i18n-title="scale.status_disconnected" title="⚖️ Bilancia"
<span class="scale-dot"></span> onclick="_scaleShowInfo()">
<span class="scale-icon-wrapper">
<span class="scale-icon-emoji">⚖️</span>
<span class="scale-status-dot"></span>
</span>
</button> </button>
<button class="header-btn header-gemini-btn" onclick="showPage('chat')" title="Chat con Gemini" data-i18n-title="chat.title"> <button class="header-btn header-gemini-btn" onclick="showPage('chat')" title="Chat con Gemini" data-i18n-title="chat.title">
<svg class="gemini-icon" viewBox="0 0 24 24" width="24" height="24" fill="white"><path d="M12 0C12 6.627 6.627 12 0 12c6.627 0 12 5.373 12 12 0-6.627 5.373-12 12-12-6.627 0-12-5.373-12-12z"/></svg> <svg class="gemini-icon" viewBox="0 0 24 24" width="24" height="24" fill="white"><path d="M12 0C12 6.627 6.627 12 0 12c6.627 0 12 5.373 12 12 0-6.627 5.373-12 12-12-6.627 0-12-5.373-12-12z"/></svg>