From c37585d4b3731acadce5dde3b77b69b12a63cb18 Mon Sep 17 00:00:00 2001 From: Serhiy Mytrovtsiy Date: Tue, 30 Apr 2024 22:43:39 +0200 Subject: [PATCH] feat: moved widget activation threshold slider to the input with a base that allows specifying the threshold more accurate --- Modules/Net/main.swift | 25 +++++++++------ Modules/Net/portal.swift | 11 +++++-- Modules/Net/settings.swift | 64 ++++++++++++++++++++++++++------------ 3 files changed, 69 insertions(+), 31 deletions(-) diff --git a/Modules/Net/main.swift b/Modules/Net/main.swift index dd03109c..754f3faa 100644 --- a/Modules/Net/main.swift +++ b/Modules/Net/main.swift @@ -135,8 +135,14 @@ public class Network: Module { private let ipUpdater = NSBackgroundActivityScheduler(identifier: "eu.exelban.Stats.Network.IP") private let usageReseter = NSBackgroundActivityScheduler(identifier: "eu.exelban.Stats.Network.Usage") + private var widgetActivationThresholdState: Bool { + Store.shared.bool(key: "\(self.config.name)_widgetActivationThresholdState", defaultValue: false) + } private var widgetActivationThreshold: Int { - Store.shared.int(key: "\(self.config.name)_widgetActivationThreshold", defaultValue: 0) * 1_024 + Store.shared.int(key: "\(self.config.name)_widgetActivationThreshold", defaultValue: 0) + } + private var widgetActivationThresholdSize: SizeUnit { + SizeUnit.fromString(Store.shared.string(key: "\(self.name)_widgetActivationThresholdSize", defaultValue: SizeUnit.MB.key)) } private var publicIPRefreshInterval: String { Store.shared.string(key: "\(self.name)_publicIPRefreshInterval", defaultValue: "never") @@ -212,11 +218,14 @@ public class Network: Module { self.popupView.usageCallback(value) self.portalView.usageCallback(value) - var upload: Int64 = 0 - var download: Int64 = 0 - if value.bandwidth.upload >= self.widgetActivationThreshold || value.bandwidth.download >= self.widgetActivationThreshold { - upload = value.bandwidth.upload - download = value.bandwidth.download + var upload: Int64 = value.bandwidth.upload + var download: Int64 = value.bandwidth.download + if self.widgetActivationThresholdState { + let threshold = self.widgetActivationThresholdSize.toBytes(self.widgetActivationThreshold) + if value.bandwidth.upload >= threshold || value.bandwidth.download >= threshold { + upload = 0 + download = 0 + } } self.menuBar.widgets.filter{ $0.isActive }.forEach { (w: Widget) in @@ -256,9 +265,7 @@ public class Network: Module { self.ipUpdater.repeats = true self.ipUpdater.schedule { (completion: @escaping NSBackgroundActivityScheduler.CompletionHandler) in - guard self.enabled && self.isAvailable() else { - return - } + guard self.enabled && self.isAvailable() else { return } debug("going to automatically refresh IP address...") NotificationCenter.default.post(name: .refreshPublicIP, object: nil, userInfo: nil) completion(NSBackgroundActivityScheduler.Result.finished) diff --git a/Modules/Net/portal.swift b/Modules/Net/portal.swift index 441bd7a5..956a50b1 100644 --- a/Modules/Net/portal.swift +++ b/Modules/Net/portal.swift @@ -26,6 +26,12 @@ public class Portal: PortalWrapper { private var chartScale: Scale { Scale.fromString(Store.shared.string(key: "\(self.name)_chartScale", defaultValue: Scale.none.key)) } + private var chartFixedScale: Int { + Store.shared.int(key: "\(self.name)_chartFixedScale", defaultValue: 12) + } + private var chartFixedScaleSize: SizeUnit { + SizeUnit.fromString(Store.shared.string(key: "\(self.name)_chartFixedScaleSize", defaultValue: SizeUnit.MB.key)) + } private var downloadColor: NSColor { let v = Color.fromString(Store.shared.string(key: "\(self.name)_downloadColor", defaultValue: Color.secondBlue.key)) @@ -68,7 +74,8 @@ public class Portal: PortalWrapper { reversedOrder: self.reverseOrderState, outColor: self.uploadColor, inColor: self.downloadColor, - scale: self.chartScale + scale: self.chartScale, + fixedScale: Double(self.chartFixedScaleSize.toBytes(self.chartFixedScale)) ) chart.base = self.base container.addSubview(chart) @@ -88,7 +95,7 @@ public class Portal: PortalWrapper { chart.base = self.base } chart.addValue(upload: Double(value.bandwidth.upload), download: Double(value.bandwidth.download)) - chart.setScale(self.chartScale, 1) + chart.setScale(self.chartScale, Double(self.chartFixedScaleSize.toBytes(self.chartFixedScale))) chart.setColors(in: self.downloadColor, out: self.uploadColor) } diff --git a/Modules/Net/settings.swift b/Modules/Net/settings.swift index 3b93a87e..27af1ac4 100644 --- a/Modules/Net/settings.swift +++ b/Modules/Net/settings.swift @@ -18,7 +18,9 @@ internal class Settings: NSStackView, Settings_v, NSTextFieldDelegate { private var readerType: String = "interface" private var usageReset: String = AppUpdateInterval.atStart.rawValue private var VPNModeState: Bool = false + private var widgetActivationThresholdState: Bool = false private var widgetActivationThreshold: Int = 0 + private var widgetActivationThresholdSize: SizeUnit = .MB private var ICMPHost: String = "1.1.1.1" private var publicIPRefreshInterval: String = "never" private var baseValue: String = "byte" @@ -32,6 +34,7 @@ internal class Settings: NSStackView, Settings_v, NSTextFieldDelegate { private let title: String private var sliderView: NSView? = nil private var section: PreferencesSection? = nil + private var widgetThresholdSection: PreferencesSection? = nil private var list: [Network_interface] = [] @@ -48,7 +51,9 @@ internal class Settings: NSStackView, Settings_v, NSTextFieldDelegate { self.readerType = Store.shared.string(key: "\(self.title)_reader", defaultValue: self.readerType) self.usageReset = Store.shared.string(key: "\(self.title)_usageReset", defaultValue: self.usageReset) self.VPNModeState = Store.shared.bool(key: "\(self.title)_VPNMode", defaultValue: self.VPNModeState) + self.widgetActivationThresholdState = Store.shared.bool(key: "\(self.title)_widgetActivationThresholdState", defaultValue: self.widgetActivationThresholdState) self.widgetActivationThreshold = Store.shared.int(key: "\(self.title)_widgetActivationThreshold", defaultValue: self.widgetActivationThreshold) + self.widgetActivationThresholdSize = SizeUnit.fromString(Store.shared.string(key: "\(self.title)_widgetActivationThresholdSize", defaultValue: self.widgetActivationThresholdSize.key)) self.ICMPHost = Store.shared.string(key: "\(self.title)_ICMPHost", defaultValue: self.ICMPHost) self.publicIPRefreshInterval = Store.shared.string(key: "\(self.title)_publicIPRefreshInterval", defaultValue: self.publicIPRefreshInterval) self.baseValue = Store.shared.string(key: "\(self.title)_base", defaultValue: self.baseValue) @@ -140,17 +145,30 @@ internal class Settings: NSStackView, Settings_v, NSTextFieldDelegate { self.addArrangedSubview(section) self.section = section - self.sliderView = sliderView( - action: #selector(self.sliderCallback), - value: self.widgetActivationThreshold, - initialValue: self.widgetActivationThreshold != 0 ? "\(self.widgetActivationThreshold) KB" : localizedString("Disabled"), - min: 0, - max: 1024, - valueWidth: 70 - ) - self.addArrangedSubview(PreferencesSection([ - PreferencesRow(localizedString("Widget activation threshold"), component: self.sliderView!) - ])) + self.widgetThresholdSection = PreferencesSection([ + PreferencesRow(localizedString("Widget activation threshold"), component: switchView( + action: #selector(self.toggleWidgetActivationThreshold), + state: self.widgetActivationThresholdState + )), + PreferencesRow(localizedString("Value"), component: { + let view: NSStackView = NSStackView() + view.orientation = .horizontal + view.spacing = 2 + let valueField = StepperInput(self.widgetActivationThreshold, range: NSRange(location: 1, length: 1023)) + valueField.callback = self.changeWidgetActivationThreshold + valueField.widthAnchor.constraint(equalToConstant: 80).isActive = true + view.addArrangedSubview(NSView()) + view.addArrangedSubview(valueField) + view.addArrangedSubview(selectView( + action: #selector(self.toggleWidgetActivationThresholdSize), + items: SizeUnit.allCases, + selected: self.widgetActivationThresholdSize.key + )) + return view + }()) + ]) + self.addArrangedSubview(self.widgetThresholdSection!) + self.widgetThresholdSection?.toggleVisibility(1, newState: self.widgetActivationThresholdState) let valueField: NSTextField = NSTextField() valueField.widthAnchor.constraint(equalToConstant: 250).isActive = true @@ -158,8 +176,6 @@ internal class Settings: NSStackView, Settings_v, NSTextFieldDelegate { valueField.textColor = .textColor valueField.isEditable = true valueField.isSelectable = true - valueField.isBezeled = false - valueField.canDrawSubviewsIntoLayer = true valueField.usesSingleLineMode = true valueField.maximumNumberOfLines = 1 valueField.focusRingType = .none @@ -209,13 +225,21 @@ internal class Settings: NSStackView, Settings_v, NSTextFieldDelegate { self.VPNModeState = controlState(sender) Store.shared.set(key: "\(self.title)_VPNMode", value: self.VPNModeState) } - @objc private func sliderCallback(_ sender: NSSlider) { - let value = Int(sender.doubleValue) - if let field = self.sliderView?.subviews.first(where: { $0 is NSTextField }), let view = field as? NSTextField { - view.stringValue = value == 0 ? localizedString("Disabled") : "\(value) KB" - } - self.widgetActivationThreshold = value - Store.shared.set(key: "\(self.title)_widgetActivationThreshold", value: self.widgetActivationThreshold) + @objc func toggleWidgetActivationThreshold(_ sender: NSControl) { + self.widgetActivationThresholdState = controlState(sender) + Store.shared.set(key: "\(self.title)_widgetActivationThresholdState", value: self.widgetActivationThresholdState) + self.widgetThresholdSection?.toggleVisibility(1, newState: self.widgetActivationThresholdState) + } + @objc private func changeWidgetActivationThreshold(_ newValue: Int) { + self.widgetActivationThreshold = newValue + Store.shared.set(key: "\(self.title)_widgetActivationThreshold", value: newValue) + } + @objc private func toggleWidgetActivationThresholdSize(_ sender: NSMenuItem) { + guard let key = sender.representedObject as? String, + let value = SizeUnit.allCases.first(where: { $0.key == key }) else { return } + self.widgetActivationThresholdSize = value + Store.shared.set(key: "\(self.title)_widgetActivationThresholdSize", value: key) + self.display() } func controlTextDidChange(_ notification: Notification) {