perf(mangel): Foto-Kompression vor Upload in beiden Clients ergänzt
PWA lud Mangel-Fotos bislang komplett unkomprimiert hoch (rohes File aus capture-Input) - Canvas-basierte Verkleinerung/Neukodierung (max. 1600px, JPEG q0.7) vor dem Enqueue ergänzt. Flutter-Client nutzte nur imageQuality (reine JPEG-Kompression ohne Auflösungs-Downscale) - maxWidth/maxHeight ergänzt. Beides zahlt sich bei schlechter Feld-Verbindung aus. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VDMvneg6wKfXdXvTYNd3dN
This commit is contained in:
1 parent
ecca012197
commit
c8d9480cf9
4 files changed
+254
-2
No files matched your search
@@ -14795,3 +14795,207 @@ Keine Commits in dieser Session.
|
||||
- frontend/DEVLOG.md | 387 ++++++++++++
|
||||
|
||||
---
|
||||
## 2026-09-12 22:01 – 22:11 (9m)
|
||||
**Beschreibung:** Claude Code Session
|
||||
**Projekt:** asb-material
|
||||
|
||||
### Commits
|
||||
- ecca012 fix(flutter): Sync-Abbruch-Bug in Offline-Queues behoben, API-URL konfigurierbar
|
||||
|
||||
### Geänderte Dateien
|
||||
- DEVLOG.md | 144 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
- arbeitskacheln/15_mobile.md | 12 +++++++
|
||||
- flutter_app/lib/main.dart | 12 ++++---
|
||||
- flutter_app/lib/offline/mangel_queue.dart | 14 +++++++-
|
||||
- flutter_app/lib/offline/queue.dart | 20 ++++++++++-
|
||||
- flutter_app/test/mangel_queue_test.dart | 143 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
- flutter_app/test/offline_queue_test.dart | 6 ++++
|
||||
|
||||
---
|
||||
## 2026-09-12 22:12 – 22:12 (0m)
|
||||
**Beschreibung:** Claude Code Session
|
||||
**Projekt:** asb-material
|
||||
|
||||
### Commits
|
||||
Keine Commits in dieser Session.
|
||||
|
||||
### Geänderte Dateien
|
||||
- DEVLOG.md | 144 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
- arbeitskacheln/15_mobile.md | 12 +++++++
|
||||
- flutter_app/lib/main.dart | 12 ++++---
|
||||
- flutter_app/lib/offline/mangel_queue.dart | 14 +++++++-
|
||||
- flutter_app/lib/offline/queue.dart | 20 ++++++++++-
|
||||
- flutter_app/test/mangel_queue_test.dart | 143 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
- flutter_app/test/offline_queue_test.dart | 6 ++++
|
||||
|
||||
---
|
||||
## 2026-09-12 22:14 – 22:15 (0m)
|
||||
**Beschreibung:** Claude Code Session
|
||||
**Projekt:** asb-material
|
||||
|
||||
### Commits
|
||||
Keine Commits in dieser Session.
|
||||
|
||||
### Geänderte Dateien
|
||||
- DEVLOG.md | 144 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
- arbeitskacheln/15_mobile.md | 12 +++++++
|
||||
- flutter_app/lib/main.dart | 12 ++++---
|
||||
- flutter_app/lib/offline/mangel_queue.dart | 14 +++++++-
|
||||
- flutter_app/lib/offline/queue.dart | 20 ++++++++++-
|
||||
- flutter_app/test/mangel_queue_test.dart | 143 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
- flutter_app/test/offline_queue_test.dart | 6 ++++
|
||||
|
||||
---
|
||||
## 2026-09-12 22:15 – 22:15 (0m)
|
||||
**Beschreibung:** Claude Code Session
|
||||
**Projekt:** asb-material
|
||||
|
||||
### Commits
|
||||
Keine Commits in dieser Session.
|
||||
|
||||
### Geänderte Dateien
|
||||
- DEVLOG.md | 144 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
- arbeitskacheln/15_mobile.md | 12 +++++++
|
||||
- flutter_app/lib/main.dart | 12 ++++---
|
||||
- flutter_app/lib/offline/mangel_queue.dart | 14 +++++++-
|
||||
- flutter_app/lib/offline/queue.dart | 20 ++++++++++-
|
||||
- flutter_app/test/mangel_queue_test.dart | 143 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
- flutter_app/test/offline_queue_test.dart | 6 ++++
|
||||
|
||||
---
|
||||
## 2026-09-12 22:15 – 22:15 (0m)
|
||||
**Beschreibung:** Claude Code Session
|
||||
**Projekt:** asb-material
|
||||
|
||||
### Commits
|
||||
Keine Commits in dieser Session.
|
||||
|
||||
### Geänderte Dateien
|
||||
- DEVLOG.md | 144 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
- arbeitskacheln/15_mobile.md | 12 +++++++
|
||||
- flutter_app/lib/main.dart | 12 ++++---
|
||||
- flutter_app/lib/offline/mangel_queue.dart | 14 +++++++-
|
||||
- flutter_app/lib/offline/queue.dart | 20 ++++++++++-
|
||||
- flutter_app/test/mangel_queue_test.dart | 143 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
- flutter_app/test/offline_queue_test.dart | 6 ++++
|
||||
|
||||
---
|
||||
## 2026-09-12 22:16 – 22:17 (0m)
|
||||
**Beschreibung:** Claude Code Session
|
||||
**Projekt:** asb-material
|
||||
|
||||
### Commits
|
||||
Keine Commits in dieser Session.
|
||||
|
||||
### Geänderte Dateien
|
||||
- DEVLOG.md | 144 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
- arbeitskacheln/15_mobile.md | 12 +++++++
|
||||
- flutter_app/lib/main.dart | 12 ++++---
|
||||
- flutter_app/lib/offline/mangel_queue.dart | 14 +++++++-
|
||||
- flutter_app/lib/offline/queue.dart | 20 ++++++++++-
|
||||
- flutter_app/test/mangel_queue_test.dart | 143 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
- flutter_app/test/offline_queue_test.dart | 6 ++++
|
||||
|
||||
---
|
||||
## 2026-09-12 22:17 – 22:17 (0m)
|
||||
**Beschreibung:** Claude Code Session
|
||||
**Projekt:** asb-material
|
||||
|
||||
### Commits
|
||||
Keine Commits in dieser Session.
|
||||
|
||||
### Geänderte Dateien
|
||||
- DEVLOG.md | 144 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
- arbeitskacheln/15_mobile.md | 12 +++++++
|
||||
- flutter_app/lib/main.dart | 12 ++++---
|
||||
- flutter_app/lib/offline/mangel_queue.dart | 14 +++++++-
|
||||
- flutter_app/lib/offline/queue.dart | 20 ++++++++++-
|
||||
- flutter_app/test/mangel_queue_test.dart | 143 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
- flutter_app/test/offline_queue_test.dart | 6 ++++
|
||||
|
||||
---
|
||||
## 2026-09-12 22:18 – 22:18 (0m)
|
||||
**Beschreibung:** Claude Code Session
|
||||
**Projekt:** asb-material
|
||||
|
||||
### Commits
|
||||
Keine Commits in dieser Session.
|
||||
|
||||
### Geänderte Dateien
|
||||
- DEVLOG.md | 144 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
- arbeitskacheln/15_mobile.md | 12 +++++++
|
||||
- flutter_app/lib/main.dart | 12 ++++---
|
||||
- flutter_app/lib/offline/mangel_queue.dart | 14 +++++++-
|
||||
- flutter_app/lib/offline/queue.dart | 20 ++++++++++-
|
||||
- flutter_app/test/mangel_queue_test.dart | 143 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
- flutter_app/test/offline_queue_test.dart | 6 ++++
|
||||
|
||||
---
|
||||
## 2026-09-12 22:19 – 22:19 (0m)
|
||||
**Beschreibung:** Claude Code Session
|
||||
**Projekt:** asb-material
|
||||
|
||||
### Commits
|
||||
Keine Commits in dieser Session.
|
||||
|
||||
### Geänderte Dateien
|
||||
- DEVLOG.md | 144 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
- arbeitskacheln/15_mobile.md | 12 +++++++
|
||||
- flutter_app/lib/main.dart | 12 ++++---
|
||||
- flutter_app/lib/offline/mangel_queue.dart | 14 +++++++-
|
||||
- flutter_app/lib/offline/queue.dart | 20 ++++++++++-
|
||||
- flutter_app/test/mangel_queue_test.dart | 143 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
- flutter_app/test/offline_queue_test.dart | 6 ++++
|
||||
|
||||
---
|
||||
## 2026-09-12 22:20 – 22:20 (0m)
|
||||
**Beschreibung:** Claude Code Session
|
||||
**Projekt:** asb-material
|
||||
|
||||
### Commits
|
||||
Keine Commits in dieser Session.
|
||||
|
||||
### Geänderte Dateien
|
||||
- DEVLOG.md | 144 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
- arbeitskacheln/15_mobile.md | 12 +++++++
|
||||
- flutter_app/lib/main.dart | 12 ++++---
|
||||
- flutter_app/lib/offline/mangel_queue.dart | 14 +++++++-
|
||||
- flutter_app/lib/offline/queue.dart | 20 ++++++++++-
|
||||
- flutter_app/test/mangel_queue_test.dart | 143 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
- flutter_app/test/offline_queue_test.dart | 6 ++++
|
||||
|
||||
---
|
||||
## 2026-09-12 22:21 – 22:21 (0m)
|
||||
**Beschreibung:** Claude Code Session
|
||||
**Projekt:** asb-material
|
||||
|
||||
### Commits
|
||||
Keine Commits in dieser Session.
|
||||
|
||||
### Geänderte Dateien
|
||||
- DEVLOG.md | 144 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
- arbeitskacheln/15_mobile.md | 12 +++++++
|
||||
- flutter_app/lib/main.dart | 12 ++++---
|
||||
- flutter_app/lib/offline/mangel_queue.dart | 14 +++++++-
|
||||
- flutter_app/lib/offline/queue.dart | 20 ++++++++++-
|
||||
- flutter_app/test/mangel_queue_test.dart | 143 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
- flutter_app/test/offline_queue_test.dart | 6 ++++
|
||||
|
||||
---
|
||||
## 2026-09-12 22:21 – 22:21 (0m)
|
||||
**Beschreibung:** Claude Code Session
|
||||
**Projekt:** asb-material
|
||||
|
||||
### Commits
|
||||
Keine Commits in dieser Session.
|
||||
|
||||
### Geänderte Dateien
|
||||
- DEVLOG.md | 144 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
- arbeitskacheln/15_mobile.md | 12 +++++++
|
||||
- flutter_app/lib/main.dart | 12 ++++---
|
||||
- flutter_app/lib/offline/mangel_queue.dart | 14 +++++++-
|
||||
- flutter_app/lib/offline/queue.dart | 20 ++++++++++-
|
||||
- flutter_app/test/mangel_queue_test.dart | 143 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
- flutter_app/test/offline_queue_test.dart | 6 ++++
|
||||
|
||||
---
|
||||
@@ -61,7 +61,17 @@ class _MangelMeldenScreenState extends State<MangelMeldenScreen> {
|
||||
}
|
||||
|
||||
Future<void> _fotoAufnehmen() async {
|
||||
final bild = await ImagePicker().pickImage(source: ImageSource.camera, imageQuality: 70);
|
||||
// Fund (Foto-Kompression-Check): `imageQuality` allein komprimiert nur die
|
||||
// JPEG-Qualität, verkleinert aber NICHT die Auflösung - ein 12MP-Kamerafoto
|
||||
// bleibt trotzdem mehrere MB groß. `maxWidth`/`maxHeight` skaliert zusätzlich
|
||||
// herunter, was bei schlechter Feld-Verbindung den eigentlichen Unterschied
|
||||
// macht (1600px reicht für einen Mangel-Nachweis völlig aus).
|
||||
final bild = await ImagePicker().pickImage(
|
||||
source: ImageSource.camera,
|
||||
imageQuality: 70,
|
||||
maxWidth: 1600,
|
||||
maxHeight: 1600,
|
||||
);
|
||||
if (bild == null || !mounted) return;
|
||||
setState(() => _foto = File(bild.path));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
// Fund (Foto-Kompression-Check, Flutter-Pendant hat imageQuality+maxWidth/
|
||||
// maxHeight): die PWA lud Mangel-Fotos bislang komplett unkomprimiert hoch
|
||||
// (rohes File-Objekt aus <input type="file" capture>) - ein 12MP-Kamerafoto
|
||||
// sind mehrere MB, die im Feld über schlechte Verbindung übertragen werden
|
||||
// müssen. Canvas-basierte Verkleinerung/Neukodierung vor dem Enqueue schließt
|
||||
// diese Lücke, ohne eine zusätzliche Bibliothek zu brauchen.
|
||||
const MAX_ABMESSUNG = 1600;
|
||||
const JPEG_QUALITAET = 0.7;
|
||||
|
||||
export async function komprimiereFoto(datei: File): Promise<File> {
|
||||
if (!datei.type.startsWith("image/")) return datei;
|
||||
|
||||
const bitmap = await createImageBitmap(datei).catch(() => null);
|
||||
if (!bitmap) return datei; // z.B. HEIC ohne Browser-Decoder-Unterstützung
|
||||
|
||||
const skalierung = Math.min(1, MAX_ABMESSUNG / Math.max(bitmap.width, bitmap.height));
|
||||
const breite = Math.round(bitmap.width * skalierung);
|
||||
const hoehe = Math.round(bitmap.height * skalierung);
|
||||
|
||||
const canvas = document.createElement("canvas");
|
||||
canvas.width = breite;
|
||||
canvas.height = hoehe;
|
||||
const kontext = canvas.getContext("2d");
|
||||
if (!kontext) return datei;
|
||||
kontext.drawImage(bitmap, 0, 0, breite, hoehe);
|
||||
|
||||
const blob = await new Promise<Blob | null>((resolve) =>
|
||||
canvas.toBlob(resolve, "image/jpeg", JPEG_QUALITAET)
|
||||
);
|
||||
if (!blob || blob.size >= datei.size) return datei; // kein Gewinn, Original behalten
|
||||
|
||||
const name = datei.name.replace(/\.[^.]+$/, "") + ".jpg";
|
||||
return new File([blob], name, { type: "image/jpeg" });
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import { useSearchParams } from "react-router-dom";
|
||||
import { apiRequest } from "../api/client";
|
||||
import { useAuth } from "../auth/AuthContext";
|
||||
import { DokumentePanel } from "../components/DokumentePanel";
|
||||
import { komprimiereFoto } from "../offline/fotoKomprimierung";
|
||||
import * as mangelQueue from "../offline/mangelQueue";
|
||||
import type { MangelQueueItem } from "../offline/mangelQueue";
|
||||
import { useOnlineStatus } from "../offline/useOnlineStatus";
|
||||
@@ -173,7 +174,10 @@ export function MangelListePage() {
|
||||
type="file"
|
||||
accept="image/*"
|
||||
capture="environment"
|
||||
onChange={(e) => setFoto(e.target.files?.[0] ?? null)}
|
||||
onChange={async (e) => {
|
||||
const datei = e.target.files?.[0] ?? null;
|
||||
setFoto(datei ? await komprimiereFoto(datei) : null);
|
||||
}}
|
||||
/>
|
||||
<button className="btn btn-primary" onClick={melden} disabled={wirdGemeldet}>
|
||||
Melden {!online && "(wird bei Verbindung übertragen)"}
|
||||
|
||||
Reference in new issue
Block a user