fix: APK install conflict (PackageInstaller) + dashboard stat skeleton

APK install conflict:
- Replace ACTION_VIEW-based install with PackageInstaller.Session API (API 21+)
- PackageInstaller gives us the actual install status via BroadcastReceiver:
  STATUS_PENDING_USER_ACTION → launch system confirmation dialog automatically
  STATUS_SUCCESS → success toast
  STATUS_FAILURE_CONFLICT/INCOMPATIBLE → show AlertDialog offering to
    uninstall the old version (ACTION_DELETE) so user can re-download and install
- FileProvider no longer needed for install (still kept for other uses)
- Kiosk: derive target package from filename (gateway vs kiosk self-update)

Dashboard 0-flash:
- Replace hardcoded 0 in HTML stat-value spans with ... placeholder
- Add .stat-loading CSS class: shimmer skeleton animation (gradient sweep)
- showPage(dashboard): set ... + stat-loading before API call
- loadDashboard: remove stat-loading class and set real count after data arrives
This commit is contained in:
dadaloop82
2026-05-03 17:51:18 +00:00
parent 58e69625bd
commit 73fbb73974
5 changed files with 179 additions and 30 deletions
+15
View File
@@ -372,6 +372,21 @@ body {
color: var(--primary);
}
/* Skeleton pulse while stat is loading */
.stat-value.stat-loading {
color: transparent;
background: linear-gradient(90deg, var(--border) 25%, var(--bg-dark, #e2e8f0) 50%, var(--border) 75%);
background-size: 200% 100%;
animation: stat-shimmer 1.2s infinite;
border-radius: 6px;
min-width: 2rem;
display: inline-block;
}
@keyframes stat-shimmer {
0% { background-position: 200% 0; }
100% { background-position: -200% 0; }
}
.stat-label {
font-size: 0.85rem;
color: var(--text-light);
+11 -2
View File
@@ -2227,7 +2227,14 @@ function showPage(pageId, param = null) {
// Page-specific init
switch(pageId) {
case 'dashboard': loadDashboard(); break;
case 'dashboard':
// Show skeleton on stat-cards while data loads
['dispensa', 'frigo', 'freezer'].forEach(loc => {
const el = document.getElementById(`stat-${loc}`);
if (el) { el.textContent = '…'; el.classList.add('stat-loading'); }
});
loadDashboard();
break;
case 'inventory':
if (param !== null) {
currentLocation = param;
@@ -2643,7 +2650,9 @@ async function loadDashboard() {
['dispensa', 'frigo', 'freezer'].forEach(loc => {
const s = summary.find(x => x.location === loc);
const count = s ? s.product_count : 0;
document.getElementById(`stat-${loc}`).textContent = count;
const el = document.getElementById(`stat-${loc}`);
el.textContent = count;
el.classList.remove('stat-loading');
total += count;
});
// Add non-standard locations