Files
Camper-Monitor/VanControl/CarPlay/CarPlayLevelScreen.swift
fototeddyandClaude Opus 5 ae12d8ede4 CarPlay-Demo: Nivellierung auf dem Fahrzeugdisplay
Eigene Build-Konfiguration "CarPlay" samt Schema, damit der Versuchsbau neben
der TestFlight-App stehen kann: eigener Name, eigene Bundle-ID, persoenliches
Team, manuelles Signing. Debug und Release bleiben unberuehrt.

Wichtig dabei: Die Signing-Einstellungen stehen ausschliesslich in den
Target-Konfigurationen. Steht CODE_SIGN_STYLE auf Projektebene, schreibt der
naechste xcodebuild-Lauf alle uebrigen Konfigurationen auf Manual um und loescht
ihr Team – der TestFlight-Build waere damit hin.

Der CarPlay-Code haengt an `CARPLAY_DEMO` und existiert im regulaeren Build
nicht. Die Szene zeichnet in das gelieferte CPWindow; das CPMapTemplate darueber
bleibt leer, weil es auf dem Stellplatz nichts zu tippen gibt. Die Anzeige
sperrt sich oberhalb von 5 km/h selbst – erzwungen, nicht zugesagt.

Die Groessen sind auf die 400x240 Punkte ausgelegt, die CarPlay liefert, nicht
auf die 800x480 Pixel. In Pixeln gedachte Schriftgroessen sind auf dem
Fahrzeugdisplay doppelt zu gross und schneiden den Text ab.

Bekannt: Unter iOS 26.5 stuerzt Apples CarPlayTemplateUIHost beim Aufbau der
Navigationsleiste ab (`_updateShareButtonVisibility` fragt seinen
destinationSharingDelegate nach `vehicleSupportsDestinationSharing`, den dieser
nicht kennt). Beides ist privates API und von der App aus nicht erreichbar;
unter iOS 18 laeuft es. Szene und Root-Template werden vorher in beiden
Faellen akzeptiert.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-10 18:35:33 +02:00

92 lines
3.3 KiB
Swift
Raw Permalink 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.
#if CARPLAY_DEMO
import SwiftUI
/// Die Libelle auf dem Fahrzeugdisplay.
///
/// Quer geteilt: links die Blase, rechts in Worten, was zu tun ist. Beim
/// Rangieren wird abwechselnd auf Display und Umfeld geschaut deshalb steht
/// die Aussage in einem Satz da, statt sich aus zwei Zahlen ergeben zu müssen.
///
/// Die Groessen sind auf die 400 × 240 **Punkte** ausgelegt, die CarPlay
/// liefert nicht auf die 800 × 480 Pixel. Das ist die Falle: In Pixeln
/// gedachte Schriftgroessen sind auf dem Fahrzeugdisplay doppelt zu gross und
/// schneiden den Text ab.
struct CarPlayLevelScreen: View {
@Environment(CarPlayLevelSource.self) private var source
private var state: LevelState {
LevelState(pitch: source.pitch, roll: source.roll)
}
var body: some View {
ZStack {
Color.black.ignoresSafeArea()
if CarPlaySpeedGate.shared.isStationary {
levelling
} else {
driving
}
}
.onAppear { CarPlaySpeedGate.shared.start() }
.onDisappear { CarPlaySpeedGate.shared.stop() }
}
private var levelling: some View {
HStack(spacing: 18) {
LevelBubble(pitch: source.pitch, roll: source.roll)
VStack(alignment: .leading, spacing: 10) {
VStack(alignment: .leading, spacing: 2) {
let lines = state.shortInstructions
ForEach(lines.isEmpty ? ["Keine Verbindung"] : lines, id: \.self) { line in
Text(line)
.font(.system(size: 20, weight: .semibold, design: .rounded))
.foregroundStyle(state.isLevel ? .green : .white)
.lineLimit(1)
.minimumScaleFactor(0.8)
}
}
HStack(spacing: 16) {
tile("Längs", LevelDirectionFormatting.pitchTile(source.pitch))
tile("Quer", LevelDirectionFormatting.rollTile(source.roll))
}
if source.isSimulated {
// Ohne diesen Hinweis wäre ein Screenshot aus dem Simulator
// eine Behauptung über Messwerte, die es nicht gab.
Text("Simulierte Werte")
.font(.system(size: 11, weight: .medium))
.foregroundStyle(.orange)
}
}
.frame(maxWidth: .infinity, alignment: .leading)
}
.padding(16)
}
private var driving: some View {
VStack(spacing: 10) {
Image(systemName: "car.fill")
.font(.system(size: 30))
Text("Nivellierung nur im Stand")
.font(.system(size: 20, weight: .semibold, design: .rounded))
}
.foregroundStyle(.white.opacity(0.7))
}
private func tile(_ label: String, _ value: String) -> some View {
VStack(alignment: .leading, spacing: 1) {
Text(label)
.font(.system(size: 11, weight: .medium))
.foregroundStyle(.secondary)
Text(value)
.font(.system(size: 22, weight: .semibold, design: .rounded))
.monospacedDigit()
.foregroundStyle(.white)
}
}
}
#endif