Am Netz und trotzdem kein Blitz sah aus wie Akkubetrieb — dabei ist es der Normalfall, sobald das Ladelimit greift. Jetzt steht in diesem Zustand ein Stecker im Akku, ausgestanzt wie der Blitz. Drei Zustände, drei Zeichen: lädt, hängt am Netz, läuft auf Akku. Der Mixer folgt jetzt der Anordnung von SoundSource, weil sie dort gut gelöst ist: eine Zeile je Programm, links das Symbol als Kachel, dann der Stummschalter, dann der Regler, rechts der Wert. Vorher stand der Stummschalter rechts zwischen den Zusatzelementen, obwohl er zur Lautstärke gehört, und die Prozentzahl sprang zwischen zwei Zeilen. Die Farben folgen SoundSource **nicht**. Dort ist jeder Regler grün; in Onyx ist Farbe ein Signal — die Verstärkung über 100 % ist eines, eine gewöhnliche Lautstärke nicht. Nebenbei zwei Fehler im Regler: der Knopf stand an den Enden über die Bahn hinaus, und die Ziehposition rechnete ohne seine Breite. Am rechten Anschlag ließen sich die letzten Prozent deshalb nicht einstellen. Das Popover ist die Hauptfläche und jetzt 330 statt 280 Punkte breit. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
105 lines
3.8 KiB
Swift
105 lines
3.8 KiB
Swift
import Testing
|
|
import CoreGraphics
|
|
import AppKit
|
|
@testable import MetricsProvider
|
|
|
|
// SF Symbols kennt fünf Füllstufen und keine Blitz-Varianten außer bei 100 %.
|
|
// Beides passt nicht zu dem, was macOS selbst zeigt: eine stufenlose Füllung
|
|
// und einen Blitz **im** Akku. Also selbst gezeichnet.
|
|
|
|
@Suite("Akkuglyph")
|
|
struct BatteryGlyphTests {
|
|
|
|
private let inner: CGFloat = 20
|
|
|
|
@Test("Die Füllung folgt dem Ladestand stufenlos")
|
|
func fillIsProportional() {
|
|
// Der eigentliche Gewinn gegenüber fünf festen Stufen: 60 % sieht aus
|
|
// wie 60 % und nicht wie 50 %.
|
|
#expect(BatteryGlyph.fillWidth(charge: 0.5, inner: inner) == 10)
|
|
#expect(BatteryGlyph.fillWidth(charge: 1.0, inner: inner) == 20)
|
|
}
|
|
|
|
@Test("Ein leerer Akku bleibt leer")
|
|
func emptyStaysEmpty() {
|
|
#expect(BatteryGlyph.fillWidth(charge: 0, inner: inner) == 0)
|
|
}
|
|
|
|
@Test("Ein fast leerer Akku ist trotzdem zu sehen")
|
|
func nearlyEmptyIsStillVisible() {
|
|
// Zwei Prozent ergäben 0,4 Punkte — unsichtbar, und damit
|
|
// ununterscheidbar von „leer". Ein Rest bleibt stehen.
|
|
let width = BatteryGlyph.fillWidth(charge: 0.02, inner: inner)
|
|
#expect(width >= BatteryGlyph.minimumFill)
|
|
}
|
|
|
|
@Test("Über hundert Prozent läuft nichts über")
|
|
func neverOverflows() {
|
|
#expect(BatteryGlyph.fillWidth(charge: 2, inner: inner) == inner)
|
|
#expect(BatteryGlyph.fillWidth(charge: -1, inner: inner) == 0)
|
|
}
|
|
|
|
@Test("Wenig Ladung gilt als kritisch")
|
|
func lowIsFlagged() {
|
|
// Dieselbe Schwelle wie in macOS: ab zwanzig Prozent abwärts wird die
|
|
// Farbe zum Signal.
|
|
#expect(BatteryGlyph.isLow(charge: 0.19))
|
|
#expect(!BatteryGlyph.isLow(charge: 0.21))
|
|
}
|
|
|
|
@Test("Beim Laden gilt nichts als kritisch")
|
|
func chargingIsNeverLow() {
|
|
// Ein roter Akku, der gerade lädt, wäre eine Warnung vor etwas, das
|
|
// sich schon erledigt.
|
|
#expect(!BatteryGlyph.isLow(charge: 0.05, isCharging: true))
|
|
}
|
|
|
|
@Test("Das Glyph hat die Maße der Menüleiste")
|
|
func sizeFitsMenuBar() {
|
|
// Breiter als hoch, wie ein Akku aussieht — und niedrig genug, dass es
|
|
// in die 22 Punkte der Leiste passt.
|
|
#expect(BatteryGlyph.size.width > BatteryGlyph.size.height)
|
|
#expect(BatteryGlyph.size.height <= 14)
|
|
}
|
|
}
|
|
|
|
// Am Netz, aber es tut sich nichts — weil das Ladelimit erreicht ist. Ohne
|
|
// eigenes Zeichen sieht das genauso aus wie Akkubetrieb, und man fragt sich,
|
|
// ob das Kabel wirklich steckt.
|
|
|
|
@Suite("Ladezustand im Glyph")
|
|
struct BatteryIndicatorTests {
|
|
|
|
@Test("Beim Laden der Blitz")
|
|
func chargingShowsBolt() {
|
|
#expect(BatteryGlyph.indicator(isCharging: true, isPluggedIn: true) == .bolt)
|
|
}
|
|
|
|
@Test("Am Netz ohne Laden der Stecker")
|
|
func pluggedButIdleShowsPlug() {
|
|
// Der Fall, um den es geht: Ladelimit erreicht.
|
|
#expect(BatteryGlyph.indicator(isCharging: false, isPluggedIn: true) == .plug)
|
|
}
|
|
|
|
@Test("Im Akkubetrieb gar nichts")
|
|
func onBatteryShowsNothing() {
|
|
#expect(BatteryGlyph.indicator(isCharging: false, isPluggedIn: false) == .none)
|
|
}
|
|
|
|
@Test("Laden schlägt alles andere")
|
|
func chargingWins() {
|
|
// Sollte der Netzzustand einmal widersprüchlich gemeldet werden, ist
|
|
// „lädt" die Auskunft, die zählt.
|
|
#expect(BatteryGlyph.indicator(isCharging: true, isPluggedIn: false) == .bolt)
|
|
}
|
|
|
|
@Test("Jedes Zeichen gibt es auch wirklich")
|
|
func everyIndicatorResolves() {
|
|
for indicator in BatteryGlyph.Indicator.allCases {
|
|
guard let name = indicator.symbolName else { continue }
|
|
#expect(NSImage(systemSymbolName: name, accessibilityDescription: nil) != nil,
|
|
"\(name) gibt es nicht")
|
|
}
|
|
}
|
|
}
|