forked from fritob/Camper-Monitor
Komplikation fürs Zifferblatt, und die App heisst jetzt VanControl Pro
Zwei Dinge in einem Commit, weil sie sich dieselben Dateien teilen: project.pbxproj und WatchRootView.swift tragen beides. **Komplikation.** Neues Target CamperMonitorComplication, auf watchOS sind Komplikationen WidgetKit-Widgets. Es wird in die Watch-App eingebettet (PlugIns) und bietet die vier Zubehör-Familien an. Ein Tipp öffnet die App direkt auf der Nivellierung statt in der Geräteliste: Die Komplikation hängt eine Adresse an, die Watch-App führt dafür jetzt einen Navigationsweg, den sie von aussen setzen kann. Die Adresse steht in Shared/WatchDeepLink.swift, weil beide Seiten sie brauchen – ein Tippfehler auf einer Seite bliebe sonst stumm. Bewusst ohne Messwert: Eine Komplikation läuft in einem eigenen Prozess und käme an die Werte nur über eine App-Gruppe, und die verlangt eine bezahlte Mitgliedschaft. Ein Wert, der beim Blick aufs Zifferblatt Stunden alt sein kann, wäre ohnehin schlimmer als keiner – man glaubt ihm. Die Komplikation tut deshalb genau eine Sache, und die zuverlässig. **Rebranding.** Der sichtbare Name ist überall VanControl Pro: CFBundleDisplayName beider Apple-Targets, Android-Label, die Texte in beiden Apps, beide READMEs und der Name der APK im Gitea-Ablauf. Die Kennungen bleiben, wie sie sind – Bundle-IDs, Android-Paket, Target-, Ordner- und Schemanamen. Eine geänderte Bundle-ID ist für iOS eine neue App: Geräte, Fahrzeugprofile und Victron-Schlüssel wären weg, dazu neue Profile und eine neu zu koppelnde Watch-App. Sichtbar ist davon nichts, also gibt es dafür auch keinen Grund. Geprüft: alle drei Apple-Targets bauen, die Erweiterung liegt im Watch-Bundle unter PlugIns, die Anzeigenamen stimmen im gebauten Bundle, Tests grün. Die neue Bundle-ID der Erweiterung braucht beim ersten Lauf aus Xcode ein Profil, das Xcode selbst anlegt. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -41,9 +41,7 @@ struct WatchLevelView: View {
|
||||
.padding(.top, 2)
|
||||
}
|
||||
|
||||
NavigationLink {
|
||||
WatchAlignView()
|
||||
} label: {
|
||||
NavigationLink(value: WatchRoute.align) {
|
||||
Label("Ausrichten", systemImage: "arrow.left.and.right")
|
||||
}
|
||||
.buttonStyle(.borderedProminent)
|
||||
|
||||
@@ -6,10 +6,28 @@ struct WatchRootView: View {
|
||||
@Environment(PhoneLink.self) private var link
|
||||
@Environment(WatchLevelRadio.self) private var radio
|
||||
|
||||
/// Der Weg durch die Ansichten liegt hier, damit ihn auch die Komplikation
|
||||
/// setzen kann: Ein Tipp aufs Zifferblatt springt direkt zur Nivellierung,
|
||||
/// statt in der Geräteliste zu landen.
|
||||
@State private var path: [WatchRoute] = []
|
||||
|
||||
var body: some View {
|
||||
NavigationStack {
|
||||
NavigationStack(path: $path) {
|
||||
content
|
||||
.navigationTitle(link.payload?.profile.name ?? "Camper")
|
||||
.navigationDestination(for: WatchRoute.self) { route in
|
||||
switch route {
|
||||
case .level: WatchLevelView()
|
||||
case .align: WatchAlignView()
|
||||
case .device(let id): WatchDeviceDetailView(deviceID: id)
|
||||
}
|
||||
}
|
||||
}
|
||||
.onOpenURL { url in
|
||||
guard WatchDeepLink.isLevel(url) else { return }
|
||||
// Nicht anhängen, sondern ersetzen: Wer vom Zifferblatt kommt, will
|
||||
// die Nivellierung sehen und nicht einen Stapel von vorhin.
|
||||
path = [.level]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,9 +36,7 @@ struct WatchRootView: View {
|
||||
// Die Nivellierung steht immer oben und immer da: Sie kommt vom
|
||||
// Sensor selbst und braucht das iPhone nicht.
|
||||
Section {
|
||||
NavigationLink {
|
||||
WatchLevelView()
|
||||
} label: {
|
||||
NavigationLink(value: WatchRoute.level) {
|
||||
LevelSummaryRow(reading: WatchLevelReading(radio: radio, phone: link))
|
||||
}
|
||||
}
|
||||
@@ -28,9 +44,7 @@ struct WatchRootView: View {
|
||||
if let payload = link.payload {
|
||||
Section {
|
||||
ForEach(payload.devices.filter { $0.role != .leveling }) { device in
|
||||
NavigationLink {
|
||||
WatchDeviceDetailView(deviceID: device.id)
|
||||
} label: {
|
||||
NavigationLink(value: WatchRoute.device(device.id)) {
|
||||
DeviceRow(device: device)
|
||||
}
|
||||
}
|
||||
@@ -55,7 +69,7 @@ struct WatchRootView: View {
|
||||
VStack(spacing: 4) {
|
||||
Label("Warte auf das iPhone", systemImage: "iphone.gen3.radiowaves.left.and.right")
|
||||
.font(.footnote.weight(.medium))
|
||||
Text("Dort muss Camper Monitor geöffnet sein.")
|
||||
Text("Dort muss VanControl Pro geöffnet sein.")
|
||||
.font(.caption2)
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
@@ -63,6 +77,14 @@ struct WatchRootView: View {
|
||||
}
|
||||
}
|
||||
|
||||
/// Wohin die Uhr springen kann. Als eigener Typ, weil der Weg von aussen
|
||||
/// gesetzt wird – von der Komplikation.
|
||||
enum WatchRoute: Hashable {
|
||||
case level
|
||||
case align
|
||||
case device(UUID)
|
||||
}
|
||||
|
||||
/// Eine Gerätezeile: Name klein, Hauptwert gross – auf dem kleinen Bildschirm
|
||||
/// zählt nur der eine Wert, wegen dem man den Arm hebt.
|
||||
struct DeviceRow: View {
|
||||
|
||||
Reference in New Issue
Block a user