mirror of
https://github.com/morgan9e/macos-stats
synced 2026-04-14 00:04:15 +09:00
feat: small redesign in the Network popup view. Moved interface details to the dedicated section, added interface dns servers (#2789), added interface speed (#2702)
This commit is contained in:
@@ -339,12 +339,20 @@ public func separatorView(_ title: String, origin: NSPoint = NSPoint(x: 0, y: 0)
|
|||||||
return view
|
return view
|
||||||
}
|
}
|
||||||
|
|
||||||
public func popupRow(_ view: NSView, title: String, value: String) -> (LabelField, ValueField, NSView) {
|
public func popupRow(_ view: NSView? = nil, title: String, value: String, multiline: Bool = false) -> (LabelField, ValueField, NSView) {
|
||||||
let rowView: NSView = NSView(frame: NSRect(x: 0, y: 0, width: view.frame.width, height: 22))
|
let lines: CGFloat = CGFloat(multiline ? value.filter { $0 == "\n" }.count + 1 : 1)
|
||||||
|
let width = view?.frame.width ?? 0
|
||||||
|
let height = multiline ? ((lines*16) + (22-16)): 22
|
||||||
|
|
||||||
|
let rowView: NSView = NSView(frame: NSRect(x: 0, y: 0, width: width, height: height))
|
||||||
|
|
||||||
let labelWidth = title.widthOfString(usingFont: .systemFont(ofSize: 12, weight: .regular)) + 4
|
let labelWidth = title.widthOfString(usingFont: .systemFont(ofSize: 12, weight: .regular)) + 4
|
||||||
let labelView: LabelField = LabelField(frame: NSRect(x: 0, y: (22-16)/2, width: labelWidth, height: 16), title)
|
let labelView: LabelField = LabelField(frame: NSRect(x: 0, y: ((22-16)/2) + ((lines-1)*16), width: labelWidth, height: 16), title)
|
||||||
let valueView: ValueField = ValueField(frame: NSRect(x: labelWidth, y: (22-16)/2, width: rowView.frame.width - labelWidth, height: 16), value)
|
let valueView: ValueField = ValueField(frame: NSRect(x: labelWidth, y: (22-16)/2, width: rowView.frame.width - labelWidth, height: multiline ? 16*lines : 16), value)
|
||||||
|
|
||||||
|
if multiline {
|
||||||
|
valueView.cell?.usesSingleLineMode = false
|
||||||
|
}
|
||||||
|
|
||||||
rowView.addSubview(labelView)
|
rowView.addSubview(labelView)
|
||||||
rowView.addSubview(valueView)
|
rowView.addSubview(valueView)
|
||||||
@@ -352,7 +360,7 @@ public func popupRow(_ view: NSView, title: String, value: String) -> (LabelFiel
|
|||||||
if let view = view as? NSStackView {
|
if let view = view as? NSStackView {
|
||||||
rowView.heightAnchor.constraint(equalToConstant: rowView.bounds.height).isActive = true
|
rowView.heightAnchor.constraint(equalToConstant: rowView.bounds.height).isActive = true
|
||||||
view.addArrangedSubview(rowView)
|
view.addArrangedSubview(rowView)
|
||||||
} else {
|
} else if let view {
|
||||||
view.addSubview(rowView)
|
view.addSubview(rowView)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,9 +22,11 @@ public enum Network_t: String, Codable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public struct Network_interface: Codable {
|
public struct Network_interface: Codable {
|
||||||
|
var status: Bool = false
|
||||||
var displayName: String = ""
|
var displayName: String = ""
|
||||||
var BSDName: String = ""
|
var BSDName: String = ""
|
||||||
var address: String = ""
|
var address: String = ""
|
||||||
|
var transmitRate: Double = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct Network_addr: Codable {
|
public struct Network_addr: Codable {
|
||||||
@@ -39,7 +41,6 @@ public struct Network_wifi: Codable {
|
|||||||
var bssid: String? = nil
|
var bssid: String? = nil
|
||||||
var RSSI: Int? = nil
|
var RSSI: Int? = nil
|
||||||
var noise: Int? = nil
|
var noise: Int? = nil
|
||||||
var transmitRate: Double? = nil
|
|
||||||
|
|
||||||
var standard: String? = nil
|
var standard: String? = nil
|
||||||
var mode: String? = nil
|
var mode: String? = nil
|
||||||
@@ -55,7 +56,6 @@ public struct Network_wifi: Codable {
|
|||||||
self.ssid = nil
|
self.ssid = nil
|
||||||
self.RSSI = nil
|
self.RSSI = nil
|
||||||
self.noise = nil
|
self.noise = nil
|
||||||
self.transmitRate = nil
|
|
||||||
self.standard = nil
|
self.standard = nil
|
||||||
self.mode = nil
|
self.mode = nil
|
||||||
self.security = nil
|
self.security = nil
|
||||||
@@ -75,6 +75,8 @@ public struct Network_Usage: Codable, RemoteType {
|
|||||||
var laddr: Network_addr = Network_addr() // local ip
|
var laddr: Network_addr = Network_addr() // local ip
|
||||||
var raddr: Network_addr = Network_addr() // remote ip
|
var raddr: Network_addr = Network_addr() // remote ip
|
||||||
|
|
||||||
|
var dns: [String] = []
|
||||||
|
|
||||||
var interface: Network_interface? = nil
|
var interface: Network_interface? = nil
|
||||||
var connectionType: Network_t? = nil
|
var connectionType: Network_t? = nil
|
||||||
var status: Bool = false
|
var status: Bool = false
|
||||||
@@ -87,6 +89,8 @@ public struct Network_Usage: Codable, RemoteType {
|
|||||||
self.laddr = Network_addr()
|
self.laddr = Network_addr()
|
||||||
self.raddr = Network_addr()
|
self.raddr = Network_addr()
|
||||||
|
|
||||||
|
self.dns = []
|
||||||
|
|
||||||
self.interface = nil
|
self.interface = nil
|
||||||
self.connectionType = nil
|
self.connectionType = nil
|
||||||
|
|
||||||
@@ -277,6 +281,7 @@ public class Network: Module {
|
|||||||
case "displayName": replacement = value.interface?.displayName ?? "-"
|
case "displayName": replacement = value.interface?.displayName ?? "-"
|
||||||
case "BSDName": replacement = value.interface?.BSDName ?? "-"
|
case "BSDName": replacement = value.interface?.BSDName ?? "-"
|
||||||
case "address": replacement = value.interface?.address ?? "-"
|
case "address": replacement = value.interface?.address ?? "-"
|
||||||
|
case "transmitRate": replacement = "\(value.interface?.transmitRate ?? 0)"
|
||||||
default: return
|
default: return
|
||||||
}
|
}
|
||||||
case "$wifi":
|
case "$wifi":
|
||||||
@@ -285,7 +290,6 @@ public class Network: Module {
|
|||||||
case "bssid": replacement = value.wifiDetails.bssid ?? "-"
|
case "bssid": replacement = value.wifiDetails.bssid ?? "-"
|
||||||
case "RSSI": replacement = "\(value.wifiDetails.RSSI ?? 0)"
|
case "RSSI": replacement = "\(value.wifiDetails.RSSI ?? 0)"
|
||||||
case "noise": replacement = "\(value.wifiDetails.noise ?? 0)"
|
case "noise": replacement = "\(value.wifiDetails.noise ?? 0)"
|
||||||
case "transmitRate": replacement = "\(value.wifiDetails.transmitRate ?? 0)"
|
|
||||||
case "standard": replacement = value.wifiDetails.standard ?? "-"
|
case "standard": replacement = value.wifiDetails.standard ?? "-"
|
||||||
case "mode": replacement = value.wifiDetails.mode ?? "-"
|
case "mode": replacement = value.wifiDetails.mode ?? "-"
|
||||||
case "security": replacement = value.wifiDetails.security ?? "-"
|
case "security": replacement = value.wifiDetails.security ?? "-"
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
import Cocoa
|
import Cocoa
|
||||||
import Kit
|
import Kit
|
||||||
|
|
||||||
|
// swiftlint:disable:next type_body_length
|
||||||
internal class Popup: PopupWrapper {
|
internal class Popup: PopupWrapper {
|
||||||
private var uploadContainerView: NSView? = nil
|
private var uploadContainerView: NSView? = nil
|
||||||
private var uploadView: NSView? = nil
|
private var uploadView: NSView? = nil
|
||||||
@@ -30,23 +31,30 @@ internal class Popup: PopupWrapper {
|
|||||||
private var downloadColorView: NSView? = nil
|
private var downloadColorView: NSView? = nil
|
||||||
private var uploadColorView: NSView? = nil
|
private var uploadColorView: NSView? = nil
|
||||||
|
|
||||||
private var detailsView: NSStackView? = nil
|
|
||||||
private var totalUploadLabel: LabelField? = nil
|
private var totalUploadLabel: LabelField? = nil
|
||||||
private var totalUploadField: ValueField? = nil
|
private var totalUploadField: ValueField? = nil
|
||||||
private var totalDownloadLabel: LabelField? = nil
|
private var totalDownloadLabel: LabelField? = nil
|
||||||
private var totalDownloadField: ValueField? = nil
|
private var totalDownloadField: ValueField? = nil
|
||||||
private var statusField: ValueField? = nil
|
private var statusField: ValueField? = nil
|
||||||
private var connectivityField: ValueField? = nil
|
private var connectivityField: ValueField? = nil
|
||||||
private var interfaceField: ValueField? = nil
|
|
||||||
private var macAddressField: ValueField? = nil
|
|
||||||
private var latencyField: ValueField? = nil
|
private var latencyField: ValueField? = nil
|
||||||
|
|
||||||
|
private var interfaceView: NSStackView? = nil
|
||||||
|
private var interfaceField: ValueField? = nil
|
||||||
|
private var interfaceStatusField: ValueField? = nil
|
||||||
|
private var macAddressField: ValueField? = nil
|
||||||
private var ssidField: ValueField? = nil
|
private var ssidField: ValueField? = nil
|
||||||
private var standardField: ValueField? = nil
|
private var standardField: ValueField? = nil
|
||||||
private var channelField: ValueField? = nil
|
private var channelField: ValueField? = nil
|
||||||
private var ssidView: NSView? = nil
|
private var ssidView: NSView? = nil
|
||||||
|
|
||||||
|
private var interfaceDetailsState: Bool = false
|
||||||
private var standardView: NSView? = nil
|
private var standardView: NSView? = nil
|
||||||
private var channelView: NSView? = nil
|
private var channelView: NSView? = nil
|
||||||
|
private var interfaceSpeedView: NSView? = nil
|
||||||
|
private var interfaceSpeedField: ValueField? = nil
|
||||||
|
private var dnsServersView: NSView? = nil
|
||||||
|
private var dnsServersField: ValueField? = nil
|
||||||
|
|
||||||
private var addressView: NSStackView? = nil
|
private var addressView: NSStackView? = nil
|
||||||
private var localIPField: ValueField? = nil
|
private var localIPField: ValueField? = nil
|
||||||
@@ -116,11 +124,13 @@ internal class Popup: PopupWrapper {
|
|||||||
self.chartFixedScale = Store.shared.int(key: "\(self.title)_chartFixedScale", defaultValue: self.chartFixedScale)
|
self.chartFixedScale = Store.shared.int(key: "\(self.title)_chartFixedScale", defaultValue: self.chartFixedScale)
|
||||||
self.chartFixedScaleSize = SizeUnit.fromString(Store.shared.string(key: "\(self.title)_chartFixedScaleSize", defaultValue: self.chartFixedScaleSize.key))
|
self.chartFixedScaleSize = SizeUnit.fromString(Store.shared.string(key: "\(self.title)_chartFixedScaleSize", defaultValue: self.chartFixedScaleSize.key))
|
||||||
self.publicIPState = Store.shared.bool(key: "\(self.title)_publicIP", defaultValue: self.publicIPState)
|
self.publicIPState = Store.shared.bool(key: "\(self.title)_publicIP", defaultValue: self.publicIPState)
|
||||||
|
self.interfaceDetailsState = Store.shared.bool(key: "\(self.title)_interfaceDetails", defaultValue: self.interfaceDetailsState)
|
||||||
|
|
||||||
self.addArrangedSubview(self.initDashboard())
|
self.addArrangedSubview(self.initDashboard())
|
||||||
self.addArrangedSubview(self.initChart())
|
self.addArrangedSubview(self.initChart())
|
||||||
self.addArrangedSubview(self.initConnectivityChart())
|
self.addArrangedSubview(self.initConnectivityChart())
|
||||||
self.addArrangedSubview(self.initDetails())
|
self.addArrangedSubview(self.initDetails())
|
||||||
|
self.addArrangedSubview(self.initInterface())
|
||||||
self.addArrangedSubview(self.initAddress())
|
self.addArrangedSubview(self.initAddress())
|
||||||
self.addArrangedSubview(self.initProcesses())
|
self.addArrangedSubview(self.initProcesses())
|
||||||
|
|
||||||
@@ -264,22 +274,61 @@ internal class Popup: PopupWrapper {
|
|||||||
self.statusField = popupRow(view, title: "\(localizedString("Status")):", value: localizedString("Unknown")).1
|
self.statusField = popupRow(view, title: "\(localizedString("Status")):", value: localizedString("Unknown")).1
|
||||||
self.connectivityField = popupRow(view, title: "\(localizedString("Internet connection")):", value: localizedString("Unknown")).1
|
self.connectivityField = popupRow(view, title: "\(localizedString("Internet connection")):", value: localizedString("Unknown")).1
|
||||||
self.latencyField = popupRow(view, title: "\(localizedString("Latency")):", value: "0 ms").1
|
self.latencyField = popupRow(view, title: "\(localizedString("Latency")):", value: "0 ms").1
|
||||||
|
|
||||||
|
return view
|
||||||
|
}
|
||||||
|
|
||||||
|
private func initInterface() -> NSView {
|
||||||
|
let view = NSStackView(frame: NSRect(x: 0, y: 0, width: self.frame.width, height: 0))
|
||||||
|
view.orientation = .vertical
|
||||||
|
view.spacing = 0
|
||||||
|
|
||||||
|
let row: NSView = NSView(frame: NSRect(x: 0, y: 0, width: view.frame.width, height: Constants.Popup.separatorHeight))
|
||||||
|
row.heightAnchor.constraint(equalToConstant: Constants.Popup.separatorHeight).isActive = true
|
||||||
|
|
||||||
|
let button = NSButtonWithPadding()
|
||||||
|
button.frame = CGRect(x: view.frame.width - 18, y: 6, width: 18, height: 18)
|
||||||
|
button.bezelStyle = .regularSquare
|
||||||
|
button.isBordered = false
|
||||||
|
button.imageScaling = NSImageScaling.scaleAxesIndependently
|
||||||
|
button.contentTintColor = .lightGray
|
||||||
|
button.action = #selector(self.toggleInterfaceDetails)
|
||||||
|
button.target = self
|
||||||
|
button.toolTip = localizedString("Details")
|
||||||
|
button.image = Bundle(for: Module.self).image(forResource: "tune")!
|
||||||
|
|
||||||
|
row.addSubview(separatorView(localizedString("Interface"), width: self.frame.width))
|
||||||
|
row.addSubview(button)
|
||||||
|
|
||||||
|
view.addArrangedSubview(row)
|
||||||
|
|
||||||
self.interfaceField = popupRow(view, title: "\(localizedString("Interface")):", value: localizedString("Unknown")).1
|
self.interfaceField = popupRow(view, title: "\(localizedString("Interface")):", value: localizedString("Unknown")).1
|
||||||
|
self.interfaceStatusField = popupRow(view, title: "\(localizedString("Status")):", value: localizedString("Unknown")).1
|
||||||
self.macAddressField = popupRow(view, title: "\(localizedString("Physical address")):", value: localizedString("Unknown")).1
|
self.macAddressField = popupRow(view, title: "\(localizedString("Physical address")):", value: localizedString("Unknown")).1
|
||||||
self.macAddressField?.isSelectable = true
|
self.macAddressField?.isSelectable = true
|
||||||
|
|
||||||
let ssid = popupRow(view, title: "\(localizedString("Network")):", value: localizedString("Unknown"))
|
let ssid = popupRow(view, title: "\(localizedString("Network")):", value: localizedString("Unknown"))
|
||||||
let standard = popupRow(view, title: "\(localizedString("Standard")):", value: localizedString("Unknown"))
|
let standard = popupRow(view, title: "\(localizedString("Standard")):", value: localizedString("Unavailable"))
|
||||||
let channel = popupRow(view, title: "\(localizedString("Channel")):", value: localizedString("Unknown"))
|
let channel = popupRow(view, title: "\(localizedString("Channel")):", value: localizedString("Unavailable"))
|
||||||
|
let speed = popupRow(view, title: "\(localizedString("Speed")):", value: localizedString("Unknown"))
|
||||||
|
|
||||||
self.ssidField = ssid.1
|
self.ssidField = ssid.1
|
||||||
self.standardField = standard.1
|
self.standardField = standard.1
|
||||||
self.channelField = channel.1
|
self.channelField = channel.1
|
||||||
|
self.interfaceSpeedField = speed.1
|
||||||
|
|
||||||
self.ssidView = ssid.2
|
self.ssidView = ssid.2
|
||||||
self.standardView = standard.2
|
self.standardView = standard.2
|
||||||
self.channelView = channel.2
|
self.channelView = channel.2
|
||||||
|
self.interfaceSpeedView = speed.2
|
||||||
|
|
||||||
self.detailsView = view
|
if !self.interfaceDetailsState {
|
||||||
|
self.standardView?.removeFromSuperview()
|
||||||
|
self.channelView?.removeFromSuperview()
|
||||||
|
self.interfaceSpeedView?.removeFromSuperview()
|
||||||
|
}
|
||||||
|
|
||||||
|
self.interfaceView = view
|
||||||
return view
|
return view
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -393,23 +442,27 @@ internal class Popup: PopupWrapper {
|
|||||||
self.interfaceField?.stringValue += ", \(cc)"
|
self.interfaceField?.stringValue += ", \(cc)"
|
||||||
}
|
}
|
||||||
self.interfaceField?.stringValue += ")"
|
self.interfaceField?.stringValue += ")"
|
||||||
|
self.interfaceStatusField?.stringValue = localizedString(interface.status ? "UP" : "DOWN")
|
||||||
self.macAddressField?.stringValue = interface.address
|
self.macAddressField?.stringValue = interface.address
|
||||||
|
self.interfaceSpeedField?.stringValue = "\(Int(interface.transmitRate.rounded()))baseT"
|
||||||
} else {
|
} else {
|
||||||
self.interfaceField?.stringValue = localizedString("Unknown")
|
self.interfaceField?.stringValue = localizedString("Unknown")
|
||||||
|
self.interfaceStatusField?.stringValue = localizedString("Unknown")
|
||||||
self.macAddressField?.stringValue = localizedString("Unknown")
|
self.macAddressField?.stringValue = localizedString("Unknown")
|
||||||
|
self.interfaceSpeedField?.stringValue = localizedString("Unknown")
|
||||||
}
|
}
|
||||||
|
|
||||||
if value.connectionType == .wifi {
|
if value.connectionType == .wifi {
|
||||||
if let view = self.ssidView, view.superview == nil && value.wifiDetails.ssid != nil {
|
if let view = self.ssidView, view.superview == nil && value.wifiDetails.ssid != nil {
|
||||||
self.detailsView?.addArrangedSubview(view)
|
self.interfaceView?.addArrangedSubview(view)
|
||||||
resized = true
|
resized = true
|
||||||
}
|
}
|
||||||
if let view = self.standardView, view.superview == nil && value.wifiDetails.standard != nil {
|
if self.interfaceDetailsState, let view = self.standardView, view.superview == nil && value.wifiDetails.standard != nil {
|
||||||
self.detailsView?.addArrangedSubview(view)
|
self.interfaceView?.addArrangedSubview(view)
|
||||||
resized = true
|
resized = true
|
||||||
}
|
}
|
||||||
if let view = self.channelView, view.superview == nil && value.wifiDetails.channel != nil {
|
if self.interfaceDetailsState, let view = self.channelView, view.superview == nil && value.wifiDetails.channel != nil {
|
||||||
self.detailsView?.addArrangedSubview(view)
|
self.interfaceView?.addArrangedSubview(view)
|
||||||
resized = true
|
resized = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -428,15 +481,11 @@ internal class Popup: PopupWrapper {
|
|||||||
if let v = value.wifiDetails.noise {
|
if let v = value.wifiDetails.noise {
|
||||||
noise = "\(v) dBm"
|
noise = "\(v) dBm"
|
||||||
}
|
}
|
||||||
var txRate = localizedString("Unknown")
|
|
||||||
if let v = value.wifiDetails.transmitRate {
|
|
||||||
txRate = "\(v) Mbps"
|
|
||||||
}
|
|
||||||
|
|
||||||
let number = value.wifiDetails.channelNumber ?? localizedString("Unknown")
|
let number = value.wifiDetails.channelNumber ?? localizedString("Unknown")
|
||||||
let band = value.wifiDetails.channelBand ?? localizedString("Unknown")
|
let band = value.wifiDetails.channelBand ?? localizedString("Unknown")
|
||||||
let width = value.wifiDetails.channelWidth ?? localizedString("Unknown")
|
let width = value.wifiDetails.channelWidth ?? localizedString("Unknown")
|
||||||
self.channelField?.toolTip = "RSSI: \(rssi)\nNoise: \(noise)\nChannel number: \(number)\nChannel band: \(band)\nChannel width: \(width)\nTransmit rate: \(txRate)"
|
self.channelField?.toolTip = "RSSI: \(rssi)\nNoise: \(noise)\nChannel number: \(number)\nChannel band: \(band)\nChannel width: \(width)\n"
|
||||||
} else {
|
} else {
|
||||||
if self.ssidView?.superview != nil {
|
if self.ssidView?.superview != nil {
|
||||||
self.ssidField?.stringValue = localizedString("Unavailable")
|
self.ssidField?.stringValue = localizedString("Unavailable")
|
||||||
@@ -469,7 +518,7 @@ internal class Popup: PopupWrapper {
|
|||||||
if let addr = value.raddr.v4 {
|
if let addr = value.raddr.v4 {
|
||||||
if view.superview == nil {
|
if view.superview == nil {
|
||||||
self.addressView?.addArrangedSubview(view)
|
self.addressView?.addArrangedSubview(view)
|
||||||
self.recalculateHeight()
|
resized = true
|
||||||
}
|
}
|
||||||
var ip = addr
|
var ip = addr
|
||||||
if let cc = value.raddr.countryCode, !cc.isEmpty {
|
if let cc = value.raddr.countryCode, !cc.isEmpty {
|
||||||
@@ -480,7 +529,7 @@ internal class Popup: PopupWrapper {
|
|||||||
}
|
}
|
||||||
} else if view.superview != nil {
|
} else if view.superview != nil {
|
||||||
view.removeFromSuperview()
|
view.removeFromSuperview()
|
||||||
self.recalculateHeight()
|
resized = true
|
||||||
self.publicIPv4Field?.stringValue = localizedString("Unknown")
|
self.publicIPv4Field?.stringValue = localizedString("Unknown")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -505,6 +554,31 @@ internal class Popup: PopupWrapper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.interfaceDetailsState {
|
||||||
|
if !value.dns.isEmpty {
|
||||||
|
let servers = value.dns.joined(separator: "\n")
|
||||||
|
|
||||||
|
if self.dnsServersField == nil || value.dns.count != self.dnsServersField?.stringValue.split(separator: "\n").count {
|
||||||
|
if let view = self.dnsServersView {
|
||||||
|
view.removeFromSuperview()
|
||||||
|
}
|
||||||
|
let view = popupRow(self.interfaceView, title: "\(localizedString("DNS Server")):", value: servers, multiline: true)
|
||||||
|
self.dnsServersField = view.1
|
||||||
|
self.dnsServersView = view.2
|
||||||
|
self.dnsServersField?.isSelectable = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.dnsServersField?.stringValue != servers {
|
||||||
|
self.dnsServersField?.stringValue = servers
|
||||||
|
}
|
||||||
|
|
||||||
|
resized = true
|
||||||
|
} else if let view = self.dnsServersView {
|
||||||
|
view.removeFromSuperview()
|
||||||
|
resized = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
self.statusField?.stringValue = localizedString(value.status ? "UP" : "DOWN")
|
self.statusField?.stringValue = localizedString(value.status ? "UP" : "DOWN")
|
||||||
|
|
||||||
if resized {
|
if resized {
|
||||||
@@ -706,6 +780,32 @@ internal class Popup: PopupWrapper {
|
|||||||
Store.shared.set(key: "\(self.title)_chartFixedScaleSize", value: self.chartFixedScaleSize.key)
|
Store.shared.set(key: "\(self.title)_chartFixedScaleSize", value: self.chartFixedScaleSize.key)
|
||||||
self.display()
|
self.display()
|
||||||
}
|
}
|
||||||
|
@objc private func toggleInterfaceDetails() {
|
||||||
|
self.interfaceDetailsState = !self.interfaceDetailsState
|
||||||
|
Store.shared.set(key: "\(self.title)_interfaceDetails", value: self.interfaceDetailsState)
|
||||||
|
|
||||||
|
if !self.interfaceDetailsState {
|
||||||
|
self.standardView?.removeFromSuperview()
|
||||||
|
self.channelView?.removeFromSuperview()
|
||||||
|
self.interfaceSpeedView?.removeFromSuperview()
|
||||||
|
self.dnsServersView?.removeFromSuperview()
|
||||||
|
} else {
|
||||||
|
if let view = self.standardView, view.superview == nil && self.standardField?.stringValue != localizedString("Unavailable") {
|
||||||
|
self.interfaceView?.addArrangedSubview(view)
|
||||||
|
}
|
||||||
|
if let view = self.channelView, view.superview == nil && self.channelField?.stringValue != localizedString("Unavailable") {
|
||||||
|
self.interfaceView?.addArrangedSubview(view)
|
||||||
|
}
|
||||||
|
if let view = self.interfaceSpeedView, view.superview == nil {
|
||||||
|
self.interfaceView?.addArrangedSubview(view)
|
||||||
|
}
|
||||||
|
if let view = self.dnsServersView, view.superview == nil {
|
||||||
|
self.interfaceView?.addArrangedSubview(view)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.recalculateHeight()
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: - helpers
|
// MARK: - helpers
|
||||||
|
|
||||||
|
|||||||
@@ -234,6 +234,17 @@ internal class UsageReader: Reader<Network_Usage>, CWEventDelegate {
|
|||||||
if String(cString: pointer.pointee.ifa_name) != self.interfaceID {
|
if String(cString: pointer.pointee.ifa_name) != self.interfaceID {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
self.usage.interface?.status = (pointer.pointee.ifa_flags & UInt32(IFF_UP)) != 0
|
||||||
|
|
||||||
|
if let raw = pointer.pointee.ifa_data {
|
||||||
|
let dataPtr = raw.assumingMemoryBound(to: if_data.self)
|
||||||
|
let ifData = dataPtr.pointee
|
||||||
|
let baud = UInt64(ifData.ifi_baudrate)
|
||||||
|
if baud > 0 {
|
||||||
|
self.usage.interface?.transmitRate = Double(baud) / 1_000_000.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
self.getLocalIP(pointer)
|
self.getLocalIP(pointer)
|
||||||
|
|
||||||
if let info = self.getBytesInfo(pointer) {
|
if let info = self.getBytesInfo(pointer) {
|
||||||
@@ -330,6 +341,18 @@ internal class UsageReader: Reader<Network_Usage>, CWEventDelegate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let prefs = SCPreferencesCreate(nil, "Stats" as CFString, nil), let services = SCNetworkServiceCopyAll(prefs) as? [SCNetworkService] {
|
||||||
|
for service in services {
|
||||||
|
if let interface = SCNetworkServiceGetInterface(service), let name = SCNetworkInterfaceGetBSDName(interface), name as String == self.interfaceID,
|
||||||
|
let serviceID = SCNetworkServiceGetServiceID(service) {
|
||||||
|
let key = "State:/Network/Service/\(serviceID)/DNS" as CFString
|
||||||
|
if let settings = SCDynamicStoreCopyValue(nil, key) as? [String: Any] {
|
||||||
|
self.usage.dns = settings["ServerAddresses"] as? [String] ?? []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
guard self.usage.interface != nil else { return }
|
guard self.usage.interface != nil else { return }
|
||||||
|
|
||||||
if self.usage.wifiDetails.ssid != nil && (self.usage.wifiDetails.ssid == "" || self.usage.wifiDetails.ssid == "<redacted>") {
|
if self.usage.wifiDetails.ssid != nil && (self.usage.wifiDetails.ssid == "" || self.usage.wifiDetails.ssid == "<redacted>") {
|
||||||
@@ -360,7 +383,6 @@ internal class UsageReader: Reader<Network_Usage>, CWEventDelegate {
|
|||||||
|
|
||||||
self.usage.wifiDetails.RSSI = interface.rssiValue()
|
self.usage.wifiDetails.RSSI = interface.rssiValue()
|
||||||
self.usage.wifiDetails.noise = interface.noiseMeasurement()
|
self.usage.wifiDetails.noise = interface.noiseMeasurement()
|
||||||
self.usage.wifiDetails.transmitRate = interface.transmitRate()
|
|
||||||
|
|
||||||
self.usage.wifiDetails.standard = interface.activePHYMode().description
|
self.usage.wifiDetails.standard = interface.activePHYMode().description
|
||||||
self.usage.wifiDetails.mode = interface.interfaceMode().description
|
self.usage.wifiDetails.mode = interface.interfaceMode().description
|
||||||
@@ -505,9 +527,29 @@ internal class UsageReader: Reader<Network_Usage>, CWEventDelegate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ssidDidChangeForWiFiInterface(withName interfaceName: String) {
|
public func ssidDidChangeForWiFiInterface(withName interfaceName: String) {
|
||||||
self.getWiFiDetails()
|
self.getWiFiDetails()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func isInterfaceUp(_ ifName: String) -> Bool {
|
||||||
|
var addrs: UnsafeMutablePointer<ifaddrs>? = nil
|
||||||
|
guard getifaddrs(&addrs) == 0, let first = addrs else { return false }
|
||||||
|
defer { freeifaddrs(addrs) }
|
||||||
|
|
||||||
|
var ptr = first
|
||||||
|
while true {
|
||||||
|
let name = String(cString: ptr.pointee.ifa_name)
|
||||||
|
if name == ifName {
|
||||||
|
return (ptr.pointee.ifa_flags & UInt32(IFF_UP)) != 0
|
||||||
|
}
|
||||||
|
if let next = ptr.pointee.ifa_next {
|
||||||
|
ptr = next
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ProcessReader: Reader<[Network_Process]> {
|
public class ProcessReader: Reader<[Network_Process]> {
|
||||||
|
|||||||
Reference in New Issue
Block a user