1
0
mirror of https://github.com/Toxblh/MTMR.git synced 2026-01-10 17:08:39 +00:00

Merge remote-tracking branch 'upstream/master'

This commit is contained in:
ad 2018-04-21 08:19:44 +03:00
commit 9abb17ee76
12 changed files with 239 additions and 43 deletions

BIN
.DS_Store vendored

Binary file not shown.

View File

@ -21,6 +21,7 @@
607EEA4B2087835F009DA5F0 /* WeatherBarItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 607EEA4A2087835F009DA5F0 /* WeatherBarItem.swift */; };
607EEA4D2087A8DA009DA5F0 /* CurrencyBarItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 607EEA4C2087A8DA009DA5F0 /* CurrencyBarItem.swift */; };
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 */; };
@ -71,6 +72,7 @@
607EEA4A2087835F009DA5F0 /* WeatherBarItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeatherBarItem.swift; sourceTree = "<group>"; };
607EEA4C2087A8DA009DA5F0 /* CurrencyBarItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CurrencyBarItem.swift; sourceTree = "<group>"; };
B0008E542080286C003AD4DD /* SupportHelpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SupportHelpers.swift; sourceTree = "<group>"; };
B04B7BB62087398C00C835D0 /* BatteryBarItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BatteryBarItem.swift; sourceTree = "<group>"; };
B05600D22083E9BB00EB218D /* CustomSlider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomSlider.swift; sourceTree = "<group>"; };
B059D621205E03F5006E6B86 /* TouchBarController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TouchBarController.swift; sourceTree = "<group>"; };
B059D623205E04F3006E6B86 /* CustomButtonTouchBarItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomButtonTouchBarItem.swift; sourceTree = "<group>"; };
@ -176,6 +178,7 @@
368EDDE620812A1D00E10953 /* ScrollViewItem.swift */,
6042B6A62083E03A00C525C8 /* AppScrubberTouchBarItem.swift */,
B05600D22083E9BB00EB218D /* CustomSlider.swift */,
B04B7BB62087398C00C835D0 /* BatteryBarItem.swift */,
607EEA4A2087835F009DA5F0 /* WeatherBarItem.swift */,
607EEA4C2087A8DA009DA5F0 /* CurrencyBarItem.swift */,
);
@ -355,6 +358,7 @@
607EEA4D2087A8DA009DA5F0 /* CurrencyBarItem.swift in Sources */,
6027D1B92080E52A004FFDC7 /* BrightnessViewController.swift in Sources */,
368EDDE720812A1D00E10953 /* ScrollViewItem.swift in Sources */,
B04B7BB72087398C00C835D0 /* BatteryBarItem.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

View File

@ -13,7 +13,6 @@ class AppDelegate: NSObject, NSApplicationDelegate {
let statusItem = NSStatusBar.system.statusItem(withLength:NSStatusItem.squareLength)
func applicationDidFinishLaunching(_ aNotification: Notification) {
// Insert code here to initialize your application
TouchBarController.shared.setupControlStripPresence()
if let button = statusItem.button {
@ -23,7 +22,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
}
func applicationWillTerminate(_ aNotification: Notification) {
// Insert code here to tear down your application
}
@objc func openPrefereces(_ sender: Any?) {

View File

@ -18,7 +18,9 @@ class AppleScriptTouchBarItem: CustomButtonTouchBarItem {
DispatchQueue.main.async {
var error: NSDictionary?
guard script.compileAndReturnError(&error) else {
// print(error?.description ?? "unknown error")
#if DEBUG
print(error?.description ?? "unknown error")
#endif
DispatchQueue.main.async {
self.button.title = "error"
}
@ -33,7 +35,9 @@ class AppleScriptTouchBarItem: CustomButtonTouchBarItem {
}
func refreshAndSchedule() {
// print("refresh happened")
#if DEBUG
print("refresh happened")
#endif
let scriptResult = self.execute()
DispatchQueue.main.async {
self.button.title = scriptResult

137
MTMR/BatteryBarItem.swift Normal file
View File

@ -0,0 +1,137 @@
//
// 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)
self.view = button
button.bezelColor = .clear
let batteryInfo = BatteryInfo(button: button)
batteryInfo.start()
batteryInfo.updateInfo()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
class BatteryInfo: NSObject {
var current: Int = 0
var timeToEmpty: Int = 0
var timeToFull: Int = 0
var isCharged: Bool = false
var isCharging: Bool = false
var ACPower: String = ""
var timeRemaining: String = ""
var button: NSButton?
var loop:CFRunLoopSource?
init(button: NSButton) {
super.init()
self.button = button
self.start()
}
func start() {
let opaque = Unmanaged.passRetained(self).toOpaque()
let context = UnsafeMutableRawPointer(opaque)
loop = IOPSNotificationCreateRunLoopSource({ (context) in
guard let ctx = context else {
return
}
let watcher = Unmanaged<BatteryInfo>.fromOpaque(ctx).takeUnretainedValue()
watcher.updateInfo()
}, context).takeRetainedValue() as CFRunLoopSource
CFRunLoopAddSource(CFRunLoopGetCurrent(), loop, CFRunLoopMode.defaultMode)
}
func stop() {
if !(self.loop != nil) {
return
}
CFRunLoopRemoveSource(CFRunLoopGetCurrent(), self.loop, CFRunLoopMode.defaultMode)
self.loop = nil
}
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
}
let ACPower = psDesc[kIOPSPowerSourceStateKey]
if (ACPower != nil) {
self.ACPower = ACPower as! String
}
}
}
}
func getFormattedTime(time: Int) -> String {
if (time > 0) {
let timeFormatted = NSString(format: " (%d:%02d)", time / 60, time % 60) as String
return timeFormatted
} else if (time == 0) {
return ""
}
return " (?)"
}
public func updateInfo() {
var title = ""
self.getPSInfo()
if ACPower == "AC Power" {
title += "⚡️"
timeRemaining = getFormattedTime(time: timeToFull)
} else {
timeRemaining = getFormattedTime(time: timeToEmpty)
}
title += String(current) + "%" + timeRemaining
button?.title = title
}
}

View File

@ -16,7 +16,7 @@ class CurrencyBarItem: CustomButtonTouchBarItem {
private var from: String
private var to: String
private var oldValue: Float32!
private let currencies = [
"USD": "$",
"EUR": "",
@ -31,44 +31,47 @@ class CurrencyBarItem: CustomButtonTouchBarItem {
"IDR": "Rp",
"MXN": "$",
"SGD": "$",
"CHF": "Fr."
"CHF": "Fr.",
"BTC": "฿",
"LTC": "Ł",
"ETH": "Ξ",
]
init(identifier: NSTouchBarItem.Identifier, interval: TimeInterval, from: String, to: String, onTap: @escaping () -> ()) {
self.interval = interval
self.from = from
self.to = to
if let prefix = currencies[from] {
self.prefix = prefix
} else {
self.prefix = from
}
super.init(identifier: identifier, title: "", onTap: onTap)
button.bezelColor = .clear
self.view = button
timer = Timer.scheduledTimer(timeInterval: interval, target: self, selector: #selector(updateCurrency), userInfo: nil, repeats: true)
updateCurrency()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
@objc func updateCurrency() {
let urlRequest = URLRequest(url: URL(string: "https://api.coinbase.com/v2/exchange-rates?currency=\(from)")!)
let task = URLSession.shared.dataTask(with: urlRequest) { (data, response, error) in
if error == nil {
do {
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as! [String : AnyObject]
var value: Float32!
if let data_array = json["data"] as? [String : AnyObject] {
if let rates = data_array["rates"] as? [String : AnyObject] {
if let item = rates["\(self.to)"] as? String {
@ -89,21 +92,21 @@ class CurrencyBarItem: CustomButtonTouchBarItem {
task.resume()
}
func setCurrency(value: Float32) {
var color = NSColor.white
if let oldValue = self.oldValue {
if oldValue < value {
color = NSColor(red: 95.0/255.0, green: 185.0/255.0, blue: 50.0/255.0, alpha: 1.0)
color = NSColor.green
} else if oldValue > value {
color = NSColor(red: 185.0/255.0, green: 95.0/255.0, blue: 50.0/255.0, alpha: 1.0)
color = NSColor.red
}
}
self.oldValue = value
button.title = String(format: "%@%.2f", self.prefix, value)
let textRange = NSRange(location: 0, length: button.title.count)
let newTitle = NSMutableAttributedString(string: button.title)
newTitle.addAttribute(NSAttributedStringKey.foregroundColor, value: color, range: textRange)

View File

@ -60,6 +60,10 @@ class SupportedTypesHolder {
let imageParameter = GeneralParameter.image(source: NSImage(named: .touchBarVolumeUpTemplate)!)
return (item: .staticButton(title: ""), action: .hidKey(keycode: NX_KEYTYPE_SOUND_UP), parameters: [.image: imageParameter])
},
"mute": { _ in
let imageParameter = GeneralParameter.image(source: NSImage(named: .touchBarAudioOutputMuteTemplate)!)
return (item: .staticButton(title: ""), action: .hidKey(keycode: NX_KEYTYPE_MUTE), parameters: [.image: imageParameter])
},
"previous": { _ in
let imageParameter = GeneralParameter.image(source: NSImage(named: .touchBarRewindTemplate)!)
return (item: .staticButton(title: ""), action: .hidKey(keycode: NX_KEYTYPE_PREVIOUS), parameters: [.image: imageParameter])
@ -113,15 +117,6 @@ class SupportedTypesHolder {
return (item: .brightness(refreshInterval: interval ?? 0.5), action: .none, parameters: [:])
}
},
"battery": { decoder in
enum CodingKeys: String, CodingKey { case refreshInterval }
let container = try decoder.container(keyedBy: CodingKeys.self)
let interval = try container.decodeIfPresent(Double.self, forKey: .refreshInterval)
let scriptPath = Bundle.main.path(forResource: "Battery", ofType: "scpt")!
let item = ItemType.appleScriptTitledButton(source: Source(filePath: scriptPath), refreshInterval: interval ?? 1800.0)
let action = try ActionType(from: decoder)
return (item: item, action: action, parameters: [:])
},
"sleep": { _ in return (item: .staticButton(title: "☕️"), action: .shellScript(executable: "/usr/bin/pmset", parameters: ["sleepnow"]), parameters: [:]) },
"displaySleep": { _ in return (item: .staticButton(title: "☕️"), action: .shellScript(executable: "/usr/bin/pmset", parameters: ["displaysleepnow"]), parameters: [:]) },
]
@ -149,6 +144,7 @@ enum ItemType: Decodable {
case staticButton(title: String)
case appleScriptTitledButton(source: SourceProtocol, refreshInterval: Double)
case timeButton(formatTemplate: String)
case battery()
case dock()
case volume()
case brightness(refreshInterval: Double)
@ -174,6 +170,7 @@ enum ItemType: Decodable {
case staticButton
case appleScriptTitledButton
case timeButton
case battery
case dock
case volume
case brightness
@ -195,6 +192,8 @@ enum ItemType: Decodable {
case .timeButton:
let template = try container.decodeIfPresent(String.self, forKey: .formatTemplate) ?? "HH:mm"
self = .timeButton(formatTemplate: template)
case .battery:
self = .battery()
case .dock:
self = .dock()
case .volume:
@ -209,7 +208,7 @@ enum ItemType: Decodable {
let icon_type = try container.decodeIfPresent(String.self, forKey: .icon_type) ?? "text"
self = .weather(interval: interval, units: units, api_key: api_key, icon_type: icon_type)
case .currency:
let interval = try container.decodeIfPresent(Double.self, forKey: .refreshInterval) ?? 1800.0
let interval = try container.decodeIfPresent(Double.self, forKey: .refreshInterval) ?? 600.0
let from = try container.decodeIfPresent(String.self, forKey: .from) ?? "RUB"
let to = try container.decodeIfPresent(String.self, forKey: .to) ?? "USD"
self = .currency(interval: interval, from: from, to: to)

View File

@ -58,6 +58,7 @@ func HIDPostAuxKey(_ key: Int) {
// hidsystem/ev_keymap.h
let NX_KEYTYPE_SOUND_UP = 0
let NX_KEYTYPE_SOUND_DOWN = 1
let NX_KEYTYPE_MUTE = 7
let NX_KEYTYPE_BRIGHTNESS_UP = 2
let NX_KEYTYPE_BRIGHTNESS_DOWN = 3
@ -69,3 +70,4 @@ let NX_KEYTYPE_PREVIOUS = 18

View File

@ -23,6 +23,8 @@ extension ItemType {
return "com.toxblh.mtmr.appleScriptButton."
case .timeButton(formatTemplate: _):
return "com.toxblh.mtmr.timeButton."
case .battery():
return "com.toxblh.mtmr.battery."
case .dock():
return "com.toxblh.mtmr.dock"
case .volume():
@ -40,7 +42,6 @@ extension ItemType {
extension NSTouchBarItem.Identifier {
static let controlStripItem = NSTouchBarItem.Identifier("com.toxblh.mtmr.controlStrip")
static let centerScrollArea = NSTouchBarItem.Identifier("com.toxblh.mtmr.scrollArea")
}
class TouchBarController: NSObject, NSTouchBarDelegate {
@ -54,6 +55,8 @@ class TouchBarController: NSObject, NSTouchBarDelegate {
var leftIdentifiers: [NSTouchBarItem.Identifier] = []
var centerItems: [NSTouchBarItem] = []
var rightIdentifiers: [NSTouchBarItem.Identifier] = []
var scrollArea: NSCustomTouchBarItem?
var centerScrollArea = NSTouchBarItem.Identifier("com.toxblh.mtmr.scrollArea.".appending(UUID().uuidString))
private override init() {
super.init()
@ -81,8 +84,12 @@ class TouchBarController: NSObject, NSTouchBarDelegate {
return definition.align == .center ? items[identifier] : nil
}
self.centerScrollArea = NSTouchBarItem.Identifier("com.toxblh.mtmr.scrollArea.".appending(UUID().uuidString))
self.scrollArea = ScrollViewItem(identifier: centerScrollArea, items: centerItems)
touchBar.delegate = self
touchBar.defaultItemIdentifiers = self.leftIdentifiers + [.centerScrollArea] + self.rightIdentifiers
touchBar.defaultItemIdentifiers = []
touchBar.defaultItemIdentifiers = self.leftIdentifiers + [centerScrollArea] + self.rightIdentifiers
self.presentTouchBar()
}
@ -141,8 +148,8 @@ class TouchBarController: NSObject, NSTouchBarDelegate {
}
func touchBar(_ touchBar: NSTouchBar, makeItemForIdentifier identifier: NSTouchBarItem.Identifier) -> NSTouchBarItem? {
if identifier == .centerScrollArea {
return ScrollViewItem(identifier: identifier, items: centerItems)
if identifier == centerScrollArea {
return self.scrollArea
}
guard let item = self.items[identifier],
@ -164,6 +171,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 .battery():
barItem = BatteryBarItem(identifier: identifier)
case .dock:
barItem = AppScrubberTouchBarItem(identifier: identifier)
case .volume:
@ -225,7 +234,9 @@ class TouchBarController: NSObject, NSTouchBarDelegate {
case .openUrl(url: let url):
return {
if let url = URL(string: url), NSWorkspace.shared.open(url) {
// print("URL was successfully opened")
#if DEBUG
print("URL was successfully opened")
#endif
} else {
print("error", url)
}

View File

@ -33,6 +33,10 @@ class WeatherBarItem: CustomButtonTouchBarItem, CLLocationManagerDelegate {
units_str = "°C"
}
if self.units == "imperial" {
units_str = "°F"
}
if icon_type == "images" {
iconsSource = iconsImages
} else {

View File

@ -66,8 +66,10 @@
{ "type": "previous", "width": 44 },
{ "type": "play", "width": 44 },
{ "type": "next", "width": 44 },
{ "type": "weather", "refreshInterval": 1800 },
{ "type": "weather", "icon_type": "images", "units": "metric" },
{ "type": "currency", "from": "BTC", "to": "USD" },
{ "type": "sleep", "width": 44 },
{ "type": "mute", "width": 40, "align": "right" },
{ "type": "volumeDown", "width": 34, "align": "right" },
{ "type": "volume", "width": 60, "align": "right" },
{ "type": "volumeUp", "width": 34, "align": "right" },

View File

@ -46,7 +46,6 @@ Maybe:
## Installation
1. Download last release [Releases](https://github.com/Toxblh/MTMR/releases)
2. Unzip
3. Open MTMR
4. Open preset `open ~/Library/Application\ Support/MTMR/items.json` and customize it. Restart MTMR to apply changes.
@ -62,16 +61,20 @@ File for customize your preset for MTMR: `open ~/Library/Application\ Support/MT
- brightnessDown
- volumeDown
- volumeUp
- mute
- dock
> Native Plugins
- battery
- currency
- weather
> Media Keys
- previous
- play
- next
> AppleScript plugins
- weather
- battery
- sleep
- displaySleep
@ -106,8 +109,30 @@ File for customize your preset for MTMR: `open ~/Library/Application\ Support/MT
"formatTemplate": "HH:mm" //optional
```
## Native plugins
- `weather`
> Provider: https://openweathermap.org Need allowance location service
```js
"type": "weather",
"refreshInterval": 600,
"units": "metric", // or imperial
"icon_type": "text" // or images
"api_key": "" // you can get the key on openweather
```
- `currency`
> Provider: https://coinbase.com
```js
"type": "currency",
"refreshInterval": 600,
"align": "right",
"from": "BTC",
"to": "USD",
```
## Actions:
- `hidKey`
> https://github.com/aosm/IOHIDFamily/blob/master/IOHIDSystem/IOKit/hidsystem/ev_keymap.h use only numbers
```json
"action": "hidKey",
"keycode": 53,
@ -132,10 +157,16 @@ File for customize your preset for MTMR: `open ~/Library/Application\ Support/MT
```js
"action": "shellScript",
"executablePath": "/usr/bin/pmset",
"shellArguments": "sleepnow", // optional
"shellArguments": ["sleepnow"], // optional
```
- `openUrl`
```js
"action": "openUrl",
"url": "https://google.com",
```
## Additional paramaters:
- `width` allow to restrict how much room a particular button will take