Files
MacMonitor/Sources/UI/ContentView.swift

228 lines
8.4 KiB
Swift

import SwiftUI
public struct ContentView: View {
@State private var store = SystemTelemetryStore.shared
public init() {}
public var body: some View {
NavigationSplitView {
sidebarContent
} detail: {
detailContent
}
.frame(minWidth: 800, minHeight: 520)
.onAppear {
store.start()
}
}
private var sidebarContent: some View {
List {
Section("System Status") {
Label("Dashboard", systemImage: "gauge.with.needle")
Label("Architecture", systemImage: "cpu")
}
Section("Telemetry Domains") {
Label("CPU & Thermals", systemImage: "flame")
Label("Fans & Cooling", systemImage: "fanblades")
Label("Memory & Swap", systemImage: "memorychip")
Label("Disks & Volumes", systemImage: "internaldrive")
Label("Processes", systemImage: "list.bullet.rectangle")
Label("Network", systemImage: "network")
Label("Graphics (GPU)", systemImage: "display")
}
}
.listStyle(.sidebar)
.navigationSplitViewColumnWidth(min: 200, ideal: 220, max: 280)
}
private var detailContent: some View {
ScrollView {
VStack(alignment: .leading, spacing: 20) {
// Header Banner
headerCard
// Telemetry Engine Control
engineControlCard
// System Specifications
specsCard
// Providers Status
providersCard
}
.padding(24)
}
.navigationTitle("MacMonitor Dashboard")
}
private var headerCard: some View {
HStack(alignment: .center, spacing: 16) {
Image(systemName: "macpro.gen3.fill")
.resizable()
.scaledToFit()
.frame(width: 48, height: 48)
.foregroundStyle(.blue)
VStack(alignment: .leading, spacing: 4) {
Text(store.hostModel)
.font(.title2.bold())
Text("Intel x86_64 • \(store.osVersion)")
.font(.subheadline)
.foregroundStyle(.secondary)
}
Spacer()
HStack(spacing: 8) {
Circle()
.fill(store.isRunning ? Color.green : Color.red)
.frame(width: 10, height: 10)
Text(store.isRunning ? "ENGINE ACTIVE" : "ENGINE PAUSED")
.font(.caption.bold())
.foregroundStyle(store.isRunning ? .green : .secondary)
}
.padding(.horizontal, 12)
.padding(.vertical, 6)
.background(.quaternary, in: Capsule())
}
.padding(16)
.background(.background, in: RoundedRectangle(cornerRadius: 12))
.overlay(RoundedRectangle(cornerRadius: 12).stroke(.separator, lineWidth: 1))
}
private var engineControlCard: some View {
VStack(alignment: .leading, spacing: 12) {
Text("Telemetry Coordinator Engine")
.font(.headline)
HStack(spacing: 16) {
Button(action: {
if store.isRunning {
store.stop()
} else {
store.start()
}
}) {
Label(store.isRunning ? "Pause Engine" : "Start Engine",
systemImage: store.isRunning ? "pause.fill" : "play.fill")
}
.buttonStyle(.borderedProminent)
.tint(store.isRunning ? .orange : .green)
Button(action: {
store.triggerManualSample()
}) {
Label("Sample Now", systemImage: "arrow.clockwise")
}
.buttonStyle(.bordered)
Spacer()
Picker("Polling Interval:", selection: Binding(
get: { store.sampleInterval },
set: { store.setSampleInterval($0) }
)) {
Text("0.5s").tag(0.5)
Text("1.0s").tag(1.0)
Text("2.0s").tag(2.0)
Text("5.0s").tag(5.0)
}
.pickerStyle(.segmented)
.frame(width: 220)
}
HStack {
Text("Last Sample Cycle: \(store.lastUpdateTimestamp.formatted(date: .omitted, time: .standard))")
.font(.caption)
.foregroundStyle(.secondary)
Spacer()
Text("Queue: com.i3omb.macmonitor.telemetry (QOS_UTILITY)")
.font(.caption)
.foregroundStyle(.secondary)
}
}
.padding(16)
.background(.background, in: RoundedRectangle(cornerRadius: 12))
.overlay(RoundedRectangle(cornerRadius: 12).stroke(.separator, lineWidth: 1))
}
private var specsCard: some View {
VStack(alignment: .leading, spacing: 12) {
Text("Host Architecture & Kernel")
.font(.headline)
Grid(alignment: .leading, horizontalSpacing: 24, verticalSpacing: 10) {
GridRow {
Text("Hardware Model:").foregroundStyle(.secondary)
Text(store.hostModel).bold()
Text("Physical Cores:").foregroundStyle(.secondary)
Text("\(store.physicalCpuCount)").bold()
}
GridRow {
Text("Darwin Kernel:").foregroundStyle(.secondary)
Text(store.kernelVersion).bold()
Text("Logical Cores:").foregroundStyle(.secondary)
Text("\(store.logicalCpuCount)").bold()
}
GridRow {
Text("Target Architecture:").foregroundStyle(.secondary)
Text("Intel x86_64").bold()
Text("Deployment Target:").foregroundStyle(.secondary)
Text("macOS 14.0 (Sonoma)").bold()
}
}
}
.padding(16)
.background(.background, in: RoundedRectangle(cornerRadius: 12))
.overlay(RoundedRectangle(cornerRadius: 12).stroke(.separator, lineWidth: 1))
}
private var providersCard: some View {
VStack(alignment: .leading, spacing: 12) {
HStack {
Text("Registered Telemetry Providers")
.font(.headline)
Spacer()
Text("\(store.registeredProviderCount) Active")
.font(.caption.bold())
.padding(.horizontal, 8)
.padding(.vertical, 4)
.background(Color.blue.opacity(0.15))
.foregroundStyle(.blue)
.clipShape(Capsule())
}
if store.latestSnapshot.isEmpty {
HStack(spacing: 12) {
Image(systemName: "info.circle")
.foregroundStyle(.secondary)
Text("Telemetry coordinator initialized. Awaiting provider metrics.")
.font(.subheadline)
.foregroundStyle(.secondary)
}
.padding(.vertical, 8)
} else {
ForEach(Array(store.latestSnapshot.keys.sorted()), id: \.self) { key in
HStack {
Image(systemName: "checkmark.circle.fill")
.foregroundStyle(.green)
Text(key)
.font(.system(.body, design: .monospaced))
Spacer()
Text("\(store.latestSnapshot[key]?.count ?? 0) metrics")
.font(.caption)
.foregroundStyle(.secondary)
}
.padding(.vertical, 4)
}
}
}
.padding(16)
.background(.background, in: RoundedRectangle(cornerRadius: 12))
.overlay(RoundedRectangle(cornerRadius: 12).stroke(.separator, lineWidth: 1))
}
}