diff --git a/AGENTS.md b/AGENTS.md index 6cea913..a3e5c0a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -23,7 +23,13 @@ intended 96x96 square, moved the "Montiert" pill to match, added `color-scheme` popups stop rendering in the browser's default light palette against the dark app, root-caused and fixed a JS crash in the "Mein Audi" image-cycle click handler, merged the separate "Fahrzeugbilder" upload grid into "Bild der Übersicht" (pick a view, tap its photo to upload), and turned the back -arrow from red to the neutral headline color — see section C). This file is the entry point for every new agent +arrow from red to the neutral headline color; a tenth round the same day ran a real full Apple HIG +audit (Navigation/Presentation/Selection & Input/Patterns categories, not just the sixth round's +5-page pass) and fixed the three findings that survived: closed a second, larger silent-failure gap +in `profilSpeichern()` itself (the shared save path for ~25 fields, previously an unhandled promise +rejection with zero user feedback), added a spinner to the "Lädt …" bootstrap screen, and gave the +Anzugsmoment/km-correction popups the same primary-button styling the Setup popup already used — +see section C). This file is the entry point for every new agent session: what this repo is, what is finished, what is missing, and how to work here. Detail lives in the linked documents — this file points, it does not duplicate. @@ -1082,6 +1088,44 @@ wraps the web app for iPhone; a PWA home-screen install is the accepted intermed confirmed the pyscript service ran via the container's HA log, then did a full page reload (forces a real backend re-fetch, not just optimistic local UI state) and the corrected value was still there. +- [x] Tenth round the same day (2026-08-16) — a real full Apple HIG audit, not just the sixth + round's 5-page pass: read Tab Bars, Sidebars, Sheets, Alerts, Action Sheets, Toolbars/ + Navigation Bars, Buttons, Pickers, Loading, Feedback, Privacy, and Undo/Redo directly off + developer.apple.com and cross-checked each against the actual code (not just CSS) — most of + the app already held up (5-tab bar, destructive-button placement, 44pt tap targets, + `prefers-reduced-motion` support, confirm-sheet button ordering all already correct). Three + real findings surfaced, all fixed and user-approved via `AskUserQuestion` before implementing: + (1) **A second, larger silent-failure gap than the one already fixed for receipt upload.** + `profilSpeichern()` — the shared save path for roughly 25 editable fields across the app + (Anzugsmoment, service book, SmartDeal, tax, insurance, oil change, pause time, backup + interval, start image, ...) — was `async` with no `try`/`catch` at any of its ~25 call sites, + so a failed backend write was an unhandled promise rejection with zero user feedback; the + popup had already closed and the UI already updated optimistically, so the change looked + saved when it silently wasn't. Wrapped the one call inside `profilSpeichern()` itself in + `try`/`catch`, reusing the existing `hinweis()` error-sheet pattern — one central fix instead + of ~25 call-site patches. `serviceRufen()` (the separate wrapper used by km-correction, manual + trip/fuel entry, tire-set switching, deletions, restart, ...) got the identical treatment. + Verified live by monkey-patching `hass.callService` to reject inside the running app (via + `host.hass.callService = () => Promise.reject(...)`), then triggering a real Anzugsmoment save + through the actual UI: before the fix, the popup silently closed with a stale "Uncaught (in + promise)" console entry and no user-visible sign anything went wrong; after the fix, a + "Speichern fehlgeschlagen" sheet appears with the real error text. A follow-up full reload + confirmed the failed test write never reached the backend (value reverted to the real stored + 120 Nm) — the fix only adds feedback, it doesn't change persistence behavior. + (2) **"Lädt …" bootstrap screen got a progress indicator** (new `.lade-spinner` CSS, a plain + rotating ring) instead of bare static text, per HIG Loading guidance to show something moving + while content loads — notable here because this exact screen has a documented history of + genuinely hanging, so a spinner also helps a user tell "still loading" apart from "stuck". + Respects the existing global `prefers-reduced-motion` override (`*, *::before, *::after` + block already forces `animation-duration:.01ms` app-wide) with no extra code. + (3) **Anzugsmoment and km-correction popups now use `.aktion.primaer` on Speichern**, matching + the Setup and SmartDeal popups, which already distinguished their primary action — these two + were the only popups in the app stacking two visually-identical plain buttons. + All three verified live in `audi_ha_test` (version `1786916894`): spinner CSS confirmed via + `getComputedStyle` (16×16px, `border-radius:50%`, `animation-name:lade-spin`) since a genuine + race-condition-timed screenshot proved too fast to catch reliably; Speichern/Abbrechen + hierarchy confirmed via screenshot on both popups; error-sheet fix confirmed via the + monkey-patch test above. Synced to `installationspaket/`. - [ ] Fix remaining documentation drift (statistics claim, README gaps, obsolete TODO comment) — text-only changes; INSTALL.md's WLAN/TommiG1 drift and stale variable names were fixed 2026-08-12 (see section B); `DESIGN_REVIEW_2026-08-13.md` and `REVIEW_main_2026-08-13.md` diff --git a/homeassistant/installationspaket/www/audi-dashboard-app.js b/homeassistant/installationspaket/www/audi-dashboard-app.js index 8f479e1..852312b 100644 --- a/homeassistant/installationspaket/www/audi-dashboard-app.js +++ b/homeassistant/installationspaket/www/audi-dashboard-app.js @@ -189,7 +189,17 @@ let PROFIL_ROH = null; // letzter vom Backend gelesener Rohstand, für configCar async function profilSpeichern() { const neuesProfil = configCarZuProfil(PROFIL_ROH); PROFIL_ROH = neuesProfil; - await HASS.callService("pyscript", "audi_dashboard_profil_schreiben", { profil_json: JSON.stringify(neuesProfil) }); + // HIG "Feedback": profilSpeichern() ist der Speicherpfad fuer praktisch + // jedes editierbare Feld im Panel (~25 Aufrufstellen) und wurde bisher an + // keiner davon awaited oder abgefangen - ein Fehlschlag war eine unhandled + // promise rejection ohne jede Rueckmeldung. Zentral hier gefangen, aus + // demselben Grund wie serviceRufen() weiter unten. + try { + await HASS.callService("pyscript", "audi_dashboard_profil_schreiben", { profil_json: JSON.stringify(neuesProfil) }); + } catch (err) { + console.error("audi_dashboard: profilSpeichern", err); + hinweis("Speichern fehlgeschlagen", err && err.message ? err.message : "Die Änderung konnte nicht gespeichert werden."); + } } /* ------------------------------------------------------------- Bilder @@ -2376,7 +2386,7 @@ function vReifen() { text-transform:none;font-size:12.5px;line-height:1.6"> Korrigiert nur den bisher gefahrenen Stand - weitere Fahrten mit diesem Satz zählen ab hier weiter dazu. - + ` : ""} @@ -2415,7 +2425,7 @@ function vReifen() {