Phase 4.A.1: Live Activity + Dynamic Island für laufende Gassi-Tour
Neues Widget-Extension-Target BanYaroGoWidgetExtension: - Bundle-ID app.banyaro.ios.BanYaroGoWidget - NSExtensionPointIdentifier = com.apple.widgetkit-extension - Synced root group + explizite Info.plist + Embed-Phase in App-Target - Cross-Membership der Shared/WalkActivityAttributes.swift in beiden Targets Shared/WalkActivityAttributes.swift: - ActivityAttributes mit startedAt (fix) - ContentState mit distanceMeters, elapsedSeconds, pointCount, isPaused, isAutoPaused BanYaroGoWidget/WalkLiveActivity.swift: - Lock-Screen-View: Pfote-Icon + Status-Pille (Live/Pause/Auto-Pause) + Stats-Spalten (Distanz/Dauer/Punkte) - Dynamic Island compact: Pfote leading, Distanz trailing - Dynamic Island minimal: nur Pfote - Dynamic Island expanded: Distanz/Dauer/Status mit Pfote zentriert WalkActivityController: - @MainActor Facade um ActivityKit - start() prüft areActivitiesEnabled, killt orphaned current, request mit Initial-State - update() async via Task - end() mit dismissalPolicy.immediate TrackingView: - .onChange(of: tracker.isTracking) → Start/End - persistTicker (5s) → update - .onChange(of: tracker.isPaused/isAutoPaused) → sofort update für saubere UX BanYaroGo-Info.plist: NSSupportsLiveActivities = true
This commit is contained in:
parent
fec7c79b05
commit
500a645bfd
8 changed files with 458 additions and 0 deletions
|
|
@ -34,7 +34,17 @@ struct TrackingView: View {
|
|||
.onReceive(persistTicker) { _ in
|
||||
tracker.checkAutoPause()
|
||||
persistActive()
|
||||
updateLiveActivity()
|
||||
}
|
||||
.onChange(of: tracker.isTracking) { _, isTracking in
|
||||
if isTracking {
|
||||
startLiveActivity()
|
||||
} else {
|
||||
WalkActivityController.end()
|
||||
}
|
||||
}
|
||||
.onChange(of: tracker.isPaused) { _, _ in updateLiveActivity() }
|
||||
.onChange(of: tracker.isAutoPaused) { _, _ in updateLiveActivity() }
|
||||
.onAppear { offerResumeIfNeeded() }
|
||||
.sheet(isPresented: $showFinishSheet) {
|
||||
FinishWalkSheet(
|
||||
|
|
@ -320,6 +330,29 @@ struct TrackingView: View {
|
|||
|
||||
// MARK: - Helpers
|
||||
|
||||
private func startLiveActivity() {
|
||||
guard let startedAt = tracker.startedAt else { return }
|
||||
WalkActivityController.start(
|
||||
startedAt: startedAt,
|
||||
initialState: liveActivityState()
|
||||
)
|
||||
}
|
||||
|
||||
private func updateLiveActivity() {
|
||||
guard tracker.isTracking else { return }
|
||||
WalkActivityController.update(liveActivityState())
|
||||
}
|
||||
|
||||
private func liveActivityState() -> WalkActivityAttributes.WalkActivityState {
|
||||
WalkActivityAttributes.WalkActivityState(
|
||||
distanceMeters: tracker.totalDistanceMeters,
|
||||
elapsedSeconds: tracker.effectiveElapsedSeconds,
|
||||
pointCount: tracker.points.count,
|
||||
isPaused: tracker.isPaused,
|
||||
isAutoPaused: tracker.isAutoPaused
|
||||
)
|
||||
}
|
||||
|
||||
private func formatDuration(_ seconds: Int) -> String {
|
||||
let h = seconds / 3600
|
||||
let m = (seconds % 3600) / 60
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue