forked from fritob/Camper-Monitor
Kalibrierung und Einbaulage standen direkt unter der Libelle. Wer im Fahrzeug die Anzeige abliest und dabei scrollt, verstellt so leicht den Nullpunkt - und merkt es nicht, weil die Anzeige danach schlicht null zeigt. Beides liegt jetzt hinter "Neigungsmesser einrichten". In der Geräteansicht bleibt, was im Betrieb gebraucht wird: die Libelle, die Werte und der Ausrichtungs-Assistent. Die Einrichtungszeile nennt den Stand, damit man nicht erst hineinschauen muss - fehlt der Nullpunkt, steht das dort. Die Namen sagen jetzt, was geschieht. "Auf aktuelle Lage kalibrieren" klang nach einer Messung, gemeint ist das Festlegen des Nullpunkts: jetzt "Aktuelle Lage als eben übernehmen", das Zurücksetzen entsprechend "Nullpunkt verwerfen". Aus dem Hauptwort "Einbaulage" wird "Einbaulage bestimmen". Die beiden Schritte stehen in der Reihenfolge, in der sie gehören: erst die Einbaulage, sonst legt der Nullpunkt sich auf die falsche Achse. Beide Knöpfe bleiben stumm, solange keine Werte ankommen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
126 lines
4.9 KiB
Swift
126 lines
4.9 KiB
Swift
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)
|
||
}
|
||
}
|
||
}
|