diff --git a/ROADMAP.md b/ROADMAP.md index 7a74e35..7ab9c38 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -31,6 +31,21 @@ Bericht-Moduls. --- +## 7. Galerie-Auswahl: „permission"-Fehler ab dem 3. Foto (gemeldet 2026-09-30) + +Befund (Prod-Zugriffslog 30.09., Auftrag 114 / SO2609-0088, JHB Bio): erster Anlauf 19:40:21 — +**nur 2** `upload_photo`-POSTs, danach rote Toasts mit „permission". Der Server hat die übrigen +Fotos nie gesehen; zweiter Anlauf 19:41:48 lief mit 8 POSTs durch. Ursache: `handleFiles()` +las jedes Foto erst, nachdem das vorige hochgeladen war. Chrome/Android gibt die Galerie-Dateien +nur kurz frei (bzw. prüft, ob sie seit der Auswahl verändert wurden) → `NotReadableError` +(„could not be read, typically due to permission problems…"). Die betroffenen Fotos landeten +nicht in der Queue. + +- [x] Fix (lokal, noch nicht deployed): erst **alle** Dateien sofort in den Speicher lesen + (`readFileNow`, ein Wiederholversuch nach 500 ms), dann hochladen. Unlesbare Datei → + klare Meldung „bitte nochmal auswählen". +- [ ] Am Handy gegenprüfen: 8–10 Fotos aus der Galerie auf einmal auswählen. + ## 6. Rauswurf aus dem Auftrag + unsichtbare Warteschlange (gemeldet 2026-09-18) Gemeldet von Eddy: am 17.09.2026 gegen 18 Uhr mehrere Fotos in einem Auftrag gemacht, diff --git a/app.js b/app.js index 73386c2..bf4c9db 100644 --- a/app.js +++ b/app.js @@ -1092,7 +1092,21 @@ router.on('/orders/:id', async (args) => { // das Verkleinern mitten in der Serie (siehe resizeImage). await offline.acquireWakeLock(); try { - for (const f of files) { + // ERST ALLE Bilder einlesen, DANN hochladen. Die Datei-Referenzen aus der + // Galerie-Auswahl sind unter Android nur kurz lesbar: frueher wurde Foto 3 + // erst gelesen, nachdem Foto 1 und 2 schon hochgeladen waren — da warf Chrome + // "NotReadableError: ... could not be read, typically due to permission + // problems ..." und die restliche Auswahl kam nie an (30.09.2026, JHB Bio, + // Prod-Log: nur 2 upload_photo-POSTs). Eine File aus dem Speicher bleibt lesbar. + const copies = []; + for (const f of Array.from(files)) { + try { + copies.push(await readFileNow(f)); + } catch (e) { + showToast('Foto ' + (f.name || '') + ' konnte nicht gelesen werden — bitte nochmal auswählen', 'error'); + } + } + for (const f of copies) { // Ein einzelnes Foto darf die restliche Auswahl nicht blockieren try { await uploadPhoto(args.id, f); @@ -1242,6 +1256,21 @@ async function refreshPhotoConfig() { } catch (_) { /* offline o.ae. — der zwischengespeicherte Wert gilt weiter */ } } +/* Eine ausgewaehlte Datei sofort komplett in den Speicher holen (siehe handleFiles). + * Ein Fehlversuch wird einmal wiederholt — frisch aufgenommene Fotos schreibt die + * Galerie-App teils noch nach, dann klappt der zweite Lesezugriff. */ +async function readFileNow(f) { + let buf; + try { + buf = await f.arrayBuffer(); + } catch (_) { + await new Promise(r => setTimeout(r, 500)); + buf = await f.arrayBuffer(); + } + return new File([buf], f.name || ('foto_' + Date.now() + '.jpg'), + { type: f.type || 'image/jpeg', lastModified: f.lastModified || Date.now() }); +} + async function uploadPhoto(orderId, file) { // Persist-First, streng: das Foto geht UNVERAENDERT und als ALLERERSTES in die // Queue. Frueher wurde davor verkleinert — und weil das Verkleinern bei