Kalender ueber EventKit, Orte nach dem Import, Fotos verkleinert, Signalsperre (2026.9.3.1-.3)

- Kalendertermine gehen nativ ueber EventKit statt ueber das Teilen-Blatt:
  Apples Kalender meldet sich beim System gar nicht als Teilen-Ziel an, ein
  anderes Dateiformat haette also nie geholfen (Abschnitt BS).
- Der Rueckblick stoesst jetzt selbst das Screening an, wenn er Fahrten
  angelegt hat - sonst blieb eine importierte Fahrt ohne Ort liegen, solange
  das Fahrzeug steht (Abschnitt BT).
- Fahrzeugfotos werden vor dem Upload im Browser auf 2000 px/WebP gebracht.
  Gemessen: 3.099.022 -> 325.994 Bytes. Damit ist die Nachrichtengrenze der
  WebSocket-Verbindung kein Thema mehr ("connection lost" auf der realen
  Instanz). Formate, die der Browser weder umwandeln noch anzeigen kann,
  werden mit klarer Meldung abgelehnt statt roh gespeichert.
- Zwei Wechsel des Fahrtsignals in derselben Sekunde kosteten eine ganze
  Fahrt: das "on" ueberholte den noch laufenden Beende-Vorgang und fiel durch
  beide Zweige. Neue asyncio-Sperre plus Regressionstest, der ohne sie
  nachweislich rot ist (Abschnitt BU).

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
2026-09-03 01:59:32 +02:00
co-authored by Claude Opus 5
parent 8c95e50554
commit 6016053a92
18 changed files with 1072 additions and 78 deletions
+20
View File
@@ -106,6 +106,26 @@ fi
exit 1
}
# Kalender-Berechtigung, aus demselben Grund an derselben Stelle.
#
# Warum ZWEI Schluessel: seit iOS 17 gibt es einen eigenen Nur-Schreiben-Zugriff
# (NSCalendarsWriteOnlyAccessUsageDescription), aeltere Fassungen kennen nur den
# alten Sammelschluessel. Der System-Editor (native/KalenderTermin.swift) fragt
# auf iOS 17+ von sich aus gar nicht - die Schluessel sind die Absicherung fuer
# den Fall, dass EventKit doch einmal fragt. Fehlt der passende, beendet iOS die
# App wortlos, statt eine Rueckfrage zu zeigen.
echo "==> Kalender-Berechtigung eintragen"
KALENDERGRUND="Traegt Werkstatt- und Wechseltermine in deinen Kalender ein."
for SCHLUESSEL in NSCalendarsWriteOnlyAccessUsageDescription NSCalendarsUsageDescription; do
if ! /usr/libexec/PlistBuddy -c "Set :$SCHLUESSEL $KALENDERGRUND" "$PLIST" 2>/dev/null; then
/usr/libexec/PlistBuddy -c "Add :$SCHLUESSEL string $KALENDERGRUND" "$PLIST"
fi
/usr/libexec/PlistBuddy -c "Print :$SCHLUESSEL" "$PLIST" >/dev/null || {
echo "FEHLER: $SCHLUESSEL liess sich nicht setzen." >&2
exit 1
}
done
# Share-Erweiterung ins Xcode-Projekt haengen.
#
# Aus demselben Grund wie die Team-Kennung und der Standort-Schluessel oben:
+21 -13
View File
@@ -53,6 +53,11 @@ const ZIEL_NAME = "DataMetric360Share"
const BUNDLE_ID = "app.datametric360.teilen"
const GRUPPE = "group.app.datametric360"
/* Eigene Capacitor-Plugins der App - je eine Swift-Datei, die neben der
Erweiterung ins App-Ziel gehört. Sie liegen aus demselben Grund unter
native/ wie alles andere hier: ios/ ist gitignored und wird neu erzeugt. */
const PLUGIN_DATEIEN = ["BelegZwischenablage.swift", "KalenderTermin.swift"]
/** pbxproj-Wert ohne die optionalen Anfuehrungszeichen. */
const entquotet = (wert) => String(wert ?? "").replace(/^"|"$/g, "")
const SCHEMA = "datametric360"
@@ -87,10 +92,9 @@ for (const datei of ["ShareViewController.swift", "Info.plist", `${ZIEL_NAME}.en
copyFileSync(join(quelleErw, datei), join(zielErw, datei))
}
copyFileSync(join(APP, "native", "App.entitlements"), join(iosApp, "App", "App.entitlements"))
copyFileSync(
join(APP, "native", "BelegZwischenablage.swift"),
join(iosApp, "App", "BelegZwischenablage.swift"),
)
for (const datei of PLUGIN_DATEIEN) {
copyFileSync(join(APP, "native", datei), join(iosApp, "App", datei))
}
melden(`Quellen nach ios/App/${ZIEL_NAME}/ kopiert`)
/* ------------------------------------------------------------- URL-Schema */
@@ -129,24 +133,28 @@ if (!appPlist.includes("CFBundleURLTypes")) {
const projekt = xcode.project(pbxPfad)
projekt.parseSync()
/* ------------------------------------------- Zwischenablage-Plugin (App-Ziel)
/* ------------------------------------------------ Eigene Plugins (App-Ziel)
Steht VOR dem Ausstieg unten: die Erweiterung ist nach dem ersten Lauf
vorhanden, das Plugin muss trotzdem bei jedem Bau geprüft werden - ios/
vorhanden, die Plugins müssen trotzdem bei jedem Bau geprüft werden - ios/
wird von `npx cap add ios` jederzeit neu erzeugt.
`addSourceFile` ohne Gruppe hängt die Datei an die ERSTE Sources-Phase des
Projekts, und das ist die des App-Ziels - genau die richtige. (Mit Gruppe
landete die Datei nur im Navigator; daran ist am 02.09.2026 die Erweiterung
ohne Programm entstanden, siehe unten.) */
const PLUGIN_DATEI = "BelegZwischenablage.swift"
const schonDrin = JSON.stringify(projekt.pbxSourcesBuildPhaseObj()).includes(PLUGIN_DATEI)
if (schonDrin) {
melden("Zwischenablage-Plugin war bereits im App-Ziel")
} else {
projekt.addSourceFile(`App/${PLUGIN_DATEI}`)
let pluginsGeaendert = false
for (const datei of PLUGIN_DATEIEN) {
if (JSON.stringify(projekt.pbxSourcesBuildPhaseObj()).includes(datei)) {
melden(`${datei} war bereits im App-Ziel`)
continue
}
projekt.addSourceFile(`App/${datei}`)
melden(`${datei} ins App-Ziel gehängt`)
pluginsGeaendert = true
}
if (pluginsGeaendert) {
writeFileSync(pbxPfad, projekt.writeSync())
melden("Zwischenablage-Plugin ins App-Ziel gehängt")
// Nach dem Schreiben neu einlesen: der Rest des Skripts arbeitet sonst auf
// einem Stand, der die eigene Änderung nicht kennt.
projekt.parseSync()