diff --git a/MTMR/CustomButtonTouchBarItem.swift b/MTMR/CustomButtonTouchBarItem.swift index a61a508..c6aa049 100644 --- a/MTMR/CustomButtonTouchBarItem.swift +++ b/MTMR/CustomButtonTouchBarItem.swift @@ -10,11 +10,15 @@ import Cocoa class CustomButtonTouchBarItem: NSCustomTouchBarItem, NSGestureRecognizerDelegate { var tapClosure: (() -> Void)? - var longTapClosure: (() -> Void)? + var longTapClosure: (() -> Void)? { + didSet { + longClick.isEnabled = longTapClosure != nil + } + } private var button: NSButton! private var singleClick: HapticClickGestureRecognizer! - private var longClick: NSPressGestureRecognizer! + private var longClick: LongPressGestureRecognizer! init(identifier: NSTouchBarItem.Identifier, title: String) { attributedTitle = title.defaultTouchbarAttributedString @@ -22,7 +26,8 @@ class CustomButtonTouchBarItem: NSCustomTouchBarItem, NSGestureRecognizerDelegat super.init(identifier: identifier) button = CustomHeightButton(title: title, target: nil, action: nil) - longClick = NSPressGestureRecognizer(target: self, action: #selector(handleGestureLong)) + longClick = LongPressGestureRecognizer(target: self, action: #selector(handleGestureLong)) + longClick.isEnabled = false longClick.allowedTouchTypes = .direct longClick.delegate = self @@ -97,7 +102,9 @@ class CustomButtonTouchBarItem: NSCustomTouchBarItem, NSGestureRecognizerDelegat } func gestureRecognizer(_ gestureRecognizer: NSGestureRecognizer, shouldRequireFailureOf otherGestureRecognizer: NSGestureRecognizer) -> Bool { - if gestureRecognizer == singleClick && otherGestureRecognizer == longClick { + if gestureRecognizer == singleClick && otherGestureRecognizer == longClick + || gestureRecognizer == longClick && otherGestureRecognizer == singleClick // need it + { return false } return true @@ -115,15 +122,8 @@ class CustomButtonTouchBarItem: NSCustomTouchBarItem, NSGestureRecognizerDelegat @objc func handleGestureLong(gr: NSPressGestureRecognizer) { switch gr.state { - case .began: - if let closure = self.longTapClosure { - HapticFeedback.shared.tap(strong: 2) - closure() - } else if let closure = self.tapClosure { - HapticFeedback.shared.tap(strong: 6) - closure() - print("long click") - } + case .possible: // tiny hack because we're calling action manually + (self.longTapClosure ?? self.tapClosure)?() break default: break @@ -181,6 +181,55 @@ class HapticClickGestureRecognizer: NSClickGestureRecognizer { } } +class LongPressGestureRecognizer: NSPressGestureRecognizer { + private let recognizeTimeout = 0.4 + private var timer: Timer? + + override func touchesBegan(with event: NSEvent) { + timerInvalidate() + + let touches = event.touches(for: self.view!) + if touches.count == 1 { // to prevent it for built-in two/three-finger gestures + timer = Timer.scheduledTimer(timeInterval: recognizeTimeout, target: self, selector: #selector(self.onTimer), userInfo: nil, repeats: false) + } + + super.touchesBegan(with: event) + } + + override func touchesMoved(with event: NSEvent) { + timerInvalidate() // to prevent it for built-in two/three-finger gestures + super.touchesMoved(with: event) + } + + override func touchesCancelled(with event: NSEvent) { + timerInvalidate() + super.touchesCancelled(with: event) + } + + override func touchesEnded(with event: NSEvent) { + timerInvalidate() + super.touchesEnded(with: event) + } + + private func timerInvalidate() { + if let timer = timer { + timer.invalidate() + self.timer = nil + } + } + + @objc private func onTimer() { + if let target = self.target, let action = self.action { + target.performSelector(onMainThread: action, with: self, waitUntilDone: false) + HapticFeedback.shared.tap(strong: 6) + } + } + + deinit { + timerInvalidate() + } +} + extension String { var defaultTouchbarAttributedString: NSAttributedString { let attrTitle = NSMutableAttributedString(string: self, attributes: [.foregroundColor: NSColor.white, .font: NSFont.systemFont(ofSize: 15, weight: .regular), .baselineOffset: 1]) diff --git a/MTMR/Widgets/CurrencyBarItem.swift b/MTMR/Widgets/CurrencyBarItem.swift index 1d1bbde..dfe3479 100644 --- a/MTMR/Widgets/CurrencyBarItem.swift +++ b/MTMR/Widgets/CurrencyBarItem.swift @@ -127,4 +127,8 @@ class CurrencyBarItem: CustomButtonTouchBarItem { newTitle.setAlignment(.center, range: NSRange(location: 0, length: title.count)) attributedTitle = newTitle } + + deinit { + activity.invalidate() + } } diff --git a/MTMR/Widgets/WeatherBarItem.swift b/MTMR/Widgets/WeatherBarItem.swift index 711e00a..61ffeac 100644 --- a/MTMR/Widgets/WeatherBarItem.swift +++ b/MTMR/Widgets/WeatherBarItem.swift @@ -135,4 +135,8 @@ class WeatherBarItem: CustomButtonTouchBarItem, CLLocationManagerDelegate { // print("inside didChangeAuthorization "); updateWeather() } + + deinit { + activity.invalidate() + } } diff --git a/MTMR/Widgets/YandexWeatherBarItem.swift b/MTMR/Widgets/YandexWeatherBarItem.swift index 0d4f9ab..6df2149 100644 --- a/MTMR/Widgets/YandexWeatherBarItem.swift +++ b/MTMR/Widgets/YandexWeatherBarItem.swift @@ -121,6 +121,10 @@ class YandexWeatherBarItem: CustomButtonTouchBarItem, CLLocationManagerDelegate func locationManager(_: CLLocationManager, didChangeAuthorization _: CLAuthorizationStatus) { updateWeather() } + + deinit { + activity.invalidate() + } } extension String {