This commit is contained in:
Serhiy Mytrovtsiy
2019-07-03 20:41:05 +02:00
parent 81af45661c
commit 6e1f0ff85a
12 changed files with 152 additions and 80 deletions

View File

@@ -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

View File

@@ -15,6 +15,9 @@ extension Notification.Name {
let modules: Observable<[Module]> = Observable([CPU(), Memory(), Disk(), Battery(), Network()])
let colors: Observable<Bool> = Observable(true)
let labelForChart: Observable<Bool> = 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() {

View File

@@ -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
}
}

View File

@@ -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() {

View File

@@ -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
}
}

View File

@@ -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()
}
}

View File

@@ -87,8 +87,10 @@ class Network: Module {
self.active << state
if !state {
menu.submenu = nil
self.stop()
} else {
menu.submenu = submenu
self.start()
}
}

View File

@@ -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() {}

View File

@@ -17,7 +17,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.2.1</string>
<string>1.2.2</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSApplicationCategoryType</key>

View File

@@ -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)
}
}
}

View File

@@ -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
// }
// }
//}

View File

@@ -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<Bool> { get }
var available: Observable<Bool> { 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))