Author SHA1 Message Date
fototeddyandClaude Sonnet 5 8401f62d91 California-Seitenansicht eng zuschneiden statt in quadratischer Leinwand
Die Vorlage lag auf einer quadratischen 1254×1254-Leinwand, der Van
darin füllte aber nur rund 59% der Höhe – bei deklariertem
sideAspect = 1 (quadratisch) rechnete SwiftUI die Anzeigegrösse für
dieses volle Quadrat, wodurch der Van in der gemeinsamen Bildhülle
deutlich kleiner erschien als Vanster, dessen Vorlage eng auf die
Silhouette zugeschnitten ist.

Bild jetzt auf den Inhalt zugeschnitten (plus kleiner Rand, wie bei
Vanster), sideAspect entsprechend von 1 auf das tatsächliche Verhältnis
der zugeschnittenen Vorlage (1212×790) angepasst. In beiden
Asset-Katalogen ersetzt (iPhone und Watch, siehe vorherigen Commit zur
Watch-Fahrzeuggrafik).

Die Heckansicht war laut Rückmeldung bereits optisch stimmig und blieb
unverändert.

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

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-09 20:27:20 +02:00
fototeddyandClaude Sonnet 5 c45cf36920 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>
2026-09-09 20:22:32 +02:00
fototeddyandClaude Sonnet 5 47ead9b006 Watch-App-Icon an das neue Haupt-App-Icon angleichen
VanControlWatch hat ein eigenes, vom iPhone-Target unabhängiges
AppIcon.appiconset – das zeigte beim Einbinden von App1/App2 noch das
alte Logo. Jetzt dieselbe Vorlage wie das primäre iPhone-Icon
(App1-Testflight), damit iPhone- und Watch-App auf dem Homescreen
zusammengehörig aussehen.

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

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-09 20:14:17 +02:00
14 changed files with 54 additions and 20 deletions
+1 -1
View File
@@ -39,7 +39,7 @@ enum VehicleGraphicStyle: String, CaseIterable, Identifiable, Codable, Sendable
var sideAspect: Double { var sideAspect: Double {
switch self { switch self {
case .vanster: return VehicleTilt.sideAspect case .vanster: return VehicleTilt.sideAspect
case .california: return 1 case .california: return 1212.0 / 790.0
} }
} }
+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;
Binary file not shown.

Before

Width:  |  Height:  |  Size: 323 KiB

After

Width:  |  Height:  |  Size: 311 KiB

+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.

Before

Width:  |  Height:  |  Size: 1.1 MiB

After

Width:  |  Height:  |  Size: 1.1 MiB

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: 311 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",