- fix Battery module settings visibility

- add option to select the battery time: short (01:25) and long (1h 25min) (#129)
- add missing translations
This commit is contained in:
Serhiy Mytrovtsiy
2020-10-31 21:13:31 +01:00
parent 10dedf6fb1
commit c39b91c0b8
16 changed files with 161 additions and 57 deletions

View File

@@ -12,18 +12,9 @@
import Cocoa
import StatsKit
public enum battery_additional_t: String {
case none = "None"
case separator_1 = "separator_1"
case percentage = "Percentage"
case time = "Time"
case percentageAndTime = "Percentage and time"
case timeAndPercentage = "Time and percentage"
}
extension battery_additional_t: CaseIterable {}
public class BatterykWidget: Widget {
private var additional: battery_additional_t = .none
private var additional: String = "none"
private var timeFormat: String = "short"
private var iconState: Bool = true
private var colorState: Bool = false
@@ -44,14 +35,15 @@ public class BatterykWidget: Widget {
self.canDrawConcurrently = true
if self.store != nil {
self.additional = battery_additional_t(rawValue: store!.pointee.string(key: "\(self.title)_\(self.type.rawValue)_additional", defaultValue: self.additional.rawValue)) ?? self.additional
self.additional = store!.pointee.string(key: "\(self.title)_\(self.type.rawValue)_additional", defaultValue: self.additional)
self.timeFormat = store!.pointee.string(key: "\(self.title)_timeFormat", defaultValue: self.timeFormat)
self.iconState = store!.pointee.bool(key: "\(self.title)_\(self.type.rawValue)_icon", defaultValue: self.iconState)
self.colorState = store!.pointee.bool(key: "\(self.title)_\(self.type.rawValue)_color", defaultValue: self.colorState)
}
if self.preview {
self.percentage = 0.72
self.additional = .none
self.additional = "none"
self.iconState = true
self.colorState = false
}
@@ -66,33 +58,34 @@ public class BatterykWidget: Widget {
var width: CGFloat = 30
var x: CGFloat = Constants.Widget.margin+1
let isShortTimeFormat: Bool = self.timeFormat == "short"
switch self.additional {
case .percentage:
case "percentage":
let rowWidth = self.drawOneRow(
value: "\(Int((self.percentage.rounded(toPlaces: 2)) * 100))%",
x: x
).rounded(.up)
width += rowWidth + Constants.Widget.margin
x += rowWidth + Constants.Widget.margin
case .time:
case "time":
let rowWidth = self.drawOneRow(
value: Double(self.time*60).printSecondsToHoursMinutesSeconds(),
value: Double(self.time*60).printSecondsToHoursMinutesSeconds(short: isShortTimeFormat),
x: x
).rounded(.up)
width += rowWidth + Constants.Widget.margin
x += rowWidth + Constants.Widget.margin
case .percentageAndTime:
case "percentageAndTime":
let rowWidth = self.drawTwoRows(
first: "\(Int((self.percentage.rounded(toPlaces: 2)) * 100))%",
second: Double(self.time*60).printSecondsToHoursMinutesSeconds(),
second: Double(self.time*60).printSecondsToHoursMinutesSeconds(short: isShortTimeFormat),
x: x
).rounded(.up)
width += rowWidth + Constants.Widget.margin
x += rowWidth + Constants.Widget.margin
case .timeAndPercentage:
case "timeAndPercentage":
let rowWidth = self.drawTwoRows(
first: Double(self.time*60).printSecondsToHoursMinutesSeconds(),
first: Double(self.time*60).printSecondsToHoursMinutesSeconds(short: isShortTimeFormat),
second: "\(Int((self.percentage.rounded(toPlaces: 2)) * 100))%",
x: x
).rounded(.up)
@@ -220,6 +213,7 @@ public class BatterykWidget: Widget {
public func setValue(percentage: Double, ACStatus: Bool, isCharging: Bool, time: Int) {
var updated: Bool = false
let timeFormat: String = store!.pointee.string(key: "\(self.title)_timeFormat", defaultValue: self.timeFormat)
if self.percentage != percentage {
self.percentage = percentage
@@ -237,6 +231,10 @@ public class BatterykWidget: Widget {
self.time = time
updated = true
}
if self.timeFormat != timeFormat {
self.timeFormat = timeFormat
updated = true
}
if updated {
DispatchQueue.main.async(execute: {
@@ -252,12 +250,12 @@ public class BatterykWidget: Widget {
let view: NSView = NSView(frame: NSRect(x: Constants.Settings.margin, y: Constants.Settings.margin, width: superview.frame.width - (Constants.Settings.margin*2), height: superview.frame.height - (Constants.Settings.margin*2)))
view.addSubview(SelectTitleRow(
frame: NSRect(x: 0, y: rowHeight + Constants.Settings.margin, width: view.frame.width, height: rowHeight),
view.addSubview(SelectRow(
frame: NSRect(x: 0, y: (rowHeight + Constants.Settings.margin) * 1, width: view.frame.width, height: rowHeight),
title: LocalizedString("Additional information"),
action: #selector(toggleAdditional),
items: battery_additional_t.allCases.map{ return $0.rawValue },
selected: self.additional.rawValue
items: BatteryAdditionals,
selected: self.additional
))
view.addSubview(ToggleTitleRow(
@@ -271,9 +269,11 @@ public class BatterykWidget: Widget {
}
@objc private func toggleAdditional(_ sender: NSMenuItem) {
let newValue: battery_additional_t = battery_additional_t(rawValue: sender.title) ?? .none
self.additional = newValue
self.store?.pointee.set(key: "\(self.title)_\(self.type.rawValue)_additional", value: self.additional.rawValue)
guard let key = sender.representedObject as? String else {
return
}
self.additional = key
self.store?.pointee.set(key: "\(self.title)_\(self.type.rawValue)_additional", value: key)
self.display()
}

View File

@@ -64,6 +64,11 @@ public class Battery: Module {
self.usageReader = UsageReader()
self.processReader = ProcessReader(self.config.name, store: store)
self.settingsView.callback = {
DispatchQueue.global(qos: .background).async {
self.usageReader?.read()
}
}
self.settingsView.callbackWhenUpdateNumberOfProcesses = {
self.popupView.numberOfProcessesUpdated()
DispatchQueue.global(qos: .background).async {

View File

@@ -57,6 +57,11 @@ internal class Popup: NSView, Popup_p {
return (self.processHeight*CGFloat(self.numberOfProcesses))+Constants.Popup.separatorHeight
}
}
private var timeFormat: String {
get {
return self.store.pointee.string(key: "\(self.title)_timeFormat", defaultValue: "short")
}
}
public var sizeCallback: ((NSSize) -> Void)? = nil
@@ -219,12 +224,12 @@ internal class Popup: NSView, Popup_p {
if value.powerSource == "Battery Power" {
self.timeLabelField?.stringValue = "\(LocalizedString("Time to discharge")):"
if value.timeToEmpty != -1 && value.timeToEmpty != 0 {
self.timeField?.stringValue = Double(value.timeToEmpty*60).printSecondsToHoursMinutesSeconds()
self.timeField?.stringValue = Double(value.timeToEmpty*60).printSecondsToHoursMinutesSeconds(short: self.timeFormat == "short")
}
} else {
self.timeLabelField?.stringValue = "\(LocalizedString("Time to charge")):"
if value.timeToCharge != -1 && value.timeToCharge != 0 {
self.timeField?.stringValue = Double(value.timeToCharge*60).printSecondsToHoursMinutesSeconds()
self.timeField?.stringValue = Double(value.timeToCharge*60).printSecondsToHoursMinutesSeconds(short: self.timeFormat == "short")
}
}

View File

@@ -29,11 +29,13 @@ internal class Settings: NSView, Settings_v {
return self.store.pointee.string(key: "\(self.title)_lowLevelNotification", defaultValue: "0.15")
}
}
private var timeFormat: String = "short"
public init(_ title: String, store: UnsafePointer<Store>) {
self.title = title
self.store = store
self.numberOfProcesses = store.pointee.int(key: "\(self.title)_processes", defaultValue: self.numberOfProcesses)
self.timeFormat = store.pointee.string(key: "\(self.title)_timeFormat", defaultValue: self.timeFormat)
super.init(frame: CGRect(
x: 0,
@@ -53,6 +55,8 @@ internal class Settings: NSView, Settings_v {
self.subviews.forEach{ $0.removeFromSuperview() }
let rowHeight: CGFloat = 30
let num: CGFloat = widget == .battery ? 3 : 2
let height: CGFloat = ((rowHeight + Constants.Settings.margin) * num) + Constants.Settings.margin
let levels: [String] = self.levelsList.map { (v: String) -> String in
if let level = Double(v) {
@@ -63,8 +67,8 @@ internal class Settings: NSView, Settings_v {
self.addSubview(SelectTitleRow(
frame: NSRect(
x:Constants.Settings.margin,
y: Constants.Settings.margin + (rowHeight + Constants.Settings.margin) * 1,
x: Constants.Settings.margin,
y: Constants.Settings.margin + (rowHeight + Constants.Settings.margin) * (num-1),
width: self.frame.width - (Constants.Settings.margin*2),
height: rowHeight
),
@@ -76,8 +80,8 @@ internal class Settings: NSView, Settings_v {
self.addSubview(SelectTitleRow(
frame: NSRect(
x:Constants.Settings.margin,
y: Constants.Settings.margin + (rowHeight + Constants.Settings.margin) * 0,
x: Constants.Settings.margin,
y: Constants.Settings.margin + (rowHeight + Constants.Settings.margin) * (num-2),
width: self.frame.width - (Constants.Settings.margin*2),
height: rowHeight
),
@@ -87,7 +91,22 @@ internal class Settings: NSView, Settings_v {
selected: "\(self.numberOfProcesses)"
))
self.setFrameSize(NSSize(width: self.frame.width, height: 30 + (Constants.Settings.margin*2)))
if widget == .battery {
self.addSubview(SelectRow(
frame: NSRect(
x: Constants.Settings.margin,
y: Constants.Settings.margin + (rowHeight + Constants.Settings.margin) * 0,
width: self.frame.width - (Constants.Settings.margin*2),
height: rowHeight
),
title: LocalizedString("Time format"),
action: #selector(toggleTimeFormat),
items: ShortLong,
selected: self.timeFormat
))
}
self.setFrameSize(NSSize(width: self.frame.width, height: height))
}
@objc private func changeUpdateInterval(_ sender: NSMenuItem) {
@@ -105,4 +124,13 @@ internal class Settings: NSView, Settings_v {
self.callbackWhenUpdateNumberOfProcesses()
}
}
@objc private func toggleTimeFormat(_ sender: NSMenuItem) {
guard let key = sender.representedObject as? String else {
return
}
self.timeFormat = key
self.store.pointee.set(key: "\(self.title)_timeFormat", value: key)
self.callback()
}
}

View File

@@ -28,6 +28,8 @@
"Dots" = "Punkte";
"Arrows" = "Pfeile";
"Characters" = "Briefe";
"Short" = "Kurz";
"Long" = "Lange";
// Alerts
"New version available" = "Neue Version verfügbar";
@@ -152,3 +154,7 @@
"Low level notification" = "Batterie Ladezustand Benachrichtigung";
"Low battery" = "Akku schwach";
"Battery remaining" = "%0% verbleiben";
"Percentage" = "Prozentsatz";
"Percentage and time" = "Prozentsatz und Zeit";
"Time and percentage" = "Zeit und Prozentsatz";
"Time format" = "Zeitformat";

View File

@@ -28,6 +28,8 @@
"Dots" = "Dots";
"Arrows" = "Arrows";
"Characters" = "Character";
"Short" = "Short";
"Long" = "Long";
// Alerts
"New version available" = "New version available";
@@ -152,3 +154,7 @@
"Low level notification" = "Low level notification";
"Low battery" = "Low battery";
"Battery remaining" = "%0% remaining";
"Percentage" = "Percentage";
"Percentage and time" = "Percentage and time";
"Time and percentage" = "Time and percentage";
"Time format" = "Time format";

View File

@@ -28,6 +28,8 @@
"Dots" = "Puntos";
"Arrows" = "Flechas";
"Characters" = "Letras";
"Short" = "Corto";
"Long" = "Largo";
// Alerts
"New version available" = "Nueva versión disponible";
@@ -149,3 +151,7 @@
"Low level notification" = "Notificación de nivel bajo";
"Low battery" = "Batería baja";
"Battery remaining" = "%0% restante";
"Percentage" = "Porcentaje";
"Percentage and time" = "Porcentaje y tiempo";
"Time and percentage" = "Tiempo y porcentaje";
"Time format" = "Formato de tiempo";

View File

@@ -28,6 +28,8 @@
"Dots" = "도트";
"Arrows" = "화살";
"Characters" = "편지";
"Short" = "짧은";
"Long" = "긴";
// Alerts
"New version available" = "새로운 버전을 이용할 수 있습니다";
@@ -152,3 +154,7 @@
"Low level notification" = "베터리 부족 상태 알림";
"Low battery" = "배터리 부족";
"Battery remaining" = "%0% 남았습니다";
"Percentage" = "백분율";
"Percentage and time" = "비율과 시간";
"Time and percentage" = "시간과 비율";
"Time format" = "시간 형식";

View File

@@ -28,6 +28,8 @@
"Dots" = "Punkty";
"Arrows" = "Strzałki";
"Characters" = "Litery";
"Short" = "Krótki";
"Long" = "Długi";
// Alerts
"New version available" = "Nowa wersja dostępna";
@@ -152,3 +154,7 @@
"Low level notification" = "Powiadomienie o niskim poziomie";
"Low battery" = "Niski poziom baterii";
"Battery remaining" = "Pozostało %0%";
"Percentage" = "Procenty";
"Percentage and time" = "Procenty i czas";
"Time and percentage" = "Czas i procenty";
"Time format" = "Format czasu";

View File

@@ -28,6 +28,8 @@
"Dots" = "Точки";
"Arrows" = "Стрелки";
"Characters" = "Символы";
"Short" = "Короткий";
"Long" = "Длинный";
// Alerts
"New version available" = "Доступна новая версия";
@@ -152,3 +154,7 @@
"Low level notification" = "Сообщение о низком уровне заряда";
"Low battery" = "Низкий заряд аккумулятора";
"Battery remaining" = "%0% осталось";
"Percentage" = "Проценты";
"Percentage and time" = "Проценты и время";
"Time and percentage" = "Время и Проценты";
"Time format" = "Формат времени";

View File

@@ -28,6 +28,8 @@
"Dots" = "Noktalar";
"Arrows" = "Oklar";
"Characters" = "Mektuplar";
"Short" = "Kısa";
"Long" = "Uzun";
// Alerts
"New version available" = "Yeni versiyon indirilebilir";
@@ -152,3 +154,7 @@
"Low level notification" = "Düşük güç bildirimi";
"Low battery" = "Düşük batarya";
"Battery remaining" = "%0% kaldı";
"Percentage" = "Yüzde";
"Percentage and time" = "Yüzde ve zaman";
"Time and percentage" = "Zaman ve yüzde";
"Time format" = "Zaman formatı";

View File

@@ -28,6 +28,8 @@
"Dots" = "Пункти";
"Arrows" = "Стрілки";
"Characters" = "Літери";
"Short" = "Короткий";
"Long" = "Довгий";
// Alerts
"New version available" = "Доступна нова версія";
@@ -152,3 +154,7 @@
"Low level notification" = "Повідомлення про низький рівень заряду";
"Low battery" = "Низький заряд акумулятора";
"Battery remaining" = "%0% залишилось";
"Percentage" = "Проценти";
"Percentage and time" = "Проценти і час";
"Time and percentage" = "Час і проценти";
"Time format" = "Формат часу";

View File

@@ -28,6 +28,8 @@
"Dots" = "点";
"Arrows" = "箭";
"Characters" = "字母";
"Short" = "短";
"Long" = "长";
// Alerts
"New version available" = "新版本可用";
@@ -152,3 +154,7 @@
"Low level notification" = "低电量通知";
"Low battery" = "低电量";
"Battery remaining" = "剩余 %0%";
"Percentage" = "百分比";
"Percentage and time" = "百分比和时间";
"Time and percentage" = "时间和百分比";
"Time format" = "时间格式";

View File

@@ -28,6 +28,8 @@
"Dots" = "點";
"Arrows" = "箭";
"Characters" = "字母";
"Short" = "短";
"Long" = "長";
// Alerts
"New version available" = "新版本可用";
@@ -148,3 +150,7 @@
"Low level notification" = "低電量通知";
"Low battery" = "低電量";
"Battery remaining" = "剩餘 %0%";
"Percentage" = "百分比";
"Percentage and time" = "百分比和時間";
"Time and percentage" = "時間和百分比";
"Time format" = "時間格式";

View File

@@ -187,34 +187,26 @@ public extension Double {
}
}
func secondsToHoursMinutesSeconds() -> (Int?, Int?, Int?) {
let hrs = self / 3600
func secondsToHoursMinutesSeconds() -> (Int, Int) {
let mins = (self.truncatingRemainder(dividingBy: 3600)) / 60
let seconds = (self.truncatingRemainder(dividingBy:3600)).truncatingRemainder(dividingBy:60)
return (Int(hrs) > 0 ? Int(hrs) : nil , Int(mins) > 0 ? Int(mins) : nil, Int(seconds) > 0 ? Int(seconds) : nil)
return (Int(self / 3600) , Int(mins))
}
func printSecondsToHoursMinutesSeconds() -> String {
let time = self.secondsToHoursMinutesSeconds()
func printSecondsToHoursMinutesSeconds(short: Bool = false) -> String {
let (h, m) = self.secondsToHoursMinutesSeconds()
let minutes = m > 9 ? "\(m)" : "0\(m)"
switch time {
case (nil, let x? , let y?):
return "\(x)min \(y)sec"
case (nil, let x?, nil):
return "\(x)min"
case (let x?, nil, nil):
return "\(x)h"
case (nil, nil, let x?):
return "\(x)sec"
case (let x?, nil, let z?):
return "\(x)h \(z)sec"
case (let x?, let y?, nil):
return "\(x)h \(y)min"
case (let x?, let y?, let z?):
return "\(x)h \(y)min \(z)sec"
default:
return "n/a"
if short {
return "\(h):\(minutes)"
}
if h == 0 {
return "\(minutes)min"
} else if m == 0 {
return "\(h)h"
}
return "\(h)h \(minutes)min"
}
}

View File

@@ -66,6 +66,20 @@ public let SpeedPictogram: [KeyValue_t] = [
KeyValue_t(key: "chars", value: "Characters"),
]
public let BatteryAdditionals: [KeyValue_t] = [
KeyValue_t(key: "none", value: "None"),
KeyValue_t(key: "separator", value: "separator"),
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"),
]
public let ReaderUpdateIntervals: [Int] = [1, 2, 3, 5, 10, 15, 30]
public let NumbersOfProcesses: [Int] = [3, 5, 8, 10, 15]