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
38
Shared/WalkActivityAttributes.swift
Normal file
38
Shared/WalkActivityAttributes.swift
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
import Foundation
|
||||
import ActivityKit
|
||||
|
||||
/// Live Activity attributes for a running Gassi-Tour. Lives in `Shared/` and
|
||||
/// is compiled into both the app target (which starts/updates/ends activities)
|
||||
/// and the widget extension (which renders the lock screen + Dynamic Island).
|
||||
struct WalkActivityAttributes: ActivityAttributes {
|
||||
public typealias ContentState = WalkActivityState
|
||||
|
||||
public struct WalkActivityState: Codable, Hashable {
|
||||
public var distanceMeters: Double
|
||||
public var elapsedSeconds: Int
|
||||
public var pointCount: Int
|
||||
public var isPaused: Bool
|
||||
public var isAutoPaused: Bool
|
||||
|
||||
public init(
|
||||
distanceMeters: Double,
|
||||
elapsedSeconds: Int,
|
||||
pointCount: Int,
|
||||
isPaused: Bool,
|
||||
isAutoPaused: Bool
|
||||
) {
|
||||
self.distanceMeters = distanceMeters
|
||||
self.elapsedSeconds = elapsedSeconds
|
||||
self.pointCount = pointCount
|
||||
self.isPaused = isPaused
|
||||
self.isAutoPaused = isAutoPaused
|
||||
}
|
||||
}
|
||||
|
||||
/// Walk start time — fixed for the duration of the activity.
|
||||
public var startedAt: Date
|
||||
|
||||
public init(startedAt: Date) {
|
||||
self.startedAt = startedAt
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue