Fahrzeuggrafik-Stil (Vanster/California) auf die Watch ausweiten

Die Uhr zeigte in der Fahrzeug-Ansicht bislang immer Vanster fest
verdrahtet, unabhängig von der Auswahl am iPhone – das galt schon vor
dieser Session, nicht erst seit dem Solar-Merge.

WatchDevice trägt jetzt vehicleGraphicStyle (nur beim Neigungsmesser
belegt, wie orientation), von PhoneWatchLink beim Aufbau der Nutzlast
gefüllt. WatchVehicleView nimmt den Stil als Parameter statt der fest
verdrahteten Vanster-Bildnamen, WatchLevelView reicht ihn aus dem
zuletzt vom iPhone übertragenen Stand durch. California-Bilder dafür
zusätzlich in den Watch-eigenen Asset-Katalog kopiert (die Uhr hat
einen eigenen, vom iPhone getrennten Katalog).

Ausgewählt wird der Stil weiterhin nur am iPhone (Neigungsmesser
einrichten → Fahrzeuggrafik). Persistenz war dafür schon vorhanden:
vehicleGraphicStyle ist ein normales, codiertes Feld auf
ConfiguredDevice ohne eigene encode(to:)-Überschreibung – wird also
schon beim Speichern mitgeschrieben.

Nebenbei: Xcode hat beim Bearbeiten den Build-Zähler auf 2 gesetzt und
LSApplicationCategoryType (Dienstprogramme) ergänzt – unverändert
übernommen.

