Sechs neue Widgets (CPU, GPU, Speicher, Akku, Sensoren, Netzwerk) und dieselben sechs als einzeln aktivierbare Menüleisten-Module mit fünf Darstellungsarten. Panel-Widget und Menüleisten-Modul derselben Größe teilen sich die Messschleife über Referenzzählung. Ohne das liefe für jede Anzeige ein eigener Timer mit denselben IOKit- und SMC-Abfragen — bei sechs Modulen und ebenso vielen Widgets ein Vielfaches der nötigen Arbeit. Meldet sich der letzte Konsument ab, hört die Schleife auf; im Ruhezustand misst Onyx nichts. Die Differenzrechnung ist testgetrieben, und die Tests haben zwei echte Fehler gefunden. Erstens: mein Überlaufschutz beim Durchsatz hielt einen zurückgesetzten Zähler (Interface-Wechsel) für einen Überlauf und zeigte 4,3 GB/s. Da if_data64 64-Bit-Zähler liefert, die bei 10 Gbit/s erst nach 470 Jahren umlaufen, ist ein kleinerer Wert immer ein Zurücksetzen — die Unterscheidung produzierte nur den Ausreißer, den sie verhindern sollte. Zweitens: ByteCountFormatter schrieb bei null „Zero KB/s" statt „0 KB/s". Bei den CPU-Zählern bleibt der Überlaufschutz nötig: die sind 32 Bit breit und laufen nach gut 400 Tagen wirklich um, deshalb `&-` statt `-`. Sensoren kommen über den SMC-Leser aus Spike A statt über die private IOHID-Schnittstelle — auf dieser Maschine nachweislich verifiziert, und die dort gefundene Little-Endian-Eigenheit ist berücksichtigt. Nur eine kurze Liste benannter Fühler statt aller 3486 Keys: eine Wand aus Kürzeln ist keine Information. Gegengemessen statt vermutet: 15 Kerne, 39,8 W, GPU 50 %, 16,6/24 GB mit kritischem Druck, Akku 68 Zyklen bei 100 % Gesundheit, fünf Sensoren, zwei Lüfter, en0 mit 661 KB/s. Menüleisten-Module zeichnen in labelColor statt in den Onyx-Farben — nur die Systemfarbe passt sich heller wie dunkler Leiste an. Feste Breite je Darstellungsart, sonst schiebt jeder Messwert die halbe Leiste hin und her. Standardmäßig ist kein Modul aktiv: sechs neue Symbole beim ersten Start wären eine Zumutung. 145 Tests grün.
59 lines
2.4 KiB
Swift
59 lines
2.4 KiB
Swift
import SwiftUI
|
|
import OnyxDesign
|
|
import OnyxWidgetKit
|
|
|
|
/// Vorläufige Widgets für Phase 2.
|
|
///
|
|
/// Sie tragen keine echten Daten — ihr Zweck ist zu belegen, dass Registry,
|
|
/// Layout-Engine, Persistenz und Panelgröße zusammenspielen, bevor die Provider
|
|
/// dazukommen. Jedes wird in seiner Phase durch das echte Widget ersetzt; die
|
|
/// Kennungen bleiben dabei gleich, damit gespeicherte Layouts weitergelten.
|
|
struct PlaceholderWidget: OnyxWidget {
|
|
let id: String
|
|
let displayName: String
|
|
let symbolName: String
|
|
let supportedSizes: [WidgetSize]
|
|
/// In welcher Phase dieses Widget echt wird.
|
|
let phase: String
|
|
|
|
func makeView(size: WidgetSize) -> AnyView {
|
|
AnyView(
|
|
VStack(alignment: .leading, spacing: 6) {
|
|
HStack(spacing: 6) {
|
|
Image(systemName: symbolName)
|
|
.font(.system(size: 12, weight: .medium))
|
|
.foregroundStyle(Onyx.Color.accent)
|
|
Text(displayName)
|
|
.font(Onyx.Font.caption)
|
|
.foregroundStyle(Onyx.Color.textSecondary)
|
|
}
|
|
Spacer(minLength: 0)
|
|
Text(phase)
|
|
.font(Onyx.Font.caption)
|
|
.foregroundStyle(Onyx.Color.textTertiary)
|
|
}
|
|
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading)
|
|
)
|
|
}
|
|
}
|
|
|
|
@MainActor
|
|
enum PlaceholderWidgets {
|
|
/// Registriert nur noch die Karten, deren echte Fassung fehlt. Sobald ein
|
|
/// Widget umgesetzt ist, verschwindet es hier — die Kennung bleibt gleich,
|
|
/// damit gespeicherte Layouts weitergelten.
|
|
static func registerAll() {
|
|
let widgets: [PlaceholderWidget] = [
|
|
.init(id: "fans", displayName: "Lüfter", symbolName: "fan",
|
|
supportedSizes: [.small, .medium], phase: "Phase 6"),
|
|
.init(id: "audio", displayName: "Audio-Mixer", symbolName: "slider.horizontal.3",
|
|
supportedSizes: [.medium, .large], phase: "Phase 7"),
|
|
.init(id: "shelf", displayName: "Ablage", symbolName: "tray.full",
|
|
supportedSizes: [.small, .medium], phase: "Phase 8"),
|
|
.init(id: "airdrop", displayName: "AirDrop", symbolName: "shareplay",
|
|
supportedSizes: [.small], phase: "Phase 8"),
|
|
]
|
|
widgets.forEach { WidgetRegistry.shared.register($0) }
|
|
}
|
|
}
|