diff --git a/AGENTS.md b/AGENTS.md
index 4752d97..1dea019 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -1169,6 +1169,40 @@ wraps the web app for iPhone; a PWA home-screen install is the accepted intermed
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/`.
+ **Nachbesserung am selben Tag, nach Fehlermeldung des Nutzers** ("copy paste from pc brings
+ error no pdf but it is the latest bill") — zwei echte Fehler, beide bestätigt:
+ (1) `navigator.clipboard.read()` (der "Aus Zwischenablage einfügen"-Knopf) gibt laut
+ Spezifikation **nur Text, HTML und Bilder** heraus. Eine im Explorer/Finder kopierte PDF-Datei
+ taucht dort grundsätzlich nicht auf - der Knopf konnte am Rechner also gar nicht funktionieren
+ und behauptete dann fälschlich, es liege kein PDF vor. Der Weg, der dort funktioniert, ist
+ Strg+V: das `paste`-Ereignis trägt die Datei in `clipboardData.files`. Die Meldung nennt jetzt
+ genau das, statt die Datei zu beschuldigen; die Ablagefläche sagt es von vornherein
+ ("oder mit Strg+V einfügen", per `tastenkuerzelEinfuegen()` auf Mac Cmd+V).
+ (2) Die Erkennung hing allein am MIME-Typ (`type === "application/pdf"`) - eine aus dem
+ Explorer kopierte oder gezogene Datei kommt je nach Browser und Quelle aber mit **leerem**
+ `type` an und wurde dadurch abgelehnt. Neue Hilfsfunktion `istPdf()` prüft zusätzlich die
+ Dateiendung; live nachgestellt mit genau diesem Fall (`new File([...], "Tankbeleg_August.pdf",
+ {})`, `type === ""`) - vorher abgelehnt, jetzt korrekt hochgeladen.
+ (3) Auf Rückfrage des Nutzers ("why is it that way? computer has copy paste function") noch
+ einen Schritt weiter: Der Einfügen-Knopf wird am Rechner jetzt **gar nicht mehr angeboten**
+ (`zwischenablageKnopfSinnvoll()`, Prüfung auf `(pointer: coarse)`), weil er dort prinzipiell
+ nicht funktionieren kann - ein Knopf, der zwangsläufig in eine Fehlermeldung läuft, ist
+ schlechter als keiner. "Datei auswählen" wird dort zur primären Aktion; auf dem Telefon bleibt
+ alles wie zuvor. Der Unterschied dahinter, kurz: Strg+V ist eine bewusste Nutzergeste an die
+ Seite, deshalb bekommt die Seite den vollen Inhalt inklusive Dateien - `clipboard.read()` ist
+ die Seite, die von sich aus die Zwischenablage ausliest, und das wird aus Datenschutzgründen
+ stark eingeschränkt (sonst könnte jede Seite still mitlesen, was zuletzt kopiert wurde).
+ Live geprüft: Desktop zeigt nur noch "Datei auswählen [primaer]"/"Abbrechen", Mobil (375px,
+ `pointer: coarse`) weiterhin alle drei Knöpfe.
+- [x] Preis je Liter überall auf 2 Nachkommastellen (2026-08-17, Nutzerwunsch: "€/l for gas is
+ common to be displayed as x,xx €/l") — alle sieben Stellen von `de(..., 3)` auf `de(..., 2)`
+ umgestellt: Jahres- und Monatsschnitt in der Tankliste, Zeilenwert je Tankvorgang, "Preis je
+ Liter" im Einzelbeleg, die Live-Vorschau in beiden Tankformularen (statisch und im
+ `data-tankpreisfeld`-Handler) sowie die CSV-Spalte "€/l". Im CSV kein Informationsverlust: der
+ Wert ist aus den ebenfalls exportierten Spalten Liter und Kosten jederzeit neu berechenbar.
+ `companion-app` (Nachfolger-App) brauchte keine Änderung - deren `eur()` rundet ohnehin schon
+ auf 2 Stellen. Live geprüft: keine `de(..., 3)`-Aufrufe mehr in der Datei, Liste und
+ Einzelbeleg zeigen "2,07 €/l", "1,99 €/l" usw.
- [ ] 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 371acff..37afc31 100644
--- a/homeassistant/installationspaket/www/audi-dashboard-app.js
+++ b/homeassistant/installationspaket/www/audi-dashboard-app.js
@@ -2805,7 +2805,7 @@ function tankFelder(praefix, f) {
const kraftstoff = q && q.fuel_type ? q.fuel_type : KRAFTSTOFFSORTEN[0];
const station = q && q.station_name ? q.station_name : "";
const preisText = q && q.liters && q.fuel_total_eur != null && q.liters > 0
- ? `Preis je Liter: ${de(q.fuel_total_eur / q.liters, 3)} €` : "Preis je Liter: wird berechnet";
+ ? `Preis je Liter: ${de(q.fuel_total_eur / q.liters, 2)} €` : "Preis je Liter: wird berechnet";
return `
@@ -3006,7 +3006,7 @@ function hinweis(titel, text) {
unverändert. */
function belegDateiVerarbeiten(datei, tankId, kontext) {
if (!datei) return;
- if (datei.type && datei.type !== "application/pdf") {
+ if (!istPdf(datei)) {
belegFehler = { context: kontext, meldung: "Nur PDF-Belege werden unterstützt" };
render(); return;
}
@@ -3025,9 +3025,16 @@ function belegDateiVerarbeiten(datei, tankId, kontext) {
leser.readAsDataURL(datei);
}
+/* Nicht nur auf den MIME-Typ verlassen: eine aus dem Explorer/Finder kopierte
+ oder gezogene Datei kommt je nach Browser und Quelle mit leerem type an. */
+function istPdf(datei) {
+ if (!datei) return false;
+ return datei.type === "application/pdf" || /\.pdf$/i.test(datei.name || "");
+}
+
/* Nimmt das erste PDF aus einer DataTransfer-/Clipboard-Dateiliste. */
function belegAusDateiliste(dateien) {
- return [...(dateien || [])].find((d) => d.type === "application/pdf") || null;
+ return [...(dateien || [])].find(istPdf) || null;
}
function belegPopupSchliessenUndLaden(datei) {
@@ -3040,12 +3047,21 @@ function belegPopupSchliessenUndLaden(datei) {
/* Telefon-Weg: das aus der Mail kopierte PDF liegt in der Zwischenablage.
navigator.clipboard.read() ist der einzige Weg, ohne dass der Nutzer in ein
- Eingabefeld tippen muss - iOS zeigt dafür seine eigene Einfügen-Abfrage. */
+ Eingabefeld tippen muss - iOS zeigt dafür seine eigene Einfügen-Abfrage.
+
+ WICHTIG (Ursache eines gemeldeten Fehlers): Am Rechner hilft dieser Knopf
+ bei einer im Explorer/Finder kopierten Datei NICHT. clipboard.read() gibt
+ laut Spezifikation nur Text, HTML und Bilder heraus - eine kopierte
+ PDF-Datei taucht dort gar nicht auf, egal wie frisch sie ist. Der Weg, der
+ dort funktioniert, ist Strg+V: das paste-Ereignis trägt die echte Datei in
+ clipboardData.files. Deshalb sagt die Meldung unten genau das, statt
+ pauschal "kein PDF" zu behaupten. */
async function belegAusZwischenablage() {
const ctx = belegPopup;
if (!ctx) return;
+ const strgVHinweis = `Am Rechner kann der Browser eine kopierte Datei nur über ${tastenkuerzelEinfuegen()} entgegennehmen - bitte so einfügen oder das PDF hineinziehen.`;
if (!navigator.clipboard || !navigator.clipboard.read) {
- belegPopup.fehler = "Dieser Browser kann die Zwischenablage nicht lesen - bitte ziehen oder Datei auswählen.";
+ belegPopup.fehler = strgVHinweis;
render(); return;
}
try {
@@ -3053,13 +3069,25 @@ async function belegAusZwischenablage() {
const typ = (eintrag.types || []).find((t) => t === "application/pdf");
if (typ) { belegPopupSchliessenUndLaden(new File([await eintrag.getType(typ)], "beleg.pdf", { type: "application/pdf" })); return; }
}
- belegPopup.fehler = "In der Zwischenablage liegt kein PDF.";
+ belegPopup.fehler = strgVHinweis;
} catch (err) {
- belegPopup.fehler = "Kein Zugriff auf die Zwischenablage.";
+ belegPopup.fehler = "Kein Zugriff auf die Zwischenablage. " + strgVHinweis;
}
render();
}
+function tastenkuerzelEinfuegen() {
+ return /Mac|iPhone|iPad/.test(navigator.platform || navigator.userAgent) ? "Cmd+V" : "Strg+V";
+}
+
+/* Der Einfügen-Knopf wird nur auf Tippgeräten angeboten. Am Rechner kann er
+ aus Datenschutzgründen prinzipiell nicht funktionieren (clipboard.read()
+ gibt Dateien nie heraus, siehe oben) - ein Knopf, der dort zwangsläufig
+ scheitert, führt nur in eine Sackgasse. Dort bleiben Ziehen und Strg+V. */
+function zwischenablageKnopfSinnvoll() {
+ return window.matchMedia && window.matchMedia("(pointer: coarse)").matches;
+}
+
function vBelegPopup() {
if (!belegPopup) return "";
return `
@@ -3067,11 +3095,11 @@ function vBelegPopup() {
Beleg hochladen
PDF hierher ziehen
- oder aus der Zwischenablage einfügen
+ oder mit ${tastenkuerzelEinfuegen()} einfügen
@@ -3006,7 +3006,7 @@ function hinweis(titel, text) {
unverändert. */
function belegDateiVerarbeiten(datei, tankId, kontext) {
if (!datei) return;
- if (datei.type && datei.type !== "application/pdf") {
+ if (!istPdf(datei)) {
belegFehler = { context: kontext, meldung: "Nur PDF-Belege werden unterstützt" };
render(); return;
}
@@ -3025,9 +3025,16 @@ function belegDateiVerarbeiten(datei, tankId, kontext) {
leser.readAsDataURL(datei);
}
+/* Nicht nur auf den MIME-Typ verlassen: eine aus dem Explorer/Finder kopierte
+ oder gezogene Datei kommt je nach Browser und Quelle mit leerem type an. */
+function istPdf(datei) {
+ if (!datei) return false;
+ return datei.type === "application/pdf" || /\.pdf$/i.test(datei.name || "");
+}
+
/* Nimmt das erste PDF aus einer DataTransfer-/Clipboard-Dateiliste. */
function belegAusDateiliste(dateien) {
- return [...(dateien || [])].find((d) => d.type === "application/pdf") || null;
+ return [...(dateien || [])].find(istPdf) || null;
}
function belegPopupSchliessenUndLaden(datei) {
@@ -3040,12 +3047,21 @@ function belegPopupSchliessenUndLaden(datei) {
/* Telefon-Weg: das aus der Mail kopierte PDF liegt in der Zwischenablage.
navigator.clipboard.read() ist der einzige Weg, ohne dass der Nutzer in ein
- Eingabefeld tippen muss - iOS zeigt dafür seine eigene Einfügen-Abfrage. */
+ Eingabefeld tippen muss - iOS zeigt dafür seine eigene Einfügen-Abfrage.
+
+ WICHTIG (Ursache eines gemeldeten Fehlers): Am Rechner hilft dieser Knopf
+ bei einer im Explorer/Finder kopierten Datei NICHT. clipboard.read() gibt
+ laut Spezifikation nur Text, HTML und Bilder heraus - eine kopierte
+ PDF-Datei taucht dort gar nicht auf, egal wie frisch sie ist. Der Weg, der
+ dort funktioniert, ist Strg+V: das paste-Ereignis trägt die echte Datei in
+ clipboardData.files. Deshalb sagt die Meldung unten genau das, statt
+ pauschal "kein PDF" zu behaupten. */
async function belegAusZwischenablage() {
const ctx = belegPopup;
if (!ctx) return;
+ const strgVHinweis = `Am Rechner kann der Browser eine kopierte Datei nur über ${tastenkuerzelEinfuegen()} entgegennehmen - bitte so einfügen oder das PDF hineinziehen.`;
if (!navigator.clipboard || !navigator.clipboard.read) {
- belegPopup.fehler = "Dieser Browser kann die Zwischenablage nicht lesen - bitte ziehen oder Datei auswählen.";
+ belegPopup.fehler = strgVHinweis;
render(); return;
}
try {
@@ -3053,13 +3069,25 @@ async function belegAusZwischenablage() {
const typ = (eintrag.types || []).find((t) => t === "application/pdf");
if (typ) { belegPopupSchliessenUndLaden(new File([await eintrag.getType(typ)], "beleg.pdf", { type: "application/pdf" })); return; }
}
- belegPopup.fehler = "In der Zwischenablage liegt kein PDF.";
+ belegPopup.fehler = strgVHinweis;
} catch (err) {
- belegPopup.fehler = "Kein Zugriff auf die Zwischenablage.";
+ belegPopup.fehler = "Kein Zugriff auf die Zwischenablage. " + strgVHinweis;
}
render();
}
+function tastenkuerzelEinfuegen() {
+ return /Mac|iPhone|iPad/.test(navigator.platform || navigator.userAgent) ? "Cmd+V" : "Strg+V";
+}
+
+/* Der Einfügen-Knopf wird nur auf Tippgeräten angeboten. Am Rechner kann er
+ aus Datenschutzgründen prinzipiell nicht funktionieren (clipboard.read()
+ gibt Dateien nie heraus, siehe oben) - ein Knopf, der dort zwangsläufig
+ scheitert, führt nur in eine Sackgasse. Dort bleiben Ziehen und Strg+V. */
+function zwischenablageKnopfSinnvoll() {
+ return window.matchMedia && window.matchMedia("(pointer: coarse)").matches;
+}
+
function vBelegPopup() {
if (!belegPopup) return "";
return `
@@ -3067,11 +3095,11 @@ function vBelegPopup() {
Beleg hochladen
PDF hierher ziehen
- oder aus der Zwischenablage einfügen
+ oder mit ${tastenkuerzelEinfuegen()} einfügen