- AI prompt: always return a best-guess price (never null/price_not_found)
for unrecognised items returns generic package estimate with '~' prefix
- Cache key bumped to v3 to invalidate old null-returning cache entries
- JS: manually-added items (no smart match, no spec) default to qty=1/conf
instead of qty=1/pz so _calcEstimatedTotal treats them as a single pack
- Price badge: shows '~€X.XX' prefix when source_note starts with '~'
so user knows the price is a rough estimate
- app.js and style.css versioned to 20260507a so browsers load new code
- get_shopping_price / get_all_shopping_prices moved to dedicated 'price'
rate-limit bucket (60 req/min) separate from general (120 req/min)
to avoid false 429s during sequential per-item price loading
- Add get_shopping_price / get_all_shopping_prices API endpoints
- AI (Gemini) estimates retail price per natural unit (pack, piece, bunch)
instead of always per-kg — avoids absurd totals like €1609
- _calcEstimatedTotal: proper g/ml→package conversion using defQty + regex
on unit_label; only 'kg'/'l' labels trigger weight/volume math
- Cache key bumped to v2 to invalidate old per-kg cached entries
- Suggested quantity cap lowered from 20 to 10 conf/pz
- Unit mismatch guard: if totalUsed >> buyCount*5 for unit=conf, use
purchase frequency instead of raw consumption rate
- JS _buildPricePayload: use smartShoppingItems for qty/unit (not Bring! spec)
- JS _cachedPrices: persist in sessionStorage (survives navigation);
validated by _qty/_unit metadata so stale totals auto-invalidate
- Price display redesigned: right-side column per row (price-col-main +
price-col-unit) instead of small inline badge
- fetchAllPrices: buttons disabled immediately before guard check;
running total uses only current shoppingItems (not Object.values cache)
- Background refresh: always silent (removed 90s interaction condition)
- visibilitychange: sets _bgCall=true for shopping before refreshCurrentPage
- .gitignore: add runtime data files (bring_migrate_ts, shopping_price_cache,
anomaly_dismissed, opened_shelf_cache, shopping_name_cache)
- Remove bring_catalog.json and bring_migrate_ts.json from tracking
style.css:
- Connected dot: white fill + green border/glow (was green-on-green, invisible)
app.js:
- _kioskReconfigureScale(): show #kiosk-needs-update-notice + toast when
kiosk APK is too old and reconfigureScale() method is missing
- _scaleUpdateStatus(): show/hide #scale-live-diag panel, update device + battery
- _scaleOnMessage weight: update #scale-diag-weight in real time
- _scaleOnMessage status: update #scale-diag-proto with BLE protocol
index.html:
- #kiosk-needs-update-notice: amber warning + download link inside kiosk panel
- #scale-live-diag: device name, battery, live weight readout, reconnect info
- CSS cache bump ?v=20260506d
style.css:
- Scale connected dot: bright #4ade80 fill + white border + double shadow
so it pops on the dark green header (was white on green = invisible)
index.html:
- Scale settings tab: add kiosk panel with 'Riconfigura bilancia BLE'
button (hidden in browser, shown in kiosk mode)
- Wrap gateway download section and WebSocket URL section with IDs
so JS can hide them in kiosk mode
- CSS cache bust ?v=20260506b
app.js:
- syncSettingsFromDB: in kiosk mode hide scale gateway download section,
WebSocket URL section and test button; show kiosk BLE panel instead;
auto-set URL to ws://localhost:8765
- Add _kioskReconfigureScale() helper that calls _kioskBridge.reconfigureScale()
KioskActivity.kt:
- Add reconfigureScale() @JavascriptInterface: stops GatewayService,
clears saved scale device prefs, launches SetupActivity at step 4
- Import GatewayService
app.js:
- _injectKioskOverlay: move kiosk-mode class assignment BEFORE the
_kiosk_overlay existence guard — fixes race where Kotlin onPageFinished
injects buttons during the await api() pause, then JS skips the class
- _PREF_LOC_NEEDED: 3 → 2 (remember use-location after 2 picks, not 3)
KioskActivity.kt:
- showNativeUpdateBanner: remove auto-start of triggerApkDownload;
banner now shows with 'Scarica' button enabled, download only starts
when user taps it (confirms before install)
GatewayService:
- onScanStopped() now calls scheduleReconnect() when not connected, so
if the scale is off at startup the service keeps retrying every 8s
instead of giving up after the first 20s scan window
SettingsActivity:
- Add 'Riconfigura bilancia' button (yellow outline) when a scale is
already configured — clears saved device, stops the gateway service,
and opens SetupActivity directly at step 4 (scale scan step)
SetupActivity:
- Accept 'start_step' intent extra to jump directly to a specific step
(used by SettingsActivity reconfigure flow)
initInactivityWatcher() was called once at startup and returned early if
screensaver was disabled at that moment. Enabling it later from the
settings panel had no effect until page reload.
- Make initInactivityWatcher() idempotent: attach DOM listeners only once
(flag _inactivityListenersAttached), check screensaver_enabled dynamically
inside each handler so disabling/enabling is reflected immediately
- Call initInactivityWatcher() at end of saveSettings() so the inactivity
timer starts immediately when user enables screensaver
- .env: split 'Bimby/Moulinex Cookeo' into 'Bimby' and 'Moulinex Cookeo'
- translations (it/en/de): add use_all_confirm_*, throw_all_confirm_*,
confirm.cancel, confirm.proceed, location.dispensa/frigo/freezer
- app.js: when ANY opened package exists, always show disambiguation
dialog ('solo questa confezione?' vs 'tutto?') instead of silently
finishing one — was previously showing dialog only for 2+ opened packages
- CSS: header-title-wrap uses position:absolute with left:0/right:0
+ justify-content:center so title is truly centered regardless of
button count on each side (kiosk has 2 left / 3 right)
- header-actions gets margin-left:auto to push right; both sides z-index:1
- Bump version 1.7.2 → 1.7.3 so already-open kiosk tabs will see
the update badge once the new version is deployed to the server
- CSS cache bust: ?v=20260506a
- app.js: move initInactivityWatcher() inside syncSettingsFromDB().then()
so it reads screensaver_enabled after server sync, not stale localStorage
- app.js: skip gemini_key/bring_password in save_settings POST when empty
to avoid overwriting server .env with blank values
- api/index.php: add screensaver_enabled to getServerSettings() + saveSettings()
style.css was still served with ?v=20260421a so all CSS changes since
April 21 (scale indicator redesign, banner close button fix, etc.) were
invisible in the kiosk WebView — it used the cached old file.
Bumping manifest.json version 1.7.1→1.7.2 causes the auto-update
detector (_checkWebappUpdate) to fire on the kiosk: it compares the
loaded page version (1.7.1) with the server version (1.7.2), detects
a change, and shows the '⬆️ Aggiorna' badge so the user can reload.
- explainBannerAnomaly: querySelector('#alert-banner .banner-detail')
was wrong (class is 'alert-banner-detail'); function returned null → no-op.
Fixed to getElementById('alert-banner-detail').
- alert-banner-inner: position close button absolutely (top:10px right:10px)
so it is removed from the flex row and can never push the title-body to
collapse or wrap under it. Inner gets padding-right:44px to reserve space.
- alert-banner-body: flex:1 1 0 + overflow:hidden for robust sizing
- alert-banner-title: word-break/overflow-wrap so very long product names
wrap cleanly inside the body instead of overflowing
kiosk setup wizard:
- Scale step: ask user to power on the scale before scanning (new
'Accendi la bilancia' card with 'Bilancia accesa → Cerca' button)
- BLE scan: filter results to only show compatible scales (scaleScore>0)
hiding clearly non-scale BLE devices from the list
- After device selection: run a live connection test — connect to the
scale, display the live weight, ask 'Corrisponde al peso sulla bilancia?'
with ✅ Sì / ❌ Riprova / Skip buttons before confirming the device
webapp:
- Scale indicator not live on first load: scaleInit() was firing before
syncSettingsFromDB() resolved; fixed by chaining .then(scaleInit)
- Scale icon green-on-green: connected state dot changed from #22c55e
(green, invisible on dark-green header) to white with green border+glow,
visible on any background color
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
- SettingsActivity: replace GATEWAY_PACKAGE / PackageManager check with
GatewayService status; show BLE device name + live :8765 probe;
buttons now restart GatewayService or redirect to setup wizard
- activity_settings.xml: rename section label to 'BILANCIA SMART',
update button text to '⚙️ Configura bilancia'
- evershelf-scale-gateway/README.md: add DEPRECATED notice (gateway is
now integrated into kiosk v1.6.0+, this app is no longer maintained)
- evershelf-kiosk/README.md: full rewrite — reflects v1.6.0, integrated
BLE gateway, 6-step wizard, permissions table, protocol reference
- README.md: update kiosk features (remove gateway APK install/launch,
add integrated BLE service), update scale section, update architecture,
add kiosk v1.6.0 entry in Recent Updates
- KioskActivity: move launchGatewayInBackground() BEFORE enableKioskLock() so
Android's lock-task restriction does not block starting the gateway Activity
- KioskActivity: webView.clearCache(true) before loadUrl — no caching
- KioskActivity: checkForUpdates() uses proper semver > comparison (not !=)
to avoid false-positive 'update available' when already up-to-date
- KioskActivity: showNativeUpdateBanner() removed 30s auto-hide, now auto-
triggers download immediately when update detected
- SetupActivity: onResume() re-checks gateway status when returning from gateway
config (user opens gateway, configures it, presses back → wizard refreshes)
- SetupActivity: checkGatewayStatus() probes TCP 127.0.0.1:8765 to show whether
gateway is actually running, with clear 'not running' warning to configure first
- SettingsActivity: same TCP probe for live gateway status in settings screen
- build.gradle.kts: versionCode 9, versionName 1.5.3
- assets/img/logo/logo.png: trimmed full logo (icon + text, transparent bg)
- assets/img/logo/logo_icon.png: icon-only crop (no text, for header)
- drawable-*/ic_logo.png: multi-density PNGs for Android splash (mdpi→xxxhdpi)
- activity_kiosk.xml: replace ic_launcher_foreground with ic_logo at 260dp,
remove redundant 'EverShelf' text row (already in logo image)
- index.html: add logo_icon.png in header title, logo.png in preloader
- style.css: add .app-preloader-logo and .header-logo-icon rules
Fallback install (Intent.ACTION_VIEW):
- Remove FLAG_ACTIVITY_NEW_TASK: it caused startActivityForResult to return
RESULT_CANCELED immediately, making the system installer dialog disappear in ~1s
- After fallback returns with app not installed: show '🔄 Riprova installazione'
button that calls tryFallbackInstall() directly (skips PackageInstaller which
is known to give STATUS=1 on this device)
Screensaver:
- KioskActivity.applyScreensaverFlag(): always add FLAG_KEEP_SCREEN_ON, never
clear it — screen must ALWAYS stay on in kiosk mode
- The 'salvaschermo' toggle controls the in-app JS clock overlay (webapp setting),
NOT the Android screen timeout
- finishSetup(): always push screensaver_enabled to webapp API (not just when scale
is configured)
- SettingsActivity save: remove FLAG_KEEP_SCREEN_ON conditional; push
screensaver_enabled to server API on save
- Update setup wizard description + strings to clarify in-app overlay vs screen off
Bump version to 1.5.2 (versionCode 8)
- Wizard step 4 (scale): skip question if scale already configured (KEY_HAS_SCALE=true), show gateway status directly
- Add '⚙️ Apri Gateway per configurarlo' button in setup wizard after gateway is installed
- Add same button in SettingsActivity SMART SCALE section (visible only when installed)
- Fix btnRunWizard in SettingsActivity: immediately launches SetupActivity instead of just showing a toast
- Bump version to 1.5.1 (versionCode 7)
- Before launching system installer (ACTION_VIEW fallback), show a
non-cancellable dialog warning: press Fine, NOT Apri
- After installer returns, force SetupActivity back to foreground in case
user pressed Open anyway (FLAG_ACTIVITY_REORDER_TO_FRONT)
- SetupActivity: catch STATUS_FAILURE=1 separately and immediately retry with
Intent.ACTION_VIEW (system installer dialog) instead of showing a dead error.
STATUS=1 is a generic PackageInstaller failure that can happen on many
Android 14 devices even with a valid APK, but the system installer handles it.
- SetupActivity: remove misleading 'incompatibile' hint for status=1 (was wrong;
STATUS_FAILURE_INCOMPATIBLE = 7, not 1).
- SetupActivity: deduplicate buildDeviceLabel() to shared private method
- KioskActivity: fix KIOSK_DOWNLOAD_URL to point to kiosk-latest release
(was pointing to 'latest' which only has the gateway APK, so self-update
was silently broken).
- Bump version 1.4.0 -> 1.5.0 (versionCode 5 -> 6)
- KioskActivity: remove .use{} on PackageInstaller session to prevent premature
session close causing STATUS_FAILURE=1; align with SetupActivity pattern
- SetupActivity: show full diagnostic info (status code + human-readable hint,
device, Android version) in the UI card instead of just 'status=1'
- SetupActivity: use Build.PRODUCT/BOARD fallback when MANUFACTURER='unknown'
- ErrorReporter: add forceReport param to bypass in-session dedup for retries
- ErrorReporter: include Android SDK version in deviceInfo; fallback for
'unknown' MANUFACTURER/MODEL using PRODUCT/HARDWARE/BOARD
README:
- Added prominent live demo banner at the top with links to
https://evershelfproject.dadaloop.it/demo and project website
Wiki (docs/wiki/):
- Home.md — overview, table of contents, what's new
- Installation.md — Docker, Apache, Nginx, HTTPS, cron, backup
- Configuration.md — full .env reference, settings UI, rate limits
- Features.md — complete feature documentation
- API-Reference.md — all REST endpoints with params/responses
- Android-Kiosk.md — setup wizard, permissions, troubleshooting
- Scale-Gateway.md — BLE protocol, setup, troubleshooting
- Translations.md — how to add/edit language files
- Contributing.md — dev workflow, branch strategy, CI, code style
- FAQ.md — common issues and solutions
- Add _showDestructiveConfirm() helper: shows modal with 5-second
auto-confirm countdown bar; user can confirm early or cancel
- throwAll(): now shows confirmation before discarding all stock
- submitUseAll(): same confirmation before marking all as used
- undoTransactionEntry(): replace native confirm() with modal
- Rename core logic to _doSubmitUseAll() / _doUndoTransaction()
- btn-log-undo: more visible (red tint + larger font) so user can
easily undo accidental operations from the history log
- Bump app.js version to v=20260505a