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>
75 lines
2.8 KiB
Swift
75 lines
2.8 KiB
Swift
import SwiftUI
|
||
import AppKit
|
||
import OnyxDesign
|
||
import OnyxHelperProtocol
|
||
|
||
/// Wer das Ladelimit **lesen** kann.
|
||
///
|
||
/// Nur lesen, und das ist eine gemessene Grenze, keine Bequemlichkeit: der
|
||
/// SMC lehnt Schreibzugriffe auf `CHLT` ab. Der Helfer hat es versucht und
|
||
/// `false` gemeldet, der Wert blieb unverändert. macOS setzt das Limit
|
||
/// offenbar auf einem anderen Weg als über den SMC-Userclient.
|
||
///
|
||
/// Ein Regler, der sich ziehen lässt und dann zurückspringt, ist schlimmer als
|
||
/// gar keiner — er behauptet eine Fähigkeit, die nicht existiert.
|
||
@MainActor
|
||
public protocol ChargeLimitReading: AnyObject {
|
||
/// Das eingestellte Limit in Prozent, `nil` wenn keines gilt.
|
||
var chargeLimit: Int? { get }
|
||
/// Ob der Wert überhaupt gelesen werden kann — ohne Helfer nicht.
|
||
var canReadCharge: Bool { get }
|
||
func refreshChargeLimit()
|
||
}
|
||
|
||
/// Zeigt das Ladelimit und führt dorthin, wo man es ändern kann.
|
||
public struct ChargeLimitControl: View {
|
||
|
||
private let control: any ChargeLimitReading
|
||
/// Im Popover ist Platz für den Hinweis, in der Kachel nicht.
|
||
private let roomy: Bool
|
||
|
||
public init(control: any ChargeLimitReading, roomy: Bool) {
|
||
self.control = control
|
||
self.roomy = roomy
|
||
}
|
||
|
||
public var body: some View {
|
||
HStack(spacing: Onyx.Space.sm) {
|
||
Text("charge.limit", bundle: .module)
|
||
.font(Onyx.Font.caption)
|
||
.foregroundStyle(Onyx.Color.textSecondary)
|
||
|
||
Spacer(minLength: 4)
|
||
|
||
if let limit = control.chargeLimit, limit < ChargeSafety.noLimit {
|
||
Text(verbatim: "\(limit) %")
|
||
.font(Onyx.Font.metricSmall).monospacedDigit()
|
||
.foregroundStyle(Onyx.Color.accent)
|
||
} else if control.canReadCharge {
|
||
Text("charge.limit.off", bundle: .module)
|
||
.font(Onyx.Font.metricSmall)
|
||
.foregroundStyle(Onyx.Color.textTertiary)
|
||
} else {
|
||
Text(verbatim: "–")
|
||
.font(Onyx.Font.metricSmall)
|
||
.foregroundStyle(Onyx.Color.textTertiary)
|
||
}
|
||
|
||
if roomy {
|
||
// Kein Regler, sondern der Weg dorthin, wo es wirklich geht.
|
||
Button {
|
||
NSWorkspace.shared.open(
|
||
URL(string: "x-apple.systempreferences:com.apple.Battery-Settings.extension")!)
|
||
} label: {
|
||
Image(systemName: "arrow.up.forward.app")
|
||
.font(.system(size: Onyx.Symbol.small))
|
||
.foregroundStyle(Onyx.Color.textTertiary)
|
||
}
|
||
.buttonStyle(.plain)
|
||
.help(Text("charge.limit.inSystemSettings", bundle: .module))
|
||
}
|
||
}
|
||
.onAppear { control.refreshChargeLimit() }
|
||
}
|
||
}
|