Fix pull-to-refresh on touch devices, add drag/paste receipt upload

The pull-to-refresh gesture logic was already correct (verified by driving
real pointer events through it); what was missing was overscroll-behavior
on the scroll container, so on real touch hardware the browser's own
native overscroll could take the gesture over before it hit the threshold.

"Beleg hochladen" now opens a dialog instead of the native file picker:
drag a PDF in at the computer, paste it from the clipboard on the phone
(copied out of a mail), file picker kept as a third route. All three
sources share one upload path.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
2026-08-17 00:29:05 +02:00
co-authored by Claude Sonnet 5
parent 8a751fe441
commit 5aaf1cd958
9 changed files with 374 additions and 55 deletions
+46 -3
View File
@@ -1,6 +1,6 @@
# AGENTS.md — Project state, review findings, open items, and working rules
**Last updated: 2026-08-16** (merged the `umsetzung-datametric360` branch — companion app phases
**Last updated: 2026-08-17** (merged the `umsetzung-datametric360` branch — companion app phases
110 done, see `UMSETZUNGSPLAN.md`; 2026-08-13: cleaned up remaining EU Data Act residue, fixed
oversized toggle switches, and fixed a desktop-layout audit (settings button / rings logo / popups
overflowing past the capped content column) — see `DESIGN_AUDIT_2026-08-13.md`; 2026-08-16: fixed
@@ -28,8 +28,13 @@ audit (Navigation/Presentation/Selection & Input/Patterns categories, not just t
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
Anzugsmoment/km-correction popups the same primary-button styling the Setup popup already used;
2026-08-17: fixed pull-to-refresh on Übersicht not working — the JS gesture logic was already
correct (verified via live pointer-event simulation), the real gap was a missing
`overscroll-behavior` on the scroll container letting the browser's own native overscroll compete
with it on real touch devices; same day: the fuel-receipt upload got a proper dialog — drag the PDF
in at the computer, paste it from the clipboard on the phone, file picker still available as a third
route — 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.
@@ -1126,6 +1131,44 @@ wraps the web app for iPhone; a PWA home-screen install is the accepted intermed
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/`.
- [x] Eleventh round (2026-08-17) — "why can't I pull to refresh on Übersicht", investigated as a
real bug report rather than assumed working: live-tested the gesture by dispatching real
`PointerEvent`s through the exact `pointerdown`/`pointermove`/`pointerup` handlers in
`ereignisseVerdrahten()` (the `ptrY0`/`ptrDrag` logic) — every step fired correctly (drag
threshold, "Loslassen zum Aktualisieren" label swap, spinner, `datenAktualisieren()` call,
collapse), so the app's own JS/CSS was never the defect. Root cause instead: `main#view` (the
actual scroll container) had no `overscroll-behavior` set at all, so on a **real** touchscreen
the browser's own native overscroll/pull gesture can intercept or compete with the custom drag
before it reaches the threshold — this can't reproduce via desktop testing or synthetic pointer
events, only real touch hardware, which is exactly why the live test above passed while the
user's real phone didn't work. Fixed with `overscroll-behavior-y: contain` on `main#view` plus
`overscroll-behavior: none` on the outer `:host > div` wrapper, so a gesture leaving `main#view`
never chains up into the underlying Home Assistant page either. Re-ran the same synthetic
pointer-event test after deploying — gesture still fires identically end-to-end, confirmed via
`getComputedStyle` that `overscroll-behavior-y` computes to `contain`; no visual regressions,
no new console errors. Synced to `installationspaket/`. Not yet confirmed fixed on the user's
actual device — the code-level fix is the standard remedy for this exact symptom class, but ask
if it's still reproducing before assuming this is fully closed.
- [x] Beleg-Upload: Ziehen und Einfügen (2026-08-17) — "Beleg hochladen" opened the native file
picker directly, which is the wrong affordance for both of the user's actual routes: at the
computer the PDF should be draggable in, on the phone it arrives as a PDF copied out of a mail
and needs pasting. Replaced the immediate picker with a small dialog (`belegPopup` state,
`vBelegPopup()`, rendered into the existing `#overlay` alongside `sheetMarkup()`/
`vSetupPopup()`): a dashed drop area plus "Aus Zwischenablage einfügen" and "Datei auswählen"
(the old path, kept as the third route). The upload itself was extracted out of the click
handler into `belegDateiVerarbeiten()` so all three sources share one code path — including the
deliberate non-`serviceRufen()` error handling whose reasoning is unchanged (see its comment).
Notes worth keeping: `dragover` **must** `preventDefault()` or the browser just opens the PDF
itself and no `drop` ever fires; the drag/drop/paste listeners hang on `document`, not on the
drop zone, because the zone lives in the shadow DOM and a drag crossing its edge would
otherwise be lost — and because `render()` replaces the overlay's `innerHTML`, so per-element
listeners wouldn't survive. Phone pasting uses `navigator.clipboard.read()` (iOS shows its own
paste prompt) with the keyboard `paste` event as the desktop path. Non-PDFs are rejected with
an in-dialog message instead of being uploaded. Verified live in `audi_ha_test` by
instrumenting `hass.callService` and driving real `DragEvent`/`ClipboardEvent`/`KeyboardEvent`s:
drop → zone highlights (`darueber`), dialog closes, service called with the right filename and
base64 payload; paste → same; a dropped PNG → "Das war kein PDF." and no service call; Escape →
closes. 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`