mirror of
https://github.com/morgan9e/macos-stats
synced 2026-04-15 00:34:08 +09:00
feat: initialized first widget for the CPU module
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
|
||||
import Cocoa
|
||||
import Kit
|
||||
import WidgetKit
|
||||
|
||||
public struct CPU_Load: Codable {
|
||||
var totalUsage: Double = 0
|
||||
@@ -82,6 +83,8 @@ public class CPU: Module {
|
||||
return color.additional as! NSColor
|
||||
}
|
||||
|
||||
private var userDefaults: UserDefaults? = UserDefaults(suiteName: "eu.exelban.Stats.widgets")
|
||||
|
||||
public init() {
|
||||
self.settingsView = Settings(.CPU)
|
||||
self.popupView = Popup(.CPU)
|
||||
@@ -157,6 +160,12 @@ public class CPU: Module {
|
||||
self.portalView.callback(value)
|
||||
self.notificationsView.loadCallback(value)
|
||||
|
||||
if #available(macOS 11.0, *) {
|
||||
guard let blobData = try? JSONEncoder().encode(value) else { return }
|
||||
self.userDefaults?.set(blobData, forKey: "CPU@LoadReader")
|
||||
WidgetCenter.shared.reloadTimelines(ofKind: CPU_entry.kind)
|
||||
}
|
||||
|
||||
self.menuBar.widgets.filter{ $0.isActive }.forEach { (w: Widget) in
|
||||
switch w.item {
|
||||
case let widget as Mini: widget.setValue(value.totalUsage)
|
||||
|
||||
111
Modules/CPU/widget.swift
Normal file
111
Modules/CPU/widget.swift
Normal file
@@ -0,0 +1,111 @@
|
||||
//
|
||||
// widget.swift
|
||||
// CPU
|
||||
//
|
||||
// Created by Serhiy Mytrovtsiy on 01/07/2024
|
||||
// Using Swift 5.0
|
||||
// Running on macOS 14.5
|
||||
//
|
||||
// Copyright © 2024 Serhiy Mytrovtsiy. All rights reserved.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import WidgetKit
|
||||
import Charts
|
||||
|
||||
public struct CPU_entry: TimelineEntry {
|
||||
public static let kind = "CPUWidget"
|
||||
public static var snapshot: CPU_entry = CPU_entry(value: CPU_Load(totalUsage: 0.34, systemLoad: 0.11, userLoad: 0.23, idleLoad: 0.66))
|
||||
|
||||
public var date: Date {
|
||||
Calendar.current.date(byAdding: .second, value: 5, to: Date())!
|
||||
}
|
||||
public var value: CPU_Load? = nil
|
||||
}
|
||||
|
||||
@available(macOS 11.0, *)
|
||||
public struct Provider: TimelineProvider {
|
||||
public typealias Entry = CPU_entry
|
||||
|
||||
private let userDefaults: UserDefaults? = UserDefaults(suiteName: "eu.exelban.Stats.widgets")
|
||||
|
||||
public func placeholder(in context: Context) -> CPU_entry {
|
||||
CPU_entry()
|
||||
}
|
||||
|
||||
public func getSnapshot(in context: Context, completion: @escaping (CPU_entry) -> Void) {
|
||||
completion(CPU_entry.snapshot)
|
||||
}
|
||||
|
||||
public func getTimeline(in context: Context, completion: @escaping (Timeline<CPU_entry>) -> Void) {
|
||||
var entry = CPU_entry()
|
||||
if let raw = userDefaults?.data(forKey: "CPU@LoadReader"), let load = try? JSONDecoder().decode(CPU_Load.self, from: raw) {
|
||||
entry.value = load
|
||||
}
|
||||
let entries: [CPU_entry] = [entry]
|
||||
completion(Timeline(entries: entries, policy: .atEnd))
|
||||
}
|
||||
}
|
||||
|
||||
@available(macOS 14.0, *)
|
||||
public struct CPUWidget: Widget {
|
||||
var systemColor: Color = Color(nsColor: NSColor.systemRed)
|
||||
var userColor: Color = Color(nsColor: NSColor.systemBlue)
|
||||
var idleColor: Color = Color(nsColor: NSColor.lightGray)
|
||||
|
||||
public init() {}
|
||||
|
||||
public var body: some WidgetConfiguration {
|
||||
StaticConfiguration(kind: CPU_entry.kind, provider: Provider()) { entry in
|
||||
VStack(spacing: 10) {
|
||||
if let value = entry.value {
|
||||
HStack {
|
||||
Chart {
|
||||
SectorMark(angle: .value("System load", value.systemLoad), innerRadius: .ratio(0.8)).foregroundStyle(self.systemColor)
|
||||
SectorMark(angle: .value("User load", value.userLoad), innerRadius: .ratio(0.8)).foregroundStyle(self.userColor)
|
||||
SectorMark(angle: .value("Idle", value.idleLoad), innerRadius: .ratio(0.8)).foregroundStyle(self.idleColor)
|
||||
}
|
||||
.frame(maxWidth: .infinity, maxHeight: 84)
|
||||
.chartLegend(.hidden)
|
||||
.chartBackground { chartProxy in
|
||||
GeometryReader { geometry in
|
||||
if let anchor = chartProxy.plotFrame {
|
||||
let frame = geometry[anchor]
|
||||
Text("\(Int(value.totalUsage*100))%")
|
||||
.font(.system(size: 16, weight: .regular))
|
||||
.position(x: frame.midX, y: frame.midY)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
VStack(spacing: 3) {
|
||||
HStack {
|
||||
Rectangle().fill(self.systemColor).frame(width: 12, height: 12).cornerRadius(2)
|
||||
Text("System:")
|
||||
.font(.system(size: 12, weight: .regular))
|
||||
.foregroundColor(.secondary)
|
||||
Spacer()
|
||||
Text("\(Int(value.systemLoad*100))%")
|
||||
}
|
||||
HStack {
|
||||
Rectangle().fill(self.userColor).frame(width: 12, height: 12).cornerRadius(2)
|
||||
Text("User:")
|
||||
.font(.system(size: 12, weight: .regular))
|
||||
.foregroundColor(.secondary)
|
||||
Spacer()
|
||||
Text("\(Int(value.userLoad*100))%")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Text("No data")
|
||||
}
|
||||
}
|
||||
.containerBackground(for: .widget) {
|
||||
Color.clear
|
||||
}
|
||||
}
|
||||
.configurationDisplayName("CPU widget")
|
||||
.description("Displays CPU stats")
|
||||
.supportedFamilies([.systemSmall])
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user