diff --git a/AGENTS.md b/AGENTS.md index 7fe1dea..1a7ab1d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -8284,3 +8284,57 @@ Projekts aus den Apple-Richtlinien. - **Hochladen über einen eigenen HTTP-Endpunkt** statt über den Dienst: hebt die 3-MB-Grenze des Panels auf (WebSocket, aiohttp-Vorgabe 4 MiB) und spart die Base64-Aufblähung. Gemessen: über REST gehen 12 MB durch, über den WebSocket bricht die Verbindung ab 3,2 MB Rohbild wortlos ab. + +### Nachtrag .21-.23: gleiche Köpfe, Luft an den Zeilen, und `-.ics` + +**Die Listenköpfe tragen jetzt dasselbe Format** (Vorschlag B von dreien, vom Eigentümer gewählt): +Jahr und Monat beide 13px in der Zweitfarbe, gemischt geschrieben, ohne Sperrung; die Fahrtzeile +bleibt 16px. Vorher standen drei Elemente in drei Formaten — 16px weiß, 11px grau gesperrt in +Versalien, wieder 16px weiß. Die Versalien aus .20 waren mein Fehlgriff: sie sind der iOS-Stil vor +13, heute schreibt Apple Abschnittsköpfe gemischt. Unterschieden werden die Ebenen über die +Position, nicht über die Schrift. Tanken teilt die Regel; seine rechte Spalte bleibt bewusst +anders (Ansage des Eigentümers). + +Die drei Vorschläge lagen als gerendertes Muster vor (echte App-CSS, Audi Type, eigenständige HTML) +— das ist der Weg, der bei Gestaltungsfragen zu einer Entscheidung führt, statt sie zu beschreiben. + +**Die Zeilen haben wieder Luft**: `padding-left: 20px` statt 0. Das ist nicht geraten, sondern die +Spalte des Aufklapp-Pfeils — die Zeilen stehen damit auf derselben Kante wie der Text der +Kopfzeilen, wie iOS es in gruppierten Listen macht. Bei 375px behält die Beschriftungsspalte 157px, +der längste Ortsname der Testdaten braucht 142,7px. Von den 58px aus .19 bleiben 38 gewonnen. + +**Die Galerie merkt sich ihren Platz.** `useState(0)` setzte ihn bei jeder Rückkehr auf die +Seitenansicht zurück. Im Panel war das nie aufgefallen, weil `bild` dort eine modulweite Variable +ist und den Seitenwechsel überlebt; in der App lag der Zustand in der Komponente und starb mit ihr. + +**Jeder Kalendertermin hieß `-.ics`.** In `dateiname()` stand `[^wäöüÄÖÜß-]`, gemeint war +`[^\wäöüÄÖÜß-]` — ohne das `\w` überlebten nur w, ä, ö, ü, ß und der Bindestrich: + +| Titel | vorher | jetzt | +|---|---|---| +| RS4 Avant competition: Ölwechsel | `-ö-w-.ics` | `rs4-avant-competition-oelwechsel.ics` | +| Audi RS4: Inspektion | `-.ics` | `audi-rs4-inspektion.ics` | +| Wechseltermin | `-.ics` | `wechseltermin.ics` | + +Zwei verschiedene Termine überschrieben einander damit im Zwischenspeicher. Umlaute werden jetzt +umgeschrieben statt weggeworfen (ein „ö" im Dateinamen muss über die Teilen-Kette prozentkodiert +werden — eine Fehlerquelle weniger), und die Übergabe läuft über `files` statt `url`. + +**Nicht bestätigt ist, dass das den Kalender-Export repariert.** Der Verdacht bleibt, dass iOS +„Kalender" im Teilen-Blatt gar nicht als Ziel führt; der verlässliche Weg wäre EventKit, also +nativ. Steht zur Prüfung beim Eigentümer. + +### Was am 02.09. abends offen blieb + +- **Fahrt bleibt offen, wenn das Trip-Signal ihr Ende nie meldet.** Im Testcontainer nachgewiesen: + Trip-Status ging 16:33:15 auf `on` und nie wieder auf `off`, Zündung ging 16:54:21 aus, der + Kilometerstand stand ab 16:52 (209.480 → 209.490, also 10 km). Im Laufzeitspeicher steht seither + `fahrt_start_ts: 2026-09-02T16:32:18` — die Fahrt ist nie in der Liste gelandet. Der FMM003 hätte + `trip=false` nach seinem eigenen 900-s-Timeout senden müssen. **Vorschlag, noch nicht gebaut** + (der Eigentümer prüft zuerst den Dongle): bleibt das Trip-Signal an, während die Zündung länger + als 900s + Puffer aus ist und der Kilometerstand steht, die Fahrt zum Zündungsende schließen. +- **Zwischenablage:** `navigator.clipboard.read()` gibt in WebKit nur Text, HTML und Bilder heraus. + Ein PDF ist dort nie zu holen — der Knopf kann nicht funktionieren. Entweder nativ über + `UIPasteboard` oder er verschwindet auf dem Telefon. +- **Teilen legt keinen Tankvorgang an** (Abschnitt BQ) — die drei OTA-Teile und der native Umbau + stehen weiter aus. diff --git a/companion-app/src/screens/MeinAudi.tsx b/companion-app/src/screens/MeinAudi.tsx index 3333e02..acf1a8d 100644 --- a/companion-app/src/screens/MeinAudi.tsx +++ b/companion-app/src/screens/MeinAudi.tsx @@ -33,9 +33,31 @@ interface AusstattungGruppe { serie?: string[] } +/** Zuletzt gezeigter Galerieplatz - modulweit, damit er den Seitenwechsel + ueberlebt (siehe Begruendung in der Komponente). */ +let gemerkterBildIndex = 0 + export function MeinAudi({ geheZu }: { geheZu: (name: SeitenName, id?: string) => void }) { const { fahrzeug, einstellungen } = useDaten() - const [bildIndex, setzeBildIndex] = useState(0) + /* Der Platz in der Galerie ueberlebt den Seitenwechsel. + + useState(0) setzte ihn bei jeder Rueckkehr auf die Seitenansicht zurueck + - wer sich das Cockpit ansah, im Menue wechselte und zurueckkam, fing + wieder vorn an (gemeldet vom Eigentuemer, 02.09.2026). Im Panel ist das + nie aufgefallen, weil `bild` dort eine modulweite Variable ist und den + Seitenwechsel deshalb ueberlebt; hier liegt der Zustand in der + Komponente und stirbt mit ihr. + + Modulweit statt im Speicher: der Platz ist eine Ansichtssache, kein + Datum. Er soll die Sitzung ueberleben, nicht den Neustart. */ + const [bildIndex, setzeBildIndexIntern] = useState(gemerkterBildIndex) + const setzeBildIndex = (naechster: number | ((vorher: number) => number)) => { + setzeBildIndexIntern((vorher) => { + const wert = typeof naechster === "function" ? naechster(vorher) : naechster + gemerkterBildIndex = wert + return wert + }) + } if (!fahrzeug || !einstellungen) return null const aktiverSatz = diff --git a/companion-app/src/screens/kalender.ts b/companion-app/src/screens/kalender.ts index 55331b4..53f2784 100644 --- a/companion-app/src/screens/kalender.ts +++ b/companion-app/src/screens/kalender.ts @@ -79,8 +79,29 @@ function hash(text: string): number { return wert } +/** + * Dateiname für den Termin. + * + * Hier stand `[^wäöüÄÖÜß-]` - gemeint war `[^\\wäöüÄÖÜß-]`, also "alles + * außer Wortzeichen". Ohne das `\\w` überlebten nur w, ä, ö, ü, ß und der + * Bindestrich: aus "Wechseltermin" wurde `-.ics`, aus "Audi RS4: Inspektion" + * ebenfalls `-.ics`. Ein Name ohne Stamm, und zwei verschiedene Termine + * überschrieben einander im Zwischenspeicher. + * + * Jetzt mit Umlaut-Umschrift statt Wegwerfen (ein "ö" im Dateinamen muss über + * die Teilen-Kette prozentkodiert werden und ist eine Fehlerquelle mehr), + * zusammengefassten Bindestrichen und einem Rückfall, falls vom Titel nichts + * übrig bleibt. + */ function dateiname(titel: string): string { - return `${titel.replace(/[^wäöüÄÖÜß-]+/g, "-").toLowerCase()}.ics` + const stamm = titel + .replace(/ä/g, "ae").replace(/ö/g, "oe").replace(/ü/g, "ue") + .replace(/Ä/g, "Ae").replace(/Ö/g, "Oe").replace(/Ü/g, "Ue") + .replace(/ß/g, "ss") + .replace(/[^A-Za-z0-9]+/g, "-") + .replace(/^-+|-+$/g, "") + .toLowerCase() + return `${stamm || "termin"}.ics` } export async function kalenderDateiLaden( @@ -102,7 +123,10 @@ export async function kalenderDateiLaden( directory: Directory.Cache, encoding: Encoding.UTF8, }) - await Share.share({ title: titel, url: geschrieben.uri }) + /* files statt url: beides landet im Plugin als URL in den activityItems, + aber `files` ist der dokumentierte Weg für lokale Dateien - `url` ist + für Links gedacht. dialogTitle ist Android-only und schadet hier nicht. */ + await Share.share({ title: titel, files: [geschrieben.uri], dialogTitle: titel }) return } diff --git a/companion-app/src/stile/screens.css b/companion-app/src/stile/screens.css index 974346f..d88b121 100644 --- a/companion-app/src/stile/screens.css +++ b/companion-app/src/stile/screens.css @@ -1092,27 +1092,39 @@ button.dm-sicherheitszeile:active { background: var(--tile-2); } margin-left: 0; } -/* Der Monat ist ein Abschnittskopf, kein kleingeratener Eintrag. +/* Jahr und Monat tragen DENSELBEN Kopf, die Fahrtzeile trägt den Inhalt. - Vorher unterschied er sich von der Fahrtzeile nur durch Größe (13 gegen - 16px) und Farbe - beim Lesen wirkte die Liste dadurch zweistufig statt - dreistufig, und genau danach hat der Eigentümer gefragt (02.09.2026). - Versalien plus Sperrung sind die Form, die iOS für Abschnittsköpfe - benutzt und die in dieser Oberfläche schon über dem Seitentitel steht - (.ads-eyebrow). + In der Liste standen drei Elemente in drei Formaten: 2026 in 16px weiß, + September in 11px grau gesperrt in Versalien, der Ortsname wieder in 16px + weiß. Der Eigentümer hat das am 02.09.2026 als unprofessionell bezeichnet - + zu Recht: zwei Köpfe, die dasselbe tun, sollen auch gleich aussehen. - 11px und nicht 10: das ist die Untergrenze, die dieses Projekt aus den - Apple-Richtlinien übernommen hat. In beiden Oberflächen dieselben Werte, - damit der Kopf nicht je Gerät anders aussieht. */ -.dm-liste .ads-accordion--lvl2 .ads-acc-h__k { - font-size: 11px; - letter-spacing: .18em; - text-transform: uppercase; - color: var(--fg3); + Beide jetzt 13px in der Zweitfarbe, gemischt geschrieben und ohne Sperrung. + Das ist zugleich die heutige Apple-Form: Abschnittsköpfe klein und in + Sekundärfarbe, aber gemischt - Versalien sind der Stil vor iOS 13. Der + Inhalt bleibt größer als sein Kopf, wie es die Richtlinien verlangen. + Unterschieden werden die beiden Ebenen über die Position, nicht über die + Schrift. + + Von drei Vorschlägen (Monat als eigener Abschnitt ohne Aufklappen / beide + Köpfe gleich / Jahr als Seitenüberschrift) hat der Eigentümer diesen + gewählt: das Zusammenklappen ganzer Jahre bleibt erhalten. */ +.dm-liste .ads-acc-h__k { + font-size: 13px; + color: var(--fg2); } +/* 20px statt 0: die Zeilen standen sonst 34px vom Bildschirmrand entfernt und + damit sichtbar enger als alles andere in der Kachel (gemeldet 02.09.2026). + 20px ist nicht geraten, sondern die Spalte des Aufklapp-Pfeils - die Zeilen + stehen damit auf derselben Kante wie der Text der Kopfzeilen, so wie iOS es + in gruppierten Listen macht. + + Nachgemessen bei 375px: die Beschriftungsspalte behält 157px, der längste + Ortsname der Testdaten ("Ingolstadt → Adelschlag") braucht 142,7px. Von den + 58px, die vorher verschenkt waren, bleiben 38 gewonnen. */ .dm-liste .dm-blatt { - padding-left: 0; + padding-left: 20px; } .dm-blatt { diff --git a/custom_components/audi_dashboard/frontend/app/bundle.json b/custom_components/audi_dashboard/frontend/app/bundle.json index 107a695..962aa06 100644 --- a/custom_components/audi_dashboard/frontend/app/bundle.json +++ b/custom_components/audi_dashboard/frontend/app/bundle.json @@ -1 +1 @@ -{"version":"2026.9.2.20","sha256":"04aa82b37c019eadf0c9c23bc27e4931b9371dba512ddd979adc1ea70f482924","bytes":266578,"gebaut":"2026-09-02T14:34:34Z"} \ No newline at end of file +{"version":"2026.9.2.23","sha256":"a4b55f9576980ea8f52a5c7782bc0879ff7e4c6561e19f844c44dad903bb87c5","bytes":266680,"gebaut":"2026-09-02T19:03:48Z"} \ No newline at end of file diff --git a/custom_components/audi_dashboard/frontend/app/bundle.zip b/custom_components/audi_dashboard/frontend/app/bundle.zip index ff2eed1..92049e4 100644 Binary files a/custom_components/audi_dashboard/frontend/app/bundle.zip and b/custom_components/audi_dashboard/frontend/app/bundle.zip differ diff --git a/custom_components/audi_dashboard/frontend/audi-dashboard.css b/custom_components/audi_dashboard/frontend/audi-dashboard.css index 917d31e..8d08978 100644 --- a/custom_components/audi_dashboard/frontend/audi-dashboard.css +++ b/custom_components/audi_dashboard/frontend/audi-dashboard.css @@ -917,25 +917,38 @@ img.carfix.klein { aspect-ratio: auto; height: auto; } ohne Platz zu kosten. Beschränkt auf .liste, weil das linke Polster von .leaf anderswo (Batteriewerte, Servicebuch) gewollt ist. */ .liste .lvl2 { margin-left: 0; } -/* Der Monat ist ein Abschnittskopf, kein kleingeratener Eintrag. +/* Jahr und Monat tragen DENSELBEN Kopf, die Fahrtzeile traegt den Inhalt. - Vorher unterschied er sich von der Fahrtzeile nur durch Groesse (13 gegen - 16px) und Farbe - beim Lesen wirkte die Liste dadurch zweistufig statt - dreistufig, und genau danach hat der Eigentuemer gefragt (02.09.2026). - Versalien plus Sperrung sind die Form, die iOS fuer Abschnittskoepfe - benutzt und die in dieser Oberflaeche schon ueber dem Seitentitel steht - (.eyebrow). + In der Liste standen drei Elemente in drei Formaten: 2026 in 16px weiss, + September in 11px grau gesperrt in Versalien, der Ortsname wieder in 16px + weiss. Der Eigentuemer hat das am 02.09.2026 als unprofessionell + bezeichnet - zu Recht: zwei Koepfe, die dasselbe tun, sollen auch gleich + aussehen. - 11px und nicht 10: das ist die Untergrenze, die dieses Projekt aus den - Apple-Richtlinien uebernommen hat. In beiden Oberflaechen dieselben - Werte, damit der Kopf nicht je Geraet anders aussieht. */ -.liste .lvl2 .acc-h .k { - font-size: 11px; - letter-spacing: .18em; - text-transform: uppercase; - color: var(--fg3); + Beide jetzt 13px in der Zweitfarbe, gemischt geschrieben und ohne + Sperrung. Das ist zugleich die heutige Apple-Form: Abschnittskoepfe + klein und in Sekundaerfarbe, aber gemischt - Versalien sind der Stil vor + iOS 13. Der Inhalt bleibt groesser als sein Kopf, wie es die Richtlinien + verlangen. Unterschieden werden die beiden Ebenen ueber die Position, + nicht ueber die Schrift. + + Von drei Vorschlaegen (Monat als eigener Abschnitt ohne Aufklappen / + beide Koepfe gleich / Jahr als Seitenueberschrift) hat der Eigentuemer + diesen gewaehlt: das Zusammenklappen ganzer Jahre bleibt erhalten. */ +.liste .acc-h .k { + font-size: 13px; + color: var(--fg2); } -.liste .leaf { padding-left: 0; } +/* 20px statt 0: die Zeilen standen sonst 34px vom Bildschirmrand entfernt und + damit sichtbar enger als alles andere in der Kachel (gemeldet 02.09.2026). + 20px ist nicht geraten, sondern die Spalte des Aufklapp-Pfeils - die + Zeilen stehen damit auf derselben Kante wie der Text der Kopfzeilen, so + wie iOS es in gruppierten Listen macht. + + Nachgemessen bei 375px: die Beschriftungsspalte behaelt 157px, der + laengste Ortsname der Testdaten ("Ingolstadt -> Adelschlag") braucht + 142,7px. Von den 58px, die vorher verschenkt waren, bleiben 38 gewonnen. */ +.liste .leaf { padding-left: 20px; } .tile-h { display: block; width: 100%; diff --git a/custom_components/audi_dashboard/manifest.json b/custom_components/audi_dashboard/manifest.json index 5218590..07c3e2f 100644 --- a/custom_components/audi_dashboard/manifest.json +++ b/custom_components/audi_dashboard/manifest.json @@ -1,7 +1,7 @@ { "domain": "audi_dashboard", "name": "Audi Dashboard", - "version": "2026.9.2.20", + "version": "2026.9.2.23", "documentation": "https://gitea.nothaft.cloud/paul/audi-app/src/branch/main/README.md", "issue_tracker": "https://gitea.nothaft.cloud/paul/audi-app/issues", "codeowners": ["@paul"],