Replaces the ActivityKit boilerplate with a real lock screen/Dynamic Island UI driven by live pitch/roll readings, toggled from the leveling device's detail screen. Since iOS 17 shows any running Live Activity on CarPlay's dashboard without a dedicated CarPlay app entitlement, this covers the requested CarPlay use case without one. Also fixes the widget extension never being embedded into the app (missing Embed Foundation Extensions build phase and target dependency), which meant no widget or Live Activity could ever have rendered regardless of code changes. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
53 lines
2.0 KiB
Swift
53 lines
2.0 KiB
Swift
import SwiftUI
|
||
|
||
@main
|
||
struct CamperMonitorApp: App {
|
||
@State private var store: DeviceStore
|
||
@State private var bluetooth: BluetoothManager
|
||
@State private var watch: PhoneWatchLink
|
||
@State private var levelActivity: LevelActivityManager
|
||
@Environment(\.scenePhase) private var scenePhase
|
||
|
||
init() {
|
||
let store = DeviceStore()
|
||
let bluetooth = BluetoothManager(store: store)
|
||
let levelActivity = LevelActivityManager()
|
||
bluetooth.activityManager = levelActivity
|
||
_store = State(initialValue: store)
|
||
_bluetooth = State(initialValue: bluetooth)
|
||
_watch = State(initialValue: PhoneWatchLink(store: store, bluetooth: bluetooth))
|
||
_levelActivity = State(initialValue: levelActivity)
|
||
}
|
||
|
||
var body: some Scene {
|
||
WindowGroup {
|
||
DashboardView()
|
||
.environment(store)
|
||
.environment(bluetooth)
|
||
.environment(watch)
|
||
.environment(levelActivity)
|
||
.task { watch.activate() }
|
||
}
|
||
.onChange(of: scenePhase) { _, phase in
|
||
// Im Hintergrund darf ohne Service-Filter ohnehin nicht gescannt
|
||
// werden, also Funk sparen und beim Zurückkommen neu starten.
|
||
//
|
||
// Ausnahme: Solange jemand auf die Uhr schaut, läuft es weiter. Beim
|
||
// Rangieren liegt das iPhone in der Halterung mit dunklem Bildschirm
|
||
// – hörte das Funkgerät dann auf, wäre die Anzeige am Handgelenk
|
||
// genau dann tot, wenn sie gebraucht wird. Die verbundenen Geräte
|
||
// (Neigungsmesser, BMS, Kühlbox) liefern im Hintergrund weiter; die
|
||
// Victron-Werbedaten nicht, dafür müsste ohne Filter gesucht werden.
|
||
watch.isAppInBackground = phase != .active
|
||
switch phase {
|
||
case .active:
|
||
bluetooth.start()
|
||
case .background:
|
||
if !watch.wantsLiveUpdates { bluetooth.stop() }
|
||
default:
|
||
break
|
||
}
|
||
}
|
||
}
|
||
}
|