Compare commits
16 Commits
kiosk-1.7.13
...
v1.7.14
| Author | SHA1 | Date | |
|---|---|---|---|
| 45dc79e5b7 | |||
| 8508993441 | |||
| a3147d704e | |||
| 834d8efab4 | |||
| 8894a5a2c7 | |||
| 5f4c29bd5a | |||
| 460875430b | |||
| 8a596cb7d8 | |||
| 99b8953ccf | |||
| c87d7d2cde | |||
| 424fc7bbe3 | |||
| 61a2372caa | |||
| ad9be3b705 | |||
| bd8dc0501a | |||
| c9a6f8ec42 | |||
| 0afdf60d38 |
@@ -5,6 +5,23 @@ All notable changes to EverShelf will be documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en1.1.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [Unreleased] — Ideas & Roadmap
|
||||
|
||||
> Ideas collected during development. No priority or date implied.
|
||||
|
||||
- **Recipe scraps tips** — During cooking steps, detect "waste" generated (peels, cores, bones, eggshells, coffee grounds, citrus zest, etc.) and surface AI-powered tips on how to reuse them (compost, natural cleaner, broth, candied peel, etc.). Could be shown as an optional collapsible hint card below the step that generates the scrap.
|
||||
|
||||
## [1.7.14] - 2026-05-16
|
||||
|
||||
### Added
|
||||
- **In-app bug report form** — "Segnala un problema" now opens a modal form instead of redirecting to GitHub. Users can select type (Bug / Feature / Question), write title and description, optionally add reproduction steps. A GitHub issue is created directly with labels and app metadata attached.
|
||||
|
||||
### Fixed
|
||||
- **Kiosk settings button** — "Apri configurazione kiosk" in webapp settings was showing a toast asking to tap a gear icon that no longer exists. Now calls `openNativeSettings()` bridge directly (opens Android SettingsActivity). Fallback for old APKs shows a proper "update the kiosk app" hint.
|
||||
- **False update badge** — `manifest.json` version was `1.7.12` while the app header showed `v1.7.13`, causing the server to report an older deployed version and triggering a spurious update notification.
|
||||
- **Kiosk settings gear disappeared** — Race condition where Kotlin's `onPageFinished` injects `#_kiosk_overlay` before JS runs; JS found the element already present and returned early without ever restoring the native gear button. Fixed: JS no longer hides the native gear on load; `closeModal()` restores it with `setNativeSettingsVisible(true)`.
|
||||
- **`openNativeSettings()` fragile typeof check** — Android `@JavascriptInterface` methods are not always detected as `'function'` by typeof; replaced with try/catch.
|
||||
|
||||
## [1.7.13] - 2026-05-16
|
||||
|
||||
### Fixed
|
||||
|
||||
@@ -438,6 +438,10 @@ try {
|
||||
reportError();
|
||||
break;
|
||||
|
||||
case 'report_bug':
|
||||
reportBugManual();
|
||||
break;
|
||||
|
||||
case 'check_update':
|
||||
checkUpdate();
|
||||
break;
|
||||
@@ -6897,6 +6901,86 @@ function reportError(): void {
|
||||
echo json_encode(['ok' => true]);
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /api/?action=report_bug
|
||||
*
|
||||
* Manual bug/feature/question report submitted by the user via the in-app form.
|
||||
* Creates a GitHub issue directly with the provided title and description.
|
||||
*
|
||||
* Expected JSON body:
|
||||
* type string 'bug'|'feature'|'question'
|
||||
* title string Issue title (required, max 150 chars)
|
||||
* description string Main description (required, max 3000 chars)
|
||||
* steps string? Steps to reproduce (optional, max 2000 chars)
|
||||
* lang string? UI language the user is running
|
||||
* url string? Page URL
|
||||
* user_agent string? Navigator UA
|
||||
* version string? App version
|
||||
*/
|
||||
function reportBugManual(): void {
|
||||
$input = json_decode(file_get_contents('php://input'), true) ?: [];
|
||||
|
||||
$allowedTypes = ['bug', 'feature', 'question'];
|
||||
$type = in_array($input['type'] ?? '', $allowedTypes, true) ? $input['type'] : 'bug';
|
||||
$title = substr(trim($input['title'] ?? ''), 0, 150);
|
||||
$desc = substr(trim($input['description'] ?? ''), 0, 3000);
|
||||
$steps = substr(trim($input['steps'] ?? ''), 0, 2000);
|
||||
$ua = substr(trim($input['user_agent'] ?? ($_SERVER['HTTP_USER_AGENT'] ?? '')), 0, 300);
|
||||
$url = substr(trim($input['url'] ?? ''), 0, 300);
|
||||
$ver = substr(trim($input['version'] ?? ''), 0, 50);
|
||||
$lang = preg_replace('/[^a-z\-]/', '', strtolower($input['lang'] ?? 'it'));
|
||||
|
||||
if (empty($title) || empty($desc)) {
|
||||
echo json_encode(['ok' => false, 'error' => 'title and description required']);
|
||||
return;
|
||||
}
|
||||
|
||||
$token = _ghToken();
|
||||
if (!$token) {
|
||||
// No GitHub token configured — log locally and return ok so the UX is not broken
|
||||
_appendErrorLog('pwa', 'manual_report', $title, $desc, $url, $ua, ['type' => $type, 'version' => $ver, 'lang' => $lang]);
|
||||
echo json_encode(['ok' => true, 'issue' => null]);
|
||||
return;
|
||||
}
|
||||
|
||||
// Labels: always 'user-report' + type-specific label
|
||||
$labelMap = [
|
||||
'bug' => ['bug', 'user-report'],
|
||||
'feature' => ['enhancement', 'user-report'],
|
||||
'question' => ['question', 'user-report'],
|
||||
];
|
||||
$labels = $labelMap[$type];
|
||||
|
||||
$typeEmoji = ['bug' => '🐛', 'feature' => '💡', 'question' => '❓'][$type];
|
||||
$ts = date('Y-m-d H:i:s T');
|
||||
|
||||
$body = "## {$typeEmoji} User Report\n\n";
|
||||
$body .= "**Description:**\n{$desc}\n\n";
|
||||
if ($steps) {
|
||||
$body .= "**Steps to reproduce:**\n{$steps}\n\n";
|
||||
}
|
||||
$body .= "---\n";
|
||||
$body .= "**Version:** `{$ver}` \n";
|
||||
$body .= "**Language:** `{$lang}` \n";
|
||||
if ($url) $body .= "**URL:** `{$url}` \n";
|
||||
if ($ua) $body .= "**User-Agent:** `{$ua}` \n";
|
||||
$body .= "**Reported at:** {$ts}\n\n";
|
||||
$body .= "_This issue was submitted via the in-app bug report form._";
|
||||
|
||||
$res = _githubRequest($token, 'POST',
|
||||
'https://api.github.com/repos/' . GH_REPO . '/issues',
|
||||
['title' => $title, 'body' => $body, 'labels' => $labels]
|
||||
);
|
||||
|
||||
$issueNum = $res['body']['number'] ?? null;
|
||||
$issueUrl = $res['body']['html_url'] ?? null;
|
||||
if ($issueNum) {
|
||||
echo json_encode(['ok' => true, 'issue' => $issueNum, 'url' => $issueUrl]);
|
||||
} else {
|
||||
echo json_encode(['ok' => false, 'error' => 'github_api_error']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Append to data/error_reports.log (local safety net, max 500 KB)
|
||||
*/
|
||||
|
||||
@@ -3103,6 +3103,36 @@ body.server-offline .bottom-nav {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* ── Bug report form ── */
|
||||
.bug-type-pills {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.bug-type-pill {
|
||||
flex: 1;
|
||||
min-width: 80px;
|
||||
padding: 7px 10px;
|
||||
border: 1.5px solid #cbd5e1;
|
||||
border-radius: 20px;
|
||||
background: #fff;
|
||||
color: #475569;
|
||||
font-size: 0.88rem;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.15s, background 0.15s, color 0.15s;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
.bug-type-pill.active {
|
||||
border-color: var(--primary, #2d5016);
|
||||
background: var(--primary, #2d5016);
|
||||
color: #fff;
|
||||
font-weight: 600;
|
||||
}
|
||||
.bug-type-pill:not(.active):hover {
|
||||
border-color: var(--primary, #2d5016);
|
||||
color: var(--primary, #2d5016);
|
||||
}
|
||||
|
||||
.modal-detail {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
+130
-50
@@ -2100,51 +2100,124 @@ async function _loadAboutSection() {
|
||||
* Manually triggered bug report from the About section in Settings.
|
||||
* Collects basic info and submits via the existing report_error endpoint.
|
||||
*/
|
||||
async function reportBugManual() {
|
||||
const btn = document.getElementById('btn-report-bug');
|
||||
const statusEl = document.getElementById('report-bug-status');
|
||||
if (!btn || !statusEl) return;
|
||||
function reportBugManual() {
|
||||
const mc = document.getElementById('modal-content');
|
||||
if (!mc) return;
|
||||
|
||||
btn.disabled = true;
|
||||
mc.innerHTML = `
|
||||
<div class="modal-header">
|
||||
<h3>${t('about.report_bug_modal_title')}</h3>
|
||||
<button class="modal-close" onclick="closeModal()">✕</button>
|
||||
</div>
|
||||
<div style="padding:16px 20px 20px">
|
||||
<div style="margin-bottom:14px">
|
||||
<div class="bug-type-pills">
|
||||
<button type="button" class="bug-type-pill active" data-btype="bug">🐛 ${t('about.report_type_bug')}</button>
|
||||
<button type="button" class="bug-type-pill" data-btype="feature">💡 ${t('about.report_type_feature')}</button>
|
||||
<button type="button" class="bug-type-pill" data-btype="question">❓ ${t('about.report_type_question')}</button>
|
||||
</div>
|
||||
</div>
|
||||
<div style="margin-bottom:12px">
|
||||
<label class="settings-label" style="display:block;margin-bottom:4px">${t('about.report_field_title')} *</label>
|
||||
<input type="text" id="bug-form-title" maxlength="150" autocomplete="off"
|
||||
placeholder="${t('about.report_field_title_ph')}"
|
||||
style="width:100%;box-sizing:border-box;padding:9px 11px;border:1.5px solid #cbd5e1;border-radius:8px;font-size:0.95rem;background:#fff;color:#1e293b;outline:none">
|
||||
</div>
|
||||
<div style="margin-bottom:12px">
|
||||
<label class="settings-label" style="display:block;margin-bottom:4px">${t('about.report_field_desc')} *</label>
|
||||
<textarea id="bug-form-desc" rows="4" maxlength="3000"
|
||||
placeholder="${t('about.report_field_desc_ph')}"
|
||||
style="width:100%;box-sizing:border-box;padding:9px 11px;border:1.5px solid #cbd5e1;border-radius:8px;font-size:0.95rem;resize:vertical;background:#fff;color:#1e293b;outline:none;font-family:inherit"></textarea>
|
||||
</div>
|
||||
<div id="bug-form-steps-group" style="margin-bottom:12px">
|
||||
<label class="settings-label" style="display:block;margin-bottom:4px">${t('about.report_field_steps')}</label>
|
||||
<textarea id="bug-form-steps" rows="3" maxlength="2000"
|
||||
placeholder="${t('about.report_field_steps_ph')}"
|
||||
style="width:100%;box-sizing:border-box;padding:9px 11px;border:1.5px solid #cbd5e1;border-radius:8px;font-size:0.95rem;resize:vertical;background:#fff;color:#1e293b;outline:none;font-family:inherit"></textarea>
|
||||
</div>
|
||||
<p class="settings-hint" style="margin:0 0 14px;font-size:0.78rem">
|
||||
${t('about.report_auto_info').replace('{version}', _loadedVersion || '—').replace('{lang}', _currentLang || '—')}
|
||||
</p>
|
||||
<div style="display:flex;gap:8px;justify-content:flex-end">
|
||||
<button type="button" class="btn btn-secondary" onclick="closeModal()">${t('common.cancel') || 'Annulla'}</button>
|
||||
<button type="button" class="btn btn-primary" id="bug-form-submit" onclick="_submitBugReport()">
|
||||
${t('about.report_send_btn')}
|
||||
</button>
|
||||
</div>
|
||||
<div id="bug-form-status" style="display:none;margin-top:10px;text-align:center;font-size:0.88rem;padding:8px;border-radius:6px"></div>
|
||||
</div>
|
||||
`;
|
||||
document.getElementById('modal-overlay').style.display = 'flex';
|
||||
|
||||
// Pill click: switch type, show/hide steps field
|
||||
mc.querySelectorAll('.bug-type-pill').forEach(pill => {
|
||||
pill.addEventListener('click', () => {
|
||||
mc.querySelectorAll('.bug-type-pill').forEach(p => p.classList.remove('active'));
|
||||
pill.classList.add('active');
|
||||
const stepsGroup = document.getElementById('bug-form-steps-group');
|
||||
if (stepsGroup) stepsGroup.style.display = (pill.dataset.btype === 'bug') ? '' : 'none';
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function _submitBugReport() {
|
||||
const submitBtn = document.getElementById('bug-form-submit');
|
||||
const statusEl = document.getElementById('bug-form-status');
|
||||
const titleEl = document.getElementById('bug-form-title');
|
||||
const descEl = document.getElementById('bug-form-desc');
|
||||
const stepsEl = document.getElementById('bug-form-steps');
|
||||
const activePill = document.querySelector('#modal-content .bug-type-pill.active');
|
||||
|
||||
const title = titleEl?.value.trim() || '';
|
||||
const desc = descEl?.value.trim() || '';
|
||||
const steps = stepsEl?.value.trim() || '';
|
||||
const type = activePill?.dataset.btype || 'bug';
|
||||
|
||||
// Inline validation
|
||||
if (!title) {
|
||||
titleEl.style.borderColor = '#dc2626';
|
||||
titleEl.focus();
|
||||
return;
|
||||
}
|
||||
if (!desc) {
|
||||
descEl.style.borderColor = '#dc2626';
|
||||
descEl.focus();
|
||||
return;
|
||||
}
|
||||
|
||||
submitBtn.disabled = true;
|
||||
statusEl.style.display = '';
|
||||
statusEl.style.background = '#f1f5f9';
|
||||
statusEl.style.color = '#64748b';
|
||||
statusEl.textContent = t('about.report_bug_sending');
|
||||
|
||||
const manifest = await fetch('manifest.json?_=' + Date.now()).then(r => r.json()).catch(() => ({}));
|
||||
|
||||
try {
|
||||
const res = await fetch(API_BASE + '?action=report_error', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
source: 'pwa',
|
||||
type: 'manual_report',
|
||||
message: 'Manual bug report submitted from Settings → About',
|
||||
stack: '',
|
||||
url: location.href,
|
||||
user_agent: navigator.userAgent,
|
||||
version: manifest.version || '',
|
||||
context: {
|
||||
lang: _currentLang,
|
||||
online: navigator.onLine,
|
||||
version_guard_bypass: true,
|
||||
}
|
||||
})
|
||||
const res = await api('report_bug', null, 'POST', {
|
||||
type,
|
||||
title,
|
||||
description: desc,
|
||||
steps,
|
||||
user_agent: navigator.userAgent,
|
||||
url: location.href,
|
||||
version: _loadedVersion || '',
|
||||
lang: _currentLang || 'it',
|
||||
});
|
||||
const json = await res.json();
|
||||
if (json.ok) {
|
||||
|
||||
if (res.ok) {
|
||||
statusEl.style.background = '#dcfce7';
|
||||
statusEl.style.color = '#15803d';
|
||||
statusEl.textContent = t('about.report_bug_sent');
|
||||
// Open GitHub issues so user can add details
|
||||
setTimeout(() => window.open('https://github.com/dadaloop82/EverShelf/issues', '_blank', 'noopener'), 800);
|
||||
const issueRef = res.issue ? ` (#${res.issue})` : '';
|
||||
statusEl.textContent = t('about.report_bug_sent') + issueRef;
|
||||
submitBtn.style.display = 'none';
|
||||
setTimeout(() => closeModal(), 3500);
|
||||
} else {
|
||||
throw new Error(json.error || 'error');
|
||||
throw new Error(res.error || 'error');
|
||||
}
|
||||
} catch(e) {
|
||||
statusEl.style.background = '#fee2e2';
|
||||
statusEl.style.color = '#dc2626';
|
||||
statusEl.textContent = t('about.report_bug_error');
|
||||
} finally {
|
||||
btn.disabled = false;
|
||||
submitBtn.disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2337,6 +2410,9 @@ async function loadSettingsUI() {
|
||||
// Show kiosk self-update panel
|
||||
const updatePanel = document.getElementById('kiosk-update-panel');
|
||||
if (updatePanel) updatePanel.style.display = '';
|
||||
// Show kiosk native settings shortcut panel
|
||||
const nativePanel = document.getElementById('kiosk-native-settings-panel');
|
||||
if (nativePanel) nativePanel.style.display = '';
|
||||
}
|
||||
|
||||
// Populate About section version
|
||||
@@ -2356,6 +2432,19 @@ function _kioskReconfigureScale() {
|
||||
}
|
||||
}
|
||||
|
||||
// ── Kiosk: open native SettingsActivity (server URL, BLE, screensaver) ──
|
||||
function _openKioskNativeSettings() {
|
||||
if (typeof _kioskBridge === 'undefined') return;
|
||||
// Use try/catch directly: Android @JavascriptInterface methods are not always
|
||||
// detected as 'function' by typeof, so we just call and catch if unavailable.
|
||||
try {
|
||||
_kioskBridge.openNativeSettings();
|
||||
} catch(e) {
|
||||
// Older APK without openNativeSettings bridge — inform user to update
|
||||
showToast(t('settings.kiosk.native_update_hint') || 'Aggiorna l\'app kiosk per usare questa funzione', 'warning', 4000);
|
||||
}
|
||||
}
|
||||
|
||||
// ── Kiosk: manual update check ────────────────────────────────────────
|
||||
let _kioskPendingApkUrl = '';
|
||||
|
||||
@@ -2466,6 +2555,10 @@ function _injectKioskOverlay() {
|
||||
const appHeader = document.querySelector('.app-header');
|
||||
if (appHeader) appHeader.classList.add('kiosk-mode');
|
||||
|
||||
const btnStyle = 'background:rgba(255,255,255,0.2);border:none;color:#fff;width:34px;height:34px;border-radius:50%;font-size:15px;cursor:pointer;display:flex;align-items:center;justify-content:center;-webkit-tap-highlight-color:transparent;touch-action:manipulation;';
|
||||
|
||||
// If the Kotlin onPageFinished already injected #_kiosk_overlay (with only ✕ and ↻),
|
||||
// nothing more to do — the native Android btnSettings (top-right) opens SettingsActivity.
|
||||
if (document.getElementById('_kiosk_overlay')) return;
|
||||
|
||||
const headerLeft = document.getElementById('header-left');
|
||||
@@ -2475,8 +2568,6 @@ function _injectKioskOverlay() {
|
||||
wrap.id = '_kiosk_overlay';
|
||||
wrap.style.cssText = 'display:flex;gap:6px;align-items:center;';
|
||||
|
||||
const btnStyle = 'background:rgba(255,255,255,0.2);border:none;color:#fff;width:34px;height:34px;border-radius:50%;font-size:15px;cursor:pointer;display:flex;align-items:center;justify-content:center;-webkit-tap-highlight-color:transparent;touch-action:manipulation;';
|
||||
|
||||
// Exit button
|
||||
const exitBtn = document.createElement('button');
|
||||
exitBtn.id = '_kiosk_exit_btn';
|
||||
@@ -2499,24 +2590,13 @@ function _injectKioskOverlay() {
|
||||
_kioskBridge.hardReload();
|
||||
});
|
||||
|
||||
// Settings button — replaces the native Android settings button
|
||||
const settBtn = document.createElement('button');
|
||||
settBtn.id = '_kiosk_settings_btn';
|
||||
settBtn.textContent = '\u2699\uFE0F';
|
||||
settBtn.title = t('settings.title') || 'Settings';
|
||||
settBtn.style.cssText = btnStyle.replace('font-size:15px', 'font-size:16px');
|
||||
settBtn.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
showPage('settings');
|
||||
});
|
||||
// NOTE: No ⚙️ button here — the native Android settings button (top-right, injected by
|
||||
// Kotlin) opens SettingsActivity (server URL, BLE scale, screensaver). Do NOT call
|
||||
// setNativeSettingsVisible(false) — that would hide the only way to reconfigure the kiosk.
|
||||
|
||||
wrap.appendChild(exitBtn);
|
||||
wrap.appendChild(refBtn);
|
||||
wrap.appendChild(settBtn);
|
||||
headerLeft.appendChild(wrap);
|
||||
|
||||
// Permanently hide the native Android settings button — replaced by the web overlay button above.
|
||||
try { _kioskBridge.setNativeSettingsVisible(false); } catch(_) {}
|
||||
}
|
||||
|
||||
function renderAppliances(appliances) {
|
||||
@@ -4910,8 +4990,8 @@ function showItemDetail(inventoryId, productId) {
|
||||
function closeModal() {
|
||||
document.getElementById('modal-overlay').style.display = 'none';
|
||||
clearMoveModalTimer();
|
||||
// Native kiosk settings button is permanently replaced by the web overlay button — keep hidden.
|
||||
try { if (typeof _kioskBridge !== 'undefined') _kioskBridge.setNativeSettingsVisible(false); } catch (_) {}
|
||||
// Restore the native kiosk settings button when the modal closes.
|
||||
try { if (typeof _kioskBridge !== 'undefined') _kioskBridge.setNativeSettingsVisible(true); } catch (_) {}
|
||||
_cancelScaleAutoConfirm(false);
|
||||
_scaleRecipeAutoFillPaused = false;
|
||||
_scaleUserDismissed = false;
|
||||
|
||||
@@ -11,8 +11,8 @@ android {
|
||||
applicationId = "it.dadaloop.evershelf.kiosk"
|
||||
minSdk = 24
|
||||
targetSdk = 34
|
||||
versionCode = 14
|
||||
versionName = "1.7.13"
|
||||
versionCode = 15
|
||||
versionName = "1.7.14"
|
||||
}
|
||||
|
||||
signingConfigs {
|
||||
|
||||
@@ -515,6 +515,17 @@ class KioskActivity : AppCompatActivity() {
|
||||
btnSettings.visibility = if (visible) View.VISIBLE else View.GONE
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Open the native SettingsActivity from the webapp settings page.
|
||||
* Allows configuring server URL, BLE scale and screensaver without
|
||||
* the user having to find the native gear button.
|
||||
*/
|
||||
@JavascriptInterface
|
||||
fun openNativeSettings() {
|
||||
runOnUiThread {
|
||||
startActivity(Intent(this@KioskActivity, SettingsActivity::class.java))
|
||||
}
|
||||
}
|
||||
}, "_kioskBridge")
|
||||
|
||||
val url = prefs.getString(KEY_URL, "http://evershelf.local") ?: "http://evershelf.local"
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
android.useAndroidX=true
|
||||
android.enableJetifier=true
|
||||
# Build trigger: versionName 1.7.13 fix (8d87494)
|
||||
# Build trigger: TTS bridge fix (95389eb)
|
||||
# Build trigger: v1.7.14 with openNativeSettings fix (834d8ef)
|
||||
|
||||
+16
-5
@@ -11,7 +11,7 @@
|
||||
<title>EverShelf</title>
|
||||
<link rel="manifest" href="manifest.json">
|
||||
<link rel="icon" type="image/png" href="assets/img/logo/logo_icon.png">
|
||||
<link rel="stylesheet" href="assets/css/style.css?v=20260513a">
|
||||
<link rel="stylesheet" href="assets/css/style.css?v=20260516a">
|
||||
<!-- QuaggaJS for barcode scanning -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/@ericblade/quagga2@1.8.4/dist/quagga.min.js"></script>
|
||||
<!-- @xenova/transformers: ES-module bootstrap that exposes a lazy category-classifier as window._categoryPipelinePromise -->
|
||||
@@ -67,7 +67,7 @@
|
||||
<!-- Title — left-aligned; grows to fill space -->
|
||||
<div class="header-title-wrap">
|
||||
<h1 class="header-title" onclick="showPage('dashboard')">
|
||||
<img src="assets/img/logo/logo_icon.png" alt="" class="header-logo-icon" aria-hidden="true" /><span data-i18n="nav.title">EverShelf</span><span class="header-version">v1.7.13</span>
|
||||
<img src="assets/img/logo/logo_icon.png" alt="" class="header-logo-icon" aria-hidden="true" /><span data-i18n="nav.title">EverShelf</span><span class="header-version">v1.7.14</span>
|
||||
</h1>
|
||||
<!-- Update badge — shown alongside title, never replaces it -->
|
||||
<span class="header-update-badge" id="header-update-badge" style="display:none"></span>
|
||||
@@ -1302,6 +1302,18 @@
|
||||
<p class="settings-hint" style="margin-top:8px" data-i18n="settings.kiosk.download_sub">Modalità kiosk full-screen + gateway bilancia integrato. Sorgente: <code>evershelf-kiosk/</code></p>
|
||||
</div>
|
||||
|
||||
<!-- Kiosk native settings panel (visible only inside kiosk WebView) -->
|
||||
<div id="kiosk-native-settings-panel" style="display:none;background:rgba(99,102,241,0.06);border:1.5px solid rgba(99,102,241,0.2);border-radius:12px;padding:16px;margin-top:16px">
|
||||
<div style="display:flex;align-items:center;gap:10px;margin-bottom:10px">
|
||||
<span style="font-size:1.4rem">🖥️</span>
|
||||
<div>
|
||||
<p style="margin:0;font-weight:700;font-size:0.9rem" data-i18n="settings.kiosk.native_title">Configurazione Kiosk</p>
|
||||
<p class="settings-hint" style="margin:2px 0 0" data-i18n="settings.kiosk.native_hint">URL server, bilancia BLE, salvaschermo e setup wizard.</p>
|
||||
</div>
|
||||
</div>
|
||||
<button class="btn btn-secondary full-width" onclick="_openKioskNativeSettings()">⚙️ <span data-i18n="settings.kiosk.native_btn">Apri configurazione kiosk</span></button>
|
||||
</div>
|
||||
|
||||
<!-- Kiosk self-update panel (visible only inside kiosk WebView) -->
|
||||
<div id="kiosk-update-panel" style="display:none;background:rgba(16,185,129,0.06);border:1.5px solid rgba(16,185,129,0.2);border-radius:12px;padding:16px;margin-top:16px">
|
||||
<div style="display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:10px">
|
||||
@@ -1332,7 +1344,7 @@
|
||||
<button class="btn btn-outline full-width" onclick="reportBugManual()" id="btn-report-bug">
|
||||
🐛 <span data-i18n="about.report_bug">Segnala un problema</span>
|
||||
</button>
|
||||
<p class="settings-hint" style="text-align:center;margin:0" data-i18n="about.report_bug_hint">Qualcosa non funziona? Apri una segnalazione su GitHub.</p>
|
||||
<p class="settings-hint" style="text-align:center;margin:0" data-i18n="about.report_bug_hint">Qualcosa non funziona? Inviaci una segnalazione direttamente dall'app.</p>
|
||||
<div style="display:flex;gap:8px">
|
||||
<a class="btn btn-outline full-width" style="text-decoration:none;text-align:center"
|
||||
href="https://github.com/dadaloop82/EverShelf/blob/main/CHANGELOG.md"
|
||||
@@ -1342,7 +1354,6 @@
|
||||
target="_blank" rel="noopener" data-i18n="about.github">GitHub</a>
|
||||
</div>
|
||||
</div>
|
||||
<div id="report-bug-status" style="display:none;margin-top:8px;text-align:center;font-size:0.85rem"></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -1548,6 +1559,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="assets/js/app.js?v=20260513a"></script>
|
||||
<script src="assets/js/app.js?v=20260516a"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
"name": "EverShelf",
|
||||
"short_name": "EverShelf",
|
||||
"description": "Gestione completa della dispensa di casa con scansione barcode",
|
||||
"version": "1.7.12",
|
||||
"version": "1.7.14",
|
||||
"start_url": "/evershelf/",
|
||||
"display": "standalone",
|
||||
"background_color": "#f0f4e8",
|
||||
|
||||
+19
-2
@@ -677,7 +677,12 @@
|
||||
"kiosk": {
|
||||
"hint": "Verwandeln Sie ein Android-Tablet in ein EverShelf-Panel mit integriertem BLE-Waagen-Gateway.",
|
||||
"download_btn": "📥 EverShelf Kiosk herunterladen (APK)",
|
||||
"download_sub": "Vollbild-Kioskmodus + integriertes Waagen-Gateway. Quellcode: evershelf-kiosk/"
|
||||
"download_sub": "Vollbild-Kioskmodus + integriertes Waagen-Gateway. Quellcode: evershelf-kiosk/",
|
||||
"native_title": "Kiosk-Konfiguration",
|
||||
"native_hint": "Server-URL, BLE-Waage, Bildschirmschoner und Einrichtungsassistent.",
|
||||
"native_btn": "Kiosk-Konfiguration öffnen",
|
||||
"native_tap_hint": "Zahnrad oben rechts antippen",
|
||||
"native_update_hint": "Kiosk-App aktualisieren, um diese Funktion zu nutzen"
|
||||
},
|
||||
"saved": "✅ Konfiguration gespeichert!",
|
||||
"saved_local": "✅ Konfiguration lokal gespeichert",
|
||||
@@ -1092,7 +1097,19 @@
|
||||
"title": "Über",
|
||||
"version": "Version",
|
||||
"report_bug": "Fehler melden",
|
||||
"report_bug_hint": "Etwas funktioniert nicht? Öffne ein Issue auf GitHub.",
|
||||
"report_bug_hint": "Etwas funktioniert nicht? Sende uns direkt aus der App eine Meldung.",
|
||||
"report_bug_modal_title": "Fehler melden",
|
||||
"report_type_bug": "Fehler",
|
||||
"report_type_feature": "Funktion",
|
||||
"report_type_question": "Frage",
|
||||
"report_field_title": "Titel",
|
||||
"report_field_title_ph": "Kurze Beschreibung des Problems",
|
||||
"report_field_desc": "Beschreibung",
|
||||
"report_field_desc_ph": "Problem detailliert beschreiben…",
|
||||
"report_field_steps": "Schritte zum Reproduzieren (optional)",
|
||||
"report_field_steps_ph": "1. Gehe zu…\n2. Tippe auf…\n3. Fehler erscheint…",
|
||||
"report_auto_info": "Automatisch beigefügt: Version {version}, Sprache {lang}.",
|
||||
"report_send_btn": "Bericht senden",
|
||||
"report_bug_sending": "Wird gesendet…",
|
||||
"report_bug_sent": "Bericht gesendet — danke!",
|
||||
"report_bug_error": "Bericht konnte nicht gesendet werden. Verbindung prüfen.",
|
||||
|
||||
+19
-2
@@ -677,7 +677,12 @@
|
||||
"kiosk": {
|
||||
"hint": "Turn an Android tablet into an always-on EverShelf panel with built-in BLE scale gateway.",
|
||||
"download_btn": "📥 Download EverShelf Kiosk (APK)",
|
||||
"download_sub": "Full-screen kiosk mode + integrated scale gateway. Source: evershelf-kiosk/"
|
||||
"download_sub": "Full-screen kiosk mode + integrated scale gateway. Source: evershelf-kiosk/",
|
||||
"native_title": "Kiosk Configuration",
|
||||
"native_hint": "Server URL, BLE scale, screensaver and setup wizard.",
|
||||
"native_btn": "Open kiosk configuration",
|
||||
"native_tap_hint": "Tap the gear button at the top right",
|
||||
"native_update_hint": "Update the kiosk app to use this feature"
|
||||
},
|
||||
"saved": "✅ Configuration saved!",
|
||||
"saved_local": "✅ Configuration saved locally",
|
||||
@@ -1092,7 +1097,19 @@
|
||||
"title": "About",
|
||||
"version": "Version",
|
||||
"report_bug": "Report a Bug",
|
||||
"report_bug_hint": "Something not working? Open an issue on GitHub.",
|
||||
"report_bug_hint": "Something not working? Send us a report directly from the app.",
|
||||
"report_bug_modal_title": "Report a Bug",
|
||||
"report_type_bug": "Bug",
|
||||
"report_type_feature": "Feature",
|
||||
"report_type_question": "Question",
|
||||
"report_field_title": "Title",
|
||||
"report_field_title_ph": "Brief description of the issue",
|
||||
"report_field_desc": "Description",
|
||||
"report_field_desc_ph": "Describe the issue in detail…",
|
||||
"report_field_steps": "Steps to reproduce (optional)",
|
||||
"report_field_steps_ph": "1. Go to…\n2. Tap…\n3. See the error…",
|
||||
"report_auto_info": "Automatically attached: version {version}, language {lang}.",
|
||||
"report_send_btn": "Send report",
|
||||
"report_bug_sending": "Sending…",
|
||||
"report_bug_sent": "Report sent — thank you!",
|
||||
"report_bug_error": "Could not send the report. Check your connection.",
|
||||
|
||||
+19
-2
@@ -677,7 +677,12 @@
|
||||
"kiosk": {
|
||||
"hint": "Trasforma un tablet Android in un pannello EverShelf sempre acceso, con bilancia BLE integrata.",
|
||||
"download_btn": "📥 Scarica EverShelf Kiosk (APK)",
|
||||
"download_sub": "Modalità kiosk full-screen + gateway bilancia integrato. Sorgente: evershelf-kiosk/"
|
||||
"download_sub": "Modalità kiosk full-screen + gateway bilancia integrato. Sorgente: evershelf-kiosk/",
|
||||
"native_title": "Configurazione Kiosk",
|
||||
"native_hint": "URL server, bilancia BLE, salvaschermo e setup wizard.",
|
||||
"native_btn": "Apri configurazione kiosk",
|
||||
"native_tap_hint": "Tocca la rotella in alto a destra",
|
||||
"native_update_hint": "Aggiorna l'app kiosk per usare questa funzione"
|
||||
},
|
||||
"saved": "✅ Configurazione salvata!",
|
||||
"saved_local": "✅ Configurazione salvata localmente",
|
||||
@@ -1092,7 +1097,19 @@
|
||||
"title": "Informazioni",
|
||||
"version": "Versione",
|
||||
"report_bug": "Segnala un problema",
|
||||
"report_bug_hint": "Qualcosa non funziona? Apri una segnalazione su GitHub.",
|
||||
"report_bug_hint": "Qualcosa non funziona? Inviaci una segnalazione direttamente dall'app.",
|
||||
"report_bug_modal_title": "Segnala un problema",
|
||||
"report_type_bug": "Bug",
|
||||
"report_type_feature": "Funzionalità",
|
||||
"report_type_question": "Domanda",
|
||||
"report_field_title": "Titolo",
|
||||
"report_field_title_ph": "Breve descrizione del problema",
|
||||
"report_field_desc": "Descrizione",
|
||||
"report_field_desc_ph": "Descrivi il problema in dettaglio…",
|
||||
"report_field_steps": "Passi per riprodurlo (opzionale)",
|
||||
"report_field_steps_ph": "1. Vai su…\n2. Tocca…\n3. Vedi l'errore…",
|
||||
"report_auto_info": "Saranno allegati automaticamente: versione {version}, lingua {lang}.",
|
||||
"report_send_btn": "Invia segnalazione",
|
||||
"report_bug_sending": "Invio in corso…",
|
||||
"report_bug_sent": "Segnalazione inviata — grazie!",
|
||||
"report_bug_error": "Impossibile inviare la segnalazione. Controlla la connessione.",
|
||||
|
||||
Reference in New Issue
Block a user