diff --git a/MTMR/AppleScriptTouchBarItem.swift b/MTMR/AppleScriptTouchBarItem.swift
index 1ee67a7..f61cbad 100644
--- a/MTMR/AppleScriptTouchBarItem.swift
+++ b/MTMR/AppleScriptTouchBarItem.swift
@@ -5,11 +5,43 @@ class AppleScriptTouchBarItem: CustomButtonTouchBarItem {
private let interval: TimeInterval
private var forceHideConstraint: NSLayoutConstraint!
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]) {
self.interval = interval
self.alternativeImages = alternativeImages
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)
title = "scheduled"
DispatchQueue.appleScriptQueue.async {
@@ -38,10 +70,6 @@ class AppleScriptTouchBarItem: CustomButtonTouchBarItem {
}
}
- required init?(coder _: NSCoder) {
- fatalError("init(coder:) has not been implemented")
- }
-
func refreshAndSchedule() {
#if DEBUG
print("refresh happened (interval \(interval)), self \(identifier.rawValue))")
@@ -62,7 +90,7 @@ class AppleScriptTouchBarItem: CustomButtonTouchBarItem {
func updateIcon(iconLabel: String) {
if alternativeImages[iconLabel] != nil {
DispatchQueue.main.async {
- self.image = self.alternativeImages[iconLabel]!.image
+ self.setImage(self.alternativeImages[iconLabel]!.image)
}
} else {
print("Cannot find icon with label \"\(iconLabel)\"")
diff --git a/MTMR/BasicView.swift b/MTMR/BasicView.swift
index 5d388cb..3b04e33 100644
--- a/MTMR/BasicView.swift
+++ b/MTMR/BasicView.swift
@@ -15,6 +15,7 @@ class BasicView: NSCustomTouchBarItem, NSGestureRecognizerDelegate {
var threefingers: NSPanGestureRecognizer!
var fourfingers: NSPanGestureRecognizer!
var swipeItems: [SwipeItem] = []
+ var items: [NSTouchBarItem] = []
var prevPositions: [Int: CGFloat] = [2:0, 3:0, 4:0]
// legacy gesture positions
@@ -25,6 +26,7 @@ class BasicView: NSCustomTouchBarItem, NSGestureRecognizerDelegate {
init(identifier: NSTouchBarItem.Identifier, items: [NSTouchBarItem], swipeItems: [SwipeItem]) {
super.init(identifier: identifier)
self.swipeItems = swipeItems
+ self.items = items
let views = items.compactMap { $0.view }
let stackView = NSStackView(views: views)
stackView.spacing = 1
diff --git a/MTMR/CustomButtonTouchBarItem.swift b/MTMR/CustomButtonTouchBarItem.swift
index 6b734d2..6dd9b82 100644
--- a/MTMR/CustomButtonTouchBarItem.swift
+++ b/MTMR/CustomButtonTouchBarItem.swift
@@ -8,24 +8,130 @@
import Cocoa
-class CustomButtonTouchBarItem: NSCustomTouchBarItem, NSGestureRecognizerDelegate {
- var tapClosure: (() -> Void)?
- var longTapClosure: (() -> Void)? {
- didSet {
- longClick.isEnabled = longTapClosure != nil
+enum Align: String, Decodable {
+ case left
+ case center
+ case right
+}
+
+// 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: ()->() = {}
+ 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 singleClick: HapticClickGestureRecognizer!
private var longClick: LongPressGestureRecognizer!
+ private var attributedTitle: NSAttributedString
init(identifier: NSTouchBarItem.Identifier, title: String) {
attributedTitle = title.defaultTouchbarAttributedString
super.init(identifier: identifier)
+
+ initButton(title: title, imageSource: nil)
+ }
+
+ func initButton(title: String, imageSource: Source?) {
button = CustomHeightButton(title: title, target: nil, action: nil)
+ self.setImage(imageSource?.image)
longClick = LongPressGestureRecognizer(target: self, action: #selector(handleGestureLong))
longClick.isEnabled = false
@@ -33,6 +139,7 @@ class CustomButtonTouchBarItem: NSCustomTouchBarItem, NSGestureRecognizerDelegat
longClick.delegate = self
singleClick = HapticClickGestureRecognizer(target: self, action: #selector(handleGestureSingle))
+ singleClick.isEnabled = false
singleClick.allowedTouchTypes = .direct
singleClick.delegate = self
@@ -40,6 +147,45 @@ class CustomButtonTouchBarItem: NSCustomTouchBarItem, NSGestureRecognizerDelegat
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) {
fatalError("init(coder:) has not been implemented")
}
@@ -58,27 +204,35 @@ class CustomButtonTouchBarItem: NSCustomTouchBarItem, NSGestureRecognizerDelegat
var title: String {
get {
- return attributedTitle.string
+ return getAttributedTitle().string
}
set {
- attributedTitle = newValue.defaultTouchbarAttributedString
+ setAttributedTitle(newValue.defaultTouchbarAttributedString)
}
}
-
- var attributedTitle: NSAttributedString {
- didSet {
- button?.imagePosition = attributedTitle.length > 0 ? .imageLeading : .imageOnly
- button?.attributedTitle = attributedTitle
- }
+
+ func getAttributedTitle() -> NSAttributedString {
+ return attributedTitle
+ }
+
+ func setAttributedTitle(_ attributedTitle: NSAttributedString) {
+ self.attributedTitle = attributedTitle
+ button?.imagePosition = attributedTitle.length > 0 ? .imageLeading : .imageOnly
+ button?.attributedTitle = attributedTitle
+ }
+
+ private var image: NSImage?
+
+ func getImage() -> NSImage? {
+ return image
+ }
+
+ func setImage(_ image: NSImage?) {
+ self.image = image
+ button.image = image
}
- var image: NSImage? {
- didSet {
- button.image = image
- }
- }
-
- private func reinstallButton() {
+ func reinstallButton() {
let title = button.attributedTitle
let image = button.image
let cell = CustomButtonCell(parentItem: self)
@@ -116,7 +270,7 @@ class CustomButtonTouchBarItem: NSCustomTouchBarItem, NSGestureRecognizerDelegat
@objc func handleGestureSingle(gr: NSClickGestureRecognizer) {
switch gr.state {
case .ended:
- tapClosure?()
+ self.tapAction?.closure(self)
break
default:
break
@@ -126,7 +280,7 @@ class CustomButtonTouchBarItem: NSCustomTouchBarItem, NSGestureRecognizerDelegat
@objc func handleGestureLong(gr: NSPressGestureRecognizer) {
switch gr.state {
case .possible: // tiny hack because we're calling action manually
- (self.longTapClosure ?? self.tapClosure)?()
+ (self.longTapAction?.closure ?? self.tapAction?.closure)?(self)
break
default:
break
@@ -156,7 +310,7 @@ class CustomButtonCell: NSButtonCell {
if flag {
setAttributedTitle(attributedTitle, withColor: .lightGray)
} else if let parentItem = self.parentItem {
- attributedTitle = parentItem.attributedTitle
+ attributedTitle = parentItem.getAttributedTitle()
}
}
}
diff --git a/MTMR/EventActions.swift b/MTMR/EventActions.swift
new file mode 100644
index 0000000..77cb5e5
--- /dev/null
+++ b/MTMR/EventActions.swift
@@ -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
+ }
+ }
+}
diff --git a/MTMR/Info.plist b/MTMR/Info.plist
index ae0a326..2afd22d 100644
--- a/MTMR/Info.plist
+++ b/MTMR/Info.plist
@@ -19,7 +19,7 @@
CFBundleShortVersionString
0.25
CFBundleVersion
- 402
+ 622
LSApplicationCategoryType
public.app-category.utilities
LSMinimumSystemVersion
diff --git a/MTMR/ItemsParsing.swift b/MTMR/ItemsParsing.swift
index 851cf15..9f347c8 100644
--- a/MTMR/ItemsParsing.swift
+++ b/MTMR/ItemsParsing.swift
@@ -3,550 +3,90 @@ import Foundation
extension Data {
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 {
- let type: ItemType
- let action: ActionType
- let longAction: LongActionType
- let additionalParameters: [GeneralParameters.CodingKeys: GeneralParameter]
+ let obj: CustomTouchBarItem
+
+ enum ParsingErrors: Error {
+ case noMatchingType(description: String)
+ }
private enum CodingKeys: String, CodingKey {
- case type
+ case objtype = "type"
}
-
- init(type: ItemType, action: ActionType, longAction: LongActionType, additionalParameters: [GeneralParameters.CodingKeys: GeneralParameter]) {
- self.type = type
- self.action = action
- self.longAction = longAction
- self.additionalParameters = additionalParameters
- }
-
- init(from decoder: Decoder) throws {
- let container = try decoder.container(keyedBy: CodingKeys.self)
- let type = try container.decode(String.self, forKey: .type)
- let parametersDecoder = SupportedTypesHolder.sharedInstance.lookup(by: type)
- 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 -> (
- item: ItemType,
- action: ActionType,
- longAction: LongActionType,
- parameters: [GeneralParameters.CodingKeys: GeneralParameter]
-)
-
-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 (
- item: .staticButton(title: "del"),
- action: .keyPress(keycode: 117),
- longAction: .none,
- parameters: [:]
- ) },
-
- "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: [:]
- ) },
-
+
+ static let types: [CustomTouchBarItem.Type] = [
+
+ // custom buttons
+ CustomButtonTouchBarItem.self,
+ AppleScriptTouchBarItem.self,
+ ShellScriptTouchBarItem.self,
+
+
+ // basic widget buttons
+ EscapeBarItem.self,
+ DeleteBarItem.self,
+ BrightnessUpBarItem.self,
+ BrightnessDownBarItem.self,
+ IlluminationUpBarItem.self,
+ IlluminationDownBarItem.self,
+ VolumeUpBarItem.self,
+ VolumeDownBarItem.self,
+ MuteBarItem.self,
+ PreviousBarItem.self,
+ PlayBarItem.self,
+ NextBarItem.self,
+ SleepBarItem.self,
+ DisplaySleepBarItem.self,
+
+
+ // custom widgets
+ TimeTouchBarItem.self,
+ BatteryBarItem.self,
+ AppScrubberTouchBarItem.self,
+ VolumeViewController.self,
+ BrightnessViewController.self,
+ WeatherBarItem.self,
+ YandexWeatherBarItem.self,
+ CurrencyBarItem.self,
+ InputSourceBarItem.self,
+ MusicBarItem.self,
+ NightShiftBarItem.self,
+ DnDBarItem.self,
+ PomodoroBarItem.self,
+ NetworkBarItem.self,
+ DarkModeBarItem.self,
+
+
+ // custom-custom objects!
+ SwipeItem.self,
+ GroupBarItem.self,
+ ExitTouchbarBarItem.self,
+ CloseBarItem.self,
]
- static let sharedInstance = SupportedTypesHolder()
-
- 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(obj: CustomTouchBarItem) {
+ self.obj = obj
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
- let type = try container.decode(ItemTypeRaw.self, forKey: .type)
- 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:
- let title = try container.decode(String.self, forKey: .title)
- self = .staticButton(title: title)
-
- 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)
+ let objType = try container.decode(String.self, forKey: .objtype)
+
+
+ for obj in BarItemDefinition.types {
+ if obj.typeIdentifier == objType {
+ self.obj = try obj.init(from: decoder)
+ return
+ }
}
- }
-}
-
-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
- result[.align] = .align(align)
-
- 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
+
+
+ print("Cannot find preset mapping for \(objType)")
+ throw ParsingErrors.noMatchingType(description: "Cannot find preset mapping for \(objType)")
}
}
@@ -646,12 +186,6 @@ extension Data {
}
}
-enum Align: String, Decodable {
- case left
- case center
- case right
-}
-
extension URL {
var appleScript: NSAppleScript? {
guard FileManager.default.fileExists(atPath: path) else { return nil }
diff --git a/MTMR/ShellScriptTouchBarItem.swift b/MTMR/ShellScriptTouchBarItem.swift
index 94d51ec..098a3fb 100644
--- a/MTMR/ShellScriptTouchBarItem.swift
+++ b/MTMR/ShellScriptTouchBarItem.swift
@@ -12,11 +12,40 @@ class ShellScriptTouchBarItem: CustomButtonTouchBarItem {
private let source: String
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) {
self.interval = interval
self.source = source.string ?? "echo No \"source\""
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)
DispatchQueue.shellScriptQueue.async {
@@ -24,10 +53,6 @@ class ShellScriptTouchBarItem: CustomButtonTouchBarItem {
}
}
- required init?(coder _: NSCoder) {
- fatalError("init(coder:) has not been implemented")
- }
-
func refreshAndSchedule() {
// Execute script and get result
let scriptResult = execute(source)
@@ -45,7 +70,7 @@ class ShellScriptTouchBarItem: CustomButtonTouchBarItem {
if (newBackgoundColor != self?.backgroundColor) { // performance optimization because of reinstallButton
self?.backgroundColor = newBackgoundColor
}
- self?.attributedTitle = title
+ self?.setAttributedTitle(title)
self?.forceHideConstraint.isActive = scriptResult == ""
}
diff --git a/MTMR/SwipeItem.swift b/MTMR/SwipeItem.swift
index baf7949..399b102 100644
--- a/MTMR/SwipeItem.swift
+++ b/MTMR/SwipeItem.swift
@@ -9,12 +9,25 @@
import Foundation
import Foundation
-class SwipeItem: NSCustomTouchBarItem {
+class SwipeItem: CustomTouchBarItem {
private var scriptApple: NSAppleScript?
private var scriptBash: String?
private var direction: String
private var fingers: Int
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?) {
self.direction = direction
self.fingers = fingers
@@ -28,6 +41,19 @@ class SwipeItem: NSCustomTouchBarItem {
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) {
if direction == "right" && Float(offset) > self.minOffset && self.fingers == fingers {
self.execute()
diff --git a/MTMR/TouchBarController.swift b/MTMR/TouchBarController.swift
index 9bf1a78..1ec6f74 100644
--- a/MTMR/TouchBarController.swift
+++ b/MTMR/TouchBarController.swift
@@ -16,52 +16,6 @@ struct ExactItem {
let appSupportDirectory = NSSearchPathForDirectoriesInDomains(.applicationSupportDirectory, .userDomainMask, true).first!.appending("/MTMR")
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 {
static let controlStripItem = NSTouchBarItem.Identifier("com.toxblh.mtmr.controlStrip")
@@ -73,12 +27,7 @@ class TouchBarController: NSObject, NSTouchBarDelegate {
var touchBar: NSTouchBar!
fileprivate var lastPresetPath = ""
- var jsonItems: [BarItemDefinition] = []
- var itemDefinitions: [NSTouchBarItem.Identifier: BarItemDefinition] = [:]
- var items: [NSTouchBarItem.Identifier: NSTouchBarItem] = [:]
- var leftIdentifiers: [NSTouchBarItem.Identifier] = []
- var centerIdentifiers: [NSTouchBarItem.Identifier] = []
- var rightIdentifiers: [NSTouchBarItem.Identifier] = []
+ var items: [CustomTouchBarItem] = []
var basicViewIdentifier = NSTouchBarItem.Identifier("com.toxblh.mtmr.scrollView.".appending(UUID().uuidString))
var basicView: BasicView?
var swipeItems: [SwipeItem] = []
@@ -90,14 +39,6 @@ class TouchBarController: NSObject, NSTouchBarDelegate {
private override 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
@@ -108,21 +49,23 @@ class TouchBarController: NSObject, NSTouchBarDelegate {
reloadStandardConfig()
}
- func createAndUpdatePreset(newJsonItems: [BarItemDefinition]) {
+ func createAndUpdatePreset(newItems: [BarItemDefinition]) {
if let oldBar = self.touchBar {
minimizeSystemModal(oldBar)
}
touchBar = NSTouchBar()
- jsonItems = newJsonItems
- itemDefinitions = [:]
- items = [:]
+ (items, swipeItems) = getItems(newItems: newItems)
- loadItemDefinitions(jsonItems: jsonItems)
- createItems()
-
- let centerItems = centerIdentifiers.compactMap({ (identifier) -> NSTouchBarItem? in
- items[identifier]
+ let leftItems = items.compactMap({ (item) -> CustomTouchBarItem? in
+ item.align == .left ? item : nil
})
+ 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 scrollArea = ScrollViewItem(identifier: centerScrollArea, items: centerItems)
@@ -130,15 +73,17 @@ class TouchBarController: NSObject, NSTouchBarDelegate {
touchBar.delegate = self
touchBar.defaultItemIdentifiers = [basicViewIdentifier]
- let leftItems = leftIdentifiers.compactMap({ (identifier) -> NSTouchBarItem? in
- items[identifier]
- })
- let rightItems = rightIdentifiers.compactMap({ (identifier) -> NSTouchBarItem? in
- items[identifier]
- })
-
- basicView = BasicView(identifier: basicViewIdentifier, items:leftItems + [scrollArea] + rightItems, swipeItems: swipeItems)
+ basicView = BasicView(identifier: basicViewIdentifier, items: leftItems + [scrollArea] + rightItems, swipeItems: swipeItems)
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()
}
@@ -166,41 +111,26 @@ class TouchBarController: NSObject, NSTouchBarDelegate {
reloadPreset(path: presetPath)
}
- func reloadPreset(path: String) {
- lastPresetPath = path
- let items = path.fileData?.barItemDefinitions() ?? [BarItemDefinition(type: .staticButton(title: "bad preset"), action: .none, longAction: .none, additionalParameters: [:])]
- 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)
- }
+ func reloadPreset(path: String?) {
+ if path != nil {
+ lastPresetPath = path!
}
+
+ let items = lastPresetPath.fileData?.barItemDefinitions() ?? [BarItemDefinition(obj: CustomButtonTouchBarItem(title: "bad preset"))]
+ createAndUpdatePreset(newItems: items)
}
- func createItems() {
- for (identifier, definition) in itemDefinitions {
- let item = createItem(forIdentifier: identifier, definition: definition)
- if item is SwipeItem {
- swipeItems.append(item as! SwipeItem)
+ func getItems(newItems: [BarItemDefinition]) -> ([CustomTouchBarItem], [SwipeItem]) {
+ var items: [CustomTouchBarItem] = []
+ var swipeItems: [SwipeItem] = []
+ for item in newItems {
+ if item.obj is SwipeItem {
+ swipeItems.append(item.obj as! SwipeItem)
} else {
- items[identifier] = item
+ items.append(item.obj)
}
}
+ return (items, swipeItems)
}
@objc func setupControlStripPresence() {
@@ -224,7 +154,7 @@ class TouchBarController: NSObject, NSTouchBarDelegate {
}
}
- @objc private func dismissTouchBar() {
+ @objc func dismissTouchBar() {
minimizeSystemModal(touchBar)
updateControlStripPresence()
}
@@ -241,198 +171,8 @@ class TouchBarController: NSObject, NSTouchBarDelegate {
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 {
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
- }
-}
diff --git a/MTMR/Widgets/AppScrubberTouchBarItem.swift b/MTMR/Widgets/AppScrubberTouchBarItem.swift
index adc5541..bc3002e 100644
--- a/MTMR/Widgets/AppScrubberTouchBarItem.swift
+++ b/MTMR/Widgets/AppScrubberTouchBarItem.swift
@@ -7,7 +7,7 @@
import Cocoa
-class AppScrubberTouchBarItem: NSCustomTouchBarItem {
+class AppScrubberTouchBarItem: CustomTouchBarItem {
private var scrollView = NSScrollView()
private var autoResize: Bool = false
private var widthConstraint: NSLayoutConstraint?
@@ -19,6 +19,20 @@ class AppScrubberTouchBarItem: NSCustomTouchBarItem {
private var frontmostApplicationIdentifier: String? {
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 items: [DockBarItem] = []
@@ -29,6 +43,35 @@ class AppScrubberTouchBarItem: NSCustomTouchBarItem {
self.autoResize = autoResize
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.didTerminateApplicationNotification, object: nil)
NSWorkspace.shared.notificationCenter.addObserver(self, selector: #selector(softReloadItems), name: NSWorkspace.didActivateApplicationNotification, object: nil)
@@ -36,10 +79,7 @@ class AppScrubberTouchBarItem: NSCustomTouchBarItem {
persistentAppIdentifiers = AppSettings.dockPersistentAppIds
hardReloadItems()
}
-
- required init?(coder _: NSCoder) {
- fatalError("init(coder:) has not been implemented")
- }
+
@objc func hardReloadItems() {
applications = launchedApplications()
@@ -82,12 +122,17 @@ class AppScrubberTouchBarItem: NSCustomTouchBarItem {
public func createAppButton(for app: DockItem) -> DockBarItem {
let item = DockBarItem(app)
item.isBordered = false
- item.tapClosure = { [weak self] in
- self?.switchToApp(app: app)
- }
- item.longTapClosure = { [weak self] in
- self?.handleHalfLongPress(item: app)
- }
+
+ item.setTapAction(
+ EventAction({ [weak self] (_ caller: CustomButtonTouchBarItem) in
+ self?.switchToApp(app: app)
+ } )
+ )
+ item.setLongTapAction(
+ EventAction({ [weak self] (_ caller: CustomButtonTouchBarItem) in
+ self?.handleHalfLongPress(item: app)
+ } )
+ )
item.killAppClosure = {[weak self] in
self?.handleLongPress(item: app)
}
@@ -212,8 +257,8 @@ class DockBarItem: CustomButtonTouchBarItem {
super.init(identifier: .init(app.bundleIdentifier), title: "")
dotView.wantsLayer = true
- image = app.icon
- image?.size = NSSize(width: iconWidth, height: iconWidth)
+ self.setImage(app.icon)
+ self.getImage()?.size = NSSize(width: iconWidth, height: iconWidth)
killGestureRecognizer = LongPressGestureRecognizer(target: self, action: #selector(firePanGestureRecognizer))
killGestureRecognizer.allowedTouchTypes = .direct
@@ -243,4 +288,8 @@ class DockBarItem: CustomButtonTouchBarItem {
required init?(coder _: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
+
+ required init(from decoder: Decoder) {
+ fatalError("init(from decoder:) has not been implemented")
+ }
}
diff --git a/MTMR/Widgets/BatteryBarItem.swift b/MTMR/Widgets/BatteryBarItem.swift
index 377c86b..ca590d7 100644
--- a/MTMR/Widgets/BatteryBarItem.swift
+++ b/MTMR/Widgets/BatteryBarItem.swift
@@ -12,21 +12,35 @@ import IOKit.ps
class BatteryBarItem: CustomButtonTouchBarItem {
private let batteryInfo = BatteryInfo()
+ override class var typeIdentifier: String {
+ return "battery"
+ }
+
init(identifier: NSTouchBarItem.Identifier) {
super.init(identifier: identifier, title: " ")
+ self.setup()
+ }
+
+ required init?(coder _: NSCoder) {
+ 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()
}
- required init?(coder _: NSCoder) {
- fatalError("init(coder:) has not been implemented")
- }
-
func refresh() {
- attributedTitle = batteryInfo.formattedInfo()
+ setAttributedTitle(batteryInfo.formattedInfo())
}
deinit {
diff --git a/MTMR/Widgets/BrightnessDownBarItem.swift b/MTMR/Widgets/BrightnessDownBarItem.swift
new file mode 100644
index 0000000..1575f43
--- /dev/null
+++ b/MTMR/Widgets/BrightnessDownBarItem.swift
@@ -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")
+ }
+}
+
diff --git a/MTMR/Widgets/BrightnessUpBarItem.swift b/MTMR/Widgets/BrightnessUpBarItem.swift
new file mode 100644
index 0000000..7738ac9
--- /dev/null
+++ b/MTMR/Widgets/BrightnessUpBarItem.swift
@@ -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")
+ }
+}
+
diff --git a/MTMR/Widgets/BrightnessViewController.swift b/MTMR/Widgets/BrightnessViewController.swift
index ac83201..0f592bc 100644
--- a/MTMR/Widgets/BrightnessViewController.swift
+++ b/MTMR/Widgets/BrightnessViewController.swift
@@ -3,12 +3,39 @@ import AVFoundation
import Cocoa
import CoreAudio
-class BrightnessViewController: NSCustomTouchBarItem {
+class BrightnessViewController: CustomTouchBarItem {
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) {
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 {
sliderItem = CustomSlider()
} else {
@@ -22,14 +49,10 @@ class BrightnessViewController: NSCustomTouchBarItem {
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)
}
- required init?(coder _: NSCoder) {
- fatalError("init(coder:) has not been implemented")
- }
-
deinit {
sliderItem.unbind(NSBindingName.value)
}
diff --git a/MTMR/Widgets/CloseBarItem.swift b/MTMR/Widgets/CloseBarItem.swift
new file mode 100644
index 0000000..a30e062
--- /dev/null
+++ b/MTMR/Widgets/CloseBarItem.swift
@@ -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)
+
+ } ))
+ }
+
+}
diff --git a/MTMR/Widgets/CurrencyBarItem.swift b/MTMR/Widgets/CurrencyBarItem.swift
index 71e5599..f8047aa 100644
--- a/MTMR/Widgets/CurrencyBarItem.swift
+++ b/MTMR/Widgets/CurrencyBarItem.swift
@@ -58,6 +58,18 @@ class CurrencyBarItem: CustomButtonTouchBarItem {
"LTC": 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) {
activity = NSBackgroundActivityScheduler(identifier: "\(identifier.rawValue).updatecheck")
@@ -87,7 +99,51 @@ class CurrencyBarItem: CustomButtonTouchBarItem {
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.qualityOfService = .utility
activity.schedule { (completion: NSBackgroundActivityScheduler.CompletionHandler) in
@@ -97,10 +153,6 @@ class CurrencyBarItem: CustomButtonTouchBarItem {
updateCurrency()
}
- required init?(coder _: NSCoder) {
- fatalError("init(coder:) has not been implemented")
- }
-
@objc func updateCurrency() {
let urlRequest = URLRequest(url: URL(string: "https://api.coinbase.com/v2/exchange-rates?currency=\(from)")!)
@@ -153,10 +205,10 @@ class CurrencyBarItem: CustomButtonTouchBarItem {
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])
newTitle.setAlignment(.center, range: NSRange(location: 0, length: title.count))
- attributedTitle = newTitle
+ setAttributedTitle(newTitle)
}
deinit {
diff --git a/MTMR/Widgets/DarkModeBarItem.swift b/MTMR/Widgets/DarkModeBarItem.swift
index ceaba78..7beedbd 100644
--- a/MTMR/Widgets/DarkModeBarItem.swift
+++ b/MTMR/Widgets/DarkModeBarItem.swift
@@ -1,26 +1,43 @@
import Foundation
-class DarkModeBarItem: CustomButtonTouchBarItem, Widget {
- static var name: String = "darkmode"
- static var identifier: String = "com.toxblh.mtmr.darkmode"
-
+class DarkModeBarItem: CustomButtonTouchBarItem {
private var timer: Timer!
+
+ override class var typeIdentifier: String {
+ return "darkMode"
+ }
init(identifier: NSTouchBarItem.Identifier) {
super.init(identifier: identifier, title: "")
- isBordered = false
- setWidth(value: 24)
-
- tapClosure = { [weak self] in self?.DarkModeToggle() }
-
- timer = Timer.scheduledTimer(timeInterval: 3, target: self, selector: #selector(refresh), userInfo: nil, repeats: true)
-
- refresh()
+
+ self.setup()
}
required init?(coder _: NSCoder) {
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() {
DarkMode.isEnabled = !DarkMode.isEnabled
@@ -28,7 +45,7 @@ class DarkModeBarItem: CustomButtonTouchBarItem, Widget {
}
@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"))
}
}
diff --git a/MTMR/Widgets/DeleteBarItem.swift b/MTMR/Widgets/DeleteBarItem.swift
new file mode 100644
index 0000000..0ff3030
--- /dev/null
+++ b/MTMR/Widgets/DeleteBarItem.swift
@@ -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")
+ }
+}
diff --git a/MTMR/Widgets/DisplaySleepBarItem.swift b/MTMR/Widgets/DisplaySleepBarItem.swift
new file mode 100644
index 0000000..f7b7c8a
--- /dev/null
+++ b/MTMR/Widgets/DisplaySleepBarItem.swift
@@ -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")
+ }
+}
+
diff --git a/MTMR/Widgets/DnDBarItem.swift b/MTMR/Widgets/DnDBarItem.swift
index 18344ca..4c6f150 100644
--- a/MTMR/Widgets/DnDBarItem.swift
+++ b/MTMR/Widgets/DnDBarItem.swift
@@ -11,21 +11,39 @@ import Foundation
class DnDBarItem: CustomButtonTouchBarItem {
private var timer: Timer!
+ override class var typeIdentifier: String {
+ return "dnd"
+ }
+
init(identifier: NSTouchBarItem.Identifier) {
super.init(identifier: identifier, title: "")
- isBordered = false
- setWidth(value: 32)
-
- tapClosure = { [weak self] in self?.DnDToggle() }
-
- timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(refresh), userInfo: nil, repeats: true)
-
- refresh()
+ self.setup()
}
required init?(coder _: NSCoder) {
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() {
DoNotDisturb.isEnabled = !DoNotDisturb.isEnabled
@@ -33,7 +51,7 @@ class DnDBarItem: CustomButtonTouchBarItem {
}
@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"))
}
}
diff --git a/MTMR/Widgets/EscapeBarItem.swift b/MTMR/Widgets/EscapeBarItem.swift
new file mode 100644
index 0000000..3d6c364
--- /dev/null
+++ b/MTMR/Widgets/EscapeBarItem.swift
@@ -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")
+ }
+}
diff --git a/MTMR/Widgets/ExitTouchbarBarItem.swift b/MTMR/Widgets/ExitTouchbarBarItem.swift
new file mode 100644
index 0000000..f54412d
--- /dev/null
+++ b/MTMR/Widgets/ExitTouchbarBarItem.swift
@@ -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()
+
+ } ))
+ }
+
+}
diff --git a/MTMR/Widgets/GroupBarItem.swift b/MTMR/Widgets/GroupBarItem.swift
index b7ed226..0e732c2 100644
--- a/MTMR/Widgets/GroupBarItem.swift
+++ b/MTMR/Widgets/GroupBarItem.swift
@@ -7,50 +7,96 @@
//
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 items: [NSTouchBarItem.Identifier: NSTouchBarItem] = [:]
+ var items: [CustomTouchBarItem] = []
var leftIdentifiers: [NSTouchBarItem.Identifier] = []
var centerIdentifiers: [NSTouchBarItem.Identifier] = []
var centerItems: [NSTouchBarItem] = []
var rightIdentifiers: [NSTouchBarItem.Identifier] = []
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
+ popoverItem = NSPopoverTouchBarItem(identifier: identifier)
super.init(identifier: identifier)
- popoverTouchBar.delegate = self
+
+ self.setup(title: title)
}
required init?(coder _: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
+
+ required init(from decoder: Decoder) throws {
+ try super.init(from: decoder)
+ popoverItem = NSPopoverTouchBarItem(identifier: identifier)
+
+ let container = try decoder.container(keyedBy: CodingKeys.self)
+ self.jsonItems = try container.decode([BarItemDefinition].self, forKey: .items)
+ let title = try container.decodeIfPresent(String.self, forKey: .title) ?? " "
+
+ self.setup(title: title)
+ }
+
+
+ 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
- deinit {}
+ if getWidth() == 0.0 {
+ setWidth(value: 60)
+ }
+ }
- @objc override func showPopover(_: Any?) {
- itemDefinitions = [:]
- items = [:]
- leftIdentifiers = []
- centerItems = []
- rightIdentifiers = []
-
- loadItemDefinitions(jsonItems: jsonItems)
- createItems()
-
- centerItems = centerIdentifiers.compactMap({ (identifier) -> NSTouchBarItem? in
- items[identifier]
+ @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))
- scrollArea = ScrollViewItem(identifier: centerScrollArea, items: centerItems)
-
+ let centerScrollArea = NSTouchBarItem.Identifier("com.toxblh.mtmr.scrollArea.".appending(UUID().uuidString))
+ let scrollArea = ScrollViewItem(identifier: centerScrollArea, items: centerItems)
+
TouchBarController.shared.touchBar.delegate = self
- TouchBarController.shared.touchBar.defaultItemIdentifiers = []
- TouchBarController.shared.touchBar.defaultItemIdentifiers = leftIdentifiers + [centerScrollArea] + rightIdentifiers
+ TouchBarController.shared.touchBar.defaultItemIdentifiers = [basicViewIdentifier]
+
+ basicView = BasicView(identifier: basicViewIdentifier, items: leftItems + [scrollArea] + rightItems, swipeItems: swipeItems)
+ basicView?.legacyGesturesEnabled = AppSettings.multitouchGestures
+
if AppSettings.showControlStripState {
presentSystemModal(TouchBarController.shared.touchBar, systemTrayItemIdentifier: .controlStripItem)
@@ -60,41 +106,23 @@ class GroupBarItem: NSPopoverTouchBarItem, NSTouchBarDelegate {
}
func touchBar(_: NSTouchBar, makeItemForIdentifier identifier: NSTouchBarItem.Identifier) -> NSTouchBarItem? {
- if identifier == centerScrollArea {
- return scrollArea
+ if identifier == basicViewIdentifier {
+ return basicView
}
- guard let item = self.items[identifier],
- let definition = self.itemDefinitions[identifier],
- definition.align != .center else {
- return nil
- }
- return item
+ return nil
}
-
- 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)
+
+ func getItems(newItems: [BarItemDefinition]) -> [CustomTouchBarItem] {
+ var items: [CustomTouchBarItem] = []
+ for item in newItems {
+ if item.obj is SwipeItem {
+ swipeItems.append(item.obj as! SwipeItem)
+ } else {
+ items.append(item.obj)
}
}
- }
-
- func createItems() {
- for (identifier, definition) in itemDefinitions {
- items[identifier] = TouchBarController.shared.createItem(forIdentifier: identifier, definition: definition)
- }
+ return items
}
}
+
diff --git a/MTMR/Widgets/IlluminationDownBarItem.swift b/MTMR/Widgets/IlluminationDownBarItem.swift
new file mode 100644
index 0000000..a9b7099
--- /dev/null
+++ b/MTMR/Widgets/IlluminationDownBarItem.swift
@@ -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")
+ }
+}
+
diff --git a/MTMR/Widgets/IlluminationUpBarItem.swift b/MTMR/Widgets/IlluminationUpBarItem.swift
new file mode 100644
index 0000000..0abaa1b
--- /dev/null
+++ b/MTMR/Widgets/IlluminationUpBarItem.swift
@@ -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")
+ }
+}
+
diff --git a/MTMR/Widgets/InputSourceBarItem.swift b/MTMR/Widgets/InputSourceBarItem.swift
index 6e8b15b..6fcc66e 100644
--- a/MTMR/Widgets/InputSourceBarItem.swift
+++ b/MTMR/Widgets/InputSourceBarItem.swift
@@ -11,22 +11,39 @@ import Cocoa
class InputSourceBarItem: CustomButtonTouchBarItem {
fileprivate var notificationCenter: CFNotificationCenter
let buttonSize = NSSize(width: 21, height: 21)
+
+ override class var typeIdentifier: String {
+ return "inputsource"
+ }
init(identifier: NSTouchBarItem.Identifier) {
notificationCenter = CFNotificationCenterGetDistributedCenter()
super.init(identifier: identifier, title: "⏳")
-
- observeIputSourceChangedNotification()
- textInputSourceDidChange()
- tapClosure = { [weak self] in
- self?.switchInputSource()
- }
+
+ self.setup()
}
required init?(coder _: NSCoder) {
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 {
CFNotificationCenterRemoveEveryObserver(notificationCenter, UnsafeRawPointer(Unmanaged.passUnretained(self).toOpaque()))
}
@@ -45,7 +62,7 @@ class InputSourceBarItem: CustomButtonTouchBarItem {
if let iconImage = iconImage {
iconImage.size = buttonSize
- image = iconImage
+ self.setImage(iconImage)
title = ""
} else {
title = currentSource.name
diff --git a/MTMR/Widgets/MusicBarItem.swift b/MTMR/Widgets/MusicBarItem.swift
index 23b2029..b5bde38 100644
--- a/MTMR/Widgets/MusicBarItem.swift
+++ b/MTMR/Widgets/MusicBarItem.swift
@@ -33,17 +33,36 @@ class MusicBarItem: CustomButtonTouchBarItem {
private var songTitle: String?
private var timer: Timer?
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) {
self.interval = interval
self.disableMarquee = disableMarquee
super.init(identifier: identifier, title: "⏳")
- isBordered = false
- tapClosure = { [weak self] in self?.playPause() }
- longTapClosure = { [weak self] in self?.nextTrack() }
+ self.setup()
+ }
+
+ func setup() {
+ self.setTapAction(
+ EventAction({ [weak self] (_ caller: CustomButtonTouchBarItem) in
+ self?.playPause()
+ } )
+ )
+ self.setLongTapAction(
+ EventAction({ [weak self] (_ caller: CustomButtonTouchBarItem) in
+ self?.nextTrack()
+ } )
+ )
refreshAndSchedule()
}
@@ -60,11 +79,23 @@ class MusicBarItem: CustomButtonTouchBarItem {
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.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() {
for ident in playerBundleIdentifiers {
+ print("checking \(ident)")
if let musicPlayer = SBApplication(bundleIdentifier: ident.rawValue) {
+ print("musicPlayer \(musicPlayer)")
if musicPlayer.isRunning {
+ print("musicPlayer.isRunning \(musicPlayer.isRunning)")
if ident == .Spotify {
let mp = (musicPlayer as SpotifyApplication)
mp.playpause!()
@@ -194,6 +225,7 @@ class MusicBarItem: CustomButtonTouchBarItem {
for ident in playerBundleIdentifiers {
if let musicPlayer = SBApplication(bundleIdentifier: ident.rawValue) {
if musicPlayer.isRunning {
+ print("musicPlayer \(musicPlayer)")
var tempTitle = ""
if ident == .Spotify {
tempTitle = (musicPlayer as SpotifyApplication).title
@@ -268,7 +300,7 @@ class MusicBarItem: CustomButtonTouchBarItem {
let appPath = NSWorkspace.shared.absolutePathForApplication(withBundleIdentifier: ident.rawValue) {
let image = NSWorkspace.shared.icon(forFile: appPath)
image.size = self.iconSize
- self.image = image
+ self.setImage(image)
iconUpdated = true
}
break
@@ -278,7 +310,7 @@ class MusicBarItem: CustomButtonTouchBarItem {
DispatchQueue.main.async {
if !iconUpdated {
- self.image = nil
+ self.setImage(nil)
}
if !titleUpdated {
diff --git a/MTMR/Widgets/MuteBarItem.swift b/MTMR/Widgets/MuteBarItem.swift
new file mode 100644
index 0000000..b8594bd
--- /dev/null
+++ b/MTMR/Widgets/MuteBarItem.swift
@@ -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")
+ }
+}
+
diff --git a/MTMR/Widgets/NetworkBarItem.swift b/MTMR/Widgets/NetworkBarItem.swift
index 57de0bf..3056933 100644
--- a/MTMR/Widgets/NetworkBarItem.swift
+++ b/MTMR/Widgets/NetworkBarItem.swift
@@ -8,12 +8,17 @@
import Foundation
-class NetworkBarItem: CustomButtonTouchBarItem, Widget {
- static var name: String = "network"
- static var identifier: String = "com.toxblh.mtmr.network"
-
+class NetworkBarItem: CustomButtonTouchBarItem {
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) {
self.flip = flip
super.init(identifier: identifier, title: " ")
@@ -23,6 +28,14 @@ class NetworkBarItem: CustomButtonTouchBarItem, Widget {
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.flip = try container.decodeIfPresent(Bool.self, forKey: .flip) ?? false
+
+ try super.init(from: decoder)
+ startMonitoringProcess()
+ }
func startMonitoringProcess() {
var pipe: Pipe
@@ -144,6 +157,6 @@ class NetworkBarItem: CustomButtonTouchBarItem, Widget {
}
- self.attributedTitle = newTitle
+ self.setAttributedTitle(newTitle)
}
}
diff --git a/MTMR/Widgets/NextBarItem.swift b/MTMR/Widgets/NextBarItem.swift
new file mode 100644
index 0000000..797d30c
--- /dev/null
+++ b/MTMR/Widgets/NextBarItem.swift
@@ -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")
+ }
+}
+
diff --git a/MTMR/Widgets/NightShiftBarItem.swift b/MTMR/Widgets/NightShiftBarItem.swift
index 517a8e7..a3347a9 100644
--- a/MTMR/Widgets/NightShiftBarItem.swift
+++ b/MTMR/Widgets/NightShiftBarItem.swift
@@ -11,6 +11,10 @@ import Foundation
class NightShiftBarItem: CustomButtonTouchBarItem {
private let nsclient = CBBlueLightClient()
private var timer: Timer!
+
+ override class var typeIdentifier: String {
+ return "nightShift"
+ }
private var blueLightStatus: Status {
var status: Status = Status()
@@ -28,19 +32,33 @@ class NightShiftBarItem: CustomButtonTouchBarItem {
init(identifier: NSTouchBarItem.Identifier) {
super.init(identifier: identifier, title: "")
- isBordered = false
- setWidth(value: 28)
-
- tapClosure = { [weak self] in self?.nightShiftAction() }
-
- timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(refresh), userInfo: nil, repeats: true)
-
- refresh()
+ self.setup()
}
required init?(coder _: NSCoder) {
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() {
setNightShift(state: !isNightShiftEnabled)
@@ -48,6 +66,6 @@ class NightShiftBarItem: CustomButtonTouchBarItem {
}
@objc func refresh() {
- image = isNightShiftEnabled ? #imageLiteral(resourceName: "nightShiftOn") : #imageLiteral(resourceName: "nightShiftOff")
+ self.setImage(isNightShiftEnabled ? #imageLiteral(resourceName: "nightShiftOn") : #imageLiteral(resourceName: "nightShiftOff"))
}
}
diff --git a/MTMR/Widgets/PlayBarItem.swift b/MTMR/Widgets/PlayBarItem.swift
new file mode 100644
index 0000000..7143115
--- /dev/null
+++ b/MTMR/Widgets/PlayBarItem.swift
@@ -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")
+ }
+}
+
diff --git a/MTMR/Widgets/PomodoroBarItem.swift b/MTMR/Widgets/PomodoroBarItem.swift
index 7e081f7..2557f61 100644
--- a/MTMR/Widgets/PomodoroBarItem.swift
+++ b/MTMR/Widgets/PomodoroBarItem.swift
@@ -8,25 +8,14 @@
import Cocoa
-class PomodoroBarItem: CustomButtonTouchBarItem, Widget {
- static let identifier = "com.toxblh.mtmr.pomodoro."
- static let name = "pomodoro"
- static let decoder: ParametersDecoder = { decoder in
- enum CodingKeys: String, CodingKey {
- case workTime
- case restTime
- }
-
- let container = try decoder.container(keyedBy: CodingKeys.self)
- let workTime = try container.decodeIfPresent(Double.self, forKey: .workTime)
- let restTime = try container.decodeIfPresent(Double.self, forKey: .restTime)
-
- return (
- item: .pomodoro(workTime: workTime ?? 1500.00, restTime: restTime ?? 300),
- action: .none,
- longAction: .none,
- parameters: [:]
- )
+class PomodoroBarItem: CustomButtonTouchBarItem {
+ override class var typeIdentifier: String {
+ return "pomodoro"
+ }
+
+ private enum CodingKeys: String, CodingKey {
+ case workTime
+ case restTime
}
private enum TimeTypes {
@@ -45,18 +34,44 @@ class PomodoroBarItem: CustomButtonTouchBarItem, Widget {
private var timeLeftString: String {
return String(format: "%.2i:%.2i", timeLeft / 60, timeLeft % 60)
}
+
init(identifier: NSTouchBarItem.Identifier, workTime: TimeInterval, restTime: TimeInterval) {
self.workTime = workTime
self.restTime = restTime
super.init(identifier: identifier, title: defaultTitle)
- tapClosure = { [weak self] in self?.startStopWork() }
- longTapClosure = { [weak self] in self?.startStopRest() }
+
+ 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.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 {
timer?.cancel()
diff --git a/MTMR/Widgets/PreviousBarItem.swift b/MTMR/Widgets/PreviousBarItem.swift
new file mode 100644
index 0000000..e440d34
--- /dev/null
+++ b/MTMR/Widgets/PreviousBarItem.swift
@@ -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")
+ }
+}
+
diff --git a/MTMR/Widgets/SleepBarItem.swift b/MTMR/Widgets/SleepBarItem.swift
new file mode 100644
index 0000000..e988ac5
--- /dev/null
+++ b/MTMR/Widgets/SleepBarItem.swift
@@ -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")
+ }
+}
+
diff --git a/MTMR/Widgets/TimeTouchBarItem.swift b/MTMR/Widgets/TimeTouchBarItem.swift
index 4a1df35..4bf659c 100644
--- a/MTMR/Widgets/TimeTouchBarItem.swift
+++ b/MTMR/Widgets/TimeTouchBarItem.swift
@@ -4,7 +4,40 @@ class TimeTouchBarItem: CustomButtonTouchBarItem {
private let dateFormatter = DateFormatter()
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) {
+ 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
if let locale = locale {
dateFormatter.locale = Locale(identifier: locale)
@@ -12,14 +45,10 @@ class TimeTouchBarItem: CustomButtonTouchBarItem {
if let abbr = timeZone {
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) {
- fatalError("init(coder:) has not been implemented")
+
+ func setupTimer() {
+ timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(updateTime), userInfo: nil, repeats: true)
}
@objc func updateTime() {
diff --git a/MTMR/Widgets/VolumeDownBarItem.swift b/MTMR/Widgets/VolumeDownBarItem.swift
new file mode 100644
index 0000000..31f2806
--- /dev/null
+++ b/MTMR/Widgets/VolumeDownBarItem.swift
@@ -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")
+ }
+}
+
diff --git a/MTMR/Widgets/VolumeUpBarItem.swift b/MTMR/Widgets/VolumeUpBarItem.swift
new file mode 100644
index 0000000..abbc0f6
--- /dev/null
+++ b/MTMR/Widgets/VolumeUpBarItem.swift
@@ -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")
+ }
+}
+
diff --git a/MTMR/Widgets/VolumeViewController.swift b/MTMR/Widgets/VolumeViewController.swift
index b46f0f5..abf9f18 100644
--- a/MTMR/Widgets/VolumeViewController.swift
+++ b/MTMR/Widgets/VolumeViewController.swift
@@ -3,12 +3,33 @@ import AVFoundation
import Cocoa
import CoreAudio
-class VolumeViewController: NSCustomTouchBarItem {
+class VolumeViewController: CustomTouchBarItem {
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) {
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(
mSelector: kAudioHardwareServiceDeviceProperty_VirtualMasterVolume,
mScope: kAudioDevicePropertyScopeOutput,
@@ -36,6 +57,7 @@ class VolumeViewController: NSCustomTouchBarItem {
self.sliderItem.floatValue = self.getInputGain() * 100
}
}
+
required init?(coder _: NSCoder) {
fatalError("init(coder:) has not been implemented")
diff --git a/MTMR/Widgets/WeatherBarItem.swift b/MTMR/Widgets/WeatherBarItem.swift
index 61ffeac..addd48e 100644
--- a/MTMR/Widgets/WeatherBarItem.swift
+++ b/MTMR/Widgets/WeatherBarItem.swift
@@ -21,10 +21,21 @@ class WeatherBarItem: CustomButtonTouchBarItem, CLLocationManagerDelegate {
private var iconsSource: Dictionary
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") {
- activity = NSBackgroundActivityScheduler(identifier: "\(identifier.rawValue).updatecheck")
- activity.interval = interval
+ self.activity = NSBackgroundActivityScheduler(identifier: "\(identifier.rawValue).updatecheck")
+ self.activity.interval = interval
self.units = units
self.api_key = api_key
@@ -43,7 +54,44 @@ class WeatherBarItem: CustomButtonTouchBarItem, CLLocationManagerDelegate {
}
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()
if status == .restricted || status == .denied {
print("User permission not given")
@@ -69,10 +117,6 @@ class WeatherBarItem: CustomButtonTouchBarItem, CLLocationManagerDelegate {
manager.startUpdatingLocation()
}
- required init?(coder _: NSCoder) {
- fatalError("init(coder:) has not been implemented")
- }
-
@objc func updateWeather() {
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)")!)
diff --git a/MTMR/Widgets/YandexWeatherBarItem.swift b/MTMR/Widgets/YandexWeatherBarItem.swift
index 740ea2c..9c34b56 100644
--- a/MTMR/Widgets/YandexWeatherBarItem.swift
+++ b/MTMR/Widgets/YandexWeatherBarItem.swift
@@ -19,13 +19,38 @@ class YandexWeatherBarItem: CustomButtonTouchBarItem, CLLocationManagerDelegate
private var location: CLLocation!
private var prevLocation: CLLocation!
private var manager: CLLocationManager!
+
+ override class var typeIdentifier: String {
+ return "weather"
+ }
+
+ private enum CodingKeys: String, CodingKey {
+ case refreshInterval
+ }
init(identifier: NSTouchBarItem.Identifier, interval: TimeInterval) {
activity = NSBackgroundActivityScheduler(identifier: "\(identifier.rawValue).updatecheck")
activity.interval = interval
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()
if status == .restricted || status == .denied {
print("User permission not given")
@@ -50,11 +75,12 @@ class YandexWeatherBarItem: CustomButtonTouchBarItem, CLLocationManagerDelegate
manager.desiredAccuracy = kCLLocationAccuracyHundredMeters
manager.startUpdatingLocation()
- tapClosure = tapClosure ?? defaultTapAction
- }
-
- required init?(coder _: NSCoder) {
- fatalError("init(coder:) has not been implemented")
+
+ self.setTapAction(
+ EventAction({ [weak self] (_ caller: CustomButtonTouchBarItem) in
+ self?.defaultTapAction()
+ } )
+ )
}
@objc func updateWeather() {