Farben einstellbar — und erst mal überhaupt eine Farbe

Das Grün, das überall auftauchte, war die System-Akzentfarbe: `.tint` und
`.accentColor` werden ohne eigene Angabe dorthin durchgereicht, und das
betraf alle Popovers und das ganze Einstellungsfenster. Die Notch-Widgets
dagegen benutzten Onyx' eigenes Blau. Zwei Farben, ungewollt.

Jetzt eine, und die ist einstellbar. Ein neuer Reiter „Farben": Akzentfarbe
mit sechs Vorschlägen und einem Knopf, der die Systemfarbe übernimmt, dazu
das Paar für Herunter- und Hochladen samt Tauschknopf.

Die Signalfarben bleiben fest und stehen nur zur Ansicht dort. Gelb heißt
Warnung, Rot heißt kritisch, Grün heißt in Ordnung — bei Temperatur, Akku,
Lüfter und Fehlern. Wer sie umstellen kann, kann ihre Bedeutung zerstören;
ein rotes „alles gut" liest niemand richtig. Sichtbar sind sie trotzdem,
sonst sucht man die Warnfarbe im Reiter und findet sie nirgends.

Umgesetzt über die Tokens statt über vierzig Fundstellen: `Onyx.Color.accent`
ist keine Konstante mehr, sondern liest bei jedem Zugriff aus `OnyxTheme`.
Damit merkt SwiftUI die Abhängigkeit und zeichnet neu, sobald die Farbe sich
ändert. Dazu ein `.tint` an den vier Wurzeln — Panel, Popovers, Einstellungen,
Einrichtung —, damit auch Haken, Regler und Auswahlfelder mitziehen.

Nebenbei die Beschriftung: „Je Programm" heißt jetzt „Programme". Großgesetzt
las sich das als englisches „J-E".

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-08-13 23:24:40 +02:00
parent 7a3d2c1c39
commit 2aa60eedf9
20 changed files with 757 additions and 45 deletions

View File

@@ -40,7 +40,7 @@ private struct SectionTitle: View {
var body: some View {
Text(text, bundle: .module)
.font(.caption.weight(.semibold))
.foregroundStyle(.tint)
.foregroundStyle(Onyx.Color.accent)
.textCase(.uppercase)
}
}
@@ -81,7 +81,9 @@ private struct Dial: View {
let value: Double
let caption: String
let text: String
var tint: Color = .accentColor
/// Ohne Angabe die Akzentfarbe. Als Standardwert ginge sie nicht: der
/// wird außerhalb des Hauptthreads erzeugt, die Farbe liegt aber dort.
var tint: Color?
var body: some View {
// Sechs Punkte Abstand statt zwei: die Beschriftung klebte am Ring und
@@ -91,7 +93,8 @@ private struct Dial: View {
Circle().stroke(.quaternary, lineWidth: 5)
Circle()
.trim(from: 0, to: min(max(value, 0), 1))
.stroke(tint, style: .init(lineWidth: 5, lineCap: .round))
.stroke(tint ?? Onyx.Color.accent,
style: .init(lineWidth: 5, lineCap: .round))
.rotationEffect(.degrees(-90))
Text(text).font(.system(size: 15, weight: .medium).monospacedDigit())
}
@@ -182,10 +185,10 @@ private struct CoreGrid: View {
spacing: 3) {
ForEach(Array(values.enumerated()), id: \.offset) { _, value in
RoundedRectangle(cornerRadius: 2, style: .continuous)
.fill(Color.accentColor.opacity(0.18))
.fill(Onyx.Color.accent.opacity(0.18))
.overlay(alignment: .bottom) {
RoundedRectangle(cornerRadius: 2, style: .continuous)
.fill(Color.accentColor)
.fill(Onyx.Color.accent)
.frame(height: max(14 * value, 1.5))
}
.frame(height: 14)
@@ -208,7 +211,7 @@ private struct MemoryDetail: View {
text: MetricFormat.percent(memory.usedFraction),
tint: pressureColor)
VStack(alignment: .leading, spacing: 3) {
legend(.accentColor, "popover.memory.app", memory.app)
legend(Onyx.Color.accent, "popover.memory.app", memory.app)
legend(.purple, "popover.memory.wired", memory.wired)
legend(.teal, "popover.memory.compressed", memory.compressed)
legend(.gray, "popover.memory.free", memory.free)
@@ -220,7 +223,7 @@ private struct MemoryDetail: View {
// ist ein voller Speicher kein Problem macOS füllt ihn absichtlich.
Row(label: String(localized: "popover.memory.swapUsed", bundle: .module),
value: "\(bytes(memory.swapUsed)) / \(bytes(memory.swapTotal))",
emphasis: memory.swapUsed > 512 * 1024 * 1024 ? .orange : nil)
emphasis: memory.swapUsed > 512 * 1024 * 1024 ? Onyx.Color.warning : nil)
if !snapshot.topMemoryProcesses.isEmpty {
SectionTitle(text: "popover.processes")
@@ -232,9 +235,9 @@ private struct MemoryDetail: View {
private var pressureColor: Color {
switch snapshot.memory.pressure {
case .normal: .green
case .warning: .orange
case .critical: .red
case .normal: Onyx.Color.positive
case .warning: Onyx.Color.warning
case .critical: Onyx.Color.critical
}
}
@@ -264,8 +267,9 @@ private struct BatteryDetail: View {
Dial(value: battery.charge,
caption: String(localized: "metric.battery", bundle: .module),
text: MetricFormat.percent(battery.charge),
tint: battery.isCharging ? .green
: (battery.charge < 0.2 ? .red : .accentColor))
tint: battery.isCharging ? Onyx.Color.positive
: (battery.charge < 0.2 ? Onyx.Color.critical
: Onyx.Color.accent))
// Beides gehört neben den Ring: die Schätzung und der Grund
// dafür. Am Netzteil" über dem Ring und Am Netz, lädt nicht"
// darunter waren zweimal dieselbe Auskunft an zwei Stellen
@@ -382,7 +386,7 @@ private struct BatteryDetail: View {
private func tint(for activity: ChargeActivity) -> Color {
// Farbe nur, wo sie etwas meldet: Laden ist ein Zustand, den man
// sucht. Alles andere bleibt zurückhaltend.
activity == .charging ? .green : .secondary
activity == .charging ? Onyx.Color.positive : .secondary
}
private func duration(_ seconds: TimeInterval) -> String {