Menüleiste: Breite mitwachsend, Symbole unverzerrt, Sensor wählbar

Die Netzwerkkachel war auf „↓ 999,9 MB/s" dimensioniert und stand damit
neben „↓ 13 KB/s" zur Hälfte leer. Auf den schlimmsten Fall auszulegen ist
für einen Wert, der sich um den Faktor tausend ändert, die falsche Antwort.
Gemessen wird jetzt, was dasteht — mit unsymmetrischer Hysterese: sofort
wachsen, denn abgeschnittene Messwerte sind falsche Messwerte, und erst nach
zehn ruhigeren Messungen schrumpfen, damit ein Lastausschlag die Leiste nicht
zum Pumpen bringt.

Das Akkusymbol war zerquetscht. Ein Batteriesymbol ist doppelt so breit wie
hoch und wurde in ein Quadrat gezeichnet. Symbole behalten jetzt ihr
Seitenverhältnis, und die Breite des Elements richtet sich nach dem, was das
Symbol tatsächlich braucht — sonst hätte ein breites Glyph dieselbe Spalte
wie ein schmales.

Bei den Sensoren stand stumm das Maximum über alle Punkte: eine Zahl, von
der niemand weiß, woher sie kommt. Jetzt wählbar, und der gewählte Sensor
gibt sein eigenes Kürzel — „Temp 46°" sagt weniger als „Heatpipe 46°".
Voreinstellung bleibt der wärmste Punkt, weil das die häufigste Frage ist.

Und die Lüfterkachel zeigte „2500" ohne Einheit.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-08-11 12:46:06 +02:00
parent 386eb6ae70
commit 70a665f532
9 changed files with 969 additions and 671 deletions

View File

@@ -0,0 +1,73 @@
import Testing
import CoreGraphics
@testable import OnyxMenuBar
// Eine feste Breite für den schlimmsten Fall lässt neben jedem gewöhnlichen
// Wert Platz stehen: 13 KB/s" braucht gut halb so viel wie 999,9 MB/s".
// Eine Breite, die jedem Wert folgt, schiebt dagegen bei jeder Messung alle
// Symbole rechts davon hin und her.
//
// Also: sofort wachsen, aber erst nach einer Weile schrumpfen.
@Suite("Mitwachsende Breite")
struct AdaptiveWidthTests {
@Test("Am Anfang gilt, was gebraucht wird")
func startsAtNeeded() {
var width = AdaptiveWidth(minimum: 20)
#expect(width.update(needed: 60) == 60)
}
@Test("Mehr Platz wird sofort genommen")
func growsImmediately() {
// Sonst wird abgeschnitten, und abgeschnittene Messwerte sind falsche
// Messwerte.
var width = AdaptiveWidth(minimum: 20)
_ = width.update(needed: 40)
#expect(width.update(needed: 80) == 80)
}
@Test("Weniger Platz wird nicht sofort abgegeben")
func shrinksOnlyAfterPatience() {
var width = AdaptiveWidth(minimum: 20)
_ = width.update(needed: 80)
for _ in 0..<(AdaptiveWidth.shrinkAfter - 1) {
#expect(width.update(needed: 40) == 80)
}
}
@Test("Nach genügend ruhigen Messungen schrumpft es")
func shrinksEventually() {
var width = AdaptiveWidth(minimum: 20)
_ = width.update(needed: 80)
var last: CGFloat = 0
for _ in 0..<AdaptiveWidth.shrinkAfter { last = width.update(needed: 40) }
#expect(last == 40)
}
@Test("Ein einzelner Ausreißer setzt die Geduld zurück")
func spikeResetsPatience() {
// Ein kurzer Lastausschlag darf nicht dazu führen, dass gleich danach
// geschrumpft und beim nächsten Ausschlag wieder gewachsen wird.
var width = AdaptiveWidth(minimum: 20)
_ = width.update(needed: 80)
for _ in 0..<(AdaptiveWidth.shrinkAfter - 1) { _ = width.update(needed: 40) }
_ = width.update(needed: 80)
#expect(width.update(needed: 40) == 80)
}
@Test("Unter die Mindestbreite geht es nie")
func neverBelowMinimum() {
var width = AdaptiveWidth(minimum: 20)
var last: CGFloat = 0
for _ in 0...AdaptiveWidth.shrinkAfter { last = width.update(needed: 5) }
#expect(last == 20)
}
@Test("Gleichbleibende Werte ändern nichts")
func steadyValueIsStable() {
var width = AdaptiveWidth(minimum: 20)
_ = width.update(needed: 55)
for _ in 0..<20 { #expect(width.update(needed: 55) == 55) }
}
}