From bb51751da659fcff12d0de6189fc6c57e90d846e Mon Sep 17 00:00:00 2001 From: NafeeJ Date: Sun, 2 Feb 2020 12:13:54 -0500 Subject: [PATCH] Finalized for v1.3 --- BatteryEstimate.xcodeproj/project.pbxproj | 4 +- BatteryEstimate/AppDelegate.swift | 88 +++++++++++++++++----- BatteryEstimate/Base.lproj/Main.storyboard | 44 +++++++++++ BatteryEstimate/ViewController.swift | 22 ++++++ 4 files changed, 137 insertions(+), 21 deletions(-) diff --git a/BatteryEstimate.xcodeproj/project.pbxproj b/BatteryEstimate.xcodeproj/project.pbxproj index 15fc436..2deaf9b 100644 --- a/BatteryEstimate.xcodeproj/project.pbxproj +++ b/BatteryEstimate.xcodeproj/project.pbxproj @@ -509,7 +509,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); - MARKETING_VERSION = 1.2; + MARKETING_VERSION = 1.3; PRODUCT_BUNDLE_IDENTIFIER = com.nafeeworkshop.BatteryEstimate; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -538,7 +538,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); - MARKETING_VERSION = 1.2; + MARKETING_VERSION = 1.3; PRODUCT_BUNDLE_IDENTIFIER = com.nafeeworkshop.BatteryEstimate; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; diff --git a/BatteryEstimate/AppDelegate.swift b/BatteryEstimate/AppDelegate.swift index 38c1063..c1c0f91 100644 --- a/BatteryEstimate/AppDelegate.swift +++ b/BatteryEstimate/AppDelegate.swift @@ -14,9 +14,20 @@ class AppDelegate: NSObject, NSApplicationDelegate { let statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength) var updateTimer: Timer? + static var currentInterval = AppDelegate.updateInterval var menu: NSMenu? var windowController: MainWindowController? - + + //Power values + var isCharging: Bool! + var batteryPercentage: String! + + //User Preferences + static let showPercentageKey: String = "ShowPercentage" + static var showPercentage: Bool = false + static let updateIntervalKey: String = "UpdateIntervalKey" + static var updateInterval: Double = 2 + func applicationDidFinishLaunching(_ aNotification: Notification) { //Create menu @@ -25,13 +36,17 @@ class AppDelegate: NSObject, NSApplicationDelegate { menu?.addItem(NSMenuItem(title: "Quit BatteryEstimate", action: #selector(NSApplication.terminate(_:)), keyEquivalent: "q")) statusItem.menu = menu + //load user preferences + loadPreferences() + //Update time remaining - updateEstimate() - updateTimer = Timer.scheduledTimer(timeInterval: 3, target: self, selector: #selector(updateEstimate), userInfo: nil, repeats: true) - RunLoop.current.add(updateTimer!, forMode: RunLoop.Mode.common) + updateAll() //initialize window windowController = (NSStoryboard(name: "Main", bundle: nil).instantiateController(withIdentifier: "mainWindow") as! MainWindowController) + + updateTimer = Timer.scheduledTimer(timeInterval: AppDelegate.updateInterval, target: self, selector: #selector(updateAll), userInfo: nil, repeats: true) + RunLoop.current.add(updateTimer!, forMode: RunLoop.Mode.common) } func applicationWillTerminate(_ aNotification: Notification) { @@ -39,15 +54,34 @@ class AppDelegate: NSObject, NSApplicationDelegate { } //Set menu bar title to current time remaining - @objc func updateEstimate() { + @objc func updateAll() { + if AppDelegate.changeInterval() { + updateTimer?.invalidate() + updateTimer = Timer.scheduledTimer(timeInterval: AppDelegate.updateInterval, target: self, selector: #selector(updateAll), userInfo: nil, repeats: true) + RunLoop.current.add(updateTimer!, forMode: RunLoop.Mode.common) + AppDelegate.currentInterval = AppDelegate.updateInterval + } - //⚡︎ official high voltage emoji - //ϟ some symbol that looks like high voltage - statusItem.button?.title = "⚡︎ " + getTimeRemaining() + updatePowerValues() + if (!AppDelegate.showPercentage) { statusItem.button?.title = getTimeRemaining() } + else { statusItem.button?.title = getTimeRemaining() + " | " + batteryPercentage} + } + + static func changeInterval() -> Bool { + return AppDelegate.currentInterval != AppDelegate.updateInterval + } + + func loadPreferences() { + if (UserDefaults.standard.value(forKey: AppDelegate.showPercentageKey) != nil) { + AppDelegate.showPercentage = UserDefaults.standard.value(forKey: AppDelegate.showPercentageKey) as! Bool + } + if (UserDefaults.standard.value(forKey: AppDelegate.updateIntervalKey) != nil) { + AppDelegate.updateInterval = UserDefaults.standard.value(forKey: AppDelegate.updateIntervalKey) as! Double + } } //returns esimated battery remaining as String in format HH:MM or other status - @objc func getTimeRemaining() -> String { + func getTimeRemaining() -> String { let remainingSeconds: Double = IOPSGetTimeRemainingEstimate() //most likely condition so test first for optimization @@ -55,23 +89,23 @@ class AppDelegate: NSObject, NSApplicationDelegate { let formattedHours: Int = Int(floor(remainingSeconds / 3600)) let formattedMinutes: Int = Int(remainingSeconds / 60) % 60 - if (formattedMinutes < 10) { return String(formattedHours) + ":" + "0" + String(formattedMinutes) } + if (formattedMinutes < 10) { return "↓ " + String(formattedHours) + ":" + "0" + String(formattedMinutes) } - return String(formattedHours) + ":" + String(formattedMinutes) + return "↓ " + String(formattedHours) + ":" + String(formattedMinutes) } //if its not greater than 0 then check if its unknown, if so just say that its being calculated else if (remainingSeconds == kIOPSTimeRemainingUnknown) { return "Calculating" } //remainingSeconds fell through its checks so device must be plugged in, check if its charging and return so - else if (isCharging()) { return "Charging" } + else if (isCharging) { return "⚡︎ Charging" } //ϟ //fell through charging check, must not be charging - return "Not Charging" + return "✗ Not Charging" } - //checks if the battery is charging - func isCharging() -> Bool { + //updates power values + func updatePowerValues() { let info = IOPSCopyPowerSourcesInfo().takeRetainedValue() let list = IOPSCopyPowerSourcesList(info).takeRetainedValue() as Array @@ -79,12 +113,28 @@ class AppDelegate: NSObject, NSApplicationDelegate { if let desc = IOPSGetPowerSourceDescription(info, ps).takeUnretainedValue() as? [String: Any] { //if the powersource is the battery, return if it is charging or not let psName = desc[kIOPSNameKey] as? String - let isCharging = desc[kIOPSIsChargingKey] as? Bool - if (psName != nil && psName == "InternalBattery-0" && isCharging != nil) { return isCharging! } + + //if the power source is nil or isn't the internal battery then set error values for power values + if (psName != nil && psName == "InternalBattery-0") { + + //update isCharging + let isCharging = desc[kIOPSIsChargingKey] as? Bool + if (isCharging != nil) { self.isCharging = isCharging! } + else { self.isCharging = false } + + //only update batteryPercentage if the user wants the percentage + if (AppDelegate.showPercentage) { + let currentCapacity = desc[kIOPSCurrentCapacityKey] as! Double + let maxCapacity = desc[kIOPSMaxCapacityKey] as! Double + self.batteryPercentage = String(format: "%.0f", (currentCapacity / maxCapacity) * 100) + "%" + } + } + else { + self.isCharging = false + batteryPercentage = "Error" + } } } - - return false; } @objc func loadPrefsWindow() { diff --git a/BatteryEstimate/Base.lproj/Main.storyboard b/BatteryEstimate/Base.lproj/Main.storyboard index 297aa50..81f7e77 100644 --- a/BatteryEstimate/Base.lproj/Main.storyboard +++ b/BatteryEstimate/Base.lproj/Main.storyboard @@ -721,13 +721,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/BatteryEstimate/ViewController.swift b/BatteryEstimate/ViewController.swift index ee68ed6..f0049d8 100644 --- a/BatteryEstimate/ViewController.swift +++ b/BatteryEstimate/ViewController.swift @@ -33,5 +33,27 @@ class ViewController: NSViewController { @IBAction func launchOnLoginClicked(_ checkbox: NSButton) { LaunchAtLogin.isEnabled = (checkbox.state == NSButton.StateValue.on) } + + @IBOutlet var showPercentage: NSButton! { + didSet { + showPercentage.state = AppDelegate.showPercentage ? NSButton.StateValue.on : NSButton.StateValue.off + } + } + + @IBAction func showPercentageClicked(_ checkbox: NSButton) { + AppDelegate.showPercentage = checkbox.state == NSButton.StateValue.on + UserDefaults.standard.set(checkbox.state == NSButton.StateValue.on, forKey: AppDelegate.showPercentageKey) + } + + @IBOutlet var updateInterval: NSPopUpButton! { + didSet { + updateInterval.selectItem(at: Int(AppDelegate.updateInterval - 1)) + } + } + + @IBAction func updateIntervalClicked(_ menuItem: NSPopUpButton) { + AppDelegate.updateInterval = Double(menuItem.indexOfSelectedItem + 1) + UserDefaults.standard.set(AppDelegate.updateInterval, forKey: AppDelegate.updateIntervalKey) + } }