mirror of
https://github.com/morgan9e/macos-stats
synced 2026-04-14 00:04:15 +09:00
feat: updated Disk portal view
This commit is contained in:
@@ -24,7 +24,7 @@ public class NetworkChart: WidgetWrapper {
|
||||
|
||||
private var chart: NetworkChartView = NetworkChartView(
|
||||
frame: NSRect(x: 0, y: 0, width: 30, height: Constants.Widget.height - (2*Constants.Widget.margin.y)),
|
||||
num: 60, minMax: false
|
||||
num: 60, minMax: false, toolTip: false
|
||||
)
|
||||
private var width: CGFloat {
|
||||
get {
|
||||
|
||||
@@ -300,14 +300,16 @@ public class NetworkChartView: NSView {
|
||||
private var commonScale: Bool = true
|
||||
private var reverseOrder: Bool = false
|
||||
|
||||
private var cursorToolTip: Bool = false
|
||||
private var cursor: NSPoint? = nil
|
||||
private var stop: Bool = false
|
||||
|
||||
public init(frame: NSRect, num: Int, minMax: Bool = true, outColor: NSColor = .systemRed, inColor: NSColor = .systemBlue) {
|
||||
public init(frame: NSRect, num: Int, minMax: Bool = true, outColor: NSColor = .systemRed, inColor: NSColor = .systemBlue, toolTip: Bool = false) {
|
||||
self.minMax = minMax
|
||||
self.points = Array(repeating: (0, 0), count: num)
|
||||
self.topColor = inColor
|
||||
self.bottomColor = outColor
|
||||
self.cursorToolTip = toolTip
|
||||
super.init(frame: frame)
|
||||
|
||||
self.addTrackingArea(NSTrackingArea(
|
||||
@@ -561,30 +563,36 @@ public class NetworkChartView: NSView {
|
||||
}
|
||||
|
||||
public override func mouseEntered(with event: NSEvent) {
|
||||
guard self.cursorToolTip else { return }
|
||||
self.cursor = convert(event.locationInWindow, from: nil)
|
||||
self.needsDisplay = true
|
||||
}
|
||||
|
||||
public override func mouseMoved(with event: NSEvent) {
|
||||
guard self.cursorToolTip else { return }
|
||||
self.cursor = convert(event.locationInWindow, from: nil)
|
||||
self.needsDisplay = true
|
||||
}
|
||||
|
||||
public override func mouseDragged(with event: NSEvent) {
|
||||
guard self.cursorToolTip else { return }
|
||||
self.cursor = convert(event.locationInWindow, from: nil)
|
||||
self.needsDisplay = true
|
||||
}
|
||||
|
||||
public override func mouseExited(with event: NSEvent) {
|
||||
guard self.cursorToolTip else { return }
|
||||
self.cursor = nil
|
||||
self.needsDisplay = true
|
||||
}
|
||||
|
||||
public override func mouseDown(with: NSEvent) {
|
||||
guard self.cursorToolTip else { return }
|
||||
self.shadowPoints = self.points
|
||||
self.stop = true
|
||||
}
|
||||
public override func mouseUp(with: NSEvent) {
|
||||
guard self.cursorToolTip else { return }
|
||||
self.stop = false
|
||||
}
|
||||
}
|
||||
@@ -858,11 +866,11 @@ public class BarChartView: NSView {
|
||||
let value = self.values[i]
|
||||
let color = value.color ?? .controlAccentColor
|
||||
let activeBlockNum = Int(round(value.value*Double(blocks)))
|
||||
let h = value.value*partitionSize.height
|
||||
let h = value.value*(partitionSize.height-spacing)
|
||||
|
||||
if dirtyRect.height < 30 && h != 0 {
|
||||
if dirtyRect.height < 30 && h != 0 {
|
||||
let block = NSBezierPath(
|
||||
roundedRect: NSRect(x: x+spacing, y: 1, width: partitionSize.width-(spacing*2), height: value.value*partitionSize.height),
|
||||
roundedRect: NSRect(x: x+spacing, y: 1, width: partitionSize.width-(spacing*2), height: h),
|
||||
xRadius: 1, yRadius: 1
|
||||
)
|
||||
color.setFill()
|
||||
|
||||
@@ -47,6 +47,8 @@ public class Portal: PortalWrapper {
|
||||
private var pCoresColor: NSColor { self.pCoresColorState.additional as? NSColor ?? NSColor.systemBlue }
|
||||
|
||||
public override func load() {
|
||||
self.loadColors()
|
||||
|
||||
let view = NSStackView()
|
||||
view.orientation = .horizontal
|
||||
view.distribution = .fillEqually
|
||||
@@ -70,6 +72,14 @@ public class Portal: PortalWrapper {
|
||||
detailsView.heightAnchor.constraint(equalTo: view.heightAnchor).isActive = true
|
||||
}
|
||||
|
||||
public func loadColors() {
|
||||
self.systemColorState = Color.fromString(Store.shared.string(key: "\(self.name)_systemColor", defaultValue: self.systemColorState.key))
|
||||
self.userColorState = Color.fromString(Store.shared.string(key: "\(self.name)_userColor", defaultValue: self.userColorState.key))
|
||||
self.idleColorState = Color.fromString(Store.shared.string(key: "\(self.name)_idleColor", defaultValue: self.idleColorState.key))
|
||||
self.eCoresColorState = Color.fromString(Store.shared.string(key: "\(self.name)_eCoresColor", defaultValue: self.eCoresColorState.key))
|
||||
self.pCoresColorState = Color.fromString(Store.shared.string(key: "\(self.name)_pCoresColor", defaultValue: self.pCoresColorState.key))
|
||||
}
|
||||
|
||||
private func charts() -> NSView {
|
||||
let view = NSStackView()
|
||||
view.orientation = .vertical
|
||||
@@ -145,7 +155,7 @@ public class Portal: PortalWrapper {
|
||||
var usagePerCore: [ColorValue] = []
|
||||
if let cores = SystemKit.shared.device.info.cpu?.cores, cores.count == value.usagePerCore.count {
|
||||
for i in 0..<value.usagePerCore.count {
|
||||
usagePerCore.append(ColorValue(value.usagePerCore[i], color: cores[i].type == .efficiency ? NSColor.systemTeal : NSColor.systemBlue))
|
||||
usagePerCore.append(ColorValue(value.usagePerCore[i], color: cores[i].type == .efficiency ? self.eCoresColor : self.pCoresColor))
|
||||
}
|
||||
} else {
|
||||
for i in 0..<value.usagePerCore.count {
|
||||
|
||||
@@ -44,6 +44,16 @@ public struct drive: Codable {
|
||||
|
||||
var activity: stats = stats()
|
||||
var smart: smart_t? = nil
|
||||
|
||||
var percentage: Double {
|
||||
let total = self.size
|
||||
let free = self.free
|
||||
var usedSpace = total - free
|
||||
if usedSpace < 0 {
|
||||
usedSpace = 0
|
||||
}
|
||||
return Double(usedSpace) / Double(total)
|
||||
}
|
||||
}
|
||||
|
||||
public class Disks: Codable {
|
||||
@@ -194,7 +204,7 @@ public class Disk: Module {
|
||||
|
||||
private let popupView: Popup = Popup()
|
||||
private let settingsView: Settings = Settings()
|
||||
private let portalView: Portal = Portal()
|
||||
private let portalView: Portal = Portal(.disk)
|
||||
private let notificationsView: Notifications
|
||||
|
||||
private var capacityReader: CapacityReader = CapacityReader(.disk)
|
||||
@@ -276,25 +286,17 @@ public class Disk: Module {
|
||||
return
|
||||
}
|
||||
|
||||
let total = d.size
|
||||
let free = d.free
|
||||
var usedSpace = total - free
|
||||
if usedSpace < 0 {
|
||||
usedSpace = 0
|
||||
}
|
||||
let percentage = Double(usedSpace) / Double(total)
|
||||
|
||||
self.portalView.loadCallback(percentage)
|
||||
self.notificationsView.utilizationCallback(percentage)
|
||||
self.portalView.utilizationCallback(d)
|
||||
self.notificationsView.utilizationCallback(d.percentage)
|
||||
|
||||
self.menuBar.widgets.filter{ $0.isActive }.forEach { (w: Widget) in
|
||||
switch w.item {
|
||||
case let widget as Mini: widget.setValue(percentage)
|
||||
case let widget as BarChart: widget.setValue([[ColorValue(percentage)]])
|
||||
case let widget as MemoryWidget: widget.setValue((DiskSize(free).getReadableMemory(), DiskSize(usedSpace).getReadableMemory()))
|
||||
case let widget as Mini: widget.setValue(d.percentage)
|
||||
case let widget as BarChart: widget.setValue([[ColorValue(d.percentage)]])
|
||||
case let widget as MemoryWidget: widget.setValue((DiskSize(d.free).getReadableMemory(), DiskSize(d.size - d.free).getReadableMemory()))
|
||||
case let widget as PieChart:
|
||||
widget.setValue([
|
||||
circle_segment(value: percentage, color: NSColor.systemBlue)
|
||||
circle_segment(value: d.percentage, color: NSColor.systemBlue)
|
||||
])
|
||||
default: break
|
||||
}
|
||||
@@ -302,9 +304,7 @@ public class Disk: Module {
|
||||
}
|
||||
|
||||
private func activityCallback(_ value: Disks) {
|
||||
guard self.enabled else {
|
||||
return
|
||||
}
|
||||
guard self.enabled else { return }
|
||||
|
||||
DispatchQueue.main.async(execute: {
|
||||
self.popupView.activityCallback(value)
|
||||
@@ -314,6 +314,8 @@ public class Disk: Module {
|
||||
return
|
||||
}
|
||||
|
||||
self.portalView.activityCallback(d)
|
||||
|
||||
self.menuBar.widgets.filter{ $0.isActive }.forEach { (w: Widget) in
|
||||
switch w.item {
|
||||
case let widget as SpeedWidget: widget.setValue(upload: d.activity.write, download: d.activity.read)
|
||||
|
||||
@@ -16,21 +16,9 @@ internal class Popup: PopupWrapper {
|
||||
private var title: String
|
||||
|
||||
private var readColorState: Color = .secondBlue
|
||||
private var readColor: NSColor {
|
||||
var value = NSColor.systemRed
|
||||
if let color = self.readColorState.additional as? NSColor {
|
||||
value = color
|
||||
}
|
||||
return value
|
||||
}
|
||||
private var readColor: NSColor { self.readColorState.additional as? NSColor ?? NSColor.systemRed }
|
||||
private var writeColorState: Color = .secondRed
|
||||
private var writeColor: NSColor {
|
||||
var value = NSColor.systemBlue
|
||||
if let color = self.writeColorState.additional as? NSColor {
|
||||
value = color
|
||||
}
|
||||
return value
|
||||
}
|
||||
private var writeColor: NSColor { self.writeColorState.additional as? NSColor ?? NSColor.systemBlue }
|
||||
|
||||
private var disks: NSStackView = {
|
||||
let view = NSStackView()
|
||||
@@ -239,7 +227,7 @@ internal class DiskView: NSStackView {
|
||||
private var temperatureView: TemperatureView?
|
||||
private var lifeView: LifeView?
|
||||
|
||||
init(width: CGFloat, BSDName: String, name: String, size: Int64, free: Int64, path: URL?, smart: smart_t?) {
|
||||
init(width: CGFloat, BSDName: String = "", name: String = "", size: Int64 = 1, free: Int64 = 1, path: URL? = nil, smart: smart_t? = nil) {
|
||||
self.BSDName = BSDName
|
||||
self.name = name
|
||||
let innerWidth: CGFloat = width - (Constants.Popup.margins * 2)
|
||||
|
||||
@@ -12,55 +12,112 @@
|
||||
import Cocoa
|
||||
import Kit
|
||||
|
||||
internal class Portal: NSStackView, Portal_p {
|
||||
internal var name: String { Disk.name }
|
||||
|
||||
public class Portal: PortalWrapper {
|
||||
private var circle: PieChartView? = nil
|
||||
private var chart: NetworkChartView? = nil
|
||||
|
||||
private var nameField: NSTextField? = nil
|
||||
private var usedField: NSTextField? = nil
|
||||
private var freeField: NSTextField? = nil
|
||||
|
||||
private var valueColorState: Color = .secondBlue
|
||||
private var valueColor: NSColor { self.valueColorState.additional as? NSColor ?? NSColor.systemBlue }
|
||||
|
||||
private var readColor: NSColor {
|
||||
Color.fromString(Store.shared.string(key: "\(Disk.name)_readColor", defaultValue: Color.secondBlue.key)).additional as! NSColor
|
||||
}
|
||||
private var writeColor: NSColor {
|
||||
Color.fromString(Store.shared.string(key: "\(Disk.name)_writeColor", defaultValue: Color.secondRed.key)).additional as! NSColor
|
||||
}
|
||||
|
||||
private var initialized: Bool = false
|
||||
|
||||
init() {
|
||||
super.init(frame: NSRect.zero)
|
||||
public override func load() {
|
||||
self.loadColors()
|
||||
|
||||
self.wantsLayer = true
|
||||
self.layer?.backgroundColor = NSColor.windowBackgroundColor.cgColor
|
||||
self.layer?.cornerRadius = 3
|
||||
|
||||
self.orientation = .vertical
|
||||
self.distribution = .fillEqually
|
||||
self.spacing = Constants.Popup.spacing*2
|
||||
self.edgeInsets = NSEdgeInsets(
|
||||
top: Constants.Popup.spacing*2,
|
||||
let view = NSStackView()
|
||||
view.orientation = .horizontal
|
||||
view.distribution = .fillEqually
|
||||
view.spacing = Constants.Popup.spacing*2
|
||||
view.edgeInsets = NSEdgeInsets(
|
||||
top: 0,
|
||||
left: Constants.Popup.spacing*2,
|
||||
bottom: Constants.Popup.spacing*2,
|
||||
bottom: 0,
|
||||
right: Constants.Popup.spacing*2
|
||||
)
|
||||
self.addArrangedSubview(PortalHeader(name))
|
||||
|
||||
self.circle = PieChartView(frame: NSRect.zero, segments: [], drawValue: true)
|
||||
self.circle!.toolTip = localizedString("Disk usage")
|
||||
self.addArrangedSubview(self.circle!)
|
||||
let chartsView = self.charts()
|
||||
let detailsView = self.details()
|
||||
|
||||
self.heightAnchor.constraint(equalToConstant: Constants.Popup.portalHeight).isActive = true
|
||||
view.addArrangedSubview(chartsView)
|
||||
view.addArrangedSubview(detailsView)
|
||||
|
||||
self.addArrangedSubview(view)
|
||||
|
||||
chartsView.heightAnchor.constraint(equalTo: view.heightAnchor).isActive = true
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
private func loadColors() {
|
||||
self.valueColorState = Color.fromString(Store.shared.string(key: "\(self.name)_valueColor", defaultValue: self.valueColorState.key))
|
||||
}
|
||||
|
||||
public override func updateLayer() {
|
||||
self.layer?.backgroundColor = NSColor.windowBackgroundColor.cgColor
|
||||
private func charts() -> NSView {
|
||||
let view = NSStackView()
|
||||
view.orientation = .vertical
|
||||
view.distribution = .fillEqually
|
||||
view.spacing = Constants.Popup.spacing*2
|
||||
view.edgeInsets = NSEdgeInsets(
|
||||
top: Constants.Popup.spacing*4,
|
||||
left: Constants.Popup.spacing*4,
|
||||
bottom: Constants.Popup.spacing*4,
|
||||
right: Constants.Popup.spacing*4
|
||||
)
|
||||
|
||||
let chart = PieChartView(frame: NSRect.zero, segments: [], drawValue: true)
|
||||
chart.toolTip = localizedString("Disk usage")
|
||||
view.addArrangedSubview(chart)
|
||||
self.circle = chart
|
||||
|
||||
return view
|
||||
}
|
||||
|
||||
public func loadCallback(_ value: Double) {
|
||||
private func details() -> NSView {
|
||||
let view = NSStackView()
|
||||
view.orientation = .vertical
|
||||
view.distribution = .fillEqually
|
||||
view.spacing = Constants.Popup.spacing*2
|
||||
|
||||
self.nameField = portalRow(view, title: "\(localizedString("Name")):")
|
||||
self.usedField = portalRow(view, title: "\(localizedString("Used")):")
|
||||
self.freeField = portalRow(view, title: "\(localizedString("Free")):")
|
||||
|
||||
let chart = NetworkChartView(frame: NSRect.zero, num: 120, minMax: false, outColor: self.writeColor, inColor: self.readColor)
|
||||
chart.heightAnchor.constraint(equalToConstant: 26).isActive = true
|
||||
self.chart = chart
|
||||
view.addArrangedSubview(chart)
|
||||
|
||||
return view
|
||||
}
|
||||
|
||||
internal func utilizationCallback(_ value: drive) {
|
||||
DispatchQueue.main.async(execute: {
|
||||
if (self.window?.isVisible ?? false) || !self.initialized {
|
||||
self.circle?.setValue(value)
|
||||
self.nameField?.stringValue = value.mediaName
|
||||
self.usedField?.stringValue = DiskSize(value.size - value.free).getReadableMemory()
|
||||
self.freeField?.stringValue = DiskSize(value.free).getReadableMemory()
|
||||
|
||||
self.circle?.setValue(value.percentage)
|
||||
self.circle?.setSegments([
|
||||
circle_segment(value: value, color: .controlAccentColor)
|
||||
circle_segment(value: value.percentage, color: self.valueColor)
|
||||
])
|
||||
self.initialized = true
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
internal func activityCallback(_ value: drive) {
|
||||
DispatchQueue.main.async(execute: {
|
||||
self.chart?.addValue(upload: Double(value.activity.write), download: Double(value.activity.read))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,7 +174,7 @@ internal class Popup: PopupWrapper {
|
||||
|
||||
let chart = NetworkChartView(
|
||||
frame: NSRect(x: 0, y: 1, width: container.frame.width, height: container.frame.height - 2),
|
||||
num: 120, outColor: self.uploadColor, inColor: self.downloadColor
|
||||
num: 120, outColor: self.uploadColor, inColor: self.downloadColor, toolTip: true
|
||||
)
|
||||
chart.setReverseOrder(self.reverseOrderState)
|
||||
chart.base = self.base
|
||||
|
||||
Reference in New Issue
Block a user