forked from fritob/Camper-Monitor
Demo-Modus: Persistenz und Kühlbox-Bedienung reparieren, Live Activity aktivieren
Drei vom Nutzer im Testbuild gefundene Fehler: * DeviceStore.save() schrieb auch im Demo-Modus in UserDefaults. Jede Änderung während aktivem Demo-Modus (z.B. Fahrzeuggrafik oder Einbaulage ändern) persistierte damit die erfundenen Fahrzeuge/Geräte dauerhaft – sie blieben nach dem Deaktivieren des Demo-Modus stehen. save() ist jetzt im Demo-Modus ein no-op. * Die Kühlbox-Schalter (Ein/Aus, Eco/Max, Solltemperatur, Sperre) liefen über sendFridgeSettings(), das eine echte Bluetooth-Verbindung voraussetzt (`managed`-Eintrag) – im Demo-Modus gibt es die nie, die Schalter taten also nichts. Im Demo-Modus wird der angezeigte AlpicoolState jetzt direkt geändert, ohne den Umweg über einen Stellbefehl. * Der Live-Activity-Schalter liess sich nicht einschalten, weil dem Haupt-App-Target der Info.plist-Schlüssel NSSupportsLiveActivities fehlte – Activity.request() wirft ohne ihn, wird aber vom Aufrufer stillschweigend abgefangen, sodass der Schalter beim Antippen einfach auf Aus zurückspringt. Build (App + Watch) und Tests grün. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
b956324234
commit
eed8f33e30
@@ -507,6 +507,7 @@
|
|||||||
INFOPLIST_FILE = "Config/VanControl-Info.plist";
|
INFOPLIST_FILE = "Config/VanControl-Info.plist";
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = "VanControl Pro";
|
INFOPLIST_KEY_CFBundleDisplayName = "VanControl Pro";
|
||||||
INFOPLIST_KEY_NSBluetoothAlwaysUsageDescription = "Zum Auslesen von Victron-Geraeten und dem Daly BMS per Bluetooth.";
|
INFOPLIST_KEY_NSBluetoothAlwaysUsageDescription = "Zum Auslesen von Victron-Geraeten und dem Daly BMS per Bluetooth.";
|
||||||
|
INFOPLIST_KEY_NSSupportsLiveActivities = YES;
|
||||||
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
|
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
|
||||||
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
|
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
|
||||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||||
@@ -538,6 +539,7 @@
|
|||||||
INFOPLIST_FILE = "Config/VanControl-Info.plist";
|
INFOPLIST_FILE = "Config/VanControl-Info.plist";
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = "VanControl Pro";
|
INFOPLIST_KEY_CFBundleDisplayName = "VanControl Pro";
|
||||||
INFOPLIST_KEY_NSBluetoothAlwaysUsageDescription = "Zum Auslesen von Victron-Geraeten und dem Daly BMS per Bluetooth.";
|
INFOPLIST_KEY_NSBluetoothAlwaysUsageDescription = "Zum Auslesen von Victron-Geraeten und dem Daly BMS per Bluetooth.";
|
||||||
|
INFOPLIST_KEY_NSSupportsLiveActivities = YES;
|
||||||
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
|
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
|
||||||
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
|
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
|
||||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||||
|
|||||||
@@ -394,6 +394,10 @@ final class BluetoothManager: NSObject {
|
|||||||
// MARK: - Kühlbox steuern (vom Hauptthread aufgerufen)
|
// MARK: - Kühlbox steuern (vom Hauptthread aufgerufen)
|
||||||
|
|
||||||
func updateFridgeZoneMode(for device: ConfiguredDevice) {
|
func updateFridgeZoneMode(for device: ConfiguredDevice) {
|
||||||
|
guard !isDemo else {
|
||||||
|
applyDemoFridgeChange(for: device.id) { $0.zoneMode = device.fridgeZoneMode }
|
||||||
|
return
|
||||||
|
}
|
||||||
let deviceID = device.id, mode = device.fridgeZoneMode
|
let deviceID = device.id, mode = device.fridgeZoneMode
|
||||||
queue.async {
|
queue.async {
|
||||||
guard let session = self.session(for: deviceID) else { return }
|
guard let session = self.session(for: deviceID) else { return }
|
||||||
@@ -404,21 +408,51 @@ final class BluetoothManager: NSObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func setFridgeTarget(_ celsius: Int, zone: AlpicoolState.Zone, for deviceID: UUID) {
|
func setFridgeTarget(_ celsius: Int, zone: AlpicoolState.Zone, for deviceID: UUID) {
|
||||||
|
guard !isDemo else {
|
||||||
|
applyDemoFridgeChange(for: deviceID) { state in
|
||||||
|
switch zone {
|
||||||
|
case .left: state.leftTarget = celsius
|
||||||
|
case .right: state.rightTarget = celsius
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
sendFridgeSettings(for: deviceID) { _ in AlpicoolState.setTarget(zone: zone, to: celsius) }
|
sendFridgeSettings(for: deviceID) { _ in AlpicoolState.setTarget(zone: zone, to: celsius) }
|
||||||
}
|
}
|
||||||
|
|
||||||
func setFridgePower(_ on: Bool, for deviceID: UUID) {
|
func setFridgePower(_ on: Bool, for deviceID: UUID) {
|
||||||
|
guard !isDemo else {
|
||||||
|
applyDemoFridgeChange(for: deviceID) { $0.isPoweredOn = on }
|
||||||
|
return
|
||||||
|
}
|
||||||
sendFridgeSettings(for: deviceID) { $0.settingsCommand(poweredOn: on) }
|
sendFridgeSettings(for: deviceID) { $0.settingsCommand(poweredOn: on) }
|
||||||
}
|
}
|
||||||
|
|
||||||
func setFridgeEco(_ eco: Bool, for deviceID: UUID) {
|
func setFridgeEco(_ eco: Bool, for deviceID: UUID) {
|
||||||
|
guard !isDemo else {
|
||||||
|
applyDemoFridgeChange(for: deviceID) { $0.runMode = eco ? 1 : 0 }
|
||||||
|
return
|
||||||
|
}
|
||||||
sendFridgeSettings(for: deviceID) { $0.settingsCommand(eco: eco) }
|
sendFridgeSettings(for: deviceID) { $0.settingsCommand(eco: eco) }
|
||||||
}
|
}
|
||||||
|
|
||||||
func setFridgeLock(_ locked: Bool, for deviceID: UUID) {
|
func setFridgeLock(_ locked: Bool, for deviceID: UUID) {
|
||||||
|
guard !isDemo else {
|
||||||
|
applyDemoFridgeChange(for: deviceID) { $0.isLocked = locked }
|
||||||
|
return
|
||||||
|
}
|
||||||
sendFridgeSettings(for: deviceID) { $0.settingsCommand(locked: locked) }
|
sendFridgeSettings(for: deviceID) { $0.settingsCommand(locked: locked) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Im Demo-Modus gibt es keine Box, die einen Stellbefehl bestätigt – die
|
||||||
|
/// Änderung wird direkt im angezeigten Zustand nachgezogen, auf dem
|
||||||
|
/// Hauptthread, wo `fridgeStates` lebt.
|
||||||
|
private func applyDemoFridgeChange(for deviceID: UUID, _ change: (inout AlpicoolState) -> Void) {
|
||||||
|
var state = fridgeStates[deviceID] ?? DemoData.fridgeState
|
||||||
|
change(&state)
|
||||||
|
fridgeStates[deviceID] = state
|
||||||
|
}
|
||||||
|
|
||||||
/// Der Einstellungsblock wird aus dem zuletzt empfangenen Zustand gebaut –
|
/// Der Einstellungsblock wird aus dem zuletzt empfangenen Zustand gebaut –
|
||||||
/// und zwar auf der Funk-Queue, wo dieser Zustand lebt.
|
/// und zwar auf der Funk-Queue, wo dieser Zustand lebt.
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -244,7 +244,12 @@ final class DeviceStore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Im Demo-Modus wird nichts geschrieben – sonst überlebten die erfundenen
|
||||||
|
/// Fahrzeuge und Geräte das Ausschalten des Demo-Modus, weil z.B. das
|
||||||
|
/// Ändern der Fahrzeuggrafik oder der Einbaulage ganz normal `save()`
|
||||||
|
/// aufruft.
|
||||||
private func save() {
|
private func save() {
|
||||||
|
guard !DemoData.isEnabled else { return }
|
||||||
let defaults = UserDefaults.standard
|
let defaults = UserDefaults.standard
|
||||||
if let data = try? JSONEncoder().encode(devices) {
|
if let data = try? JSONEncoder().encode(devices) {
|
||||||
defaults.set(data, forKey: Self.devicesKey)
|
defaults.set(data, forKey: Self.devicesKey)
|
||||||
|
|||||||
Reference in New Issue
Block a user