Files
Camper-Monitor/VanControl/Views/LevelSetupView.swift
T
fototeddyandClaude Sonnet 5 303a9735d0 App-Namen im iOS-Projekt auf VanControl vereinheitlichen
CamperMonitor (Haupt-Repo) und VanAligneiOS (aus dem gemergten
solar-integration-Branch) liefen unter zwei verschiedenen internen
Namen, obwohl die App nach aussen längst einheitlich "VanControl Pro"
heisst. Jetzt durchgängig VanControl:

- Ordner: CamperMonitor/, CamperMonitorWatch/, CamperMonitorComplication/,
  VanAligneiOSWidget/ → VanControl/, VanControlWatch/,
  VanControlComplication/, VanControlWidget/
- Xcode-Projekt: CamperMonitor.xcodeproj → VanControl.xcodeproj, alle
  Targets/Schemes/Produktnamen entsprechend umbenannt
- Bundle-Identifier auf Wunsch mitgeändert: de.s0.fototeddy.VanControl*
  (App noch nicht veröffentlicht); dabei auch die
  WKCompanionAppBundleIdentifier-Werte korrigiert, die noch das alte
  de.fritob-Präfix statt des tatsächlichen de.s0.fototeddy-Präfixes
  trugen
- Swift-Dateien/Typen: CamperMonitorApp → VanControlApp,
  VanAligneiOSWidget* → VanControlWidget*
- Config/*-Info.plist umbenannt, README.md/Tools/README.md/run-tests.sh
  auf die neuen Pfade angepasst

Bewusst unverändert: firmware/vanalign und alle Bezüge auf "VanAlign"
als Namen der Neigungsmesser-Hardware (eigenständiges Produkt, kein
App-Name) sowie der komplette Android/-Ordner.

Build (App, Watch, Debug) und Protokoll-Testlauf grün.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-06 21:25:28 +02:00

126 lines
4.9 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import SwiftUI
/// Einrichtung des Neigungsmessers: Einbaulage und Nullpunkt.
///
/// Beides wird einmal eingestellt und danach kaum wieder angefasst. In der
/// Geräteansicht standen die Knöpfe direkt unter der Libelle ein Fehlgriff
/// beim Ablesen verstellte dort den Nullpunkt. Deshalb liegen sie hier.
///
/// Die Reihenfolge ist nicht beliebig: erst muss klar sein, welche Achse des
/// Sensors welche des Fahrzeugs ist, sonst wird der Nullpunkt auf die falsche
/// Achse gelegt.
struct LevelSetupView: View {
let device: ConfiguredDevice
@Environment(BluetoothManager.self) private var bluetooth
@State private var showSensorSetup = false
@State private var showResetConfirmation = false
private var state: LevelState { bluetooth.levelStates[device.id] ?? LevelState() }
/// Immer der aktuelle Stand `device` veraltet, sobald der Assistent
/// eine neue Einbaulage gespeichert hat.
@Environment(DeviceStore.self) private var store
private var currentDevice: ConfiguredDevice {
store.devices.first { $0.id == device.id } ?? device
}
var body: some View {
List {
Section {
HStack(spacing: 24) {
reading("Längs", state.pitch)
reading("Quer", state.roll)
}
.frame(maxWidth: .infinity)
.padding(.vertical, 4)
}
Section {
Button {
showSensorSetup = true
} label: {
LabeledContent {
Text(currentDevice.sensorOrientation.summary)
.font(.caption)
} label: {
Label("Einbaulage bestimmen",
systemImage: "arrow.triangle.2.circlepath")
}
}
.disabled(!state.hasReading)
} header: {
Text("Schritt 1 Einbaulage")
} footer: {
Text("Sitzt der Sensor quer oder verdreht im Fahrzeug, meldet er längs "
+ "und quer vertauscht. Der Assistent klärt das durch zweimaliges "
+ "Kippen. Danach den Nullpunkt setzen.")
}
Section {
Button {
bluetooth.calibrateLevel(for: device.id)
} label: {
Label("Aktuelle Lage als eben übernehmen", systemImage: "scope")
}
.disabled(!state.hasReading)
if !state.isKnownUncalibrated {
Button(role: .destructive) {
showResetConfirmation = true
} label: {
// Ohne das bliebe das Symbol in der Akzentfarbe, während
// die Beschriftung rot ist.
Label("Nullpunkt verwerfen", systemImage: "arrow.uturn.backward")
.foregroundStyle(.red)
}
}
} header: {
Text("Schritt 2 Nullpunkt")
} footer: {
Text(calibrationHint)
}
}
.navigationTitle("Neigungsmesser einrichten")
.navigationBarTitleDisplayMode(.inline)
.sheet(isPresented: $showSensorSetup) {
SensorSetupView(device: currentDevice)
}
.confirmationDialog("Nullpunkt verwerfen?",
isPresented: $showResetConfirmation,
titleVisibility: .visible) {
Button("Verwerfen", role: .destructive) {
bluetooth.resetLevelCalibration(for: device.id)
}
} message: {
Text("Die Anzeige zeigt danach wieder die Lage des Sensors.")
}
}
private var calibrationHint: String {
if state.isCalibrated, let pitchOffset = state.pitchOffset,
let rollOffset = state.rollOffset {
return String(format: "Der Nullpunkt liegt bei %.1f° längs und %.1f° quer. "
+ "Zum Neusetzen das Fahrzeug eben stellen und dann tippen.",
pitchOffset, rollOffset)
}
if state.isKnownUncalibrated {
return "Noch kein Nullpunkt gesetzt die Anzeige zeigt die Lage des "
+ "Sensors, nicht die des Fahrzeugs. Fahrzeug eben stellen, dann tippen."
}
// Ältere Firmware gibt die Offsets nicht heraus.
return "Zum Setzen das Fahrzeug eben stellen und dann tippen. Ob schon ein "
+ "Nullpunkt gesetzt wurde, meldet dieses Gerät nicht zurück."
}
private func reading(_ title: String, _ value: Double?) -> some View {
VStack(spacing: 2) {
Text(value.map { String(format: "%.1f°", $0) } ?? "")
.font(.title2.weight(.semibold).monospacedDigit())
Text(title)
.font(.caption)
.foregroundStyle(.secondary)
}
}
}