From c39b91c0b8e9ed52e1d9953281dabc206cff632c Mon Sep 17 00:00:00 2001 From: Serhiy Mytrovtsiy Date: Sat, 31 Oct 2020 21:13:31 +0100 Subject: [PATCH] - fix Battery module settings visibility - add option to select the battery time: short (01:25) and long (1h 25min) (#129) - add missing translations --- ModuleKit/Widgets/Battery.swift | 54 +++++++++---------- Modules/Battery/main.swift | 5 ++ Modules/Battery/popup.swift | 9 +++- Modules/Battery/settings.swift | 38 +++++++++++-- .../de.lproj/Localizable.strings | 6 +++ .../en.lproj/Localizable.strings | 6 +++ .../es.lproj/Localizable.strings | 6 +++ .../ko.lproj/Localizable.strings | 6 +++ .../pl.lproj/Localizable.strings | 6 +++ .../ru.lproj/Localizable.strings | 6 +++ .../tr.lproj/Localizable.strings | 6 +++ .../uk.lproj/Localizable.strings | 6 +++ .../zh-Hans.lproj/Localizable.strings | 6 +++ .../zh-Hant.lproj/Localizable.strings | 6 +++ StatsKit/extensions.swift | 38 ++++++------- StatsKit/helpers.swift | 14 +++++ 16 files changed, 161 insertions(+), 57 deletions(-) diff --git a/ModuleKit/Widgets/Battery.swift b/ModuleKit/Widgets/Battery.swift index 0bf98295..ffe6190c 100644 --- a/ModuleKit/Widgets/Battery.swift +++ b/ModuleKit/Widgets/Battery.swift @@ -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() } diff --git a/Modules/Battery/main.swift b/Modules/Battery/main.swift index 34414cd8..120b767b 100644 --- a/Modules/Battery/main.swift +++ b/Modules/Battery/main.swift @@ -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 { diff --git a/Modules/Battery/popup.swift b/Modules/Battery/popup.swift index 82240bc0..197d2055 100644 --- a/Modules/Battery/popup.swift +++ b/Modules/Battery/popup.swift @@ -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") } } diff --git a/Modules/Battery/settings.swift b/Modules/Battery/settings.swift index ef38d9cf..687ca35b 100644 --- a/Modules/Battery/settings.swift +++ b/Modules/Battery/settings.swift @@ -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) { 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() + } } diff --git a/Stats/Supporting Files/de.lproj/Localizable.strings b/Stats/Supporting Files/de.lproj/Localizable.strings index ab820450..efd4ea9d 100644 --- a/Stats/Supporting Files/de.lproj/Localizable.strings +++ b/Stats/Supporting Files/de.lproj/Localizable.strings @@ -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"; diff --git a/Stats/Supporting Files/en.lproj/Localizable.strings b/Stats/Supporting Files/en.lproj/Localizable.strings index d504d841..95ee009f 100644 --- a/Stats/Supporting Files/en.lproj/Localizable.strings +++ b/Stats/Supporting Files/en.lproj/Localizable.strings @@ -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"; diff --git a/Stats/Supporting Files/es.lproj/Localizable.strings b/Stats/Supporting Files/es.lproj/Localizable.strings index e4f5b02e..55f168f9 100644 --- a/Stats/Supporting Files/es.lproj/Localizable.strings +++ b/Stats/Supporting Files/es.lproj/Localizable.strings @@ -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"; diff --git a/Stats/Supporting Files/ko.lproj/Localizable.strings b/Stats/Supporting Files/ko.lproj/Localizable.strings index 5fc7ee89..14910d12 100644 --- a/Stats/Supporting Files/ko.lproj/Localizable.strings +++ b/Stats/Supporting Files/ko.lproj/Localizable.strings @@ -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" = "시간 형식"; diff --git a/Stats/Supporting Files/pl.lproj/Localizable.strings b/Stats/Supporting Files/pl.lproj/Localizable.strings index fc6f5acc..78dcc0d8 100644 --- a/Stats/Supporting Files/pl.lproj/Localizable.strings +++ b/Stats/Supporting Files/pl.lproj/Localizable.strings @@ -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"; diff --git a/Stats/Supporting Files/ru.lproj/Localizable.strings b/Stats/Supporting Files/ru.lproj/Localizable.strings index d4bbc892..a204ff4f 100644 --- a/Stats/Supporting Files/ru.lproj/Localizable.strings +++ b/Stats/Supporting Files/ru.lproj/Localizable.strings @@ -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" = "Формат времени"; diff --git a/Stats/Supporting Files/tr.lproj/Localizable.strings b/Stats/Supporting Files/tr.lproj/Localizable.strings index 074a8ef9..db07c239 100644 --- a/Stats/Supporting Files/tr.lproj/Localizable.strings +++ b/Stats/Supporting Files/tr.lproj/Localizable.strings @@ -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ı"; diff --git a/Stats/Supporting Files/uk.lproj/Localizable.strings b/Stats/Supporting Files/uk.lproj/Localizable.strings index 02d5f876..3b414b5a 100644 --- a/Stats/Supporting Files/uk.lproj/Localizable.strings +++ b/Stats/Supporting Files/uk.lproj/Localizable.strings @@ -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" = "Формат часу"; diff --git a/Stats/Supporting Files/zh-Hans.lproj/Localizable.strings b/Stats/Supporting Files/zh-Hans.lproj/Localizable.strings index 2f4a2f53..9a7446dc 100644 --- a/Stats/Supporting Files/zh-Hans.lproj/Localizable.strings +++ b/Stats/Supporting Files/zh-Hans.lproj/Localizable.strings @@ -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" = "时间格式"; diff --git a/Stats/Supporting Files/zh-Hant.lproj/Localizable.strings b/Stats/Supporting Files/zh-Hant.lproj/Localizable.strings index 03e11654..79246422 100644 --- a/Stats/Supporting Files/zh-Hant.lproj/Localizable.strings +++ b/Stats/Supporting Files/zh-Hant.lproj/Localizable.strings @@ -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" = "時間格式"; diff --git a/StatsKit/extensions.swift b/StatsKit/extensions.swift index 23c3ebf2..ea82b1e1 100644 --- a/StatsKit/extensions.swift +++ b/StatsKit/extensions.swift @@ -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" } } diff --git a/StatsKit/helpers.swift b/StatsKit/helpers.swift index 5cdc07e3..7e3deafc 100644 --- a/StatsKit/helpers.swift +++ b/StatsKit/helpers.swift @@ -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]