forked from fritob/Camper-Monitor
Begleitet das Einparken: verfolgt die Neigung über die Zeit, meldet ob es besser oder schlechter wird, und erinnert an den flachsten Punkt - "vor 4 Sekunden stand das Fahrzeug 0,8 Grad flacher". Bei Erreichen der Toleranz gibt es eine Vibration, das Display bleibt währenddessen wach. Bewusst ohne Positionsbestimmung. Aus einem MEMS-Sensor lässt sich keine brauchbare Strecke ableiten: der Fehler wächst beim zweifachen Integrieren quadratisch mit der Zeit, und im Schritttempo gehen die tatsächlichen Beschleunigungen im Rauschen unter. Gebraucht wird sie auch nicht - beim Einparken lautet die Frage nie "wo stehe ich", sondern "wird es besser". Das steckt vollständig im zeitlichen Verlauf der Neigung, ohne jede Annahme über das Gelände. Die vorhandene Verlaufsaufzeichnung war mit einem Punkt alle fünf Sekunden zu grob; der Assistent führt einen eigenen Ringpuffer, der nur läuft solange die Ansicht offen ist. Sind Spurweite und Radstand hinterlegt, kommt die nötige Höhe der Auffahrkeile dazu. Das ist reine Geometrie und damit exakt. Die Masse stehen im Fahrzeugprofil. Dabei fiel auf, dass sich vorhandene Fahrzeuge praktisch nicht bearbeiten liessen: das ging nur über eine Wischgeste, die niemand findet - erst recht nicht, wenn dort jetzt die Masse einzutragen sind. Die Zeile hat nun einen sichtbaren Knopf dafür, wie bei den WLAN-Einstellungen: antippen wählt aus, das Zeichen daneben öffnet die Bearbeitung. Ausserdem übernimmt der Assistent den anliegenden Messwert beim Öffnen. Sonst stand dort bis zur nächsten Messung "Warte auf Messwerte", obwohl längst welche vorlagen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
54 lines
2.0 KiB
Swift
54 lines
2.0 KiB
Swift
import Foundation
|
||
|
||
/// Ein Fahrzeug. Jedes Profil hat seinen eigenen Satz Geräte; die App zeigt und
|
||
/// funkt immer nur für das gerade gewählte.
|
||
struct Profile: Identifiable, Codable, Hashable, Sendable {
|
||
var id: UUID
|
||
var name: String
|
||
/// SF-Symbol für die Auswahl im Dashboard.
|
||
var symbol: String
|
||
|
||
/// Spurweite in Metern – für die Berechnung der Auffahrkeile quer.
|
||
var trackWidth: Double?
|
||
/// Radstand in Metern – dasselbe längs.
|
||
var wheelbase: Double?
|
||
|
||
init(id: UUID = UUID(),
|
||
name: String,
|
||
symbol: String = "box.truck",
|
||
trackWidth: Double? = nil,
|
||
wheelbase: Double? = nil) {
|
||
self.id = id
|
||
self.name = name
|
||
self.symbol = symbol
|
||
self.trackWidth = trackWidth
|
||
self.wheelbase = wheelbase
|
||
}
|
||
|
||
/// Profile aus der Zeit vor den Fahrzeugmassen haben noch keine.
|
||
init(from decoder: Decoder) throws {
|
||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||
id = try container.decode(UUID.self, forKey: .id)
|
||
name = try container.decode(String.self, forKey: .name)
|
||
symbol = try container.decode(String.self, forKey: .symbol)
|
||
trackWidth = try container.decodeIfPresent(Double.self, forKey: .trackWidth)
|
||
wheelbase = try container.decodeIfPresent(Double.self, forKey: .wheelbase)
|
||
}
|
||
|
||
/// Profil, dem Geräte aus der Zeit vor der Profilverwaltung zugeordnet
|
||
/// werden. Feste Kennung, damit die Zuordnung beim Update erhalten bleibt.
|
||
static let defaultID = UUID(uuidString: "00000000-0000-0000-0000-00000000C001")!
|
||
|
||
static var initial: Profile {
|
||
Profile(id: defaultID, name: "Mein Camper")
|
||
}
|
||
|
||
/// Auswahl für die Profilbearbeitung.
|
||
/// Alle Namen gegen NSImage(systemSymbolName:) geprüft – ein nicht
|
||
/// existierendes Symbol lässt SwiftUI stillschweigend auf Text zurückfallen.
|
||
static let symbols = [
|
||
"box.truck", "truck.pickup.side", "bus", "bus.doubledecker",
|
||
"car", "car.side", "tent", "sailboat", "house.lodge", "mountain.2",
|
||
]
|
||
}
|