feat: refactored disk SMART details

This commit is contained in:
Serhiy Mytrovtsiy
2025-03-13 19:33:45 +01:00
parent e1d2ee8fbe
commit 24bca54fd3

View File

@@ -151,7 +151,6 @@ internal class Popup: PopupWrapper {
value.reversed().forEach { (drive: drive) in
if let view = views.first(where: { $0.name == drive.mediaName }) {
view.updateReadWrite(read: drive.activity.read, write: drive.activity.write)
view.updateReadWritten(read: drive.activity.readBytes, written: drive.activity.writeBytes)
}
}
}
@@ -281,25 +280,13 @@ internal class DiskView: NSStackView {
private var chartView: ChartView
private var barView: BarView
private var legendView: LegendView
private var readView: SpeedView?
private var writeView: SpeedView?
private var readDataView: DataView
private var writtenDataView: DataView
private var temperatureView: TemperatureView?
private var lifeView: LifeView?
private var detailsView: DetailsView
private var detailsState: Bool {
get { Store.shared.bool(key: "\(self.uuid)_details", defaultValue: false) }
set { Store.shared.set(key: "\(self.uuid)_details", value: newValue) }
}
private var readColor: NSColor {
SColor.fromString(Store.shared.string(key: "\(ModuleType.disk.stringValue)_readColor", defaultValue: SColor.secondBlue.key)).additional as! NSColor
}
private var writeColor: NSColor {
SColor.fromString(Store.shared.string(key: "\(ModuleType.disk.stringValue)_writeColor", defaultValue: SColor.secondRed.key)).additional as! NSColor
}
init(width: CGFloat, uuid: String = "", name: String = "", size: Int64 = 1, free: Int64 = 1, path: URL? = nil, smart: smart_t? = nil, resize: @escaping () -> Void) {
self.sizeCallback = resize
self.uuid = uuid
@@ -310,18 +297,10 @@ internal class DiskView: NSStackView {
self.chartView = ChartView(width: innerWidth)
self.barView = BarView(width: innerWidth, size: size, free: free)
self.legendView = LegendView(width: innerWidth, id: "\(name)_\(path?.absoluteString ?? "")", size: size, free: free)
self.readDataView = DataView(width: innerWidth, title: "\(localizedString("Total read")):")
self.writtenDataView = DataView(width: innerWidth, title: "\(localizedString("Total written")):")
if let smart {
self.temperatureView = TemperatureView(width: innerWidth, smart: smart)
self.lifeView = LifeView(width: innerWidth, smart: smart)
}
self.detailsView = DetailsView(width: innerWidth, id: "\(name)_\(path?.absoluteString ?? "")", smart: smart)
super.init(frame: NSRect(x: 0, y: 0, width: width, height: 0))
self.readView = SpeedView(width: innerWidth, title: "\(localizedString("Read")):", color: self.readColor)
self.writeView = SpeedView(width: innerWidth, title: "\(localizedString("Write")):", color: self.writeColor)
self.widthAnchor.constraint(equalToConstant: width).isActive = true
self.orientation = .vertical
self.distribution = .fillProportionally
@@ -340,6 +319,7 @@ internal class DiskView: NSStackView {
self.addArrangedSubview(self.chartView)
self.addArrangedSubview(self.barView)
self.addArrangedSubview(self.legendView)
self.addArrangedSubview(self.detailsView)
self.toggleDetails()
}
@@ -356,19 +336,13 @@ internal class DiskView: NSStackView {
self.nameView.update(free: free, read: nil, write: nil)
self.legendView.update(free: free)
self.barView.update(free: free)
self.temperatureView?.update(smart)
self.lifeView?.update(smart)
self.detailsView.update(smart: smart)
}
public func updateReadWrite(read: Int64, write: Int64) {
self.readView?.update(read)
self.writeView?.update(write)
self.nameView.update(free: nil, read: read, write: write)
self.chartView.update(read: read, write: write)
}
public func updateReadWritten(read: Int64, written: Int64) {
self.readDataView.update(read)
self.writtenDataView.update(written)
self.detailsView.update(read: read, write: write)
}
public func setChartColor(read: NSColor? = nil, write: NSColor? = nil) {
self.chartView.setColors(read: read, write: write)
@@ -379,25 +353,9 @@ internal class DiskView: NSStackView {
private func toggleDetails() {
if self.detailsState {
if let view = self.readView {
self.addArrangedSubview(view)
}
if let view = self.writeView {
self.addArrangedSubview(view)
}
self.addArrangedSubview(self.readDataView)
self.addArrangedSubview(self.writtenDataView)
if let temperatureView = self.temperatureView, let lifeView = self.lifeView {
self.addArrangedSubview(temperatureView)
self.addArrangedSubview(lifeView)
}
self.addArrangedSubview(self.detailsView)
} else {
self.readView?.removeFromSuperview()
self.writeView?.removeFromSuperview()
self.readDataView.removeFromSuperview()
self.writtenDataView.removeFromSuperview()
self.temperatureView?.removeFromSuperview()
self.lifeView?.removeFromSuperview()
self.detailsView.removeFromSuperview()
}
let h = self.arrangedSubviews.map({ $0.bounds.height + self.spacing }).reduce(0, +) - 5 + 10
@@ -636,12 +594,8 @@ internal class LegendView: NSView {
private var ready: Bool = false
private var showUsedSpace: Bool {
get {
Store.shared.bool(key: "\(self.id)_usedSpace", defaultValue: false)
}
set {
Store.shared.set(key: "\(self.id)_usedSpace", value: newValue)
}
get { Store.shared.bool(key: "\(self.id)_usedSpace", defaultValue: false) }
set { Store.shared.set(key: "\(self.id)_usedSpace", value: newValue) }
}
private var legendField: NSTextField? = nil
@@ -757,173 +711,128 @@ internal class LegendView: NSView {
}
}
internal class TemperatureView: NSStackView {
private var initialized: Bool = false
private let field: NSTextField = TextView()
internal class DetailsView: NSStackView {
private var smartHeight: CGFloat {
get { (22*6) + Constants.Popup.separatorHeight }
}
init(width: CGFloat, smart: smart_t) {
super.init(frame: CGRect(x: 0, y: 0, width: width, height: 16))
private var readSpeedValueField: ValueField?
private var writeSpeedValueField: ValueField?
private var totalReadValueField: ValueField?
private var totalWrittenValueField: ValueField?
private var temperatureValueField: ValueField?
private var healthValueField: ValueField?
private var powerCyclesValueField: ValueField?
private var powerOnHoursValueField: ValueField?
private var readColor: NSColor {
SColor.fromString(Store.shared.string(key: "\(ModuleType.disk.stringValue)_readColor", defaultValue: SColor.secondBlue.key)).additional as! NSColor
}
private var writeColor: NSColor {
SColor.fromString(Store.shared.string(key: "\(ModuleType.disk.stringValue)_writeColor", defaultValue: SColor.secondRed.key)).additional as! NSColor
}
public init(width: CGFloat, id: String, smart: smart_t? = nil) {
super.init(frame: CGRect(x: 0, y: 0, width: width, height: 0))
self.orientation = .horizontal
self.orientation = .vertical
self.distribution = .fillProportionally
self.spacing = 0
let title = TextView()
title.font = NSFont.systemFont(ofSize: 11, weight: .light)
title.stringValue = "\(localizedString("Temperature")):"
title.cell?.truncatesLastVisibleLine = true
self.addArrangedSubview(self.initSpeed())
self.addArrangedSubview(self.initSmart())
self.field.font = NSFont.systemFont(ofSize: 11, weight: .regular)
self.field.alignment = .right
self.field.stringValue = "\(temperature(Double(smart.temperature)))"
self.addArrangedSubview(title)
self.addArrangedSubview(NSView())
self.addArrangedSubview(self.field)
self.widthAnchor.constraint(equalToConstant: self.frame.width).isActive = true
self.heightAnchor.constraint(equalToConstant: self.frame.height).isActive = true
self.recalculateHeight()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
public func update(_ newValue: smart_t?) {
if (self.window?.isVisible ?? false) || !self.initialized {
if let newValue {
self.field.stringValue = "\(temperature(Double(newValue.temperature)))"
private func recalculateHeight() {
var h: CGFloat = 0
self.arrangedSubviews.forEach { v in
if let v = v as? NSStackView {
h += v.arrangedSubviews.map({ $0.bounds.height }).reduce(0, +)
} else {
self.field.stringValue = "-"
h += v.bounds.height
}
self.initialized = true
}
if self.frame.size.height != h {
self.setFrameSize(NSSize(width: self.frame.width, height: h))
}
}
}
internal class LifeView: NSStackView {
private var initialized: Bool = false
private let field: NSTextField = TextView()
init(width: CGFloat, smart: smart_t) {
super.init(frame: CGRect(x: 0, y: 0, width: width, height: 16))
private func initSpeed() -> NSView {
let view: NSView = NSView(frame: NSRect(x: 0, y: 0, width: self.frame.width, height: 44))
view.widthAnchor.constraint(equalToConstant: view.bounds.width).isActive = true
view.heightAnchor.constraint(equalToConstant: view.bounds.height).isActive = true
let container: NSStackView = NSStackView(frame: NSRect(x: 0, y: 0, width: view.frame.width, height: view.frame.height))
container.orientation = .vertical
container.spacing = 0
self.orientation = .horizontal
self.spacing = 0
(_, _, self.readSpeedValueField) = popupWithColorRow(container, color: self.readColor, title: "\(localizedString("Read")):", value: "0 KB/s")
(_, _, self.writeSpeedValueField) = popupWithColorRow(container, color: self.writeColor, title: "\(localizedString("Write")):", value: "0 KB/s")
let title = TextView()
title.font = NSFont.systemFont(ofSize: 11, weight: .light)
title.stringValue = "\(localizedString("Health")):"
title.cell?.truncatesLastVisibleLine = true
self.readSpeedValueField?.font = NSFont.systemFont(ofSize: 11, weight: .regular)
self.writeSpeedValueField?.font = NSFont.systemFont(ofSize: 11, weight: .regular)
self.field.font = NSFont.systemFont(ofSize: 11, weight: .regular)
self.field.alignment = .right
self.field.stringValue = "\(smart.life)%"
view.addSubview(container)
self.addArrangedSubview(title)
self.addArrangedSubview(NSView())
self.addArrangedSubview(self.field)
self.widthAnchor.constraint(equalToConstant: self.frame.width).isActive = true
self.heightAnchor.constraint(equalToConstant: self.frame.height).isActive = true
return view
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
private func initSmart() -> NSView {
let view: NSView = NSView(frame: NSRect(x: 0, y: 0, width: self.frame.width, height: self.smartHeight))
view.widthAnchor.constraint(equalToConstant: view.bounds.width).isActive = true
view.heightAnchor.constraint(equalToConstant: view.bounds.height).isActive = true
let separator = separatorView(localizedString("SMART"), origin: NSPoint(x: 0, y: self.smartHeight-Constants.Popup.separatorHeight), width: self.frame.width)
let container: NSStackView = NSStackView(frame: NSRect(x: 0, y: 0, width: view.frame.width, height: separator.frame.origin.y))
container.orientation = .vertical
container.spacing = 0
self.totalReadValueField = popupRow(container, title: "\(localizedString("Total read")):", value: "0 KB").1
self.totalWrittenValueField = popupRow(container, title: "\(localizedString("Total written")):", value: "0 KB").1
self.temperatureValueField = popupRow(container, title: "\(localizedString("Temperature")):", value: "\(temperature(0))").1
self.healthValueField = popupRow(container, title: "\(localizedString("Health")):", value: "0%").1
self.powerCyclesValueField = popupRow(container, title: "\(localizedString("Power cycles")):", value: "0").1
self.powerOnHoursValueField = popupRow(container, title: "\(localizedString("Power on hours")):", value: "0").1
self.totalReadValueField?.font = NSFont.systemFont(ofSize: 11, weight: .regular)
self.totalWrittenValueField?.font = NSFont.systemFont(ofSize: 11, weight: .regular)
self.temperatureValueField?.font = NSFont.systemFont(ofSize: 11, weight: .regular)
self.healthValueField?.font = NSFont.systemFont(ofSize: 11, weight: .regular)
self.powerCyclesValueField?.font = NSFont.systemFont(ofSize: 11, weight: .regular)
self.powerOnHoursValueField?.font = NSFont.systemFont(ofSize: 11, weight: .regular)
view.addSubview(separator)
view.addSubview(container)
return view
}
public func update(_ newValue: smart_t?) {
if (self.window?.isVisible ?? false) || !self.initialized {
if let newValue {
self.field.stringValue = "\(newValue.life)%"
} else {
self.field.stringValue = "-"
}
self.initialized = true
public func update(read: Int64?, write: Int64?) {
guard self.window?.isVisible ?? false else { return }
if let read = read {
self.readSpeedValueField?.stringValue = Units(bytes: read).getReadableSpeed()
}
if let write = write {
self.writeSpeedValueField?.stringValue = Units(bytes: write).getReadableSpeed()
}
}
}
internal class DataView: NSStackView {
private var initialized: Bool = false
private let field: NSTextField = TextView()
init(width: CGFloat, title: String) {
super.init(frame: CGRect(x: 0, y: 0, width: width, height: 16))
public func update(smart: smart_t?) {
guard self.window?.isVisible ?? false, let smart else { return }
self.orientation = .horizontal
self.spacing = 0
self.totalReadValueField?.stringValue = Units(bytes: smart.totalRead).getReadableMemory(style: .decimal)
self.totalWrittenValueField?.stringValue = Units(bytes: smart.totalWritten).getReadableMemory(style: .decimal)
let titleField = TextView()
titleField.font = NSFont.systemFont(ofSize: 11, weight: .light)
titleField.stringValue = title
titleField.cell?.truncatesLastVisibleLine = true
self.temperatureValueField?.stringValue = "\(temperature(Double(smart.temperature)))"
self.healthValueField?.stringValue = "\(smart.life)%"
self.field.font = NSFont.systemFont(ofSize: 11, weight: .regular)
self.field.alignment = .right
self.field.stringValue = "0"
self.addArrangedSubview(titleField)
self.addArrangedSubview(NSView())
self.addArrangedSubview(self.field)
self.widthAnchor.constraint(equalToConstant: self.frame.width).isActive = true
self.heightAnchor.constraint(equalToConstant: self.frame.height).isActive = true
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
public func update(_ newValue: Int64) {
if (self.window?.isVisible ?? false) || !self.initialized {
self.field.stringValue = Units(bytes: newValue).getReadableMemory()
self.initialized = true
}
}
}
internal class SpeedView: NSStackView {
private var initialized: Bool = false
private let field: NSTextField = TextView()
init(width: CGFloat, title: String, color: NSColor) {
super.init(frame: CGRect(x: 0, y: 0, width: width, height: 16))
self.orientation = .horizontal
self.spacing = 0
let colorView: NSView = NSView(frame: NSRect(x: 0, y: 0, width: 12, height: 12))
colorView.widthAnchor.constraint(equalToConstant: 12).isActive = true
colorView.heightAnchor.constraint(equalToConstant: 12).isActive = true
colorView.wantsLayer = true
colorView.layer?.backgroundColor = color.cgColor
colorView.layer?.cornerRadius = 2
let titleField = TextView()
titleField.font = NSFont.systemFont(ofSize: 11, weight: .light)
titleField.stringValue = title
titleField.cell?.truncatesLastVisibleLine = true
self.field.font = NSFont.systemFont(ofSize: 11, weight: .regular)
self.field.alignment = .right
self.field.stringValue = "0"
self.addArrangedSubview(colorView)
self.addArrangedSubview(titleField)
self.addArrangedSubview(NSView())
self.addArrangedSubview(self.field)
self.widthAnchor.constraint(equalToConstant: self.frame.width).isActive = true
self.heightAnchor.constraint(equalToConstant: self.frame.height).isActive = true
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
public func update(_ newValue: Int64) {
if (self.window?.isVisible ?? false) || !self.initialized {
self.field.stringValue = Units(bytes: newValue).getReadableSpeed()
self.initialized = true
}
self.powerCyclesValueField?.stringValue = "\(smart.powerCycles)"
self.powerOnHoursValueField?.stringValue = "\(smart.powerOnHours)"
}
}