forked from fritob/Camper-Monitor
Neigungsmesser: Einrichtung auf eine eigene Seite
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>
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -107,10 +107,8 @@ struct LevelControls: View {
|
||||
|
||||
@Environment(BluetoothManager.self) private var bluetooth
|
||||
@Environment(DeviceStore.self) private var store
|
||||
@State private var showResetConfirmation = false
|
||||
@State private var showAssistant = false
|
||||
@AppStorage("levelDisplayStyle") private var displayStyle: LevelDisplayStyle = .bubble
|
||||
@State private var showSensorSetup = false
|
||||
|
||||
var body: some View {
|
||||
Section {
|
||||
@@ -165,65 +163,30 @@ struct LevelControls: View {
|
||||
.disabled(!state.hasReading)
|
||||
}
|
||||
|
||||
// Einbaulage und Nullpunkt liegen auf einer eigenen Seite. Direkt unter
|
||||
// der Libelle verstellte ein Fehlgriff beim Ablesen den Nullpunkt.
|
||||
Section {
|
||||
Button {
|
||||
showSensorSetup = true
|
||||
NavigationLink {
|
||||
LevelSetupView(device: device)
|
||||
} label: {
|
||||
LabeledContent {
|
||||
Text(device.sensorOrientation.summary)
|
||||
.font(.caption)
|
||||
Text(setupSummary).font(.caption)
|
||||
} label: {
|
||||
Label("Einbaulage", systemImage: "arrow.triangle.2.circlepath")
|
||||
Label("Neigungsmesser einrichten", systemImage: "slider.horizontal.3")
|
||||
}
|
||||
}
|
||||
} header: {
|
||||
Text("Sensor")
|
||||
} footer: {
|
||||
Text("Sitzt der Sensor quer oder verdreht, meldet er längs und quer "
|
||||
+ "vertauscht. Der Assistent klärt das durch zweimaliges Kippen.")
|
||||
}
|
||||
|
||||
Section {
|
||||
Button("Auf aktuelle Lage kalibrieren", systemImage: "scope") {
|
||||
bluetooth.calibrateLevel(for: device.id)
|
||||
}
|
||||
if !state.isKnownUncalibrated {
|
||||
Button("Kalibrierung zurücksetzen", systemImage: "arrow.uturn.backward", role: .destructive) {
|
||||
showResetConfirmation = true
|
||||
}
|
||||
}
|
||||
} header: {
|
||||
Text("Kalibrierung")
|
||||
} footer: {
|
||||
if state.isCalibrated, let pitchOffset = state.pitchOffset,
|
||||
let rollOffset = state.rollOffset {
|
||||
Text(String(format: "Nullpunkt liegt bei %.1f° längs und %.1f° quer. "
|
||||
+ "Zum Kalibrieren das Fahrzeug eben stellen und dann tippen.",
|
||||
pitchOffset, rollOffset))
|
||||
} else if state.isKnownUncalibrated {
|
||||
Text("Noch nicht kalibriert – die Anzeige zeigt die Lage des Sensors, "
|
||||
+ "nicht die des Fahrzeugs. Fahrzeug eben stellen und dann kalibrieren.")
|
||||
} else {
|
||||
// Ältere Firmware gibt die Offsets nicht heraus.
|
||||
Text("Zum Kalibrieren das Fahrzeug eben stellen und dann tippen. "
|
||||
+ "Ob bereits kalibriert wurde, meldet dieses Gerät nicht zurück.")
|
||||
}
|
||||
}
|
||||
.sheet(isPresented: $showSensorSetup) {
|
||||
SensorSetupView(device: device)
|
||||
Text("Einbaulage des Sensors und Nullpunkt der Anzeige.")
|
||||
}
|
||||
.fullScreenCover(isPresented: $showAssistant) {
|
||||
AlignmentAssistantView(device: device, profile: store.activeProfile)
|
||||
}
|
||||
.confirmationDialog("Kalibrierung zurücksetzen?",
|
||||
isPresented: $showResetConfirmation,
|
||||
titleVisibility: .visible) {
|
||||
Button("Zurücksetzen", role: .destructive) {
|
||||
bluetooth.resetLevelCalibration(for: device.id)
|
||||
}
|
||||
} message: {
|
||||
Text("Die Anzeige zeigt danach wieder die Lage des Sensors.")
|
||||
}
|
||||
}
|
||||
|
||||
/// Was auf der Einrichtungsseite zu holen ist – der Nullpunkt zuerst, denn
|
||||
/// ohne ihn stimmt die Anzeige nicht.
|
||||
private var setupSummary: String {
|
||||
state.isKnownUncalibrated ? "Nullpunkt fehlt" : device.sensorOrientation.summary
|
||||
}
|
||||
|
||||
private func reading(_ title: String, _ value: Double?) -> some View {
|
||||
|
||||
Reference in New Issue
Block a user