mirror of
https://github.com/Toxblh/MTMR.git
synced 2026-01-11 17:38:38 +00:00
Refactored parsing
Rewrote presets parsing. Instead of parsing presets in a separate file using bunch of huge enums it is now parsed inside each object. To implement a new class: 1. Derive your class from CustomTouchBarItem (for static) or CustomButtonTouchBarItem (for buttons) 2. Override class var typeIdentifier with your object identificator 3. Override init(from decoder: Decoder) and read all custom json params you need 4. Don't forget to call super.init(identifier: CustomTouchBarItem.createIdentifier(type)) in the init() function 5. Add your new class to BarItemDefinition.types in ItemParsing.swift Good example is PomodoroBarItem If you want to inherid from some other NS class (NSSlider or NSPopoverTouchBarItem or other) then look into GroupBarItem and BrightnessViewController
This commit is contained in:
parent
c51b6acdf1
commit
101a81bf3b
@ -6,10 +6,42 @@ class AppleScriptTouchBarItem: CustomButtonTouchBarItem {
|
|||||||
private var forceHideConstraint: NSLayoutConstraint!
|
private var forceHideConstraint: NSLayoutConstraint!
|
||||||
private let alternativeImages: [String: SourceProtocol]
|
private let alternativeImages: [String: SourceProtocol]
|
||||||
|
|
||||||
|
private enum CodingKeys: String, CodingKey {
|
||||||
|
case source
|
||||||
|
case alternativeImages
|
||||||
|
case refreshInterval
|
||||||
|
}
|
||||||
|
|
||||||
|
override class var typeIdentifier: String {
|
||||||
|
return "appleScriptTitledButton"
|
||||||
|
}
|
||||||
|
|
||||||
init?(identifier: NSTouchBarItem.Identifier, source: SourceProtocol, interval: TimeInterval, alternativeImages: [String: SourceProtocol]) {
|
init?(identifier: NSTouchBarItem.Identifier, source: SourceProtocol, interval: TimeInterval, alternativeImages: [String: SourceProtocol]) {
|
||||||
self.interval = interval
|
self.interval = interval
|
||||||
self.alternativeImages = alternativeImages
|
self.alternativeImages = alternativeImages
|
||||||
super.init(identifier: identifier, title: "⏳")
|
super.init(identifier: identifier, title: "⏳")
|
||||||
|
|
||||||
|
initScripts(source: source)
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder _: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
required init(from decoder: Decoder) throws {
|
||||||
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
|
let source = try container.decode(Source.self, forKey: .source)
|
||||||
|
self.interval = try container.decodeIfPresent(Double.self, forKey: .refreshInterval) ?? 1800.0
|
||||||
|
self.alternativeImages = try container.decodeIfPresent([String: Source].self, forKey: .alternativeImages) ?? [:]
|
||||||
|
|
||||||
|
print("AppleScriptTouchBarItem.init(from decoder)")
|
||||||
|
try super.init(from: decoder)
|
||||||
|
self.title = "⏳"
|
||||||
|
|
||||||
|
initScripts(source: source)
|
||||||
|
}
|
||||||
|
|
||||||
|
func initScripts(source: SourceProtocol) {
|
||||||
forceHideConstraint = view.widthAnchor.constraint(equalToConstant: 0)
|
forceHideConstraint = view.widthAnchor.constraint(equalToConstant: 0)
|
||||||
title = "scheduled"
|
title = "scheduled"
|
||||||
DispatchQueue.appleScriptQueue.async {
|
DispatchQueue.appleScriptQueue.async {
|
||||||
@ -38,10 +70,6 @@ class AppleScriptTouchBarItem: CustomButtonTouchBarItem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
required init?(coder _: NSCoder) {
|
|
||||||
fatalError("init(coder:) has not been implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
func refreshAndSchedule() {
|
func refreshAndSchedule() {
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
print("refresh happened (interval \(interval)), self \(identifier.rawValue))")
|
print("refresh happened (interval \(interval)), self \(identifier.rawValue))")
|
||||||
@ -62,7 +90,7 @@ class AppleScriptTouchBarItem: CustomButtonTouchBarItem {
|
|||||||
func updateIcon(iconLabel: String) {
|
func updateIcon(iconLabel: String) {
|
||||||
if alternativeImages[iconLabel] != nil {
|
if alternativeImages[iconLabel] != nil {
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.image = self.alternativeImages[iconLabel]!.image
|
self.setImage(self.alternativeImages[iconLabel]!.image)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
print("Cannot find icon with label \"\(iconLabel)\"")
|
print("Cannot find icon with label \"\(iconLabel)\"")
|
||||||
|
|||||||
@ -15,6 +15,7 @@ class BasicView: NSCustomTouchBarItem, NSGestureRecognizerDelegate {
|
|||||||
var threefingers: NSPanGestureRecognizer!
|
var threefingers: NSPanGestureRecognizer!
|
||||||
var fourfingers: NSPanGestureRecognizer!
|
var fourfingers: NSPanGestureRecognizer!
|
||||||
var swipeItems: [SwipeItem] = []
|
var swipeItems: [SwipeItem] = []
|
||||||
|
var items: [NSTouchBarItem] = []
|
||||||
var prevPositions: [Int: CGFloat] = [2:0, 3:0, 4:0]
|
var prevPositions: [Int: CGFloat] = [2:0, 3:0, 4:0]
|
||||||
|
|
||||||
// legacy gesture positions
|
// legacy gesture positions
|
||||||
@ -25,6 +26,7 @@ class BasicView: NSCustomTouchBarItem, NSGestureRecognizerDelegate {
|
|||||||
init(identifier: NSTouchBarItem.Identifier, items: [NSTouchBarItem], swipeItems: [SwipeItem]) {
|
init(identifier: NSTouchBarItem.Identifier, items: [NSTouchBarItem], swipeItems: [SwipeItem]) {
|
||||||
super.init(identifier: identifier)
|
super.init(identifier: identifier)
|
||||||
self.swipeItems = swipeItems
|
self.swipeItems = swipeItems
|
||||||
|
self.items = items
|
||||||
let views = items.compactMap { $0.view }
|
let views = items.compactMap { $0.view }
|
||||||
let stackView = NSStackView(views: views)
|
let stackView = NSStackView(views: views)
|
||||||
stackView.spacing = 1
|
stackView.spacing = 1
|
||||||
|
|||||||
@ -8,24 +8,130 @@
|
|||||||
|
|
||||||
import Cocoa
|
import Cocoa
|
||||||
|
|
||||||
class CustomButtonTouchBarItem: NSCustomTouchBarItem, NSGestureRecognizerDelegate {
|
enum Align: String, Decodable {
|
||||||
var tapClosure: (() -> Void)?
|
case left
|
||||||
var longTapClosure: (() -> Void)? {
|
case center
|
||||||
didSet {
|
case right
|
||||||
longClick.isEnabled = longTapClosure != nil
|
}
|
||||||
|
|
||||||
|
// CustomTouchBarItem is a base class for all widgets
|
||||||
|
// This class provides some basic parameter parsing (width, align)
|
||||||
|
// To implement a new class:
|
||||||
|
// 1. Derive your class from CustomTouchBarItem (for static) or CustomButtonTouchBarItem (for buttons)
|
||||||
|
// 2. Override class var typeIdentifier with your object identificator
|
||||||
|
// 3. Override init(from decoder: Decoder) and read all custom json params you need
|
||||||
|
// 4. Don't forget to call super.init(identifier: CustomTouchBarItem.createIdentifier(type)) in the init() function
|
||||||
|
// 5. Add your new class to BarItemDefinition.types in ItemParsing.swift
|
||||||
|
//
|
||||||
|
// Good example is PomodoroBarItem
|
||||||
|
//
|
||||||
|
// If you want to inherid from some other NS class (NSSlider or NSPopoverTouchBarItem or other) then
|
||||||
|
// look into GroupBarItem and BrightnessViewController
|
||||||
|
|
||||||
|
class CustomTouchBarItem: NSCustomTouchBarItem, Decodable {
|
||||||
|
var align: Align
|
||||||
|
private var width: NSLayoutConstraint?
|
||||||
|
|
||||||
|
class var typeIdentifier: String {
|
||||||
|
return "NOTDEFINED"
|
||||||
|
}
|
||||||
|
|
||||||
|
func setWidth(value: CGFloat) {
|
||||||
|
guard value > 0 else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if let width = self.width {
|
||||||
|
width.isActive = false
|
||||||
|
}
|
||||||
|
self.width = view.widthAnchor.constraint(equalToConstant: value)
|
||||||
|
self.width!.isActive = true
|
||||||
|
}
|
||||||
|
|
||||||
|
func getWidth() -> CGFloat {
|
||||||
|
return width?.constant ?? 0.0
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum CodingKeys: String, CodingKey {
|
||||||
|
case type
|
||||||
|
case width
|
||||||
|
case align
|
||||||
|
// TODO move bordered and background from custom button class
|
||||||
|
//case bordered
|
||||||
|
//case background
|
||||||
|
//case title
|
||||||
|
}
|
||||||
|
|
||||||
|
override init(identifier: NSTouchBarItem.Identifier) {
|
||||||
|
self.align = .center
|
||||||
|
|
||||||
|
// setting width here wouldn't make any affect
|
||||||
|
super.init(identifier: identifier)
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder _: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
required init(from decoder: Decoder) throws {
|
||||||
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
|
|
||||||
|
let type = try container.decode(String.self, forKey: .type)
|
||||||
|
self.align = try container.decodeIfPresent(Align.self, forKey: .align) ?? .center
|
||||||
|
|
||||||
|
super.init(identifier: CustomTouchBarItem.createIdentifier(type))
|
||||||
|
|
||||||
|
if let width = try container.decodeIfPresent(CGFloat.self, forKey: .width) {
|
||||||
|
self.setWidth(value: width)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static func identifierBase(_ type: String) -> String {
|
||||||
|
return "com.toxblh.mtmr." + type
|
||||||
|
}
|
||||||
|
|
||||||
|
static func createIdentifier(_ type: String) -> NSTouchBarItem.Identifier {
|
||||||
|
let dateFormatter = DateFormatter()
|
||||||
|
dateFormatter.dateFormat = "HH-mm-ss"
|
||||||
|
let time = dateFormatter.string(from: Date())
|
||||||
|
let identifierString = CustomTouchBarItem.identifierBase(type).appending(time + "--" + UUID().uuidString)
|
||||||
|
return NSTouchBarItem.Identifier(identifierString)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CustomButtonTouchBarItem: CustomTouchBarItem, NSGestureRecognizerDelegate {
|
||||||
|
private var tapAction: EventAction?
|
||||||
|
private var longTapAction: EventAction?
|
||||||
var finishViewConfiguration: ()->() = {}
|
var finishViewConfiguration: ()->() = {}
|
||||||
|
override class var typeIdentifier: String {
|
||||||
|
return "staticButton"
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum CodingKeys: String, CodingKey {
|
||||||
|
case title
|
||||||
|
case bordered
|
||||||
|
case background
|
||||||
|
case image
|
||||||
|
case action
|
||||||
|
case longAction
|
||||||
|
}
|
||||||
|
|
||||||
private var button: NSButton!
|
private var button: NSButton!
|
||||||
private var singleClick: HapticClickGestureRecognizer!
|
private var singleClick: HapticClickGestureRecognizer!
|
||||||
private var longClick: LongPressGestureRecognizer!
|
private var longClick: LongPressGestureRecognizer!
|
||||||
|
private var attributedTitle: NSAttributedString
|
||||||
|
|
||||||
init(identifier: NSTouchBarItem.Identifier, title: String) {
|
init(identifier: NSTouchBarItem.Identifier, title: String) {
|
||||||
attributedTitle = title.defaultTouchbarAttributedString
|
attributedTitle = title.defaultTouchbarAttributedString
|
||||||
|
|
||||||
super.init(identifier: identifier)
|
super.init(identifier: identifier)
|
||||||
|
|
||||||
|
initButton(title: title, imageSource: nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func initButton(title: String, imageSource: Source?) {
|
||||||
button = CustomHeightButton(title: title, target: nil, action: nil)
|
button = CustomHeightButton(title: title, target: nil, action: nil)
|
||||||
|
self.setImage(imageSource?.image)
|
||||||
|
|
||||||
longClick = LongPressGestureRecognizer(target: self, action: #selector(handleGestureLong))
|
longClick = LongPressGestureRecognizer(target: self, action: #selector(handleGestureLong))
|
||||||
longClick.isEnabled = false
|
longClick.isEnabled = false
|
||||||
@ -33,6 +139,7 @@ class CustomButtonTouchBarItem: NSCustomTouchBarItem, NSGestureRecognizerDelegat
|
|||||||
longClick.delegate = self
|
longClick.delegate = self
|
||||||
|
|
||||||
singleClick = HapticClickGestureRecognizer(target: self, action: #selector(handleGestureSingle))
|
singleClick = HapticClickGestureRecognizer(target: self, action: #selector(handleGestureSingle))
|
||||||
|
singleClick.isEnabled = false
|
||||||
singleClick.allowedTouchTypes = .direct
|
singleClick.allowedTouchTypes = .direct
|
||||||
singleClick.delegate = self
|
singleClick.delegate = self
|
||||||
|
|
||||||
@ -40,6 +147,45 @@ class CustomButtonTouchBarItem: NSCustomTouchBarItem, NSGestureRecognizerDelegat
|
|||||||
button.attributedTitle = attributedTitle
|
button.attributedTitle = attributedTitle
|
||||||
}
|
}
|
||||||
|
|
||||||
|
required init(from decoder: Decoder) throws {
|
||||||
|
attributedTitle = "".defaultTouchbarAttributedString
|
||||||
|
|
||||||
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
|
let title = try container.decodeIfPresent(String.self, forKey: .title) ?? ""
|
||||||
|
|
||||||
|
try super.init(from: decoder)
|
||||||
|
|
||||||
|
if let borderedFlag = try container.decodeIfPresent(Bool.self, forKey: .bordered) {
|
||||||
|
self.isBordered = borderedFlag
|
||||||
|
}
|
||||||
|
|
||||||
|
if let bgColor = try container.decodeIfPresent(String.self, forKey: .background)?.hexColor {
|
||||||
|
self.backgroundColor = bgColor
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
let imageSource = try container.decodeIfPresent(Source.self, forKey: .image)
|
||||||
|
initButton(title: title, imageSource: imageSource)
|
||||||
|
|
||||||
|
self.setTapAction(try? SingleTapEventAction(from: decoder))
|
||||||
|
self.setLongTapAction(try? LongTapEventAction(from: decoder))
|
||||||
|
}
|
||||||
|
|
||||||
|
// From for static buttons
|
||||||
|
convenience init(title: String) {
|
||||||
|
self.init(identifier: CustomTouchBarItem.createIdentifier(CustomButtonTouchBarItem.typeIdentifier), title: title)
|
||||||
|
}
|
||||||
|
|
||||||
|
func setTapAction(_ action: EventAction?) {
|
||||||
|
self.tapAction = action
|
||||||
|
self.singleClick?.isEnabled = action != nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func setLongTapAction(_ action: EventAction?) {
|
||||||
|
self.longTapAction = action
|
||||||
|
self.longClick?.isEnabled = action != nil
|
||||||
|
}
|
||||||
|
|
||||||
required init?(coder _: NSCoder) {
|
required init?(coder _: NSCoder) {
|
||||||
fatalError("init(coder:) has not been implemented")
|
fatalError("init(coder:) has not been implemented")
|
||||||
}
|
}
|
||||||
@ -58,27 +204,35 @@ class CustomButtonTouchBarItem: NSCustomTouchBarItem, NSGestureRecognizerDelegat
|
|||||||
|
|
||||||
var title: String {
|
var title: String {
|
||||||
get {
|
get {
|
||||||
return attributedTitle.string
|
return getAttributedTitle().string
|
||||||
}
|
}
|
||||||
set {
|
set {
|
||||||
attributedTitle = newValue.defaultTouchbarAttributedString
|
setAttributedTitle(newValue.defaultTouchbarAttributedString)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var attributedTitle: NSAttributedString {
|
func getAttributedTitle() -> NSAttributedString {
|
||||||
didSet {
|
return attributedTitle
|
||||||
button?.imagePosition = attributedTitle.length > 0 ? .imageLeading : .imageOnly
|
|
||||||
button?.attributedTitle = attributedTitle
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var image: NSImage? {
|
func setAttributedTitle(_ attributedTitle: NSAttributedString) {
|
||||||
didSet {
|
self.attributedTitle = attributedTitle
|
||||||
button.image = image
|
button?.imagePosition = attributedTitle.length > 0 ? .imageLeading : .imageOnly
|
||||||
}
|
button?.attributedTitle = attributedTitle
|
||||||
}
|
}
|
||||||
|
|
||||||
private func reinstallButton() {
|
private var image: NSImage?
|
||||||
|
|
||||||
|
func getImage() -> NSImage? {
|
||||||
|
return image
|
||||||
|
}
|
||||||
|
|
||||||
|
func setImage(_ image: NSImage?) {
|
||||||
|
self.image = image
|
||||||
|
button.image = image
|
||||||
|
}
|
||||||
|
|
||||||
|
func reinstallButton() {
|
||||||
let title = button.attributedTitle
|
let title = button.attributedTitle
|
||||||
let image = button.image
|
let image = button.image
|
||||||
let cell = CustomButtonCell(parentItem: self)
|
let cell = CustomButtonCell(parentItem: self)
|
||||||
@ -116,7 +270,7 @@ class CustomButtonTouchBarItem: NSCustomTouchBarItem, NSGestureRecognizerDelegat
|
|||||||
@objc func handleGestureSingle(gr: NSClickGestureRecognizer) {
|
@objc func handleGestureSingle(gr: NSClickGestureRecognizer) {
|
||||||
switch gr.state {
|
switch gr.state {
|
||||||
case .ended:
|
case .ended:
|
||||||
tapClosure?()
|
self.tapAction?.closure(self)
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
@ -126,7 +280,7 @@ class CustomButtonTouchBarItem: NSCustomTouchBarItem, NSGestureRecognizerDelegat
|
|||||||
@objc func handleGestureLong(gr: NSPressGestureRecognizer) {
|
@objc func handleGestureLong(gr: NSPressGestureRecognizer) {
|
||||||
switch gr.state {
|
switch gr.state {
|
||||||
case .possible: // tiny hack because we're calling action manually
|
case .possible: // tiny hack because we're calling action manually
|
||||||
(self.longTapClosure ?? self.tapClosure)?()
|
(self.longTapAction?.closure ?? self.tapAction?.closure)?(self)
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
@ -156,7 +310,7 @@ class CustomButtonCell: NSButtonCell {
|
|||||||
if flag {
|
if flag {
|
||||||
setAttributedTitle(attributedTitle, withColor: .lightGray)
|
setAttributedTitle(attributedTitle, withColor: .lightGray)
|
||||||
} else if let parentItem = self.parentItem {
|
} else if let parentItem = self.parentItem {
|
||||||
attributedTitle = parentItem.attributedTitle
|
attributedTitle = parentItem.getAttributedTitle()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
184
MTMR/EventActions.swift
Normal file
184
MTMR/EventActions.swift
Normal file
@ -0,0 +1,184 @@
|
|||||||
|
//
|
||||||
|
// EventActions.swift
|
||||||
|
// MTMR
|
||||||
|
//
|
||||||
|
// Created by Fedor Zaitsev on 4/27/20.
|
||||||
|
// Copyright © 2020 Anton Palgunov. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
class EventAction {
|
||||||
|
var closure: ((_ caller: CustomButtonTouchBarItem) -> Void)
|
||||||
|
|
||||||
|
func setHidKeyClosure(keycode: Int32) -> EventAction {
|
||||||
|
closure = { (_ caller: CustomButtonTouchBarItem) in
|
||||||
|
HIDPostAuxKey(keycode)
|
||||||
|
}
|
||||||
|
return self
|
||||||
|
}
|
||||||
|
|
||||||
|
func setKeyPressClosure(keycode: Int) -> EventAction {
|
||||||
|
closure = { (_ caller: CustomButtonTouchBarItem) in
|
||||||
|
GenericKeyPress(keyCode: CGKeyCode(keycode)).send()
|
||||||
|
}
|
||||||
|
return self
|
||||||
|
}
|
||||||
|
|
||||||
|
func setAppleScriptClosure(appleScript: NSAppleScript) -> EventAction {
|
||||||
|
closure = { (_ caller: CustomButtonTouchBarItem) in
|
||||||
|
DispatchQueue.appleScriptQueue.async {
|
||||||
|
var error: NSDictionary?
|
||||||
|
appleScript.executeAndReturnError(&error)
|
||||||
|
if let error = error {
|
||||||
|
print("error \(error) when handling apple script ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return self
|
||||||
|
}
|
||||||
|
|
||||||
|
func setShellScriptClosure(executable: String, parameters: [String]) -> EventAction {
|
||||||
|
closure = { (_ caller: CustomButtonTouchBarItem) in
|
||||||
|
let task = Process()
|
||||||
|
task.launchPath = executable
|
||||||
|
task.arguments = parameters
|
||||||
|
task.launch()
|
||||||
|
}
|
||||||
|
return self
|
||||||
|
}
|
||||||
|
|
||||||
|
func setOpenUrlClosure(url: String) -> EventAction {
|
||||||
|
closure = { (_ caller: CustomButtonTouchBarItem) in
|
||||||
|
if let url = URL(string: url), NSWorkspace.shared.open(url) {
|
||||||
|
#if DEBUG
|
||||||
|
print("URL was successfully opened")
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
print("error", url)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return self
|
||||||
|
}
|
||||||
|
|
||||||
|
init() {
|
||||||
|
self.closure = { (_ caller: CustomButtonTouchBarItem) in }
|
||||||
|
}
|
||||||
|
|
||||||
|
init(_ closure: @escaping (_ caller: CustomButtonTouchBarItem) -> Void) {
|
||||||
|
self.closure = closure
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class LongTapEventAction: EventAction, Decodable {
|
||||||
|
private enum CodingKeys: String, CodingKey {
|
||||||
|
case longAction
|
||||||
|
case longKeycode
|
||||||
|
case longActionAppleScript
|
||||||
|
case longExecutablePath
|
||||||
|
case longShellArguments
|
||||||
|
case longUrl
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum LongActionTypeRaw: String, Decodable {
|
||||||
|
case hidKey
|
||||||
|
case keyPress
|
||||||
|
case appleScript
|
||||||
|
case shellScript
|
||||||
|
case openUrl
|
||||||
|
}
|
||||||
|
|
||||||
|
required init(from decoder: Decoder) throws {
|
||||||
|
super.init()
|
||||||
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
|
let type = try container.decodeIfPresent(LongActionTypeRaw.self, forKey: .longAction)
|
||||||
|
|
||||||
|
switch type {
|
||||||
|
case .some(.hidKey):
|
||||||
|
let keycode = try container.decode(Int32.self, forKey: .longKeycode)
|
||||||
|
|
||||||
|
_ = setHidKeyClosure(keycode: keycode)
|
||||||
|
case .some(.keyPress):
|
||||||
|
let keycode = try container.decode(Int.self, forKey: .longKeycode)
|
||||||
|
|
||||||
|
_ = setKeyPressClosure(keycode: keycode)
|
||||||
|
case .some(.appleScript):
|
||||||
|
let source = try container.decode(Source.self, forKey: .longActionAppleScript)
|
||||||
|
|
||||||
|
guard let appleScript = source.appleScript else {
|
||||||
|
print("cannot create apple script")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = setAppleScriptClosure(appleScript: appleScript)
|
||||||
|
case .some(.shellScript):
|
||||||
|
let executable = try container.decode(String.self, forKey: .longExecutablePath)
|
||||||
|
let parameters = try container.decodeIfPresent([String].self, forKey: .longShellArguments) ?? []
|
||||||
|
|
||||||
|
_ = setShellScriptClosure(executable: executable, parameters: parameters)
|
||||||
|
case .some(.openUrl):
|
||||||
|
let url = try container.decode(String.self, forKey: .longUrl)
|
||||||
|
|
||||||
|
_ = setOpenUrlClosure(url: url)
|
||||||
|
case .none:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SingleTapEventAction: EventAction, Decodable {
|
||||||
|
private enum CodingKeys: String, CodingKey {
|
||||||
|
case action
|
||||||
|
case keycode
|
||||||
|
case actionAppleScript
|
||||||
|
case executablePath
|
||||||
|
case shellArguments
|
||||||
|
case url
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum ActionTypeRaw: String, Decodable {
|
||||||
|
case hidKey
|
||||||
|
case keyPress
|
||||||
|
case appleScript
|
||||||
|
case shellScript
|
||||||
|
case openUrl
|
||||||
|
}
|
||||||
|
|
||||||
|
required init(from decoder: Decoder) throws {
|
||||||
|
super.init()
|
||||||
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
|
let type = try container.decodeIfPresent(ActionTypeRaw.self, forKey: .action)
|
||||||
|
|
||||||
|
switch type {
|
||||||
|
case .some(.hidKey):
|
||||||
|
let keycode = try container.decode(Int32.self, forKey: .keycode)
|
||||||
|
|
||||||
|
_ = setHidKeyClosure(keycode: keycode)
|
||||||
|
case .some(.keyPress):
|
||||||
|
let keycode = try container.decode(Int.self, forKey: .keycode)
|
||||||
|
|
||||||
|
_ = setKeyPressClosure(keycode: keycode)
|
||||||
|
case .some(.appleScript):
|
||||||
|
let source = try container.decode(Source.self, forKey: .actionAppleScript)
|
||||||
|
|
||||||
|
guard let appleScript = source.appleScript else {
|
||||||
|
print("cannot create apple script")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = setAppleScriptClosure(appleScript: appleScript)
|
||||||
|
case .some(.shellScript):
|
||||||
|
let executable = try container.decode(String.self, forKey: .executablePath)
|
||||||
|
let parameters = try container.decodeIfPresent([String].self, forKey: .shellArguments) ?? []
|
||||||
|
|
||||||
|
_ = setShellScriptClosure(executable: executable, parameters: parameters)
|
||||||
|
case .some(.openUrl):
|
||||||
|
let url = try container.decode(String.self, forKey: .url)
|
||||||
|
|
||||||
|
_ = setOpenUrlClosure(url: url)
|
||||||
|
case .none:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -19,7 +19,7 @@
|
|||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>0.25</string>
|
<string>0.25</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>402</string>
|
<string>622</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>
|
||||||
|
|||||||
@ -3,550 +3,90 @@ import Foundation
|
|||||||
|
|
||||||
extension Data {
|
extension Data {
|
||||||
func barItemDefinitions() -> [BarItemDefinition]? {
|
func barItemDefinitions() -> [BarItemDefinition]? {
|
||||||
return try? JSONDecoder().decode([BarItemDefinition].self, from: utf8string!.stripComments().data(using: .utf8)!)
|
return try? JSONDecoder().decode([BarItemDefinition].self, from: utf8string!.stripComments().data(using: .utf8)!)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct BarItemDefinition: Decodable {
|
struct BarItemDefinition: Decodable {
|
||||||
let type: ItemType
|
let obj: CustomTouchBarItem
|
||||||
let action: ActionType
|
|
||||||
let longAction: LongActionType
|
enum ParsingErrors: Error {
|
||||||
let additionalParameters: [GeneralParameters.CodingKeys: GeneralParameter]
|
case noMatchingType(description: String)
|
||||||
|
}
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
private enum CodingKeys: String, CodingKey {
|
||||||
case type
|
case objtype = "type"
|
||||||
}
|
}
|
||||||
|
|
||||||
init(type: ItemType, action: ActionType, longAction: LongActionType, additionalParameters: [GeneralParameters.CodingKeys: GeneralParameter]) {
|
static let types: [CustomTouchBarItem.Type] = [
|
||||||
self.type = type
|
|
||||||
self.action = action
|
|
||||||
self.longAction = longAction
|
|
||||||
self.additionalParameters = additionalParameters
|
|
||||||
}
|
|
||||||
|
|
||||||
init(from decoder: Decoder) throws {
|
// custom buttons
|
||||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
CustomButtonTouchBarItem.self,
|
||||||
let type = try container.decode(String.self, forKey: .type)
|
AppleScriptTouchBarItem.self,
|
||||||
let parametersDecoder = SupportedTypesHolder.sharedInstance.lookup(by: type)
|
ShellScriptTouchBarItem.self,
|
||||||
var additionalParameters = try GeneralParameters(from: decoder).parameters
|
|
||||||
|
|
||||||
if let result = try? parametersDecoder(decoder),
|
|
||||||
case let (itemType, action, longAction, parameters) = result {
|
|
||||||
parameters.forEach { additionalParameters[$0] = $1 }
|
|
||||||
self.init(type: itemType, action: action, longAction: longAction, additionalParameters: additionalParameters)
|
|
||||||
} else {
|
|
||||||
self.init(type: .staticButton(title: "unknown"), action: .none, longAction: .none, additionalParameters: additionalParameters)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
typealias ParametersDecoder = (Decoder) throws -> (
|
// basic widget buttons
|
||||||
item: ItemType,
|
EscapeBarItem.self,
|
||||||
action: ActionType,
|
DeleteBarItem.self,
|
||||||
longAction: LongActionType,
|
BrightnessUpBarItem.self,
|
||||||
parameters: [GeneralParameters.CodingKeys: GeneralParameter]
|
BrightnessDownBarItem.self,
|
||||||
)
|
IlluminationUpBarItem.self,
|
||||||
|
IlluminationDownBarItem.self,
|
||||||
|
VolumeUpBarItem.self,
|
||||||
|
VolumeDownBarItem.self,
|
||||||
|
MuteBarItem.self,
|
||||||
|
PreviousBarItem.self,
|
||||||
|
PlayBarItem.self,
|
||||||
|
NextBarItem.self,
|
||||||
|
SleepBarItem.self,
|
||||||
|
DisplaySleepBarItem.self,
|
||||||
|
|
||||||
class SupportedTypesHolder {
|
|
||||||
private var supportedTypes: [String: ParametersDecoder] = [
|
|
||||||
"escape": { _ in (
|
|
||||||
item: .staticButton(title: "esc"),
|
|
||||||
action: .keyPress(keycode: 53),
|
|
||||||
longAction: .none,
|
|
||||||
parameters: [.align: .align(.left)]
|
|
||||||
) },
|
|
||||||
|
|
||||||
"delete": { _ in (
|
// custom widgets
|
||||||
item: .staticButton(title: "del"),
|
TimeTouchBarItem.self,
|
||||||
action: .keyPress(keycode: 117),
|
BatteryBarItem.self,
|
||||||
longAction: .none,
|
AppScrubberTouchBarItem.self,
|
||||||
parameters: [:]
|
VolumeViewController.self,
|
||||||
) },
|
BrightnessViewController.self,
|
||||||
|
WeatherBarItem.self,
|
||||||
|
YandexWeatherBarItem.self,
|
||||||
|
CurrencyBarItem.self,
|
||||||
|
InputSourceBarItem.self,
|
||||||
|
MusicBarItem.self,
|
||||||
|
NightShiftBarItem.self,
|
||||||
|
DnDBarItem.self,
|
||||||
|
PomodoroBarItem.self,
|
||||||
|
NetworkBarItem.self,
|
||||||
|
DarkModeBarItem.self,
|
||||||
|
|
||||||
"brightnessUp": { _ in
|
|
||||||
let imageParameter = GeneralParameter.image(source: #imageLiteral(resourceName: "brightnessUp"))
|
|
||||||
return (
|
|
||||||
item: .staticButton(title: ""),
|
|
||||||
action: .keyPress(keycode: 144),
|
|
||||||
longAction: .none,
|
|
||||||
parameters: [.image: imageParameter]
|
|
||||||
)
|
|
||||||
},
|
|
||||||
|
|
||||||
"brightnessDown": { _ in
|
|
||||||
let imageParameter = GeneralParameter.image(source: #imageLiteral(resourceName: "brightnessDown"))
|
|
||||||
return (
|
|
||||||
item: .staticButton(title: ""),
|
|
||||||
action: .keyPress(keycode: 145),
|
|
||||||
longAction: .none,
|
|
||||||
parameters: [.image: imageParameter]
|
|
||||||
)
|
|
||||||
},
|
|
||||||
|
|
||||||
"illuminationUp": { _ in
|
|
||||||
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]
|
|
||||||
)
|
|
||||||
},
|
|
||||||
|
|
||||||
"illuminationDown": { _ in
|
|
||||||
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]
|
|
||||||
)
|
|
||||||
},
|
|
||||||
|
|
||||||
"volumeDown": { _ in
|
|
||||||
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]
|
|
||||||
)
|
|
||||||
},
|
|
||||||
|
|
||||||
"volumeUp": { _ in
|
|
||||||
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]
|
|
||||||
)
|
|
||||||
},
|
|
||||||
|
|
||||||
"mute": { _ in
|
|
||||||
let imageParameter = GeneralParameter.image(source: NSImage(named: NSImage.touchBarAudioOutputMuteTemplateName)!)
|
|
||||||
return (
|
|
||||||
item: .staticButton(title: ""),
|
|
||||||
action: .hidKey(keycode: NX_KEYTYPE_MUTE),
|
|
||||||
longAction: .none,
|
|
||||||
parameters: [.image: imageParameter]
|
|
||||||
)
|
|
||||||
},
|
|
||||||
|
|
||||||
"previous": { _ in
|
|
||||||
let imageParameter = GeneralParameter.image(source: NSImage(named: NSImage.touchBarRewindTemplateName)!)
|
|
||||||
return (
|
|
||||||
item: .staticButton(title: ""),
|
|
||||||
action: .hidKey(keycode: NX_KEYTYPE_PREVIOUS),
|
|
||||||
longAction: .none,
|
|
||||||
parameters: [.image: imageParameter]
|
|
||||||
)
|
|
||||||
},
|
|
||||||
|
|
||||||
"play": { _ in
|
|
||||||
let imageParameter = GeneralParameter.image(source: NSImage(named: NSImage.touchBarPlayPauseTemplateName)!)
|
|
||||||
return (
|
|
||||||
item: .staticButton(title: ""),
|
|
||||||
action: .hidKey(keycode: NX_KEYTYPE_PLAY),
|
|
||||||
longAction: .none,
|
|
||||||
parameters: [.image: imageParameter]
|
|
||||||
)
|
|
||||||
},
|
|
||||||
|
|
||||||
"next": { _ in
|
|
||||||
let imageParameter = GeneralParameter.image(source: NSImage(named: NSImage.touchBarFastForwardTemplateName)!)
|
|
||||||
return (
|
|
||||||
item: .staticButton(title: ""),
|
|
||||||
action: .hidKey(keycode: NX_KEYTYPE_NEXT),
|
|
||||||
longAction: .none,
|
|
||||||
parameters: [.image: imageParameter]
|
|
||||||
)
|
|
||||||
},
|
|
||||||
|
|
||||||
"sleep": { _ in (
|
|
||||||
item: .staticButton(title: "☕️"),
|
|
||||||
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: [:]
|
|
||||||
) },
|
|
||||||
|
|
||||||
|
// custom-custom objects!
|
||||||
|
SwipeItem.self,
|
||||||
|
GroupBarItem.self,
|
||||||
|
ExitTouchbarBarItem.self,
|
||||||
|
CloseBarItem.self,
|
||||||
]
|
]
|
||||||
|
|
||||||
static let sharedInstance = SupportedTypesHolder()
|
init(obj: CustomTouchBarItem) {
|
||||||
|
self.obj = obj
|
||||||
func lookup(by type: String) -> ParametersDecoder {
|
|
||||||
return supportedTypes[type] ?? { decoder in (
|
|
||||||
item: try ItemType(from: decoder),
|
|
||||||
action: try ActionType(from: decoder),
|
|
||||||
longAction: try LongActionType(from: decoder),
|
|
||||||
parameters: [:]
|
|
||||||
) }
|
|
||||||
}
|
|
||||||
|
|
||||||
func register(typename: String, decoder: @escaping ParametersDecoder) {
|
|
||||||
supportedTypes[typename] = decoder
|
|
||||||
}
|
|
||||||
|
|
||||||
func register(typename: String, item: ItemType, action: ActionType, longAction: LongActionType) {
|
|
||||||
register(typename: typename) { _ in
|
|
||||||
(
|
|
||||||
item: item,
|
|
||||||
action,
|
|
||||||
longAction,
|
|
||||||
parameters: [:]
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum ItemType: Decodable {
|
|
||||||
case staticButton(title: String)
|
|
||||||
case appleScriptTitledButton(source: SourceProtocol, refreshInterval: Double, alternativeImages: [String: SourceProtocol])
|
|
||||||
case shellScriptTitledButton(source: SourceProtocol, refreshInterval: Double)
|
|
||||||
case timeButton(formatTemplate: String, timeZone: String?, locale: String?)
|
|
||||||
case battery
|
|
||||||
case dock(autoResize: Bool, filter: String?)
|
|
||||||
case volume
|
|
||||||
case brightness(refreshInterval: Double)
|
|
||||||
case weather(interval: Double, units: String, api_key: String, icon_type: String)
|
|
||||||
case yandexWeather(interval: Double)
|
|
||||||
case currency(interval: Double, from: String, to: String, full: Bool)
|
|
||||||
case inputsource
|
|
||||||
case music(interval: Double, disableMarquee: Bool)
|
|
||||||
case group(items: [BarItemDefinition])
|
|
||||||
case nightShift
|
|
||||||
case dnd
|
|
||||||
case pomodoro(workTime: Double, restTime: Double)
|
|
||||||
case network(flip: Bool)
|
|
||||||
case darkMode
|
|
||||||
case swipe(direction: String, fingers: Int, minOffset: Float, sourceApple: SourceProtocol?, sourceBash: SourceProtocol?)
|
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
|
||||||
case type
|
|
||||||
case title
|
|
||||||
case source
|
|
||||||
case refreshInterval
|
|
||||||
case from
|
|
||||||
case to
|
|
||||||
case full
|
|
||||||
case timeZone
|
|
||||||
case units
|
|
||||||
case api_key
|
|
||||||
case icon_type
|
|
||||||
case formatTemplate
|
|
||||||
case locale
|
|
||||||
case image
|
|
||||||
case url
|
|
||||||
case longUrl
|
|
||||||
case items
|
|
||||||
case workTime
|
|
||||||
case restTime
|
|
||||||
case flip
|
|
||||||
case autoResize
|
|
||||||
case filter
|
|
||||||
case disableMarquee
|
|
||||||
case alternativeImages
|
|
||||||
case sourceApple
|
|
||||||
case sourceBash
|
|
||||||
case direction
|
|
||||||
case fingers
|
|
||||||
case minOffset
|
|
||||||
}
|
|
||||||
|
|
||||||
enum ItemTypeRaw: String, Decodable {
|
|
||||||
case staticButton
|
|
||||||
case appleScriptTitledButton
|
|
||||||
case shellScriptTitledButton
|
|
||||||
case timeButton
|
|
||||||
case battery
|
|
||||||
case dock
|
|
||||||
case volume
|
|
||||||
case brightness
|
|
||||||
case weather
|
|
||||||
case yandexWeather
|
|
||||||
case currency
|
|
||||||
case inputsource
|
|
||||||
case music
|
|
||||||
case group
|
|
||||||
case nightShift
|
|
||||||
case dnd
|
|
||||||
case pomodoro
|
|
||||||
case network
|
|
||||||
case darkMode
|
|
||||||
case swipe
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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 objType = try container.decode(String.self, forKey: .objtype)
|
||||||
switch type {
|
|
||||||
case .appleScriptTitledButton:
|
|
||||||
let source = try container.decode(Source.self, forKey: .source)
|
|
||||||
let interval = try container.decodeIfPresent(Double.self, forKey: .refreshInterval) ?? 1800.0
|
|
||||||
let alternativeImages = try container.decodeIfPresent([String: Source].self, forKey: .alternativeImages) ?? [:]
|
|
||||||
self = .appleScriptTitledButton(source: source, refreshInterval: interval, alternativeImages: alternativeImages)
|
|
||||||
|
|
||||||
case .shellScriptTitledButton:
|
|
||||||
let source = try container.decode(Source.self, forKey: .source)
|
|
||||||
let interval = try container.decodeIfPresent(Double.self, forKey: .refreshInterval) ?? 1800.0
|
|
||||||
self = .shellScriptTitledButton(source: source, refreshInterval: interval)
|
|
||||||
|
|
||||||
case .staticButton:
|
for obj in BarItemDefinition.types {
|
||||||
let title = try container.decode(String.self, forKey: .title)
|
if obj.typeIdentifier == objType {
|
||||||
self = .staticButton(title: title)
|
self.obj = try obj.init(from: decoder)
|
||||||
|
return
|
||||||
case .timeButton:
|
}
|
||||||
let template = try container.decodeIfPresent(String.self, forKey: .formatTemplate) ?? "HH:mm"
|
|
||||||
let timeZone = try container.decodeIfPresent(String.self, forKey: .timeZone) ?? nil
|
|
||||||
let locale = try container.decodeIfPresent(String.self, forKey: .locale) ?? nil
|
|
||||||
self = .timeButton(formatTemplate: template, timeZone: timeZone, locale: locale)
|
|
||||||
|
|
||||||
case .battery:
|
|
||||||
self = .battery
|
|
||||||
|
|
||||||
case .dock:
|
|
||||||
let autoResize = try container.decodeIfPresent(Bool.self, forKey: .autoResize) ?? false
|
|
||||||
let filterRegexString = try container.decodeIfPresent(String.self, forKey: .filter)
|
|
||||||
self = .dock(autoResize: autoResize, filter: filterRegexString)
|
|
||||||
|
|
||||||
case .volume:
|
|
||||||
self = .volume
|
|
||||||
|
|
||||||
case .brightness:
|
|
||||||
let interval = try container.decodeIfPresent(Double.self, forKey: .refreshInterval) ?? 0.5
|
|
||||||
self = .brightness(refreshInterval: interval)
|
|
||||||
|
|
||||||
case .weather:
|
|
||||||
let interval = try container.decodeIfPresent(Double.self, forKey: .refreshInterval) ?? 1800.0
|
|
||||||
let units = try container.decodeIfPresent(String.self, forKey: .units) ?? "metric"
|
|
||||||
let api_key = try container.decodeIfPresent(String.self, forKey: .api_key) ?? "32c4256d09a4c52b38aecddba7a078f6"
|
|
||||||
let icon_type = try container.decodeIfPresent(String.self, forKey: .icon_type) ?? "text"
|
|
||||||
self = .weather(interval: interval, units: units, api_key: api_key, icon_type: icon_type)
|
|
||||||
|
|
||||||
case .yandexWeather:
|
|
||||||
let interval = try container.decodeIfPresent(Double.self, forKey: .refreshInterval) ?? 1800.0
|
|
||||||
self = .yandexWeather(interval: interval)
|
|
||||||
|
|
||||||
case .currency:
|
|
||||||
let interval = try container.decodeIfPresent(Double.self, forKey: .refreshInterval) ?? 600.0
|
|
||||||
let from = try container.decodeIfPresent(String.self, forKey: .from) ?? "RUB"
|
|
||||||
let to = try container.decodeIfPresent(String.self, forKey: .to) ?? "USD"
|
|
||||||
let full = try container.decodeIfPresent(Bool.self, forKey: .full) ?? false
|
|
||||||
self = .currency(interval: interval, from: from, to: to, full: full)
|
|
||||||
|
|
||||||
case .inputsource:
|
|
||||||
self = .inputsource
|
|
||||||
|
|
||||||
case .music:
|
|
||||||
let interval = try container.decodeIfPresent(Double.self, forKey: .refreshInterval) ?? 5.0
|
|
||||||
let disableMarquee = try container.decodeIfPresent(Bool.self, forKey: .disableMarquee) ?? false
|
|
||||||
self = .music(interval: interval, disableMarquee: disableMarquee)
|
|
||||||
|
|
||||||
case .group:
|
|
||||||
let items = try container.decode([BarItemDefinition].self, forKey: .items)
|
|
||||||
self = .group(items: items)
|
|
||||||
|
|
||||||
case .nightShift:
|
|
||||||
self = .nightShift
|
|
||||||
|
|
||||||
case .dnd:
|
|
||||||
self = .dnd
|
|
||||||
|
|
||||||
case .pomodoro:
|
|
||||||
let workTime = try container.decodeIfPresent(Double.self, forKey: .workTime) ?? 1500.0
|
|
||||||
let restTime = try container.decodeIfPresent(Double.self, forKey: .restTime) ?? 600.0
|
|
||||||
self = .pomodoro(workTime: workTime, restTime: restTime)
|
|
||||||
|
|
||||||
case .network:
|
|
||||||
let flip = try container.decodeIfPresent(Bool.self, forKey: .flip) ?? false
|
|
||||||
self = .network(flip: flip)
|
|
||||||
|
|
||||||
case .darkMode:
|
|
||||||
self = .darkMode
|
|
||||||
|
|
||||||
case .swipe:
|
|
||||||
let sourceApple = try container.decodeIfPresent(Source.self, forKey: .sourceApple)
|
|
||||||
let sourceBash = try container.decodeIfPresent(Source.self, forKey: .sourceBash)
|
|
||||||
let direction = try container.decode(String.self, forKey: .direction)
|
|
||||||
let fingers = try container.decode(Int.self, forKey: .fingers)
|
|
||||||
let minOffset = try container.decodeIfPresent(Float.self, forKey: .minOffset) ?? 0.0
|
|
||||||
self = .swipe(direction: direction, fingers: fingers, minOffset: minOffset, sourceApple: sourceApple, sourceBash: sourceBash)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum ActionType: Decodable {
|
|
||||||
case none
|
|
||||||
case hidKey(keycode: Int32)
|
|
||||||
case keyPress(keycode: Int)
|
|
||||||
case appleScript(source: SourceProtocol)
|
|
||||||
case shellScript(executable: String, parameters: [String])
|
|
||||||
case custom(closure: () -> Void)
|
|
||||||
case openUrl(url: String)
|
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
|
||||||
case action
|
|
||||||
case keycode
|
|
||||||
case actionAppleScript
|
|
||||||
case executablePath
|
|
||||||
case shellArguments
|
|
||||||
case url
|
|
||||||
}
|
|
||||||
|
|
||||||
private enum ActionTypeRaw: String, Decodable {
|
|
||||||
case hidKey
|
|
||||||
case keyPress
|
|
||||||
case appleScript
|
|
||||||
case shellScript
|
|
||||||
case openUrl
|
|
||||||
}
|
|
||||||
|
|
||||||
init(from decoder: Decoder) throws {
|
|
||||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
|
||||||
let type = try container.decodeIfPresent(ActionTypeRaw.self, forKey: .action)
|
|
||||||
|
|
||||||
switch type {
|
|
||||||
case .some(.hidKey):
|
|
||||||
let keycode = try container.decode(Int32.self, forKey: .keycode)
|
|
||||||
self = .hidKey(keycode: keycode)
|
|
||||||
|
|
||||||
case .some(.keyPress):
|
|
||||||
let keycode = try container.decode(Int.self, forKey: .keycode)
|
|
||||||
self = .keyPress(keycode: keycode)
|
|
||||||
|
|
||||||
case .some(.appleScript):
|
|
||||||
let source = try container.decode(Source.self, forKey: .actionAppleScript)
|
|
||||||
self = .appleScript(source: source)
|
|
||||||
|
|
||||||
case .some(.shellScript):
|
|
||||||
let executable = try container.decode(String.self, forKey: .executablePath)
|
|
||||||
let parameters = try container.decodeIfPresent([String].self, forKey: .shellArguments) ?? []
|
|
||||||
self = .shellScript(executable: executable, parameters: parameters)
|
|
||||||
|
|
||||||
case .some(.openUrl):
|
|
||||||
let url = try container.decode(String.self, forKey: .url)
|
|
||||||
self = .openUrl(url: url)
|
|
||||||
|
|
||||||
case .none:
|
|
||||||
self = .none
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum LongActionType: Decodable {
|
|
||||||
case none
|
|
||||||
case hidKey(keycode: Int32)
|
|
||||||
case keyPress(keycode: Int)
|
|
||||||
case appleScript(source: SourceProtocol)
|
|
||||||
case shellScript(executable: String, parameters: [String])
|
|
||||||
case custom(closure: () -> Void)
|
|
||||||
case openUrl(url: String)
|
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
|
||||||
case longAction
|
|
||||||
case longKeycode
|
|
||||||
case longActionAppleScript
|
|
||||||
case longExecutablePath
|
|
||||||
case longShellArguments
|
|
||||||
case longUrl
|
|
||||||
}
|
|
||||||
|
|
||||||
private enum LongActionTypeRaw: String, Decodable {
|
|
||||||
case hidKey
|
|
||||||
case keyPress
|
|
||||||
case appleScript
|
|
||||||
case shellScript
|
|
||||||
case openUrl
|
|
||||||
}
|
|
||||||
|
|
||||||
init(from decoder: Decoder) throws {
|
|
||||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
|
||||||
let longType = try container.decodeIfPresent(LongActionTypeRaw.self, forKey: .longAction)
|
|
||||||
|
|
||||||
switch longType {
|
|
||||||
case .some(.hidKey):
|
|
||||||
let keycode = try container.decode(Int32.self, forKey: .longKeycode)
|
|
||||||
self = .hidKey(keycode: keycode)
|
|
||||||
|
|
||||||
case .some(.keyPress):
|
|
||||||
let keycode = try container.decode(Int.self, forKey: .longKeycode)
|
|
||||||
self = .keyPress(keycode: keycode)
|
|
||||||
|
|
||||||
case .some(.appleScript):
|
|
||||||
let source = try container.decode(Source.self, forKey: .longActionAppleScript)
|
|
||||||
self = .appleScript(source: source)
|
|
||||||
|
|
||||||
case .some(.shellScript):
|
|
||||||
let executable = try container.decode(String.self, forKey: .longExecutablePath)
|
|
||||||
let parameters = try container.decodeIfPresent([String].self, forKey: .longShellArguments) ?? []
|
|
||||||
self = .shellScript(executable: executable, parameters: parameters)
|
|
||||||
|
|
||||||
case .some(.openUrl):
|
|
||||||
let longUrl = try container.decode(String.self, forKey: .longUrl)
|
|
||||||
self = .openUrl(url: longUrl)
|
|
||||||
|
|
||||||
case .none:
|
|
||||||
self = .none
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum GeneralParameter {
|
|
||||||
case width(_: CGFloat)
|
|
||||||
case image(source: SourceProtocol)
|
|
||||||
case align(_: Align)
|
|
||||||
case bordered(_: Bool)
|
|
||||||
case background(_: NSColor)
|
|
||||||
case title(_: String)
|
|
||||||
}
|
|
||||||
|
|
||||||
struct GeneralParameters: Decodable {
|
|
||||||
let parameters: [GeneralParameters.CodingKeys: GeneralParameter]
|
|
||||||
|
|
||||||
enum CodingKeys: String, CodingKey {
|
|
||||||
case width
|
|
||||||
case image
|
|
||||||
case align
|
|
||||||
case bordered
|
|
||||||
case background
|
|
||||||
case title
|
|
||||||
}
|
|
||||||
|
|
||||||
init(from decoder: Decoder) throws {
|
|
||||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
|
||||||
var result: [GeneralParameters.CodingKeys: GeneralParameter] = [:]
|
|
||||||
|
|
||||||
if let value = try container.decodeIfPresent(CGFloat.self, forKey: .width) {
|
|
||||||
result[.width] = .width(value)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let imageSource = try container.decodeIfPresent(Source.self, forKey: .image) {
|
|
||||||
result[.image] = .image(source: imageSource)
|
|
||||||
}
|
|
||||||
|
|
||||||
let align = try container.decodeIfPresent(Align.self, forKey: .align) ?? .center
|
print("Cannot find preset mapping for \(objType)")
|
||||||
result[.align] = .align(align)
|
throw ParsingErrors.noMatchingType(description: "Cannot find preset mapping for \(objType)")
|
||||||
|
|
||||||
if let borderedFlag = try container.decodeIfPresent(Bool.self, forKey: .bordered) {
|
|
||||||
result[.bordered] = .bordered(borderedFlag)
|
|
||||||
}
|
|
||||||
|
|
||||||
if let backgroundColor = try container.decodeIfPresent(String.self, forKey: .background)?.hexColor {
|
|
||||||
result[.background] = .background(backgroundColor)
|
|
||||||
}
|
|
||||||
|
|
||||||
if let title = try container.decodeIfPresent(String.self, forKey: .title) {
|
|
||||||
result[.title] = .title(title)
|
|
||||||
}
|
|
||||||
|
|
||||||
parameters = result
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -646,12 +186,6 @@ extension Data {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Align: String, Decodable {
|
|
||||||
case left
|
|
||||||
case center
|
|
||||||
case right
|
|
||||||
}
|
|
||||||
|
|
||||||
extension URL {
|
extension URL {
|
||||||
var appleScript: NSAppleScript? {
|
var appleScript: NSAppleScript? {
|
||||||
guard FileManager.default.fileExists(atPath: path) else { return nil }
|
guard FileManager.default.fileExists(atPath: path) else { return nil }
|
||||||
|
|||||||
@ -12,11 +12,40 @@ class ShellScriptTouchBarItem: CustomButtonTouchBarItem {
|
|||||||
private let source: String
|
private let source: String
|
||||||
private var forceHideConstraint: NSLayoutConstraint!
|
private var forceHideConstraint: NSLayoutConstraint!
|
||||||
|
|
||||||
|
private enum CodingKeys: String, CodingKey {
|
||||||
|
case source
|
||||||
|
case refreshInterval
|
||||||
|
}
|
||||||
|
|
||||||
|
override class var typeIdentifier: String {
|
||||||
|
return "shellScriptTitledButton"
|
||||||
|
}
|
||||||
|
|
||||||
init?(identifier: NSTouchBarItem.Identifier, source: SourceProtocol, interval: TimeInterval) {
|
init?(identifier: NSTouchBarItem.Identifier, source: SourceProtocol, interval: TimeInterval) {
|
||||||
self.interval = interval
|
self.interval = interval
|
||||||
self.source = source.string ?? "echo No \"source\""
|
self.source = source.string ?? "echo No \"source\""
|
||||||
super.init(identifier: identifier, title: "⏳")
|
super.init(identifier: identifier, title: "⏳")
|
||||||
|
|
||||||
|
initScripts()
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder _: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
required init(from decoder: Decoder) throws {
|
||||||
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
|
let source = try container.decode(Source.self, forKey: .source)
|
||||||
|
self.source = source.string ?? "echo No \"source\""
|
||||||
|
self.interval = try container.decodeIfPresent(Double.self, forKey: .refreshInterval) ?? 1800.0
|
||||||
|
|
||||||
|
try super.init(from: decoder)
|
||||||
|
self.title = "⏳"
|
||||||
|
|
||||||
|
initScripts()
|
||||||
|
}
|
||||||
|
|
||||||
|
func initScripts() {
|
||||||
forceHideConstraint = view.widthAnchor.constraint(equalToConstant: 0)
|
forceHideConstraint = view.widthAnchor.constraint(equalToConstant: 0)
|
||||||
|
|
||||||
DispatchQueue.shellScriptQueue.async {
|
DispatchQueue.shellScriptQueue.async {
|
||||||
@ -24,10 +53,6 @@ class ShellScriptTouchBarItem: CustomButtonTouchBarItem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
required init?(coder _: NSCoder) {
|
|
||||||
fatalError("init(coder:) has not been implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
func refreshAndSchedule() {
|
func refreshAndSchedule() {
|
||||||
// Execute script and get result
|
// Execute script and get result
|
||||||
let scriptResult = execute(source)
|
let scriptResult = execute(source)
|
||||||
@ -45,7 +70,7 @@ class ShellScriptTouchBarItem: CustomButtonTouchBarItem {
|
|||||||
if (newBackgoundColor != self?.backgroundColor) { // performance optimization because of reinstallButton
|
if (newBackgoundColor != self?.backgroundColor) { // performance optimization because of reinstallButton
|
||||||
self?.backgroundColor = newBackgoundColor
|
self?.backgroundColor = newBackgoundColor
|
||||||
}
|
}
|
||||||
self?.attributedTitle = title
|
self?.setAttributedTitle(title)
|
||||||
self?.forceHideConstraint.isActive = scriptResult == ""
|
self?.forceHideConstraint.isActive = scriptResult == ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -9,12 +9,25 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
class SwipeItem: NSCustomTouchBarItem {
|
class SwipeItem: CustomTouchBarItem {
|
||||||
private var scriptApple: NSAppleScript?
|
private var scriptApple: NSAppleScript?
|
||||||
private var scriptBash: String?
|
private var scriptBash: String?
|
||||||
private var direction: String
|
private var direction: String
|
||||||
private var fingers: Int
|
private var fingers: Int
|
||||||
private var minOffset: Float
|
private var minOffset: Float
|
||||||
|
|
||||||
|
private enum CodingKeys: String, CodingKey {
|
||||||
|
case sourceApple
|
||||||
|
case sourceBash
|
||||||
|
case direction
|
||||||
|
case fingers
|
||||||
|
case minOffset
|
||||||
|
}
|
||||||
|
|
||||||
|
override class var typeIdentifier: String {
|
||||||
|
return "swipe"
|
||||||
|
}
|
||||||
|
|
||||||
init?(identifier: NSTouchBarItem.Identifier, direction: String, fingers: Int, minOffset: Float, sourceApple: SourceProtocol?, sourceBash: SourceProtocol?) {
|
init?(identifier: NSTouchBarItem.Identifier, direction: String, fingers: Int, minOffset: Float, sourceApple: SourceProtocol?, sourceBash: SourceProtocol?) {
|
||||||
self.direction = direction
|
self.direction = direction
|
||||||
self.fingers = fingers
|
self.fingers = fingers
|
||||||
@ -28,6 +41,19 @@ class SwipeItem: NSCustomTouchBarItem {
|
|||||||
fatalError("init(coder:) has not been implemented")
|
fatalError("init(coder:) has not been implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
required init(from decoder: Decoder) throws {
|
||||||
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
|
|
||||||
|
self.scriptApple = try container.decodeIfPresent(Source.self, forKey: .sourceApple)?.appleScript
|
||||||
|
self.scriptBash = try container.decodeIfPresent(Source.self, forKey: .sourceBash)?.string
|
||||||
|
self.direction = try container.decode(String.self, forKey: .direction)
|
||||||
|
self.fingers = try container.decode(Int.self, forKey: .fingers)
|
||||||
|
self.minOffset = try container.decodeIfPresent(Float.self, forKey: .minOffset) ?? 0.0
|
||||||
|
|
||||||
|
|
||||||
|
try super.init(from: decoder)
|
||||||
|
}
|
||||||
|
|
||||||
func processEvent(offset: CGFloat, fingers: Int) {
|
func processEvent(offset: CGFloat, fingers: Int) {
|
||||||
if direction == "right" && Float(offset) > self.minOffset && self.fingers == fingers {
|
if direction == "right" && Float(offset) > self.minOffset && self.fingers == fingers {
|
||||||
self.execute()
|
self.execute()
|
||||||
|
|||||||
@ -16,52 +16,6 @@ struct ExactItem {
|
|||||||
let appSupportDirectory = NSSearchPathForDirectoriesInDomains(.applicationSupportDirectory, .userDomainMask, true).first!.appending("/MTMR")
|
let appSupportDirectory = NSSearchPathForDirectoriesInDomains(.applicationSupportDirectory, .userDomainMask, true).first!.appending("/MTMR")
|
||||||
let standardConfigPath = appSupportDirectory.appending("/items.json")
|
let standardConfigPath = appSupportDirectory.appending("/items.json")
|
||||||
|
|
||||||
extension ItemType {
|
|
||||||
var identifierBase: String {
|
|
||||||
switch self {
|
|
||||||
case .staticButton(title: _):
|
|
||||||
return "com.toxblh.mtmr.staticButton."
|
|
||||||
case .appleScriptTitledButton(source: _):
|
|
||||||
return "com.toxblh.mtmr.appleScriptButton."
|
|
||||||
case .shellScriptTitledButton(source: _):
|
|
||||||
return "com.toxblh.mtmr.shellScriptButton."
|
|
||||||
case .timeButton(formatTemplate: _, timeZone: _, locale: _):
|
|
||||||
return "com.toxblh.mtmr.timeButton."
|
|
||||||
case .battery:
|
|
||||||
return "com.toxblh.mtmr.battery."
|
|
||||||
case .dock(autoResize: _, filter: _):
|
|
||||||
return "com.toxblh.mtmr.dock"
|
|
||||||
case .volume:
|
|
||||||
return "com.toxblh.mtmr.volume"
|
|
||||||
case .brightness(refreshInterval: _):
|
|
||||||
return "com.toxblh.mtmr.brightness"
|
|
||||||
case .weather(interval: _, units: _, api_key: _, icon_type: _):
|
|
||||||
return "com.toxblh.mtmr.weather"
|
|
||||||
case .yandexWeather(interval: _):
|
|
||||||
return "com.toxblh.mtmr.yandexWeather"
|
|
||||||
case .currency(interval: _, from: _, to: _, full: _):
|
|
||||||
return "com.toxblh.mtmr.currency"
|
|
||||||
case .inputsource:
|
|
||||||
return "com.toxblh.mtmr.inputsource."
|
|
||||||
case .music(interval: _):
|
|
||||||
return "com.toxblh.mtmr.music."
|
|
||||||
case .group(items: _):
|
|
||||||
return "com.toxblh.mtmr.groupBar."
|
|
||||||
case .nightShift:
|
|
||||||
return "com.toxblh.mtmr.nightShift."
|
|
||||||
case .dnd:
|
|
||||||
return "com.toxblh.mtmr.dnd."
|
|
||||||
case .pomodoro(interval: _):
|
|
||||||
return PomodoroBarItem.identifier
|
|
||||||
case .network(flip: _):
|
|
||||||
return NetworkBarItem.identifier
|
|
||||||
case .darkMode:
|
|
||||||
return DarkModeBarItem.identifier
|
|
||||||
case .swipe(direction: _, fingers: _, minOffset: _, sourceApple: _, sourceBash: _):
|
|
||||||
return "com.toxblh.mtmr.swipe."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension NSTouchBarItem.Identifier {
|
extension NSTouchBarItem.Identifier {
|
||||||
static let controlStripItem = NSTouchBarItem.Identifier("com.toxblh.mtmr.controlStrip")
|
static let controlStripItem = NSTouchBarItem.Identifier("com.toxblh.mtmr.controlStrip")
|
||||||
@ -73,12 +27,7 @@ class TouchBarController: NSObject, NSTouchBarDelegate {
|
|||||||
var touchBar: NSTouchBar!
|
var touchBar: NSTouchBar!
|
||||||
|
|
||||||
fileprivate var lastPresetPath = ""
|
fileprivate var lastPresetPath = ""
|
||||||
var jsonItems: [BarItemDefinition] = []
|
var items: [CustomTouchBarItem] = []
|
||||||
var itemDefinitions: [NSTouchBarItem.Identifier: BarItemDefinition] = [:]
|
|
||||||
var items: [NSTouchBarItem.Identifier: NSTouchBarItem] = [:]
|
|
||||||
var leftIdentifiers: [NSTouchBarItem.Identifier] = []
|
|
||||||
var centerIdentifiers: [NSTouchBarItem.Identifier] = []
|
|
||||||
var rightIdentifiers: [NSTouchBarItem.Identifier] = []
|
|
||||||
var basicViewIdentifier = NSTouchBarItem.Identifier("com.toxblh.mtmr.scrollView.".appending(UUID().uuidString))
|
var basicViewIdentifier = NSTouchBarItem.Identifier("com.toxblh.mtmr.scrollView.".appending(UUID().uuidString))
|
||||||
var basicView: BasicView?
|
var basicView: BasicView?
|
||||||
var swipeItems: [SwipeItem] = []
|
var swipeItems: [SwipeItem] = []
|
||||||
@ -90,14 +39,6 @@ class TouchBarController: NSObject, NSTouchBarDelegate {
|
|||||||
|
|
||||||
private override init() {
|
private override init() {
|
||||||
super.init()
|
super.init()
|
||||||
SupportedTypesHolder.sharedInstance.register(typename: "exitTouchbar", item: .staticButton(title: "exit"), action: .custom(closure: { [weak self] in self?.dismissTouchBar() }), longAction: .none)
|
|
||||||
|
|
||||||
SupportedTypesHolder.sharedInstance.register(typename: "close") { _ in
|
|
||||||
(item: .staticButton(title: ""), action: .custom(closure: { [weak self] in
|
|
||||||
guard let `self` = self else { return }
|
|
||||||
self.reloadPreset(path: self.lastPresetPath)
|
|
||||||
}), longAction: .none, parameters: [.width: .width(30), .image: .image(source: (NSImage(named: NSImage.stopProgressFreestandingTemplateName))!)])
|
|
||||||
}
|
|
||||||
|
|
||||||
blacklistAppIdentifiers = AppSettings.blacklistedAppIds
|
blacklistAppIdentifiers = AppSettings.blacklistedAppIds
|
||||||
|
|
||||||
@ -108,21 +49,23 @@ class TouchBarController: NSObject, NSTouchBarDelegate {
|
|||||||
reloadStandardConfig()
|
reloadStandardConfig()
|
||||||
}
|
}
|
||||||
|
|
||||||
func createAndUpdatePreset(newJsonItems: [BarItemDefinition]) {
|
func createAndUpdatePreset(newItems: [BarItemDefinition]) {
|
||||||
if let oldBar = self.touchBar {
|
if let oldBar = self.touchBar {
|
||||||
minimizeSystemModal(oldBar)
|
minimizeSystemModal(oldBar)
|
||||||
}
|
}
|
||||||
touchBar = NSTouchBar()
|
touchBar = NSTouchBar()
|
||||||
jsonItems = newJsonItems
|
(items, swipeItems) = getItems(newItems: newItems)
|
||||||
itemDefinitions = [:]
|
|
||||||
items = [:]
|
|
||||||
|
|
||||||
loadItemDefinitions(jsonItems: jsonItems)
|
let leftItems = items.compactMap({ (item) -> CustomTouchBarItem? in
|
||||||
createItems()
|
item.align == .left ? item : nil
|
||||||
|
|
||||||
let centerItems = centerIdentifiers.compactMap({ (identifier) -> NSTouchBarItem? in
|
|
||||||
items[identifier]
|
|
||||||
})
|
})
|
||||||
|
let centerItems = items.compactMap({ (item) -> CustomTouchBarItem? in
|
||||||
|
item.align == .center ? item : nil
|
||||||
|
})
|
||||||
|
let rightItems = items.compactMap({ (item) -> CustomTouchBarItem? in
|
||||||
|
item.align == .right ? item : nil
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
let centerScrollArea = NSTouchBarItem.Identifier("com.toxblh.mtmr.scrollArea.".appending(UUID().uuidString))
|
let centerScrollArea = NSTouchBarItem.Identifier("com.toxblh.mtmr.scrollArea.".appending(UUID().uuidString))
|
||||||
let scrollArea = ScrollViewItem(identifier: centerScrollArea, items: centerItems)
|
let scrollArea = ScrollViewItem(identifier: centerScrollArea, items: centerItems)
|
||||||
@ -130,16 +73,18 @@ class TouchBarController: NSObject, NSTouchBarDelegate {
|
|||||||
touchBar.delegate = self
|
touchBar.delegate = self
|
||||||
touchBar.defaultItemIdentifiers = [basicViewIdentifier]
|
touchBar.defaultItemIdentifiers = [basicViewIdentifier]
|
||||||
|
|
||||||
let leftItems = leftIdentifiers.compactMap({ (identifier) -> NSTouchBarItem? in
|
basicView = BasicView(identifier: basicViewIdentifier, items: leftItems + [scrollArea] + rightItems, swipeItems: swipeItems)
|
||||||
items[identifier]
|
|
||||||
})
|
|
||||||
let rightItems = rightIdentifiers.compactMap({ (identifier) -> NSTouchBarItem? in
|
|
||||||
items[identifier]
|
|
||||||
})
|
|
||||||
|
|
||||||
basicView = BasicView(identifier: basicViewIdentifier, items:leftItems + [scrollArea] + rightItems, swipeItems: swipeItems)
|
|
||||||
basicView?.legacyGesturesEnabled = AppSettings.multitouchGestures
|
basicView?.legacyGesturesEnabled = AppSettings.multitouchGestures
|
||||||
|
|
||||||
|
// it seems that we need to set width only after we added them to the view
|
||||||
|
// so lets reset width here
|
||||||
|
for item in items {
|
||||||
|
item.setWidth(value: item.getWidth())
|
||||||
|
if item is CustomButtonTouchBarItem {
|
||||||
|
(item as! CustomButtonTouchBarItem).reinstallButton()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
updateActiveApp()
|
updateActiveApp()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -166,41 +111,26 @@ class TouchBarController: NSObject, NSTouchBarDelegate {
|
|||||||
reloadPreset(path: presetPath)
|
reloadPreset(path: presetPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
func reloadPreset(path: String) {
|
func reloadPreset(path: String?) {
|
||||||
lastPresetPath = path
|
if path != nil {
|
||||||
let items = path.fileData?.barItemDefinitions() ?? [BarItemDefinition(type: .staticButton(title: "bad preset"), action: .none, longAction: .none, additionalParameters: [:])]
|
lastPresetPath = path!
|
||||||
createAndUpdatePreset(newJsonItems: items)
|
|
||||||
}
|
|
||||||
|
|
||||||
func loadItemDefinitions(jsonItems: [BarItemDefinition]) {
|
|
||||||
let dateFormatter = DateFormatter()
|
|
||||||
dateFormatter.dateFormat = "HH-mm-ss"
|
|
||||||
let time = dateFormatter.string(from: Date())
|
|
||||||
for item in jsonItems {
|
|
||||||
let identifierString = item.type.identifierBase.appending(time + "--" + UUID().uuidString)
|
|
||||||
let identifier = NSTouchBarItem.Identifier(identifierString)
|
|
||||||
itemDefinitions[identifier] = item
|
|
||||||
if item.align == .left {
|
|
||||||
leftIdentifiers.append(identifier)
|
|
||||||
}
|
|
||||||
if item.align == .right {
|
|
||||||
rightIdentifiers.append(identifier)
|
|
||||||
}
|
|
||||||
if item.align == .center {
|
|
||||||
centerIdentifiers.append(identifier)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let items = lastPresetPath.fileData?.barItemDefinitions() ?? [BarItemDefinition(obj: CustomButtonTouchBarItem(title: "bad preset"))]
|
||||||
|
createAndUpdatePreset(newItems: items)
|
||||||
}
|
}
|
||||||
|
|
||||||
func createItems() {
|
func getItems(newItems: [BarItemDefinition]) -> ([CustomTouchBarItem], [SwipeItem]) {
|
||||||
for (identifier, definition) in itemDefinitions {
|
var items: [CustomTouchBarItem] = []
|
||||||
let item = createItem(forIdentifier: identifier, definition: definition)
|
var swipeItems: [SwipeItem] = []
|
||||||
if item is SwipeItem {
|
for item in newItems {
|
||||||
swipeItems.append(item as! SwipeItem)
|
if item.obj is SwipeItem {
|
||||||
|
swipeItems.append(item.obj as! SwipeItem)
|
||||||
} else {
|
} else {
|
||||||
items[identifier] = item
|
items.append(item.obj)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return (items, swipeItems)
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func setupControlStripPresence() {
|
@objc func setupControlStripPresence() {
|
||||||
@ -224,7 +154,7 @@ class TouchBarController: NSObject, NSTouchBarDelegate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc private func dismissTouchBar() {
|
@objc func dismissTouchBar() {
|
||||||
minimizeSystemModal(touchBar)
|
minimizeSystemModal(touchBar)
|
||||||
updateControlStripPresence()
|
updateControlStripPresence()
|
||||||
}
|
}
|
||||||
@ -241,198 +171,8 @@ class TouchBarController: NSObject, NSTouchBarDelegate {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func createItem(forIdentifier identifier: NSTouchBarItem.Identifier, definition item: BarItemDefinition) -> NSTouchBarItem? {
|
|
||||||
var barItem: NSTouchBarItem!
|
|
||||||
switch item.type {
|
|
||||||
case let .staticButton(title: title):
|
|
||||||
barItem = CustomButtonTouchBarItem(identifier: identifier, title: title)
|
|
||||||
case let .appleScriptTitledButton(source: source, refreshInterval: interval, alternativeImages: alternativeImages):
|
|
||||||
barItem = AppleScriptTouchBarItem(identifier: identifier, source: source, interval: interval, alternativeImages: alternativeImages)
|
|
||||||
case let .shellScriptTitledButton(source: source, refreshInterval: interval):
|
|
||||||
barItem = ShellScriptTouchBarItem(identifier: identifier, source: source, interval: interval)
|
|
||||||
case let .timeButton(formatTemplate: template, timeZone: timeZone, locale: locale):
|
|
||||||
barItem = TimeTouchBarItem(identifier: identifier, formatTemplate: template, timeZone: timeZone, locale: locale)
|
|
||||||
case .battery:
|
|
||||||
barItem = BatteryBarItem(identifier: identifier)
|
|
||||||
case let .dock(autoResize: autoResize, filter: regexString):
|
|
||||||
if let regexString = regexString {
|
|
||||||
guard let regex = try? NSRegularExpression(pattern: regexString, options: []) else {
|
|
||||||
barItem = CustomButtonTouchBarItem(identifier: identifier, title: "Bad regex")
|
|
||||||
break
|
|
||||||
}
|
|
||||||
barItem = AppScrubberTouchBarItem(identifier: identifier, autoResize: autoResize, filter: regex)
|
|
||||||
} else {
|
|
||||||
barItem = AppScrubberTouchBarItem(identifier: identifier, autoResize: autoResize)
|
|
||||||
}
|
|
||||||
case .volume:
|
|
||||||
if case let .image(source)? = item.additionalParameters[.image] {
|
|
||||||
barItem = VolumeViewController(identifier: identifier, image: source.image)
|
|
||||||
} else {
|
|
||||||
barItem = VolumeViewController(identifier: identifier)
|
|
||||||
}
|
|
||||||
case let .brightness(refreshInterval: interval):
|
|
||||||
if case let .image(source)? = item.additionalParameters[.image] {
|
|
||||||
barItem = BrightnessViewController(identifier: identifier, refreshInterval: interval, image: source.image)
|
|
||||||
} else {
|
|
||||||
barItem = BrightnessViewController(identifier: identifier, refreshInterval: interval)
|
|
||||||
}
|
|
||||||
case let .weather(interval: interval, units: units, api_key: api_key, icon_type: icon_type):
|
|
||||||
barItem = WeatherBarItem(identifier: identifier, interval: interval, units: units, api_key: api_key, icon_type: icon_type)
|
|
||||||
case let .yandexWeather(interval: interval):
|
|
||||||
barItem = YandexWeatherBarItem(identifier: identifier, interval: interval)
|
|
||||||
case let .currency(interval: interval, from: from, to: to, full: full):
|
|
||||||
barItem = CurrencyBarItem(identifier: identifier, interval: interval, from: from, to: to, full: full)
|
|
||||||
case .inputsource:
|
|
||||||
barItem = InputSourceBarItem(identifier: identifier)
|
|
||||||
case let .music(interval: interval, disableMarquee: disableMarquee):
|
|
||||||
barItem = MusicBarItem(identifier: identifier, interval: interval, disableMarquee: disableMarquee)
|
|
||||||
case let .group(items: items):
|
|
||||||
barItem = GroupBarItem(identifier: identifier, items: items)
|
|
||||||
case .nightShift:
|
|
||||||
barItem = NightShiftBarItem(identifier: identifier)
|
|
||||||
case .dnd:
|
|
||||||
barItem = DnDBarItem(identifier: identifier)
|
|
||||||
case let .pomodoro(workTime: workTime, restTime: restTime):
|
|
||||||
barItem = PomodoroBarItem(identifier: identifier, workTime: workTime, restTime: restTime)
|
|
||||||
case let .network(flip: flip):
|
|
||||||
barItem = NetworkBarItem(identifier: identifier, flip: flip)
|
|
||||||
case .darkMode:
|
|
||||||
barItem = DarkModeBarItem(identifier: identifier)
|
|
||||||
case let .swipe(direction: direction, fingers: fingers, minOffset: minOffset, sourceApple: sourceApple, sourceBash: sourceBash):
|
|
||||||
barItem = SwipeItem(identifier: identifier, direction: direction, fingers: fingers, minOffset: minOffset, sourceApple: sourceApple, sourceBash: sourceBash)
|
|
||||||
}
|
|
||||||
|
|
||||||
if let action = self.action(forItem: item), let item = barItem as? CustomButtonTouchBarItem {
|
|
||||||
item.tapClosure = action
|
|
||||||
}
|
|
||||||
if let longAction = self.longAction(forItem: item), let item = barItem as? CustomButtonTouchBarItem {
|
|
||||||
item.longTapClosure = longAction
|
|
||||||
}
|
|
||||||
if case let .bordered(bordered)? = item.additionalParameters[.bordered], let item = barItem as? CustomButtonTouchBarItem {
|
|
||||||
item.isBordered = bordered
|
|
||||||
}
|
|
||||||
if case let .background(color)? = item.additionalParameters[.background], let item = barItem as? CustomButtonTouchBarItem {
|
|
||||||
item.backgroundColor = color
|
|
||||||
}
|
|
||||||
if case let .width(value)? = item.additionalParameters[.width], let widthBarItem = barItem as? CanSetWidth {
|
|
||||||
widthBarItem.setWidth(value: value)
|
|
||||||
}
|
|
||||||
if case let .image(source)? = item.additionalParameters[.image], let item = barItem as? CustomButtonTouchBarItem {
|
|
||||||
item.image = source.image
|
|
||||||
}
|
|
||||||
if case let .title(value)? = item.additionalParameters[.title] {
|
|
||||||
if let item = barItem as? GroupBarItem {
|
|
||||||
item.collapsedRepresentationLabel = value
|
|
||||||
} else if let item = barItem as? CustomButtonTouchBarItem {
|
|
||||||
item.title = value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return barItem
|
|
||||||
}
|
|
||||||
|
|
||||||
func action(forItem item: BarItemDefinition) -> (() -> Void)? {
|
|
||||||
switch item.action {
|
|
||||||
case let .hidKey(keycode: keycode):
|
|
||||||
return { HIDPostAuxKey(keycode) }
|
|
||||||
case let .keyPress(keycode: keycode):
|
|
||||||
return { GenericKeyPress(keyCode: CGKeyCode(keycode)).send() }
|
|
||||||
case let .appleScript(source: source):
|
|
||||||
guard let appleScript = source.appleScript else {
|
|
||||||
print("cannot create apple script for item \(item)")
|
|
||||||
return {}
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
DispatchQueue.appleScriptQueue.async {
|
|
||||||
var error: NSDictionary?
|
|
||||||
appleScript.executeAndReturnError(&error)
|
|
||||||
if let error = error {
|
|
||||||
print("error \(error) when handling \(item) ")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case let .shellScript(executable: executable, parameters: parameters):
|
|
||||||
return {
|
|
||||||
let task = Process()
|
|
||||||
task.launchPath = executable
|
|
||||||
task.arguments = parameters
|
|
||||||
task.launch()
|
|
||||||
}
|
|
||||||
case let .openUrl(url: url):
|
|
||||||
return {
|
|
||||||
if let url = URL(string: url), NSWorkspace.shared.open(url) {
|
|
||||||
#if DEBUG
|
|
||||||
print("URL was successfully opened")
|
|
||||||
#endif
|
|
||||||
} else {
|
|
||||||
print("error", url)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case let .custom(closure: closure):
|
|
||||||
return closure
|
|
||||||
case .none:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func longAction(forItem item: BarItemDefinition) -> (() -> Void)? {
|
|
||||||
switch item.longAction {
|
|
||||||
case let .hidKey(keycode: keycode):
|
|
||||||
return { HIDPostAuxKey(keycode) }
|
|
||||||
case let .keyPress(keycode: keycode):
|
|
||||||
return { GenericKeyPress(keyCode: CGKeyCode(keycode)).send() }
|
|
||||||
case let .appleScript(source: source):
|
|
||||||
guard let appleScript = source.appleScript else {
|
|
||||||
print("cannot create apple script for item \(item)")
|
|
||||||
return {}
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
var error: NSDictionary?
|
|
||||||
appleScript.executeAndReturnError(&error)
|
|
||||||
if let error = error {
|
|
||||||
print("error \(error) when handling \(item) ")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case let .shellScript(executable: executable, parameters: parameters):
|
|
||||||
return {
|
|
||||||
let task = Process()
|
|
||||||
task.launchPath = executable
|
|
||||||
task.arguments = parameters
|
|
||||||
task.launch()
|
|
||||||
}
|
|
||||||
case let .openUrl(url: url):
|
|
||||||
return {
|
|
||||||
if let url = URL(string: url), NSWorkspace.shared.open(url) {
|
|
||||||
#if DEBUG
|
|
||||||
print("URL was successfully opened")
|
|
||||||
#endif
|
|
||||||
} else {
|
|
||||||
print("error", url)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case let .custom(closure: closure):
|
|
||||||
return closure
|
|
||||||
case .none:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protocol CanSetWidth {
|
protocol CanSetWidth {
|
||||||
func setWidth(value: CGFloat)
|
func setWidth(value: CGFloat)
|
||||||
}
|
}
|
||||||
|
|
||||||
extension NSCustomTouchBarItem: CanSetWidth {
|
|
||||||
func setWidth(value: CGFloat) {
|
|
||||||
view.widthAnchor.constraint(equalToConstant: value).isActive = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension BarItemDefinition {
|
|
||||||
var align: Align {
|
|
||||||
if case let .align(result)? = additionalParameters[.align] {
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
return .center
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
import Cocoa
|
import Cocoa
|
||||||
|
|
||||||
class AppScrubberTouchBarItem: NSCustomTouchBarItem {
|
class AppScrubberTouchBarItem: CustomTouchBarItem {
|
||||||
private var scrollView = NSScrollView()
|
private var scrollView = NSScrollView()
|
||||||
private var autoResize: Bool = false
|
private var autoResize: Bool = false
|
||||||
private var widthConstraint: NSLayoutConstraint?
|
private var widthConstraint: NSLayoutConstraint?
|
||||||
@ -20,6 +20,20 @@ class AppScrubberTouchBarItem: NSCustomTouchBarItem {
|
|||||||
return NSWorkspace.shared.frontmostApplication?.bundleIdentifier
|
return NSWorkspace.shared.frontmostApplication?.bundleIdentifier
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum ParsingErrors: Error {
|
||||||
|
case IncorrectRegex(description: String)
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum CodingKeys: String, CodingKey {
|
||||||
|
case autoResize
|
||||||
|
case filter
|
||||||
|
}
|
||||||
|
|
||||||
|
override class var typeIdentifier: String {
|
||||||
|
return "dock"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private var applications: [DockItem] = []
|
private var applications: [DockItem] = []
|
||||||
private var items: [DockBarItem] = []
|
private var items: [DockBarItem] = []
|
||||||
|
|
||||||
@ -29,6 +43,35 @@ class AppScrubberTouchBarItem: NSCustomTouchBarItem {
|
|||||||
self.autoResize = autoResize
|
self.autoResize = autoResize
|
||||||
view = scrollView
|
view = scrollView
|
||||||
|
|
||||||
|
self.setup()
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder _: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
required init(from decoder: Decoder) throws {
|
||||||
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
|
|
||||||
|
self.autoResize = try container.decodeIfPresent(Bool.self, forKey: .autoResize) ?? false
|
||||||
|
let filterRegexString = try container.decodeIfPresent(String.self, forKey: .filter)
|
||||||
|
|
||||||
|
if let filterRegexString = filterRegexString {
|
||||||
|
let regex = try? NSRegularExpression(pattern: filterRegexString, options: [])
|
||||||
|
if regex == nil {
|
||||||
|
throw ParsingErrors.IncorrectRegex(description: "incorrect regex")
|
||||||
|
}
|
||||||
|
self.filter = regex
|
||||||
|
} else {
|
||||||
|
self.filter = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
try super.init(from: decoder)
|
||||||
|
view = scrollView
|
||||||
|
self.setup()
|
||||||
|
}
|
||||||
|
|
||||||
|
func setup() {
|
||||||
NSWorkspace.shared.notificationCenter.addObserver(self, selector: #selector(hardReloadItems), name: NSWorkspace.didLaunchApplicationNotification, object: nil)
|
NSWorkspace.shared.notificationCenter.addObserver(self, selector: #selector(hardReloadItems), name: NSWorkspace.didLaunchApplicationNotification, object: nil)
|
||||||
NSWorkspace.shared.notificationCenter.addObserver(self, selector: #selector(hardReloadItems), name: NSWorkspace.didTerminateApplicationNotification, object: nil)
|
NSWorkspace.shared.notificationCenter.addObserver(self, selector: #selector(hardReloadItems), name: NSWorkspace.didTerminateApplicationNotification, object: nil)
|
||||||
NSWorkspace.shared.notificationCenter.addObserver(self, selector: #selector(softReloadItems), name: NSWorkspace.didActivateApplicationNotification, object: nil)
|
NSWorkspace.shared.notificationCenter.addObserver(self, selector: #selector(softReloadItems), name: NSWorkspace.didActivateApplicationNotification, object: nil)
|
||||||
@ -37,9 +80,6 @@ class AppScrubberTouchBarItem: NSCustomTouchBarItem {
|
|||||||
hardReloadItems()
|
hardReloadItems()
|
||||||
}
|
}
|
||||||
|
|
||||||
required init?(coder _: NSCoder) {
|
|
||||||
fatalError("init(coder:) has not been implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc func hardReloadItems() {
|
@objc func hardReloadItems() {
|
||||||
applications = launchedApplications()
|
applications = launchedApplications()
|
||||||
@ -82,12 +122,17 @@ class AppScrubberTouchBarItem: NSCustomTouchBarItem {
|
|||||||
public func createAppButton(for app: DockItem) -> DockBarItem {
|
public func createAppButton(for app: DockItem) -> DockBarItem {
|
||||||
let item = DockBarItem(app)
|
let item = DockBarItem(app)
|
||||||
item.isBordered = false
|
item.isBordered = false
|
||||||
item.tapClosure = { [weak self] in
|
|
||||||
self?.switchToApp(app: app)
|
item.setTapAction(
|
||||||
}
|
EventAction({ [weak self] (_ caller: CustomButtonTouchBarItem) in
|
||||||
item.longTapClosure = { [weak self] in
|
self?.switchToApp(app: app)
|
||||||
self?.handleHalfLongPress(item: app)
|
} )
|
||||||
}
|
)
|
||||||
|
item.setLongTapAction(
|
||||||
|
EventAction({ [weak self] (_ caller: CustomButtonTouchBarItem) in
|
||||||
|
self?.handleHalfLongPress(item: app)
|
||||||
|
} )
|
||||||
|
)
|
||||||
item.killAppClosure = {[weak self] in
|
item.killAppClosure = {[weak self] in
|
||||||
self?.handleLongPress(item: app)
|
self?.handleLongPress(item: app)
|
||||||
}
|
}
|
||||||
@ -212,8 +257,8 @@ class DockBarItem: CustomButtonTouchBarItem {
|
|||||||
super.init(identifier: .init(app.bundleIdentifier), title: "")
|
super.init(identifier: .init(app.bundleIdentifier), title: "")
|
||||||
dotView.wantsLayer = true
|
dotView.wantsLayer = true
|
||||||
|
|
||||||
image = app.icon
|
self.setImage(app.icon)
|
||||||
image?.size = NSSize(width: iconWidth, height: iconWidth)
|
self.getImage()?.size = NSSize(width: iconWidth, height: iconWidth)
|
||||||
|
|
||||||
killGestureRecognizer = LongPressGestureRecognizer(target: self, action: #selector(firePanGestureRecognizer))
|
killGestureRecognizer = LongPressGestureRecognizer(target: self, action: #selector(firePanGestureRecognizer))
|
||||||
killGestureRecognizer.allowedTouchTypes = .direct
|
killGestureRecognizer.allowedTouchTypes = .direct
|
||||||
@ -243,4 +288,8 @@ class DockBarItem: CustomButtonTouchBarItem {
|
|||||||
required init?(coder _: NSCoder) {
|
required init?(coder _: NSCoder) {
|
||||||
fatalError("init(coder:) has not been implemented")
|
fatalError("init(coder:) has not been implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
required init(from decoder: Decoder) {
|
||||||
|
fatalError("init(from decoder:) has not been implemented")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,21 +12,35 @@ import IOKit.ps
|
|||||||
class BatteryBarItem: CustomButtonTouchBarItem {
|
class BatteryBarItem: CustomButtonTouchBarItem {
|
||||||
private let batteryInfo = BatteryInfo()
|
private let batteryInfo = BatteryInfo()
|
||||||
|
|
||||||
|
override class var typeIdentifier: String {
|
||||||
|
return "battery"
|
||||||
|
}
|
||||||
|
|
||||||
init(identifier: NSTouchBarItem.Identifier) {
|
init(identifier: NSTouchBarItem.Identifier) {
|
||||||
super.init(identifier: identifier, title: " ")
|
super.init(identifier: identifier, title: " ")
|
||||||
|
|
||||||
batteryInfo.start { [weak self] in
|
self.setup()
|
||||||
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")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
required init(from decoder: Decoder) throws {
|
||||||
|
try super.init(from: decoder)
|
||||||
|
|
||||||
|
self.setup()
|
||||||
|
}
|
||||||
|
|
||||||
|
func setup() {
|
||||||
|
batteryInfo.start { [weak self] in
|
||||||
|
self?.refresh()
|
||||||
|
}
|
||||||
|
refresh()
|
||||||
|
}
|
||||||
|
|
||||||
func refresh() {
|
func refresh() {
|
||||||
attributedTitle = batteryInfo.formattedInfo()
|
setAttributedTitle(batteryInfo.formattedInfo())
|
||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
|
|||||||
27
MTMR/Widgets/BrightnessDownBarItem.swift
Normal file
27
MTMR/Widgets/BrightnessDownBarItem.swift
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
//
|
||||||
|
// BrightnessDownBarItem.swift
|
||||||
|
// MTMR
|
||||||
|
//
|
||||||
|
// Created by Fedor Zaitsev on 4/27/20.
|
||||||
|
// Copyright © 2020 Anton Palgunov. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
class BrightnessDownBarItem: CustomButtonTouchBarItem {
|
||||||
|
override class var typeIdentifier: String {
|
||||||
|
return "brightnessDown"
|
||||||
|
}
|
||||||
|
|
||||||
|
required init(from decoder: Decoder) throws {
|
||||||
|
try super.init(from: decoder)
|
||||||
|
|
||||||
|
self.setImage(#imageLiteral(resourceName: "brightnessDown"))
|
||||||
|
self.setTapAction(EventAction().setKeyPressClosure(keycode: 145))
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder _: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
27
MTMR/Widgets/BrightnessUpBarItem.swift
Normal file
27
MTMR/Widgets/BrightnessUpBarItem.swift
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
//
|
||||||
|
// BrightnessUpBarItem.swift
|
||||||
|
// MTMR
|
||||||
|
//
|
||||||
|
// Created by Fedor Zaitsev on 4/27/20.
|
||||||
|
// Copyright © 2020 Anton Palgunov. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
class BrightnessUpBarItem: CustomButtonTouchBarItem {
|
||||||
|
override class var typeIdentifier: String {
|
||||||
|
return "brightnessUp"
|
||||||
|
}
|
||||||
|
|
||||||
|
required init(from decoder: Decoder) throws {
|
||||||
|
try super.init(from: decoder)
|
||||||
|
|
||||||
|
self.setImage(#imageLiteral(resourceName: "brightnessUp"))
|
||||||
|
self.setTapAction(EventAction().setKeyPressClosure(keycode: 144))
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder _: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ -3,12 +3,39 @@ import AVFoundation
|
|||||||
import Cocoa
|
import Cocoa
|
||||||
import CoreAudio
|
import CoreAudio
|
||||||
|
|
||||||
class BrightnessViewController: NSCustomTouchBarItem {
|
class BrightnessViewController: CustomTouchBarItem {
|
||||||
private(set) var sliderItem: CustomSlider!
|
private(set) var sliderItem: CustomSlider!
|
||||||
|
|
||||||
|
override class var typeIdentifier: String {
|
||||||
|
return "brightness"
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum CodingKeys: String, CodingKey {
|
||||||
|
case image
|
||||||
|
case refreshInterval
|
||||||
|
}
|
||||||
|
|
||||||
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)
|
||||||
|
self.setup(image: nil, interval: refreshInterval)
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder _: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
required init(from decoder: Decoder) throws {
|
||||||
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
|
let image = try container.decodeIfPresent(Source.self, forKey: .image)?.image
|
||||||
|
let interval = try container.decodeIfPresent(Double.self, forKey: .refreshInterval) ?? 0.5
|
||||||
|
|
||||||
|
try super.init(from: decoder)
|
||||||
|
|
||||||
|
self.setup(image: image, interval: interval)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func setup(image: NSImage?, interval: Double) {
|
||||||
if image == nil {
|
if image == nil {
|
||||||
sliderItem = CustomSlider()
|
sliderItem = CustomSlider()
|
||||||
} else {
|
} else {
|
||||||
@ -22,14 +49,10 @@ class BrightnessViewController: NSCustomTouchBarItem {
|
|||||||
|
|
||||||
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: interval, 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) {
|
|
||||||
fatalError("init(coder:) has not been implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
sliderItem.unbind(NSBindingName.value)
|
sliderItem.unbind(NSBindingName.value)
|
||||||
}
|
}
|
||||||
|
|||||||
48
MTMR/Widgets/CloseBarItem.swift
Normal file
48
MTMR/Widgets/CloseBarItem.swift
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
//
|
||||||
|
// CloseBarItem.swift
|
||||||
|
// MTMR
|
||||||
|
//
|
||||||
|
// Created by Fedor Zaitsev on 4/30/20.
|
||||||
|
// Copyright © 2020 Anton Palgunov. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
class CloseBarItem: CustomButtonTouchBarItem {
|
||||||
|
override class var typeIdentifier: String {
|
||||||
|
return "close"
|
||||||
|
}
|
||||||
|
|
||||||
|
init(identifier: NSTouchBarItem.Identifier) {
|
||||||
|
super.init(identifier: identifier, title: "")
|
||||||
|
|
||||||
|
if self.title == "" {
|
||||||
|
self.title = "close"
|
||||||
|
}
|
||||||
|
|
||||||
|
self.setTapAction(EventAction.init({_ in
|
||||||
|
|
||||||
|
TouchBarController.shared.reloadPreset(path: nil)
|
||||||
|
|
||||||
|
} ))
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder _: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
required init(from decoder: Decoder) throws {
|
||||||
|
try super.init(from: decoder)
|
||||||
|
|
||||||
|
if self.title == "" {
|
||||||
|
self.title = "close"
|
||||||
|
}
|
||||||
|
|
||||||
|
self.setTapAction(EventAction.init({_ in
|
||||||
|
|
||||||
|
TouchBarController.shared.reloadPreset(path: nil)
|
||||||
|
|
||||||
|
} ))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -59,6 +59,18 @@ class CurrencyBarItem: CustomButtonTouchBarItem {
|
|||||||
"ETH": 2,
|
"ETH": 2,
|
||||||
]
|
]
|
||||||
|
|
||||||
|
override class var typeIdentifier: String {
|
||||||
|
return "currency"
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum CodingKeys: String, CodingKey {
|
||||||
|
case refreshInterval
|
||||||
|
case from
|
||||||
|
case to
|
||||||
|
case full
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
init(identifier: NSTouchBarItem.Identifier, interval: TimeInterval, from: String, to: String, full: Bool) {
|
init(identifier: NSTouchBarItem.Identifier, interval: TimeInterval, from: String, to: String, full: Bool) {
|
||||||
activity = NSBackgroundActivityScheduler(identifier: "\(identifier.rawValue).updatecheck")
|
activity = NSBackgroundActivityScheduler(identifier: "\(identifier.rawValue).updatecheck")
|
||||||
activity.interval = interval
|
activity.interval = interval
|
||||||
@ -87,7 +99,51 @@ class CurrencyBarItem: CustomButtonTouchBarItem {
|
|||||||
|
|
||||||
|
|
||||||
super.init(identifier: identifier, title: "⏳")
|
super.init(identifier: identifier, title: "⏳")
|
||||||
|
self.setup()
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder _: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
required init(from decoder: Decoder) throws {
|
||||||
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
|
|
||||||
|
let interval = try container.decodeIfPresent(Double.self, forKey: .refreshInterval) ?? 600.0
|
||||||
|
let from = try container.decodeIfPresent(String.self, forKey: .from) ?? "RUB"
|
||||||
|
let to = try container.decodeIfPresent(String.self, forKey: .to) ?? "USD"
|
||||||
|
let full = try container.decodeIfPresent(Bool.self, forKey: .full) ?? false
|
||||||
|
|
||||||
|
activity = NSBackgroundActivityScheduler(identifier: CustomTouchBarItem.createIdentifier("Currency.updatecheck").rawValue)
|
||||||
|
activity.interval = interval
|
||||||
|
self.from = from
|
||||||
|
self.to = to
|
||||||
|
self.full = full
|
||||||
|
|
||||||
|
if let prefix = currencies[from] {
|
||||||
|
self.prefix = prefix
|
||||||
|
} else {
|
||||||
|
prefix = from
|
||||||
|
}
|
||||||
|
|
||||||
|
if let postfix = currencies[to] {
|
||||||
|
self.postfix = postfix
|
||||||
|
} else {
|
||||||
|
postfix = to
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if let decimal = decimals[to] {
|
||||||
|
self.decimal = decimal
|
||||||
|
} else {
|
||||||
|
decimal = 2
|
||||||
|
}
|
||||||
|
|
||||||
|
try super.init(from: decoder)
|
||||||
|
self.setup()
|
||||||
|
}
|
||||||
|
|
||||||
|
func setup() {
|
||||||
activity.repeats = true
|
activity.repeats = true
|
||||||
activity.qualityOfService = .utility
|
activity.qualityOfService = .utility
|
||||||
activity.schedule { (completion: NSBackgroundActivityScheduler.CompletionHandler) in
|
activity.schedule { (completion: NSBackgroundActivityScheduler.CompletionHandler) in
|
||||||
@ -97,10 +153,6 @@ class CurrencyBarItem: CustomButtonTouchBarItem {
|
|||||||
updateCurrency()
|
updateCurrency()
|
||||||
}
|
}
|
||||||
|
|
||||||
required init?(coder _: NSCoder) {
|
|
||||||
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)")!)
|
||||||
|
|
||||||
@ -153,10 +205,10 @@ class CurrencyBarItem: CustomButtonTouchBarItem {
|
|||||||
title = String(format: "%@%.2f", prefix, value)
|
title = String(format: "%@%.2f", prefix, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
let regularFont = attributedTitle.attribute(.font, at: 0, effectiveRange: nil) as? NSFont ?? NSFont.systemFont(ofSize: 15)
|
let regularFont = getAttributedTitle().attribute(.font, at: 0, effectiveRange: nil) as? NSFont ?? NSFont.systemFont(ofSize: 15)
|
||||||
let newTitle = NSMutableAttributedString(string: title as String, attributes: [.foregroundColor: color, .font: regularFont, .baselineOffset: 1])
|
let newTitle = NSMutableAttributedString(string: title as String, attributes: [.foregroundColor: color, .font: regularFont, .baselineOffset: 1])
|
||||||
newTitle.setAlignment(.center, range: NSRange(location: 0, length: title.count))
|
newTitle.setAlignment(.center, range: NSRange(location: 0, length: title.count))
|
||||||
attributedTitle = newTitle
|
setAttributedTitle(newTitle)
|
||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
|
|||||||
@ -1,34 +1,51 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
class DarkModeBarItem: CustomButtonTouchBarItem, Widget {
|
class DarkModeBarItem: CustomButtonTouchBarItem {
|
||||||
static var name: String = "darkmode"
|
|
||||||
static var identifier: String = "com.toxblh.mtmr.darkmode"
|
|
||||||
|
|
||||||
private var timer: Timer!
|
private var timer: Timer!
|
||||||
|
|
||||||
|
override class var typeIdentifier: String {
|
||||||
|
return "darkMode"
|
||||||
|
}
|
||||||
|
|
||||||
init(identifier: NSTouchBarItem.Identifier) {
|
init(identifier: NSTouchBarItem.Identifier) {
|
||||||
super.init(identifier: identifier, title: "")
|
super.init(identifier: identifier, title: "")
|
||||||
isBordered = false
|
|
||||||
setWidth(value: 24)
|
|
||||||
|
|
||||||
tapClosure = { [weak self] in self?.DarkModeToggle() }
|
self.setup()
|
||||||
|
|
||||||
timer = Timer.scheduledTimer(timeInterval: 3, target: self, selector: #selector(refresh), userInfo: nil, repeats: true)
|
|
||||||
|
|
||||||
refresh()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
required init?(coder _: NSCoder) {
|
required init?(coder _: NSCoder) {
|
||||||
fatalError("init(coder:) has not been implemented")
|
fatalError("init(coder:) has not been implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
required init(from decoder: Decoder) throws {
|
||||||
|
try super.init(from: decoder)
|
||||||
|
|
||||||
|
self.setup()
|
||||||
|
}
|
||||||
|
|
||||||
|
func setup() {
|
||||||
|
if getWidth() == 0.0 {
|
||||||
|
setWidth(value: 24)
|
||||||
|
}
|
||||||
|
|
||||||
|
self.setTapAction(
|
||||||
|
EventAction({ [weak self] (_ caller: CustomButtonTouchBarItem) in
|
||||||
|
self?.DarkModeToggle()
|
||||||
|
} )
|
||||||
|
)
|
||||||
|
|
||||||
|
timer = Timer.scheduledTimer(timeInterval: 3, target: self, selector: #selector(refresh), userInfo: nil, repeats: true)
|
||||||
|
|
||||||
|
refresh()
|
||||||
|
}
|
||||||
|
|
||||||
func DarkModeToggle() {
|
func DarkModeToggle() {
|
||||||
DarkMode.isEnabled = !DarkMode.isEnabled
|
DarkMode.isEnabled = !DarkMode.isEnabled
|
||||||
refresh()
|
refresh()
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func refresh() {
|
@objc func refresh() {
|
||||||
image = DarkMode.isEnabled ? #imageLiteral(resourceName: "dark-mode-on") : #imageLiteral(resourceName: "dark-mode-off")
|
self.setImage(DarkMode.isEnabled ? #imageLiteral(resourceName: "dark-mode-on") : #imageLiteral(resourceName: "dark-mode-off"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
27
MTMR/Widgets/DeleteBarItem.swift
Normal file
27
MTMR/Widgets/DeleteBarItem.swift
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
//
|
||||||
|
// DeleteBarItem.swift
|
||||||
|
// MTMR
|
||||||
|
//
|
||||||
|
// Created by Fedor Zaitsev on 4/27/20.
|
||||||
|
// Copyright © 2020 Anton Palgunov. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
class DeleteBarItem: CustomButtonTouchBarItem {
|
||||||
|
override class var typeIdentifier: String {
|
||||||
|
return "delete"
|
||||||
|
}
|
||||||
|
|
||||||
|
required init(from decoder: Decoder) throws {
|
||||||
|
try super.init(from: decoder)
|
||||||
|
|
||||||
|
print("DeleteBarItem.init")
|
||||||
|
self.title = "del"
|
||||||
|
self.setTapAction(EventAction().setKeyPressClosure(keycode: 117))
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder _: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
}
|
||||||
27
MTMR/Widgets/DisplaySleepBarItem.swift
Normal file
27
MTMR/Widgets/DisplaySleepBarItem.swift
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
//
|
||||||
|
// DisplaySleep.swift
|
||||||
|
// MTMR
|
||||||
|
//
|
||||||
|
// Created by Fedor Zaitsev on 4/27/20.
|
||||||
|
// Copyright © 2020 Anton Palgunov. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
class DisplaySleepBarItem: CustomButtonTouchBarItem {
|
||||||
|
override class var typeIdentifier: String {
|
||||||
|
return "displaySleep"
|
||||||
|
}
|
||||||
|
|
||||||
|
required init(from decoder: Decoder) throws {
|
||||||
|
try super.init(from: decoder)
|
||||||
|
|
||||||
|
self.title = "☕️"
|
||||||
|
self.setTapAction(EventAction().setShellScriptClosure(executable: "/usr/bin/pmset", parameters: ["displaysleepnow"]))
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder _: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ -11,29 +11,47 @@ import Foundation
|
|||||||
class DnDBarItem: CustomButtonTouchBarItem {
|
class DnDBarItem: CustomButtonTouchBarItem {
|
||||||
private var timer: Timer!
|
private var timer: Timer!
|
||||||
|
|
||||||
|
override class var typeIdentifier: String {
|
||||||
|
return "dnd"
|
||||||
|
}
|
||||||
|
|
||||||
init(identifier: NSTouchBarItem.Identifier) {
|
init(identifier: NSTouchBarItem.Identifier) {
|
||||||
super.init(identifier: identifier, title: "")
|
super.init(identifier: identifier, title: "")
|
||||||
isBordered = false
|
self.setup()
|
||||||
setWidth(value: 32)
|
|
||||||
|
|
||||||
tapClosure = { [weak self] in self?.DnDToggle() }
|
|
||||||
|
|
||||||
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(refresh), userInfo: nil, repeats: true)
|
|
||||||
|
|
||||||
refresh()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
required init?(coder _: NSCoder) {
|
required init?(coder _: NSCoder) {
|
||||||
fatalError("init(coder:) has not been implemented")
|
fatalError("init(coder:) has not been implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
required init(from decoder: Decoder) throws {
|
||||||
|
try super.init(from: decoder)
|
||||||
|
self.setup()
|
||||||
|
}
|
||||||
|
|
||||||
|
func setup() {
|
||||||
|
if getWidth() == 0.0 {
|
||||||
|
setWidth(value: 32)
|
||||||
|
}
|
||||||
|
|
||||||
|
self.setTapAction(
|
||||||
|
EventAction({ [weak self] (_ caller: CustomButtonTouchBarItem) in
|
||||||
|
self?.DnDToggle()
|
||||||
|
} )
|
||||||
|
)
|
||||||
|
|
||||||
|
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(refresh), userInfo: nil, repeats: true)
|
||||||
|
|
||||||
|
refresh()
|
||||||
|
}
|
||||||
|
|
||||||
func DnDToggle() {
|
func DnDToggle() {
|
||||||
DoNotDisturb.isEnabled = !DoNotDisturb.isEnabled
|
DoNotDisturb.isEnabled = !DoNotDisturb.isEnabled
|
||||||
refresh()
|
refresh()
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func refresh() {
|
@objc func refresh() {
|
||||||
image = DoNotDisturb.isEnabled ? #imageLiteral(resourceName: "dnd-on") : #imageLiteral(resourceName: "dnd-off")
|
self.setImage(DoNotDisturb.isEnabled ? #imageLiteral(resourceName: "dnd-on") : #imageLiteral(resourceName: "dnd-off"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
27
MTMR/Widgets/EscapeBarItem.swift
Normal file
27
MTMR/Widgets/EscapeBarItem.swift
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
//
|
||||||
|
// EscapeBarItem.swift
|
||||||
|
// MTMR
|
||||||
|
//
|
||||||
|
// Created by Fedor Zaitsev on 4/27/20.
|
||||||
|
// Copyright © 2020 Anton Palgunov. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
class EscapeBarItem: CustomButtonTouchBarItem {
|
||||||
|
override class var typeIdentifier: String {
|
||||||
|
return "escape"
|
||||||
|
}
|
||||||
|
|
||||||
|
required init(from decoder: Decoder) throws {
|
||||||
|
try super.init(from: decoder)
|
||||||
|
|
||||||
|
self.title = "escape"
|
||||||
|
self.setTapAction(EventAction().setKeyPressClosure(keycode: 53))
|
||||||
|
self.align = .left
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder _: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
}
|
||||||
50
MTMR/Widgets/ExitTouchbarBarItem.swift
Normal file
50
MTMR/Widgets/ExitTouchbarBarItem.swift
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
//
|
||||||
|
// ExitTouchbarBarItem.swift
|
||||||
|
// MTMR
|
||||||
|
//
|
||||||
|
// Created by Fedor Zaitsev on 4/30/20.
|
||||||
|
// Copyright © 2020 Anton Palgunov. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
class ExitTouchbarBarItem: CustomButtonTouchBarItem {
|
||||||
|
private var timer: Timer!
|
||||||
|
|
||||||
|
override class var typeIdentifier: String {
|
||||||
|
return "exitTouchbar"
|
||||||
|
}
|
||||||
|
|
||||||
|
init(identifier: NSTouchBarItem.Identifier) {
|
||||||
|
super.init(identifier: identifier, title: "")
|
||||||
|
|
||||||
|
if self.title == "" {
|
||||||
|
self.title = "exit"
|
||||||
|
}
|
||||||
|
|
||||||
|
self.setTapAction(EventAction.init({_ in
|
||||||
|
|
||||||
|
TouchBarController.shared.dismissTouchBar()
|
||||||
|
|
||||||
|
} ))
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder _: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
required init(from decoder: Decoder) throws {
|
||||||
|
try super.init(from: decoder)
|
||||||
|
|
||||||
|
if self.title == "" {
|
||||||
|
self.title = "exit"
|
||||||
|
}
|
||||||
|
|
||||||
|
self.setTapAction(EventAction.init({_ in
|
||||||
|
|
||||||
|
TouchBarController.shared.dismissTouchBar()
|
||||||
|
|
||||||
|
} ))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -7,50 +7,96 @@
|
|||||||
//
|
//
|
||||||
import Cocoa
|
import Cocoa
|
||||||
|
|
||||||
class GroupBarItem: NSPopoverTouchBarItem, NSTouchBarDelegate {
|
|
||||||
var jsonItems: [BarItemDefinition]
|
class GroupBarItem: CustomTouchBarItem, NSTouchBarDelegate {
|
||||||
|
private(set) var popoverItem: NSPopoverTouchBarItem!
|
||||||
|
var jsonItems: [BarItemDefinition] = []
|
||||||
|
|
||||||
|
override class var typeIdentifier: String {
|
||||||
|
return "group"
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum CodingKeys: String, CodingKey {
|
||||||
|
case items
|
||||||
|
case title
|
||||||
|
}
|
||||||
|
|
||||||
var itemDefinitions: [NSTouchBarItem.Identifier: BarItemDefinition] = [:]
|
var itemDefinitions: [NSTouchBarItem.Identifier: BarItemDefinition] = [:]
|
||||||
var items: [NSTouchBarItem.Identifier: NSTouchBarItem] = [:]
|
var items: [CustomTouchBarItem] = []
|
||||||
var leftIdentifiers: [NSTouchBarItem.Identifier] = []
|
var leftIdentifiers: [NSTouchBarItem.Identifier] = []
|
||||||
var centerIdentifiers: [NSTouchBarItem.Identifier] = []
|
var centerIdentifiers: [NSTouchBarItem.Identifier] = []
|
||||||
var centerItems: [NSTouchBarItem] = []
|
var centerItems: [NSTouchBarItem] = []
|
||||||
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 swipeItems: [SwipeItem] = []
|
||||||
|
var centerScrollArea = NSTouchBarItem.Identifier("com.toxblh.mtmr.GroupScrollArea.".appending(UUID().uuidString))
|
||||||
|
var basicView: BasicView?
|
||||||
|
var basicViewIdentifier = NSTouchBarItem.Identifier("com.toxblh.mtmr.GroupScrollView.".appending(UUID().uuidString))
|
||||||
|
|
||||||
init(identifier: NSTouchBarItem.Identifier, items: [BarItemDefinition]) {
|
|
||||||
|
init(identifier: NSTouchBarItem.Identifier, items: [BarItemDefinition], title: String) {
|
||||||
jsonItems = items
|
jsonItems = items
|
||||||
|
popoverItem = NSPopoverTouchBarItem(identifier: identifier)
|
||||||
super.init(identifier: identifier)
|
super.init(identifier: identifier)
|
||||||
popoverTouchBar.delegate = self
|
|
||||||
|
self.setup(title: title)
|
||||||
}
|
}
|
||||||
|
|
||||||
required init?(coder _: NSCoder) {
|
required init?(coder _: NSCoder) {
|
||||||
fatalError("init(coder:) has not been implemented")
|
fatalError("init(coder:) has not been implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
deinit {}
|
required init(from decoder: Decoder) throws {
|
||||||
|
try super.init(from: decoder)
|
||||||
|
popoverItem = NSPopoverTouchBarItem(identifier: identifier)
|
||||||
|
|
||||||
@objc override func showPopover(_: Any?) {
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
itemDefinitions = [:]
|
self.jsonItems = try container.decode([BarItemDefinition].self, forKey: .items)
|
||||||
items = [:]
|
let title = try container.decodeIfPresent(String.self, forKey: .title) ?? " "
|
||||||
leftIdentifiers = []
|
|
||||||
centerItems = []
|
|
||||||
rightIdentifiers = []
|
|
||||||
|
|
||||||
loadItemDefinitions(jsonItems: jsonItems)
|
self.setup(title: title)
|
||||||
createItems()
|
}
|
||||||
|
|
||||||
centerItems = centerIdentifiers.compactMap({ (identifier) -> NSTouchBarItem? in
|
|
||||||
items[identifier]
|
func setup(title: String) {
|
||||||
|
let button = NSButton(title: title, target: self,
|
||||||
|
action: #selector(GroupBarItem.showPopover(_:)))
|
||||||
|
|
||||||
|
// Use the built-in gesture recognizer for tap and hold to open our popover's NSTouchBar.
|
||||||
|
let gestureRecognizer = popoverItem.makeStandardActivatePopoverGestureRecognizer()
|
||||||
|
button.addGestureRecognizer(gestureRecognizer)
|
||||||
|
|
||||||
|
popoverItem.collapsedRepresentation = button
|
||||||
|
|
||||||
|
view = button
|
||||||
|
|
||||||
|
if getWidth() == 0.0 {
|
||||||
|
setWidth(value: 60)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc func showPopover(_: Any?) {
|
||||||
|
items = getItems(newItems: jsonItems)
|
||||||
|
|
||||||
|
let leftItems = items.compactMap({ (item) -> CustomTouchBarItem? in
|
||||||
|
item.align == .left || item.align == .center ? item : nil
|
||||||
|
})
|
||||||
|
let centerItems = items.compactMap({ (item) -> CustomTouchBarItem? in
|
||||||
|
item.align == .center && false ? item : nil
|
||||||
|
})
|
||||||
|
let rightItems = items.compactMap({ (item) -> CustomTouchBarItem? in
|
||||||
|
item.align == .right ? item : nil
|
||||||
})
|
})
|
||||||
|
|
||||||
centerScrollArea = NSTouchBarItem.Identifier("com.toxblh.mtmr.scrollArea.".appending(UUID().uuidString))
|
let centerScrollArea = NSTouchBarItem.Identifier("com.toxblh.mtmr.scrollArea.".appending(UUID().uuidString))
|
||||||
scrollArea = ScrollViewItem(identifier: centerScrollArea, items: centerItems)
|
let scrollArea = ScrollViewItem(identifier: centerScrollArea, items: centerItems)
|
||||||
|
|
||||||
TouchBarController.shared.touchBar.delegate = self
|
TouchBarController.shared.touchBar.delegate = self
|
||||||
TouchBarController.shared.touchBar.defaultItemIdentifiers = []
|
TouchBarController.shared.touchBar.defaultItemIdentifiers = [basicViewIdentifier]
|
||||||
TouchBarController.shared.touchBar.defaultItemIdentifiers = leftIdentifiers + [centerScrollArea] + rightIdentifiers
|
|
||||||
|
basicView = BasicView(identifier: basicViewIdentifier, items: leftItems + [scrollArea] + rightItems, swipeItems: swipeItems)
|
||||||
|
basicView?.legacyGesturesEnabled = AppSettings.multitouchGestures
|
||||||
|
|
||||||
|
|
||||||
if AppSettings.showControlStripState {
|
if AppSettings.showControlStripState {
|
||||||
presentSystemModal(TouchBarController.shared.touchBar, systemTrayItemIdentifier: .controlStripItem)
|
presentSystemModal(TouchBarController.shared.touchBar, systemTrayItemIdentifier: .controlStripItem)
|
||||||
@ -60,41 +106,23 @@ class GroupBarItem: NSPopoverTouchBarItem, NSTouchBarDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func touchBar(_: NSTouchBar, makeItemForIdentifier identifier: NSTouchBarItem.Identifier) -> NSTouchBarItem? {
|
func touchBar(_: NSTouchBar, makeItemForIdentifier identifier: NSTouchBarItem.Identifier) -> NSTouchBarItem? {
|
||||||
if identifier == centerScrollArea {
|
if identifier == basicViewIdentifier {
|
||||||
return scrollArea
|
return basicView
|
||||||
}
|
}
|
||||||
|
|
||||||
guard let item = self.items[identifier],
|
return nil
|
||||||
let definition = self.itemDefinitions[identifier],
|
|
||||||
definition.align != .center else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return item
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadItemDefinitions(jsonItems: [BarItemDefinition]) {
|
func getItems(newItems: [BarItemDefinition]) -> [CustomTouchBarItem] {
|
||||||
let dateFormatter = DateFormatter()
|
var items: [CustomTouchBarItem] = []
|
||||||
dateFormatter.dateFormat = "HH-mm-ss"
|
for item in newItems {
|
||||||
let time = dateFormatter.string(from: Date())
|
if item.obj is SwipeItem {
|
||||||
for item in jsonItems {
|
swipeItems.append(item.obj as! SwipeItem)
|
||||||
let identifierString = item.type.identifierBase.appending(time + "--" + UUID().uuidString)
|
} else {
|
||||||
let identifier = NSTouchBarItem.Identifier(identifierString)
|
items.append(item.obj)
|
||||||
itemDefinitions[identifier] = item
|
|
||||||
if item.align == .left {
|
|
||||||
leftIdentifiers.append(identifier)
|
|
||||||
}
|
|
||||||
if item.align == .right {
|
|
||||||
rightIdentifiers.append(identifier)
|
|
||||||
}
|
|
||||||
if item.align == .center {
|
|
||||||
centerIdentifiers.append(identifier)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
return items
|
||||||
|
|
||||||
func createItems() {
|
|
||||||
for (identifier, definition) in itemDefinitions {
|
|
||||||
items[identifier] = TouchBarController.shared.createItem(forIdentifier: identifier, definition: definition)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
27
MTMR/Widgets/IlluminationDownBarItem.swift
Normal file
27
MTMR/Widgets/IlluminationDownBarItem.swift
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
//
|
||||||
|
// illuminationDownBarItem.swift
|
||||||
|
// MTMR
|
||||||
|
//
|
||||||
|
// Created by Fedor Zaitsev on 4/27/20.
|
||||||
|
// Copyright © 2020 Anton Palgunov. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
class IlluminationDownBarItem: CustomButtonTouchBarItem {
|
||||||
|
override class var typeIdentifier: String {
|
||||||
|
return "illuminationDown"
|
||||||
|
}
|
||||||
|
|
||||||
|
required init(from decoder: Decoder) throws {
|
||||||
|
try super.init(from: decoder)
|
||||||
|
|
||||||
|
self.setImage(#imageLiteral(resourceName: "ill_down"))
|
||||||
|
self.setTapAction(EventAction().setHidKeyClosure(keycode: NX_KEYTYPE_ILLUMINATION_DOWN))
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder _: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
27
MTMR/Widgets/IlluminationUpBarItem.swift
Normal file
27
MTMR/Widgets/IlluminationUpBarItem.swift
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
//
|
||||||
|
// illuminationUpBarItem.swift
|
||||||
|
// MTMR
|
||||||
|
//
|
||||||
|
// Created by Fedor Zaitsev on 4/27/20.
|
||||||
|
// Copyright © 2020 Anton Palgunov. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
class IlluminationUpBarItem: CustomButtonTouchBarItem {
|
||||||
|
override class var typeIdentifier: String {
|
||||||
|
return "illuminationUp"
|
||||||
|
}
|
||||||
|
|
||||||
|
required init(from decoder: Decoder) throws {
|
||||||
|
try super.init(from: decoder)
|
||||||
|
|
||||||
|
self.setImage(#imageLiteral(resourceName: "ill_up"))
|
||||||
|
self.setTapAction(EventAction().setHidKeyClosure(keycode: NX_KEYTYPE_ILLUMINATION_UP))
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder _: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ -12,21 +12,38 @@ 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)
|
||||||
|
|
||||||
|
override class var typeIdentifier: String {
|
||||||
|
return "inputsource"
|
||||||
|
}
|
||||||
|
|
||||||
init(identifier: NSTouchBarItem.Identifier) {
|
init(identifier: NSTouchBarItem.Identifier) {
|
||||||
notificationCenter = CFNotificationCenterGetDistributedCenter()
|
notificationCenter = CFNotificationCenterGetDistributedCenter()
|
||||||
super.init(identifier: identifier, title: "⏳")
|
super.init(identifier: identifier, title: "⏳")
|
||||||
|
|
||||||
observeIputSourceChangedNotification()
|
self.setup()
|
||||||
textInputSourceDidChange()
|
|
||||||
tapClosure = { [weak self] in
|
|
||||||
self?.switchInputSource()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
required init?(coder _: NSCoder) {
|
required init?(coder _: NSCoder) {
|
||||||
fatalError("init(coder:) has not been implemented")
|
fatalError("init(coder:) has not been implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
required init(from decoder: Decoder) throws {
|
||||||
|
notificationCenter = CFNotificationCenterGetDistributedCenter()
|
||||||
|
try super.init(from: decoder)
|
||||||
|
|
||||||
|
self.setup()
|
||||||
|
}
|
||||||
|
|
||||||
|
func setup() {
|
||||||
|
observeIputSourceChangedNotification()
|
||||||
|
textInputSourceDidChange()
|
||||||
|
self.setTapAction(
|
||||||
|
EventAction({ [weak self] (_ caller: CustomButtonTouchBarItem) in
|
||||||
|
self?.switchInputSource()
|
||||||
|
}
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
CFNotificationCenterRemoveEveryObserver(notificationCenter, UnsafeRawPointer(Unmanaged.passUnretained(self).toOpaque()))
|
CFNotificationCenterRemoveEveryObserver(notificationCenter, UnsafeRawPointer(Unmanaged.passUnretained(self).toOpaque()))
|
||||||
}
|
}
|
||||||
@ -45,7 +62,7 @@ class InputSourceBarItem: CustomButtonTouchBarItem {
|
|||||||
|
|
||||||
if let iconImage = iconImage {
|
if let iconImage = iconImage {
|
||||||
iconImage.size = buttonSize
|
iconImage.size = buttonSize
|
||||||
image = iconImage
|
self.setImage(iconImage)
|
||||||
title = ""
|
title = ""
|
||||||
} else {
|
} else {
|
||||||
title = currentSource.name
|
title = currentSource.name
|
||||||
|
|||||||
@ -34,16 +34,35 @@ class MusicBarItem: CustomButtonTouchBarItem {
|
|||||||
private var timer: Timer?
|
private var timer: Timer?
|
||||||
private let iconSize = NSSize(width: 21, height: 21)
|
private let iconSize = NSSize(width: 21, height: 21)
|
||||||
|
|
||||||
|
private enum CodingKeys: String, CodingKey {
|
||||||
|
case refreshInterval
|
||||||
|
case disableMarquee
|
||||||
|
}
|
||||||
|
|
||||||
|
override class var typeIdentifier: String {
|
||||||
|
return "music"
|
||||||
|
}
|
||||||
|
|
||||||
init(identifier: NSTouchBarItem.Identifier, interval: TimeInterval, disableMarquee: Bool) {
|
init(identifier: NSTouchBarItem.Identifier, interval: TimeInterval, disableMarquee: Bool) {
|
||||||
self.interval = interval
|
self.interval = interval
|
||||||
self.disableMarquee = disableMarquee
|
self.disableMarquee = disableMarquee
|
||||||
|
|
||||||
super.init(identifier: identifier, title: "⏳")
|
super.init(identifier: identifier, title: "⏳")
|
||||||
isBordered = false
|
|
||||||
|
|
||||||
tapClosure = { [weak self] in self?.playPause() }
|
self.setup()
|
||||||
longTapClosure = { [weak self] in self?.nextTrack() }
|
}
|
||||||
|
|
||||||
|
func setup() {
|
||||||
|
self.setTapAction(
|
||||||
|
EventAction({ [weak self] (_ caller: CustomButtonTouchBarItem) in
|
||||||
|
self?.playPause()
|
||||||
|
} )
|
||||||
|
)
|
||||||
|
self.setLongTapAction(
|
||||||
|
EventAction({ [weak self] (_ caller: CustomButtonTouchBarItem) in
|
||||||
|
self?.nextTrack()
|
||||||
|
} )
|
||||||
|
)
|
||||||
|
|
||||||
refreshAndSchedule()
|
refreshAndSchedule()
|
||||||
}
|
}
|
||||||
@ -61,10 +80,22 @@ class MusicBarItem: CustomButtonTouchBarItem {
|
|||||||
fatalError("init(coder:) has not been implemented")
|
fatalError("init(coder:) has not been implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
required init(from decoder: Decoder) throws {
|
||||||
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
|
self.interval = try container.decodeIfPresent(Double.self, forKey: .refreshInterval) ?? 5.0
|
||||||
|
self.disableMarquee = try container.decodeIfPresent(Bool.self, forKey: .disableMarquee) ?? false
|
||||||
|
|
||||||
|
try super.init(from: decoder)
|
||||||
|
self.setup()
|
||||||
|
}
|
||||||
|
|
||||||
@objc func playPause() {
|
@objc func playPause() {
|
||||||
for ident in playerBundleIdentifiers {
|
for ident in playerBundleIdentifiers {
|
||||||
|
print("checking \(ident)")
|
||||||
if let musicPlayer = SBApplication(bundleIdentifier: ident.rawValue) {
|
if let musicPlayer = SBApplication(bundleIdentifier: ident.rawValue) {
|
||||||
|
print("musicPlayer \(musicPlayer)")
|
||||||
if musicPlayer.isRunning {
|
if musicPlayer.isRunning {
|
||||||
|
print("musicPlayer.isRunning \(musicPlayer.isRunning)")
|
||||||
if ident == .Spotify {
|
if ident == .Spotify {
|
||||||
let mp = (musicPlayer as SpotifyApplication)
|
let mp = (musicPlayer as SpotifyApplication)
|
||||||
mp.playpause!()
|
mp.playpause!()
|
||||||
@ -194,6 +225,7 @@ class MusicBarItem: CustomButtonTouchBarItem {
|
|||||||
for ident in playerBundleIdentifiers {
|
for ident in playerBundleIdentifiers {
|
||||||
if let musicPlayer = SBApplication(bundleIdentifier: ident.rawValue) {
|
if let musicPlayer = SBApplication(bundleIdentifier: ident.rawValue) {
|
||||||
if musicPlayer.isRunning {
|
if musicPlayer.isRunning {
|
||||||
|
print("musicPlayer \(musicPlayer)")
|
||||||
var tempTitle = ""
|
var tempTitle = ""
|
||||||
if ident == .Spotify {
|
if ident == .Spotify {
|
||||||
tempTitle = (musicPlayer as SpotifyApplication).title
|
tempTitle = (musicPlayer as SpotifyApplication).title
|
||||||
@ -268,7 +300,7 @@ class MusicBarItem: CustomButtonTouchBarItem {
|
|||||||
let appPath = NSWorkspace.shared.absolutePathForApplication(withBundleIdentifier: ident.rawValue) {
|
let appPath = NSWorkspace.shared.absolutePathForApplication(withBundleIdentifier: ident.rawValue) {
|
||||||
let image = NSWorkspace.shared.icon(forFile: appPath)
|
let image = NSWorkspace.shared.icon(forFile: appPath)
|
||||||
image.size = self.iconSize
|
image.size = self.iconSize
|
||||||
self.image = image
|
self.setImage(image)
|
||||||
iconUpdated = true
|
iconUpdated = true
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
@ -278,7 +310,7 @@ class MusicBarItem: CustomButtonTouchBarItem {
|
|||||||
|
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
if !iconUpdated {
|
if !iconUpdated {
|
||||||
self.image = nil
|
self.setImage(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !titleUpdated {
|
if !titleUpdated {
|
||||||
|
|||||||
27
MTMR/Widgets/MuteBarItem.swift
Normal file
27
MTMR/Widgets/MuteBarItem.swift
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
//
|
||||||
|
// MuteBarItem.swift
|
||||||
|
// MTMR
|
||||||
|
//
|
||||||
|
// Created by Fedor Zaitsev on 4/27/20.
|
||||||
|
// Copyright © 2020 Anton Palgunov. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
class MuteBarItem: CustomButtonTouchBarItem {
|
||||||
|
override class var typeIdentifier: String {
|
||||||
|
return "mute"
|
||||||
|
}
|
||||||
|
|
||||||
|
required init(from decoder: Decoder) throws {
|
||||||
|
try super.init(from: decoder)
|
||||||
|
|
||||||
|
self.setImage(NSImage(named: NSImage.touchBarAudioOutputMuteTemplateName)!)
|
||||||
|
self.setTapAction(EventAction().setHidKeyClosure(keycode: NX_KEYTYPE_MUTE))
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder _: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ -8,12 +8,17 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
class NetworkBarItem: CustomButtonTouchBarItem, Widget {
|
class NetworkBarItem: CustomButtonTouchBarItem {
|
||||||
static var name: String = "network"
|
|
||||||
static var identifier: String = "com.toxblh.mtmr.network"
|
|
||||||
|
|
||||||
private let flip: Bool
|
private let flip: Bool
|
||||||
|
|
||||||
|
private enum CodingKeys: String, CodingKey {
|
||||||
|
case flip
|
||||||
|
}
|
||||||
|
|
||||||
|
override class var typeIdentifier: String {
|
||||||
|
return "network"
|
||||||
|
}
|
||||||
|
|
||||||
init(identifier: NSTouchBarItem.Identifier, flip: Bool = false) {
|
init(identifier: NSTouchBarItem.Identifier, flip: Bool = false) {
|
||||||
self.flip = flip
|
self.flip = flip
|
||||||
super.init(identifier: identifier, title: " ")
|
super.init(identifier: identifier, title: " ")
|
||||||
@ -24,6 +29,14 @@ class NetworkBarItem: CustomButtonTouchBarItem, Widget {
|
|||||||
fatalError("init(coder:) has not been implemented")
|
fatalError("init(coder:) has not been implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
required init(from decoder: Decoder) throws {
|
||||||
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
|
self.flip = try container.decodeIfPresent(Bool.self, forKey: .flip) ?? false
|
||||||
|
|
||||||
|
try super.init(from: decoder)
|
||||||
|
startMonitoringProcess()
|
||||||
|
}
|
||||||
|
|
||||||
func startMonitoringProcess() {
|
func startMonitoringProcess() {
|
||||||
var pipe: Pipe
|
var pipe: Pipe
|
||||||
var outputHandle: FileHandle
|
var outputHandle: FileHandle
|
||||||
@ -144,6 +157,6 @@ class NetworkBarItem: CustomButtonTouchBarItem, Widget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
self.attributedTitle = newTitle
|
self.setAttributedTitle(newTitle)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
27
MTMR/Widgets/NextBarItem.swift
Normal file
27
MTMR/Widgets/NextBarItem.swift
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
//
|
||||||
|
// NextBarItem.swift
|
||||||
|
// MTMR
|
||||||
|
//
|
||||||
|
// Created by Fedor Zaitsev on 4/27/20.
|
||||||
|
// Copyright © 2020 Anton Palgunov. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
class NextBarItem: CustomButtonTouchBarItem {
|
||||||
|
override class var typeIdentifier: String {
|
||||||
|
return "next"
|
||||||
|
}
|
||||||
|
|
||||||
|
required init(from decoder: Decoder) throws {
|
||||||
|
try super.init(from: decoder)
|
||||||
|
|
||||||
|
self.setImage(NSImage(named: NSImage.touchBarFastForwardTemplateName)!)
|
||||||
|
self.setTapAction(EventAction().setHidKeyClosure(keycode: NX_KEYTYPE_NEXT))
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder _: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ -12,6 +12,10 @@ class NightShiftBarItem: CustomButtonTouchBarItem {
|
|||||||
private let nsclient = CBBlueLightClient()
|
private let nsclient = CBBlueLightClient()
|
||||||
private var timer: Timer!
|
private var timer: Timer!
|
||||||
|
|
||||||
|
override class var typeIdentifier: String {
|
||||||
|
return "nightShift"
|
||||||
|
}
|
||||||
|
|
||||||
private var blueLightStatus: Status {
|
private var blueLightStatus: Status {
|
||||||
var status: Status = Status()
|
var status: Status = Status()
|
||||||
nsclient.getBlueLightStatus(&status)
|
nsclient.getBlueLightStatus(&status)
|
||||||
@ -28,26 +32,40 @@ class NightShiftBarItem: CustomButtonTouchBarItem {
|
|||||||
|
|
||||||
init(identifier: NSTouchBarItem.Identifier) {
|
init(identifier: NSTouchBarItem.Identifier) {
|
||||||
super.init(identifier: identifier, title: "")
|
super.init(identifier: identifier, title: "")
|
||||||
isBordered = false
|
self.setup()
|
||||||
setWidth(value: 28)
|
|
||||||
|
|
||||||
tapClosure = { [weak self] in self?.nightShiftAction() }
|
|
||||||
|
|
||||||
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(refresh), userInfo: nil, repeats: true)
|
|
||||||
|
|
||||||
refresh()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
required init?(coder _: NSCoder) {
|
required init?(coder _: NSCoder) {
|
||||||
fatalError("init(coder:) has not been implemented")
|
fatalError("init(coder:) has not been implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
required init(from decoder: Decoder) throws {
|
||||||
|
try super.init(from: decoder)
|
||||||
|
self.setup()
|
||||||
|
}
|
||||||
|
|
||||||
|
func setup() {
|
||||||
|
if getWidth() == 0.0 {
|
||||||
|
setWidth(value: 28)
|
||||||
|
}
|
||||||
|
|
||||||
|
self.setTapAction(
|
||||||
|
EventAction( { [weak self] (_ caller: CustomButtonTouchBarItem) in
|
||||||
|
self?.nightShiftAction()
|
||||||
|
} )
|
||||||
|
)
|
||||||
|
|
||||||
|
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(refresh), userInfo: nil, repeats: true)
|
||||||
|
|
||||||
|
refresh()
|
||||||
|
}
|
||||||
|
|
||||||
func nightShiftAction() {
|
func nightShiftAction() {
|
||||||
setNightShift(state: !isNightShiftEnabled)
|
setNightShift(state: !isNightShiftEnabled)
|
||||||
refresh()
|
refresh()
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func refresh() {
|
@objc func refresh() {
|
||||||
image = isNightShiftEnabled ? #imageLiteral(resourceName: "nightShiftOn") : #imageLiteral(resourceName: "nightShiftOff")
|
self.setImage(isNightShiftEnabled ? #imageLiteral(resourceName: "nightShiftOn") : #imageLiteral(resourceName: "nightShiftOff"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
27
MTMR/Widgets/PlayBarItem.swift
Normal file
27
MTMR/Widgets/PlayBarItem.swift
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
//
|
||||||
|
// PlayBarItem.swift
|
||||||
|
// MTMR
|
||||||
|
//
|
||||||
|
// Created by Fedor Zaitsev on 4/27/20.
|
||||||
|
// Copyright © 2020 Anton Palgunov. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
class PlayBarItem: CustomButtonTouchBarItem {
|
||||||
|
override class var typeIdentifier: String {
|
||||||
|
return "play"
|
||||||
|
}
|
||||||
|
|
||||||
|
required init(from decoder: Decoder) throws {
|
||||||
|
try super.init(from: decoder)
|
||||||
|
|
||||||
|
self.setImage(NSImage(named: NSImage.touchBarPlayPauseTemplateName)!)
|
||||||
|
self.setTapAction(EventAction().setHidKeyClosure(keycode: NX_KEYTYPE_PLAY))
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder _: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ -8,25 +8,14 @@
|
|||||||
|
|
||||||
import Cocoa
|
import Cocoa
|
||||||
|
|
||||||
class PomodoroBarItem: CustomButtonTouchBarItem, Widget {
|
class PomodoroBarItem: CustomButtonTouchBarItem {
|
||||||
static let identifier = "com.toxblh.mtmr.pomodoro."
|
override class var typeIdentifier: String {
|
||||||
static let name = "pomodoro"
|
return "pomodoro"
|
||||||
static let decoder: ParametersDecoder = { decoder in
|
}
|
||||||
enum CodingKeys: String, CodingKey {
|
|
||||||
case workTime
|
|
||||||
case restTime
|
|
||||||
}
|
|
||||||
|
|
||||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
private enum CodingKeys: String, CodingKey {
|
||||||
let workTime = try container.decodeIfPresent(Double.self, forKey: .workTime)
|
case workTime
|
||||||
let restTime = try container.decodeIfPresent(Double.self, forKey: .restTime)
|
case restTime
|
||||||
|
|
||||||
return (
|
|
||||||
item: .pomodoro(workTime: workTime ?? 1500.00, restTime: restTime ?? 300),
|
|
||||||
action: .none,
|
|
||||||
longAction: .none,
|
|
||||||
parameters: [:]
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum TimeTypes {
|
private enum TimeTypes {
|
||||||
@ -46,18 +35,44 @@ class PomodoroBarItem: CustomButtonTouchBarItem, Widget {
|
|||||||
return String(format: "%.2i:%.2i", timeLeft / 60, timeLeft % 60)
|
return String(format: "%.2i:%.2i", timeLeft / 60, timeLeft % 60)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
init(identifier: NSTouchBarItem.Identifier, workTime: TimeInterval, restTime: TimeInterval) {
|
init(identifier: NSTouchBarItem.Identifier, workTime: TimeInterval, restTime: TimeInterval) {
|
||||||
self.workTime = workTime
|
self.workTime = workTime
|
||||||
self.restTime = restTime
|
self.restTime = restTime
|
||||||
super.init(identifier: identifier, title: defaultTitle)
|
super.init(identifier: identifier, title: defaultTitle)
|
||||||
tapClosure = { [weak self] in self?.startStopWork() }
|
|
||||||
longTapClosure = { [weak self] in self?.startStopRest() }
|
self.setup()
|
||||||
}
|
}
|
||||||
|
|
||||||
required init?(coder _: NSCoder) {
|
required init?(coder _: NSCoder) {
|
||||||
fatalError("init(coder:) has not been implemented")
|
fatalError("init(coder:) has not been implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
required init(from decoder: Decoder) throws {
|
||||||
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
|
|
||||||
|
self.workTime = try container.decodeIfPresent(Double.self, forKey: .workTime) ?? 1500.0
|
||||||
|
self.restTime = try container.decodeIfPresent(Double.self, forKey: .restTime) ?? 600.0
|
||||||
|
|
||||||
|
try super.init(from: decoder)
|
||||||
|
self.title = defaultTitle
|
||||||
|
|
||||||
|
self.setup()
|
||||||
|
}
|
||||||
|
|
||||||
|
func setup() {
|
||||||
|
self.setTapAction(
|
||||||
|
EventAction({ [weak self] (_ caller: CustomButtonTouchBarItem) in
|
||||||
|
self?.startStopWork()
|
||||||
|
} )
|
||||||
|
)
|
||||||
|
self.setLongTapAction(
|
||||||
|
EventAction({ [weak self] (_ caller: CustomButtonTouchBarItem) in
|
||||||
|
self?.startStopRest()
|
||||||
|
} )
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
timer?.cancel()
|
timer?.cancel()
|
||||||
timer = nil
|
timer = nil
|
||||||
|
|||||||
27
MTMR/Widgets/PreviousBarItem.swift
Normal file
27
MTMR/Widgets/PreviousBarItem.swift
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
//
|
||||||
|
// PreviousBarItem.swift
|
||||||
|
// MTMR
|
||||||
|
//
|
||||||
|
// Created by Fedor Zaitsev on 4/27/20.
|
||||||
|
// Copyright © 2020 Anton Palgunov. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
class PreviousBarItem: CustomButtonTouchBarItem {
|
||||||
|
override class var typeIdentifier: String {
|
||||||
|
return "previous"
|
||||||
|
}
|
||||||
|
|
||||||
|
required init(from decoder: Decoder) throws {
|
||||||
|
try super.init(from: decoder)
|
||||||
|
|
||||||
|
self.setImage(NSImage(named: NSImage.touchBarRewindTemplateName)!)
|
||||||
|
self.setTapAction(EventAction().setHidKeyClosure(keycode: NX_KEYTYPE_PREVIOUS))
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder _: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
27
MTMR/Widgets/SleepBarItem.swift
Normal file
27
MTMR/Widgets/SleepBarItem.swift
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
//
|
||||||
|
// SleepBarItem.swift
|
||||||
|
// MTMR
|
||||||
|
//
|
||||||
|
// Created by Fedor Zaitsev on 4/27/20.
|
||||||
|
// Copyright © 2020 Anton Palgunov. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
class SleepBarItem: CustomButtonTouchBarItem {
|
||||||
|
override class var typeIdentifier: String {
|
||||||
|
return "sleep"
|
||||||
|
}
|
||||||
|
|
||||||
|
required init(from decoder: Decoder) throws {
|
||||||
|
try super.init(from: decoder)
|
||||||
|
|
||||||
|
self.title = "☕️"
|
||||||
|
self.setTapAction(EventAction().setShellScriptClosure(executable: "/usr/bin/pmset", parameters: ["sleepnow"]))
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder _: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ -4,7 +4,40 @@ class TimeTouchBarItem: CustomButtonTouchBarItem {
|
|||||||
private let dateFormatter = DateFormatter()
|
private let dateFormatter = DateFormatter()
|
||||||
private var timer: Timer!
|
private var timer: Timer!
|
||||||
|
|
||||||
|
private enum CodingKeys: String, CodingKey {
|
||||||
|
case formatTemplate
|
||||||
|
case timeZone
|
||||||
|
case locale
|
||||||
|
}
|
||||||
|
|
||||||
|
override class var typeIdentifier: String {
|
||||||
|
return "timeButton"
|
||||||
|
}
|
||||||
|
|
||||||
init(identifier: NSTouchBarItem.Identifier, formatTemplate: String, timeZone: String? = nil, locale: String? = nil) {
|
init(identifier: NSTouchBarItem.Identifier, formatTemplate: String, timeZone: String? = nil, locale: String? = nil) {
|
||||||
|
super.init(identifier: identifier, title: " ")
|
||||||
|
self.setupFormatter(formatTemplate: formatTemplate, timeZone: timeZone, locale: locale)
|
||||||
|
self.setupTimer()
|
||||||
|
updateTime()
|
||||||
|
}
|
||||||
|
|
||||||
|
required init(from decoder: Decoder) throws {
|
||||||
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
|
let template = try container.decodeIfPresent(String.self, forKey: .formatTemplate) ?? "HH:mm"
|
||||||
|
let timeZone = try container.decodeIfPresent(String.self, forKey: .timeZone) ?? nil
|
||||||
|
let locale = try container.decodeIfPresent(String.self, forKey: .locale) ?? nil
|
||||||
|
|
||||||
|
try super.init(from: decoder)
|
||||||
|
self.setupFormatter(formatTemplate: template, timeZone: timeZone, locale: locale)
|
||||||
|
self.setupTimer()
|
||||||
|
updateTime()
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder _: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func setupFormatter(formatTemplate: String, timeZone: String? = nil, locale: String? = nil) {
|
||||||
dateFormatter.dateFormat = formatTemplate
|
dateFormatter.dateFormat = formatTemplate
|
||||||
if let locale = locale {
|
if let locale = locale {
|
||||||
dateFormatter.locale = Locale(identifier: locale)
|
dateFormatter.locale = Locale(identifier: locale)
|
||||||
@ -12,14 +45,10 @@ class TimeTouchBarItem: CustomButtonTouchBarItem {
|
|||||||
if let abbr = timeZone {
|
if let abbr = timeZone {
|
||||||
dateFormatter.timeZone = TimeZone(abbreviation: abbr)
|
dateFormatter.timeZone = TimeZone(abbreviation: abbr)
|
||||||
}
|
}
|
||||||
super.init(identifier: identifier, title: " ")
|
|
||||||
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(updateTime), userInfo: nil, repeats: true)
|
|
||||||
isBordered = false
|
|
||||||
updateTime()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
required init?(coder _: NSCoder) {
|
func setupTimer() {
|
||||||
fatalError("init(coder:) has not been implemented")
|
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(updateTime), userInfo: nil, repeats: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func updateTime() {
|
@objc func updateTime() {
|
||||||
|
|||||||
27
MTMR/Widgets/VolumeDownBarItem.swift
Normal file
27
MTMR/Widgets/VolumeDownBarItem.swift
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
//
|
||||||
|
// volumeDownBarItem.swift
|
||||||
|
// MTMR
|
||||||
|
//
|
||||||
|
// Created by Fedor Zaitsev on 4/27/20.
|
||||||
|
// Copyright © 2020 Anton Palgunov. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
class VolumeDownBarItem: CustomButtonTouchBarItem {
|
||||||
|
override class var typeIdentifier: String {
|
||||||
|
return "volumeDown"
|
||||||
|
}
|
||||||
|
|
||||||
|
required init(from decoder: Decoder) throws {
|
||||||
|
try super.init(from: decoder)
|
||||||
|
|
||||||
|
self.setImage(NSImage(named: NSImage.touchBarVolumeDownTemplateName)!)
|
||||||
|
self.setTapAction(EventAction().setHidKeyClosure(keycode: NX_KEYTYPE_SOUND_DOWN))
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder _: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
27
MTMR/Widgets/VolumeUpBarItem.swift
Normal file
27
MTMR/Widgets/VolumeUpBarItem.swift
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
//
|
||||||
|
// VolumeUpBarItem.swift
|
||||||
|
// MTMR
|
||||||
|
//
|
||||||
|
// Created by Fedor Zaitsev on 4/27/20.
|
||||||
|
// Copyright © 2020 Anton Palgunov. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
class VolumeUpBarItem: CustomButtonTouchBarItem {
|
||||||
|
override class var typeIdentifier: String {
|
||||||
|
return "volumeUp"
|
||||||
|
}
|
||||||
|
|
||||||
|
required init(from decoder: Decoder) throws {
|
||||||
|
try super.init(from: decoder)
|
||||||
|
|
||||||
|
self.setImage(NSImage(named: NSImage.touchBarVolumeUpTemplateName)!)
|
||||||
|
self.setTapAction(EventAction().setHidKeyClosure(keycode: NX_KEYTYPE_SOUND_UP))
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder _: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ -3,12 +3,33 @@ import AVFoundation
|
|||||||
import Cocoa
|
import Cocoa
|
||||||
import CoreAudio
|
import CoreAudio
|
||||||
|
|
||||||
class VolumeViewController: NSCustomTouchBarItem {
|
class VolumeViewController: CustomTouchBarItem {
|
||||||
private(set) var sliderItem: CustomSlider!
|
private(set) var sliderItem: CustomSlider!
|
||||||
|
|
||||||
|
override class var typeIdentifier: String {
|
||||||
|
return "volume"
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum CodingKeys: String, CodingKey {
|
||||||
|
case image
|
||||||
|
}
|
||||||
|
|
||||||
init(identifier: NSTouchBarItem.Identifier, image: NSImage? = nil) {
|
init(identifier: NSTouchBarItem.Identifier, image: NSImage? = nil) {
|
||||||
super.init(identifier: identifier)
|
super.init(identifier: identifier)
|
||||||
|
|
||||||
|
self.setup(image: image)
|
||||||
|
}
|
||||||
|
|
||||||
|
required init(from decoder: Decoder) throws {
|
||||||
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
|
let image = try container.decodeIfPresent(Source.self, forKey: .image)?.image
|
||||||
|
|
||||||
|
try super.init(from: decoder)
|
||||||
|
|
||||||
|
self.setup(image: image)
|
||||||
|
}
|
||||||
|
|
||||||
|
func setup(image: NSImage?) {
|
||||||
var forPropertyAddress = AudioObjectPropertyAddress(
|
var forPropertyAddress = AudioObjectPropertyAddress(
|
||||||
mSelector: kAudioHardwareServiceDeviceProperty_VirtualMasterVolume,
|
mSelector: kAudioHardwareServiceDeviceProperty_VirtualMasterVolume,
|
||||||
mScope: kAudioDevicePropertyScopeOutput,
|
mScope: kAudioDevicePropertyScopeOutput,
|
||||||
@ -37,6 +58,7 @@ class VolumeViewController: NSCustomTouchBarItem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
required init?(coder _: NSCoder) {
|
required init?(coder _: NSCoder) {
|
||||||
fatalError("init(coder:) has not been implemented")
|
fatalError("init(coder:) has not been implemented")
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,9 +22,20 @@ class WeatherBarItem: CustomButtonTouchBarItem, CLLocationManagerDelegate {
|
|||||||
|
|
||||||
private var manager: CLLocationManager!
|
private var manager: CLLocationManager!
|
||||||
|
|
||||||
|
override class var typeIdentifier: String {
|
||||||
|
return "weather"
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum CodingKeys: String, CodingKey {
|
||||||
|
case refreshInterval
|
||||||
|
case units
|
||||||
|
case api_key
|
||||||
|
case icon_type
|
||||||
|
}
|
||||||
|
|
||||||
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")
|
self.activity = NSBackgroundActivityScheduler(identifier: "\(identifier.rawValue).updatecheck")
|
||||||
activity.interval = interval
|
self.activity.interval = interval
|
||||||
self.units = units
|
self.units = units
|
||||||
self.api_key = api_key
|
self.api_key = api_key
|
||||||
|
|
||||||
@ -44,6 +55,43 @@ class WeatherBarItem: CustomButtonTouchBarItem, CLLocationManagerDelegate {
|
|||||||
|
|
||||||
super.init(identifier: identifier, title: "⏳")
|
super.init(identifier: identifier, title: "⏳")
|
||||||
|
|
||||||
|
self.setup()
|
||||||
|
}
|
||||||
|
|
||||||
|
required init(from decoder: Decoder) throws {
|
||||||
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
|
let icon_type = try container.decodeIfPresent(String.self, forKey: .icon_type) ?? "text"
|
||||||
|
|
||||||
|
|
||||||
|
self.activity = NSBackgroundActivityScheduler(identifier: CustomTouchBarItem.createIdentifier("Weather.updatecheck").rawValue)
|
||||||
|
self.activity.interval = try container.decodeIfPresent(Double.self, forKey: .refreshInterval) ?? 1800.0
|
||||||
|
self.units = try container.decodeIfPresent(String.self, forKey: .units) ?? "metric"
|
||||||
|
self.api_key = try container.decodeIfPresent(String.self, forKey: .api_key) ?? "32c4256d09a4c52b38aecddba7a078f6"
|
||||||
|
|
||||||
|
if self.units == "metric" {
|
||||||
|
units_str = "°C"
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.units == "imperial" {
|
||||||
|
units_str = "°F"
|
||||||
|
}
|
||||||
|
|
||||||
|
if icon_type == "images" {
|
||||||
|
iconsSource = iconsImages
|
||||||
|
} else {
|
||||||
|
iconsSource = iconsText
|
||||||
|
}
|
||||||
|
|
||||||
|
try super.init(from: decoder)
|
||||||
|
|
||||||
|
self.setup()
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder _: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func setup() {
|
||||||
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")
|
||||||
@ -69,10 +117,6 @@ class WeatherBarItem: CustomButtonTouchBarItem, CLLocationManagerDelegate {
|
|||||||
manager.startUpdatingLocation()
|
manager.startUpdatingLocation()
|
||||||
}
|
}
|
||||||
|
|
||||||
required init?(coder _: NSCoder) {
|
|
||||||
fatalError("init(coder:) has not been implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc func updateWeather() {
|
@objc func updateWeather() {
|
||||||
if 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=\(units)&appid=\(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)")!)
|
||||||
|
|||||||
@ -20,12 +20,37 @@ class YandexWeatherBarItem: CustomButtonTouchBarItem, CLLocationManagerDelegate
|
|||||||
private var prevLocation: CLLocation!
|
private var prevLocation: CLLocation!
|
||||||
private var manager: CLLocationManager!
|
private var manager: CLLocationManager!
|
||||||
|
|
||||||
|
override class var typeIdentifier: String {
|
||||||
|
return "weather"
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum CodingKeys: String, CodingKey {
|
||||||
|
case refreshInterval
|
||||||
|
}
|
||||||
|
|
||||||
init(identifier: NSTouchBarItem.Identifier, interval: TimeInterval) {
|
init(identifier: NSTouchBarItem.Identifier, interval: TimeInterval) {
|
||||||
activity = NSBackgroundActivityScheduler(identifier: "\(identifier.rawValue).updatecheck")
|
activity = NSBackgroundActivityScheduler(identifier: "\(identifier.rawValue).updatecheck")
|
||||||
activity.interval = interval
|
activity.interval = interval
|
||||||
|
|
||||||
super.init(identifier: identifier, title: "⏳")
|
super.init(identifier: identifier, title: "⏳")
|
||||||
|
self.setup()
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder _: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
required init(from decoder: Decoder) throws {
|
||||||
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
|
|
||||||
|
self.activity = NSBackgroundActivityScheduler(identifier: CustomTouchBarItem.createIdentifier("YandexWeather.updatecheck").rawValue)
|
||||||
|
self.activity.interval = try container.decodeIfPresent(Double.self, forKey: .refreshInterval) ?? 1800.0
|
||||||
|
|
||||||
|
try super.init(from: decoder)
|
||||||
|
self.setup()
|
||||||
|
}
|
||||||
|
|
||||||
|
func setup() {
|
||||||
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")
|
||||||
@ -50,11 +75,12 @@ class YandexWeatherBarItem: CustomButtonTouchBarItem, CLLocationManagerDelegate
|
|||||||
manager.desiredAccuracy = kCLLocationAccuracyHundredMeters
|
manager.desiredAccuracy = kCLLocationAccuracyHundredMeters
|
||||||
manager.startUpdatingLocation()
|
manager.startUpdatingLocation()
|
||||||
|
|
||||||
tapClosure = tapClosure ?? defaultTapAction
|
|
||||||
}
|
|
||||||
|
|
||||||
required init?(coder _: NSCoder) {
|
self.setTapAction(
|
||||||
fatalError("init(coder:) has not been implemented")
|
EventAction({ [weak self] (_ caller: CustomButtonTouchBarItem) in
|
||||||
|
self?.defaultTapAction()
|
||||||
|
} )
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func updateWeather() {
|
@objc func updateWeather() {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user