diff --git a/Kit/Widgets/State.swift b/Kit/Widgets/State.swift
new file mode 100644
index 00000000..fedb0533
--- /dev/null
+++ b/Kit/Widgets/State.swift
@@ -0,0 +1,60 @@
+//
+// State.swift
+// Kit
+//
+// Created by Serhiy Mytrovtsiy on 18/09/2022.
+// Using Swift 5.0.
+// Running on macOS 12.6.
+//
+// Copyright © 2022 Serhiy Mytrovtsiy. All rights reserved.
+//
+
+import Cocoa
+
+public class StateWidget: WidgetWrapper {
+ private var value: Bool = false
+
+ public init(title: String, config: NSDictionary?, preview: Bool = false) {
+ if config != nil {
+ var configuration = config!
+
+ if preview {
+ if let previewConfig = config!["Preview"] as? NSDictionary {
+ configuration = previewConfig
+ if let value = configuration["Value"] as? Bool {
+ self.value = value
+ }
+ }
+ }
+ }
+
+ super.init(.state, title: title, frame: CGRect(
+ x: 0,
+ y: Constants.Widget.margin.y,
+ width: 8 + (2*Constants.Widget.margin.x),
+ height: Constants.Widget.height - (2*Constants.Widget.margin.y)
+ ))
+
+ self.canDrawConcurrently = true
+ }
+
+ required init?(coder: NSCoder) {
+ fatalError("init(coder:) has not been implemented")
+ }
+
+ public override func draw(_ dirtyRect: NSRect) {
+ super.draw(dirtyRect)
+
+ let circle = NSBezierPath(ovalIn: CGRect(x: Constants.Widget.margin.x, y: (self.frame.height - 8)/2, width: 8, height: 8))
+ (self.value ? NSColor.systemGreen : NSColor.systemRed).set()
+ circle.fill()
+ }
+
+ public func setValue(_ value: Bool) {
+ guard self.value != value else { return }
+ self.value = value
+ DispatchQueue.main.async(execute: {
+ self.display()
+ })
+ }
+}
diff --git a/Kit/module/widget.swift b/Kit/module/widget.swift
index 51560ff3..4809d664 100644
--- a/Kit/module/widget.swift
+++ b/Kit/module/widget.swift
@@ -24,6 +24,7 @@ public enum widget_t: String {
case memory = "memory"
case label = "label"
case tachometer = "tachometer"
+ case state = "state"
public func new(module: String, config: NSDictionary, defaultWidget: widget_t) -> Widget? {
var image: NSImage? = nil
@@ -68,6 +69,9 @@ public enum widget_t: String {
case .tachometer:
preview = Tachometer(title: module, config: widgetConfig, preview: true)
item = Tachometer(title: module, config: widgetConfig, preview: false)
+ case .state:
+ preview = StateWidget(title: module, config: widgetConfig, preview: true)
+ item = StateWidget(title: module, config: widgetConfig, preview: false)
default: break
}
@@ -128,6 +132,7 @@ public enum widget_t: String {
case .memory: return localizedString("Memory widget")
case .label: return localizedString("Label widget")
case .tachometer: return localizedString("Tachometer widget")
+ case .state: return localizedString("State widget")
default: return ""
}
}
diff --git a/Modules/Net/config.plist b/Modules/Net/config.plist
index f00e4c28..a5ddacb5 100644
--- a/Modules/Net/config.plist
+++ b/Modules/Net/config.plist
@@ -40,6 +40,18 @@
system
+ state
+
+ Default
+
+ Order
+ 3
+ Preview
+
+ Value
+
+
+
diff --git a/Modules/Net/main.swift b/Modules/Net/main.swift
index 66d0c791..53064c5e 100644
--- a/Modules/Net/main.swift
+++ b/Modules/Net/main.swift
@@ -151,7 +151,7 @@ public class Network: Module {
}
self.connectivityReader?.callbackHandler = { [unowned self] value in
- self.popupView.connectivityCallback(value)
+ self.connectivityCallback(value)
}
self.settingsView.callback = { [unowned self] in
@@ -211,6 +211,19 @@ public class Network: Module {
}
}
+ private func connectivityCallback(_ raw: Bool?) {
+ guard let value = raw, self.enabled else { return }
+
+ self.popupView.connectivityCallback(value)
+
+ self.menuBar.widgets.filter{ $0.isActive }.forEach { (w: Widget) in
+ switch w.item {
+ case let widget as StateWidget: widget.setValue(value)
+ default: break
+ }
+ }
+ }
+
private func setIPUpdater() {
self.ipUpdater.interval = 60 * 60
self.ipUpdater.repeats = true
diff --git a/Stats.xcodeproj/project.pbxproj b/Stats.xcodeproj/project.pbxproj
index a1ba90d2..8c283be0 100644
--- a/Stats.xcodeproj/project.pbxproj
+++ b/Stats.xcodeproj/project.pbxproj
@@ -122,6 +122,7 @@
9AE29AF6249A52B00071B02D /* config.plist in Resources */ = {isa = PBXBuildFile; fileRef = 9AE29AF4249A52870071B02D /* config.plist */; };
9AE29AFB249A53DC0071B02D /* readers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9AE29AF9249A53780071B02D /* readers.swift */; };
9AE29AFC249A53DC0071B02D /* values.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9AE29AF7249A53420071B02D /* values.swift */; };
+ 9AEBBE4D28D773430082A6A1 /* State.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9AEBBE4C28D773430082A6A1 /* State.swift */; };
9AF9EE0924648751005D2270 /* Disk.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9AF9EE0224648751005D2270 /* Disk.framework */; };
9AF9EE0A24648751005D2270 /* Disk.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9AF9EE0224648751005D2270 /* Disk.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
9AF9EE0F2464875F005D2270 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9AF9EE0E2464875F005D2270 /* main.swift */; };
@@ -446,6 +447,7 @@
9AE29AF4249A52870071B02D /* config.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; name = config.plist; path = Modules/Sensors/config.plist; sourceTree = SOURCE_ROOT; };
9AE29AF7249A53420071B02D /* values.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = values.swift; path = Modules/Sensors/values.swift; sourceTree = SOURCE_ROOT; };
9AE29AF9249A53780071B02D /* readers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = readers.swift; path = Modules/Sensors/readers.swift; sourceTree = SOURCE_ROOT; };
+ 9AEBBE4C28D773430082A6A1 /* State.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = State.swift; sourceTree = ""; };
9AF9EE0224648751005D2270 /* Disk.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Disk.framework; sourceTree = BUILT_PRODUCTS_DIR; };
9AF9EE0524648751005D2270 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
9AF9EE0E2464875F005D2270 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; };
@@ -661,6 +663,7 @@
9A28475E2666AA2700EC1F6D /* Sensors.swift */,
9A28475C2666AA2700EC1F6D /* Speed.swift */,
9A9B8C9C27149A3700218374 /* Tachometer.swift */,
+ 9AEBBE4C28D773430082A6A1 /* State.swift */,
);
path = Widgets;
sourceTree = "";
@@ -1520,6 +1523,7 @@
9A2847792666AA5000EC1F6D /* module.swift in Sources */,
9A2847662666AA2700EC1F6D /* Speed.swift in Sources */,
9A2847682666AA2700EC1F6D /* Sensors.swift in Sources */,
+ 9AEBBE4D28D773430082A6A1 /* State.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};