feat: added Text widget to the Disk module that allows to show more details in the menu bar (#2532)

This commit is contained in:
Serhiy Mytrovtsiy
2025-05-16 21:42:18 +02:00
parent 49f11b7195
commit 446f17e195
3 changed files with 101 additions and 1 deletions

View File

@@ -125,6 +125,13 @@
<string>system</string>
</array>
</dict>
<key>text</key>
<dict>
<key>Default</key>
<false/>
<key>Order</key>
<integer>7</integer>
</dict>
</dict>
<key>Settings</key>
<dict>

View File

@@ -217,6 +217,10 @@ public class Disk: Module {
private var selectedDisk: String = ""
private var textValue: String {
Store.shared.string(key: "\(self.name)_textWidgetValue", defaultValue: "$capacity.free/$capacity.total")
}
public init() {
super.init(
moduleType: .disk,
@@ -290,6 +294,37 @@ public class Disk: Module {
widget.setValue([
circle_segment(value: d.percentage, color: NSColor.systemBlue)
])
case let widget as TextWidget:
var text = "\(self.textValue)"
let pairs = TextWidget.parseText(text)
pairs.forEach { pair in
var replacement: String? = nil
switch pair.key {
case "$capacity":
switch pair.value {
case "total": replacement = DiskSize(d.size).getReadableMemory()
case "used": replacement = DiskSize(d.size - d.free).getReadableMemory()
case "free": replacement = DiskSize(d.free).getReadableMemory()
default: return
}
case "$percentage":
var percentage: Int
switch pair.value {
case "used": percentage = Int((Double(d.size - d.free) / Double(d.size)) * 100)
case "free": percentage = Int((Double(d.free) / Double(d.size)) * 100)
default: return
}
replacement = "\(percentage < 0 ? 0 : percentage)%"
default: return
}
if let replacement {
let key = pair.value.isEmpty ? pair.key : "\(pair.key).\(pair.value)"
text = text.replacingOccurrences(of: key, with: replacement)
}
}
widget.setValue(text)
default: break
}
}

View File

@@ -12,7 +12,26 @@
import Cocoa
import Kit
internal class Settings: NSStackView, Settings_v {
var textWidgetHelp = """
<h2>Description</h2>
You can use a combination of any of the variables.
<h3>Examples:</h3>
<ul>
<li>$capacity.free/$capacity.total</li>
<li>Free: $capacity.free ($percentage.used)</li>
<li>Used: $capacity.used ($percentage.used)</li>
</ul>
<h2>Available variables</h2>
<ul>
<li><b>$capacity.free</b>: <small>Free space of active drive.</small></li>
<li><b>$capacity.used</b>: <small>Used space of active drive.</small></li>
<li><b>$capacity.total</b>: <small>Total space of active drive.</small></li>
<li><b>$percentage.free</b>: <small>Free space (percentage) of active drive.</small></li>
<li><b>$percentage.used</b>: <small>Used space (percentage) of active drive.</small></li>
</ul>
"""
internal class Settings: NSStackView, Settings_v, NSTextFieldDelegate {
private let title: String
private var removableState: Bool = false
@@ -20,6 +39,7 @@ internal class Settings: NSStackView, Settings_v {
private var numberOfProcesses: Int = 5
private var baseValue: String = "byte"
private var SMARTState: Bool = true
private var textValue: String = "$capacity.free/$capacity.total"
public var selectedDiskHandler: (String) -> Void = {_ in }
public var callback: (() -> Void) = {}
@@ -31,6 +51,8 @@ internal class Settings: NSStackView, Settings_v {
private var list: [String] = []
private let textWidgetHelpPanel: HelpHUD = HelpHUD(textWidgetHelp)
public init(_ module: ModuleType) {
self.title = module.stringValue
@@ -40,6 +62,7 @@ internal class Settings: NSStackView, Settings_v {
self.numberOfProcesses = Store.shared.int(key: "\(self.title)_processes", defaultValue: self.numberOfProcesses)
self.baseValue = Store.shared.string(key: "\(self.title)_base", defaultValue: self.baseValue)
self.SMARTState = Store.shared.bool(key: "\(self.title)_SMART", defaultValue: self.SMARTState)
self.textValue = Store.shared.string(key: "\(self.title)_textWidgetValue", defaultValue: self.textValue)
super.init(frame: NSRect.zero)
@@ -99,6 +122,15 @@ internal class Settings: NSStackView, Settings_v {
state: self.SMARTState
))
]))
if widgets.contains(where: { $0 == .text }) {
let textField = self.inputField(id: "text", value: self.textValue, placeholder: localizedString("This will be visible in the text widget"))
self.addArrangedSubview(PreferencesSection([
PreferencesRow(localizedString("Text widget value"), component: textField) { [weak self] in
self?.textWidgetHelpPanel.show()
}
]))
}
}
internal func setList(_ list: Disks) {
@@ -118,6 +150,23 @@ internal class Settings: NSStackView, Settings_v {
})
}
private func inputField(id: String, value: String, placeholder: String) -> NSView {
let field: NSTextField = NSTextField()
field.identifier = NSUserInterfaceItemIdentifier(id)
field.widthAnchor.constraint(equalToConstant: 250).isActive = true
field.font = NSFont.systemFont(ofSize: 12, weight: .regular)
field.textColor = .textColor
field.isEditable = true
field.isSelectable = true
field.usesSingleLineMode = true
field.maximumNumberOfLines = 1
field.focusRingType = .none
field.stringValue = value
field.delegate = self
field.placeholderString = placeholder
return field
}
@objc private func changeNumberOfProcesses(_ sender: NSMenuItem) {
if let value = Int(sender.title) {
self.numberOfProcesses = value
@@ -156,4 +205,13 @@ internal class Settings: NSStackView, Settings_v {
Store.shared.set(key: "\(self.title)_SMART", value: self.SMARTState)
self.callback()
}
func controlTextDidChange(_ notification: Notification) {
if let field = notification.object as? NSTextField {
if field.identifier == NSUserInterfaceItemIdentifier("text") {
self.textValue = field.stringValue
Store.shared.set(key: "\(self.title)_textWidgetValue", value: self.textValue)
}
}
}
}