diff --git a/README.md b/README.md index 73a7928e65f..af396c50c84 100644 --- a/README.md +++ b/README.md @@ -34,10 +34,10 @@ You can download latest version [here](https://github.com/exelban/stats/releases ## Todo - [X] Battery percentage - - [ ] Create new logo + - [X] Create new logo ([IconArchive](http://www.iconarchive.com/show/simple-icons-by-kxmylo/utilities-system-monitor-icon.html)) - [ ] Window with preferences - [ ] Save last modules values - - [ ] Colors toggle for each module + - [X] Colors toggle for each module - [ ] temperature module - [X] battery module - [X] move to module system (CPU, RAM, DISK) @@ -49,6 +49,15 @@ You can download latest version [here](https://github.com/exelban/stats/releases ## What's new +### v1.2.3 + - new icon + - small code refactoring + - changed font style name of the indicator in the Chart/Chart with value + - added dock icon visibility to preferences + - moved color and label preference from global to local (now each module can be configurated separately) + - now check for updates on start can be disabled in preferences + - fixed few bugs + ### v1.2.2 - fully automated build and sign app process - fixed update and about visibility window in dark mode diff --git a/Stats.xcodeproj/project.pbxproj b/Stats.xcodeproj/project.pbxproj index 86f820440f6..ed486c80d6d 100755 --- a/Stats.xcodeproj/project.pbxproj +++ b/Stats.xcodeproj/project.pbxproj @@ -15,7 +15,6 @@ 9A426DB822C2B5EE00C064C4 /* macAppUpdater.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A426DB722C2B5EE00C064C4 /* macAppUpdater.swift */; }; 9A426DBE22C2BE0000C064C4 /* Updates.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9A426DBD22C2BE0000C064C4 /* Updates.storyboard */; }; 9A57A18522A1D26D0033E318 /* MenuBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A57A18422A1D26D0033E318 /* MenuBar.swift */; }; - 9A57A19B22A1E1C50033E318 /* Module.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A57A19A22A1E1C50033E318 /* Module.swift */; }; 9A57A19D22A1E3270033E318 /* CPU.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A57A19C22A1E3270033E318 /* CPU.swift */; }; 9A58D1B022C150C800405315 /* Network.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A58D1AF22C150C800405315 /* Network.swift */; }; 9A58D1B222C150D700405315 /* NetworkReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A58D1B122C150D700405315 /* NetworkReader.swift */; }; @@ -25,6 +24,9 @@ 9A6CFC0122A1C9F5001E782D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 9A6CFC0022A1C9F5001E782D /* Assets.xcassets */; }; 9A74D59422B4315C004FE1FA /* Chart.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A74D59322B4315C004FE1FA /* Chart.swift */; }; 9A74D59722B44498004FE1FA /* Mini.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A74D59622B44498004FE1FA /* Mini.swift */; }; + 9A79B36A22D3BEE600BF1C3A /* Widget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A79B36922D3BEE600BF1C3A /* Widget.swift */; }; + 9A79B36C22D3BEF000BF1C3A /* Module.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A79B36B22D3BEF000BF1C3A /* Module.swift */; }; + 9A79B36E22D3BEF900BF1C3A /* Reader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A79B36D22D3BEF900BF1C3A /* Reader.swift */; }; 9A7B8F5E22A2A57600DEB352 /* CPUReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A7B8F5D22A2A57600DEB352 /* CPUReader.swift */; }; 9A7B8F6922A2C3A100DEB352 /* Memory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A7B8F6822A2C3A100DEB352 /* Memory.swift */; }; 9A7B8F6B22A2C3A700DEB352 /* Disk.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A7B8F6A22A2C3A700DEB352 /* Disk.swift */; }; @@ -63,7 +65,6 @@ 9A426DB722C2B5EE00C064C4 /* macAppUpdater.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = macAppUpdater.swift; sourceTree = ""; }; 9A426DBD22C2BE0000C064C4 /* Updates.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Updates.storyboard; sourceTree = ""; }; 9A57A18422A1D26D0033E318 /* MenuBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuBar.swift; sourceTree = ""; }; - 9A57A19A22A1E1C50033E318 /* Module.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Module.swift; sourceTree = ""; }; 9A57A19C22A1E3270033E318 /* CPU.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CPU.swift; sourceTree = ""; }; 9A58D1AF22C150C800405315 /* Network.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Network.swift; sourceTree = ""; }; 9A58D1B122C150D700405315 /* NetworkReader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkReader.swift; sourceTree = ""; }; @@ -73,6 +74,9 @@ 9A6CFC0022A1C9F5001E782D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 9A74D59322B4315C004FE1FA /* Chart.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Chart.swift; sourceTree = ""; }; 9A74D59622B44498004FE1FA /* Mini.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Mini.swift; sourceTree = ""; }; + 9A79B36922D3BEE600BF1C3A /* Widget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Widget.swift; sourceTree = ""; }; + 9A79B36B22D3BEF000BF1C3A /* Module.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Module.swift; sourceTree = ""; }; + 9A79B36D22D3BEF900BF1C3A /* Reader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Reader.swift; sourceTree = ""; }; 9A7B8F5D22A2A57600DEB352 /* CPUReader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CPUReader.swift; sourceTree = ""; }; 9A7B8F6822A2C3A100DEB352 /* Memory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Memory.swift; sourceTree = ""; }; 9A7B8F6A22A2C3A700DEB352 /* Disk.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Disk.swift; sourceTree = ""; }; @@ -178,6 +182,8 @@ 9A7B8F6322A2C17500DEB352 /* Disk */, 9A09C89C22B3A7BB0018426F /* Battery */, 9A58D1AE22C150B800405315 /* Network */, + 9A79B36B22D3BEF000BF1C3A /* Module.swift */, + 9A79B36D22D3BEF900BF1C3A /* Reader.swift */, ); path = Modules; sourceTree = ""; @@ -186,7 +192,6 @@ isa = PBXGroup; children = ( 9A5B1CBE229E78F0008B9D3C /* Observable.swift */, - 9A57A19A22A1E1C50033E318 /* Module.swift */, 9A5B1CC4229E7B40008B9D3C /* Extensions.swift */, 9A426DB722C2B5EE00C064C4 /* macAppUpdater.swift */, ); @@ -200,6 +205,7 @@ 9A74D59322B4315C004FE1FA /* Chart.swift */, 9A74D59622B44498004FE1FA /* Mini.swift */, 9A58D1B322C179B200405315 /* NetworkView.swift */, + 9A79B36922D3BEE600BF1C3A /* Widget.swift */, ); path = Widgets; sourceTree = ""; @@ -362,6 +368,7 @@ files = ( 9A09C8A222B3D94D0018426F /* BatteryView.swift in Sources */, 9A426DB822C2B5EE00C064C4 /* macAppUpdater.swift in Sources */, + 9A79B36E22D3BEF900BF1C3A /* Reader.swift in Sources */, 9A7B8F6F22A2C57000DEB352 /* DiskReader.swift in Sources */, 9A7B8F6922A2C3A100DEB352 /* Memory.swift in Sources */, 9A7B8F5E22A2A57600DEB352 /* CPUReader.swift in Sources */, @@ -369,17 +376,18 @@ 9A58D1B422C179B200405315 /* NetworkView.swift in Sources */, 9A09C89E22B3A7C90018426F /* Battery.swift in Sources */, 9A7B8F6D22A2C3D600DEB352 /* MemoryReader.swift in Sources */, + 9A79B36C22D3BEF000BF1C3A /* Module.swift in Sources */, 9A57A18522A1D26D0033E318 /* MenuBar.swift in Sources */, 9A57A19D22A1E3270033E318 /* CPU.swift in Sources */, 9A58D1B222C150D700405315 /* NetworkReader.swift in Sources */, 9A09C8A022B3A7E20018426F /* BatteryReader.swift in Sources */, 9A58D1B022C150C800405315 /* Network.swift in Sources */, - 9A57A19B22A1E1C50033E318 /* Module.swift in Sources */, 9A5B1CBF229E78F0008B9D3C /* Observable.swift in Sources */, 9A7B8F6B22A2C3A700DEB352 /* Disk.swift in Sources */, 9A1410F9229E721100D29793 /* AppDelegate.swift in Sources */, 9A74D59722B44498004FE1FA /* Mini.swift in Sources */, 9A5B1CC5229E7B40008B9D3C /* Extensions.swift in Sources */, + 9A79B36A22D3BEE600BF1C3A /* Widget.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Stats/AppDelegate.swift b/Stats/AppDelegate.swift index 29c748976b9..de397f70b99 100755 --- a/Stats/AppDelegate.swift +++ b/Stats/AppDelegate.swift @@ -14,9 +14,6 @@ extension Notification.Name { } let modules: Observable<[Module]> = Observable([CPU(), Memory(), Disk(), Battery(), Network()]) -let colors: Observable = Observable(true) -let labelForChart: Observable = Observable(true) - let updater = macAppUpdater(user: "exelban", repo: "stats") @NSApplicationMain @@ -30,28 +27,6 @@ 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" @@ -65,9 +40,31 @@ class AppDelegate: NSObject, NSApplicationDelegate { self.defaults.set(true, forKey: "runAtLogin") } - if defaults.object(forKey: "labelForChart") == nil { - self.defaults.set(true, forKey: "labelForChart") - labelForChart << true + if defaults.object(forKey: "dockIcon") != nil { + let dockIconStatus = defaults.bool(forKey: "dockIcon") ? NSApplication.ActivationPolicy.regular : NSApplication.ActivationPolicy.accessory + NSApp.setActivationPolicy(dockIconStatus) + } + + if defaults.object(forKey: "checkUpdatesOnLogin") == nil || defaults.bool(forKey: "checkUpdatesOnLogin") { + 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) + }) + } + } } if isRunning { diff --git a/Stats/MenuBar.swift b/Stats/MenuBar.swift index 27abbc0fce3..cc29d27fbbb 100644 --- a/Stats/MenuBar.swift +++ b/Stats/MenuBar.swift @@ -60,21 +60,21 @@ class MenuBar { let preferences = NSMenuItem(title: "Preferences", action: nil, keyEquivalent: "") let preferencesMenu = NSMenu() - let colorStatus = NSMenuItem(title: "Colors", action: #selector(toggleMenu), keyEquivalent: "") - colorStatus.state = defaults.bool(forKey: "colors") ? NSControl.StateValue.on : NSControl.StateValue.off - colorStatus.target = self - preferencesMenu.addItem(colorStatus) + let checkForUpdates = NSMenuItem(title: "Check for updates on start", action: #selector(toggleMenu), keyEquivalent: "") + checkForUpdates.state = defaults.bool(forKey: "checkUpdatesOnLogin") || defaults.object(forKey: "checkUpdatesOnLogin") == nil ? NSControl.StateValue.on : NSControl.StateValue.off + checkForUpdates.target = self + preferencesMenu.addItem(checkForUpdates) - 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: "") + let runAtLogin = NSMenuItem(title: "Start 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 preferencesMenu.addItem(runAtLogin) + let dockIcon = NSMenuItem(title: "Show icon in dock", action: #selector(toggleMenu), keyEquivalent: "") + dockIcon.state = defaults.bool(forKey: "dockIcon") ? NSControl.StateValue.on : NSControl.StateValue.off + dockIcon.target = self + preferencesMenu.addItem(dockIcon) + preferences.submenu = preferencesMenu menu.addItem(preferences) @@ -116,13 +116,12 @@ class MenuBar { case "Run at login": SMLoginItemSetEnabled(launcherId as CFString, !status) self.defaults.set(status, forKey: "runAtLogin") - case "Colors": - self.defaults.set(status, forKey: "colors") - colors << status - return - case "Label in chart": - self.defaults.set(status, forKey: "labelForChart") - labelForChart << status + case "Check for updates on start": + self.defaults.set(status, forKey: "checkUpdatesOnLogin") + case "Show icon in dock": + self.defaults.set(status, forKey: "dockIcon") + let iconStatus = status ? NSApplication.ActivationPolicy.regular : NSApplication.ActivationPolicy.accessory + NSApp.setActivationPolicy(iconStatus) return default: break } diff --git a/Stats/Modules/Battery/Battery.swift b/Stats/Modules/Battery/Battery.swift index 6d78bb4ddbb..7ead5e5f181 100644 --- a/Stats/Modules/Battery/Battery.swift +++ b/Stats/Modules/Battery/Battery.swift @@ -16,6 +16,7 @@ class Battery: Module { var submenu: NSMenu = NSMenu() var active: Observable var available: Observable + var color: Observable var reader: Reader = BatteryReader() let defaults = UserDefaults.standard @@ -26,20 +27,21 @@ class Battery: Module { self.available = Observable(self.reader.available) self.active = Observable(defaults.object(forKey: name) != nil ? defaults.bool(forKey: name) : true) self.percentageView = Observable(defaults.object(forKey: "\(self.name)_percentage") != nil ? defaults.bool(forKey: "\(self.name)_percentage") : false) + self.color = Observable(defaults.object(forKey: "\(name)_color") != nil ? defaults.bool(forKey: "\(name)_color") : false) self.view = BatteryView(frame: NSMakeRect(0, 0, MODULE_WIDTH, MODULE_HEIGHT)) initMenu() initWidget() } func start() { - if !self.reader.usage.value.isNaN { - let value = self.reader.usage!.value + if !self.reader.value.value.isNaN { + let value = self.reader.value!.value (self.view as! BatteryView).setCharging(value: value > 0) (self.view as! Widget).value(value: abs(value)) } self.reader.start() - self.reader.usage.subscribe(observer: self) { (value, _) in + self.reader.value.subscribe(observer: self) { (value, _) in if !value.isNaN { (self.view as! BatteryView).setCharging(value: value > 0) (self.view as! Widget).value(value: abs(value)) @@ -69,7 +71,13 @@ class Battery: Module { percentage.state = defaults.bool(forKey: "\(self.name)_percentage") ? NSControl.StateValue.on : NSControl.StateValue.off percentage.target = self + let color = NSMenuItem(title: "Color", action: #selector(toggleColor), keyEquivalent: "") + color.state = defaults.bool(forKey: "\(name)_color") ? NSControl.StateValue.on : NSControl.StateValue.off + color.target = self + submenu.addItem(percentage) + submenu.addItem(color) + menu.submenu = submenu } @@ -97,5 +105,11 @@ class Battery: Module { self.percentageView << state self.initWidget() } + + @objc func toggleColor(_ sender: NSMenuItem) { + sender.state = sender.state == NSControl.StateValue.on ? NSControl.StateValue.off : NSControl.StateValue.on + self.defaults.set(sender.state == NSControl.StateValue.on, forKey: "\(name)_color") + self.color << (sender.state == NSControl.StateValue.on) + } } diff --git a/Stats/Modules/Battery/BatteryReader.swift b/Stats/Modules/Battery/BatteryReader.swift index 092d166b535..8a2c89ca292 100644 --- a/Stats/Modules/Battery/BatteryReader.swift +++ b/Stats/Modules/Battery/BatteryReader.swift @@ -10,12 +10,12 @@ import Foundation import IOKit.ps class BatteryReader: Reader { - var usage: Observable! + var value: Observable! var available: Bool = false var updateTimer: Timer! init() { - self.usage = Observable(0) + self.value = Observable(0) read() } @@ -49,7 +49,7 @@ class BatteryReader: Reader { cap = 0 - cap } - self.usage << Double(cap) + self.value << Double(cap) } } } diff --git a/Stats/Modules/CPU/CPU.swift b/Stats/Modules/CPU/CPU.swift index 211fe05d6cf..9e307a62e4e 100644 --- a/Stats/Modules/CPU/CPU.swift +++ b/Stats/Modules/CPU/CPU.swift @@ -16,6 +16,7 @@ class CPU: Module { var submenu: NSMenu = NSMenu() var active: Observable var available: Observable + var color: Observable var reader: Reader = CPUReader() let defaults = UserDefaults.standard @@ -25,17 +26,17 @@ class CPU: Module { self.available = Observable(true) self.active = Observable(defaults.object(forKey: name) != nil ? defaults.bool(forKey: name) : true) self.widgetType = defaults.object(forKey: "\(name)_widget") != nil ? defaults.float(forKey: "\(name)_widget") : Widgets.Mini + self.color = Observable(defaults.object(forKey: "\(name)_color") != nil ? defaults.bool(forKey: "\(name)_color") : false) 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 + let labelStatus = defaults.bool(forKey: "\(name)_label") || defaults.object(forKey: "\(name)_label") == nil ? true : false + guard let chartView: Chart = self.view as? Chart else { + return } + self.active << false + chartView.toggleLabel(value: labelStatus) + self.active << true } func initMenu() { @@ -61,10 +62,23 @@ class CPU: Module { chartWithValue.state = self.widgetType == Widgets.ChartWithValue ? NSControl.StateValue.on : NSControl.StateValue.off chartWithValue.target = self + let color = NSMenuItem(title: "Color", action: #selector(toggleColor), keyEquivalent: "") + color.state = defaults.bool(forKey: "\(name)_color") ? NSControl.StateValue.on : NSControl.StateValue.off + color.target = self + + let label = NSMenuItem(title: "Label", action: #selector(toggleLabel), keyEquivalent: "") + label.state = defaults.bool(forKey: "\(name)_label") || defaults.object(forKey: "\(name)_label") == nil ? NSControl.StateValue.on : NSControl.StateValue.off + label.target = self + submenu.addItem(mini) submenu.addItem(chart) submenu.addItem(chartWithValue) + submenu.addItem(NSMenuItem.separator()) + + submenu.addItem(label) + submenu.addItem(color) + menu.submenu = submenu } @@ -111,7 +125,25 @@ class CPU: Module { self.defaults.set(widgetCode, forKey: "\(name)_widget") self.widgetType = widgetCode self.active << false - initWidget() + initWidget(color: defaults.object(forKey: "\(name)_color") != nil ? defaults.bool(forKey: "\(name)_color") : false) + self.active << true + } + + @objc func toggleColor(_ sender: NSMenuItem) { + sender.state = sender.state == NSControl.StateValue.on ? NSControl.StateValue.off : NSControl.StateValue.on + self.defaults.set(sender.state == NSControl.StateValue.on, forKey: "\(name)_color") + self.color << (sender.state == NSControl.StateValue.on) + } + + @objc func toggleLabel(_ sender: NSMenuItem) { + sender.state = sender.state == NSControl.StateValue.on ? NSControl.StateValue.off : NSControl.StateValue.on + self.defaults.set(sender.state == NSControl.StateValue.on, forKey: "\(name)_label") + + guard let chartView: Chart = self.view as? Chart else { + return + } + self.active << false + chartView.toggleLabel(value: sender.state == NSControl.StateValue.on) self.active << true } } diff --git a/Stats/Modules/CPU/CPUReader.swift b/Stats/Modules/CPU/CPUReader.swift index 96f155e3165..1cee0c2e05e 100644 --- a/Stats/Modules/CPU/CPUReader.swift +++ b/Stats/Modules/CPU/CPUReader.swift @@ -9,7 +9,7 @@ import Foundation class CPUReader: Reader { - var usage: Observable! + var value: Observable! var available: Bool = true var cpuInfo: processor_info_array_t! var prevCpuInfo: processor_info_array_t? @@ -21,7 +21,7 @@ class CPUReader: Reader { init() { let mibKeys: [Int32] = [ CTL_HW, HW_NCPU ] - self.usage = Observable(0) + self.value = Observable(0) mibKeys.withUnsafeBufferPointer() { mib in var sizeOfNumCPUs: size_t = MemoryLayout.size let status = sysctl(processor_info_array_t(mutating: mib.baseAddress), 2, &numCPUs, &sizeOfNumCPUs, nil, 0) @@ -77,7 +77,7 @@ class CPUReader: Reader { inUseOnAllCores = inUseOnAllCores + inUse totalOnAllCores = totalOnAllCores + total } - self.usage << (Double(inUseOnAllCores) / Double(totalOnAllCores)) + self.value << (Double(inUseOnAllCores) / Double(totalOnAllCores)) CPUUsageLock.unlock() diff --git a/Stats/Modules/Disk/Disk.swift b/Stats/Modules/Disk/Disk.swift index aba607c6461..a8580c6496e 100644 --- a/Stats/Modules/Disk/Disk.swift +++ b/Stats/Modules/Disk/Disk.swift @@ -19,6 +19,8 @@ class Disk: Module { var active: Observable var available: Observable + var color: Observable + var reader: Reader = DiskReader() @IBOutlet weak var value: NSTextField! @@ -27,23 +29,30 @@ class Disk: Module { self.available = Observable(true) self.active = Observable(defaults.object(forKey: name) != nil ? defaults.bool(forKey: name) : true) self.widgetType = defaults.object(forKey: "\(name)_widget") != nil ? defaults.float(forKey: "\(name)_widget") : Widgets.Mini + self.color = Observable(defaults.object(forKey: "\(name)_color") != nil ? defaults.bool(forKey: "\(name)_color") : false) self.initMenu() - - let widget = Mini(frame: NSMakeRect(0, 0, MODULE_WIDTH, MODULE_HEIGHT)) - widget.label = self.shortName - self.view = widget + self.initWidget() } 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 - menu.isEnabled = true + + let color = NSMenuItem(title: "Color", action: #selector(toggleColor), keyEquivalent: "") + color.state = defaults.bool(forKey: "\(name)_color") ? NSControl.StateValue.on : NSControl.StateValue.off + color.target = self + + submenu.addItem(color) + + menu.submenu = submenu } @objc func toggle(_ sender: NSMenuItem) { @@ -59,4 +68,10 @@ class Disk: Module { self.start() } } + + @objc func toggleColor(_ sender: NSMenuItem) { + sender.state = sender.state == NSControl.StateValue.on ? NSControl.StateValue.off : NSControl.StateValue.on + self.defaults.set(sender.state == NSControl.StateValue.on, forKey: "\(name)_color") + self.color << (sender.state == NSControl.StateValue.on) + } } diff --git a/Stats/Modules/Disk/DiskReader.swift b/Stats/Modules/Disk/DiskReader.swift index 2d69be2f15d..582c1a16e48 100644 --- a/Stats/Modules/Disk/DiskReader.swift +++ b/Stats/Modules/Disk/DiskReader.swift @@ -9,12 +9,12 @@ import Foundation class DiskReader: Reader { - var usage: Observable! + var value: Observable! var available: Bool = true var updateTimer: Timer! init() { - self.usage = Observable(0) + self.value = Observable(0) read() } @@ -38,7 +38,7 @@ class DiskReader: Reader { let free = freeDiskSpaceInBytes() let usedSpace = total - free - self.usage << (Double(usedSpace) / Double(total)) + self.value << (Double(usedSpace) / Double(total)) } func totalDiskSpaceInBytes() -> Int64 { diff --git a/Stats/Modules/Memory/Memory.swift b/Stats/Modules/Memory/Memory.swift index dd4fb1af774..7d883e815ae 100644 --- a/Stats/Modules/Memory/Memory.swift +++ b/Stats/Modules/Memory/Memory.swift @@ -16,6 +16,7 @@ class Memory: Module { var submenu: NSMenu = NSMenu() var active: Observable var available: Observable + var color: Observable var reader: Reader = MemoryReader() var widgetType: WidgetType @@ -27,17 +28,17 @@ class Memory: Module { self.available = Observable(true) self.active = Observable(defaults.object(forKey: name) != nil ? defaults.bool(forKey: name) : true) self.widgetType = defaults.object(forKey: "\(name)_widget") != nil ? defaults.float(forKey: "\(name)_widget") : Widgets.Mini + self.color = Observable(defaults.object(forKey: "\(name)_color") != nil ? defaults.bool(forKey: "\(name)_color") : false) 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 + let labelStatus = defaults.bool(forKey: "\(name)_label") || defaults.object(forKey: "\(name)_label") == nil ? true : false + guard let chartView: Chart = self.view as? Chart else { + return } + self.active << false + chartView.toggleLabel(value: labelStatus) + self.active << true } func initMenu() { @@ -63,10 +64,23 @@ class Memory: Module { chartWithValue.state = self.widgetType == Widgets.ChartWithValue ? NSControl.StateValue.on : NSControl.StateValue.off chartWithValue.target = self + let color = NSMenuItem(title: "Color", action: #selector(toggleColor), keyEquivalent: "") + color.state = defaults.bool(forKey: "\(name)_color") ? NSControl.StateValue.on : NSControl.StateValue.off + color.target = self + + let label = NSMenuItem(title: "Label", action: #selector(toggleLabel), keyEquivalent: "") + label.state = defaults.bool(forKey: "\(name)_label") || defaults.object(forKey: "\(name)_label") == nil ? NSControl.StateValue.on : NSControl.StateValue.off + label.target = self + submenu.addItem(mini) submenu.addItem(chart) submenu.addItem(chartWithValue) + submenu.addItem(NSMenuItem.separator()) + + submenu.addItem(label) + submenu.addItem(color) + menu.submenu = submenu } @@ -117,4 +131,22 @@ class Memory: Module { self.initWidget() self.active << true } + + @objc func toggleColor(_ sender: NSMenuItem) { + sender.state = sender.state == NSControl.StateValue.on ? NSControl.StateValue.off : NSControl.StateValue.on + self.defaults.set(sender.state == NSControl.StateValue.on, forKey: "\(name)_color") + self.color << (sender.state == NSControl.StateValue.on) + } + + @objc func toggleLabel(_ sender: NSMenuItem) { + sender.state = sender.state == NSControl.StateValue.on ? NSControl.StateValue.off : NSControl.StateValue.on + self.defaults.set(sender.state == NSControl.StateValue.on, forKey: "\(name)_label") + + guard let chartView: Chart = self.view as? Chart else { + return + } + self.active << false + chartView.toggleLabel(value: sender.state == NSControl.StateValue.on) + self.active << true + } } diff --git a/Stats/Modules/Memory/MemoryReader.swift b/Stats/Modules/Memory/MemoryReader.swift index fbcffb51a1d..2df61bb534e 100644 --- a/Stats/Modules/Memory/MemoryReader.swift +++ b/Stats/Modules/Memory/MemoryReader.swift @@ -9,13 +9,13 @@ import Foundation class MemoryReader: Reader { - var usage: Observable! + var value: Observable! var available: Bool = true var updateTimer: Timer! var totalSize: Float init() { - self.usage = Observable(0) + self.value = Observable(0) var stats = host_basic_info() var count = UInt32(MemoryLayout.size / MemoryLayout.size) @@ -68,7 +68,7 @@ class MemoryReader: Reader { let compressed = Float(stats.compressor_page_count) * Float(PAGE_SIZE) let free = totalSize - (active + wired + compressed) - self.usage << Double((totalSize - free) / totalSize) + self.value << Double((totalSize - free) / totalSize) } else { print("Error with host_statistics64(): " + (String(cString: mach_error_string(kerr), encoding: String.Encoding.ascii) ?? "unknown error")) diff --git a/Stats/Modules/Module.swift b/Stats/Modules/Module.swift new file mode 100644 index 00000000000..759a9136c01 --- /dev/null +++ b/Stats/Modules/Module.swift @@ -0,0 +1,91 @@ +// +// Module.swift +// Stats +// +// Created by Serhiy Mytrovtsiy on 08.07.2019. +// Copyright © 2019 Serhiy Mytrovtsiy. All rights reserved. +// + +import Cocoa + +protocol Module: class { + var name: String { get } + var shortName: String { get } + + var view: NSView { get set } + var menu: NSMenuItem { get } + var widgetType: WidgetType { get } + + var active: Observable { get } + var available: Observable { get } + var color: Observable { get set } + + var reader: Reader { get } + + func start() + func stop() +} + +extension Module { + func initWidget(color: Bool = false) { + var widget: Widget = Mini(frame: NSMakeRect(0, 0, MODULE_WIDTH, MODULE_HEIGHT)) + + switch self.widgetType { + case Widgets.Mini: + widget = Mini(frame: NSMakeRect(0, 0, MODULE_WIDTH, MODULE_HEIGHT)) + case Widgets.Chart: + widget = Chart(frame: NSMakeRect(0, 0, MODULE_WIDTH + 7, MODULE_HEIGHT)) + case Widgets.ChartWithValue: + widget = ChartWithValue(frame: NSMakeRect(0, 0, MODULE_WIDTH + 7, MODULE_HEIGHT)) + case Widgets.NetworkDots: + widget = NetworkDotsView(frame: NSMakeRect(0, 0, MODULE_WIDTH, MODULE_HEIGHT)) + case Widgets.NetworkArrows: + widget = NetworkArrowsView(frame: NSMakeRect(0, 0, MODULE_WIDTH, MODULE_HEIGHT)) + case Widgets.NetworkText: + widget = NetworkTextView(frame: NSMakeRect(0, 0, MODULE_WIDTH, MODULE_HEIGHT)) + case Widgets.NetworkDotsWithText: + widget = NetworkDotsTextView(frame: NSMakeRect(0, 0, MODULE_WIDTH, MODULE_HEIGHT)) + case Widgets.NetworkArrowsWithText: + widget = NetworkArrowsTextView(frame: NSMakeRect(0, 0, MODULE_WIDTH, MODULE_HEIGHT)) + default: + widget = Mini(frame: NSMakeRect(0, 0, MODULE_WIDTH, MODULE_HEIGHT)) + } + + widget.label = self.shortName + widget.color(state: self.color.value) + self.view = widget as! NSView + } + + func start() { + if !self.reader.value.value.isNaN { + guard let widget = self.view as? Widget else { + return + } + widget.value(value: self.reader.value.value) + } + + self.reader.start() + self.reader.value.subscribe(observer: self) { (value, _) in + if !value.isNaN { + guard let widget = self.view as? Widget else { + return + } + widget.value(value: value) + } + } + + self.color.subscribe(observer: self) { (value, _) in + guard let widget = self.view as? Widget else { + return + } + widget.color(state: value) + widget.redraw() + } + } + + func stop() { + self.reader.stop() + self.reader.value.unsubscribe(observer: self) + self.color.unsubscribe(observer: self) + } +} diff --git a/Stats/Modules/Network/Network.swift b/Stats/Modules/Network/Network.swift index 9924c19e015..3ed2cf3385c 100644 --- a/Stats/Modules/Network/Network.swift +++ b/Stats/Modules/Network/Network.swift @@ -16,6 +16,7 @@ class Network: Module { var submenu: NSMenu = NSMenu() var active: Observable var available: Observable + var color: Observable var reader: Reader = NetworkReader() var widgetType: WidgetType = 2.0 @@ -24,7 +25,8 @@ class Network: Module { init() { self.available = Observable(self.reader.available) self.active = Observable(defaults.object(forKey: name) != nil ? defaults.bool(forKey: name) : true) - self.widgetType = defaults.object(forKey: "\(name)_widget") != nil ? defaults.float(forKey: "\(name)_widget") : Widgets.Dots + self.widgetType = defaults.object(forKey: "\(name)_widget") != nil ? defaults.float(forKey: "\(name)_widget") : Widgets.NetworkDots + self.color = Observable(defaults.object(forKey: "\(name)_color") != nil ? defaults.bool(forKey: "\(name)_color") : false) initMenu() initWidget() } @@ -32,7 +34,7 @@ class Network: Module { func start() { self.reader.start() - self.reader.usage.subscribe(observer: self) { (value, _) in + self.reader.value.subscribe(observer: self) { (value, _) in if !value.isNaN { (self.view as! Widget).value(value: value) } @@ -51,23 +53,23 @@ class Network: Module { menu.target = self let dots = NSMenuItem(title: "Dots", action: #selector(toggleWidget), keyEquivalent: "") - dots.state = self.widgetType == Widgets.Dots ? NSControl.StateValue.on : NSControl.StateValue.off + dots.state = self.widgetType == Widgets.NetworkDots ? NSControl.StateValue.on : NSControl.StateValue.off dots.target = self let arrows = NSMenuItem(title: "Arrows", action: #selector(toggleWidget), keyEquivalent: "") - arrows.state = self.widgetType == Widgets.Arrows ? NSControl.StateValue.on : NSControl.StateValue.off + arrows.state = self.widgetType == Widgets.NetworkArrows ? NSControl.StateValue.on : NSControl.StateValue.off arrows.target = self let text = NSMenuItem(title: "Text", action: #selector(toggleWidget), keyEquivalent: "") - text.state = self.widgetType == Widgets.Text ? NSControl.StateValue.on : NSControl.StateValue.off + text.state = self.widgetType == Widgets.NetworkText ? NSControl.StateValue.on : NSControl.StateValue.off text.target = self let dotsWithText = NSMenuItem(title: "Dots with text", action: #selector(toggleWidget), keyEquivalent: "") - dotsWithText.state = self.widgetType == Widgets.DotsWithText ? NSControl.StateValue.on : NSControl.StateValue.off + dotsWithText.state = self.widgetType == Widgets.NetworkDotsWithText ? NSControl.StateValue.on : NSControl.StateValue.off dotsWithText.target = self let arrowsWithText = NSMenuItem(title: "Arrows with text", action: #selector(toggleWidget), keyEquivalent: "") - arrowsWithText.state = self.widgetType == Widgets.ArrowsWithText ? NSControl.StateValue.on : NSControl.StateValue.off + arrowsWithText.state = self.widgetType == Widgets.NetworkArrowsWithText ? NSControl.StateValue.on : NSControl.StateValue.off arrowsWithText.target = self submenu.addItem(dots) @@ -100,15 +102,15 @@ class Network: Module { switch sender.title { case "Dots": - widgetCode = Widgets.Dots + widgetCode = Widgets.NetworkDots case "Arrows": - widgetCode = Widgets.Arrows + widgetCode = Widgets.NetworkArrows case "Text": - widgetCode = Widgets.Text + widgetCode = Widgets.NetworkText case "Dots with text": - widgetCode = Widgets.DotsWithText + widgetCode = Widgets.NetworkDotsWithText case "Arrows with text": - widgetCode = Widgets.ArrowsWithText + widgetCode = Widgets.NetworkArrowsWithText default: break } diff --git a/Stats/Modules/Network/NetworkReader.swift b/Stats/Modules/Network/NetworkReader.swift index f40cd05de5a..6e3ad2e2150 100644 --- a/Stats/Modules/Network/NetworkReader.swift +++ b/Stats/Modules/Network/NetworkReader.swift @@ -9,7 +9,7 @@ import Cocoa class NetworkReader: Reader { - var usage: Observable! + var value: Observable! var available: Bool = true var updateTimer: Timer! @@ -17,7 +17,7 @@ class NetworkReader: Reader { var pipe: Pipe = Pipe() init() { - self.usage = Observable(0) + self.value = Observable(0) netProcess.launchPath = "/usr/bin/env" netProcess.arguments = ["netstat", "-w1", "-l", "en0"] netProcess.standardOutput = pipe @@ -51,7 +51,7 @@ class NetworkReader: Reader { return } - self.usage << value + self.value << value } } diff --git a/Stats/Modules/Reader.swift b/Stats/Modules/Reader.swift new file mode 100644 index 00000000000..18d60b65690 --- /dev/null +++ b/Stats/Modules/Reader.swift @@ -0,0 +1,20 @@ +// +// Reader.swift +// Stats +// +// Created by Serhiy Mytrovtsiy on 08.07.2019. +// Copyright © 2019 Serhiy Mytrovtsiy. All rights reserved. +// + +import Foundation + +protocol Reader { + var value: Observable! { get } + + var available: Bool { get } + var updateTimer: Timer! { get set } + + func start() + func stop() + func read() +} diff --git a/Stats/Supporting Files/Assets.xcassets/AppIcon.appiconset/1024.png b/Stats/Supporting Files/Assets.xcassets/AppIcon.appiconset/1024.png index 445d4033bb0..a8172494173 100644 Binary files a/Stats/Supporting Files/Assets.xcassets/AppIcon.appiconset/1024.png and b/Stats/Supporting Files/Assets.xcassets/AppIcon.appiconset/1024.png differ diff --git a/Stats/Supporting Files/Assets.xcassets/AppIcon.appiconset/128.png b/Stats/Supporting Files/Assets.xcassets/AppIcon.appiconset/128.png index e8c7df69c86..4d0f7329b58 100644 Binary files a/Stats/Supporting Files/Assets.xcassets/AppIcon.appiconset/128.png and b/Stats/Supporting Files/Assets.xcassets/AppIcon.appiconset/128.png differ diff --git a/Stats/Supporting Files/Assets.xcassets/AppIcon.appiconset/16.png b/Stats/Supporting Files/Assets.xcassets/AppIcon.appiconset/16.png index c4afacac720..628518b46ae 100644 Binary files a/Stats/Supporting Files/Assets.xcassets/AppIcon.appiconset/16.png and b/Stats/Supporting Files/Assets.xcassets/AppIcon.appiconset/16.png differ diff --git a/Stats/Supporting Files/Assets.xcassets/AppIcon.appiconset/256-1.png b/Stats/Supporting Files/Assets.xcassets/AppIcon.appiconset/256-1.png index 80c323519c2..e28ffbe4172 100644 Binary files a/Stats/Supporting Files/Assets.xcassets/AppIcon.appiconset/256-1.png and b/Stats/Supporting Files/Assets.xcassets/AppIcon.appiconset/256-1.png differ diff --git a/Stats/Supporting Files/Assets.xcassets/AppIcon.appiconset/256.png b/Stats/Supporting Files/Assets.xcassets/AppIcon.appiconset/256.png index 80c323519c2..e28ffbe4172 100644 Binary files a/Stats/Supporting Files/Assets.xcassets/AppIcon.appiconset/256.png and b/Stats/Supporting Files/Assets.xcassets/AppIcon.appiconset/256.png differ diff --git a/Stats/Supporting Files/Assets.xcassets/AppIcon.appiconset/32-1.png b/Stats/Supporting Files/Assets.xcassets/AppIcon.appiconset/32-1.png index 83f1291d2a4..71b750a80b7 100644 Binary files a/Stats/Supporting Files/Assets.xcassets/AppIcon.appiconset/32-1.png and b/Stats/Supporting Files/Assets.xcassets/AppIcon.appiconset/32-1.png differ diff --git a/Stats/Supporting Files/Assets.xcassets/AppIcon.appiconset/32.png b/Stats/Supporting Files/Assets.xcassets/AppIcon.appiconset/32.png index 83f1291d2a4..71b750a80b7 100644 Binary files a/Stats/Supporting Files/Assets.xcassets/AppIcon.appiconset/32.png and b/Stats/Supporting Files/Assets.xcassets/AppIcon.appiconset/32.png differ diff --git a/Stats/Supporting Files/Assets.xcassets/AppIcon.appiconset/512-1.png b/Stats/Supporting Files/Assets.xcassets/AppIcon.appiconset/512-1.png index 5b7abe99312..4d15d717550 100644 Binary files a/Stats/Supporting Files/Assets.xcassets/AppIcon.appiconset/512-1.png and b/Stats/Supporting Files/Assets.xcassets/AppIcon.appiconset/512-1.png differ diff --git a/Stats/Supporting Files/Assets.xcassets/AppIcon.appiconset/512.png b/Stats/Supporting Files/Assets.xcassets/AppIcon.appiconset/512.png index 5b7abe99312..4d15d717550 100644 Binary files a/Stats/Supporting Files/Assets.xcassets/AppIcon.appiconset/512.png and b/Stats/Supporting Files/Assets.xcassets/AppIcon.appiconset/512.png differ diff --git a/Stats/Supporting Files/Assets.xcassets/AppIcon.appiconset/64.png b/Stats/Supporting Files/Assets.xcassets/AppIcon.appiconset/64.png index de94fa53bba..59d8a6d3791 100644 Binary files a/Stats/Supporting Files/Assets.xcassets/AppIcon.appiconset/64.png and b/Stats/Supporting Files/Assets.xcassets/AppIcon.appiconset/64.png differ diff --git a/Stats/Supporting Files/Assets.xcassets/AppIcon.appiconset/Contents.json b/Stats/Supporting Files/Assets.xcassets/AppIcon.appiconset/Contents.json index 377279b387d..501f63e3172 100755 --- a/Stats/Supporting Files/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/Stats/Supporting Files/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -45,13 +45,13 @@ { "size" : "256x256", "idiom" : "mac", - "filename" : "512.png", + "filename" : "512-1.png", "scale" : "2x" }, { "size" : "512x512", "idiom" : "mac", - "filename" : "512-1.png", + "filename" : "512.png", "scale" : "1x" }, { diff --git a/Stats/Supporting Files/Info.plist b/Stats/Supporting Files/Info.plist index 03189f4c150..ad08de2e1a9 100755 --- a/Stats/Supporting Files/Info.plist +++ b/Stats/Supporting Files/Info.plist @@ -17,9 +17,9 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.2.2 + 1.2.3 CFBundleVersion - 7 + 8 LSApplicationCategoryType public.app-category.utilities LSMinimumSystemVersion diff --git a/Stats/Widgets/BatteryView.swift b/Stats/Widgets/BatteryView.swift index 8db7eb15bdb..c96e9738688 100644 --- a/Stats/Widgets/BatteryView.swift +++ b/Stats/Widgets/BatteryView.swift @@ -9,9 +9,12 @@ import Cocoa class BatteryView: NSView, Widget { + var label: String = "" + let batteryWidth: CGFloat = 32 let percentageWidth: CGFloat = 40 + var color: Bool = false var value: Double { didSet { self.redraw() @@ -72,7 +75,7 @@ class BatteryView: NSView, Widget { let maxWidth = w-4 let inner = NSBezierPath(roundedRect: NSRect(x: x+0.5, y: y+1.5, width: maxWidth*CGFloat(self.value), height: h-3), xRadius: 0.5, yRadius: 0.5) - self.value.batteryColor().set() + self.value.batteryColor(color: self.color).set() inner.lineWidth = 0 inner.stroke() inner.close() @@ -127,6 +130,12 @@ class BatteryView: NSView, Widget { } } + func color(state: Bool) { + if self.color != state { + self.color = state + } + } + func setCharging(value: Bool) { if self.charging != value { self.charging = value diff --git a/Stats/Widgets/Chart.swift b/Stats/Widgets/Chart.swift index 9857c784ee7..df69c9d765e 100644 --- a/Stats/Widgets/Chart.swift +++ b/Stats/Widgets/Chart.swift @@ -14,6 +14,7 @@ class Chart: NSView, Widget { var label: String = "" var height: CGFloat = 0.0 + var color: Bool = false var points: [Double] { didSet { self.redraw() @@ -25,7 +26,6 @@ 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) @@ -100,7 +100,7 @@ class Chart: NSView, Widget { let style = NSMutableParagraphStyle() style.alignment = .center let stringAttributes = [ - NSAttributedString.Key.font: NSFont.systemFont(ofSize: 7.2, weight: .bold), + NSAttributedString.Key.font: NSFont.systemFont(ofSize: 7.2, weight: .regular), NSAttributedString.Key.foregroundColor: NSColor.labelColor, NSAttributedString.Key.paragraphStyle: style ] @@ -138,6 +138,12 @@ class Chart: NSView, Widget { } } + func color(state: Bool) { + if self.color != state { + self.color = state + } + } + func toggleLabel(value: Bool) { labelEnabled = value if value { @@ -182,7 +188,7 @@ class ChartWithValue: Chart { override func value(value: Double) { self.valueLabel.stringValue = "\(Int(Float(value.roundTo(decimalPlaces: 2))! * 100))%" - self.valueLabel.textColor = value.usageColor() + self.valueLabel.textColor = value.usageColor(color: self.color) if self.points.count < 50 { self.points.append(value) @@ -208,4 +214,11 @@ class ChartWithValue: Chart { self.frame = CGRect(x: self.frame.origin.x, y: self.frame.origin.y, width: self.frame.size.width - labelPadding, height: self.frame.size.height) } } + + override func color(state: Bool) { + if self.color != state { + self.color = state + self.valueLabel.textColor = self.points.last?.usageColor(color: state) + } + } } diff --git a/Stats/Widgets/Mini.swift b/Stats/Widgets/Mini.swift index a057455e107..8fdd71f838c 100644 --- a/Stats/Widgets/Mini.swift +++ b/Stats/Widgets/Mini.swift @@ -12,6 +12,7 @@ class Mini: NSView, Widget { var valueView: NSTextField = NSTextField() var labelView: NSTextField = NSTextField() + var color: Bool = false var value: Double = 0 var label: String = "" { didSet { @@ -66,7 +67,7 @@ class Mini: NSView, Widget { } func redraw() { - self.valueView.textColor = self.value.usageColor() + self.valueView.textColor = self.value.usageColor(color: self.color) self.needsDisplay = true setNeedsDisplay(self.frame) } @@ -76,7 +77,14 @@ class Mini: NSView, Widget { self.value = value self.valueView.stringValue = "\(Int(Float(value.roundTo(decimalPlaces: 2))! * 100))%" - self.valueView.textColor = value.usageColor() + self.valueView.textColor = value.usageColor(color: self.color) + } + } + + func color(state: Bool) { + if self.color != state { + self.color = state + self.valueView.textColor = value.usageColor(color: state) } } } diff --git a/Stats/Widgets/NetworkView.swift b/Stats/Widgets/NetworkView.swift index 90f9d984bc3..cb9b273b418 100644 --- a/Stats/Widgets/NetworkView.swift +++ b/Stats/Widgets/NetworkView.swift @@ -9,6 +9,9 @@ import Cocoa class NetworkDotsView: NSView, Widget { + var label: String = "" + + var color: Bool = false var download: Int64 { didSet { self.redraw() @@ -71,9 +74,19 @@ class NetworkDotsView: NSView, Widget { self.upload = values[1] } } + + func color(state: Bool) { + if self.color != state { + self.color = state + self.redraw() + } + } } class NetworkTextView: NSView, Widget { + var label: String = "" + + var color: Bool = false var downloadValue: NSTextField = NSTextField() var uploadValue: NSTextField = NSTextField() @@ -102,6 +115,13 @@ class NetworkTextView: NSView, Widget { uploadValue.stringValue = Units(bytes: values[1]).getReadableUnit() } + func color(state: Bool) { + if self.color != state { + self.color = state + self.redraw() + } + } + func valueView() { downloadValue = NSTextField(frame: NSMakeRect(MODULE_MARGIN, MODULE_MARGIN, self.frame.size.width - MODULE_MARGIN, 9)) downloadValue.isEditable = false @@ -133,6 +153,9 @@ class NetworkTextView: NSView, Widget { } class NetworkArrowsView: NSView, Widget { + var label: String = "" + + var color: Bool = false var download: Int64 { didSet { self.redraw() @@ -209,9 +232,19 @@ class NetworkArrowsView: NSView, Widget { self.upload = values[1] } } + + func color(state: Bool) { + if self.color != state { + self.color = state + self.redraw() + } + } } class NetworkDotsTextView: NSView, Widget { + var label: String = "" + + var color: Bool = false var download: Int64 { didSet { self.redraw() @@ -280,6 +313,13 @@ class NetworkDotsTextView: NSView, Widget { } } + func color(state: Bool) { + if self.color != state { + self.color = state + self.redraw() + } + } + func valueView() { downloadValue = NSTextField(frame: NSMakeRect(MODULE_MARGIN, MODULE_MARGIN, self.frame.size.width - MODULE_MARGIN, 9)) downloadValue.isEditable = false @@ -311,6 +351,9 @@ class NetworkDotsTextView: NSView, Widget { } class NetworkArrowsTextView: NSView, Widget { + var label: String = "" + + var color: Bool = false var download: Int64 { didSet { self.redraw() @@ -393,6 +436,13 @@ class NetworkArrowsTextView: NSView, Widget { } } + func color(state: Bool) { + if self.color != state { + self.color = state + self.redraw() + } + } + func valueView() { downloadValue = NSTextField(frame: NSMakeRect(MODULE_MARGIN, MODULE_MARGIN, self.frame.size.width - MODULE_MARGIN, 9)) downloadValue.isEditable = false diff --git a/Stats/Widgets/Widget.swift b/Stats/Widgets/Widget.swift new file mode 100644 index 00000000000..5e2e66ee656 --- /dev/null +++ b/Stats/Widgets/Widget.swift @@ -0,0 +1,32 @@ +// +// Widget.swift +// Stats +// +// Created by Serhiy Mytrovtsiy on 08.07.2019. +// Copyright © 2019 Serhiy Mytrovtsiy. All rights reserved. +// + +import Foundation + +protocol Widget { + var label: String { get set } + + func value(value: Double) + func color(state: Bool) + + func redraw() +} + +typealias WidgetType = Float + +struct Widgets { + static let Mini: WidgetType = 0.0 + static let Chart: WidgetType = 1.0 + static let ChartWithValue: WidgetType = 1.1 + + static let NetworkDots: WidgetType = 2.0 + static let NetworkArrows: WidgetType = 2.1 + static let NetworkText: WidgetType = 2.2 + static let NetworkDotsWithText: WidgetType = 2.3 + static let NetworkArrowsWithText: WidgetType = 2.4 +} diff --git a/Stats/libs/Extensions.swift b/Stats/libs/Extensions.swift index 16eb29c8f03..3b047c10119 100755 --- a/Stats/libs/Extensions.swift +++ b/Stats/libs/Extensions.swift @@ -14,11 +14,11 @@ extension Double { return NSString(format: "%.\(decimalPlaces)f" as NSString, self) as String } - func usageColor(reversed: Bool = false) -> NSColor { - if !colors.value { + func usageColor(reversed: Bool = false, color: Bool = false) -> NSColor { + if !color { return NSColor.textColor } - + if reversed { switch self { case 0.6...0.8: @@ -40,10 +40,10 @@ extension Double { } } - func batteryColor() -> NSColor { + func batteryColor(color: Bool = false) -> NSColor { switch self { case 0.2...0.4: - if !colors.value { + if !color { return NSColor.controlTextColor } return NSColor.systemOrange @@ -51,7 +51,7 @@ extension Double { if self == 1 { return NSColor.controlTextColor } - if !colors.value { + if !color { return NSColor.controlTextColor } return NSColor.systemGreen diff --git a/Stats/libs/Module.swift b/Stats/libs/Module.swift deleted file mode 100644 index 3df2257a3bb..00000000000 --- a/Stats/libs/Module.swift +++ /dev/null @@ -1,125 +0,0 @@ -// -// Module.swift -// Stats -// -// Created by Serhiy Mytrovtsiy on 01.06.2019. -// Copyright © 2019 Serhiy Mytrovtsiy. All rights reserved. -// - -import Cocoa - -protocol Module: class { - var name: String { get } - 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 } - var widgetType: WidgetType { get } - - func start() - func stop() -} - -extension Module { - func initWidget() { - switch self.widgetType { - case Widgets.Mini: - let widget = Mini(frame: NSMakeRect(0, 0, MODULE_WIDTH, MODULE_HEIGHT)) - widget.label = self.shortName - self.view = widget - break - case Widgets.Chart: - let widget = Chart(frame: NSMakeRect(0, 0, MODULE_WIDTH + 7, MODULE_HEIGHT)) - widget.label = self.shortName - self.view = widget - break - case Widgets.ChartWithValue: - 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)) - break - case Widgets.Arrows: - self.view = NetworkArrowsView(frame: NSMakeRect(0, 0, MODULE_WIDTH, MODULE_HEIGHT)) - break - case Widgets.Text: - self.view = NetworkTextView(frame: NSMakeRect(0, 0, MODULE_WIDTH, MODULE_HEIGHT)) - break - case Widgets.DotsWithText: - self.view = NetworkDotsTextView(frame: NSMakeRect(0, 0, MODULE_WIDTH, MODULE_HEIGHT)) - break - case Widgets.ArrowsWithText: - self.view = NetworkArrowsTextView(frame: NSMakeRect(0, 0, MODULE_WIDTH, MODULE_HEIGHT)) - break - default: - let widget = Mini(frame: NSMakeRect(0, 0, MODULE_WIDTH, MODULE_HEIGHT)) - widget.label = self.shortName - self.view = widget - } - } - - func start() { - if !self.reader.usage.value.isNaN { - guard let widget = self.view as? Widget else { - return - } - widget.value(value: self.reader.usage.value) - } - - self.reader.start() - self.reader.usage.subscribe(observer: self) { (value, _) in - if !value.isNaN { - guard let widget = self.view as? Widget else { - return - } - widget.value(value: value) - } - } - - colors.subscribe(observer: self) { (value, _) in - guard let widget = self.view as? Widget else { - return - } - widget.redraw() - } - } - - func stop() { - self.reader.stop() - self.reader.usage.unsubscribe(observer: self) - colors.unsubscribe(observer: self) - } -} - -protocol Reader { - var usage: Observable! { get } - var available: Bool { get } - var updateTimer: Timer! { get set } - func start() - func stop() - func read() -} - -protocol Widget { - func value(value: Double) - func redraw() -} - -typealias WidgetType = Float - -struct Widgets { - static let Mini: WidgetType = 0.0 - static let Chart: WidgetType = 1.0 - static let ChartWithValue: WidgetType = 1.1 - - static let Dots: WidgetType = 2.0 - static let Arrows: WidgetType = 2.1 - static let Text: WidgetType = 2.2 - static let DotsWithText: WidgetType = 2.3 - static let ArrowsWithText: WidgetType = 2.4 -} diff --git a/StatsLauncher/Assets.xcassets/AppIcon.appiconset/1024.png b/StatsLauncher/Assets.xcassets/AppIcon.appiconset/1024.png index 445d4033bb0..a8172494173 100644 Binary files a/StatsLauncher/Assets.xcassets/AppIcon.appiconset/1024.png and b/StatsLauncher/Assets.xcassets/AppIcon.appiconset/1024.png differ diff --git a/StatsLauncher/Assets.xcassets/AppIcon.appiconset/128.png b/StatsLauncher/Assets.xcassets/AppIcon.appiconset/128.png index e8c7df69c86..4d0f7329b58 100644 Binary files a/StatsLauncher/Assets.xcassets/AppIcon.appiconset/128.png and b/StatsLauncher/Assets.xcassets/AppIcon.appiconset/128.png differ diff --git a/StatsLauncher/Assets.xcassets/AppIcon.appiconset/16.png b/StatsLauncher/Assets.xcassets/AppIcon.appiconset/16.png index c4afacac720..628518b46ae 100644 Binary files a/StatsLauncher/Assets.xcassets/AppIcon.appiconset/16.png and b/StatsLauncher/Assets.xcassets/AppIcon.appiconset/16.png differ diff --git a/StatsLauncher/Assets.xcassets/AppIcon.appiconset/256-1.png b/StatsLauncher/Assets.xcassets/AppIcon.appiconset/256-1.png index 80c323519c2..e28ffbe4172 100644 Binary files a/StatsLauncher/Assets.xcassets/AppIcon.appiconset/256-1.png and b/StatsLauncher/Assets.xcassets/AppIcon.appiconset/256-1.png differ diff --git a/StatsLauncher/Assets.xcassets/AppIcon.appiconset/256.png b/StatsLauncher/Assets.xcassets/AppIcon.appiconset/256.png index 80c323519c2..e28ffbe4172 100644 Binary files a/StatsLauncher/Assets.xcassets/AppIcon.appiconset/256.png and b/StatsLauncher/Assets.xcassets/AppIcon.appiconset/256.png differ diff --git a/StatsLauncher/Assets.xcassets/AppIcon.appiconset/32-1.png b/StatsLauncher/Assets.xcassets/AppIcon.appiconset/32-1.png index 83f1291d2a4..71b750a80b7 100644 Binary files a/StatsLauncher/Assets.xcassets/AppIcon.appiconset/32-1.png and b/StatsLauncher/Assets.xcassets/AppIcon.appiconset/32-1.png differ diff --git a/StatsLauncher/Assets.xcassets/AppIcon.appiconset/32.png b/StatsLauncher/Assets.xcassets/AppIcon.appiconset/32.png index 83f1291d2a4..71b750a80b7 100644 Binary files a/StatsLauncher/Assets.xcassets/AppIcon.appiconset/32.png and b/StatsLauncher/Assets.xcassets/AppIcon.appiconset/32.png differ diff --git a/StatsLauncher/Assets.xcassets/AppIcon.appiconset/512-1.png b/StatsLauncher/Assets.xcassets/AppIcon.appiconset/512-1.png index 5b7abe99312..4d15d717550 100644 Binary files a/StatsLauncher/Assets.xcassets/AppIcon.appiconset/512-1.png and b/StatsLauncher/Assets.xcassets/AppIcon.appiconset/512-1.png differ diff --git a/StatsLauncher/Assets.xcassets/AppIcon.appiconset/512.png b/StatsLauncher/Assets.xcassets/AppIcon.appiconset/512.png index 5b7abe99312..4d15d717550 100644 Binary files a/StatsLauncher/Assets.xcassets/AppIcon.appiconset/512.png and b/StatsLauncher/Assets.xcassets/AppIcon.appiconset/512.png differ diff --git a/StatsLauncher/Assets.xcassets/AppIcon.appiconset/64.png b/StatsLauncher/Assets.xcassets/AppIcon.appiconset/64.png index de94fa53bba..59d8a6d3791 100644 Binary files a/StatsLauncher/Assets.xcassets/AppIcon.appiconset/64.png and b/StatsLauncher/Assets.xcassets/AppIcon.appiconset/64.png differ diff --git a/StatsLauncher/Assets.xcassets/AppIcon.appiconset/Contents.json b/StatsLauncher/Assets.xcassets/AppIcon.appiconset/Contents.json index 377279b387d..501f63e3172 100755 --- a/StatsLauncher/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/StatsLauncher/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -45,13 +45,13 @@ { "size" : "256x256", "idiom" : "mac", - "filename" : "512.png", + "filename" : "512-1.png", "scale" : "2x" }, { "size" : "512x512", "idiom" : "mac", - "filename" : "512-1.png", + "filename" : "512.png", "scale" : "1x" }, {