mirror of
https://github.com/Toxblh/MTMR.git
synced 2026-01-10 17:08:39 +00:00
code format
This commit is contained in:
parent
8554dfeb5e
commit
86954a7981
@ -11,54 +11,50 @@ import Sparkle
|
|||||||
|
|
||||||
@NSApplicationMain
|
@NSApplicationMain
|
||||||
class AppDelegate: NSObject, NSApplicationDelegate {
|
class AppDelegate: NSObject, NSApplicationDelegate {
|
||||||
let statusItem = NSStatusBar.system.statusItem(withLength:NSStatusItem.squareLength)
|
let statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.squareLength)
|
||||||
var isBlockedApp: Bool = false
|
var isBlockedApp: Bool = false
|
||||||
|
|
||||||
private var fileSystemSource: DispatchSourceFileSystemObject?
|
private var fileSystemSource: DispatchSourceFileSystemObject?
|
||||||
|
|
||||||
func applicationDidFinishLaunching(_ aNotification: Notification) {
|
func applicationDidFinishLaunching(_: Notification) {
|
||||||
// Configure Sparkle
|
// Configure Sparkle
|
||||||
SUUpdater.shared().automaticallyDownloadsUpdates = false
|
SUUpdater.shared().automaticallyDownloadsUpdates = false
|
||||||
SUUpdater.shared().automaticallyChecksForUpdates = true
|
SUUpdater.shared().automaticallyChecksForUpdates = true
|
||||||
SUUpdater.shared().checkForUpdatesInBackground()
|
SUUpdater.shared().checkForUpdatesInBackground()
|
||||||
|
|
||||||
let _ = AXIsProcessTrustedWithOptions([kAXTrustedCheckOptionPrompt.takeRetainedValue() as NSString: true] as NSDictionary)
|
AXIsProcessTrustedWithOptions([kAXTrustedCheckOptionPrompt.takeRetainedValue() as NSString: true] as NSDictionary)
|
||||||
|
|
||||||
TouchBarController.shared.setupControlStripPresence()
|
TouchBarController.shared.setupControlStripPresence()
|
||||||
|
|
||||||
if let button = statusItem.button {
|
if let button = statusItem.button {
|
||||||
button.image = #imageLiteral(resourceName: "StatusImage")
|
button.image = #imageLiteral(resourceName: "StatusImage")
|
||||||
}
|
}
|
||||||
createMenu()
|
createMenu()
|
||||||
|
|
||||||
reloadOnDefaultConfigChanged()
|
reloadOnDefaultConfigChanged()
|
||||||
|
|
||||||
NSWorkspace.shared.notificationCenter.addObserver(self, selector: #selector(updateIsBlockedApp), name: NSWorkspace.didLaunchApplicationNotification, object: nil)
|
NSWorkspace.shared.notificationCenter.addObserver(self, selector: #selector(updateIsBlockedApp), name: NSWorkspace.didLaunchApplicationNotification, object: nil)
|
||||||
NSWorkspace.shared.notificationCenter.addObserver(self, selector: #selector(updateIsBlockedApp), name: NSWorkspace.didTerminateApplicationNotification, object: nil)
|
NSWorkspace.shared.notificationCenter.addObserver(self, selector: #selector(updateIsBlockedApp), name: NSWorkspace.didTerminateApplicationNotification, object: nil)
|
||||||
NSWorkspace.shared.notificationCenter.addObserver(self, selector: #selector(updateIsBlockedApp), name: NSWorkspace.didActivateApplicationNotification, object: nil)
|
NSWorkspace.shared.notificationCenter.addObserver(self, selector: #selector(updateIsBlockedApp), name: NSWorkspace.didActivateApplicationNotification, object: nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func applicationWillTerminate(_ aNotification: Notification) {
|
func applicationWillTerminate(_: Notification) {}
|
||||||
|
|
||||||
}
|
@objc func updateIsBlockedApp() {
|
||||||
|
|
||||||
@objc func updateIsBlockedApp() -> Void {
|
|
||||||
var blacklistAppIdentifiers: [String] = []
|
var blacklistAppIdentifiers: [String] = []
|
||||||
if let blackListed = UserDefaults.standard.stringArray(forKey: "com.toxblh.mtmr.blackListedApps") {
|
if let blackListed = UserDefaults.standard.stringArray(forKey: "com.toxblh.mtmr.blackListedApps") {
|
||||||
blacklistAppIdentifiers = blackListed
|
blacklistAppIdentifiers = blackListed
|
||||||
}
|
}
|
||||||
var frontmostApplicationIdentifier: String? {
|
var frontmostApplicationIdentifier: String? {
|
||||||
get {
|
guard let frontmostId = NSWorkspace.shared.frontmostApplication?.bundleIdentifier else { return nil }
|
||||||
guard let frontmostId = NSWorkspace.shared.frontmostApplication?.bundleIdentifier else { return nil }
|
return frontmostId
|
||||||
return frontmostId
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.isBlockedApp = blacklistAppIdentifiers.index(of: frontmostApplicationIdentifier!) != nil
|
isBlockedApp = blacklistAppIdentifiers.index(of: frontmostApplicationIdentifier!) != nil
|
||||||
createMenu()
|
createMenu()
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func openPreferences(_ sender: Any?) {
|
@objc func openPreferences(_: Any?) {
|
||||||
let task = Process()
|
let task = Process()
|
||||||
let appSupportDirectory = NSSearchPathForDirectoriesInDomains(.applicationSupportDirectory, .userDomainMask, true).first!.appending("/MTMR")
|
let appSupportDirectory = NSSearchPathForDirectoriesInDomains(.applicationSupportDirectory, .userDomainMask, true).first!.appending("/MTMR")
|
||||||
let presetPath = appSupportDirectory.appending("/items.json")
|
let presetPath = appSupportDirectory.appending("/items.json")
|
||||||
@ -66,14 +62,14 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
|||||||
task.arguments = [presetPath]
|
task.arguments = [presetPath]
|
||||||
task.launch()
|
task.launch()
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func toggleControlStrip(_ sender: Any?) {
|
@objc func toggleControlStrip(_: Any?) {
|
||||||
TouchBarController.shared.showControlStripState = !TouchBarController.shared.showControlStripState
|
TouchBarController.shared.showControlStripState = !TouchBarController.shared.showControlStripState
|
||||||
TouchBarController.shared.resetControlStrip()
|
TouchBarController.shared.resetControlStrip()
|
||||||
createMenu()
|
createMenu()
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func toggleBlackListedApp(_ sender: Any?) {
|
@objc func toggleBlackListedApp(_: Any?) {
|
||||||
let appIdentifier = TouchBarController.shared.frontmostApplicationIdentifier
|
let appIdentifier = TouchBarController.shared.frontmostApplicationIdentifier
|
||||||
if appIdentifier != nil {
|
if appIdentifier != nil {
|
||||||
if let index = TouchBarController.shared.blacklistAppIdentifiers.index(of: appIdentifier!) {
|
if let index = TouchBarController.shared.blacklistAppIdentifiers.index(of: appIdentifier!) {
|
||||||
@ -81,56 +77,56 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
|||||||
} else {
|
} else {
|
||||||
TouchBarController.shared.blacklistAppIdentifiers.append(appIdentifier!)
|
TouchBarController.shared.blacklistAppIdentifiers.append(appIdentifier!)
|
||||||
}
|
}
|
||||||
|
|
||||||
UserDefaults.standard.set(TouchBarController.shared.blacklistAppIdentifiers, forKey: "com.toxblh.mtmr.blackListedApps")
|
UserDefaults.standard.set(TouchBarController.shared.blacklistAppIdentifiers, forKey: "com.toxblh.mtmr.blackListedApps")
|
||||||
UserDefaults.standard.synchronize()
|
UserDefaults.standard.synchronize()
|
||||||
|
|
||||||
TouchBarController.shared.updateActiveApp()
|
TouchBarController.shared.updateActiveApp()
|
||||||
updateIsBlockedApp()
|
updateIsBlockedApp()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func openPreset(_ sender: Any?) {
|
@objc func openPreset(_: Any?) {
|
||||||
let dialog = NSOpenPanel();
|
let dialog = NSOpenPanel()
|
||||||
|
|
||||||
dialog.title = "Choose a items.json file"
|
dialog.title = "Choose a items.json file"
|
||||||
dialog.showsResizeIndicator = true
|
dialog.showsResizeIndicator = true
|
||||||
dialog.showsHiddenFiles = true
|
dialog.showsHiddenFiles = true
|
||||||
dialog.canChooseDirectories = false
|
dialog.canChooseDirectories = false
|
||||||
dialog.canCreateDirectories = false
|
dialog.canCreateDirectories = false
|
||||||
dialog.allowsMultipleSelection = false
|
dialog.allowsMultipleSelection = false
|
||||||
dialog.allowedFileTypes = ["json"]
|
dialog.allowedFileTypes = ["json"]
|
||||||
dialog.directoryURL = NSURL.fileURL(withPath: NSSearchPathForDirectoriesInDomains(.applicationSupportDirectory, .userDomainMask, true).first!.appending("/MTMR"), isDirectory: true)
|
dialog.directoryURL = NSURL.fileURL(withPath: NSSearchPathForDirectoriesInDomains(.applicationSupportDirectory, .userDomainMask, true).first!.appending("/MTMR"), isDirectory: true)
|
||||||
|
|
||||||
if dialog.runModal() == .OK, let path = dialog.url?.path {
|
if dialog.runModal() == .OK, let path = dialog.url?.path {
|
||||||
TouchBarController.shared.reloadPreset(path: path)
|
TouchBarController.shared.reloadPreset(path: path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func toggleStartAtLogin(_ sender: Any?) {
|
@objc func toggleStartAtLogin(_: Any?) {
|
||||||
LaunchAtLoginController().setLaunchAtLogin(!LaunchAtLoginController().launchAtLogin, for: NSURL.fileURL(withPath: Bundle.main.bundlePath))
|
LaunchAtLoginController().setLaunchAtLogin(!LaunchAtLoginController().launchAtLogin, for: NSURL.fileURL(withPath: Bundle.main.bundlePath))
|
||||||
createMenu()
|
createMenu()
|
||||||
}
|
}
|
||||||
|
|
||||||
func createMenu() {
|
func createMenu() {
|
||||||
let menu = NSMenu()
|
let menu = NSMenu()
|
||||||
|
|
||||||
let startAtLogin = NSMenuItem(title: "Start at login", action: #selector(toggleStartAtLogin(_:)), keyEquivalent: "L")
|
let startAtLogin = NSMenuItem(title: "Start at login", action: #selector(toggleStartAtLogin(_:)), keyEquivalent: "L")
|
||||||
startAtLogin.state = LaunchAtLoginController().launchAtLogin ? .on : .off
|
startAtLogin.state = LaunchAtLoginController().launchAtLogin ? .on : .off
|
||||||
|
|
||||||
let toggleBlackList = NSMenuItem(title: "Toggle current app in blacklist", action: #selector(toggleBlackListedApp(_:)), keyEquivalent: "B")
|
let toggleBlackList = NSMenuItem(title: "Toggle current app in blacklist", action: #selector(toggleBlackListedApp(_:)), keyEquivalent: "B")
|
||||||
toggleBlackList.state = self.isBlockedApp ? .on : .off
|
toggleBlackList.state = isBlockedApp ? .on : .off
|
||||||
|
|
||||||
let hideControlStrip = NSMenuItem(title: "Hide Control Strip", action: #selector(toggleControlStrip(_:)), keyEquivalent: "T")
|
let hideControlStrip = NSMenuItem(title: "Hide Control Strip", action: #selector(toggleControlStrip(_:)), keyEquivalent: "T")
|
||||||
hideControlStrip.state = TouchBarController.shared.showControlStripState ? .off : .on
|
hideControlStrip.state = TouchBarController.shared.showControlStripState ? .off : .on
|
||||||
|
|
||||||
let settingSeparator = NSMenuItem(title: "Settings", action: nil, keyEquivalent: "")
|
let settingSeparator = NSMenuItem(title: "Settings", action: nil, keyEquivalent: "")
|
||||||
settingSeparator.isEnabled = false
|
settingSeparator.isEnabled = false
|
||||||
|
|
||||||
menu.addItem(withTitle: "Preferences", action: #selector(openPreferences(_:)), keyEquivalent: ",")
|
menu.addItem(withTitle: "Preferences", action: #selector(openPreferences(_:)), keyEquivalent: ",")
|
||||||
menu.addItem(withTitle: "Open preset", action: #selector(openPreset(_:)), keyEquivalent: "O")
|
menu.addItem(withTitle: "Open preset", action: #selector(openPreset(_:)), keyEquivalent: "O")
|
||||||
menu.addItem(withTitle: "Check for Updates...", action: #selector(SUUpdater.checkForUpdates(_:)), keyEquivalent: "").target = SUUpdater.shared()
|
menu.addItem(withTitle: "Check for Updates...", action: #selector(SUUpdater.checkForUpdates(_:)), keyEquivalent: "").target = SUUpdater.shared()
|
||||||
|
|
||||||
menu.addItem(NSMenuItem.separator())
|
menu.addItem(NSMenuItem.separator())
|
||||||
menu.addItem(settingSeparator)
|
menu.addItem(settingSeparator)
|
||||||
menu.addItem(hideControlStrip)
|
menu.addItem(hideControlStrip)
|
||||||
@ -143,23 +139,22 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
|||||||
|
|
||||||
func reloadOnDefaultConfigChanged() {
|
func reloadOnDefaultConfigChanged() {
|
||||||
let file = NSURL.fileURL(withPath: standardConfigPath)
|
let file = NSURL.fileURL(withPath: standardConfigPath)
|
||||||
|
|
||||||
let fd = open(file.path, O_EVTONLY)
|
let fd = open(file.path, O_EVTONLY)
|
||||||
|
|
||||||
self.fileSystemSource = DispatchSource.makeFileSystemObjectSource(fileDescriptor: fd, eventMask: .write, queue: DispatchQueue(label: "DefaultConfigChanged"))
|
fileSystemSource = DispatchSource.makeFileSystemObjectSource(fileDescriptor: fd, eventMask: .write, queue: DispatchQueue(label: "DefaultConfigChanged"))
|
||||||
|
|
||||||
self.fileSystemSource?.setEventHandler(handler: {
|
fileSystemSource?.setEventHandler(handler: {
|
||||||
print("Config changed, reloading...")
|
print("Config changed, reloading...")
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
TouchBarController.shared.reloadPreset(path: file.path)
|
TouchBarController.shared.reloadPreset(path: file.path)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
self.fileSystemSource?.setCancelHandler(handler: {
|
fileSystemSource?.setCancelHandler(handler: {
|
||||||
close(fd)
|
close(fd)
|
||||||
})
|
})
|
||||||
|
|
||||||
self.fileSystemSource?.resume()
|
fileSystemSource?.resume()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -4,17 +4,17 @@ class AppleScriptTouchBarItem: CustomButtonTouchBarItem {
|
|||||||
private var script: NSAppleScript!
|
private var script: NSAppleScript!
|
||||||
private let interval: TimeInterval
|
private let interval: TimeInterval
|
||||||
private var forceHideConstraint: NSLayoutConstraint!
|
private var forceHideConstraint: NSLayoutConstraint!
|
||||||
|
|
||||||
init?(identifier: NSTouchBarItem.Identifier, source: SourceProtocol, interval: TimeInterval) {
|
init?(identifier: NSTouchBarItem.Identifier, source: SourceProtocol, interval: TimeInterval) {
|
||||||
self.interval = interval
|
self.interval = interval
|
||||||
super.init(identifier: identifier, title: "⏳")
|
super.init(identifier: identifier, title: "⏳")
|
||||||
self.forceHideConstraint = self.view.widthAnchor.constraint(equalToConstant: 0)
|
forceHideConstraint = view.widthAnchor.constraint(equalToConstant: 0)
|
||||||
guard let script = source.appleScript else {
|
guard let script = source.appleScript else {
|
||||||
self.title = "no script"
|
title = "no script"
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
self.script = script
|
self.script = script
|
||||||
self.isBordered = false
|
isBordered = false
|
||||||
DispatchQueue.appleScriptQueue.async {
|
DispatchQueue.appleScriptQueue.async {
|
||||||
var error: NSDictionary?
|
var error: NSDictionary?
|
||||||
guard script.compileAndReturnError(&error) else {
|
guard script.compileAndReturnError(&error) else {
|
||||||
@ -29,28 +29,28 @@ class AppleScriptTouchBarItem: CustomButtonTouchBarItem {
|
|||||||
self.refreshAndSchedule()
|
self.refreshAndSchedule()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
required init?(coder: NSCoder) {
|
required init?(coder _: NSCoder) {
|
||||||
fatalError("init(coder:) has not been implemented")
|
fatalError("init(coder:) has not been implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
func refreshAndSchedule() {
|
func refreshAndSchedule() {
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
print("refresh happened (interval \(self.interval)), self \(self.identifier.rawValue))")
|
print("refresh happened (interval \(interval)), self \(identifier.rawValue))")
|
||||||
#endif
|
#endif
|
||||||
let scriptResult = self.execute()
|
let scriptResult = execute()
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.title = scriptResult
|
self.title = scriptResult
|
||||||
self.forceHideConstraint.isActive = scriptResult == ""
|
self.forceHideConstraint.isActive = scriptResult == ""
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
print("did set new script result title \(scriptResult)")
|
print("did set new script result title \(scriptResult)")
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
DispatchQueue.appleScriptQueue.asyncAfter(deadline: .now() + self.interval) { [weak self] in
|
DispatchQueue.appleScriptQueue.asyncAfter(deadline: .now() + interval) { [weak self] in
|
||||||
self?.refreshAndSchedule()
|
self?.refreshAndSchedule()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func execute() -> String {
|
func execute() -> String {
|
||||||
var error: NSDictionary?
|
var error: NSDictionary?
|
||||||
let output = script.executeAndReturnError(&error)
|
let output = script.executeAndReturnError(&error)
|
||||||
@ -60,7 +60,6 @@ class AppleScriptTouchBarItem: CustomButtonTouchBarItem {
|
|||||||
}
|
}
|
||||||
return output.stringValue ?? ""
|
return output.stringValue ?? ""
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension DispatchQueue {
|
extension DispatchQueue {
|
||||||
|
|||||||
@ -9,69 +9,69 @@
|
|||||||
import Cocoa
|
import Cocoa
|
||||||
|
|
||||||
class CustomButtonTouchBarItem: NSCustomTouchBarItem, NSGestureRecognizerDelegate {
|
class CustomButtonTouchBarItem: NSCustomTouchBarItem, NSGestureRecognizerDelegate {
|
||||||
var tapClosure: (() -> ())?
|
var tapClosure: (() -> Void)?
|
||||||
var longTapClosure: (() -> ())?
|
var longTapClosure: (() -> Void)?
|
||||||
private var button: NSButton!
|
private var button: NSButton!
|
||||||
|
|
||||||
private var singleClick: NSClickGestureRecognizer!
|
private var singleClick: NSClickGestureRecognizer!
|
||||||
private var longClick: NSPressGestureRecognizer!
|
private var longClick: NSPressGestureRecognizer!
|
||||||
|
|
||||||
init(identifier: NSTouchBarItem.Identifier, title: String) {
|
init(identifier: NSTouchBarItem.Identifier, title: String) {
|
||||||
self.attributedTitle = title.defaultTouchbarAttributedString
|
attributedTitle = title.defaultTouchbarAttributedString
|
||||||
|
|
||||||
super.init(identifier: identifier)
|
super.init(identifier: identifier)
|
||||||
button = CustomHeightButton(title: title, target: nil, action: nil)
|
button = CustomHeightButton(title: title, target: nil, action: nil)
|
||||||
|
|
||||||
longClick = NSPressGestureRecognizer(target: self, action: #selector(handleGestureLong))
|
longClick = NSPressGestureRecognizer(target: self, action: #selector(handleGestureLong))
|
||||||
longClick.allowedTouchTypes = .direct
|
longClick.allowedTouchTypes = .direct
|
||||||
longClick.delegate = self
|
longClick.delegate = self
|
||||||
|
|
||||||
singleClick = NSClickGestureRecognizer(target: self, action: #selector(handleGestureSingle))
|
singleClick = NSClickGestureRecognizer(target: self, action: #selector(handleGestureSingle))
|
||||||
singleClick.allowedTouchTypes = .direct
|
singleClick.allowedTouchTypes = .direct
|
||||||
singleClick.delegate = self
|
singleClick.delegate = self
|
||||||
|
|
||||||
reinstallButton()
|
reinstallButton()
|
||||||
button.attributedTitle = attributedTitle
|
button.attributedTitle = attributedTitle
|
||||||
}
|
}
|
||||||
|
|
||||||
required init?(coder: NSCoder) {
|
required init?(coder _: NSCoder) {
|
||||||
fatalError("init(coder:) has not been implemented")
|
fatalError("init(coder:) has not been implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
var isBordered: Bool = true {
|
var isBordered: Bool = true {
|
||||||
didSet {
|
didSet {
|
||||||
reinstallButton()
|
reinstallButton()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var backgroundColor: NSColor? {
|
var backgroundColor: NSColor? {
|
||||||
didSet {
|
didSet {
|
||||||
reinstallButton()
|
reinstallButton()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var title: String {
|
var title: String {
|
||||||
get {
|
get {
|
||||||
return self.attributedTitle.string
|
return attributedTitle.string
|
||||||
}
|
}
|
||||||
set {
|
set {
|
||||||
self.attributedTitle = newValue.defaultTouchbarAttributedString
|
attributedTitle = newValue.defaultTouchbarAttributedString
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var attributedTitle: NSAttributedString {
|
var attributedTitle: NSAttributedString {
|
||||||
didSet {
|
didSet {
|
||||||
self.button?.imagePosition = attributedTitle.length > 0 ? .imageLeading : .imageOnly
|
button?.imagePosition = attributedTitle.length > 0 ? .imageLeading : .imageOnly
|
||||||
self.button?.attributedTitle = attributedTitle
|
button?.attributedTitle = attributedTitle
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var image: NSImage? {
|
var image: NSImage? {
|
||||||
didSet {
|
didSet {
|
||||||
button.image = image
|
button.image = image
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func reinstallButton() {
|
private func reinstallButton() {
|
||||||
let title = button.attributedTitle
|
let title = button.attributedTitle
|
||||||
let image = button.image
|
let image = button.image
|
||||||
@ -88,12 +88,12 @@ class CustomButtonTouchBarItem: NSCustomTouchBarItem, NSGestureRecognizerDelegat
|
|||||||
button.imageScaling = .scaleProportionallyDown
|
button.imageScaling = .scaleProportionallyDown
|
||||||
button.imageHugsTitle = true
|
button.imageHugsTitle = true
|
||||||
button.attributedTitle = title
|
button.attributedTitle = title
|
||||||
self.button?.imagePosition = title.length > 0 ? .imageLeading : .imageOnly
|
button?.imagePosition = title.length > 0 ? .imageLeading : .imageOnly
|
||||||
button.image = image
|
button.image = image
|
||||||
self.view = button
|
view = button
|
||||||
|
|
||||||
self.view.addGestureRecognizer(longClick)
|
view.addGestureRecognizer(longClick)
|
||||||
self.view.addGestureRecognizer(singleClick)
|
view.addGestureRecognizer(singleClick)
|
||||||
}
|
}
|
||||||
|
|
||||||
func gestureRecognizer(_ gestureRecognizer: NSGestureRecognizer, shouldRequireFailureOf otherGestureRecognizer: NSGestureRecognizer) -> Bool {
|
func gestureRecognizer(_ gestureRecognizer: NSGestureRecognizer, shouldRequireFailureOf otherGestureRecognizer: NSGestureRecognizer) -> Bool {
|
||||||
@ -102,19 +102,19 @@ class CustomButtonTouchBarItem: NSCustomTouchBarItem, NSGestureRecognizerDelegat
|
|||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func handleGestureSingle(gr: NSClickGestureRecognizer) {
|
@objc func handleGestureSingle(gr: NSClickGestureRecognizer) {
|
||||||
let hf: HapticFeedback = HapticFeedback()
|
let hf: HapticFeedback = HapticFeedback()
|
||||||
switch gr.state {
|
switch gr.state {
|
||||||
case .ended:
|
case .ended:
|
||||||
hf.tap(strong: 2)
|
hf.tap(strong: 2)
|
||||||
self.tapClosure?()
|
tapClosure?()
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func handleGestureLong(gr: NSPressGestureRecognizer) {
|
@objc func handleGestureLong(gr: NSPressGestureRecognizer) {
|
||||||
let hf: HapticFeedback = HapticFeedback()
|
let hf: HapticFeedback = HapticFeedback()
|
||||||
switch gr.state {
|
switch gr.state {
|
||||||
@ -130,57 +130,52 @@ class CustomButtonTouchBarItem: NSCustomTouchBarItem, NSGestureRecognizerDelegat
|
|||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class CustomHeightButton : NSButton {
|
class CustomHeightButton: NSButton {
|
||||||
|
|
||||||
override var intrinsicContentSize: NSSize {
|
override var intrinsicContentSize: NSSize {
|
||||||
var size = super.intrinsicContentSize
|
var size = super.intrinsicContentSize
|
||||||
size.height = 30
|
size.height = 30
|
||||||
return size
|
return size
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class CustomButtonCell: NSButtonCell {
|
class CustomButtonCell: NSButtonCell {
|
||||||
weak var parentItem: CustomButtonTouchBarItem?
|
weak var parentItem: CustomButtonTouchBarItem?
|
||||||
|
|
||||||
init(parentItem: CustomButtonTouchBarItem) {
|
init(parentItem: CustomButtonTouchBarItem) {
|
||||||
super.init(textCell: "")
|
super.init(textCell: "")
|
||||||
self.parentItem = parentItem
|
self.parentItem = parentItem
|
||||||
}
|
}
|
||||||
|
|
||||||
override func highlight(_ flag: Bool, withFrame cellFrame: NSRect, in controlView: NSView) {
|
override func highlight(_ flag: Bool, withFrame cellFrame: NSRect, in controlView: NSView) {
|
||||||
super.highlight(flag, withFrame: cellFrame, in: controlView)
|
super.highlight(flag, withFrame: cellFrame, in: controlView)
|
||||||
if !self.isBordered {
|
if !isBordered {
|
||||||
if flag {
|
if flag {
|
||||||
self.setAttributedTitle(self.attributedTitle, withColor: .lightGray)
|
setAttributedTitle(attributedTitle, withColor: .lightGray)
|
||||||
} else if let parentItem = self.parentItem {
|
} else if let parentItem = self.parentItem {
|
||||||
self.attributedTitle = parentItem.attributedTitle
|
attributedTitle = parentItem.attributedTitle
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
required init(coder: NSCoder) {
|
required init(coder _: NSCoder) {
|
||||||
fatalError("init(coder:) has not been implemented")
|
fatalError("init(coder:) has not been implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
func setAttributedTitle(_ title: NSAttributedString, withColor color: NSColor) {
|
func setAttributedTitle(_ title: NSAttributedString, withColor color: NSColor) {
|
||||||
let attrTitle = NSMutableAttributedString(attributedString: title)
|
let attrTitle = NSMutableAttributedString(attributedString: title)
|
||||||
attrTitle.addAttributes([.foregroundColor: color], range: NSRange(location: 0, length: attrTitle.length))
|
attrTitle.addAttributes([.foregroundColor: color], range: NSRange(location: 0, length: attrTitle.length))
|
||||||
self.attributedTitle = attrTitle
|
attributedTitle = attrTitle
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension String {
|
extension String {
|
||||||
var defaultTouchbarAttributedString: NSAttributedString {
|
var defaultTouchbarAttributedString: NSAttributedString {
|
||||||
let attrTitle = NSMutableAttributedString(string: self, attributes: [.foregroundColor: NSColor.white, .font: NSFont.systemFont(ofSize: 15, weight: .regular), .baselineOffset: 1])
|
let attrTitle = NSMutableAttributedString(string: self, attributes: [.foregroundColor: NSColor.white, .font: NSFont.systemFont(ofSize: 15, weight: .regular), .baselineOffset: 1])
|
||||||
attrTitle.setAlignment(.center, range: NSRange(location: 0, length: self.count))
|
attrTitle.setAlignment(.center, range: NSRange(location: 0, length: count))
|
||||||
return attrTitle
|
return attrTitle
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -9,34 +9,34 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
class CustomSliderCell: NSSliderCell {
|
class CustomSliderCell: NSSliderCell {
|
||||||
var knobImage:NSImage!
|
var knobImage: NSImage!
|
||||||
private var _currentKnobRect:NSRect!
|
private var _currentKnobRect: NSRect!
|
||||||
private var _barRect:NSRect!
|
private var _barRect: NSRect!
|
||||||
|
|
||||||
required init(coder aDecoder: NSCoder) {
|
required init(coder aDecoder: NSCoder) {
|
||||||
super.init(coder: aDecoder)
|
super.init(coder: aDecoder)
|
||||||
}
|
}
|
||||||
|
|
||||||
override init() {
|
override init() {
|
||||||
super.init()
|
super.init()
|
||||||
}
|
}
|
||||||
|
|
||||||
init(knob:NSImage?) {
|
init(knob: NSImage?) {
|
||||||
knobImage = knob;
|
knobImage = knob
|
||||||
super.init()
|
super.init()
|
||||||
}
|
}
|
||||||
|
|
||||||
override func drawKnob(_ knobRect: NSRect) {
|
override func drawKnob(_ knobRect: NSRect) {
|
||||||
if (knobImage == nil) {
|
if knobImage == nil {
|
||||||
super.drawKnob(knobRect)
|
super.drawKnob(knobRect)
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_currentKnobRect = knobRect;
|
_currentKnobRect = knobRect
|
||||||
drawBar(inside: _barRect, flipped: true)
|
drawBar(inside: _barRect, flipped: true)
|
||||||
|
|
||||||
let x = (knobRect.origin.x * (_barRect.size.width - (knobImage.size.width - knobRect.size.width)) / _barRect.size.width)+1;
|
let x = (knobRect.origin.x * (_barRect.size.width - (knobImage.size.width - knobRect.size.width)) / _barRect.size.width) + 1
|
||||||
let y = knobRect.origin.y+3
|
let y = knobRect.origin.y + 3
|
||||||
|
|
||||||
knobImage.draw(
|
knobImage.draw(
|
||||||
at: NSPoint(x: x, y: y),
|
at: NSPoint(x: x, y: y),
|
||||||
@ -45,63 +45,62 @@ class CustomSliderCell: NSSliderCell {
|
|||||||
fraction: 1
|
fraction: 1
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func drawBar(inside aRect: NSRect, flipped: Bool) {
|
override func drawBar(inside aRect: NSRect, flipped _: Bool) {
|
||||||
_barRect = aRect
|
_barRect = aRect
|
||||||
|
|
||||||
let barRadius = CGFloat(2)
|
let barRadius = CGFloat(2)
|
||||||
|
|
||||||
var bgRect = aRect
|
var bgRect = aRect
|
||||||
bgRect.size.height = CGFloat(4)
|
bgRect.size.height = CGFloat(4)
|
||||||
|
|
||||||
let bg = NSBezierPath(roundedRect: bgRect, xRadius: barRadius, yRadius: barRadius)
|
let bg = NSBezierPath(roundedRect: bgRect, xRadius: barRadius, yRadius: barRadius)
|
||||||
NSColor.lightGray.setFill()
|
NSColor.lightGray.setFill()
|
||||||
bg.fill()
|
bg.fill()
|
||||||
|
|
||||||
var activeRect = bgRect
|
var activeRect = bgRect
|
||||||
|
|
||||||
activeRect.size.width = CGFloat((Double(bgRect.size.width) / (self.maxValue - self.minValue)) * self.doubleValue)
|
activeRect.size.width = CGFloat((Double(bgRect.size.width) / (maxValue - minValue)) * doubleValue)
|
||||||
let active = NSBezierPath(roundedRect: activeRect, xRadius: barRadius, yRadius: barRadius)
|
let active = NSBezierPath(roundedRect: activeRect, xRadius: barRadius, yRadius: barRadius)
|
||||||
NSColor.darkGray.setFill()
|
NSColor.darkGray.setFill()
|
||||||
active.fill()
|
active.fill()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class CustomSlider:NSSlider {
|
class CustomSlider: NSSlider {
|
||||||
|
var currentValue: CGFloat = 0
|
||||||
var currentValue:CGFloat = 0
|
|
||||||
|
|
||||||
override func setNeedsDisplay(_ invalidRect: NSRect) {
|
override func setNeedsDisplay(_ invalidRect: NSRect) {
|
||||||
super.setNeedsDisplay(invalidRect)
|
super.setNeedsDisplay(invalidRect)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func awakeFromNib() {
|
override func awakeFromNib() {
|
||||||
super.awakeFromNib()
|
super.awakeFromNib()
|
||||||
if ((self.cell?.isKind(of: CustomSliderCell.self)) == false) {
|
if (cell?.isKind(of: CustomSliderCell.self)) == false {
|
||||||
let cell:CustomSliderCell = CustomSliderCell()
|
let cell: CustomSliderCell = CustomSliderCell()
|
||||||
self.cell = cell
|
self.cell = cell
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
convenience init(knob:NSImage) {
|
convenience init(knob: NSImage) {
|
||||||
self.init()
|
self.init()
|
||||||
self.cell = CustomSliderCell(knob: knob)
|
cell = CustomSliderCell(knob: knob)
|
||||||
}
|
}
|
||||||
|
|
||||||
required init?(coder: NSCoder) {
|
required init?(coder: NSCoder) {
|
||||||
super.init(coder: coder)
|
super.init(coder: coder)
|
||||||
}
|
}
|
||||||
|
|
||||||
override init(frame frameRect: NSRect) {
|
override init(frame frameRect: NSRect) {
|
||||||
super.init(frame: frameRect)
|
super.init(frame: frameRect)
|
||||||
}
|
}
|
||||||
|
|
||||||
func knobImage() -> NSImage {
|
func knobImage() -> NSImage {
|
||||||
let cell = self.cell as! CustomSliderCell
|
let cell = self.cell as! CustomSliderCell
|
||||||
return cell.knobImage
|
return cell.knobImage
|
||||||
}
|
}
|
||||||
|
|
||||||
func setKnobImage(image:NSImage) {
|
func setKnobImage(image: NSImage) {
|
||||||
let cell = self.cell as! CustomSliderCell
|
let cell = self.cell as! CustomSliderCell
|
||||||
cell.knobImage = image
|
cell.knobImage = image
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,9 +11,7 @@ import Foundation
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
extension String {
|
extension String {
|
||||||
|
|
||||||
var ifNotEmpty: String? {
|
var ifNotEmpty: String? {
|
||||||
return self.count > 0 ? self : nil
|
return count > 0 ? self : nil
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import IOKit
|
|||||||
|
|
||||||
class HapticFeedback {
|
class HapticFeedback {
|
||||||
private var actuatorRef: CFTypeRef?
|
private var actuatorRef: CFTypeRef?
|
||||||
private var deviceID: UInt64 = 0x200000001000000
|
private var deviceID: UInt64 = 0x200_0000_0100_0000
|
||||||
private var error: IOReturn = 0
|
private var error: IOReturn = 0
|
||||||
|
|
||||||
// Don't know how to do strong is enum one of
|
// Don't know how to do strong is enum one of
|
||||||
@ -24,7 +24,7 @@ class HapticFeedback {
|
|||||||
// 16 nothing
|
// 16 nothing
|
||||||
// you can get a plist `otool -s __TEXT __tpad_act_plist /System/Library/PrivateFrameworks/MultitouchSupport.framework/Versions/Current/MultitouchSupport|tail -n +3|awk -F'\t' '{print $2}'|xxd -r -p`
|
// you can get a plist `otool -s __TEXT __tpad_act_plist /System/Library/PrivateFrameworks/MultitouchSupport.framework/Versions/Current/MultitouchSupport|tail -n +3|awk -F'\t' '{print $2}'|xxd -r -p`
|
||||||
|
|
||||||
func tap(strong:Int32) -> Void {
|
func tap(strong: Int32) {
|
||||||
actuatorRef = MTActuatorCreateFromDeviceID(deviceID).takeRetainedValue()
|
actuatorRef = MTActuatorCreateFromDeviceID(deviceID).takeRetainedValue()
|
||||||
|
|
||||||
guard actuatorRef != nil else {
|
guard actuatorRef != nil else {
|
||||||
@ -53,5 +53,3 @@ class HapticFeedback {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -19,7 +19,7 @@
|
|||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>0.18.5</string>
|
<string>0.18.5</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>79</string>
|
<string>82</string>
|
||||||
<key>LSApplicationCategoryType</key>
|
<key>LSApplicationCategoryType</key>
|
||||||
<string>public.app-category.utilities</string>
|
<string>public.app-category.utilities</string>
|
||||||
<key>LSMinimumSystemVersion</key>
|
<key>LSMinimumSystemVersion</key>
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
import Foundation
|
|
||||||
import AppKit
|
import AppKit
|
||||||
|
import Foundation
|
||||||
|
|
||||||
extension Data {
|
extension Data {
|
||||||
func barItemDefinitions() -> [BarItemDefinition]? {
|
func barItemDefinitions() -> [BarItemDefinition]? {
|
||||||
return try? JSONDecoder().decode([BarItemDefinition].self, from: self.utf8string!.stripComments().data(using: .utf8)!)
|
return try? JSONDecoder().decode([BarItemDefinition].self, from: utf8string!.stripComments().data(using: .utf8)!)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -12,24 +12,24 @@ struct BarItemDefinition: Decodable {
|
|||||||
let action: ActionType
|
let action: ActionType
|
||||||
let longAction: LongActionType
|
let longAction: LongActionType
|
||||||
let additionalParameters: [GeneralParameters.CodingKeys: GeneralParameter]
|
let additionalParameters: [GeneralParameters.CodingKeys: GeneralParameter]
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
private enum CodingKeys: String, CodingKey {
|
||||||
case type
|
case type
|
||||||
}
|
}
|
||||||
|
|
||||||
init(type: ItemType, action: ActionType, longAction: LongActionType, additionalParameters: [GeneralParameters.CodingKeys:GeneralParameter]) {
|
init(type: ItemType, action: ActionType, longAction: LongActionType, additionalParameters: [GeneralParameters.CodingKeys: GeneralParameter]) {
|
||||||
self.type = type
|
self.type = type
|
||||||
self.action = action
|
self.action = action
|
||||||
self.longAction = longAction
|
self.longAction = longAction
|
||||||
self.additionalParameters = additionalParameters
|
self.additionalParameters = additionalParameters
|
||||||
}
|
}
|
||||||
|
|
||||||
init(from decoder: Decoder) throws {
|
init(from decoder: Decoder) throws {
|
||||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
let type = try container.decode(String.self, forKey: .type)
|
let type = try container.decode(String.self, forKey: .type)
|
||||||
let parametersDecoder = SupportedTypesHolder.sharedInstance.lookup(by: type)
|
let parametersDecoder = SupportedTypesHolder.sharedInstance.lookup(by: type)
|
||||||
var additionalParameters = try GeneralParameters(from: decoder).parameters
|
var additionalParameters = try GeneralParameters(from: decoder).parameters
|
||||||
|
|
||||||
if let result = try? parametersDecoder(decoder),
|
if let result = try? parametersDecoder(decoder),
|
||||||
case let (itemType, action, longAction, parameters) = result {
|
case let (itemType, action, longAction, parameters) = result {
|
||||||
parameters.forEach { additionalParameters[$0] = $1 }
|
parameters.forEach { additionalParameters[$0] = $1 }
|
||||||
@ -38,68 +38,127 @@ struct BarItemDefinition: Decodable {
|
|||||||
self.init(type: .staticButton(title: "unknown"), action: .none, longAction: .none, additionalParameters: additionalParameters)
|
self.init(type: .staticButton(title: "unknown"), action: .none, longAction: .none, additionalParameters: additionalParameters)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class SupportedTypesHolder {
|
class SupportedTypesHolder {
|
||||||
typealias ParametersDecoder = (Decoder) throws ->(item: ItemType, action: ActionType, longAction: LongActionType, parameters: [GeneralParameters.CodingKeys: GeneralParameter])
|
typealias ParametersDecoder = (Decoder) throws -> (item: ItemType, action: ActionType, longAction: LongActionType, parameters: [GeneralParameters.CodingKeys: GeneralParameter])
|
||||||
private var supportedTypes: [String: ParametersDecoder] = [
|
private var supportedTypes: [String: ParametersDecoder] = [
|
||||||
"escape": { _ in return (item: .staticButton(title: "esc"), action: .keyPress(keycode: 53), longAction: .none, parameters: [.align: .align(.left)]) },
|
"escape": { _ in (
|
||||||
|
item: .staticButton(title: "esc"),
|
||||||
"delete": { _ in return (item: .staticButton(title: "del"), action: .keyPress(keycode: 117), longAction: .none, parameters: [:])},
|
action: .keyPress(keycode: 53),
|
||||||
|
longAction: .none,
|
||||||
|
parameters: [.align: .align(.left)]
|
||||||
|
) },
|
||||||
|
|
||||||
|
"delete": { _ in (
|
||||||
|
item: .staticButton(title: "del"),
|
||||||
|
action: .keyPress(keycode: 117),
|
||||||
|
longAction: .none,
|
||||||
|
parameters: [:]
|
||||||
|
) },
|
||||||
|
|
||||||
"brightnessUp": { _ in
|
"brightnessUp": { _ in
|
||||||
let imageParameter = GeneralParameter.image(source: #imageLiteral(resourceName: "brightnessUp"))
|
let imageParameter = GeneralParameter.image(source: #imageLiteral(resourceName: "brightnessUp"))
|
||||||
return (item: .staticButton(title: ""), action: .keyPress(keycode: 144), longAction: .none, parameters: [.image: imageParameter])
|
return (
|
||||||
|
item: .staticButton(title: ""),
|
||||||
|
action: .keyPress(keycode: 144),
|
||||||
|
longAction: .none,
|
||||||
|
parameters: [.image: imageParameter]
|
||||||
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
"brightnessDown": { _ in
|
"brightnessDown": { _ in
|
||||||
let imageParameter = GeneralParameter.image(source: #imageLiteral(resourceName: "brightnessDown"))
|
let imageParameter = GeneralParameter.image(source: #imageLiteral(resourceName: "brightnessDown"))
|
||||||
return (item: .staticButton(title: ""), action: .keyPress(keycode: 145), longAction: .none, parameters: [.image: imageParameter])
|
return (
|
||||||
|
item: .staticButton(title: ""),
|
||||||
|
action: .keyPress(keycode: 145),
|
||||||
|
longAction: .none,
|
||||||
|
parameters: [.image: imageParameter]
|
||||||
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
"illuminationUp": { _ in
|
"illuminationUp": { _ in
|
||||||
let imageParameter = GeneralParameter.image(source: #imageLiteral(resourceName: "ill_up"))
|
let imageParameter = GeneralParameter.image(source: #imageLiteral(resourceName: "ill_up"))
|
||||||
return (item: .staticButton(title: ""), action: .hidKey(keycode: NX_KEYTYPE_ILLUMINATION_UP), longAction: .none, parameters: [.image: imageParameter])
|
return (
|
||||||
|
item: .staticButton(title: ""),
|
||||||
|
action: .hidKey(keycode: NX_KEYTYPE_ILLUMINATION_UP),
|
||||||
|
longAction: .none,
|
||||||
|
parameters: [.image: imageParameter]
|
||||||
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
"illuminationDown": { _ in
|
"illuminationDown": { _ in
|
||||||
let imageParameter = GeneralParameter.image(source: #imageLiteral(resourceName: "ill_down"))
|
let imageParameter = GeneralParameter.image(source: #imageLiteral(resourceName: "ill_down"))
|
||||||
return (item: .staticButton(title: ""), action: .hidKey(keycode: NX_KEYTYPE_ILLUMINATION_DOWN), longAction: .none, parameters: [.image: imageParameter])
|
return (
|
||||||
|
item: .staticButton(title: ""),
|
||||||
|
action: .hidKey(keycode: NX_KEYTYPE_ILLUMINATION_DOWN),
|
||||||
|
longAction: .none,
|
||||||
|
parameters: [.image: imageParameter]
|
||||||
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
"volumeDown": { _ in
|
"volumeDown": { _ in
|
||||||
let imageParameter = GeneralParameter.image(source: NSImage(named: NSImage.touchBarVolumeDownTemplateName)!)
|
let imageParameter = GeneralParameter.image(source: NSImage(named: NSImage.touchBarVolumeDownTemplateName)!)
|
||||||
return (item: .staticButton(title: ""), action: .hidKey(keycode: NX_KEYTYPE_SOUND_DOWN), longAction: .none, parameters: [.image: imageParameter])
|
return (
|
||||||
|
item: .staticButton(title: ""),
|
||||||
|
action: .hidKey(keycode: NX_KEYTYPE_SOUND_DOWN),
|
||||||
|
longAction: .none,
|
||||||
|
parameters: [.image: imageParameter]
|
||||||
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
"volumeUp": { _ in
|
"volumeUp": { _ in
|
||||||
let imageParameter = GeneralParameter.image(source: NSImage(named: NSImage.touchBarVolumeUpTemplateName)!)
|
let imageParameter = GeneralParameter.image(source: NSImage(named: NSImage.touchBarVolumeUpTemplateName)!)
|
||||||
return (item: .staticButton(title: ""), action: .hidKey(keycode: NX_KEYTYPE_SOUND_UP), longAction: .none, parameters: [.image: imageParameter])
|
return (
|
||||||
|
item: .staticButton(title: ""),
|
||||||
|
action: .hidKey(keycode: NX_KEYTYPE_SOUND_UP),
|
||||||
|
longAction: .none,
|
||||||
|
parameters: [.image: imageParameter]
|
||||||
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
"mute": { _ in
|
"mute": { _ in
|
||||||
let imageParameter = GeneralParameter.image(source: NSImage(named: NSImage.touchBarAudioOutputMuteTemplateName)!)
|
let imageParameter = GeneralParameter.image(source: NSImage(named: NSImage.touchBarAudioOutputMuteTemplateName)!)
|
||||||
return (item: .staticButton(title: ""), action: .hidKey(keycode: NX_KEYTYPE_MUTE), longAction: .none, parameters: [.image: imageParameter])
|
return (
|
||||||
|
item: .staticButton(title: ""),
|
||||||
|
action: .hidKey(keycode: NX_KEYTYPE_MUTE),
|
||||||
|
longAction: .none,
|
||||||
|
parameters: [.image: imageParameter]
|
||||||
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
"previous": { _ in
|
"previous": { _ in
|
||||||
let imageParameter = GeneralParameter.image(source: NSImage(named: NSImage.touchBarRewindTemplateName)!)
|
let imageParameter = GeneralParameter.image(source: NSImage(named: NSImage.touchBarRewindTemplateName)!)
|
||||||
return (item: .staticButton(title: ""), action: .hidKey(keycode: NX_KEYTYPE_PREVIOUS), longAction: .none, parameters: [.image: imageParameter])
|
return (
|
||||||
|
item: .staticButton(title: ""),
|
||||||
|
action: .hidKey(keycode: NX_KEYTYPE_PREVIOUS),
|
||||||
|
longAction: .none,
|
||||||
|
parameters: [.image: imageParameter]
|
||||||
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
"play": { _ in
|
"play": { _ in
|
||||||
let imageParameter = GeneralParameter.image(source: NSImage(named: NSImage.touchBarPlayPauseTemplateName)!)
|
let imageParameter = GeneralParameter.image(source: NSImage(named: NSImage.touchBarPlayPauseTemplateName)!)
|
||||||
return (item: .staticButton(title: ""), action: .hidKey(keycode: NX_KEYTYPE_PLAY), longAction: .none, parameters: [.image: imageParameter])
|
return (
|
||||||
|
item: .staticButton(title: ""),
|
||||||
|
action: .hidKey(keycode: NX_KEYTYPE_PLAY),
|
||||||
|
longAction: .none,
|
||||||
|
parameters: [.image: imageParameter]
|
||||||
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
"next": { _ in
|
"next": { _ in
|
||||||
let imageParameter = GeneralParameter.image(source: NSImage(named: NSImage.touchBarFastForwardTemplateName)!)
|
let imageParameter = GeneralParameter.image(source: NSImage(named: NSImage.touchBarFastForwardTemplateName)!)
|
||||||
return (item: .staticButton(title: ""), action: .hidKey(keycode: NX_KEYTYPE_NEXT), longAction: .none, parameters: [.image: imageParameter])
|
return (
|
||||||
|
item: .staticButton(title: ""),
|
||||||
|
action: .hidKey(keycode: NX_KEYTYPE_NEXT),
|
||||||
|
longAction: .none,
|
||||||
|
parameters: [.image: imageParameter]
|
||||||
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
"weather": { decoder in
|
"weather": { decoder in
|
||||||
enum CodingKeys: String, CodingKey { case refreshInterval; case units; case api_key ; case icon_type }
|
enum CodingKeys: String, CodingKey { case refreshInterval; case units; case api_key; case icon_type }
|
||||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
let interval = try container.decodeIfPresent(Double.self, forKey: .refreshInterval)
|
let interval = try container.decodeIfPresent(Double.self, forKey: .refreshInterval)
|
||||||
let units = try container.decodeIfPresent(String.self, forKey: .units)
|
let units = try container.decodeIfPresent(String.self, forKey: .units)
|
||||||
@ -107,9 +166,14 @@ class SupportedTypesHolder {
|
|||||||
let icon_type = try container.decodeIfPresent(String.self, forKey: .icon_type)
|
let icon_type = try container.decodeIfPresent(String.self, forKey: .icon_type)
|
||||||
let action = try ActionType(from: decoder)
|
let action = try ActionType(from: decoder)
|
||||||
let longAction = try LongActionType(from: decoder)
|
let longAction = try LongActionType(from: decoder)
|
||||||
return (item: .weather(interval: interval ?? 1800.00, units: units ?? "metric", api_key: api_key ?? "32c4256d09a4c52b38aecddba7a078f6", icon_type: icon_type ?? "text"), action: action, longAction: longAction, parameters: [:])
|
return (
|
||||||
|
item: .weather(interval: interval ?? 1800.00, units: units ?? "metric", api_key: api_key ?? "32c4256d09a4c52b38aecddba7a078f6", icon_type: icon_type ?? "text"),
|
||||||
|
action,
|
||||||
|
longAction,
|
||||||
|
parameters: [:]
|
||||||
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
"currency": { decoder in
|
"currency": { decoder in
|
||||||
enum CodingKeys: String, CodingKey { case refreshInterval; case from; case to }
|
enum CodingKeys: String, CodingKey { case refreshInterval; case from; case to }
|
||||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
@ -118,42 +182,87 @@ class SupportedTypesHolder {
|
|||||||
let to = try container.decodeIfPresent(String.self, forKey: .to)
|
let to = try container.decodeIfPresent(String.self, forKey: .to)
|
||||||
let action = try ActionType(from: decoder)
|
let action = try ActionType(from: decoder)
|
||||||
let longAction = try LongActionType(from: decoder)
|
let longAction = try LongActionType(from: decoder)
|
||||||
return (item: .currency(interval: interval ?? 600.00, from: from ?? "RUB", to: to ?? "USD"), action: action, longAction: longAction, parameters: [:])
|
return (
|
||||||
|
item: .currency(interval: interval ?? 600.00, from: from ?? "RUB", to: to ?? "USD"),
|
||||||
|
action,
|
||||||
|
longAction,
|
||||||
|
parameters: [:]
|
||||||
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
"dock": { decoder in
|
"dock": { _ in
|
||||||
return (item: .dock(), action: .none, longAction: .none, parameters: [:])
|
(
|
||||||
|
item: .dock(),
|
||||||
|
action: .none,
|
||||||
|
longAction: .none,
|
||||||
|
parameters: [:]
|
||||||
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
"inputsource": { decoder in
|
"inputsource": { _ in
|
||||||
return (item: .inputsource(), action: .none, longAction: .none, parameters: [:])
|
(
|
||||||
|
item: .inputsource(),
|
||||||
|
action: .none,
|
||||||
|
longAction: .none,
|
||||||
|
parameters: [:]
|
||||||
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
"volume": { decoder in
|
"volume": { decoder in
|
||||||
enum CodingKeys: String, CodingKey { case image }
|
enum CodingKeys: String, CodingKey { case image }
|
||||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
if var img = try container.decodeIfPresent(Source.self, forKey: .image) {
|
if var img = try container.decodeIfPresent(Source.self, forKey: .image) {
|
||||||
return (item: .volume(), action: .none, longAction: .none, parameters: [.image: .image(source: img)])
|
return (
|
||||||
|
item: .volume(),
|
||||||
|
action: .none,
|
||||||
|
longAction: .none,
|
||||||
|
parameters: [.image: .image(source: img)]
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
return (item: .volume(), action: .none, longAction: .none, parameters: [:])
|
return (
|
||||||
|
item: .volume(),
|
||||||
|
action: .none,
|
||||||
|
longAction: .none,
|
||||||
|
parameters: [:]
|
||||||
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
"brightness": { decoder in
|
"brightness": { decoder in
|
||||||
enum CodingKeys: String, CodingKey { case refreshInterval; case image }
|
enum CodingKeys: String, CodingKey { case refreshInterval; case image }
|
||||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
let interval = try container.decodeIfPresent(Double.self, forKey: .refreshInterval)
|
let interval = try container.decodeIfPresent(Double.self, forKey: .refreshInterval)
|
||||||
if var img = try container.decodeIfPresent(Source.self, forKey: .image) {
|
if var img = try container.decodeIfPresent(Source.self, forKey: .image) {
|
||||||
return (item: .brightness(refreshInterval: interval ?? 0.5), action: .none, longAction: .none, parameters: [.image: .image(source: img)])
|
return (
|
||||||
|
item: .brightness(refreshInterval: interval ?? 0.5),
|
||||||
|
action: .none,
|
||||||
|
longAction: .none,
|
||||||
|
parameters: [.image: .image(source: img)]
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
return (item: .brightness(refreshInterval: interval ?? 0.5), action: .none, longAction: .none, parameters: [:])
|
return (
|
||||||
|
item: .brightness(refreshInterval: interval ?? 0.5),
|
||||||
|
action: .none,
|
||||||
|
longAction: .none,
|
||||||
|
parameters: [:]
|
||||||
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
"sleep": { _ in return (item: .staticButton(title: "☕️"), action: .shellScript(executable: "/usr/bin/pmset", parameters: ["sleepnow"]), longAction: .none, parameters: [:]) },
|
"sleep": { _ in (
|
||||||
|
item: .staticButton(title: "☕️"),
|
||||||
"displaySleep": { _ in return (item: .staticButton(title: "☕️"), action: .shellScript(executable: "/usr/bin/pmset", parameters: ["displaysleepnow"]), longAction: .none, parameters: [:])},
|
action: .shellScript(executable: "/usr/bin/pmset", parameters: ["sleepnow"]),
|
||||||
|
longAction: .none,
|
||||||
|
parameters: [:]
|
||||||
|
) },
|
||||||
|
|
||||||
|
"displaySleep": { _ in (
|
||||||
|
item: .staticButton(title: "☕️"),
|
||||||
|
action: .shellScript(executable: "/usr/bin/pmset", parameters: ["displaysleepnow"]),
|
||||||
|
longAction: .none,
|
||||||
|
parameters: [:]
|
||||||
|
) },
|
||||||
|
|
||||||
"music": { decoder in
|
"music": { decoder in
|
||||||
enum CodingKeys: String, CodingKey { case refreshInterval }
|
enum CodingKeys: String, CodingKey { case refreshInterval }
|
||||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
@ -165,7 +274,7 @@ class SupportedTypesHolder {
|
|||||||
parameters: [:]
|
parameters: [:]
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
"group": { decoder in
|
"group": { decoder in
|
||||||
enum CodingKeys: CodingKey { case items }
|
enum CodingKeys: CodingKey { case items }
|
||||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
@ -177,42 +286,46 @@ class SupportedTypesHolder {
|
|||||||
parameters: [:]
|
parameters: [:]
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
"nightShift": {_ in
|
"nightShift": { _ in
|
||||||
return (
|
(
|
||||||
item: .nightShift(),
|
item: .nightShift(),
|
||||||
action: .none,
|
action: .none,
|
||||||
longAction: .none,
|
longAction: .none,
|
||||||
parameters: [:]
|
parameters: [:]
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
"dnd": { _ in
|
"dnd": { _ in
|
||||||
return (
|
(
|
||||||
item: .dnd(),
|
item: .dnd(),
|
||||||
action: .none,
|
action: .none,
|
||||||
longAction: .none,
|
longAction: .none,
|
||||||
parameters: [:]
|
parameters: [:]
|
||||||
)
|
)
|
||||||
|
},
|
||||||
}
|
|
||||||
]
|
]
|
||||||
|
|
||||||
static let sharedInstance = SupportedTypesHolder()
|
static let sharedInstance = SupportedTypesHolder()
|
||||||
|
|
||||||
func lookup(by type: String) -> ParametersDecoder {
|
func lookup(by type: String) -> ParametersDecoder {
|
||||||
return supportedTypes[type] ?? { decoder in
|
return supportedTypes[type] ?? { decoder in
|
||||||
return (item: try ItemType(from: decoder), action: try ActionType(from: decoder), longAction: try LongActionType(from: decoder), parameters: [:])
|
(item: try ItemType(from: decoder), action: try ActionType(from: decoder), longAction: try LongActionType(from: decoder), parameters: [:])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func register(typename: String, decoder: @escaping ParametersDecoder) {
|
func register(typename: String, decoder: @escaping ParametersDecoder) {
|
||||||
supportedTypes[typename] = decoder
|
supportedTypes[typename] = decoder
|
||||||
}
|
}
|
||||||
|
|
||||||
func register(typename: String, item: ItemType, action: ActionType, longAction: LongActionType) {
|
func register(typename: String, item: ItemType, action: ActionType, longAction: LongActionType) {
|
||||||
register(typename: typename) { _ in
|
register(typename: typename) { _ in
|
||||||
return (item: item, action: action, longAction: longAction, parameters: [:])
|
(
|
||||||
|
item: item,
|
||||||
|
action,
|
||||||
|
longAction,
|
||||||
|
parameters: [:]
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -232,7 +345,7 @@ enum ItemType: Decodable {
|
|||||||
case groupBar(items: [BarItemDefinition])
|
case groupBar(items: [BarItemDefinition])
|
||||||
case nightShift()
|
case nightShift()
|
||||||
case dnd()
|
case dnd()
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
private enum CodingKeys: String, CodingKey {
|
||||||
case type
|
case type
|
||||||
case title
|
case title
|
||||||
@ -249,7 +362,7 @@ enum ItemType: Decodable {
|
|||||||
case longUrl
|
case longUrl
|
||||||
case items
|
case items
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ItemTypeRaw: String, Decodable {
|
enum ItemTypeRaw: String, Decodable {
|
||||||
case staticButton
|
case staticButton
|
||||||
case appleScriptTitledButton
|
case appleScriptTitledButton
|
||||||
@ -266,65 +379,64 @@ enum ItemType: Decodable {
|
|||||||
case nightShift
|
case nightShift
|
||||||
case dnd
|
case dnd
|
||||||
}
|
}
|
||||||
|
|
||||||
init(from decoder: Decoder) throws {
|
init(from decoder: Decoder) throws {
|
||||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
let type = try container.decode(ItemTypeRaw.self, forKey: .type)
|
let type = try container.decode(ItemTypeRaw.self, forKey: .type)
|
||||||
switch type {
|
switch type {
|
||||||
|
|
||||||
case .appleScriptTitledButton:
|
case .appleScriptTitledButton:
|
||||||
let source = try container.decode(Source.self, forKey: .source)
|
let source = try container.decode(Source.self, forKey: .source)
|
||||||
let interval = try container.decodeIfPresent(Double.self, forKey: .refreshInterval) ?? 1800.0
|
let interval = try container.decodeIfPresent(Double.self, forKey: .refreshInterval) ?? 1800.0
|
||||||
self = .appleScriptTitledButton(source: source, refreshInterval: interval)
|
self = .appleScriptTitledButton(source: source, refreshInterval: interval)
|
||||||
|
|
||||||
case .staticButton:
|
case .staticButton:
|
||||||
let title = try container.decode(String.self, forKey: .title)
|
let title = try container.decode(String.self, forKey: .title)
|
||||||
self = .staticButton(title: title)
|
self = .staticButton(title: title)
|
||||||
|
|
||||||
case .timeButton:
|
case .timeButton:
|
||||||
let template = try container.decodeIfPresent(String.self, forKey: .formatTemplate) ?? "HH:mm"
|
let template = try container.decodeIfPresent(String.self, forKey: .formatTemplate) ?? "HH:mm"
|
||||||
self = .timeButton(formatTemplate: template)
|
self = .timeButton(formatTemplate: template)
|
||||||
|
|
||||||
case .battery:
|
case .battery:
|
||||||
self = .battery()
|
self = .battery()
|
||||||
|
|
||||||
case .dock:
|
case .dock:
|
||||||
self = .dock()
|
self = .dock()
|
||||||
|
|
||||||
case .volume:
|
case .volume:
|
||||||
self = .volume()
|
self = .volume()
|
||||||
|
|
||||||
case .brightness:
|
case .brightness:
|
||||||
let interval = try container.decodeIfPresent(Double.self, forKey: .refreshInterval) ?? 0.5
|
let interval = try container.decodeIfPresent(Double.self, forKey: .refreshInterval) ?? 0.5
|
||||||
self = .brightness(refreshInterval: interval)
|
self = .brightness(refreshInterval: interval)
|
||||||
|
|
||||||
case .weather:
|
case .weather:
|
||||||
let interval = try container.decodeIfPresent(Double.self, forKey: .refreshInterval) ?? 1800.0
|
let interval = try container.decodeIfPresent(Double.self, forKey: .refreshInterval) ?? 1800.0
|
||||||
let units = try container.decodeIfPresent(String.self, forKey: .units) ?? "metric"
|
let units = try container.decodeIfPresent(String.self, forKey: .units) ?? "metric"
|
||||||
let api_key = try container.decodeIfPresent(String.self, forKey: .api_key) ?? "32c4256d09a4c52b38aecddba7a078f6"
|
let api_key = try container.decodeIfPresent(String.self, forKey: .api_key) ?? "32c4256d09a4c52b38aecddba7a078f6"
|
||||||
let icon_type = try container.decodeIfPresent(String.self, forKey: .icon_type) ?? "text"
|
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)
|
self = .weather(interval: interval, units: units, api_key: api_key, icon_type: icon_type)
|
||||||
|
|
||||||
case .currency:
|
case .currency:
|
||||||
let interval = try container.decodeIfPresent(Double.self, forKey: .refreshInterval) ?? 600.0
|
let interval = try container.decodeIfPresent(Double.self, forKey: .refreshInterval) ?? 600.0
|
||||||
let from = try container.decodeIfPresent(String.self, forKey: .from) ?? "RUB"
|
let from = try container.decodeIfPresent(String.self, forKey: .from) ?? "RUB"
|
||||||
let to = try container.decodeIfPresent(String.self, forKey: .to) ?? "USD"
|
let to = try container.decodeIfPresent(String.self, forKey: .to) ?? "USD"
|
||||||
self = .currency(interval: interval, from: from, to: to)
|
self = .currency(interval: interval, from: from, to: to)
|
||||||
|
|
||||||
case .inputsource:
|
case .inputsource:
|
||||||
self = .inputsource()
|
self = .inputsource()
|
||||||
|
|
||||||
case .music:
|
case .music:
|
||||||
let interval = try container.decodeIfPresent(Double.self, forKey: .refreshInterval) ?? 1800.0
|
let interval = try container.decodeIfPresent(Double.self, forKey: .refreshInterval) ?? 1800.0
|
||||||
self = .music(interval: interval)
|
self = .music(interval: interval)
|
||||||
|
|
||||||
case .groupBar:
|
case .groupBar:
|
||||||
let items = try container.decode([BarItemDefinition].self, forKey: .items)
|
let items = try container.decode([BarItemDefinition].self, forKey: .items)
|
||||||
self = .groupBar(items: items)
|
self = .groupBar(items: items)
|
||||||
|
|
||||||
case .nightShift:
|
case .nightShift:
|
||||||
self = .nightShift()
|
self = .nightShift()
|
||||||
|
|
||||||
case .dnd:
|
case .dnd:
|
||||||
self = .dnd()
|
self = .dnd()
|
||||||
}
|
}
|
||||||
@ -337,9 +449,9 @@ enum ActionType: Decodable {
|
|||||||
case keyPress(keycode: Int)
|
case keyPress(keycode: Int)
|
||||||
case appleScript(source: SourceProtocol)
|
case appleScript(source: SourceProtocol)
|
||||||
case shellScript(executable: String, parameters: [String])
|
case shellScript(executable: String, parameters: [String])
|
||||||
case custom(closure: ()->())
|
case custom(closure: () -> Void)
|
||||||
case openUrl(url: String)
|
case openUrl(url: String)
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
private enum CodingKeys: String, CodingKey {
|
||||||
case action
|
case action
|
||||||
case keycode
|
case keycode
|
||||||
@ -348,7 +460,7 @@ enum ActionType: Decodable {
|
|||||||
case shellArguments
|
case shellArguments
|
||||||
case url
|
case url
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum ActionTypeRaw: String, Decodable {
|
private enum ActionTypeRaw: String, Decodable {
|
||||||
case hidKey
|
case hidKey
|
||||||
case keyPress
|
case keyPress
|
||||||
@ -356,49 +468,48 @@ enum ActionType: Decodable {
|
|||||||
case shellScript
|
case shellScript
|
||||||
case openUrl
|
case openUrl
|
||||||
}
|
}
|
||||||
|
|
||||||
init(from decoder: Decoder) throws {
|
init(from decoder: Decoder) throws {
|
||||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
let type = try container.decodeIfPresent(ActionTypeRaw.self, forKey: .action)
|
let type = try container.decodeIfPresent(ActionTypeRaw.self, forKey: .action)
|
||||||
|
|
||||||
switch type {
|
switch type {
|
||||||
case .some(.hidKey):
|
case .some(.hidKey):
|
||||||
let keycode = try container.decode(Int32.self, forKey: .keycode)
|
let keycode = try container.decode(Int32.self, forKey: .keycode)
|
||||||
self = .hidKey(keycode: keycode)
|
self = .hidKey(keycode: keycode)
|
||||||
|
|
||||||
case .some(.keyPress):
|
case .some(.keyPress):
|
||||||
let keycode = try container.decode(Int.self, forKey: .keycode)
|
let keycode = try container.decode(Int.self, forKey: .keycode)
|
||||||
self = .keyPress(keycode: keycode)
|
self = .keyPress(keycode: keycode)
|
||||||
|
|
||||||
case .some(.appleScript):
|
case .some(.appleScript):
|
||||||
let source = try container.decode(Source.self, forKey: .actionAppleScript)
|
let source = try container.decode(Source.self, forKey: .actionAppleScript)
|
||||||
self = .appleScript(source: source)
|
self = .appleScript(source: source)
|
||||||
|
|
||||||
case .some(.shellScript):
|
case .some(.shellScript):
|
||||||
let executable = try container.decode(String.self, forKey: .executablePath)
|
let executable = try container.decode(String.self, forKey: .executablePath)
|
||||||
let parameters = try container.decodeIfPresent([String].self, forKey: .shellArguments) ?? []
|
let parameters = try container.decodeIfPresent([String].self, forKey: .shellArguments) ?? []
|
||||||
self = .shellScript(executable: executable, parameters: parameters)
|
self = .shellScript(executable: executable, parameters: parameters)
|
||||||
|
|
||||||
case .some(.openUrl):
|
case .some(.openUrl):
|
||||||
let url = try container.decode(String.self, forKey: .url)
|
let url = try container.decode(String.self, forKey: .url)
|
||||||
self = .openUrl(url: url)
|
self = .openUrl(url: url)
|
||||||
|
|
||||||
case .none:
|
case .none:
|
||||||
self = .none
|
self = .none
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
enum LongActionType: Decodable {
|
enum LongActionType: Decodable {
|
||||||
case none
|
case none
|
||||||
case hidKey(keycode: Int32)
|
case hidKey(keycode: Int32)
|
||||||
case keyPress(keycode: Int)
|
case keyPress(keycode: Int)
|
||||||
case appleScript(source: SourceProtocol)
|
case appleScript(source: SourceProtocol)
|
||||||
case shellScript(executable: String, parameters: [String])
|
case shellScript(executable: String, parameters: [String])
|
||||||
case custom(closure: ()->())
|
case custom(closure: () -> Void)
|
||||||
case openUrl(url: String)
|
case openUrl(url: String)
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
private enum CodingKeys: String, CodingKey {
|
||||||
case longAction
|
case longAction
|
||||||
case longKeycode
|
case longKeycode
|
||||||
@ -407,7 +518,7 @@ enum LongActionType: Decodable {
|
|||||||
case longShellArguments
|
case longShellArguments
|
||||||
case longUrl
|
case longUrl
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum LongActionTypeRaw: String, Decodable {
|
private enum LongActionTypeRaw: String, Decodable {
|
||||||
case hidKey
|
case hidKey
|
||||||
case keyPress
|
case keyPress
|
||||||
@ -415,52 +526,51 @@ enum LongActionType: Decodable {
|
|||||||
case shellScript
|
case shellScript
|
||||||
case openUrl
|
case openUrl
|
||||||
}
|
}
|
||||||
|
|
||||||
init(from decoder: Decoder) throws {
|
init(from decoder: Decoder) throws {
|
||||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
let longType = try container.decodeIfPresent(LongActionTypeRaw.self, forKey: .longAction)
|
let longType = try container.decodeIfPresent(LongActionTypeRaw.self, forKey: .longAction)
|
||||||
|
|
||||||
switch longType {
|
switch longType {
|
||||||
case .some(.hidKey):
|
case .some(.hidKey):
|
||||||
let keycode = try container.decode(Int32.self, forKey: .longKeycode)
|
let keycode = try container.decode(Int32.self, forKey: .longKeycode)
|
||||||
self = .hidKey(keycode: keycode)
|
self = .hidKey(keycode: keycode)
|
||||||
|
|
||||||
case .some(.keyPress):
|
case .some(.keyPress):
|
||||||
let keycode = try container.decode(Int.self, forKey: .longKeycode)
|
let keycode = try container.decode(Int.self, forKey: .longKeycode)
|
||||||
self = .keyPress(keycode: keycode)
|
self = .keyPress(keycode: keycode)
|
||||||
|
|
||||||
case .some(.appleScript):
|
case .some(.appleScript):
|
||||||
let source = try container.decode(Source.self, forKey: .longActionAppleScript)
|
let source = try container.decode(Source.self, forKey: .longActionAppleScript)
|
||||||
self = .appleScript(source: source)
|
self = .appleScript(source: source)
|
||||||
|
|
||||||
case .some(.shellScript):
|
case .some(.shellScript):
|
||||||
let executable = try container.decode(String.self, forKey: .longExecutablePath)
|
let executable = try container.decode(String.self, forKey: .longExecutablePath)
|
||||||
let parameters = try container.decodeIfPresent([String].self, forKey: .longShellArguments) ?? []
|
let parameters = try container.decodeIfPresent([String].self, forKey: .longShellArguments) ?? []
|
||||||
self = .shellScript(executable: executable, parameters: parameters)
|
self = .shellScript(executable: executable, parameters: parameters)
|
||||||
|
|
||||||
case .some(.openUrl):
|
case .some(.openUrl):
|
||||||
let longUrl = try container.decode(String.self, forKey: .longUrl)
|
let longUrl = try container.decode(String.self, forKey: .longUrl)
|
||||||
self = .openUrl(url: longUrl)
|
self = .openUrl(url: longUrl)
|
||||||
|
|
||||||
case .none:
|
case .none:
|
||||||
self = .none
|
self = .none
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
enum GeneralParameter {
|
enum GeneralParameter {
|
||||||
case width(_: CGFloat)
|
case width(_: CGFloat)
|
||||||
case image(source: SourceProtocol)
|
case image(source: SourceProtocol)
|
||||||
case align(_: Align)
|
case align(_: Align)
|
||||||
case bordered(_: Bool)
|
case bordered(_: Bool)
|
||||||
case background(_:NSColor)
|
case background(_: NSColor)
|
||||||
case title(_:String)
|
case title(_: String)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct GeneralParameters: Decodable {
|
struct GeneralParameters: Decodable {
|
||||||
let parameters: [GeneralParameters.CodingKeys: GeneralParameter]
|
let parameters: [GeneralParameters.CodingKeys: GeneralParameter]
|
||||||
|
|
||||||
enum CodingKeys: String, CodingKey {
|
enum CodingKeys: String, CodingKey {
|
||||||
case width
|
case width
|
||||||
case image
|
case image
|
||||||
@ -469,34 +579,34 @@ struct GeneralParameters: Decodable {
|
|||||||
case background
|
case background
|
||||||
case title
|
case title
|
||||||
}
|
}
|
||||||
|
|
||||||
init(from decoder: Decoder) throws {
|
init(from decoder: Decoder) throws {
|
||||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
var result: [GeneralParameters.CodingKeys: GeneralParameter] = [:]
|
var result: [GeneralParameters.CodingKeys: GeneralParameter] = [:]
|
||||||
|
|
||||||
if let value = try container.decodeIfPresent(CGFloat.self, forKey: .width) {
|
if let value = try container.decodeIfPresent(CGFloat.self, forKey: .width) {
|
||||||
result[.width] = .width(value)
|
result[.width] = .width(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
if let imageSource = try container.decodeIfPresent(Source.self, forKey: .image) {
|
if let imageSource = try container.decodeIfPresent(Source.self, forKey: .image) {
|
||||||
result[.image] = .image(source: imageSource)
|
result[.image] = .image(source: imageSource)
|
||||||
}
|
}
|
||||||
|
|
||||||
let align = try container.decodeIfPresent(Align.self, forKey: .align) ?? .center
|
let align = try container.decodeIfPresent(Align.self, forKey: .align) ?? .center
|
||||||
result[.align] = .align(align)
|
result[.align] = .align(align)
|
||||||
|
|
||||||
if let borderedFlag = try container.decodeIfPresent(Bool.self, forKey: .bordered) {
|
if let borderedFlag = try container.decodeIfPresent(Bool.self, forKey: .bordered) {
|
||||||
result[.bordered] = .bordered(borderedFlag)
|
result[.bordered] = .bordered(borderedFlag)
|
||||||
}
|
}
|
||||||
|
|
||||||
if let backgroundColor = try container.decodeIfPresent(String.self, forKey: .background)?.hexColor {
|
if let backgroundColor = try container.decodeIfPresent(String.self, forKey: .background)?.hexColor {
|
||||||
result[.background] = .background(backgroundColor)
|
result[.background] = .background(backgroundColor)
|
||||||
}
|
}
|
||||||
|
|
||||||
if let title = try container.decodeIfPresent(String.self, forKey: .title) {
|
if let title = try container.decodeIfPresent(String.self, forKey: .title) {
|
||||||
result[.title] = .title(title)
|
result[.title] = .title(title)
|
||||||
}
|
}
|
||||||
|
|
||||||
parameters = result
|
parameters = result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -512,35 +622,35 @@ struct Source: Decodable, SourceProtocol {
|
|||||||
let filePath: String?
|
let filePath: String?
|
||||||
let base64: String?
|
let base64: String?
|
||||||
let inline: String?
|
let inline: String?
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
private enum CodingKeys: String, CodingKey {
|
||||||
case filePath
|
case filePath
|
||||||
case base64
|
case base64
|
||||||
case inline
|
case inline
|
||||||
}
|
}
|
||||||
|
|
||||||
var data: Data? {
|
var data: Data? {
|
||||||
return base64?.base64Data ?? inline?.data(using: .utf8) ?? filePath?.fileData
|
return base64?.base64Data ?? inline?.data(using: .utf8) ?? filePath?.fileData
|
||||||
}
|
}
|
||||||
|
|
||||||
var string: String? {
|
var string: String? {
|
||||||
return inline ?? filePath?.fileString
|
return inline ?? filePath?.fileString
|
||||||
}
|
}
|
||||||
|
|
||||||
var image: NSImage? {
|
var image: NSImage? {
|
||||||
return data?.image
|
return data?.image
|
||||||
}
|
}
|
||||||
|
|
||||||
var appleScript: NSAppleScript? {
|
var appleScript: NSAppleScript? {
|
||||||
return filePath?.fileURL.appleScript ?? self.string?.appleScript
|
return filePath?.fileURL.appleScript ?? string?.appleScript
|
||||||
}
|
}
|
||||||
|
|
||||||
private init(filePath: String?, base64: String?, inline: String?) {
|
private init(filePath: String?, base64: String?, inline: String?) {
|
||||||
self.filePath = filePath
|
self.filePath = filePath
|
||||||
self.base64 = base64
|
self.base64 = base64
|
||||||
self.inline = inline
|
self.inline = inline
|
||||||
}
|
}
|
||||||
|
|
||||||
init(filePath: String) {
|
init(filePath: String) {
|
||||||
self.init(filePath: filePath, base64: nil, inline: nil)
|
self.init(filePath: filePath, base64: nil, inline: nil)
|
||||||
}
|
}
|
||||||
@ -550,15 +660,15 @@ extension NSImage: SourceProtocol {
|
|||||||
var data: Data? {
|
var data: Data? {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var string: String? {
|
var string: String? {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var image: NSImage? {
|
var image: NSImage? {
|
||||||
return self
|
return self
|
||||||
}
|
}
|
||||||
|
|
||||||
var appleScript: NSAppleScript? {
|
var appleScript: NSAppleScript? {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -568,23 +678,22 @@ extension String {
|
|||||||
var base64Data: Data? {
|
var base64Data: Data? {
|
||||||
return Data(base64Encoded: self)
|
return Data(base64Encoded: self)
|
||||||
}
|
}
|
||||||
|
|
||||||
var fileData: Data? {
|
var fileData: Data? {
|
||||||
return try? Data(contentsOf: URL(fileURLWithPath: self))
|
return try? Data(contentsOf: URL(fileURLWithPath: self))
|
||||||
}
|
}
|
||||||
|
|
||||||
var fileString: String? {
|
var fileString: String? {
|
||||||
var encoding: String.Encoding = .utf8
|
var encoding: String.Encoding = .utf8
|
||||||
return try? String(contentsOfFile: self, usedEncoding: &encoding)
|
return try? String(contentsOfFile: self, usedEncoding: &encoding)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension Data {
|
extension Data {
|
||||||
var utf8string: String? {
|
var utf8string: String? {
|
||||||
return String(data: self, encoding: .utf8)
|
return String(data: self, encoding: .utf8)
|
||||||
}
|
}
|
||||||
|
|
||||||
var image: NSImage? {
|
var image: NSImage? {
|
||||||
return NSImage(data: self)?.resize(maxSize: NSSize(width: 24, height: 24))
|
return NSImage(data: self)?.resize(maxSize: NSSize(width: 24, height: 24))
|
||||||
}
|
}
|
||||||
@ -600,7 +709,7 @@ extension String {
|
|||||||
var fileURL: URL {
|
var fileURL: URL {
|
||||||
return URL(fileURLWithPath: self)
|
return URL(fileURLWithPath: self)
|
||||||
}
|
}
|
||||||
|
|
||||||
var appleScript: NSAppleScript? {
|
var appleScript: NSAppleScript? {
|
||||||
return NSAppleScript(source: self)
|
return NSAppleScript(source: self)
|
||||||
}
|
}
|
||||||
@ -608,7 +717,7 @@ extension String {
|
|||||||
|
|
||||||
extension URL {
|
extension URL {
|
||||||
var appleScript: NSAppleScript? {
|
var appleScript: NSAppleScript? {
|
||||||
guard FileManager.default.fileExists(atPath: self.path) else { return nil }
|
guard FileManager.default.fileExists(atPath: path) else { return nil }
|
||||||
return NSAppleScript(contentsOf: self, error: nil)
|
return NSAppleScript(contentsOf: self, error: nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,7 +18,7 @@ struct GenericKeyPress: KeyPress {
|
|||||||
}
|
}
|
||||||
|
|
||||||
extension KeyPress {
|
extension KeyPress {
|
||||||
func send () {
|
func send() {
|
||||||
let src = CGEventSource(stateID: .hidSystemState)
|
let src = CGEventSource(stateID: .hidSystemState)
|
||||||
let keyDown = CGEvent(keyboardEventSource: src, virtualKey: keyCode, keyDown: true)
|
let keyDown = CGEvent(keyboardEventSource: src, virtualKey: keyCode, keyDown: true)
|
||||||
let keyUp = CGEvent(keyboardEventSource: src, virtualKey: keyCode, keyDown: false)
|
let keyUp = CGEvent(keyboardEventSource: src, virtualKey: keyCode, keyDown: false)
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import Foundation
|
|||||||
class ScrollViewItem: NSCustomTouchBarItem, NSGestureRecognizerDelegate {
|
class ScrollViewItem: NSCustomTouchBarItem, NSGestureRecognizerDelegate {
|
||||||
var twofingersPrev: CGFloat = 0.0
|
var twofingersPrev: CGFloat = 0.0
|
||||||
var threefingersPrev: CGFloat = 0.0
|
var threefingersPrev: CGFloat = 0.0
|
||||||
|
|
||||||
init(identifier: NSTouchBarItem.Identifier, items: [NSTouchBarItem]) {
|
init(identifier: NSTouchBarItem.Identifier, items: [NSTouchBarItem]) {
|
||||||
super.init(identifier: identifier)
|
super.init(identifier: identifier)
|
||||||
let views = items.compactMap { $0.view }
|
let views = items.compactMap { $0.view }
|
||||||
@ -12,31 +12,31 @@ class ScrollViewItem: NSCustomTouchBarItem, NSGestureRecognizerDelegate {
|
|||||||
stackView.orientation = .horizontal
|
stackView.orientation = .horizontal
|
||||||
let scrollView = NSScrollView(frame: CGRect(origin: .zero, size: stackView.fittingSize))
|
let scrollView = NSScrollView(frame: CGRect(origin: .zero, size: stackView.fittingSize))
|
||||||
scrollView.documentView = stackView
|
scrollView.documentView = stackView
|
||||||
self.view = scrollView
|
view = scrollView
|
||||||
|
|
||||||
let twofingers = NSPanGestureRecognizer(target: self, action: #selector(twofingersHandler(_:)))
|
let twofingers = NSPanGestureRecognizer(target: self, action: #selector(twofingersHandler(_:)))
|
||||||
twofingers.allowedTouchTypes = .direct
|
twofingers.allowedTouchTypes = .direct
|
||||||
twofingers.numberOfTouchesRequired = 2
|
twofingers.numberOfTouchesRequired = 2
|
||||||
self.view.addGestureRecognizer(twofingers)
|
view.addGestureRecognizer(twofingers)
|
||||||
|
|
||||||
let threefingers = NSPanGestureRecognizer(target: self, action: #selector(threefingersHandler(_:)))
|
let threefingers = NSPanGestureRecognizer(target: self, action: #selector(threefingersHandler(_:)))
|
||||||
threefingers.allowedTouchTypes = .direct
|
threefingers.allowedTouchTypes = .direct
|
||||||
threefingers.numberOfTouchesRequired = 3
|
threefingers.numberOfTouchesRequired = 3
|
||||||
self.view.addGestureRecognizer(threefingers)
|
view.addGestureRecognizer(threefingers)
|
||||||
}
|
}
|
||||||
|
|
||||||
required init?(coder: NSCoder) {
|
required init?(coder _: NSCoder) {
|
||||||
fatalError("init(coder:) has not been implemented")
|
fatalError("init(coder:) has not been implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func twofingersHandler(_ sender: NSGestureRecognizer?) { // Volume
|
@objc func twofingersHandler(_ sender: NSGestureRecognizer?) { // Volume
|
||||||
let position = (sender?.location(in: sender?.view).x)!
|
let position = (sender?.location(in: sender?.view).x)!
|
||||||
|
|
||||||
switch sender!.state {
|
switch sender!.state {
|
||||||
case .began:
|
case .began:
|
||||||
twofingersPrev = position
|
twofingersPrev = position
|
||||||
case .changed:
|
case .changed:
|
||||||
if (((position-twofingersPrev) > 10) || ((twofingersPrev-position) > 10)) {
|
if ((position - twofingersPrev) > 10) || ((twofingersPrev - position) > 10) {
|
||||||
if position > twofingersPrev {
|
if position > twofingersPrev {
|
||||||
HIDPostAuxKey(NX_KEYTYPE_SOUND_UP)
|
HIDPostAuxKey(NX_KEYTYPE_SOUND_UP)
|
||||||
} else if position < twofingersPrev {
|
} else if position < twofingersPrev {
|
||||||
@ -50,15 +50,15 @@ class ScrollViewItem: NSCustomTouchBarItem, NSGestureRecognizerDelegate {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func threefingersHandler(_ sender: NSGestureRecognizer?) { // Brightness
|
@objc func threefingersHandler(_ sender: NSGestureRecognizer?) { // Brightness
|
||||||
let position = (sender?.location(in: sender?.view).x)!
|
let position = (sender?.location(in: sender?.view).x)!
|
||||||
|
|
||||||
switch sender!.state {
|
switch sender!.state {
|
||||||
case .began:
|
case .began:
|
||||||
threefingersPrev = position
|
threefingersPrev = position
|
||||||
case .changed:
|
case .changed:
|
||||||
if (((position-threefingersPrev) > 15) || ((threefingersPrev-position) > 15)) {
|
if ((position - threefingersPrev) > 15) || ((threefingersPrev - position) > 15) {
|
||||||
if position > threefingersPrev {
|
if position > threefingersPrev {
|
||||||
GenericKeyPress(keyCode: CGKeyCode(144)).send()
|
GenericKeyPress(keyCode: CGKeyCode(144)).send()
|
||||||
} else if position < threefingersPrev {
|
} else if position < threefingersPrev {
|
||||||
|
|||||||
@ -13,12 +13,12 @@ extension String {
|
|||||||
func trim() -> String {
|
func trim() -> String {
|
||||||
return self.trimmingCharacters(in: NSCharacterSet.whitespaces)
|
return self.trimmingCharacters(in: NSCharacterSet.whitespaces)
|
||||||
}
|
}
|
||||||
|
|
||||||
func stripComments() -> String {
|
func stripComments() -> String {
|
||||||
// ((\s|,)\/\*[\s\S]*?\*\/)|(( |, ")\/\/.*)
|
// ((\s|,)\/\*[\s\S]*?\*\/)|(( |, ")\/\/.*)
|
||||||
return self.replacingOccurrences(of: "((\\s|,)\\/\\*[\\s\\S]*?\\*\\/)|(( |, \\\")\\/\\/.*)", with: "", options: .regularExpression)
|
return self.replacingOccurrences(of: "((\\s|,)\\/\\*[\\s\\S]*?\\*\\/)|(( |, \\\")\\/\\/.*)", with: "", options: .regularExpression)
|
||||||
}
|
}
|
||||||
|
|
||||||
var hexColor: NSColor? {
|
var hexColor: NSColor? {
|
||||||
let hex = trimmingCharacters(in: CharacterSet.alphanumerics.inverted)
|
let hex = trimmingCharacters(in: CharacterSet.alphanumerics.inverted)
|
||||||
var int = UInt32()
|
var int = UInt32()
|
||||||
@ -45,7 +45,7 @@ extension NSImage {
|
|||||||
let imageHeight = Float(self.size.height)
|
let imageHeight = Float(self.size.height)
|
||||||
let maxWidth = Float(maxSize.width)
|
let maxWidth = Float(maxSize.width)
|
||||||
let maxHeight = Float(maxSize.height)
|
let maxHeight = Float(maxSize.height)
|
||||||
|
|
||||||
// Get ratio (landscape or portrait)
|
// Get ratio (landscape or portrait)
|
||||||
if (imageWidth > imageHeight) {
|
if (imageWidth > imageHeight) {
|
||||||
// Landscape
|
// Landscape
|
||||||
@ -55,27 +55,27 @@ extension NSImage {
|
|||||||
// Portrait
|
// Portrait
|
||||||
ratio = maxHeight / imageHeight;
|
ratio = maxHeight / imageHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate new size based on the ratio
|
// Calculate new size based on the ratio
|
||||||
let newWidth = imageWidth * ratio
|
let newWidth = imageWidth * ratio
|
||||||
let newHeight = imageHeight * ratio
|
let newHeight = imageHeight * ratio
|
||||||
|
|
||||||
// Create a new NSSize object with the newly calculated size
|
// Create a new NSSize object with the newly calculated size
|
||||||
let newSize:NSSize = NSSize(width: Int(newWidth), height: Int(newHeight))
|
let newSize:NSSize = NSSize(width: Int(newWidth), height: Int(newHeight))
|
||||||
|
|
||||||
// Cast the NSImage to a CGImage
|
// Cast the NSImage to a CGImage
|
||||||
var imageRect:NSRect = NSMakeRect(0, 0, self.size.width, self.size.height)
|
var imageRect:NSRect = NSMakeRect(0, 0, self.size.width, self.size.height)
|
||||||
let imageRef = self.cgImage(forProposedRect: &imageRect, context: nil, hints: nil)
|
let imageRef = self.cgImage(forProposedRect: &imageRect, context: nil, hints: nil)
|
||||||
|
|
||||||
// Create NSImage from the CGImage using the new size
|
// Create NSImage from the CGImage using the new size
|
||||||
let imageWithNewSize = NSImage(cgImage: imageRef!, size: newSize)
|
let imageWithNewSize = NSImage(cgImage: imageRef!, size: newSize)
|
||||||
|
|
||||||
// Return the new image
|
// Return the new image
|
||||||
return imageWithNewSize
|
return imageWithNewSize
|
||||||
}
|
}
|
||||||
|
|
||||||
func rotateByDegreess(degrees:CGFloat) -> NSImage {
|
func rotateByDegreess(degrees:CGFloat) -> NSImage {
|
||||||
|
|
||||||
var imageBounds = NSZeroRect ; imageBounds.size = self.size
|
var imageBounds = NSZeroRect ; imageBounds.size = self.size
|
||||||
let pathBounds = NSBezierPath(rect: imageBounds)
|
let pathBounds = NSBezierPath(rect: imageBounds)
|
||||||
var transform = NSAffineTransform()
|
var transform = NSAffineTransform()
|
||||||
@ -83,11 +83,11 @@ extension NSImage {
|
|||||||
pathBounds.transform(using: transform as AffineTransform)
|
pathBounds.transform(using: transform as AffineTransform)
|
||||||
let rotatedBounds:NSRect = NSMakeRect(NSZeroPoint.x, NSZeroPoint.y , self.size.width, self.size.height )
|
let rotatedBounds:NSRect = NSMakeRect(NSZeroPoint.x, NSZeroPoint.y , self.size.width, self.size.height )
|
||||||
let rotatedImage = NSImage(size: rotatedBounds.size)
|
let rotatedImage = NSImage(size: rotatedBounds.size)
|
||||||
|
|
||||||
//Center the image within the rotated bounds
|
//Center the image within the rotated bounds
|
||||||
imageBounds.origin.x = NSMidX(rotatedBounds) - (NSWidth(imageBounds) / 2)
|
imageBounds.origin.x = NSMidX(rotatedBounds) - (NSWidth(imageBounds) / 2)
|
||||||
imageBounds.origin.y = NSMidY(rotatedBounds) - (NSHeight(imageBounds) / 2)
|
imageBounds.origin.y = NSMidY(rotatedBounds) - (NSHeight(imageBounds) / 2)
|
||||||
|
|
||||||
// Start a new transform
|
// Start a new transform
|
||||||
transform = NSAffineTransform()
|
transform = NSAffineTransform()
|
||||||
// Move coordinate system to the center (since we want to rotate around the center)
|
// Move coordinate system to the center (since we want to rotate around the center)
|
||||||
@ -100,7 +100,7 @@ extension NSImage {
|
|||||||
transform.concat()
|
transform.concat()
|
||||||
self.draw(in: imageBounds, from: NSZeroRect, operation: NSCompositingOperation.copy, fraction: 1.0)
|
self.draw(in: imageBounds, from: NSZeroRect, operation: NSCompositingOperation.copy, fraction: 1.0)
|
||||||
rotatedImage.unlockFocus()
|
rotatedImage.unlockFocus()
|
||||||
|
|
||||||
return rotatedImage
|
return rotatedImage
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
// Copyright © 2018 Anton Palgunov. All rights reserved.
|
// Copyright © 2018 Anton Palgunov. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
func presentSystemModal(_ touchBar: NSTouchBar!, systemTrayItemIdentifier identifier: NSTouchBarItem.Identifier!) -> Void {
|
func presentSystemModal(_ touchBar: NSTouchBar!, systemTrayItemIdentifier identifier: NSTouchBarItem.Identifier!) {
|
||||||
if #available(OSX 10.14, *) {
|
if #available(OSX 10.14, *) {
|
||||||
NSTouchBar.presentSystemModalTouchBar(touchBar, systemTrayItemIdentifier: identifier)
|
NSTouchBar.presentSystemModalTouchBar(touchBar, systemTrayItemIdentifier: identifier)
|
||||||
} else {
|
} else {
|
||||||
@ -14,7 +14,7 @@ func presentSystemModal(_ touchBar: NSTouchBar!, systemTrayItemIdentifier identi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func presentSystemModal(_ touchBar: NSTouchBar!, placement: Int64, systemTrayItemIdentifier identifier: NSTouchBarItem.Identifier!) -> Void {
|
func presentSystemModal(_ touchBar: NSTouchBar!, placement: Int64, systemTrayItemIdentifier identifier: NSTouchBarItem.Identifier!) {
|
||||||
if #available(OSX 10.14, *) {
|
if #available(OSX 10.14, *) {
|
||||||
NSTouchBar.presentSystemModalTouchBar(touchBar, placement: placement, systemTrayItemIdentifier: identifier)
|
NSTouchBar.presentSystemModalTouchBar(touchBar, placement: placement, systemTrayItemIdentifier: identifier)
|
||||||
} else {
|
} else {
|
||||||
@ -22,7 +22,7 @@ func presentSystemModal(_ touchBar: NSTouchBar!, placement: Int64, systemTrayIte
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func minimizeSystemModal(_ touchBar: NSTouchBar!) -> Void {
|
func minimizeSystemModal(_ touchBar: NSTouchBar!) {
|
||||||
if #available(OSX 10.14, *) {
|
if #available(OSX 10.14, *) {
|
||||||
NSTouchBar.minimizeSystemModalTouchBar(touchBar)
|
NSTouchBar.minimizeSystemModalTouchBar(touchBar)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -8,11 +8,10 @@
|
|||||||
import Cocoa
|
import Cocoa
|
||||||
|
|
||||||
class AppScrubberTouchBarItem: NSCustomTouchBarItem, NSScrubberDelegate, NSScrubberDataSource {
|
class AppScrubberTouchBarItem: NSCustomTouchBarItem, NSScrubberDelegate, NSScrubberDataSource {
|
||||||
|
|
||||||
private var scrubber: NSScrubber!
|
private var scrubber: NSScrubber!
|
||||||
|
|
||||||
private let hf: HapticFeedback = HapticFeedback()
|
private let hf: HapticFeedback = HapticFeedback()
|
||||||
|
|
||||||
private var timer: Timer!
|
private var timer: Timer!
|
||||||
private var ticks: Int = 0
|
private var ticks: Int = 0
|
||||||
private let minTicks: Int = 5
|
private let minTicks: Int = 5
|
||||||
@ -21,24 +20,22 @@ class AppScrubberTouchBarItem: NSCustomTouchBarItem, NSScrubberDelegate, NSScrub
|
|||||||
|
|
||||||
private var persistentAppIdentifiers: [String] = []
|
private var persistentAppIdentifiers: [String] = []
|
||||||
private var runningAppsIdentifiers: [String] = []
|
private var runningAppsIdentifiers: [String] = []
|
||||||
|
|
||||||
private var frontmostApplicationIdentifier: String? {
|
private var frontmostApplicationIdentifier: String? {
|
||||||
get {
|
guard let frontmostId = NSWorkspace.shared.frontmostApplication?.bundleIdentifier else { return nil }
|
||||||
guard let frontmostId = NSWorkspace.shared.frontmostApplication?.bundleIdentifier else { return nil }
|
return frontmostId
|
||||||
return frontmostId
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private var applications: [DockItem] = []
|
private var applications: [DockItem] = []
|
||||||
|
|
||||||
override init(identifier: NSTouchBarItem.Identifier) {
|
override init(identifier: NSTouchBarItem.Identifier) {
|
||||||
super.init(identifier: identifier)
|
super.init(identifier: identifier)
|
||||||
|
|
||||||
scrubber = NSScrubber();
|
scrubber = NSScrubber()
|
||||||
scrubber.delegate = self
|
scrubber.delegate = self
|
||||||
scrubber.dataSource = self
|
scrubber.dataSource = self
|
||||||
scrubber.mode = .free // .fixed
|
scrubber.mode = .free // .fixed
|
||||||
let layout = NSScrubberFlowLayout();
|
let layout = NSScrubberFlowLayout()
|
||||||
layout.itemSize = NSSize(width: 36, height: 32)
|
layout.itemSize = NSSize(width: 36, height: 32)
|
||||||
layout.itemSpacing = 2
|
layout.itemSpacing = 2
|
||||||
scrubber.scrubberLayout = layout
|
scrubber.scrubberLayout = layout
|
||||||
@ -46,35 +43,35 @@ class AppScrubberTouchBarItem: NSCustomTouchBarItem, NSScrubberDelegate, NSScrub
|
|||||||
scrubber.showsAdditionalContentIndicators = true
|
scrubber.showsAdditionalContentIndicators = true
|
||||||
|
|
||||||
view = scrubber
|
view = scrubber
|
||||||
|
|
||||||
scrubber.register(NSScrubberImageItemView.self, forItemIdentifier: NSUserInterfaceItemIdentifier(rawValue: "ScrubberApplicationsItemReuseIdentifier"))
|
scrubber.register(NSScrubberImageItemView.self, forItemIdentifier: NSUserInterfaceItemIdentifier(rawValue: "ScrubberApplicationsItemReuseIdentifier"))
|
||||||
|
|
||||||
NSWorkspace.shared.notificationCenter.addObserver(self, selector: #selector(activeApplicationChanged), name: NSWorkspace.didLaunchApplicationNotification, object: nil)
|
NSWorkspace.shared.notificationCenter.addObserver(self, selector: #selector(activeApplicationChanged), name: NSWorkspace.didLaunchApplicationNotification, object: nil)
|
||||||
NSWorkspace.shared.notificationCenter.addObserver(self, selector: #selector(activeApplicationChanged), name: NSWorkspace.didTerminateApplicationNotification, object: nil)
|
NSWorkspace.shared.notificationCenter.addObserver(self, selector: #selector(activeApplicationChanged), name: NSWorkspace.didTerminateApplicationNotification, object: nil)
|
||||||
NSWorkspace.shared.notificationCenter.addObserver(self, selector: #selector(activeApplicationChanged), name: NSWorkspace.didActivateApplicationNotification, object: nil)
|
NSWorkspace.shared.notificationCenter.addObserver(self, selector: #selector(activeApplicationChanged), name: NSWorkspace.didActivateApplicationNotification, object: nil)
|
||||||
|
|
||||||
if let persistent = UserDefaults.standard.stringArray(forKey: "com.toxblh.mtmr.dock.persistent") {
|
if let persistent = UserDefaults.standard.stringArray(forKey: "com.toxblh.mtmr.dock.persistent") {
|
||||||
self.persistentAppIdentifiers = persistent
|
persistentAppIdentifiers = persistent
|
||||||
}
|
}
|
||||||
|
|
||||||
updateRunningApplication()
|
updateRunningApplication()
|
||||||
}
|
}
|
||||||
|
|
||||||
required init?(coder: NSCoder) {
|
required init?(coder _: NSCoder) {
|
||||||
fatalError("init(coder:) has not been implemented")
|
fatalError("init(coder:) has not been implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func activeApplicationChanged(n: Notification) {
|
@objc func activeApplicationChanged(n _: Notification) {
|
||||||
updateRunningApplication()
|
updateRunningApplication()
|
||||||
}
|
}
|
||||||
|
|
||||||
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
|
override func observeValue(forKeyPath _: String?, of _: Any?, change _: [NSKeyValueChangeKey: Any]?, context _: UnsafeMutableRawPointer?) {
|
||||||
updateRunningApplication()
|
updateRunningApplication()
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateRunningApplication() {
|
func updateRunningApplication() {
|
||||||
let newApplications = launchedApplications()
|
let newApplications = launchedApplications()
|
||||||
|
|
||||||
let index = newApplications.index {
|
let index = newApplications.index {
|
||||||
$0.bundleIdentifier == frontmostApplicationIdentifier
|
$0.bundleIdentifier == frontmostApplicationIdentifier
|
||||||
}
|
}
|
||||||
@ -82,30 +79,30 @@ class AppScrubberTouchBarItem: NSCustomTouchBarItem, NSScrubberDelegate, NSScrub
|
|||||||
applications = newApplications
|
applications = newApplications
|
||||||
applications += getDockPersistentAppsList()
|
applications += getDockPersistentAppsList()
|
||||||
scrubber.reloadData()
|
scrubber.reloadData()
|
||||||
|
|
||||||
scrubber.selectedIndex = index ?? 0
|
scrubber.selectedIndex = index ?? 0
|
||||||
}
|
}
|
||||||
|
|
||||||
public func numberOfItems(for scrubber: NSScrubber) -> Int {
|
public func numberOfItems(for _: NSScrubber) -> Int {
|
||||||
return applications.count
|
return applications.count
|
||||||
}
|
}
|
||||||
|
|
||||||
public func scrubber(_ scrubber: NSScrubber, viewForItemAt index: Int) -> NSScrubberItemView {
|
public func scrubber(_ scrubber: NSScrubber, viewForItemAt index: Int) -> NSScrubberItemView {
|
||||||
let item = scrubber.makeItem(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "ScrubberApplicationsItemReuseIdentifier"), owner: self) as? NSScrubberImageItemView ?? NSScrubberImageItemView()
|
let item = scrubber.makeItem(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "ScrubberApplicationsItemReuseIdentifier"), owner: self) as? NSScrubberImageItemView ?? NSScrubberImageItemView()
|
||||||
item.imageView.imageScaling = .scaleProportionallyDown
|
item.imageView.imageScaling = .scaleProportionallyDown
|
||||||
|
|
||||||
let app = applications[index]
|
let app = applications[index]
|
||||||
|
|
||||||
if let icon = app.icon {
|
if let icon = app.icon {
|
||||||
item.image = icon
|
item.image = icon
|
||||||
item.image.size = NSSize(width: 26, height: 26)
|
item.image.size = NSSize(width: 26, height: 26)
|
||||||
}
|
}
|
||||||
|
|
||||||
item.removeFromSuperview()
|
item.removeFromSuperview()
|
||||||
|
|
||||||
let dotView = NSView(frame: .zero)
|
let dotView = NSView(frame: .zero)
|
||||||
dotView.wantsLayer = true
|
dotView.wantsLayer = true
|
||||||
if self.runningAppsIdentifiers.contains(app.bundleIdentifier!) {
|
if runningAppsIdentifiers.contains(app.bundleIdentifier!) {
|
||||||
dotView.layer?.backgroundColor = NSColor.white.cgColor
|
dotView.layer?.backgroundColor = NSColor.white.cgColor
|
||||||
} else {
|
} else {
|
||||||
dotView.layer?.backgroundColor = NSColor.black.cgColor
|
dotView.layer?.backgroundColor = NSColor.black.cgColor
|
||||||
@ -117,48 +114,48 @@ class AppScrubberTouchBarItem: NSCustomTouchBarItem, NSScrubberDelegate, NSScrub
|
|||||||
|
|
||||||
return item
|
return item
|
||||||
}
|
}
|
||||||
|
|
||||||
public func didBeginInteracting(with scrubber: NSScrubber) {
|
public func didBeginInteracting(with _: NSScrubber) {
|
||||||
stopTimer()
|
stopTimer()
|
||||||
self.ticks = 0
|
ticks = 0
|
||||||
self.timer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(checkTimer), userInfo: nil, repeats: true)
|
timer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(checkTimer), userInfo: nil, repeats: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc private func checkTimer() {
|
@objc private func checkTimer() {
|
||||||
self.ticks += 1
|
ticks += 1
|
||||||
|
|
||||||
if (self.ticks == minTicks) {
|
if ticks == minTicks {
|
||||||
hf.tap(strong: 2)
|
hf.tap(strong: 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self.ticks > maxTicks) {
|
if ticks > maxTicks {
|
||||||
stopTimer()
|
stopTimer()
|
||||||
hf.tap(strong: 6)
|
hf.tap(strong: 6)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func stopTimer() {
|
private func stopTimer() {
|
||||||
self.timer?.invalidate()
|
timer?.invalidate()
|
||||||
self.timer = nil
|
timer = nil
|
||||||
self.lastSelected = 0
|
lastSelected = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
public func didCancelInteracting(with scrubber: NSScrubber) {
|
public func didCancelInteracting(with _: NSScrubber) {
|
||||||
stopTimer()
|
stopTimer()
|
||||||
}
|
}
|
||||||
|
|
||||||
public func didFinishInteracting(with scrubber: NSScrubber) {
|
public func didFinishInteracting(with scrubber: NSScrubber) {
|
||||||
stopTimer()
|
stopTimer()
|
||||||
|
|
||||||
if (ticks == 0) {
|
if ticks == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self.ticks >= minTicks && scrubber.selectedIndex > 0) {
|
if ticks >= minTicks && scrubber.selectedIndex > 0 {
|
||||||
self.longPress(selected: scrubber.selectedIndex)
|
longPress(selected: scrubber.selectedIndex)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let bundleIdentifier = applications[scrubber.selectedIndex].bundleIdentifier
|
let bundleIdentifier = applications[scrubber.selectedIndex].bundleIdentifier
|
||||||
if bundleIdentifier!.contains("file://") {
|
if bundleIdentifier!.contains("file://") {
|
||||||
NSWorkspace.shared.openFile(bundleIdentifier!.replacingOccurrences(of: "file://", with: ""))
|
NSWorkspace.shared.openFile(bundleIdentifier!.replacingOccurrences(of: "file://", with: ""))
|
||||||
@ -167,16 +164,16 @@ class AppScrubberTouchBarItem: NSCustomTouchBarItem, NSScrubberDelegate, NSScrub
|
|||||||
hf.tap(strong: 6)
|
hf.tap(strong: 6)
|
||||||
}
|
}
|
||||||
updateRunningApplication()
|
updateRunningApplication()
|
||||||
|
|
||||||
// NB: if you can't open app which on another space, try to check mark
|
// NB: if you can't open app which on another space, try to check mark
|
||||||
// "When switching to an application, switch to a Space with open windows for the application"
|
// "When switching to an application, switch to a Space with open windows for the application"
|
||||||
// in Mission control settings
|
// in Mission control settings
|
||||||
}
|
}
|
||||||
|
|
||||||
private func longPress(selected: Int) {
|
private func longPress(selected: Int) {
|
||||||
let bundleIdentifier = applications[selected].bundleIdentifier
|
let bundleIdentifier = applications[selected].bundleIdentifier
|
||||||
|
|
||||||
if (self.ticks > maxTicks) {
|
if ticks > maxTicks {
|
||||||
if let processIdentifier = applications[selected].pid {
|
if let processIdentifier = applications[selected].pid {
|
||||||
if !(NSRunningApplication(processIdentifier: processIdentifier)?.terminate())! {
|
if !(NSRunningApplication(processIdentifier: processIdentifier)?.terminate())! {
|
||||||
NSRunningApplication(processIdentifier: processIdentifier)?.forceTerminate()
|
NSRunningApplication(processIdentifier: processIdentifier)?.forceTerminate()
|
||||||
@ -185,34 +182,34 @@ class AppScrubberTouchBarItem: NSCustomTouchBarItem, NSScrubberDelegate, NSScrub
|
|||||||
} else {
|
} else {
|
||||||
hf.tap(strong: 6)
|
hf.tap(strong: 6)
|
||||||
if let index = self.persistentAppIdentifiers.index(of: bundleIdentifier!) {
|
if let index = self.persistentAppIdentifiers.index(of: bundleIdentifier!) {
|
||||||
self.persistentAppIdentifiers.remove(at: index)
|
persistentAppIdentifiers.remove(at: index)
|
||||||
} else {
|
} else {
|
||||||
self.persistentAppIdentifiers.append(bundleIdentifier!)
|
persistentAppIdentifiers.append(bundleIdentifier!)
|
||||||
}
|
}
|
||||||
|
|
||||||
UserDefaults.standard.set(self.persistentAppIdentifiers, forKey: "com.toxblh.mtmr.dock.persistent")
|
UserDefaults.standard.set(persistentAppIdentifiers, forKey: "com.toxblh.mtmr.dock.persistent")
|
||||||
UserDefaults.standard.synchronize()
|
UserDefaults.standard.synchronize()
|
||||||
}
|
}
|
||||||
self.ticks = 0
|
ticks = 0
|
||||||
updateRunningApplication()
|
updateRunningApplication()
|
||||||
}
|
}
|
||||||
|
|
||||||
private func launchedApplications() -> [DockItem] {
|
private func launchedApplications() -> [DockItem] {
|
||||||
self.runningAppsIdentifiers = []
|
runningAppsIdentifiers = []
|
||||||
var returnable: [DockItem] = []
|
var returnable: [DockItem] = []
|
||||||
for app in NSWorkspace.shared.runningApplications {
|
for app in NSWorkspace.shared.runningApplications {
|
||||||
guard app.activationPolicy == NSApplication.ActivationPolicy.regular else { continue }
|
guard app.activationPolicy == NSApplication.ActivationPolicy.regular else { continue }
|
||||||
guard let bundleIdentifier = app.bundleIdentifier else { continue }
|
guard let bundleIdentifier = app.bundleIdentifier else { continue }
|
||||||
|
|
||||||
self.runningAppsIdentifiers.append(bundleIdentifier)
|
runningAppsIdentifiers.append(bundleIdentifier)
|
||||||
|
|
||||||
let dockItem = DockItem(bundleIdentifier: bundleIdentifier, icon: getIcon(forBundleIdentifier: bundleIdentifier), pid: app.processIdentifier)
|
let dockItem = DockItem(bundleIdentifier: bundleIdentifier, icon: getIcon(forBundleIdentifier: bundleIdentifier), pid: app.processIdentifier)
|
||||||
returnable.append(dockItem)
|
returnable.append(dockItem)
|
||||||
}
|
}
|
||||||
return returnable
|
return returnable
|
||||||
}
|
}
|
||||||
|
|
||||||
public func getIcon(forBundleIdentifier bundleIdentifier: String? = nil, orPath path: String? = nil, orType type: String? = nil) -> NSImage {
|
public func getIcon(forBundleIdentifier bundleIdentifier: String? = nil, orPath path: String? = nil, orType _: String? = nil) -> NSImage {
|
||||||
if bundleIdentifier != nil {
|
if bundleIdentifier != nil {
|
||||||
if let appPath = NSWorkspace.shared.absolutePathForApplication(withBundleIdentifier: bundleIdentifier!) {
|
if let appPath = NSWorkspace.shared.absolutePathForApplication(withBundleIdentifier: bundleIdentifier!) {
|
||||||
return NSWorkspace.shared.icon(forFile: appPath)
|
return NSWorkspace.shared.icon(forFile: appPath)
|
||||||
@ -226,13 +223,12 @@ class AppScrubberTouchBarItem: NSCustomTouchBarItem, NSScrubberDelegate, NSScrub
|
|||||||
let genericIcon = NSImage(contentsOfFile: "/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/GenericDocumentIcon.icns")
|
let genericIcon = NSImage(contentsOfFile: "/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/GenericDocumentIcon.icns")
|
||||||
return genericIcon ?? NSImage(size: .zero)
|
return genericIcon ?? NSImage(size: .zero)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public func getDockPersistentAppsList() -> [DockItem] {
|
public func getDockPersistentAppsList() -> [DockItem] {
|
||||||
var returnable: [DockItem] = []
|
var returnable: [DockItem] = []
|
||||||
|
|
||||||
for bundleIdentifier in persistentAppIdentifiers {
|
for bundleIdentifier in persistentAppIdentifiers {
|
||||||
if !self.runningAppsIdentifiers.contains(bundleIdentifier) {
|
if !runningAppsIdentifiers.contains(bundleIdentifier) {
|
||||||
let dockItem = DockItem(bundleIdentifier: bundleIdentifier, icon: getIcon(forBundleIdentifier: bundleIdentifier))
|
let dockItem = DockItem(bundleIdentifier: bundleIdentifier, icon: getIcon(forBundleIdentifier: bundleIdentifier))
|
||||||
returnable.append(dockItem)
|
returnable.append(dockItem)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,29 +6,29 @@
|
|||||||
// Copyright © 2018 Anton Palgunov. All rights reserved.
|
// Copyright © 2018 Anton Palgunov. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
import IOKit.ps
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
import IOKit.ps
|
||||||
|
|
||||||
class BatteryBarItem: CustomButtonTouchBarItem {
|
class BatteryBarItem: CustomButtonTouchBarItem {
|
||||||
private let batteryInfo = BatteryInfo()
|
private let batteryInfo = BatteryInfo()
|
||||||
|
|
||||||
init(identifier: NSTouchBarItem.Identifier) {
|
init(identifier: NSTouchBarItem.Identifier) {
|
||||||
super.init(identifier: identifier, title: " ")
|
super.init(identifier: identifier, title: " ")
|
||||||
|
|
||||||
batteryInfo.start { [weak self] in
|
batteryInfo.start { [weak self] in
|
||||||
self?.refresh()
|
self?.refresh()
|
||||||
}
|
}
|
||||||
self.refresh()
|
refresh()
|
||||||
}
|
}
|
||||||
|
|
||||||
required init?(coder: NSCoder) {
|
required init?(coder _: NSCoder) {
|
||||||
fatalError("init(coder:) has not been implemented")
|
fatalError("init(coder:) has not been implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
func refresh() {
|
func refresh() {
|
||||||
self.attributedTitle = self.batteryInfo.formattedInfo()
|
attributedTitle = batteryInfo.formattedInfo()
|
||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
batteryInfo.stop()
|
batteryInfo.stop()
|
||||||
}
|
}
|
||||||
@ -42,85 +42,85 @@ class BatteryInfo: NSObject {
|
|||||||
var isCharging: Bool = false
|
var isCharging: Bool = false
|
||||||
var ACPower: String = ""
|
var ACPower: String = ""
|
||||||
var timeRemaining: String = ""
|
var timeRemaining: String = ""
|
||||||
var notifyBlock: ()->() = {}
|
var notifyBlock: () -> Void = {}
|
||||||
var loop:CFRunLoopSource?
|
var loop: CFRunLoopSource?
|
||||||
|
|
||||||
func start(notifyBlock: @escaping ()->()) {
|
func start(notifyBlock: @escaping () -> Void) {
|
||||||
self.notifyBlock = notifyBlock
|
self.notifyBlock = notifyBlock
|
||||||
let opaque = Unmanaged.passRetained(self).toOpaque()
|
let opaque = Unmanaged.passRetained(self).toOpaque()
|
||||||
let context = UnsafeMutableRawPointer(opaque)
|
let context = UnsafeMutableRawPointer(opaque)
|
||||||
loop = IOPSNotificationCreateRunLoopSource({ (context) in
|
loop = IOPSNotificationCreateRunLoopSource({ context in
|
||||||
guard let ctx = context else {
|
guard let ctx = context else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let watcher = Unmanaged<BatteryInfo>.fromOpaque(ctx).takeUnretainedValue()
|
let watcher = Unmanaged<BatteryInfo>.fromOpaque(ctx).takeUnretainedValue()
|
||||||
watcher.notifyBlock()
|
watcher.notifyBlock()
|
||||||
}, context).takeRetainedValue() as CFRunLoopSource
|
}, context).takeRetainedValue() as CFRunLoopSource
|
||||||
CFRunLoopAddSource(CFRunLoopGetCurrent(), loop, CFRunLoopMode.defaultMode)
|
CFRunLoopAddSource(CFRunLoopGetCurrent(), loop, CFRunLoopMode.defaultMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
func stop() {
|
func stop() {
|
||||||
self.notifyBlock = {}
|
notifyBlock = {}
|
||||||
guard let loop = self.loop else {
|
guard let loop = self.loop else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
CFRunLoopRemoveSource(CFRunLoopGetCurrent(), loop, CFRunLoopMode.defaultMode)
|
CFRunLoopRemoveSource(CFRunLoopGetCurrent(), loop, CFRunLoopMode.defaultMode)
|
||||||
self.loop = nil
|
self.loop = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getPSInfo() {
|
func getPSInfo() {
|
||||||
let psInfo = IOPSCopyPowerSourcesInfo().takeRetainedValue()
|
let psInfo = IOPSCopyPowerSourcesInfo().takeRetainedValue()
|
||||||
let psList = IOPSCopyPowerSourcesList(psInfo).takeRetainedValue() as [CFTypeRef]
|
let psList = IOPSCopyPowerSourcesList(psInfo).takeRetainedValue() as [CFTypeRef]
|
||||||
|
|
||||||
for ps in psList {
|
for ps in psList {
|
||||||
if let psDesc = IOPSGetPowerSourceDescription(psInfo, ps).takeUnretainedValue() as? [String: Any] {
|
if let psDesc = IOPSGetPowerSourceDescription(psInfo, ps).takeUnretainedValue() as? [String: Any] {
|
||||||
let current = psDesc[kIOPSCurrentCapacityKey]
|
let current = psDesc[kIOPSCurrentCapacityKey]
|
||||||
if (current != nil) {
|
if current != nil {
|
||||||
self.current = current as! Int
|
self.current = current as! Int
|
||||||
}
|
}
|
||||||
|
|
||||||
let timeToEmpty = psDesc[kIOPSTimeToEmptyKey]
|
let timeToEmpty = psDesc[kIOPSTimeToEmptyKey]
|
||||||
if (timeToEmpty != nil) {
|
if timeToEmpty != nil {
|
||||||
self.timeToEmpty = timeToEmpty as! Int
|
self.timeToEmpty = timeToEmpty as! Int
|
||||||
}
|
}
|
||||||
|
|
||||||
let timeToFull = psDesc[kIOPSTimeToFullChargeKey]
|
let timeToFull = psDesc[kIOPSTimeToFullChargeKey]
|
||||||
if (timeToFull != nil) {
|
if timeToFull != nil {
|
||||||
self.timeToFull = timeToFull as! Int
|
self.timeToFull = timeToFull as! Int
|
||||||
}
|
}
|
||||||
|
|
||||||
let isCharged = psDesc[kIOPSIsChargedKey]
|
let isCharged = psDesc[kIOPSIsChargedKey]
|
||||||
if (isCharged != nil) {
|
if isCharged != nil {
|
||||||
self.isCharged = isCharged as! Bool
|
self.isCharged = isCharged as! Bool
|
||||||
}
|
}
|
||||||
|
|
||||||
let isCharging = psDesc[kIOPSIsChargingKey]
|
let isCharging = psDesc[kIOPSIsChargingKey]
|
||||||
if (isCharging != nil) {
|
if isCharging != nil {
|
||||||
self.isCharging = isCharging as! Bool
|
self.isCharging = isCharging as! Bool
|
||||||
}
|
}
|
||||||
|
|
||||||
let ACPower = psDesc[kIOPSPowerSourceStateKey]
|
let ACPower = psDesc[kIOPSPowerSourceStateKey]
|
||||||
if (ACPower != nil) {
|
if ACPower != nil {
|
||||||
self.ACPower = ACPower as! String
|
self.ACPower = ACPower as! String
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getFormattedTime(time: Int) -> String {
|
func getFormattedTime(time: Int) -> String {
|
||||||
if (time > 0) {
|
if time > 0 {
|
||||||
let timeFormatted = NSString(format: " %d:%02d", time / 60, time % 60) as String
|
let timeFormatted = NSString(format: " %d:%02d", time / 60, time % 60) as String
|
||||||
return timeFormatted
|
return timeFormatted
|
||||||
}
|
}
|
||||||
|
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
public func formattedInfo() -> NSAttributedString {
|
public func formattedInfo() -> NSAttributedString {
|
||||||
var title = ""
|
var title = ""
|
||||||
self.getPSInfo()
|
getPSInfo()
|
||||||
|
|
||||||
if ACPower == "AC Power" {
|
if ACPower == "AC Power" {
|
||||||
if current < 100 {
|
if current < 100 {
|
||||||
title += "⚡️"
|
title += "⚡️"
|
||||||
@ -129,19 +129,18 @@ class BatteryInfo: NSObject {
|
|||||||
} else {
|
} else {
|
||||||
timeRemaining = getFormattedTime(time: timeToEmpty)
|
timeRemaining = getFormattedTime(time: timeToEmpty)
|
||||||
}
|
}
|
||||||
|
|
||||||
title += String(current) + "%"
|
title += String(current) + "%"
|
||||||
|
|
||||||
var color = NSColor.white
|
var color = NSColor.white
|
||||||
if current <= 10 && ACPower != "AC Power" {
|
if current <= 10 && ACPower != "AC Power" {
|
||||||
color = NSColor.red
|
color = NSColor.red
|
||||||
}
|
}
|
||||||
|
|
||||||
let newTitle = NSMutableAttributedString(string: title as String, attributes: [.foregroundColor: color, .font: NSFont.systemFont(ofSize: 15), .baselineOffset: 1])
|
let newTitle = NSMutableAttributedString(string: title as String, attributes: [.foregroundColor: color, .font: NSFont.systemFont(ofSize: 15), .baselineOffset: 1])
|
||||||
let newTitleSecond = NSMutableAttributedString(string: timeRemaining as String, attributes: [NSAttributedString.Key.foregroundColor: color, NSAttributedString.Key.font: NSFont.systemFont(ofSize: 8, weight: .regular), NSAttributedString.Key.baselineOffset: 7])
|
let newTitleSecond = NSMutableAttributedString(string: timeRemaining as String, attributes: [NSAttributedString.Key.foregroundColor: color, NSAttributedString.Key.font: NSFont.systemFont(ofSize: 8, weight: .regular), NSAttributedString.Key.baselineOffset: 7])
|
||||||
newTitle.append(newTitleSecond)
|
newTitle.append(newTitleSecond)
|
||||||
newTitle.setAlignment(.center, range: NSRange(location: 0, length: title.count))
|
newTitle.setAlignment(.center, range: NSRange(location: 0, length: title.count))
|
||||||
return newTitle
|
return newTitle
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,54 +1,54 @@
|
|||||||
import Cocoa
|
|
||||||
import AppKit
|
import AppKit
|
||||||
import AVFoundation
|
import AVFoundation
|
||||||
|
import Cocoa
|
||||||
import CoreAudio
|
import CoreAudio
|
||||||
|
|
||||||
class BrightnessViewController: NSCustomTouchBarItem {
|
class BrightnessViewController: NSCustomTouchBarItem {
|
||||||
private(set) var sliderItem: CustomSlider!
|
private(set) var sliderItem: CustomSlider!
|
||||||
|
|
||||||
init(identifier: NSTouchBarItem.Identifier, refreshInterval: Double, image: NSImage? = nil) {
|
init(identifier: NSTouchBarItem.Identifier, refreshInterval: Double, image: NSImage? = nil) {
|
||||||
super.init(identifier: identifier)
|
super.init(identifier: identifier)
|
||||||
|
|
||||||
if (image == nil) {
|
if image == nil {
|
||||||
sliderItem = CustomSlider()
|
sliderItem = CustomSlider()
|
||||||
} else {
|
} else {
|
||||||
sliderItem = CustomSlider(knob: image!)
|
sliderItem = CustomSlider(knob: image!)
|
||||||
}
|
}
|
||||||
sliderItem.target = self
|
sliderItem.target = self
|
||||||
sliderItem.action = #selector(BrightnessViewController.sliderValueChanged(_:))
|
sliderItem.action = #selector(BrightnessViewController.sliderValueChanged(_:))
|
||||||
sliderItem.minValue = 0.0
|
sliderItem.minValue = 0.0
|
||||||
sliderItem.maxValue = 100.0
|
sliderItem.maxValue = 100.0
|
||||||
sliderItem.floatValue = getBrightness() * 100
|
sliderItem.floatValue = getBrightness() * 100
|
||||||
|
|
||||||
self.view = sliderItem
|
view = sliderItem
|
||||||
|
|
||||||
let timer = Timer.scheduledTimer(timeInterval: refreshInterval, target: self, selector: #selector(BrightnessViewController.updateBrightnessSlider), userInfo: nil, repeats: true)
|
let timer = Timer.scheduledTimer(timeInterval: refreshInterval, target: self, selector: #selector(BrightnessViewController.updateBrightnessSlider), userInfo: nil, repeats: true)
|
||||||
RunLoop.current.add(timer, forMode: RunLoop.Mode.common)
|
RunLoop.current.add(timer, forMode: RunLoop.Mode.common)
|
||||||
}
|
}
|
||||||
|
|
||||||
required init?(coder: NSCoder) {
|
required init?(coder _: NSCoder) {
|
||||||
fatalError("init(coder:) has not been implemented")
|
fatalError("init(coder:) has not been implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
sliderItem.unbind(NSBindingName.value)
|
sliderItem.unbind(NSBindingName.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func updateBrightnessSlider() {
|
@objc func updateBrightnessSlider() {
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.sliderItem.floatValue = self.getBrightness() * 100
|
self.sliderItem.floatValue = self.getBrightness() * 100
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func sliderValueChanged(_ sender: Any) {
|
@objc func sliderValueChanged(_ sender: Any) {
|
||||||
if let sliderItem = sender as? NSSlider {
|
if let sliderItem = sender as? NSSlider {
|
||||||
setBrightness(level: Float32(sliderItem.intValue)/100.0)
|
setBrightness(level: Float32(sliderItem.intValue) / 100.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func getBrightness() -> Float32 {
|
private func getBrightness() -> Float32 {
|
||||||
if #available(OSX 10.13, *) {
|
if #available(OSX 10.13, *) {
|
||||||
return Float32(CoreDisplay_Display_GetUserBrightness(0));
|
return Float32(CoreDisplay_Display_GetUserBrightness(0))
|
||||||
} else {
|
} else {
|
||||||
var level: Float32 = 0.5
|
var level: Float32 = 0.5
|
||||||
let service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IODisplayConnect"))
|
let service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IODisplayConnect"))
|
||||||
@ -57,16 +57,15 @@ class BrightnessViewController: NSCustomTouchBarItem {
|
|||||||
return level
|
return level
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func setBrightness(level: Float) {
|
private func setBrightness(level: Float) {
|
||||||
if #available(OSX 10.13, *) {
|
if #available(OSX 10.13, *) {
|
||||||
CoreDisplay_Display_SetUserBrightness(0, Double(level));
|
CoreDisplay_Display_SetUserBrightness(0, Double(level))
|
||||||
} else {
|
} else {
|
||||||
let service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IODisplayConnect"))
|
let service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IODisplayConnect"))
|
||||||
|
|
||||||
IODisplaySetFloatParameter(service, 1, kIODisplayBrightnessKey as CFString, level)
|
IODisplaySetFloatParameter(service, 1, kIODisplayBrightnessKey as CFString, level)
|
||||||
IOObjectRelease(service)
|
IOObjectRelease(service)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -45,7 +45,7 @@ class CurrencyBarItem: CustomButtonTouchBarItem {
|
|||||||
if let prefix = currencies[from] {
|
if let prefix = currencies[from] {
|
||||||
self.prefix = prefix
|
self.prefix = prefix
|
||||||
} else {
|
} else {
|
||||||
self.prefix = from
|
prefix = from
|
||||||
}
|
}
|
||||||
|
|
||||||
super.init(identifier: identifier, title: "⏳")
|
super.init(identifier: identifier, title: "⏳")
|
||||||
@ -59,21 +59,21 @@ class CurrencyBarItem: CustomButtonTouchBarItem {
|
|||||||
updateCurrency()
|
updateCurrency()
|
||||||
}
|
}
|
||||||
|
|
||||||
required init?(coder: NSCoder) {
|
required init?(coder _: NSCoder) {
|
||||||
fatalError("init(coder:) has not been implemented")
|
fatalError("init(coder:) has not been implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func updateCurrency() {
|
@objc func updateCurrency() {
|
||||||
let urlRequest = URLRequest(url: URL(string: "https://api.coinbase.com/v2/exchange-rates?currency=\(from)")!)
|
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
|
let task = URLSession.shared.dataTask(with: urlRequest) { data, _, error in
|
||||||
if error == nil {
|
if error == nil {
|
||||||
do {
|
do {
|
||||||
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as! [String : AnyObject]
|
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as! [String: AnyObject]
|
||||||
var value: Float32!
|
var value: Float32!
|
||||||
|
|
||||||
if let data_array = json["data"] as? [String : AnyObject] {
|
if let data_array = json["data"] as? [String: AnyObject] {
|
||||||
if let rates = data_array["rates"] as? [String : AnyObject] {
|
if let rates = data_array["rates"] as? [String: AnyObject] {
|
||||||
if let item = rates["\(self.to)"] as? String {
|
if let item = rates["\(self.to)"] as? String {
|
||||||
value = Float32(item)
|
value = Float32(item)
|
||||||
}
|
}
|
||||||
@ -103,13 +103,13 @@ class CurrencyBarItem: CustomButtonTouchBarItem {
|
|||||||
color = NSColor.red
|
color = NSColor.red
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.oldValue = value
|
oldValue = value
|
||||||
|
|
||||||
let title = String(format: "%@%.2f", self.prefix, value)
|
let title = String(format: "%@%.2f", prefix, value)
|
||||||
|
|
||||||
let regularFont = self.attributedTitle.attribute(.font, at: 0, effectiveRange: nil) as? NSFont ?? NSFont.systemFont(ofSize: 15)
|
let regularFont = attributedTitle.attribute(.font, at: 0, effectiveRange: nil) as? NSFont ?? NSFont.systemFont(ofSize: 15)
|
||||||
let newTitle = NSMutableAttributedString(string: title as String, attributes: [.foregroundColor: color, .font: regularFont])
|
let newTitle = NSMutableAttributedString(string: title as String, attributes: [.foregroundColor: color, .font: regularFont])
|
||||||
newTitle.setAlignment(.center, range: NSRange(location: 0, length: title.count))
|
newTitle.setAlignment(.center, range: NSRange(location: 0, length: title.count))
|
||||||
self.attributedTitle = newTitle
|
attributedTitle = newTitle
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,49 +8,49 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
class DnDBarItem : CustomButtonTouchBarItem {
|
class DnDBarItem: CustomButtonTouchBarItem {
|
||||||
private var timer: Timer!
|
private var timer: Timer!
|
||||||
|
|
||||||
init(identifier: NSTouchBarItem.Identifier) {
|
init(identifier: NSTouchBarItem.Identifier) {
|
||||||
super.init(identifier: identifier, title: "")
|
super.init(identifier: identifier, title: "")
|
||||||
self.isBordered = false
|
isBordered = false
|
||||||
self.setWidth(value: 32)
|
setWidth(value: 32)
|
||||||
|
|
||||||
self.tapClosure = { [weak self] in self?.DnDToggle() }
|
tapClosure = { [weak self] in self?.DnDToggle() }
|
||||||
|
|
||||||
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(refresh), userInfo: nil, repeats: true)
|
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(refresh), userInfo: nil, repeats: true)
|
||||||
|
|
||||||
self.refresh()
|
refresh()
|
||||||
}
|
}
|
||||||
|
|
||||||
required init?(coder: NSCoder) {
|
required init?(coder _: NSCoder) {
|
||||||
fatalError("init(coder:) has not been implemented")
|
fatalError("init(coder:) has not been implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
func DnDToggle() {
|
func DnDToggle() {
|
||||||
DoNotDisturb.isEnabled = !DoNotDisturb.isEnabled
|
DoNotDisturb.isEnabled = !DoNotDisturb.isEnabled
|
||||||
refresh()
|
refresh()
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func refresh() {
|
@objc func refresh() {
|
||||||
self.image = DoNotDisturb.isEnabled ? #imageLiteral(resourceName: "dnd-on") : #imageLiteral(resourceName: "dnd-off")
|
image = DoNotDisturb.isEnabled ? #imageLiteral(resourceName: "dnd-on") : #imageLiteral(resourceName: "dnd-off")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct DoNotDisturb {
|
public struct DoNotDisturb {
|
||||||
private static let appId = "com.apple.notificationcenterui" as CFString
|
private static let appId = "com.apple.notificationcenterui" as CFString
|
||||||
private static let dndPref = "com.apple.notificationcenterui.dndprefs_changed"
|
private static let dndPref = "com.apple.notificationcenterui.dndprefs_changed"
|
||||||
|
|
||||||
private static func set(_ key: String, value: CFPropertyList?) {
|
private static func set(_ key: String, value: CFPropertyList?) {
|
||||||
CFPreferencesSetValue(key as CFString, value, appId, kCFPreferencesCurrentUser, kCFPreferencesCurrentHost)
|
CFPreferencesSetValue(key as CFString, value, appId, kCFPreferencesCurrentUser, kCFPreferencesCurrentHost)
|
||||||
}
|
}
|
||||||
|
|
||||||
private static func commitChanges() {
|
private static func commitChanges() {
|
||||||
CFPreferencesSynchronize(appId, kCFPreferencesCurrentUser, kCFPreferencesCurrentHost)
|
CFPreferencesSynchronize(appId, kCFPreferencesCurrentUser, kCFPreferencesCurrentHost)
|
||||||
DistributedNotificationCenter.default().postNotificationName(NSNotification.Name(dndPref), object: nil, userInfo: nil, deliverImmediately: true)
|
DistributedNotificationCenter.default().postNotificationName(NSNotification.Name(dndPref), object: nil, userInfo: nil, deliverImmediately: true)
|
||||||
NSRunningApplication.runningApplications(withBundleIdentifier: appId as String).first?.terminate()
|
NSRunningApplication.runningApplications(withBundleIdentifier: appId as String).first?.terminate()
|
||||||
}
|
}
|
||||||
|
|
||||||
private static func enable() {
|
private static func enable() {
|
||||||
set("dndStart", value: nil)
|
set("dndStart", value: nil)
|
||||||
set("dndEnd", value: nil)
|
set("dndEnd", value: nil)
|
||||||
@ -58,7 +58,7 @@ public struct DoNotDisturb {
|
|||||||
set("doNotDisturbDate", value: Date() as CFPropertyList)
|
set("doNotDisturbDate", value: Date() as CFPropertyList)
|
||||||
commitChanges()
|
commitChanges()
|
||||||
}
|
}
|
||||||
|
|
||||||
private static func disable() {
|
private static func disable() {
|
||||||
set("dndStart", value: nil)
|
set("dndStart", value: nil)
|
||||||
set("dndEnd", value: nil)
|
set("dndEnd", value: nil)
|
||||||
@ -66,8 +66,8 @@ public struct DoNotDisturb {
|
|||||||
set("doNotDisturbDate", value: nil)
|
set("doNotDisturbDate", value: nil)
|
||||||
commitChanges()
|
commitChanges()
|
||||||
}
|
}
|
||||||
|
|
||||||
static var isEnabled:Bool {
|
static var isEnabled: Bool {
|
||||||
get {
|
get {
|
||||||
return CFPreferencesGetAppBooleanValue("doNotDisturb" as CFString, appId, nil)
|
return CFPreferencesGetAppBooleanValue("doNotDisturb" as CFString, appId, nil)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,9 +8,8 @@
|
|||||||
import Cocoa
|
import Cocoa
|
||||||
|
|
||||||
class GroupBarItem: NSPopoverTouchBarItem, NSTouchBarDelegate {
|
class GroupBarItem: NSPopoverTouchBarItem, NSTouchBarDelegate {
|
||||||
|
|
||||||
var jsonItems: [BarItemDefinition]
|
var jsonItems: [BarItemDefinition]
|
||||||
|
|
||||||
var itemDefinitions: [NSTouchBarItem.Identifier: BarItemDefinition] = [:]
|
var itemDefinitions: [NSTouchBarItem.Identifier: BarItemDefinition] = [:]
|
||||||
var items: [NSTouchBarItem.Identifier: NSTouchBarItem] = [:]
|
var items: [NSTouchBarItem.Identifier: NSTouchBarItem] = [:]
|
||||||
var leftIdentifiers: [NSTouchBarItem.Identifier] = []
|
var leftIdentifiers: [NSTouchBarItem.Identifier] = []
|
||||||
@ -19,62 +18,60 @@ class GroupBarItem: NSPopoverTouchBarItem, NSTouchBarDelegate {
|
|||||||
var rightIdentifiers: [NSTouchBarItem.Identifier] = []
|
var rightIdentifiers: [NSTouchBarItem.Identifier] = []
|
||||||
var scrollArea: NSCustomTouchBarItem?
|
var scrollArea: NSCustomTouchBarItem?
|
||||||
var centerScrollArea = NSTouchBarItem.Identifier("com.toxblh.mtmr.scrollArea.".appending(UUID().uuidString))
|
var centerScrollArea = NSTouchBarItem.Identifier("com.toxblh.mtmr.scrollArea.".appending(UUID().uuidString))
|
||||||
|
|
||||||
init(identifier: NSTouchBarItem.Identifier, items: [BarItemDefinition]) {
|
init(identifier: NSTouchBarItem.Identifier, items: [BarItemDefinition]) {
|
||||||
jsonItems = items
|
jsonItems = items
|
||||||
super.init(identifier: identifier)
|
super.init(identifier: identifier)
|
||||||
self.popoverTouchBar.delegate = self
|
popoverTouchBar.delegate = self
|
||||||
}
|
}
|
||||||
|
|
||||||
required init?(coder: NSCoder) {
|
required init?(coder _: NSCoder) {
|
||||||
fatalError("init(coder:) has not been implemented")
|
fatalError("init(coder:) has not been implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
deinit {}
|
||||||
|
|
||||||
}
|
@objc override func showPopover(_: Any?) {
|
||||||
|
itemDefinitions = [:]
|
||||||
@objc override func showPopover(_ sender: Any?) {
|
items = [:]
|
||||||
self.itemDefinitions = [:]
|
leftIdentifiers = []
|
||||||
self.items = [:]
|
centerItems = []
|
||||||
self.leftIdentifiers = []
|
rightIdentifiers = []
|
||||||
self.centerItems = []
|
|
||||||
self.rightIdentifiers = []
|
loadItemDefinitions(jsonItems: jsonItems)
|
||||||
|
createItems()
|
||||||
self.loadItemDefinitions(jsonItems: jsonItems)
|
|
||||||
self.createItems()
|
|
||||||
|
|
||||||
centerItems = centerIdentifiers.compactMap({ (identifier) -> NSTouchBarItem? in
|
centerItems = centerIdentifiers.compactMap({ (identifier) -> NSTouchBarItem? in
|
||||||
return items[identifier]
|
items[identifier]
|
||||||
})
|
})
|
||||||
|
|
||||||
self.centerScrollArea = NSTouchBarItem.Identifier("com.toxblh.mtmr.scrollArea.".appending(UUID().uuidString))
|
centerScrollArea = NSTouchBarItem.Identifier("com.toxblh.mtmr.scrollArea.".appending(UUID().uuidString))
|
||||||
self.scrollArea = ScrollViewItem(identifier: centerScrollArea, items: centerItems)
|
scrollArea = ScrollViewItem(identifier: centerScrollArea, items: centerItems)
|
||||||
|
|
||||||
TouchBarController.shared.touchBar.delegate = self
|
TouchBarController.shared.touchBar.delegate = self
|
||||||
TouchBarController.shared.touchBar.defaultItemIdentifiers = []
|
TouchBarController.shared.touchBar.defaultItemIdentifiers = []
|
||||||
TouchBarController.shared.touchBar.defaultItemIdentifiers = self.leftIdentifiers + [centerScrollArea] + self.rightIdentifiers
|
TouchBarController.shared.touchBar.defaultItemIdentifiers = leftIdentifiers + [centerScrollArea] + rightIdentifiers
|
||||||
|
|
||||||
if TouchBarController.shared.showControlStripState {
|
if TouchBarController.shared.showControlStripState {
|
||||||
presentSystemModal(TouchBarController.shared.touchBar, systemTrayItemIdentifier: .controlStripItem)
|
presentSystemModal(TouchBarController.shared.touchBar, systemTrayItemIdentifier: .controlStripItem)
|
||||||
} else {
|
} else {
|
||||||
presentSystemModal(TouchBarController.shared.touchBar, placement: 1, systemTrayItemIdentifier: .controlStripItem)
|
presentSystemModal(TouchBarController.shared.touchBar, placement: 1, systemTrayItemIdentifier: .controlStripItem)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func touchBar(_ touchBar: NSTouchBar, makeItemForIdentifier identifier: NSTouchBarItem.Identifier) -> NSTouchBarItem? {
|
func touchBar(_: NSTouchBar, makeItemForIdentifier identifier: NSTouchBarItem.Identifier) -> NSTouchBarItem? {
|
||||||
if identifier == centerScrollArea {
|
if identifier == centerScrollArea {
|
||||||
return self.scrollArea
|
return scrollArea
|
||||||
}
|
}
|
||||||
|
|
||||||
guard let item = self.items[identifier],
|
guard let item = self.items[identifier],
|
||||||
let definition = self.itemDefinitions[identifier],
|
let definition = self.itemDefinitions[identifier],
|
||||||
definition.align != .center else {
|
definition.align != .center else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return item
|
return item
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadItemDefinitions(jsonItems: [BarItemDefinition]) {
|
func loadItemDefinitions(jsonItems: [BarItemDefinition]) {
|
||||||
let dateFormatter = DateFormatter()
|
let dateFormatter = DateFormatter()
|
||||||
dateFormatter.dateFormat = "HH-mm-ss"
|
dateFormatter.dateFormat = "HH-mm-ss"
|
||||||
@ -94,10 +91,10 @@ class GroupBarItem: NSPopoverTouchBarItem, NSTouchBarDelegate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func createItems() {
|
func createItems() {
|
||||||
for (identifier, definition) in self.itemDefinitions {
|
for (identifier, definition) in itemDefinitions {
|
||||||
self.items[identifier] = TouchBarController.shared.createItem(forIdentifier: identifier, definition: definition)
|
items[identifier] = TouchBarController.shared.createItem(forIdentifier: identifier, definition: definition)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,33 +9,32 @@
|
|||||||
import Cocoa
|
import Cocoa
|
||||||
|
|
||||||
class InputSourceBarItem: CustomButtonTouchBarItem {
|
class InputSourceBarItem: CustomButtonTouchBarItem {
|
||||||
|
|
||||||
fileprivate var notificationCenter: CFNotificationCenter
|
fileprivate var notificationCenter: CFNotificationCenter
|
||||||
let buttonSize = NSSize(width: 21, height: 21)
|
let buttonSize = NSSize(width: 21, height: 21)
|
||||||
|
|
||||||
init(identifier: NSTouchBarItem.Identifier) {
|
init(identifier: NSTouchBarItem.Identifier) {
|
||||||
notificationCenter = CFNotificationCenterGetDistributedCenter();
|
notificationCenter = CFNotificationCenterGetDistributedCenter()
|
||||||
super.init(identifier: identifier, title: "⏳")
|
super.init(identifier: identifier, title: "⏳")
|
||||||
|
|
||||||
observeIputSourceChangedNotification();
|
observeIputSourceChangedNotification()
|
||||||
textInputSourceDidChange()
|
textInputSourceDidChange()
|
||||||
self.tapClosure = { [weak self] in
|
tapClosure = { [weak self] in
|
||||||
self?.switchInputSource()
|
self?.switchInputSource()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
required init?(coder: NSCoder) {
|
required init?(coder _: NSCoder) {
|
||||||
fatalError("init(coder:) has not been implemented")
|
fatalError("init(coder:) has not been implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
CFNotificationCenterRemoveEveryObserver(notificationCenter, UnsafeRawPointer(Unmanaged.passUnretained(self).toOpaque()));
|
CFNotificationCenterRemoveEveryObserver(notificationCenter, UnsafeRawPointer(Unmanaged.passUnretained(self).toOpaque()))
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc public func textInputSourceDidChange() {
|
@objc public func textInputSourceDidChange() {
|
||||||
let currentSource = TISCopyCurrentKeyboardInputSource().takeUnretainedValue()
|
let currentSource = TISCopyCurrentKeyboardInputSource().takeUnretainedValue()
|
||||||
|
|
||||||
var iconImage: NSImage? = nil
|
var iconImage: NSImage?
|
||||||
|
|
||||||
if let imageURL = currentSource.iconImageURL,
|
if let imageURL = currentSource.iconImageURL,
|
||||||
let image = NSImage(contentsOf: imageURL) {
|
let image = NSImage(contentsOf: imageURL) {
|
||||||
@ -46,10 +45,10 @@ class InputSourceBarItem: CustomButtonTouchBarItem {
|
|||||||
|
|
||||||
if let iconImage = iconImage {
|
if let iconImage = iconImage {
|
||||||
iconImage.size = buttonSize
|
iconImage.size = buttonSize
|
||||||
self.image = iconImage
|
image = iconImage
|
||||||
self.title = ""
|
title = ""
|
||||||
} else {
|
} else {
|
||||||
self.title = currentSource.name
|
title = currentSource.name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,15 +64,15 @@ class InputSourceBarItem: CustomButtonTouchBarItem {
|
|||||||
})
|
})
|
||||||
|
|
||||||
for item in inputSources {
|
for item in inputSources {
|
||||||
if (item.id != currentSource.id) {
|
if item.id != currentSource.id {
|
||||||
TISSelectInputSource(item)
|
TISSelectInputSource(item)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc public func observeIputSourceChangedNotification(){
|
@objc public func observeIputSourceChangedNotification() {
|
||||||
let callback: CFNotificationCallback = { center, observer, name, object, info in
|
let callback: CFNotificationCallback = { _, observer, _, _, _ in
|
||||||
let mySelf = Unmanaged<InputSourceBarItem>.fromOpaque(observer!).takeUnretainedValue()
|
let mySelf = Unmanaged<InputSourceBarItem>.fromOpaque(observer!).takeUnretainedValue()
|
||||||
mySelf.textInputSourceDidChange()
|
mySelf.textInputSourceDidChange()
|
||||||
}
|
}
|
||||||
@ -96,7 +95,7 @@ extension TISInputSource {
|
|||||||
|
|
||||||
private func getProperty(_ key: CFString) -> AnyObject? {
|
private func getProperty(_ key: CFString) -> AnyObject? {
|
||||||
let cfType = TISGetInputSourceProperty(self, key)
|
let cfType = TISGetInputSourceProperty(self, key)
|
||||||
if (cfType != nil) {
|
if cfType != nil {
|
||||||
return Unmanaged<AnyObject>.fromOpaque(cfType!).takeUnretainedValue()
|
return Unmanaged<AnyObject>.fromOpaque(cfType!).takeUnretainedValue()
|
||||||
} else {
|
} else {
|
||||||
return nil
|
return nil
|
||||||
@ -131,4 +130,3 @@ extension TISInputSource {
|
|||||||
return OpaquePointer(TISGetInputSourceProperty(self, kTISPropertyIconRef)) as IconRef?
|
return OpaquePointer(TISGetInputSourceProperty(self, kTISPropertyIconRef)) as IconRef?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -14,57 +14,57 @@ class MusicBarItem: CustomButtonTouchBarItem {
|
|||||||
private var songTitle: String?
|
private var songTitle: String?
|
||||||
private var timer: Timer?
|
private var timer: Timer?
|
||||||
let buttonSize = NSSize(width: 21, height: 21)
|
let buttonSize = NSSize(width: 21, height: 21)
|
||||||
|
|
||||||
let playerBundleIdentifiers = [
|
let playerBundleIdentifiers = [
|
||||||
"com.apple.iTunes",
|
"com.apple.iTunes",
|
||||||
"com.spotify.client",
|
"com.spotify.client",
|
||||||
"com.coppertino.Vox",
|
"com.coppertino.Vox",
|
||||||
"com.google.Chrome",
|
"com.google.Chrome",
|
||||||
"com.apple.Safari"
|
"com.apple.Safari",
|
||||||
]
|
]
|
||||||
|
|
||||||
init(identifier: NSTouchBarItem.Identifier, interval: TimeInterval) {
|
init(identifier: NSTouchBarItem.Identifier, interval: TimeInterval) {
|
||||||
self.interval = interval
|
self.interval = interval
|
||||||
|
|
||||||
super.init(identifier: identifier, title: "⏳")
|
super.init(identifier: identifier, title: "⏳")
|
||||||
self.isBordered = false
|
isBordered = false
|
||||||
|
|
||||||
self.tapClosure = { [weak self] in self?.playPause() }
|
tapClosure = { [weak self] in self?.playPause() }
|
||||||
self.longTapClosure = { [weak self] in self?.nextTrack() }
|
longTapClosure = { [weak self] in self?.nextTrack() }
|
||||||
|
|
||||||
self.refreshAndSchedule()
|
refreshAndSchedule()
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func marquee(){
|
@objc func marquee() {
|
||||||
let str = self.title
|
let str = title
|
||||||
if (str.count > 10) {
|
if str.count > 10 {
|
||||||
let indexFirst = str.index(str.startIndex, offsetBy: 0)
|
let indexFirst = str.index(str.startIndex, offsetBy: 0)
|
||||||
let indexSecond = str.index(str.startIndex, offsetBy: 1)
|
let indexSecond = str.index(str.startIndex, offsetBy: 1)
|
||||||
self.title = String(str.suffix(from: indexSecond)) + String(str[indexFirst])
|
title = String(str.suffix(from: indexSecond)) + String(str[indexFirst])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
required init?(coder: NSCoder) {
|
required init?(coder _: NSCoder) {
|
||||||
fatalError("init(coder:) has not been implemented")
|
fatalError("init(coder:) has not been implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func playPause() {
|
@objc func playPause() {
|
||||||
for ident in playerBundleIdentifiers {
|
for ident in playerBundleIdentifiers {
|
||||||
if let musicPlayer = SBApplication(bundleIdentifier: ident) {
|
if let musicPlayer = SBApplication(bundleIdentifier: ident) {
|
||||||
if (musicPlayer.isRunning) {
|
if musicPlayer.isRunning {
|
||||||
if (musicPlayer.className == "SpotifyApplication") {
|
if musicPlayer.className == "SpotifyApplication" {
|
||||||
let mp = (musicPlayer as SpotifyApplication)
|
let mp = (musicPlayer as SpotifyApplication)
|
||||||
mp.playpause!()
|
mp.playpause!()
|
||||||
return
|
return
|
||||||
} else if (musicPlayer.className == "ITunesApplication") {
|
} else if musicPlayer.className == "ITunesApplication" {
|
||||||
let mp = (musicPlayer as iTunesApplication)
|
let mp = (musicPlayer as iTunesApplication)
|
||||||
mp.playpause!()
|
mp.playpause!()
|
||||||
return
|
return
|
||||||
} else if (musicPlayer.className == "VOXApplication") {
|
} else if musicPlayer.className == "VOXApplication" {
|
||||||
let mp = (musicPlayer as VoxApplication)
|
let mp = (musicPlayer as VoxApplication)
|
||||||
mp.playpause!()
|
mp.playpause!()
|
||||||
return
|
return
|
||||||
} else if (musicPlayer.className == "SafariApplication") {
|
} else if musicPlayer.className == "SafariApplication" {
|
||||||
// You must enable the 'Allow JavaScript from Apple Events' option in Safari's Develop menu to use 'do JavaScript'.
|
// You must enable the 'Allow JavaScript from Apple Events' option in Safari's Develop menu to use 'do JavaScript'.
|
||||||
let safariApplication = musicPlayer as SafariApplication
|
let safariApplication = musicPlayer as SafariApplication
|
||||||
let safariWindows = safariApplication.windows?().compactMap({ $0 as? SafariWindow })
|
let safariWindows = safariApplication.windows?().compactMap({ $0 as? SafariWindow })
|
||||||
@ -74,7 +74,7 @@ class MusicBarItem: CustomButtonTouchBarItem {
|
|||||||
if (tab.URL?.starts(with: "https://music.yandex.ru"))! {
|
if (tab.URL?.starts(with: "https://music.yandex.ru"))! {
|
||||||
_ = safariApplication.doJavaScript!("document.getElementsByClassName('player-controls__btn_play')[0].click()", in: tab)
|
_ = safariApplication.doJavaScript!("document.getElementsByClassName('player-controls__btn_play')[0].click()", in: tab)
|
||||||
return
|
return
|
||||||
} else if ((tab.URL?.starts(with: "https://vk.com/audios"))! || (tab.URL?.starts(with: "https://vk.com/music"))!) {
|
} else if (tab.URL?.starts(with: "https://vk.com/audios"))! || (tab.URL?.starts(with: "https://vk.com/music"))! {
|
||||||
_ = safariApplication.doJavaScript!("document.getElementsByClassName('audio_page_player_play')[0].click()", in: tab)
|
_ = safariApplication.doJavaScript!("document.getElementsByClassName('audio_page_player_play')[0].click()", in: tab)
|
||||||
return
|
return
|
||||||
} else if (tab.URL?.starts(with: "https://www.youtube.com/watch"))! {
|
} else if (tab.URL?.starts(with: "https://www.youtube.com/watch"))! {
|
||||||
@ -108,27 +108,27 @@ class MusicBarItem: CustomButtonTouchBarItem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func nextTrack() {
|
@objc func nextTrack() {
|
||||||
for ident in playerBundleIdentifiers {
|
for ident in playerBundleIdentifiers {
|
||||||
if let musicPlayer = SBApplication(bundleIdentifier: ident) {
|
if let musicPlayer = SBApplication(bundleIdentifier: ident) {
|
||||||
if (musicPlayer.isRunning) {
|
if musicPlayer.isRunning {
|
||||||
if (musicPlayer.className == "SpotifyApplication") {
|
if musicPlayer.className == "SpotifyApplication" {
|
||||||
let mp = (musicPlayer as SpotifyApplication)
|
let mp = (musicPlayer as SpotifyApplication)
|
||||||
mp.nextTrack!()
|
mp.nextTrack!()
|
||||||
updatePlayer()
|
updatePlayer()
|
||||||
return
|
return
|
||||||
} else if (musicPlayer.className == "ITunesApplication") {
|
} else if musicPlayer.className == "ITunesApplication" {
|
||||||
let mp = (musicPlayer as iTunesApplication)
|
let mp = (musicPlayer as iTunesApplication)
|
||||||
mp.nextTrack!()
|
mp.nextTrack!()
|
||||||
updatePlayer()
|
updatePlayer()
|
||||||
return
|
return
|
||||||
} else if (musicPlayer.className == "VOXApplication") {
|
} else if musicPlayer.className == "VOXApplication" {
|
||||||
let mp = (musicPlayer as VoxApplication)
|
let mp = (musicPlayer as VoxApplication)
|
||||||
mp.next!()
|
mp.next!()
|
||||||
updatePlayer()
|
updatePlayer()
|
||||||
return
|
return
|
||||||
} else if (musicPlayer.className == "SafariApplication") {
|
} else if musicPlayer.className == "SafariApplication" {
|
||||||
// You must enable the 'Allow JavaScript from Apple Events' option in Safari's Develop menu to use 'do JavaScript'.
|
// You must enable the 'Allow JavaScript from Apple Events' option in Safari's Develop menu to use 'do JavaScript'.
|
||||||
let safariApplication = musicPlayer as SafariApplication
|
let safariApplication = musicPlayer as SafariApplication
|
||||||
let safariWindows = safariApplication.windows?().compactMap({ $0 as? SafariWindow })
|
let safariWindows = safariApplication.windows?().compactMap({ $0 as? SafariWindow })
|
||||||
@ -139,7 +139,7 @@ class MusicBarItem: CustomButtonTouchBarItem {
|
|||||||
_ = safariApplication.doJavaScript!("document.getElementsByClassName('player-controls__btn_next')[0].click()", in: tab)
|
_ = safariApplication.doJavaScript!("document.getElementsByClassName('player-controls__btn_next')[0].click()", in: tab)
|
||||||
updatePlayer()
|
updatePlayer()
|
||||||
return
|
return
|
||||||
} else if ((tab.URL?.starts(with: "https://vk.com/audios"))! || (tab.URL?.starts(with: "https://vk.com/music"))!) {
|
} else if (tab.URL?.starts(with: "https://vk.com/audios"))! || (tab.URL?.starts(with: "https://vk.com/music"))! {
|
||||||
_ = safariApplication.doJavaScript!("document.getElementsByClassName('audio_page_player_next')[0].click()", in: tab)
|
_ = safariApplication.doJavaScript!("document.getElementsByClassName('audio_page_player_next')[0].click()", in: tab)
|
||||||
updatePlayer()
|
updatePlayer()
|
||||||
return
|
return
|
||||||
@ -155,7 +155,7 @@ class MusicBarItem: CustomButtonTouchBarItem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func refreshAndSchedule() {
|
func refreshAndSchedule() {
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.updatePlayer()
|
self.updatePlayer()
|
||||||
@ -164,22 +164,22 @@ class MusicBarItem: CustomButtonTouchBarItem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func updatePlayer() {
|
func updatePlayer() {
|
||||||
var iconUpdated = false
|
var iconUpdated = false
|
||||||
var titleUpdated = false
|
var titleUpdated = false
|
||||||
|
|
||||||
for var ident in playerBundleIdentifiers {
|
for var ident in playerBundleIdentifiers {
|
||||||
if let musicPlayer = SBApplication(bundleIdentifier: ident) {
|
if let musicPlayer = SBApplication(bundleIdentifier: ident) {
|
||||||
if (musicPlayer.isRunning) {
|
if musicPlayer.isRunning {
|
||||||
var tempTitle = ""
|
var tempTitle = ""
|
||||||
if (musicPlayer.className == "SpotifyApplication") {
|
if musicPlayer.className == "SpotifyApplication" {
|
||||||
tempTitle = (musicPlayer as SpotifyApplication).title
|
tempTitle = (musicPlayer as SpotifyApplication).title
|
||||||
} else if (musicPlayer.className == "ITunesApplication") {
|
} else if musicPlayer.className == "ITunesApplication" {
|
||||||
tempTitle = (musicPlayer as iTunesApplication).title
|
tempTitle = (musicPlayer as iTunesApplication).title
|
||||||
} else if (musicPlayer.className == "VOXApplication") {
|
} else if musicPlayer.className == "VOXApplication" {
|
||||||
tempTitle = (musicPlayer as VoxApplication).title
|
tempTitle = (musicPlayer as VoxApplication).title
|
||||||
} else if (musicPlayer.className == "SafariApplication") {
|
} else if musicPlayer.className == "SafariApplication" {
|
||||||
let safariApplication = musicPlayer as SafariApplication
|
let safariApplication = musicPlayer as SafariApplication
|
||||||
let safariWindows = safariApplication.windows?().compactMap({ $0 as? SafariWindow })
|
let safariWindows = safariApplication.windows?().compactMap({ $0 as? SafariWindow })
|
||||||
for window in safariWindows! {
|
for window in safariWindows! {
|
||||||
@ -190,7 +190,7 @@ class MusicBarItem: CustomButtonTouchBarItem {
|
|||||||
tempTitle = (tab.name)!
|
tempTitle = (tab.name)!
|
||||||
break
|
break
|
||||||
// }
|
// }
|
||||||
} else if ((tab.URL?.starts(with: "https://vk.com/audios"))! || (tab.URL?.starts(with: "https://vk.com/music"))!) {
|
} else if (tab.URL?.starts(with: "https://vk.com/audios"))! || (tab.URL?.starts(with: "https://vk.com/music"))! {
|
||||||
tempTitle = (tab.name)!
|
tempTitle = (tab.name)!
|
||||||
break
|
break
|
||||||
} else if (tab.URL?.starts(with: "https://www.youtube.com/watch"))! {
|
} else if (tab.URL?.starts(with: "https://www.youtube.com/watch"))! {
|
||||||
@ -202,18 +202,18 @@ class MusicBarItem: CustomButtonTouchBarItem {
|
|||||||
if tempTitle == "" {
|
if tempTitle == "" {
|
||||||
ident = ""
|
ident = ""
|
||||||
}
|
}
|
||||||
} else if (musicPlayer.className == "GoogleChromeApplication") {
|
} else if musicPlayer.className == "GoogleChromeApplication" {
|
||||||
let chromeApplication = musicPlayer as GoogleChromeApplication
|
let chromeApplication = musicPlayer as GoogleChromeApplication
|
||||||
let chromeWindows = chromeApplication.windows?().compactMap({ $0 as? GoogleChromeWindow })
|
let chromeWindows = chromeApplication.windows?().compactMap({ $0 as? GoogleChromeWindow })
|
||||||
for window in chromeWindows! {
|
for window in chromeWindows! {
|
||||||
for tab in window.tabs!() {
|
for tab in window.tabs!() {
|
||||||
let tab = tab as! GoogleChromeTab
|
let tab = tab as! GoogleChromeTab
|
||||||
if (tab.URL?.starts(with: "https://music.yandex.ru"))! {
|
if (tab.URL?.starts(with: "https://music.yandex.ru"))! {
|
||||||
if (!(tab.title?.hasSuffix("на Яндекс.Музыке"))!) {
|
if !(tab.title?.hasSuffix("на Яндекс.Музыке"))! {
|
||||||
tempTitle = tab.title!
|
tempTitle = tab.title!
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
} else if ((tab.URL?.starts(with: "https://vk.com/audios"))! || (tab.URL?.starts(with: "https://vk.com/music"))!) {
|
} else if (tab.URL?.starts(with: "https://vk.com/audios"))! || (tab.URL?.starts(with: "https://vk.com/music"))! {
|
||||||
tempTitle = tab.title!
|
tempTitle = tab.title!
|
||||||
break
|
break
|
||||||
} else if (tab.URL?.starts(with: "https://www.youtube.com/watch"))! {
|
} else if (tab.URL?.starts(with: "https://www.youtube.com/watch"))! {
|
||||||
@ -226,13 +226,13 @@ class MusicBarItem: CustomButtonTouchBarItem {
|
|||||||
ident = ""
|
ident = ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tempTitle == self.songTitle) {
|
if tempTitle == self.songTitle {
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
self.songTitle = tempTitle
|
self.songTitle = tempTitle
|
||||||
}
|
}
|
||||||
|
|
||||||
if let songTitle = self.songTitle?.ifNotEmpty {
|
if let songTitle = self.songTitle?.ifNotEmpty {
|
||||||
self.title = " " + songTitle + " "
|
self.title = " " + songTitle + " "
|
||||||
titleUpdated = true
|
titleUpdated = true
|
||||||
@ -251,12 +251,12 @@ class MusicBarItem: CustomButtonTouchBarItem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
if !iconUpdated {
|
if !iconUpdated {
|
||||||
self.image = nil
|
self.image = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if !titleUpdated {
|
if !titleUpdated {
|
||||||
self.title = ""
|
self.title = ""
|
||||||
}
|
}
|
||||||
@ -265,18 +265,20 @@ class MusicBarItem: CustomButtonTouchBarItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@objc protocol SpotifyApplication {
|
@objc protocol SpotifyApplication {
|
||||||
@objc optional var currentTrack: SpotifyTrack {get}
|
@objc optional var currentTrack: SpotifyTrack { get }
|
||||||
@objc optional func nextTrack()
|
@objc optional func nextTrack()
|
||||||
@objc optional func previousTrack()
|
@objc optional func previousTrack()
|
||||||
@objc optional func playpause()
|
@objc optional func playpause()
|
||||||
}
|
}
|
||||||
extension SBApplication: SpotifyApplication{}
|
|
||||||
|
extension SBApplication: SpotifyApplication {}
|
||||||
|
|
||||||
@objc protocol SpotifyTrack {
|
@objc protocol SpotifyTrack {
|
||||||
@objc optional var artist: String {get}
|
@objc optional var artist: String { get }
|
||||||
@objc optional var name: String {get}
|
@objc optional var name: String { get }
|
||||||
}
|
}
|
||||||
extension SBObject: SpotifyTrack{}
|
|
||||||
|
extension SBObject: SpotifyTrack {}
|
||||||
|
|
||||||
extension SpotifyApplication {
|
extension SpotifyApplication {
|
||||||
var title: String {
|
var title: String {
|
||||||
@ -285,20 +287,21 @@ extension SpotifyApplication {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@objc protocol iTunesApplication {
|
@objc protocol iTunesApplication {
|
||||||
@objc optional var currentTrack: iTunesTrack {get}
|
@objc optional var currentTrack: iTunesTrack { get }
|
||||||
@objc optional func playpause()
|
@objc optional func playpause()
|
||||||
@objc optional func nextTrack()
|
@objc optional func nextTrack()
|
||||||
@objc optional func previousTrack()
|
@objc optional func previousTrack()
|
||||||
}
|
}
|
||||||
extension SBApplication: iTunesApplication{}
|
|
||||||
|
extension SBApplication: iTunesApplication {}
|
||||||
|
|
||||||
@objc protocol iTunesTrack {
|
@objc protocol iTunesTrack {
|
||||||
@objc optional var artist: String {get}
|
@objc optional var artist: String { get }
|
||||||
@objc optional var name: String {get}
|
@objc optional var name: String { get }
|
||||||
}
|
}
|
||||||
extension SBObject: iTunesTrack{}
|
|
||||||
|
extension SBObject: iTunesTrack {}
|
||||||
|
|
||||||
extension iTunesApplication {
|
extension iTunesApplication {
|
||||||
var title: String {
|
var title: String {
|
||||||
@ -307,16 +310,15 @@ extension iTunesApplication {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@objc protocol VoxApplication {
|
@objc protocol VoxApplication {
|
||||||
@objc optional func playpause()
|
@objc optional func playpause()
|
||||||
@objc optional func next()
|
@objc optional func next()
|
||||||
@objc optional func previous()
|
@objc optional func previous()
|
||||||
@objc optional var track: String {get}
|
@objc optional var track: String { get }
|
||||||
@objc optional var artist: String {get}
|
@objc optional var artist: String { get }
|
||||||
}
|
}
|
||||||
extension SBApplication: VoxApplication{}
|
|
||||||
|
extension SBApplication: VoxApplication {}
|
||||||
|
|
||||||
extension VoxApplication {
|
extension VoxApplication {
|
||||||
var title: String {
|
var title: String {
|
||||||
@ -324,7 +326,6 @@ extension VoxApplication {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@objc public protocol SBObjectProtocol: NSObjectProtocol {
|
@objc public protocol SBObjectProtocol: NSObjectProtocol {
|
||||||
func get() -> Any!
|
func get() -> Any!
|
||||||
}
|
}
|
||||||
@ -338,6 +339,7 @@ extension VoxApplication {
|
|||||||
@objc optional func windows() -> SBElementArray
|
@objc optional func windows() -> SBElementArray
|
||||||
@objc optional func doJavaScript(_ x: String!, in in_: Any!) -> Any // Applies a string of JavaScript code to a document.
|
@objc optional func doJavaScript(_ x: String!, in in_: Any!) -> Any // Applies a string of JavaScript code to a document.
|
||||||
}
|
}
|
||||||
|
|
||||||
extension SBApplication: SafariApplication {}
|
extension SBApplication: SafariApplication {}
|
||||||
|
|
||||||
@objc public protocol SafariWindow: SBObjectProtocol {
|
@objc public protocol SafariWindow: SBObjectProtocol {
|
||||||
@ -346,36 +348,39 @@ extension SBApplication: SafariApplication {}
|
|||||||
// @objc optional var document: SafariDocument { get } // The document whose contents are displayed in the window.
|
// @objc optional var document: SafariDocument { get } // The document whose contents are displayed in the window.
|
||||||
// @objc optional func setCurrentTab(_ currentTab: SafariTab!) // The current tab.
|
// @objc optional func setCurrentTab(_ currentTab: SafariTab!) // The current tab.
|
||||||
}
|
}
|
||||||
|
|
||||||
extension SBObject: SafariWindow {}
|
extension SBObject: SafariWindow {}
|
||||||
|
|
||||||
//@objc public protocol SafariDocument: SBObjectProtocol {
|
// @objc public protocol SafariDocument: SBObjectProtocol {
|
||||||
// @objc optional var name: String { get } // Its name.
|
// @objc optional var name: String { get } // Its name.
|
||||||
// @objc optional var URL: String { get } // The current URL of the document.
|
// @objc optional var URL: String { get } // The current URL of the document.
|
||||||
//}
|
// }
|
||||||
//extension SBObject: SafariDocument {}
|
// extension SBObject: SafariDocument {}
|
||||||
|
|
||||||
@objc public protocol SafariTab: SBObjectProtocol {
|
@objc public protocol SafariTab: SBObjectProtocol {
|
||||||
@objc optional var URL: String { get } // The current URL of the tab.
|
@objc optional var URL: String { get } // The current URL of the tab.
|
||||||
@objc optional var name: String { get } // The name of the tab.
|
@objc optional var name: String { get } // The name of the tab.
|
||||||
}
|
}
|
||||||
|
|
||||||
extension SBObject: SafariTab {}
|
extension SBObject: SafariTab {}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@objc public protocol GoogleChromeApplication: SBApplicationProtocol {
|
@objc public protocol GoogleChromeApplication: SBApplicationProtocol {
|
||||||
@objc optional func windows() -> SBElementArray
|
@objc optional func windows() -> SBElementArray
|
||||||
@objc optional func executeJavaScript(javascript: String!) -> Any // Applies a string of JavaScript code to a document. //, id: Any!
|
@objc optional func executeJavaScript(javascript: String!) -> Any // Applies a string of JavaScript code to a document. //, id: Any!
|
||||||
}
|
}
|
||||||
|
|
||||||
extension SBApplication: GoogleChromeApplication {}
|
extension SBApplication: GoogleChromeApplication {}
|
||||||
|
|
||||||
@objc public protocol GoogleChromeWindow: SBObjectProtocol {
|
@objc public protocol GoogleChromeWindow: SBObjectProtocol {
|
||||||
@objc optional var name: String { get } // The title of the window.
|
@objc optional var name: String { get } // The title of the window.
|
||||||
@objc optional func tabs() -> SBElementArray
|
@objc optional func tabs() -> SBElementArray
|
||||||
}
|
}
|
||||||
|
|
||||||
extension SBObject: GoogleChromeWindow {}
|
extension SBObject: GoogleChromeWindow {}
|
||||||
|
|
||||||
@objc public protocol GoogleChromeTab: SBObjectProtocol {
|
@objc public protocol GoogleChromeTab: SBObjectProtocol {
|
||||||
@objc optional var URL: String { get } // The current URL of the tab.
|
@objc optional var URL: String { get } // The current URL of the tab.
|
||||||
@objc optional var title: String { get } // The name of the tab.
|
@objc optional var title: String { get } // The name of the tab.
|
||||||
}
|
}
|
||||||
|
|
||||||
extension SBObject: GoogleChromeTab {}
|
extension SBObject: GoogleChromeTab {}
|
||||||
|
|||||||
@ -11,43 +11,43 @@ import Foundation
|
|||||||
class NightShiftBarItem: CustomButtonTouchBarItem {
|
class NightShiftBarItem: CustomButtonTouchBarItem {
|
||||||
private let nsclient = CBBlueLightClient()
|
private let nsclient = CBBlueLightClient()
|
||||||
private var timer: Timer!
|
private var timer: Timer!
|
||||||
|
|
||||||
private var blueLightStatus: Status {
|
private var blueLightStatus: Status {
|
||||||
var status: Status = Status()
|
var status: Status = Status()
|
||||||
nsclient.getBlueLightStatus(&status)
|
nsclient.getBlueLightStatus(&status)
|
||||||
return status
|
return status
|
||||||
}
|
}
|
||||||
|
|
||||||
private var isNightShiftEnabled: Bool {
|
private var isNightShiftEnabled: Bool {
|
||||||
return self.blueLightStatus.enabled.boolValue
|
return blueLightStatus.enabled.boolValue
|
||||||
}
|
}
|
||||||
|
|
||||||
private func setNightShift(state: Bool) {
|
private func setNightShift(state: Bool) {
|
||||||
self.nsclient.setEnabled(state)
|
nsclient.setEnabled(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
init(identifier: NSTouchBarItem.Identifier) {
|
init(identifier: NSTouchBarItem.Identifier) {
|
||||||
super.init(identifier: identifier, title: "")
|
super.init(identifier: identifier, title: "")
|
||||||
self.isBordered = false
|
isBordered = false
|
||||||
self.setWidth(value: 28)
|
setWidth(value: 28)
|
||||||
|
|
||||||
|
tapClosure = { [weak self] in self?.nightShiftAction() }
|
||||||
|
|
||||||
self.tapClosure = { [weak self] in self?.nightShiftAction() }
|
|
||||||
|
|
||||||
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(refresh), userInfo: nil, repeats: true)
|
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(refresh), userInfo: nil, repeats: true)
|
||||||
|
|
||||||
self.refresh()
|
refresh()
|
||||||
}
|
}
|
||||||
|
|
||||||
required init?(coder: NSCoder) {
|
required init?(coder _: NSCoder) {
|
||||||
fatalError("init(coder:) has not been implemented")
|
fatalError("init(coder:) has not been implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
func nightShiftAction() {
|
func nightShiftAction() {
|
||||||
self.setNightShift(state: !self.isNightShiftEnabled)
|
setNightShift(state: !isNightShiftEnabled)
|
||||||
self.refresh()
|
refresh()
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func refresh() {
|
@objc func refresh() {
|
||||||
self.image = isNightShiftEnabled ? #imageLiteral(resourceName: "nightShiftOn") : #imageLiteral(resourceName: "nightShiftOff")
|
image = isNightShiftEnabled ? #imageLiteral(resourceName: "nightShiftOn") : #imageLiteral(resourceName: "nightShiftOff")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,21 +3,20 @@ import Cocoa
|
|||||||
class TimeTouchBarItem: CustomButtonTouchBarItem {
|
class TimeTouchBarItem: CustomButtonTouchBarItem {
|
||||||
private let dateFormatter = DateFormatter()
|
private let dateFormatter = DateFormatter()
|
||||||
private var timer: Timer!
|
private var timer: Timer!
|
||||||
|
|
||||||
init(identifier: NSTouchBarItem.Identifier, formatTemplate: String) {
|
init(identifier: NSTouchBarItem.Identifier, formatTemplate: String) {
|
||||||
dateFormatter.setLocalizedDateFormatFromTemplate(formatTemplate)
|
dateFormatter.setLocalizedDateFormatFromTemplate(formatTemplate)
|
||||||
super.init(identifier: identifier, title: " ")
|
super.init(identifier: identifier, title: " ")
|
||||||
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(updateTime), userInfo: nil, repeats: true)
|
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(updateTime), userInfo: nil, repeats: true)
|
||||||
self.isBordered = false
|
isBordered = false
|
||||||
updateTime()
|
updateTime()
|
||||||
}
|
}
|
||||||
|
|
||||||
required init?(coder: NSCoder) {
|
required init?(coder _: NSCoder) {
|
||||||
fatalError("init(coder:) has not been implemented")
|
fatalError("init(coder:) has not been implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func updateTime() {
|
@objc func updateTime() {
|
||||||
self.title = self.dateFormatter.string(from: Date())
|
title = dateFormatter.string(from: Date())
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,55 +1,56 @@
|
|||||||
import Cocoa
|
|
||||||
import AppKit
|
import AppKit
|
||||||
import AVFoundation
|
import AVFoundation
|
||||||
|
import Cocoa
|
||||||
import CoreAudio
|
import CoreAudio
|
||||||
|
|
||||||
class VolumeViewController: NSCustomTouchBarItem {
|
class VolumeViewController: NSCustomTouchBarItem {
|
||||||
private(set) var sliderItem: CustomSlider!
|
private(set) var sliderItem: CustomSlider!
|
||||||
|
|
||||||
init(identifier: NSTouchBarItem.Identifier, image: NSImage? = nil) {
|
init(identifier: NSTouchBarItem.Identifier, image: NSImage? = nil) {
|
||||||
super.init(identifier: identifier)
|
super.init(identifier: identifier)
|
||||||
|
|
||||||
var forPropertyAddress = AudioObjectPropertyAddress(
|
var forPropertyAddress = AudioObjectPropertyAddress(
|
||||||
mSelector: kAudioHardwareServiceDeviceProperty_VirtualMasterVolume,
|
mSelector: kAudioHardwareServiceDeviceProperty_VirtualMasterVolume,
|
||||||
mScope: kAudioDevicePropertyScopeOutput,
|
mScope: kAudioDevicePropertyScopeOutput,
|
||||||
mElement: kAudioObjectPropertyElementMaster)
|
mElement: kAudioObjectPropertyElementMaster
|
||||||
|
)
|
||||||
|
|
||||||
AudioObjectAddPropertyListenerBlock(defaultDeviceID, &forPropertyAddress, nil, audioObjectPropertyListenerBlock)
|
AudioObjectAddPropertyListenerBlock(defaultDeviceID, &forPropertyAddress, nil, audioObjectPropertyListenerBlock)
|
||||||
|
|
||||||
if (image == nil) {
|
if image == nil {
|
||||||
sliderItem = CustomSlider()
|
sliderItem = CustomSlider()
|
||||||
} else {
|
} else {
|
||||||
sliderItem = CustomSlider(knob: image!)
|
sliderItem = CustomSlider(knob: image!)
|
||||||
}
|
}
|
||||||
sliderItem.target = self
|
sliderItem.target = self
|
||||||
sliderItem.action = #selector(VolumeViewController.sliderValueChanged(_:))
|
sliderItem.action = #selector(VolumeViewController.sliderValueChanged(_:))
|
||||||
sliderItem.minValue = 0.0
|
sliderItem.minValue = 0.0
|
||||||
sliderItem.maxValue = 100.0
|
sliderItem.maxValue = 100.0
|
||||||
sliderItem.floatValue = getInputGain()*100
|
sliderItem.floatValue = getInputGain() * 100
|
||||||
|
|
||||||
self.view = sliderItem
|
view = sliderItem
|
||||||
}
|
}
|
||||||
|
|
||||||
func audioObjectPropertyListenerBlock (numberAddresses: UInt32, addresses: UnsafePointer<AudioObjectPropertyAddress>) {
|
func audioObjectPropertyListenerBlock(numberAddresses _: UInt32, addresses _: UnsafePointer<AudioObjectPropertyAddress>) {
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.sliderItem.floatValue = self.getInputGain() * 100
|
self.sliderItem.floatValue = self.getInputGain() * 100
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
required init?(coder: NSCoder) {
|
required init?(coder _: NSCoder) {
|
||||||
fatalError("init(coder:) has not been implemented")
|
fatalError("init(coder:) has not been implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
sliderItem.unbind(NSBindingName.value)
|
sliderItem.unbind(NSBindingName.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func sliderValueChanged(_ sender: Any) {
|
@objc func sliderValueChanged(_ sender: Any) {
|
||||||
if let sliderItem = sender as? NSSlider {
|
if let sliderItem = sender as? NSSlider {
|
||||||
_ = setInputGain(Float32(sliderItem.intValue)/100.0)
|
_ = setInputGain(Float32(sliderItem.intValue) / 100.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var defaultDeviceID: AudioObjectID {
|
private var defaultDeviceID: AudioObjectID {
|
||||||
var deviceID: AudioObjectID = AudioObjectID(0)
|
var deviceID: AudioObjectID = AudioObjectID(0)
|
||||||
var size: UInt32 = UInt32(MemoryLayout<AudioObjectID>.size)
|
var size: UInt32 = UInt32(MemoryLayout<AudioObjectID>.size)
|
||||||
@ -60,7 +61,7 @@ class VolumeViewController: NSCustomTouchBarItem {
|
|||||||
AudioObjectGetPropertyData(AudioObjectID(kAudioObjectSystemObject), &address, 0, nil, &size, &deviceID)
|
AudioObjectGetPropertyData(AudioObjectID(kAudioObjectSystemObject), &address, 0, nil, &size, &deviceID)
|
||||||
return deviceID
|
return deviceID
|
||||||
}
|
}
|
||||||
|
|
||||||
private func getInputGain() -> Float32 {
|
private func getInputGain() -> Float32 {
|
||||||
var volume: Float32 = 0.5
|
var volume: Float32 = 0.5
|
||||||
var size: UInt32 = UInt32(MemoryLayout.size(ofValue: volume))
|
var size: UInt32 = UInt32(MemoryLayout.size(ofValue: volume))
|
||||||
@ -71,16 +72,16 @@ class VolumeViewController: NSCustomTouchBarItem {
|
|||||||
AudioObjectGetPropertyData(defaultDeviceID, &address, 0, nil, &size, &volume)
|
AudioObjectGetPropertyData(defaultDeviceID, &address, 0, nil, &size, &volume)
|
||||||
return volume
|
return volume
|
||||||
}
|
}
|
||||||
|
|
||||||
private func setInputGain(_ volume: Float32) -> OSStatus {
|
private func setInputGain(_ volume: Float32) -> OSStatus {
|
||||||
var inputVolume: Float32 = volume
|
var inputVolume: Float32 = volume
|
||||||
|
|
||||||
if inputVolume == 0.0 {
|
if inputVolume == 0.0 {
|
||||||
_ = setMute( mute: 1)
|
_ = setMute(mute: 1)
|
||||||
} else {
|
} else {
|
||||||
_ = setMute( mute: 0)
|
_ = setMute(mute: 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
let size: UInt32 = UInt32(MemoryLayout.size(ofValue: inputVolume))
|
let size: UInt32 = UInt32(MemoryLayout.size(ofValue: inputVolume))
|
||||||
var address: AudioObjectPropertyAddress = AudioObjectPropertyAddress()
|
var address: AudioObjectPropertyAddress = AudioObjectPropertyAddress()
|
||||||
address.mScope = AudioObjectPropertyScope(kAudioDevicePropertyScopeOutput)
|
address.mScope = AudioObjectPropertyScope(kAudioDevicePropertyScopeOutput)
|
||||||
@ -88,8 +89,8 @@ class VolumeViewController: NSCustomTouchBarItem {
|
|||||||
address.mSelector = AudioObjectPropertySelector(kAudioHardwareServiceDeviceProperty_VirtualMasterVolume)
|
address.mSelector = AudioObjectPropertySelector(kAudioHardwareServiceDeviceProperty_VirtualMasterVolume)
|
||||||
return AudioObjectSetPropertyData(defaultDeviceID, &address, 0, nil, size, &inputVolume)
|
return AudioObjectSetPropertyData(defaultDeviceID, &address, 0, nil, size, &inputVolume)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func setMute( mute: Int) -> OSStatus {
|
private func setMute(mute: Int) -> OSStatus {
|
||||||
var muteVal: Int = mute
|
var muteVal: Int = mute
|
||||||
var address: AudioObjectPropertyAddress = AudioObjectPropertyAddress()
|
var address: AudioObjectPropertyAddress = AudioObjectPropertyAddress()
|
||||||
address.mSelector = AudioObjectPropertySelector(kAudioDevicePropertyMute)
|
address.mSelector = AudioObjectPropertySelector(kAudioDevicePropertyMute)
|
||||||
@ -99,4 +100,3 @@ class VolumeViewController: NSCustomTouchBarItem {
|
|||||||
return AudioObjectSetPropertyData(defaultDeviceID, &address, 0, nil, size, &muteVal)
|
return AudioObjectSetPropertyData(defaultDeviceID, &address, 0, nil, size, &muteVal)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -16,42 +16,42 @@ class WeatherBarItem: CustomButtonTouchBarItem, CLLocationManagerDelegate {
|
|||||||
private var units_str = "°F"
|
private var units_str = "°F"
|
||||||
private var prev_location: CLLocation!
|
private var prev_location: CLLocation!
|
||||||
private var location: CLLocation!
|
private var location: CLLocation!
|
||||||
private let iconsImages = ["01d": "☀️", "01n": "☀️", "02d": "⛅️", "02n": "⛅️", "03d": "☁️", "03n": "☁️", "04d": "☁️", "04n": "☁️", "09d": "⛅️", "09n": "⛅️", "10d": "🌦", "10n": "🌦", "11d": "🌩", "11n": "🌩", "13d": "❄️", "13n": "❄️", "50d": "🌫", "50n": "🌫"]
|
private let iconsImages = ["01d": "☀️", "01n": "☀️", "02d": "⛅️", "02n": "⛅️", "03d": "☁️", "03n": "☁️", "04d": "☁️", "04n": "☁️", "09d": "⛅️", "09n": "⛅️", "10d": "🌦", "10n": "🌦", "11d": "🌩", "11n": "🌩", "13d": "❄️", "13n": "❄️", "50d": "🌫", "50n": "🌫"]
|
||||||
private let iconsText = ["01d": "☀", "01n": "☀", "02d": "☁", "02n": "☁", "03d": "☁", "03n": "☁", "04d": "☁", "04n": "☁", "09d": "☂", "09n": "☂", "10d": "☂", "10n": "☂", "11d": "☈", "11n": "☈", "13d": "☃", "13n": "☃", "50d": "♨", "50n": "♨"]
|
private let iconsText = ["01d": "☀", "01n": "☀", "02d": "☁", "02n": "☁", "03d": "☁", "03n": "☁", "04d": "☁", "04n": "☁", "09d": "☂", "09n": "☂", "10d": "☂", "10n": "☂", "11d": "☈", "11n": "☈", "13d": "☃", "13n": "☃", "50d": "♨", "50n": "♨"]
|
||||||
private var iconsSource: Dictionary<String, String>
|
private var iconsSource: Dictionary<String, String>
|
||||||
|
|
||||||
private var manager:CLLocationManager!
|
private var manager: CLLocationManager!
|
||||||
|
|
||||||
init(identifier: NSTouchBarItem.Identifier, interval: TimeInterval, units: String, api_key: String, icon_type: String? = "text") {
|
init(identifier: NSTouchBarItem.Identifier, interval: TimeInterval, units: String, api_key: String, icon_type: String? = "text") {
|
||||||
activity = NSBackgroundActivityScheduler(identifier: "\(identifier.rawValue).updatecheck")
|
activity = NSBackgroundActivityScheduler(identifier: "\(identifier.rawValue).updatecheck")
|
||||||
activity.interval = interval
|
activity.interval = interval
|
||||||
self.units = units
|
self.units = units
|
||||||
self.api_key = api_key
|
self.api_key = api_key
|
||||||
|
|
||||||
if self.units == "metric" {
|
if self.units == "metric" {
|
||||||
units_str = "°C"
|
units_str = "°C"
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.units == "imperial" {
|
if self.units == "imperial" {
|
||||||
units_str = "°F"
|
units_str = "°F"
|
||||||
}
|
}
|
||||||
|
|
||||||
if icon_type == "images" {
|
if icon_type == "images" {
|
||||||
iconsSource = iconsImages
|
iconsSource = iconsImages
|
||||||
} else {
|
} else {
|
||||||
iconsSource = iconsText
|
iconsSource = iconsText
|
||||||
}
|
}
|
||||||
|
|
||||||
super.init(identifier: identifier, title: "⏳")
|
super.init(identifier: identifier, title: "⏳")
|
||||||
|
|
||||||
let status = CLLocationManager.authorizationStatus()
|
let status = CLLocationManager.authorizationStatus()
|
||||||
if status == .restricted || status == .denied {
|
if status == .restricted || status == .denied {
|
||||||
print("User permission not given")
|
print("User permission not given")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !CLLocationManager.locationServicesEnabled() {
|
if !CLLocationManager.locationServicesEnabled() {
|
||||||
print("Location services not enabled");
|
print("Location services not enabled")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,43 +62,43 @@ class WeatherBarItem: CustomButtonTouchBarItem, CLLocationManagerDelegate {
|
|||||||
completion(NSBackgroundActivityScheduler.Result.finished)
|
completion(NSBackgroundActivityScheduler.Result.finished)
|
||||||
}
|
}
|
||||||
updateWeather()
|
updateWeather()
|
||||||
|
|
||||||
manager = CLLocationManager()
|
manager = CLLocationManager()
|
||||||
manager.delegate = self
|
manager.delegate = self
|
||||||
manager.desiredAccuracy = kCLLocationAccuracyHundredMeters
|
manager.desiredAccuracy = kCLLocationAccuracyHundredMeters
|
||||||
manager.startUpdatingLocation()
|
manager.startUpdatingLocation()
|
||||||
}
|
}
|
||||||
|
|
||||||
required init?(coder: NSCoder) {
|
required init?(coder _: NSCoder) {
|
||||||
fatalError("init(coder:) has not been implemented")
|
fatalError("init(coder:) has not been implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func updateWeather() {
|
@objc func updateWeather() {
|
||||||
if self.location != nil {
|
if location != nil {
|
||||||
let urlRequest = URLRequest(url: URL(string: "https://api.openweathermap.org/data/2.5/weather?lat=\(location.coordinate.latitude)&lon=\(location.coordinate.longitude)&units=\(self.units)&appid=\(self.api_key)")!)
|
let urlRequest = URLRequest(url: URL(string: "https://api.openweathermap.org/data/2.5/weather?lat=\(location.coordinate.latitude)&lon=\(location.coordinate.longitude)&units=\(units)&appid=\(api_key)")!)
|
||||||
|
|
||||||
let task = URLSession.shared.dataTask(with: urlRequest) { (data, response, error) in
|
let task = URLSession.shared.dataTask(with: urlRequest) { data, _, error in
|
||||||
|
|
||||||
if error == nil {
|
if error == nil {
|
||||||
do {
|
do {
|
||||||
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as! [String : AnyObject]
|
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as! [String: AnyObject]
|
||||||
// print(json)
|
// print(json)
|
||||||
var temperature: Int!
|
var temperature: Int!
|
||||||
var condition_icon = ""
|
var condition_icon = ""
|
||||||
|
|
||||||
if let main = json["main"] as? [String : AnyObject] {
|
if let main = json["main"] as? [String: AnyObject] {
|
||||||
if let temp = main["temp"] as? Double {
|
if let temp = main["temp"] as? Double {
|
||||||
temperature = Int(temp)
|
temperature = Int(temp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let weather = json["weather"] as? NSArray, let item = weather[0] as? NSDictionary {
|
if let weather = json["weather"] as? NSArray, let item = weather[0] as? NSDictionary {
|
||||||
let icon = item["icon"] as! String
|
let icon = item["icon"] as! String
|
||||||
if let test = self.iconsSource[icon] {
|
if let test = self.iconsSource[icon] {
|
||||||
condition_icon = test
|
condition_icon = test
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if temperature != nil {
|
if temperature != nil {
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.setWeather(text: "\(condition_icon) \(temperature!)\(self.units_str)")
|
self.setWeather(text: "\(condition_icon) \(temperature!)\(self.units_str)")
|
||||||
@ -109,31 +109,30 @@ class WeatherBarItem: CustomButtonTouchBarItem, CLLocationManagerDelegate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
task.resume()
|
task.resume()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func setWeather(text: String) {
|
func setWeather(text: String) {
|
||||||
self.title = text
|
title = text
|
||||||
}
|
}
|
||||||
|
|
||||||
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
|
func locationManager(_: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
|
||||||
let lastLocation = locations.last!
|
let lastLocation = locations.last!
|
||||||
self.location = lastLocation
|
location = lastLocation
|
||||||
if prev_location == nil {
|
if prev_location == nil {
|
||||||
updateWeather()
|
updateWeather()
|
||||||
}
|
}
|
||||||
prev_location = lastLocation
|
prev_location = lastLocation
|
||||||
}
|
}
|
||||||
|
|
||||||
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
|
func locationManager(_: CLLocationManager, didFailWithError error: Error) {
|
||||||
print(error);
|
print(error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
|
func locationManager(_: CLLocationManager, didChangeAuthorization _: CLAuthorizationStatus) {
|
||||||
// print("inside didChangeAuthorization ");
|
// print("inside didChangeAuthorization ");
|
||||||
updateWeather()
|
updateWeather()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user