Kacheln und Fenster sprechen dieselbe Sprache
Alle Kacheln, Popovers und Fenster auf die Designschicht umgestellt: rund hundert gesetzte Schriftgrößen und 159 gesetzte Abstände und Radien sind jetzt Token. Übrig bleibt `spacing: 0` — das ist eine Aussage, keine geratene Zahl. Die Einstellungen bekommen eine Seitenleiste statt sieben Reitern, deren deutsche Beschriftungen zusammen 880 Punkte brauchten. Panel-Token stehen nicht mehr in Fenstern: dort gilt Systemsemantik, damit der Hellmodus nicht schwarz auf schwarz endet. Neu ist ein Schaufenster, das alle Bauteile nebeneinander zeigt — ohne das lässt sich eine Änderung an einem Token nur prüfen, indem man die App bedient, bis jede Kachel einmal zu sehen war. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
9b600de9a9
commit
edb327cabe
+39
-45
@@ -12,7 +12,7 @@ struct FanSettingsView: View {
|
||||
@Bindable var control: FanControl
|
||||
|
||||
var body: some View {
|
||||
Form {
|
||||
SettingsPage {
|
||||
switch control.installState {
|
||||
case .notInstalled, .failed:
|
||||
installSection
|
||||
@@ -23,16 +23,13 @@ struct FanSettingsView: View {
|
||||
// Das Ladelimit hängt am selben Helfer wie die Lüfter — beides
|
||||
// ist Hardwaresteuerung über den SMC, und beides ist erst
|
||||
// erreichbar, wenn der Helfer läuft.
|
||||
Section("charge.section") {
|
||||
OnyxFormCard(String(localized: "charge.section")) {
|
||||
ChargeLimitControl(control: control, roomy: true)
|
||||
.padding(.horizontal, OnyxForm.rowPadding)
|
||||
.padding(.bottom, OnyxForm.rowPadding)
|
||||
}
|
||||
}
|
||||
}
|
||||
.formStyle(.grouped)
|
||||
// Der eigene Untergrund des Formulars weicht ein, zwei Prozent von dem
|
||||
// des Fensters ab. In Dunkelgrau sieht man genau das als Kante.
|
||||
.scrollContentBackground(.hidden)
|
||||
.padding()
|
||||
.onAppear {
|
||||
control.refreshInstallState()
|
||||
control.start()
|
||||
@@ -43,37 +40,33 @@ struct FanSettingsView: View {
|
||||
// MARK: - Einrichtung
|
||||
|
||||
private var installSection: some View {
|
||||
Section {
|
||||
Text("fans.intro")
|
||||
.font(.callout)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
|
||||
OnyxFormCard(String(localized: "fans.group.setup"),
|
||||
hint: String(localized: "fans.intro")) {
|
||||
// Das Risiko benennen, bevor jemand zustimmt — nicht danach.
|
||||
Label("fans.warning", systemImage: "exclamationmark.triangle.fill")
|
||||
.font(.callout)
|
||||
.foregroundStyle(Onyx.Color.warning)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
|
||||
Text("fans.safety")
|
||||
.font(.callout)
|
||||
.foregroundStyle(.secondary)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
OnyxFormRow(String(localized: "fans.warning"),
|
||||
hint: String(localized: "fans.safety"),
|
||||
symbol: "exclamationmark.triangle.fill",
|
||||
tone: .warning)
|
||||
|
||||
if case .failed(let message) = control.installState {
|
||||
Text(message).font(.callout).foregroundStyle(Onyx.Color.critical)
|
||||
OnyxFormRow(message, symbol: "xmark.octagon", tone: .critical)
|
||||
}
|
||||
|
||||
Button("fans.install") { control.install() }
|
||||
OnyxFormRow(String(localized: "fans.install")) {
|
||||
Button("fans.install") { control.install() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var approvalSection: some View {
|
||||
Section {
|
||||
Label("fans.approval.needed", systemImage: "hand.raised")
|
||||
.font(.callout)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
Button("fans.approval.open") { control.openApprovalSettings() }
|
||||
Button("fans.approval.recheck") { control.refreshInstallState() }
|
||||
OnyxFormCard(String(localized: "fans.group.setup")) {
|
||||
OnyxFormRow(String(localized: "fans.approval.needed"),
|
||||
symbol: "hand.raised") {
|
||||
Button("fans.approval.open") { control.openApprovalSettings() }
|
||||
}
|
||||
OnyxFormRow(String(localized: "fans.action.recheck")) {
|
||||
Button("fans.action.recheck") { control.refreshInstallState() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,14 +75,13 @@ struct FanSettingsView: View {
|
||||
@ViewBuilder
|
||||
private var controlSection: some View {
|
||||
if let report = control.report {
|
||||
Section {
|
||||
OnyxFormCard(String(localized: "fans.group.control")) {
|
||||
if let hottest = report.hottestCelsius {
|
||||
HStack {
|
||||
Label("fans.hottest", systemImage: "thermometer")
|
||||
Spacer()
|
||||
OnyxFormRow(String(localized: "fans.hottest"), symbol: "thermometer") {
|
||||
Text("\(Int(hottest))°").monospacedDigit()
|
||||
.foregroundStyle(hottest >= FanSafety.criticalCelsius
|
||||
? Onyx.Color.critical : .secondary)
|
||||
? AnyShapeStyle(Onyx.Color.critical)
|
||||
: AnyShapeStyle(.secondary))
|
||||
}
|
||||
}
|
||||
ForEach(report.fans, id: \.index) { fan in
|
||||
@@ -97,22 +89,21 @@ struct FanSettingsView: View {
|
||||
}
|
||||
}
|
||||
|
||||
Section {
|
||||
Text("fans.safety.active")
|
||||
.font(.callout).foregroundStyle(.secondary)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
Button("fans.uninstall", role: .destructive) {
|
||||
Task { await control.uninstall() }
|
||||
OnyxFormCard(String(localized: "fans.group.danger"),
|
||||
hint: String(localized: "fans.safety.active")) {
|
||||
OnyxFormRow(String(localized: "fans.uninstall")) {
|
||||
Button("settings.action.remove", role: .destructive) {
|
||||
Task { await control.uninstall() }
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Section {
|
||||
HStack {
|
||||
OnyxFormCard(String(localized: "fans.group.control")) {
|
||||
OnyxFormRow(String(localized: "fans.connecting")) {
|
||||
ProgressView().controlSize(.small)
|
||||
Text("fans.connecting").foregroundStyle(.secondary)
|
||||
}
|
||||
if let error = control.lastError {
|
||||
Text(error).font(.callout).foregroundStyle(Onyx.Color.critical)
|
||||
OnyxFormRow(error, symbol: "xmark.octagon", tone: .critical)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -127,7 +118,7 @@ private struct FanRow: View {
|
||||
@State private var editing = false
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading, spacing: 6) {
|
||||
VStack(alignment: .leading, spacing: Onyx.Space.sm) {
|
||||
HStack {
|
||||
Label(name, systemImage: "fan")
|
||||
Spacer()
|
||||
@@ -173,6 +164,9 @@ private struct FanRow: View {
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
}
|
||||
}
|
||||
// Die Karte polstert nur `OnyxFormRow`; dieser Block ist ein eigener.
|
||||
.padding(.horizontal, OnyxForm.rowPadding)
|
||||
.padding(.vertical, Onyx.Space.row)
|
||||
.onAppear { if !editing { target = max(fan.targetRPM, fan.limits.minimum) } }
|
||||
.onChange(of: fan.targetRPM) { _, new in if !editing { target = new } }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user