diff --git a/MTMR.xcodeproj/project.pbxproj b/MTMR.xcodeproj/project.pbxproj index 2958cd6..352e69b 100644 --- a/MTMR.xcodeproj/project.pbxproj +++ b/MTMR.xcodeproj/project.pbxproj @@ -19,6 +19,7 @@ 6042B6A72083E03A00C525C8 /* AppScrubberTouchBarItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6042B6A62083E03A00C525C8 /* AppScrubberTouchBarItem.swift */; }; 6042B6AA2083E27000C525C8 /* DeprecatedCarbonAPI.c in Sources */ = {isa = PBXBuildFile; fileRef = 6042B6A92083E27000C525C8 /* DeprecatedCarbonAPI.c */; }; B0008E552080286C003AD4DD /* SupportHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0008E542080286C003AD4DD /* SupportHelpers.swift */; }; + B04B7BB72087398C00C835D0 /* BatteryBarItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = B04B7BB62087398C00C835D0 /* BatteryBarItem.swift */; }; B05600D32083E9BB00EB218D /* CustomSlider.swift in Sources */ = {isa = PBXBuildFile; fileRef = B05600D22083E9BB00EB218D /* CustomSlider.swift */; }; B059D622205E03F5006E6B86 /* TouchBarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B059D621205E03F5006E6B86 /* TouchBarController.swift */; }; B059D624205E04F3006E6B86 /* CustomButtonTouchBarItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = B059D623205E04F3006E6B86 /* CustomButtonTouchBarItem.swift */; }; @@ -67,6 +68,7 @@ 6042B6A82083E1F500C525C8 /* DeprecatedCarbonAPI.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DeprecatedCarbonAPI.h; sourceTree = ""; }; 6042B6A92083E27000C525C8 /* DeprecatedCarbonAPI.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = DeprecatedCarbonAPI.c; sourceTree = ""; }; B0008E542080286C003AD4DD /* SupportHelpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SupportHelpers.swift; sourceTree = ""; }; + B04B7BB62087398C00C835D0 /* BatteryBarItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BatteryBarItem.swift; sourceTree = ""; }; B05600D22083E9BB00EB218D /* CustomSlider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomSlider.swift; sourceTree = ""; }; B059D621205E03F5006E6B86 /* TouchBarController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TouchBarController.swift; sourceTree = ""; }; B059D623205E04F3006E6B86 /* CustomButtonTouchBarItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomButtonTouchBarItem.swift; sourceTree = ""; }; @@ -172,6 +174,7 @@ 368EDDE620812A1D00E10953 /* ScrollViewItem.swift */, 6042B6A62083E03A00C525C8 /* AppScrubberTouchBarItem.swift */, B05600D22083E9BB00EB218D /* CustomSlider.swift */, + B04B7BB62087398C00C835D0 /* BatteryBarItem.swift */, ); path = MTMR; sourceTree = ""; @@ -347,6 +350,7 @@ 36C2ECD7207B6DAE003CDA33 /* TimeTouchBarItem.swift in Sources */, 6027D1B92080E52A004FFDC7 /* BrightnessViewController.swift in Sources */, 368EDDE720812A1D00E10953 /* ScrollViewItem.swift in Sources */, + B04B7BB72087398C00C835D0 /* BatteryBarItem.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/MTMR/BatteryBarItem.swift b/MTMR/BatteryBarItem.swift new file mode 100644 index 0000000..71aa74b --- /dev/null +++ b/MTMR/BatteryBarItem.swift @@ -0,0 +1,118 @@ +// +// BatteryBarItem.swift +// MTMR +// +// Created by Anton Palgunov on 18/04/2018. +// Copyright © 2018 Anton Palgunov. All rights reserved. +// + +import IOKit.ps +import Foundation + +class BatteryBarItem: NSCustomTouchBarItem { + private var timer: Timer! + private let button = NSButton(title: "", target: nil, action: nil) + + override init(identifier: NSTouchBarItem.Identifier) { + super.init(identifier: identifier) + timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(updateInfo), userInfo: nil, repeats: true) + self.view = button + button.bezelColor = .clear + updateInfo() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + @objc func updateInfo() { + var title = "" + + let info = BatteryInfo().getInfo() + let timeRemainig = info["timeRemainig"] as! String + let percentage = info["percentage"] as! Int + let isCharging = info["isCharging"] as! Bool + let isCharged = info["isCharged"] as! Bool + + if isCharging { + title += "⚡️" + } + + title += String(percentage) + "%" + + if !isCharged { + title += " (" + timeRemainig + ")" + } + + button.title = title + } +} + +class BatteryInfo { + var current: Int = 0 + var timeToEmpty: Int = 0 + var timeToFull: Int = 0 + var isCharged: Bool = false + var isCharging: Bool = false + + func getFormattedTime(time: Int) -> String { + let timeFormatted = NSString(format: "%d:%02d", time / 60, time % 60) as String + print(timeFormatted) + + return timeFormatted + } + + func getPSInfo() { + let psInfo = IOPSCopyPowerSourcesInfo().takeRetainedValue() + let psList = IOPSCopyPowerSourcesList(psInfo).takeRetainedValue() as [CFTypeRef] + + for ps in psList { + if let psDesc = IOPSGetPowerSourceDescription(psInfo, ps).takeUnretainedValue() as? [String: Any] { + let current = psDesc[kIOPSCurrentCapacityKey] + if (current != nil) { + self.current = current as! Int + } + + let timeToEmpty = psDesc[kIOPSTimeToEmptyKey] + if (timeToEmpty != nil) { + self.timeToEmpty = timeToEmpty as! Int + } + + let timeToFull = psDesc[kIOPSTimeToFullChargeKey] + if (timeToFull != nil) { + self.timeToFull = timeToFull as! Int + } + + let isCharged = psDesc[kIOPSIsChargedKey] + if (isCharged != nil) { + self.isCharged = isCharged as! Bool + } + + let isCharging = psDesc[kIOPSIsChargingKey] + if (isCharging != nil) { + self.isCharging = isCharging as! Bool + } + } + } + } + + public func getInfo() -> [String: Any] { + var result: [String: Any] = [:] + var timeRemaining = "" + + self.getPSInfo() + + if isCharging { + timeRemaining = getFormattedTime(time: self.timeToFull) + } else { + timeRemaining = getFormattedTime(time: self.timeToEmpty) + } + + result["timeRemainig"] = timeRemaining + result["percentage"] = self.current + result["isCharging"] = self.isCharging + result["isCharged"] = self.isCharged + + return result + } +} diff --git a/MTMR/ItemsParsing.swift b/MTMR/ItemsParsing.swift index 5851f67..823253d 100644 --- a/MTMR/ItemsParsing.swift +++ b/MTMR/ItemsParsing.swift @@ -137,6 +137,7 @@ enum ItemType: Decodable { case staticButton(title: String) case appleScriptTitledButton(source: SourceProtocol, refreshInterval: Double) case timeButton(formatTemplate: String) + case batteryButton() case dock() case volume() case brightness(refreshInterval: Double) @@ -154,6 +155,7 @@ enum ItemType: Decodable { case staticButton case appleScriptTitledButton case timeButton + case batteryButton case dock case volume case brightness @@ -173,6 +175,8 @@ enum ItemType: Decodable { case .timeButton: let template = try container.decodeIfPresent(String.self, forKey: .formatTemplate) ?? "HH:mm" self = .timeButton(formatTemplate: template) + case .batteryButton: + self = .batteryButton() case .dock: self = .dock() case .volume: diff --git a/MTMR/TouchBarController.swift b/MTMR/TouchBarController.swift index ada3da1..63a6f26 100644 --- a/MTMR/TouchBarController.swift +++ b/MTMR/TouchBarController.swift @@ -23,6 +23,8 @@ extension ItemType { return "com.toxblh.mtmr.appleScriptButton." case .timeButton(formatTemplate: _): return "com.toxblh.mtmr.timeButton." + case .batteryButton(): + return "com.toxblh.mtmr.batteryButton." case .dock(): return "com.toxblh.mtmr.dock" case .volume(): @@ -152,6 +154,8 @@ class TouchBarController: NSObject, NSTouchBarDelegate { barItem = AppleScriptTouchBarItem(identifier: identifier, source: source, interval: interval, onTap: action) case .timeButton(formatTemplate: let template): barItem = TimeTouchBarItem(identifier: identifier, formatTemplate: template) + case .batteryButton(): + barItem = BatteryBarItem(identifier: identifier) case .dock: barItem = AppScrubberTouchBarItem(identifier: identifier) case .volume: