diff --git a/Modules/RAM/main.swift b/Modules/RAM/main.swift index 029e4d6f..f4e47b78 100644 --- a/Modules/RAM/main.swift +++ b/Modules/RAM/main.swift @@ -92,7 +92,7 @@ public class RAM: Module { public init() { self.settingsView = Settings("RAM") self.popupView = Popup("RAM") - self.portalView = Portal("RAM") + self.portalView = Portal(.RAM) self.notificationsView = Notifications(.RAM) super.init( @@ -149,7 +149,7 @@ public class RAM: Module { guard raw != nil, let value = raw, self.enabled else { return } self.popupView.loadCallback(value) - self.portalView.loadCallback(value) + self.portalView.callback(value) self.notificationsView.loadCallback(value) let total: Double = value.total == 0 ? 1 : value.total diff --git a/Modules/RAM/notifications.swift b/Modules/RAM/notifications.swift index 30992bde..cad5765f 100644 --- a/Modules/RAM/notifications.swift +++ b/Modules/RAM/notifications.swift @@ -14,6 +14,7 @@ import Kit internal let memoryPressureLevels: [KeyValue_t] = [ KeyValue_t(key: "", value: "Disabled"), + KeyValue_t(key: "normal", value: "Normal", additional: DispatchSource.MemoryPressureEvent.normal), KeyValue_t(key: "warning", value: "Warning", additional: DispatchSource.MemoryPressureEvent.warning), KeyValue_t(key: "critical", value: "Critical", additional: DispatchSource.MemoryPressureEvent.critical) ] @@ -71,7 +72,7 @@ class Notifications: NotificationsWrapper { self.addArrangedSubview(selectSettingsRow( title: localizedString("Memory pressure"), action: #selector(self.changePressure), - items: memoryPressureLevels, + items: memoryPressureLevels.filter({ $0.key != "normal" }), selected: self.pressureLevel )) self.addArrangedSubview(selectSettingsRow( diff --git a/Modules/RAM/popup.swift b/Modules/RAM/popup.swift index 01066d17..5a200f76 100644 --- a/Modules/RAM/popup.swift +++ b/Modules/RAM/popup.swift @@ -52,45 +52,15 @@ internal class Popup: PopupWrapper { } private var appColorState: Color = .secondBlue - private var appColor: NSColor { - var value = NSColor.systemRed - if let color = self.appColorState.additional as? NSColor { - value = color - } - return value - } + private var appColor: NSColor { self.appColorState.additional as? NSColor ?? NSColor.systemRed } private var wiredColorState: Color = .secondOrange - private var wiredColor: NSColor { - var value = NSColor.systemBlue - if let color = self.wiredColorState.additional as? NSColor { - value = color - } - return value - } + private var wiredColor: NSColor { self.wiredColorState.additional as? NSColor ?? NSColor.systemBlue } private var compressedColorState: Color = .pink - private var compressedColor: NSColor { - var value = NSColor.lightGray - if let color = self.compressedColorState.additional as? NSColor { - value = color - } - return value - } + private var compressedColor: NSColor { self.compressedColorState.additional as? NSColor ?? NSColor.lightGray } private var freeColorState: Color = .lightGray - private var freeColor: NSColor { - var value = NSColor.systemBlue - if let color = self.freeColorState.additional as? NSColor { - value = color - } - return value - } + private var freeColor: NSColor { self.freeColorState.additional as? NSColor ?? NSColor.systemBlue } private var chartColorState: Color = .systemAccent - private var chartColor: NSColor { - var value = NSColor.systemBlue - if let color = self.chartColorState.additional as? NSColor { - value = color - } - return value - } + private var chartColor: NSColor { self.chartColorState.additional as? NSColor ?? NSColor.systemBlue } public init(_ title: String) { self.title = title diff --git a/Modules/RAM/portal.swift b/Modules/RAM/portal.swift index 38833a3b..341676b3 100644 --- a/Modules/RAM/portal.swift +++ b/Modules/RAM/portal.swift @@ -12,85 +12,105 @@ import Cocoa import Kit -public class Portal: NSStackView, Portal_p { - public var name: String - +public class Portal: PortalWrapper { private var circle: PieChartView? = nil - private var level: PressureView? = nil + + private var usedField: NSTextField? = nil + private var freeField: NSTextField? = nil + private var swapField: NSTextField? = nil + private var pressureLevelField: NSTextField? = nil private var initialized: Bool = false private var appColorState: Color = .secondBlue - private var appColor: NSColor { - var value = NSColor.systemRed - if let color = self.appColorState.additional as? NSColor { - value = color - } - return value - } + private var appColor: NSColor { self.appColorState.additional as? NSColor ?? NSColor.systemRed } private var wiredColorState: Color = .secondOrange - private var wiredColor: NSColor { - var value = NSColor.systemBlue - if let color = self.wiredColorState.additional as? NSColor { - value = color - } - return value - } + private var wiredColor: NSColor { self.wiredColorState.additional as? NSColor ?? NSColor.systemBlue } private var compressedColorState: Color = .pink - private var compressedColor: NSColor { - var value = NSColor.lightGray - if let color = self.compressedColorState.additional as? NSColor { - value = color - } - return value - } + private var compressedColor: NSColor { self.compressedColorState.additional as? NSColor ?? NSColor.lightGray } private var freeColorState: Color = .lightGray - private var freeColor: NSColor { - var value = NSColor.systemBlue - if let color = self.freeColorState.additional as? NSColor { - value = color - } - return value - } + private var freeColor: NSColor { self.freeColorState.additional as? NSColor ?? NSColor.systemBlue } - init(_ name: String) { - self.name = name + public override func load() { + self.loadColors() - super.init(frame: NSRect.zero) - - 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("Memory 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") + public func loadColors() { + self.appColorState = Color.fromString(Store.shared.string(key: "\(self.name)_appColor", defaultValue: self.appColorState.key)) + self.wiredColorState = Color.fromString(Store.shared.string(key: "\(self.name)_wiredColor", defaultValue: self.wiredColorState.key)) + self.compressedColorState = Color.fromString(Store.shared.string(key: "\(self.name)_compressedColor", defaultValue: self.compressedColorState.key)) + self.freeColorState = Color.fromString(Store.shared.string(key: "\(self.name)_freeColor", defaultValue: self.freeColorState.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("Memory usage") + view.addArrangedSubview(chart) + self.circle = chart + + return view } - public func loadCallback(_ value: RAM_Usage) { + private func details() -> NSView { + let view = NSStackView() + view.orientation = .vertical + view.distribution = .fillEqually + view.spacing = Constants.Popup.spacing*2 + + self.usedField = portalRow(view, title: "\(localizedString("Used")):") + self.freeField = portalRow(view, title: "\(localizedString("Free")):") + self.swapField = portalRow(view, title: "\(localizedString("Swap")):") + self.pressureLevelField = portalRow(view, title: "\(localizedString("Memory pressure")):") + + return view + } + + internal func callback(_ value: RAM_Usage) { DispatchQueue.main.async(execute: { if (self.window?.isVisible ?? false) || !self.initialized { + self.usedField?.stringValue = Units(bytes: Int64(value.used)).getReadableMemory() + self.freeField?.stringValue = Units(bytes: Int64(value.free)).getReadableMemory() + self.swapField?.stringValue = Units(bytes: Int64(value.swap.used)).getReadableMemory() + self.pressureLevelField?.stringValue = "\(value.pressureLevel.rawValue)" + + self.usedField?.toolTip = "\(Int(value.usage.rounded(toPlaces: 2) * 100))%" + self.freeField?.toolTip = "\(Int((1-value.usage).rounded(toPlaces: 2) * 100))%" + if let level = memoryPressureLevels.first(where: { $0.additional as? DispatchSource.MemoryPressureEvent == value.pressureLevel }) { + self.pressureLevelField?.toolTip = localizedString(level.value) + } + self.circle?.setValue(value.usage) self.circle?.setSegments([ circle_segment(value: value.app/value.total, color: self.appColor),