b1411625aa
Share-Erweiterung: ein PDF aus Mail landet ueber Teilen -> DataMetric360 als Tankbeleg. Alles Native liegt versioniert unter companion-app/native/, weil ios/ gitignored ist und npx cap add ios es sonst wieder frisst; scripts/ios-teilen-einrichten.mjs haengt es bei jedem Bau ins Xcode-Projekt und ist in ios-signieren.sh eingehaengt. Der pbxproj-Teil ist auf keinem Mac erprobt - er bricht vor dem Schreiben ab, und docs/SHARE_EXTENSION.md beschreibt dieselben Handgriffe fuer Xcode. "In den Kalender uebernehmen" ging in der App nie: WKWebView ignoriert das download-Attribut, der Klick lief ins Leere. Auf dem Geraet jetzt @capacitor/filesystem plus @capacitor/share. useTheme/useBoden legten je Aufrufer eigenen Zustand an - fuenf Kopien. Der Schalter aenderte nur seine eigene, data-theme in App.tsx blieb stehen, die Tag/Nacht-Umschaltung wirkte erst nach einem Neustart. Jetzt ein Speicher je Einstellung ueber useSyncExternalStore. Zwei Regressionstests, gegen den alten Stand als fehlschlagend nachgewiesen. Alle Popups nach Apple HIG: neue Bausteine Sheet und ActionSheet, blickdicht und mit abgedunkeltem Schleier, in beiden Codebasen. Popup portalierte nach document.body - ausserhalb von [data-theme] - und war deshalb im Tagmodus fast unsichtbar; Portal zielt jetzt auf .ads-root. ImagePlaceholder merkte sich "fehlgeschlagen" ohne die Adresse: nach einem leeren Galerieplatz zeigten auch die mit Foto nur noch den Platzhalter. Vier Regressionstests, ebenfalls gegen den alten Stand geprueft. Bildadressen tragen jetzt einen Cache-Brecher - HA liefert /local/ mit 31 Tagen Cache-Vorgabe aus, im Panel eingefuegte Radfotos erschienen in der App deshalb nicht. uebersichtsbild: Panel speichert den Namen, die App verglich gegen den Dateinamen - der Vergleich traf nie zu. Kanonisch ist der Name. Weiter: Navigationspfeil statt gleichschenkligem Dreieck auf der Streckenlinie (die Kerbe unterscheidet Kopf und Ende), CI-Symbol tour-s als Fahrten-Icon, Datumsfelder zeigen ihren Wert ohne erstes Antippen, feste Beispielnamen im Setup, Kopf-Gegengewicht fuer mittige Titel, Standort-Blatt mit festem Fussabstand, NSLocationWhenInUseUsageDescription, watchPosition fuer die Live-Ortung, Art-Pille wieder als Knopf, Zwischenablage fuer Tankbelege. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
59 lines
2.1 KiB
TypeScript
59 lines
2.1 KiB
TypeScript
/**
|
|
* Ein Datumsfeld, das seinen Wert auch dann anzeigt, wenn er erst später
|
|
* eintrifft.
|
|
*
|
|
* DAS PROBLEM
|
|
* -----------
|
|
* Alle Datumsfelder der App hängen an Werten aus dem Datenkontext, und der
|
|
* füllt sich asynchron: beim ersten Rendern steht dort ein leerer String, den
|
|
* echten Wert bekommt das Feld erst danach. WebKit — die Engine der iOS-Hülle —
|
|
* baut den inneren Aufbau eines `<input type="date">` beim ersten Rendern auf
|
|
* und zieht ihn bei einer späteren Wertänderung von außen nicht zuverlässig
|
|
* nach; sichtbar blieb „tt.mm.jjjj", und erst ein Antippen brachte das Datum
|
|
* zum Vorschein (gemeldet vom Eigentümer, 2026-08-31: „erst beim ersten Klick
|
|
* aufs Datumsfeld erscheinen diese korrekt").
|
|
*
|
|
* Verschärft wird das durch den `appearance`-Reset in screens.css, der für die
|
|
* Box-Optik nötig ist — ohne ihn zeigt iOS sein eigenes, stark abgerundetes
|
|
* Chrome („gestreckter Kreis statt Box").
|
|
*
|
|
* DIE LÖSUNG
|
|
* ----------
|
|
* Der Schlüssel wechselt genau einmal: von „leer" auf „gefuellt", sobald der
|
|
* echte Wert da ist. React baut das Feld an dieser Stelle neu auf, und WebKit
|
|
* legt seinen inneren Aufbau damit gleich mit dem Wert an.
|
|
*
|
|
* Bewusst NICHT der Wert selbst als Schlüssel: dann entstünde das Feld bei
|
|
* jeder Auswahl neu, verlöre den Fokus und schlösse auf dem Telefon die
|
|
* Datumsauswahl mitten in der Bedienung. Der Wechsel leer→gefüllt passiert
|
|
* dagegen genau einmal, und zwar bevor jemand das Feld anfassen kann.
|
|
*
|
|
* Das Panel braucht das nicht: dort schreibt jedes `render()` das Markup neu,
|
|
* das Feld entsteht also ohnehin immer mit seinem Wert.
|
|
*/
|
|
|
|
export function Datumsfeld({
|
|
wert,
|
|
beiAenderung,
|
|
className = "dm-eingabe",
|
|
...rest
|
|
}: {
|
|
wert: string
|
|
beiAenderung: (wert: string) => void
|
|
className?: string
|
|
} & Omit<
|
|
React.InputHTMLAttributes<HTMLInputElement>,
|
|
"value" | "onChange" | "type" | "className"
|
|
>) {
|
|
return (
|
|
<input
|
|
key={wert ? "gefuellt" : "leer"}
|
|
type="date"
|
|
className={className}
|
|
value={wert}
|
|
onChange={(e) => beiAenderung(e.target.value)}
|
|
{...rest}
|
|
/>
|
|
)
|
|
}
|