Build (App + Watch) und Tests grün.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
fototeddy
2026-09-09 20:22:32 +02:00
co-authored by Claude Sonnet 5
parent 47ead9b006
commit c45cf36920
11 changed files with 53 additions and 19 deletions
+4
View File
@@ -92,6 +92,10 @@ struct WatchDevice: Codable, Equatable, Identifiable, Sendable {
/// den Neigungsmesser selbst an und braucht die Zuordnung deshalb auch /// den Neigungsmesser selbst an und braucht die Zuordnung deshalb auch
/// eingestellt wird sie weiterhin nur am iPhone. /// eingestellt wird sie weiterhin nur am iPhone.
var orientation: SensorOrientation? var orientation: SensorOrientation?
/// Ebenfalls nur beim Neigungsmesser: welche Fahrzeuggrafik die
/// Fahrzeug-Ansicht zeigt. Ausgewählt wird sie nur am iPhone, die Uhr
/// übernimmt nur die Anzeige.
var vehicleGraphicStyle: VehicleGraphicStyle?
/// Nur bei der Kühlbox belegt. /// Nur bei der Kühlbox belegt.
var fridge: WatchFridge? var fridge: WatchFridge?
+4 -3
View File
@@ -1190,13 +1190,14 @@ let watchPayload = WatchPayload(
devices: [ devices: [
WatchDevice(id: watchLevelID, name: "Nivellierung", role: .leveling, WatchDevice(id: watchLevelID, name: "Nivellierung", role: .leveling,
link: .live, snapshot: watchLevelSnapshot, link: .live, snapshot: watchLevelSnapshot,
level: watchLevel, orientation: watchOrientation, fridge: nil), level: watchLevel, orientation: watchOrientation,
vehicleGraphicStyle: .vanster, fridge: nil),
WatchDevice(id: watchBoosterID, name: "Ladebooster", role: .chargeBooster, WatchDevice(id: watchBoosterID, name: "Ladebooster", role: .chargeBooster,
link: .failed("Nicht gefunden"), snapshot: boosterSnapshot, link: .failed("Nicht gefunden"), snapshot: boosterSnapshot,
level: nil, orientation: nil, fridge: nil), level: nil, orientation: nil, vehicleGraphicStyle: nil, fridge: nil),
WatchDevice(id: watchFridgeID, name: "Kühlbox", role: .fridge, WatchDevice(id: watchFridgeID, name: "Kühlbox", role: .fridge,
link: .live, snapshot: nil, level: nil, link: .live, snapshot: nil, level: nil,
orientation: nil, fridge: watchFridge), orientation: nil, vehicleGraphicStyle: nil, fridge: watchFridge),
]) ])
// Der ganze Weg: verpacken, als WatchConnectivity-Wörterbuch lesen, vergleichen. // Der ganze Weg: verpacken, als WatchConnectivity-Wörterbuch lesen, vergleichen.
+10 -8
View File
@@ -501,7 +501,7 @@
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES; ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 2;
DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_ASSET_PATHS = "";
DEVELOPMENT_TEAM = V5C6Q86XJR; DEVELOPMENT_TEAM = V5C6Q86XJR;
ENABLE_PREVIEWS = YES; ENABLE_PREVIEWS = YES;
@@ -509,6 +509,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_ITSAppUsesNonExemptEncryption = NO; INFOPLIST_KEY_ITSAppUsesNonExemptEncryption = NO;
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities";
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_NSSupportsLiveActivities = YES;
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
@@ -536,7 +537,7 @@
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES; ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 2;
DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_ASSET_PATHS = "";
DEVELOPMENT_TEAM = V5C6Q86XJR; DEVELOPMENT_TEAM = V5C6Q86XJR;
ENABLE_PREVIEWS = YES; ENABLE_PREVIEWS = YES;
@@ -544,6 +545,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_ITSAppUsesNonExemptEncryption = NO; INFOPLIST_KEY_ITSAppUsesNonExemptEncryption = NO;
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities";
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_NSSupportsLiveActivities = YES;
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
@@ -569,7 +571,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 3;
DEVELOPMENT_TEAM = V5C6Q86XJR; DEVELOPMENT_TEAM = V5C6Q86XJR;
ENABLE_PREVIEWS = YES; ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
@@ -601,7 +603,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 3;
DEVELOPMENT_TEAM = V5C6Q86XJR; DEVELOPMENT_TEAM = V5C6Q86XJR;
ENABLE_PREVIEWS = YES; ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
@@ -631,7 +633,7 @@
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 2;
DEVELOPMENT_TEAM = V5C6Q86XJR; DEVELOPMENT_TEAM = V5C6Q86XJR;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = "Config/VanControlComplication-Info.plist"; INFOPLIST_FILE = "Config/VanControlComplication-Info.plist";
@@ -660,7 +662,7 @@
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 2;
DEVELOPMENT_TEAM = V5C6Q86XJR; DEVELOPMENT_TEAM = V5C6Q86XJR;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = "Config/VanControlComplication-Info.plist"; INFOPLIST_FILE = "Config/VanControlComplication-Info.plist";
@@ -691,7 +693,7 @@
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground; ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 2;
DEVELOPMENT_TEAM = V5C6Q86XJR; DEVELOPMENT_TEAM = V5C6Q86XJR;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = VanControlLiveActivity/Info.plist; INFOPLIST_FILE = VanControlLiveActivity/Info.plist;
@@ -720,7 +722,7 @@
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground; ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 2;
DEVELOPMENT_TEAM = V5C6Q86XJR; DEVELOPMENT_TEAM = V5C6Q86XJR;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = VanControlLiveActivity/Info.plist; INFOPLIST_FILE = VanControlLiveActivity/Info.plist;
+1
View File
@@ -135,6 +135,7 @@ final class PhoneWatchLink: NSObject {
snapshot: bluetooth.snapshots[device.id], snapshot: bluetooth.snapshots[device.id],
level: device.role == .leveling ? bluetooth.levelStates[device.id] : nil, level: device.role == .leveling ? bluetooth.levelStates[device.id] : nil,
orientation: device.role == .leveling ? device.sensorOrientation : nil, orientation: device.role == .leveling ? device.sensorOrientation : nil,
vehicleGraphicStyle: device.role == .leveling ? device.vehicleGraphicStyle : nil,
fridge: device.role == .fridge ? fridgeState(for: device) : nil) fridge: device.role == .fridge ? fridgeState(for: device) : nil)
} }
return WatchPayload(generatedAt: Date(), return WatchPayload(generatedAt: Date(),
Binary file not shown.

After

Width:  |  Height:  |  Size: 326 KiB

@@ -0,0 +1,10 @@
{
"images" : [
{
"filename" : "CaliforniaRear.png",
"idiom" : "universal"
}
],
"info" : { "author" : "xcode", "version" : 1 },
"properties" : { "template-rendering-intent" : "template" }
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 323 KiB

@@ -0,0 +1,10 @@
{
"images" : [
{
"filename" : "CaliforniaSide.png",
"idiom" : "universal"
}
],
"info" : { "author" : "xcode", "version" : 1 },
"properties" : { "template-rendering-intent" : "template" }
}
+2 -1
View File
@@ -50,7 +50,8 @@ struct LevelReadingPage: View {
ScrollView { ScrollView {
VStack(spacing: 8) { VStack(spacing: 8) {
if showsVehicle { if showsVehicle {
WatchVehicleView(pitch: reading.state.pitch, roll: reading.state.roll) WatchVehicleView(pitch: reading.state.pitch, roll: reading.state.roll,
style: link.payload?.levelDevice?.vehicleGraphicStyle ?? .vanster)
} else { } else {
WatchBubble(pitch: reading.state.pitch, roll: reading.state.roll) WatchBubble(pitch: reading.state.pitch, roll: reading.state.roll)
.frame(maxWidth: 110) .frame(maxWidth: 110)
+7 -4
View File
@@ -9,15 +9,18 @@ import SwiftUI
struct WatchVehicleView: View { struct WatchVehicleView: View {
let pitch: Double? let pitch: Double?
let roll: Double? let roll: Double?
/// Vom iPhone übernommen ausgewählt wird sie nur dort, siehe
/// `WatchDevice.vehicleGraphicStyle`.
var style: VehicleGraphicStyle = .vanster
/// Wie am iPhone dreifach überhöht zwei Grad wären sonst kaum zu sehen. /// Wie am iPhone dreifach überhöht zwei Grad wären sonst kaum zu sehen.
/// Die angeschriebenen Gradzahlen bleiben echt. /// Die angeschriebenen Gradzahlen bleiben echt.
var body: some View { var body: some View {
VStack(spacing: 8) { VStack(spacing: 8) {
panel(image: "VansterSide", angle: pitch, title: "Längs", panel(image: style.sideImageName, angle: pitch, title: "Längs",
lower: "Front", upper: "Heck", aspect: VehicleTilt.sideAspect) lower: "Front", upper: "Heck", aspect: style.sideAspect)
panel(image: "VansterRear", angle: roll, title: "Quer", panel(image: style.rearImageName, angle: roll, title: "Quer",
lower: "links", upper: "rechts", aspect: VehicleTilt.rearAspect) lower: "links", upper: "rechts", aspect: style.rearAspect)
} }
} }
+5 -3
View File
@@ -63,15 +63,17 @@ enum WatchDemo {
devices: [ devices: [
WatchDevice(id: levelID, name: "Nivellierung", role: .leveling, WatchDevice(id: levelID, name: "Nivellierung", role: .leveling,
link: .live, snapshot: level.snapshot(deviceID: levelID, rssi: -70), link: .live, snapshot: level.snapshot(deviceID: levelID, rssi: -70),
level: level, orientation: .identity, fridge: nil), level: level, orientation: .identity,
vehicleGraphicStyle: .vanster, fridge: nil),
WatchDevice(id: batteryID, name: "Bulltron 200 Ah", role: .bms, WatchDevice(id: batteryID, name: "Bulltron 200 Ah", role: .bms,
link: .live, snapshot: battery, level: nil, link: .live, snapshot: battery, level: nil,
orientation: nil, fridge: nil), orientation: nil, vehicleGraphicStyle: nil, fridge: nil),
WatchDevice(id: victronSolarID, name: "Solar Dach", role: .victronSolarCharger, WatchDevice(id: victronSolarID, name: "Solar Dach", role: .victronSolarCharger,
link: .live, snapshot: victronSolar, level: nil, link: .live, snapshot: victronSolar, level: nil,
orientation: nil, fridge: nil), orientation: nil, vehicleGraphicStyle: nil, fridge: nil),
WatchDevice(id: fridgeID, name: "Kühlbox", role: .fridge, WatchDevice(id: fridgeID, name: "Kühlbox", role: .fridge,
link: .live, snapshot: fridge, level: nil, orientation: nil, link: .live, snapshot: fridge, level: nil, orientation: nil,
vehicleGraphicStyle: nil,
fridge: WatchFridge(isLive: true, updated: now, fridge: WatchFridge(isLive: true, updated: now,
isPoweredOn: true, isEco: true, isLocked: false, isPoweredOn: true, isEco: true, isLocked: false,
isDualZone: false, unitSymbol: "°C", isDualZone: false, unitSymbol: "°C",