feat: initialized battery details widget (#1293)

This commit is contained in:
Serhiy Mytrovtsiy
2023-03-03 19:52:10 +01:00
parent 75e9bcff57
commit 78ca5d5793
6 changed files with 187 additions and 0 deletions

View File

@@ -35,6 +35,7 @@ identifier_name:
- AppleSiliconSensorsList
- FanValues
- CombinedModulesSpacings
- BatteryInfo
line_length: 200

View File

@@ -457,3 +457,165 @@ public class BatteryWidget: WidgetWrapper {
self.display()
}
}
public class BatteryDetailsWidget: WidgetWrapper {
private var mode: String = "percentage"
private var timeFormat: String = "short"
private var percentage: Double? = nil
private var time: Int = 0
public init(title: String, config: NSDictionary?, preview: Bool = false) {
super.init(.batteryDetails, title: title, frame: CGRect(
x: Constants.Widget.margin.x,
y: Constants.Widget.margin.y,
width: 20 + (2*Constants.Widget.margin.x),
height: Constants.Widget.height - (2*Constants.Widget.margin.y)
))
self.canDrawConcurrently = true
if preview {
self.percentage = 0.72
self.time = 415
self.mode = "percentageAndTime"
} else {
self.mode = Store.shared.string(key: "\(self.title)_\(self.type.rawValue)_mode", defaultValue: self.mode)
self.timeFormat = Store.shared.string(key: "\(self.title)_timeFormat", defaultValue: self.timeFormat)
}
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
public override func draw(_ dirtyRect: NSRect) {
super.draw(dirtyRect)
var width: CGFloat = Constants.Widget.margin.x*2
let x: CGFloat = Constants.Widget.margin.x
let isShortTimeFormat: Bool = self.timeFormat == "short"
switch self.mode {
case "percentage":
var value = "n/a"
if let percentage = self.percentage {
value = "\(Int((percentage.rounded(toPlaces: 2)) * 100))%"
}
width = self.drawOneRow(value: value, x: x).rounded(.up)
case "time":
width = self.drawOneRow(
value: Double(self.time*60).printSecondsToHoursMinutesSeconds(short: isShortTimeFormat),
x: x
).rounded(.up)
case "percentageAndTime":
var value = "n/a"
if let percentage = self.percentage {
value = "\(Int((percentage.rounded(toPlaces: 2)) * 100))%"
}
width = self.drawTwoRows(
first: value,
second: Double(self.time*60).printSecondsToHoursMinutesSeconds(short: isShortTimeFormat),
x: x
).rounded(.up)
case "timeAndPercentage":
var value = "n/a"
if let percentage = self.percentage {
value = "\(Int((percentage.rounded(toPlaces: 2)) * 100))%"
}
width = self.drawTwoRows(
first: Double(self.time*60).printSecondsToHoursMinutesSeconds(short: isShortTimeFormat),
second: value,
x: x
).rounded(.up)
default: break
}
self.setWidth(width)
}
private func drawOneRow(value: String, x: CGFloat) -> CGFloat {
let attributes = [
NSAttributedString.Key.font: NSFont.systemFont(ofSize: 12, weight: .regular),
NSAttributedString.Key.foregroundColor: isDarkMode ? NSColor.white : NSColor.textColor,
NSAttributedString.Key.paragraphStyle: NSMutableParagraphStyle()
]
let rowWidth = value.widthOfString(usingFont: .systemFont(ofSize: 12, weight: .regular))
let rect = CGRect(x: x, y: (Constants.Widget.height-12)/2, width: rowWidth, height: 12)
let str = NSAttributedString.init(string: value, attributes: attributes)
str.draw(with: rect)
return rowWidth
}
private func drawTwoRows(first: String, second: String, x: CGFloat) -> CGFloat {
let style = NSMutableParagraphStyle()
style.alignment = .center
let attributes = [
NSAttributedString.Key.font: NSFont.systemFont(ofSize: 9, weight: .regular),
NSAttributedString.Key.foregroundColor: NSColor.textColor,
NSAttributedString.Key.paragraphStyle: style
]
let rowHeight: CGFloat = self.frame.height / 2
let rowWidth = max(
first.widthOfString(usingFont: .systemFont(ofSize: 9, weight: .regular)),
second.widthOfString(usingFont: .systemFont(ofSize: 9, weight: .regular))
)
var str = NSAttributedString.init(string: first, attributes: attributes)
str.draw(with: CGRect(x: x, y: rowHeight+1, width: rowWidth, height: rowHeight))
str = NSAttributedString.init(string: second, attributes: attributes)
str.draw(with: CGRect(x: x, y: 1, width: rowWidth, height: rowHeight))
return rowWidth
}
public func setValue(percentage: Double? = nil, time: Int? = nil) {
var updated: Bool = false
let timeFormat: String = Store.shared.string(key: "\(self.title)_timeFormat", defaultValue: self.timeFormat)
if self.percentage != percentage {
self.percentage = percentage
updated = true
}
if let time = time, self.time != time {
self.time = time
updated = true
}
if self.timeFormat != timeFormat {
self.timeFormat = timeFormat
updated = true
}
if updated {
DispatchQueue.main.async(execute: {
self.display()
})
}
}
// MARK: - Settings
public override func settings() -> NSView {
let view = SettingsContainerView()
view.addArrangedSubview(selectSettingsRow(
title: localizedString("Mode"),
action: #selector(self.toggleMode),
items: BatteryInfo,
selected: self.mode
))
return view
}
@objc private func toggleMode(_ sender: NSMenuItem) {
guard let key = sender.representedObject as? String else { return }
self.mode = key
Store.shared.set(key: "\(self.title)_\(self.type.rawValue)_mode", value: key)
self.display()
}
}

View File

@@ -20,6 +20,7 @@ public enum widget_t: String {
case networkChart = "network_chart"
case speed = "speed"
case battery = "battery"
case batteryDetails = "battery_details"
case sensors = "sensors"
case memory = "memory"
case label = "label"
@@ -57,6 +58,9 @@ public enum widget_t: String {
case .battery:
preview = BatteryWidget(title: module, config: widgetConfig, preview: true)
item = BatteryWidget(title: module, config: widgetConfig, preview: false)
case .batteryDetails:
preview = BatteryDetailsWidget(title: module, config: widgetConfig, preview: true)
item = BatteryDetailsWidget(title: module, config: widgetConfig, preview: false)
case .sensors:
preview = SensorsWidget(title: module, config: widgetConfig, preview: true)
item = SensorsWidget(title: module, config: widgetConfig, preview: false)
@@ -128,6 +132,7 @@ public enum widget_t: String {
case .networkChart: return localizedString("Network chart widget")
case .speed: return localizedString("Speed widget")
case .battery: return localizedString("Battery widget")
case .batteryDetails: return localizedString("Battery details widget")
case .sensors: return localizedString("Text widget")
case .memory: return localizedString("Memory widget")
case .label: return localizedString("Label widget")

View File

@@ -101,6 +101,13 @@ public let BatteryAdditionals: [KeyValue_t] = [
KeyValue_t(key: "timeAndPercentage", value: "Time and percentage")
]
public let BatteryInfo: [KeyValue_t] = [
KeyValue_t(key: "percentage", value: "Percentage"),
KeyValue_t(key: "time", value: "Time"),
KeyValue_t(key: "percentageAndTime", value: "Percentage and time"),
KeyValue_t(key: "timeAndPercentage", value: "Time and percentage")
]
public let ShortLong: [KeyValue_t] = [
KeyValue_t(key: "short", value: "Short"),
KeyValue_t(key: "long", value: "Long")

View File

@@ -69,6 +69,13 @@
<key>Order</key>
<integer>3</integer>
</dict>
<key>battery_details</key>
<dict>
<key>Default</key>
<false/>
<key>Order</key>
<integer>4</integer>
</dict>
</dict>
</dict>
</plist>

View File

@@ -141,6 +141,11 @@ public class Battery: Module {
optimizedCharging: value.optimizedChargingEngaged,
time: value.timeToEmpty == 0 && value.timeToCharge != 0 ? value.timeToCharge : value.timeToEmpty
)
case let widget as BatteryDetailsWidget:
widget.setValue(
percentage: value.level,
time: value.timeToEmpty == 0 && value.timeToCharge != 0 ? value.timeToCharge : value.timeToEmpty
)
default: break
}
}