Skip to content

Commit

Permalink
Finalized for v1.3
Browse files Browse the repository at this point in the history
  • Loading branch information
NafeeJ committed Feb 2, 2020
1 parent b445e4d commit bb51751
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 21 deletions.
4 changes: 2 additions & 2 deletions BatteryEstimate.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -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 = "";
Expand Down Expand Up @@ -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 = "";
Expand Down
88 changes: 69 additions & 19 deletions BatteryEstimate/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -25,66 +36,105 @@ 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) {

}

//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
if (remainingSeconds > 0.0) {
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

for ps in list {
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() {
Expand Down
44 changes: 44 additions & 0 deletions BatteryEstimate/Base.lproj/Main.storyboard
Original file line number Diff line number Diff line change
Expand Up @@ -721,13 +721,57 @@
<action selector="launchOnLoginClicked:" target="XfG-lQ-9wD" id="g1O-ct-lln"/>
</connections>
</button>
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="kgy-U5-4cN">
<rect key="frame" x="18" y="214" width="176" height="18"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="check" title="Show Battery Percentage" bezelStyle="regularSquare" imagePosition="left" inset="2" id="Gq0-Xa-bai">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="showPercentageClicked:" target="XfG-lQ-9wD" id="9LR-nD-LoE"/>
</connections>
</button>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="TfI-y1-Q2T">
<rect key="frame" x="18" y="192" width="167" height="16"/>
<autoresizingMask key="autoresizingMask"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="Seconds Between Refresh:" id="roV-oO-yDO">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<popUpButton verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="9JO-fh-s2x">
<rect key="frame" x="189" y="186" width="48" height="25"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<popUpButtonCell key="cell" type="push" title="2" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="dBK-Ho-7SS" id="rpZ-wf-ixP">
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
<menu key="menu" id="wvc-7i-gJd">
<items>
<menuItem title="1" id="vsp-F7-err"/>
<menuItem title="2" state="on" id="dBK-Ho-7SS"/>
<menuItem title="3" id="gAF-6J-FiA"/>
<menuItem title="4" id="ssU-2q-rhc"/>
<menuItem title="5" id="JX1-zk-dhM"/>
</items>
</menu>
</popUpButtonCell>
<connections>
<action selector="updateIntervalClicked:" target="XfG-lQ-9wD" id="SjO-Os-vyE"/>
</connections>
</popUpButton>
</subviews>
</view>
<connections>
<outlet property="launchOnLogin" destination="5t5-0l-dah" id="BLA-qK-ouH"/>
<outlet property="showBatteryPercentage" destination="kgy-U5-4cN" id="1FU-dh-OAq"/>
<outlet property="showPercentage" destination="kgy-U5-4cN" id="2ih-hb-Thp"/>
<outlet property="updateInterval" destination="9JO-fh-s2x" id="Rhc-n5-O7Y"/>
</connections>
</viewController>
<customObject id="rPt-NT-nkU" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
<userDefaultsController representsSharedInstance="YES" id="wOg-uT-IQQ"/>
</objects>
<point key="canvasLocation" x="75" y="655"/>
</scene>
Expand Down
22 changes: 22 additions & 0 deletions BatteryEstimate/ViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}

0 comments on commit bb51751

Please sign in to comment.