From 6e1f0ff85accf49e7dc0aa1a1f1a732bde3b8231 Mon Sep 17 00:00:00 2001 From: Serhiy Mytrovtsiy Date: Wed, 3 Jul 2019 20:41:05 +0200 Subject: [PATCH] v1.2.2 --- README.md | 8 +++ Stats/AppDelegate.swift | 25 ++++++++- Stats/MenuBar.swift | 9 +++ Stats/Modules/CPU/CPU.swift | 9 +++ Stats/Modules/Disk/Disk.swift | 58 ++----------------- Stats/Modules/Memory/Memory.swift | 11 ++++ Stats/Modules/Network/Network.swift | 2 + Stats/Modules/Network/NetworkReader.swift | 18 +++--- Stats/Supporting Files/Info.plist | 2 +- Stats/Widgets/Chart.swift | 68 ++++++++++++++++++++++- Stats/libs/Extensions.swift | 13 ----- Stats/libs/Module.swift | 9 ++- 12 files changed, 152 insertions(+), 80 deletions(-) diff --git a/README.md b/README.md index 37bd4df5..2440a144 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,14 @@ You can download latest version [here](https://github.com/exelban/stats/releases ## What's new +### v1.2.2 + - added name of the indicators in the Chart/Chart with value ([#6](https://github.com/exelban/stats/issues/6)) + - added check for new version on start + - removed charts and charts with value to Disk module + - now module submenu is disabled if module is disabled + - fixed bug when network module stop working after turn on/of + - fixed few bugs + ### v1.2.1 - added charts and charts with value to Disk module - fixed bug when Chart with value does not shows diff --git a/Stats/AppDelegate.swift b/Stats/AppDelegate.swift index 85c61af1..e74afeab 100755 --- a/Stats/AppDelegate.swift +++ b/Stats/AppDelegate.swift @@ -15,6 +15,9 @@ extension Notification.Name { let modules: Observable<[Module]> = Observable([CPU(), Memory(), Disk(), Battery(), Network()]) let colors: Observable = Observable(true) +let labelForChart: Observable = Observable(false) + +let updater = macAppUpdater(user: "exelban", repo: "stats") @NSApplicationMain class AppDelegate: NSObject, NSApplicationDelegate { @@ -27,7 +30,28 @@ class AppDelegate: NSObject, NSApplicationDelegate { return } + updater.check() { result, error in + if error != nil && error as! String == "No internet connection" { + return + } + + guard error == nil, let version: version = result else { + print("Error: \(error ?? "check error")") + return + } + + if version.newest { + DispatchQueue.main.async(execute: { + let updatesVC: NSWindowController? = NSStoryboard(name: "Updates", bundle: nil).instantiateController(withIdentifier: "UpdatesVC") as? NSWindowController + updatesVC?.window?.center() + updatesVC?.window?.level = .floating + updatesVC!.showWindow(self) + }) + } + } + colors << (defaults.object(forKey: "colors") != nil ? defaults.bool(forKey: "colors") : false) + labelForChart << (defaults.object(forKey: "labelForChart") != nil ? defaults.bool(forKey: "labelForChart") : false) _ = MenuBar(menuBarItem, menuBarButton: menuBarButton) let launcherAppId = "eu.exelban.StatsLauncher" @@ -92,7 +116,6 @@ class UpdatesVC: NSViewController { @IBOutlet weak var downloadButton: NSButton! @IBOutlet weak var spinner: NSProgressIndicator! - let updater = macAppUpdater(user: "exelban", repo: "stats") var url: String? override func viewDidLoad() { diff --git a/Stats/MenuBar.swift b/Stats/MenuBar.swift index ad72edff..27abbc0f 100644 --- a/Stats/MenuBar.swift +++ b/Stats/MenuBar.swift @@ -65,6 +65,11 @@ class MenuBar { colorStatus.target = self preferencesMenu.addItem(colorStatus) + let chartLabels = NSMenuItem(title: "Label in chart", action: #selector(toggleMenu), keyEquivalent: "") + chartLabels.state = defaults.bool(forKey: "labelForChart") || defaults.object(forKey: "labelForChart") == nil ? NSControl.StateValue.on : NSControl.StateValue.off + chartLabels.target = self + preferencesMenu.addItem(chartLabels) + let runAtLogin = NSMenuItem(title: "Run at login", action: #selector(toggleMenu), keyEquivalent: "") runAtLogin.state = defaults.bool(forKey: "runAtLogin") || defaults.object(forKey: "runAtLogin") == nil ? NSControl.StateValue.on : NSControl.StateValue.off runAtLogin.target = self @@ -115,6 +120,10 @@ class MenuBar { self.defaults.set(status, forKey: "colors") colors << status return + case "Label in chart": + self.defaults.set(status, forKey: "labelForChart") + labelForChart << status + return default: break } } diff --git a/Stats/Modules/CPU/CPU.swift b/Stats/Modules/CPU/CPU.swift index 24a996c7..211fe05d 100644 --- a/Stats/Modules/CPU/CPU.swift +++ b/Stats/Modules/CPU/CPU.swift @@ -27,6 +27,15 @@ class CPU: Module { self.widgetType = defaults.object(forKey: "\(name)_widget") != nil ? defaults.float(forKey: "\(name)_widget") : Widgets.Mini initMenu() initWidget() + + labelForChart.subscribe(observer: self) { (value, _) in + guard let chartView: Chart = self.view as? Chart else { + return + } + self.active << false + chartView.toggleLabel(value: value) + self.active << true + } } func initMenu() { diff --git a/Stats/Modules/Disk/Disk.swift b/Stats/Modules/Disk/Disk.swift index 986b9906..aba607c6 100644 --- a/Stats/Modules/Disk/Disk.swift +++ b/Stats/Modules/Disk/Disk.swift @@ -29,37 +29,21 @@ class Disk: Module { self.widgetType = defaults.object(forKey: "\(name)_widget") != nil ? defaults.float(forKey: "\(name)_widget") : Widgets.Mini self.initMenu() - initWidget() + + let widget = Mini(frame: NSMakeRect(0, 0, MODULE_WIDTH, MODULE_HEIGHT)) + widget.label = self.shortName + self.view = widget } func initMenu() { menu = NSMenuItem(title: name, action: #selector(toggle), keyEquivalent: "") - submenu = NSMenu() - if defaults.object(forKey: name) != nil { menu.state = defaults.bool(forKey: name) ? NSControl.StateValue.on : NSControl.StateValue.off } else { menu.state = NSControl.StateValue.on } menu.target = self - - let mini = NSMenuItem(title: "Mini", action: #selector(toggleWidget), keyEquivalent: "") - mini.state = self.widgetType == Widgets.Mini ? NSControl.StateValue.on : NSControl.StateValue.off - mini.target = self - - let chart = NSMenuItem(title: "Chart", action: #selector(toggleWidget), keyEquivalent: "") - chart.state = self.widgetType == Widgets.Chart ? NSControl.StateValue.on : NSControl.StateValue.off - chart.target = self - - let chartWithValue = NSMenuItem(title: "Chart with value", action: #selector(toggleWidget), keyEquivalent: "") - chartWithValue.state = self.widgetType == Widgets.ChartWithValue ? NSControl.StateValue.on : NSControl.StateValue.off - chartWithValue.target = self - - submenu.addItem(mini) - submenu.addItem(chart) - submenu.addItem(chartWithValue) - - menu.submenu = submenu + menu.isEnabled = true } @objc func toggle(_ sender: NSMenuItem) { @@ -75,36 +59,4 @@ class Disk: Module { self.start() } } - - @objc func toggleWidget(_ sender: NSMenuItem) { - var widgetCode: Float = 0.0 - - switch sender.title { - case "Mini": - widgetCode = Widgets.Mini - case "Chart": - widgetCode = Widgets.Chart - case "Chart with value": - widgetCode = Widgets.ChartWithValue - default: - break - } - - if self.widgetType == widgetCode { - return - } - - for item in self.submenu.items { - if item.title == "Mini" || item.title == "Chart" || item.title == "Chart with value" { - item.state = NSControl.StateValue.off - } - } - - sender.state = sender.state == NSControl.StateValue.on ? NSControl.StateValue.off : NSControl.StateValue.on - self.defaults.set(widgetCode, forKey: "\(name)_widget") - self.widgetType = widgetCode - self.active << false - initWidget() - self.active << true - } } diff --git a/Stats/Modules/Memory/Memory.swift b/Stats/Modules/Memory/Memory.swift index 28e11d3a..dd4fb1af 100644 --- a/Stats/Modules/Memory/Memory.swift +++ b/Stats/Modules/Memory/Memory.swift @@ -29,6 +29,15 @@ class Memory: Module { self.widgetType = defaults.object(forKey: "\(name)_widget") != nil ? defaults.float(forKey: "\(name)_widget") : Widgets.Mini initMenu() initWidget() + + labelForChart.subscribe(observer: self) { (value, _) in + guard let chartView: Chart = self.view as? Chart else { + return + } + self.active << false + chartView.toggleLabel(value: value) + self.active << true + } } func initMenu() { @@ -69,8 +78,10 @@ class Memory: Module { self.active << state if !state { + menu.submenu = nil self.stop() } else { + menu.submenu = submenu self.start() } } diff --git a/Stats/Modules/Network/Network.swift b/Stats/Modules/Network/Network.swift index 7670ed72..9924c19e 100644 --- a/Stats/Modules/Network/Network.swift +++ b/Stats/Modules/Network/Network.swift @@ -87,8 +87,10 @@ class Network: Module { self.active << state if !state { + menu.submenu = nil self.stop() } else { + menu.submenu = submenu self.start() } } diff --git a/Stats/Modules/Network/NetworkReader.swift b/Stats/Modules/Network/NetworkReader.swift index 1e10b42b..f40cd05d 100644 --- a/Stats/Modules/Network/NetworkReader.swift +++ b/Stats/Modules/Network/NetworkReader.swift @@ -33,33 +33,37 @@ class NetworkReader: Reader { defer { self.pipe.fileHandleForReading.waitForDataInBackgroundAndNotify() } - + let output = self.pipe.fileHandleForReading.availableData if output.isEmpty { return } - + let outputString = String(data: output, encoding: String.Encoding.utf8) ?? "" let arr = outputString.condenseWhitespace().split(separator: " ") - + if !arr.isEmpty && Int64(arr[0]) != nil { guard let download = Int64(arr[2]), let upload = Int64(arr[5]) else { return } - + guard let value: Double = Double("\(download).\(upload)") else { return } - + self.usage << value } } - netProcess.launch() + do { + try netProcess.run() + } catch let error { + print(error) + } } func stop() { - netProcess.interrupt() + NotificationCenter.default.removeObserver(self, name: NSNotification.Name.NSFileHandleDataAvailable, object: nil) } func read() {} diff --git a/Stats/Supporting Files/Info.plist b/Stats/Supporting Files/Info.plist index 49ba35eb..03d9fd58 100755 --- a/Stats/Supporting Files/Info.plist +++ b/Stats/Supporting Files/Info.plist @@ -17,7 +17,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.2.1 + 1.2.2 CFBundleVersion 1 LSApplicationCategoryType diff --git a/Stats/Widgets/Chart.swift b/Stats/Widgets/Chart.swift index 96e5e441..9857c784 100644 --- a/Stats/Widgets/Chart.swift +++ b/Stats/Widgets/Chart.swift @@ -9,6 +9,10 @@ import Cocoa class Chart: NSView, Widget { + var labelPadding: CGFloat = 10.0 + var labelEnabled: Bool = false + var label: String = "" + var height: CGFloat = 0.0 var points: [Double] { didSet { @@ -21,6 +25,11 @@ class Chart: NSView, Widget { super.init(frame: frame) self.wantsLayer = true self.addSubview(NSView()) + self.labelEnabled = labelForChart.value + + if self.labelEnabled { + self.frame = CGRect(x: self.frame.origin.x, y: self.frame.origin.y, width: self.frame.size.width + labelPadding, height: self.frame.size.height) + } } required init?(coder decoder: NSCoder) { @@ -34,12 +43,19 @@ class Chart: NSView, Widget { let gradientColor: NSColor = NSColor(red: (26/255.0), green: (126/255.0), blue: (252/255.0), alpha: 0.5) let context = NSGraphicsContext.current!.cgContext - let xOffset: CGFloat = 4.0 + var xOffset: CGFloat = 4.0 + if labelEnabled { + xOffset = xOffset + labelPadding + } let yOffset: CGFloat = 3.0 if height == 0 { height = self.frame.size.height - CGFloat((yOffset * 2)) } - let xRatio = Double(self.frame.size.width - (xOffset * 2)) / (Double(self.points.count) - 1) + + var xRatio = Double(self.frame.size.width - (xOffset * 2)) / (Double(self.points.count) - 1) + if labelEnabled { + xRatio = Double(self.frame.size.width - (xOffset * 2) + labelPadding) / (Double(self.points.count) - 1) + } let columnXPoint = { (point: Int) -> CGFloat in return CGFloat((Double(point) * xRatio)) + xOffset @@ -76,6 +92,30 @@ class Chart: NSView, Widget { graphPath.lineWidth = 0.5 graphPath.stroke() + + if !self.labelEnabled { + return + } + + let style = NSMutableParagraphStyle() + style.alignment = .center + let stringAttributes = [ + NSAttributedString.Key.font: NSFont.systemFont(ofSize: 7.2, weight: .bold), + NSAttributedString.Key.foregroundColor: NSColor.labelColor, + NSAttributedString.Key.paragraphStyle: style + ] + + let letterHeight = (self.frame.size.height - (MODULE_MARGIN*2)) / 3 + let letterWidth: CGFloat = 10.0 + + var yMargin = MODULE_MARGIN + for char in self.label.reversed() { + let rect = CGRect(x: MODULE_MARGIN, y: yMargin, width: letterWidth, height: letterHeight) + let str = NSAttributedString.init(string: "\(char)", attributes: stringAttributes) + str.draw(with: rect) + + yMargin += letterHeight + } } func redraw() { @@ -97,6 +137,15 @@ class Chart: NSView, Widget { } } } + + func toggleLabel(value: Bool) { + labelEnabled = value + if value { + self.frame = CGRect(x: self.frame.origin.x, y: self.frame.origin.y, width: self.frame.size.width + labelPadding, height: self.frame.size.height) + } else { + self.frame = CGRect(x: self.frame.origin.x, y: self.frame.origin.y, width: self.frame.size.width - labelPadding, height: self.frame.size.height) + } + } } class ChartWithValue: Chart { @@ -104,10 +153,12 @@ class ChartWithValue: Chart { override init(frame: NSRect) { super.init(frame: frame) - self.wantsLayer = true valueLabel = NSTextField(frame: NSMakeRect(2, MODULE_HEIGHT - 11, self.frame.size.width, 10)) + if labelEnabled { + valueLabel = NSTextField(frame: NSMakeRect(labelPadding + 2, MODULE_HEIGHT - 11, self.frame.size.width, 10)) + } valueLabel.textColor = NSColor.red valueLabel.isEditable = false valueLabel.isSelectable = false @@ -146,4 +197,15 @@ class ChartWithValue: Chart { } } } + + override func toggleLabel(value: Bool) { + labelEnabled = value + if value { + valueLabel.frame = NSMakeRect(labelPadding + 2, MODULE_HEIGHT - 11, self.frame.size.width, 10) + self.frame = CGRect(x: self.frame.origin.x, y: self.frame.origin.y, width: self.frame.size.width + labelPadding, height: self.frame.size.height) + } else { + valueLabel.frame = NSMakeRect(2, MODULE_HEIGHT - 11, self.frame.size.width, 10) + self.frame = CGRect(x: self.frame.origin.x, y: self.frame.origin.y, width: self.frame.size.width - labelPadding, height: self.frame.size.height) + } + } } diff --git a/Stats/libs/Extensions.swift b/Stats/libs/Extensions.swift index e6cc8819..16eb29c8 100755 --- a/Stats/libs/Extensions.swift +++ b/Stats/libs/Extensions.swift @@ -141,16 +141,3 @@ extension NSBezierPath { self.line(to: arrowLine2) } } - -//extension NSView { -// var backgroundColor: NSColor? { -// get { -// guard let color = layer?.backgroundColor else { return nil } -// return NSColor(cgColor: color) -// } -// set { -// wantsLayer = true -// layer?.backgroundColor = newValue?.cgColor -// } -// } -//} diff --git a/Stats/libs/Module.swift b/Stats/libs/Module.swift index 60d23e2c..3df2257a 100644 --- a/Stats/libs/Module.swift +++ b/Stats/libs/Module.swift @@ -13,6 +13,7 @@ protocol Module: class { var shortName: String { get } var view: NSView { get set } var menu: NSMenuItem { get } + var submenu: NSMenu { get } var active: Observable { get } var available: Observable { get } var reader: Reader { get } @@ -31,10 +32,14 @@ extension Module { self.view = widget break case Widgets.Chart: - self.view = Chart(frame: NSMakeRect(0, 0, MODULE_WIDTH + 7, MODULE_HEIGHT)) + let widget = Chart(frame: NSMakeRect(0, 0, MODULE_WIDTH + 7, MODULE_HEIGHT)) + widget.label = self.shortName + self.view = widget break case Widgets.ChartWithValue: - self.view = ChartWithValue(frame: NSMakeRect(0, 0, MODULE_WIDTH + 7, MODULE_HEIGHT)) + let widget = ChartWithValue(frame: NSMakeRect(0, 0, MODULE_WIDTH + 7, MODULE_HEIGHT)) + widget.label = self.shortName + self.view = widget break case Widgets.Dots: self.view = NetworkDotsView(frame: NSMakeRect(0, 0, MODULE_WIDTH, MODULE_HEIGHT))