Der Blitz stand neben dem Akku statt darin, und das sah nach zwei Dingen aus statt nach einem. Mit SF Symbols ging es nicht anders: fünf feste Füllstufen, und Blitz-Varianten gibt es nur bei hundert Prozent. Also selbst gezeichnet — ein Rahmen, ein Knubbel, eine Füllung, ein Blitz. Das ist am Ende die kleinere Lösung als die Symbolakrobatik und gibt obendrein, was vorher fehlte: die Füllung läuft stufenlos, 60 % sieht aus wie 60 % und nicht wie 50 %. Der Blitz wird ausgestanzt, nicht daraufgelegt. `destinationOut` nimmt weg, was vorher gezeichnet wurde; übrig bleibt ein Loch in Blitzform, durch das die Menüleiste scheint. Das funktioniert auf hellem wie dunklem Grund, ohne die Hintergrundfarbe zu kennen — und genau so sieht der von macOS aus. Unter zwanzig Prozent wird die Füllung rot, beim Laden nie: eine Warnung vor etwas, das sich schon erledigt, ist keine. Dieselbe Form auch in der Akku-Kachel. Zwei verschiedene Akkus in einer App wären schlechter als gar keiner. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
64 lines
2.3 KiB
Swift
64 lines
2.3 KiB
Swift
import Testing
|
|
import CoreGraphics
|
|
@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)
|
|
}
|
|
}
|