1.1: Offline-Cache + Outbox für Touren/Tagebuch, WeatherKit-Fix, Aufräumen
App-Review-Fix (Guideline 2.1 WeatherKit): - OneShotLocation: deterministisches async resolve() mit 10s-Timeout statt onChange-Lauschen; WetterView lädt bei fehlendem Standort einen Berlin-Fallback → kein ewiges Hängen bei "Hole Standort…", WeatherKit ist immer sichtbar. Offline-Lesen (SwiftData): - CachedRoute/CachedDiaryEntry/CachedImage + CachedAsyncImage: Touren, Tagebuch und Fotos werden cache-first geladen und sind offline verfügbar. - Cache wird bei Logout/401 geleert (RootView), kein Durchschimmern fremder User. Offline-Speichern (Outbox): - PendingRoute/PendingRoutePhoto: Tour inkl. unterwegs hinzugefügter Fotos wird offline lokal gesichert und automatisch hochgeladen (Touren-Tab + App-Start). - Touren-Liste zeigt offline gesicherte Touren mit "wird hochgeladen"-Badge. FinishWalkSheet: - Dismiss-Schutz: Speichern-Dialog lässt sich nicht mehr wegwischen — eine aufgezeichnete Tour geht nicht mehr durch Runterwischen verloren. Wetter: - Ortslabel (Reverse-Geocoding; Fallback "Berlin · Näherung"). - Saubere Offline-Meldung statt rohem networkError. Aufräumen: - Doppeltes "Gassi-Treffen" im Mehr-Tab entfernt. - Veraltete Phase-1/2-Texte neu getextet. - Tote DogsListView gelöscht (Hund-Wechsel läuft über den Heim-Picker).
This commit is contained in:
parent
9e51f3910e
commit
a2646a18ef
16 changed files with 769 additions and 199 deletions
|
|
@ -25,6 +25,7 @@ struct FinishWalkSheet: View {
|
|||
|
||||
@State private var saveState: SaveState = .idle
|
||||
@State private var errorMessage: String?
|
||||
@State private var savedOffline = false
|
||||
|
||||
private enum SaveState: Equatable {
|
||||
case idle
|
||||
|
|
@ -144,7 +145,15 @@ struct FinishWalkSheet: View {
|
|||
.onChange(of: photoSelection) { _, newItems in
|
||||
Task { await loadPhotos(from: newItems) }
|
||||
}
|
||||
.interactiveDismissDisabled(saveState != .idle)
|
||||
// Immer blockieren: eine aufgezeichnete Tour darf nicht durch
|
||||
// versehentliches Runterwischen verloren gehen — nur „Speichern"
|
||||
// oder „Verwerfen" beenden das Sheet.
|
||||
.interactiveDismissDisabled(true)
|
||||
.alert("Offline gespeichert", isPresented: $savedOffline) {
|
||||
Button("OK") { onSaved(); dismiss() }
|
||||
} message: {
|
||||
Text("Keine Internetverbindung. Die Tour ist lokal gesichert und wird automatisch hochgeladen, sobald du wieder online bist.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -283,6 +292,15 @@ struct FinishWalkSheet: View {
|
|||
do {
|
||||
route = try await APIClient.shared.post("/api/routes", body: body)
|
||||
} catch {
|
||||
// Transportfehler (offline) → Tour inkl. Fotos lokal in die Outbox,
|
||||
// wird automatisch hochgeladen, sobald wieder Netz da ist.
|
||||
if error is URLError {
|
||||
OfflineCache.savePendingRoute(body: body, photos: photoData, in: modelContext)
|
||||
await syncHealthIfEnabled()
|
||||
saveState = .idle
|
||||
savedOffline = true
|
||||
return
|
||||
}
|
||||
errorMessage = error.localizedDescription
|
||||
saveState = .idle
|
||||
return
|
||||
|
|
@ -321,19 +339,21 @@ struct FinishWalkSheet: View {
|
|||
saveState = .uploadingPhotos(done: photoData.count, total: photoData.count)
|
||||
}
|
||||
|
||||
// Apple Health sync (only if user opted in)
|
||||
if healthKitSyncEnabled, points.count >= 2 {
|
||||
let endedAt = Date.now
|
||||
let startedAt = endedAt.addingTimeInterval(-Double(durationSeconds))
|
||||
await WalkHealthSync.shared.saveWalk(
|
||||
points: points,
|
||||
startedAt: startedAt,
|
||||
endedAt: endedAt,
|
||||
distanceMeters: distanceMeters
|
||||
)
|
||||
}
|
||||
await syncHealthIfEnabled()
|
||||
|
||||
onSaved()
|
||||
dismiss()
|
||||
}
|
||||
|
||||
private func syncHealthIfEnabled() async {
|
||||
guard healthKitSyncEnabled, points.count >= 2 else { return }
|
||||
let endedAt = Date.now
|
||||
let startedAt = endedAt.addingTimeInterval(-Double(durationSeconds))
|
||||
await WalkHealthSync.shared.saveWalk(
|
||||
points: points,
|
||||
startedAt: startedAt,
|
||||
endedAt: endedAt,
|
||||
distanceMeters: distanceMeters
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue