Teilen-Blatt, HIG-Blaetter, geteilte Ansichtseinstellungen (2026.8.31.1)
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>
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
# Tankbeleg aus dem Teilen-Blatt
|
||||
|
||||
Ein PDF aus Mail (oder einer anderen App) über **Teilen → DataMetric360** direkt
|
||||
als Tankbeleg übernehmen.
|
||||
|
||||
## Wie es zusammenhängt
|
||||
|
||||
```
|
||||
Mail ──Teilen──► DataMetric360Share (eigener Prozess)
|
||||
│
|
||||
│ PDF → Base64 → UserDefaults der App-Gruppe
|
||||
│ group.app.datametric360
|
||||
▼
|
||||
datametric360://beleg (öffnet die App)
|
||||
│
|
||||
▼
|
||||
App.tsx ──holt ab──► Tanken-Seite ──► belegLesen()
|
||||
```
|
||||
|
||||
Eine Erweiterung ist ein eigener Prozess mit eigenem Dateibereich; der einzige
|
||||
gemeinsame Boden mit der App ist die **App-Gruppe**. Der Beleg reist deshalb
|
||||
Base64-kodiert durch die geteilten `UserDefaults` — die liest
|
||||
`@capacitor/preferences` ohnehin schon, sobald man ihm die Gruppe nennt. Eine
|
||||
Datei im Gruppen-Container wäre der sauberere Ort, bräuchte auf der App-Seite
|
||||
aber eigenen nativen Code, also ein zusätzliches Plugin für einen Weg, den es
|
||||
sonst nicht gäbe.
|
||||
|
||||
Der Preis ist eine Größengrenze von 4 MB (`grenzeBytes` im
|
||||
`ShareViewController`). Ein Tankbeleg liegt bei einigen Dutzend Kilobyte; ein
|
||||
gescanntes Mehrseiten-PDF kann darüber liegen — dann sagt die Erweiterung das,
|
||||
und der Weg über **Beleg hochladen → Datei auswählen** in der App bleibt.
|
||||
|
||||
## Wo was liegt
|
||||
|
||||
| Datei | Rolle |
|
||||
|---|---|
|
||||
| `native/teilen/ShareViewController.swift` | nimmt das PDF entgegen, legt es ab, öffnet die App |
|
||||
| `native/teilen/Info.plist` | wann DataMetric360 im Teilen-Blatt erscheint (genau ein PDF) |
|
||||
| `native/teilen/DataMetric360Share.entitlements` | App-Gruppe für die Erweiterung |
|
||||
| `native/App.entitlements` | dieselbe App-Gruppe für die App |
|
||||
| `scripts/ios-teilen-einrichten.mjs` | hängt das alles ins erzeugte Xcode-Projekt |
|
||||
| `src/daten/geteilterBeleg.ts` | holt den Beleg ab, räumt ihn weg |
|
||||
| `src/App.tsx` | prüft beim Start und bei jeder Rückkehr, springt auf Tanken |
|
||||
| `src/screens/Tanken.tsx` | nimmt ihn auf und lädt ihn hoch |
|
||||
|
||||
**`companion-app/ios/` ist gitignored** und wird von `npx cap add ios` neu
|
||||
gebaut. Alles Native muss deshalb unter `native/` liegen und bei jedem Bau
|
||||
eingespielt werden — dieselbe Regel, die schon die Team-Kennung und den
|
||||
Standort-Schlüssel in `ios-signieren.sh` getrieben hat.
|
||||
|
||||
## Einmalig im Apple-Entwicklerportal
|
||||
|
||||
Ohne diese drei Schritte schlägt das Signieren fehl (die App-Gruppe muss
|
||||
existieren, bevor ein Profil sie enthalten kann):
|
||||
|
||||
1. **Identifiers → App Groups**: `group.app.datametric360` anlegen.
|
||||
2. **Identifiers → App IDs**: `app.datametric360.teilen` anlegen, Capability
|
||||
*App Groups* aktivieren, die Gruppe zuordnen.
|
||||
3. Bei der bestehenden App-ID `app.datametric360` ebenfalls *App Groups*
|
||||
aktivieren und dieselbe Gruppe zuordnen.
|
||||
|
||||
Danach in Xcode einmal die Profile neu ziehen lassen — oder schlicht
|
||||
`ios-signieren.sh` laufen lassen, das macht `-allowProvisioningUpdates`
|
||||
selbst. **Merkposten aus Abschnitt AI:** ein zwischengespeichertes altes
|
||||
Profil wird stillschweigend weiterverwendet. Ändert sich etwas an den
|
||||
Berechtigungen, das passende `.mobileprovision` unter
|
||||
`~/Library/Developer/Xcode/UserData/Provisioning Profiles` löschen und neu
|
||||
exportieren.
|
||||
|
||||
## Bauen
|
||||
|
||||
```bash
|
||||
bash scripts/ios-signieren.sh
|
||||
```
|
||||
|
||||
Der Schritt „Share-Erweiterung einrichten" läuft dort automatisch, vor dem
|
||||
Archivieren.
|
||||
|
||||
## Wenn das Skript abbricht
|
||||
|
||||
`ios-teilen-einrichten.mjs` bearbeitet die `project.pbxproj` über das
|
||||
npm-Paket `xcode`. **Das ist auf keinem Mac erprobt** — geschrieben ohne
|
||||
Zugriff auf macOS. Bricht es ab, ist nichts halb eingerichtet (es bricht vor
|
||||
dem Schreiben ab), und dasselbe lässt sich in Xcode von Hand erledigen:
|
||||
|
||||
1. **File → New → Target… → Share Extension**, Name `DataMetric360Share`,
|
||||
Sprache Swift, „Activate scheme" verneinen.
|
||||
2. Die von Xcode erzeugten `ShareViewController.swift`, `Info.plist` und das
|
||||
`MainInterface.storyboard` **löschen** und stattdessen die Dateien aus
|
||||
`native/teilen/` in das Ziel legen (Storyboard wird nicht gebraucht, die
|
||||
Erweiterung hat keine eigene Oberfläche).
|
||||
3. Bundle-ID des Ziels auf `app.datametric360.teilen` setzen.
|
||||
4. Beide Ziele → **Signing & Capabilities → + Capability → App Groups**,
|
||||
`group.app.datametric360` anhaken.
|
||||
5. Ziel `DataMetric360Share` → Build Settings → *Code Signing Entitlements* auf
|
||||
`DataMetric360Share/DataMetric360Share.entitlements`; Ziel `App` auf
|
||||
`App/App.entitlements`.
|
||||
6. Ziel `App` → Build Phases → **Embed App Extensions** muss
|
||||
`DataMetric360Share.appex` enthalten.
|
||||
7. `ios/App/App/Info.plist`: URL-Schema `datametric360` unter
|
||||
`CFBundleURLTypes` eintragen.
|
||||
|
||||
Schritt 7 ist der leiseste: fehlt er, wird der Beleg abgelegt, die App aber
|
||||
nicht geöffnet — er taucht dann erst auf, wenn man die App das nächste Mal von
|
||||
Hand startet.
|
||||
|
||||
## Prüfen, ob es wirkt
|
||||
|
||||
1. In Mail ein PDF antippen → **Teilen** → DataMetric360 muss in der Liste
|
||||
stehen (nur bei genau einem PDF, sonst absichtlich nicht).
|
||||
2. Antippen → die App kommt nach vorn, springt auf **Tanken**, das Formular ist
|
||||
offen und liest den Beleg („Beleg wird gelesen …").
|
||||
3. Danach ist der Eintrag weg: dieselbe Datei ein zweites Mal zu teilen muss
|
||||
wieder funktionieren, ein bloßes Wechseln in die App darf den Beleg **nicht**
|
||||
erneut verarbeiten.
|
||||
|
||||
## Was hier nicht steht
|
||||
|
||||
Android. Der Ablauf ist dort ein anderer (`intent-filter` statt App-Gruppe),
|
||||
und die Android-Hülle dieses Projekts ist ohnehin nicht in Gebrauch.
|
||||
Reference in New Issue
Block a user