Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions Rectangle.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@
8B1D14E3A55936EBCCC1E807 /* MiddleRightTwelfthCalculation.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA84AB4DB9E7EEFCE50AA6D8 /* MiddleRightTwelfthCalculation.swift */; };
924919761FC491952752A147 /* TopCenterLeftTwelfthCalculation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9698D1D9EE0180D7C4468304 /* TopCenterLeftTwelfthCalculation.swift */; };
944F25CD2CE5A144004B2FD2 /* PrefsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 944F25CC2CE5A144004B2FD2 /* PrefsViewController.swift */; };
944F25CF2CE5A144004B2FD2 /* ShortcutRecordingObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 944F25CE2CE5A144004B2FD2 /* ShortcutRecordingObserver.swift */; };
944F25D12CE5A144004B2FD2 /* ShortcutRecordingObserverTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 944F25D02CE5A144004B2FD2 /* ShortcutRecordingObserverTests.swift */; };
94E9B08E2C3B8D97004C7F41 /* MacTilingDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94E9B08D2C3B8D97004C7F41 /* MacTilingDefaults.swift */; };
94E9B0902C3E4578004C7F41 /* StringExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94E9B08F2C3E4578004C7F41 /* StringExtension.swift */; };
9818E00D28B59205004AA524 /* CompoundSnapArea.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9818E00C28B59205004AA524 /* CompoundSnapArea.swift */; };
Expand Down Expand Up @@ -248,6 +250,8 @@
8B8CA6901E6FE134E930135B /* UpperMiddleCenterLeftSixteenthCalculation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpperMiddleCenterLeftSixteenthCalculation.swift; sourceTree = "<group>"; };
918F847FF15D524B6DB2E6DA /* TopCenterRightSixteenthCalculation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TopCenterRightSixteenthCalculation.swift; sourceTree = "<group>"; };
944F25CC2CE5A144004B2FD2 /* PrefsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrefsViewController.swift; sourceTree = "<group>"; };
944F25CE2CE5A144004B2FD2 /* ShortcutRecordingObserver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShortcutRecordingObserver.swift; sourceTree = "<group>"; };
944F25D02CE5A144004B2FD2 /* ShortcutRecordingObserverTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShortcutRecordingObserverTests.swift; sourceTree = "<group>"; };
94E9B08D2C3B8D97004C7F41 /* MacTilingDefaults.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MacTilingDefaults.swift; sourceTree = "<group>"; };
94E9B08F2C3E4578004C7F41 /* StringExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StringExtension.swift; sourceTree = "<group>"; };
9698D1D9EE0180D7C4468304 /* TopCenterLeftTwelfthCalculation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TopCenterLeftTwelfthCalculation.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -707,6 +711,7 @@
isa = PBXGroup;
children = (
9824701F22AF9B7E0037B409 /* RectangleTests.swift */,
944F25D02CE5A144004B2FD2 /* ShortcutRecordingObserverTests.swift */,
9824702122AF9B7E0037B409 /* Info.plist */,
);
path = RectangleTests;
Expand All @@ -725,6 +730,7 @@
isa = PBXGroup;
children = (
944F25CC2CE5A144004B2FD2 /* PrefsViewController.swift */,
944F25CE2CE5A144004B2FD2 /* ShortcutRecordingObserver.swift */,
98910B3D231130AF0066EC23 /* SettingsViewController.swift */,
983DD03F28A844BE00BF1EEE /* SnapAreaViewController.swift */,
98C97FFC25893B040061F01F /* Config.swift */,
Expand Down Expand Up @@ -1096,6 +1102,7 @@
9824704C22B189250037B409 /* WindowMover.swift in Sources */,
6490B39B27BF980F0056C220 /* TopRightEighthCalculation.swift in Sources */,
944F25CD2CE5A144004B2FD2 /* PrefsViewController.swift in Sources */,
944F25CF2CE5A144004B2FD2 /* ShortcutRecordingObserver.swift in Sources */,
9818E01028B59396004AA524 /* HalvesCompoundCalculation.swift in Sources */,
988D066922EB4CCB004EABD7 /* LastThirdCalculation.swift in Sources */,
98A6EDEC2528FFC100F74B10 /* WindowActionCategory.swift in Sources */,
Expand Down Expand Up @@ -1142,6 +1149,7 @@
buildActionMask = 2147483647;
files = (
9824702022AF9B7E0037B409 /* RectangleTests.swift in Sources */,
944F25D12CE5A144004B2FD2 /* ShortcutRecordingObserverTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
2 changes: 1 addition & 1 deletion Rectangle/PrefsWindow/Config.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ extension Defaults {

var shortcuts = [String: Shortcut]()
for action in WindowAction.active {
if let masShortcut = MASShortcutBinder.shared()?.value(forKey: action.name) as? MASShortcut {
if let masShortcut = ShortcutCycle.shortcut(for: action) {
shortcuts[action.name] = Shortcut(masShortcut: masShortcut)
}
}
Expand Down
2 changes: 2 additions & 0 deletions Rectangle/PrefsWindow/PrefsViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import ServiceManagement
class PrefsViewController: NSViewController {

var actionsToViews = [WindowAction: MASShortcutView]()
private let shortcutRecordingObserver = ShortcutRecordingObserver()

@IBOutlet weak var leftHalfShortcutView: MASShortcutView!
@IBOutlet weak var rightHalfShortcutView: MASShortcutView!
Expand Down Expand Up @@ -119,6 +120,7 @@ class PrefsViewController: NSViewController {
for (action, view) in actionsToViews {
view.setAssociatedUserDefaultsKey(action.name, withTransformerName: MASDictionaryTransformerName)
}
shortcutRecordingObserver.observe(Array(actionsToViews.values))

if Defaults.allowAnyShortcut.enabled {
let passThroughValidator = PassthroughShortcutValidator()
Expand Down
24 changes: 24 additions & 0 deletions Rectangle/PrefsWindow/SettingsViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ class SettingsViewController: NSViewController {

private var aboutTodoWindowController: NSWindowController?
private var extraSettingsPopover: NSPopover?
private let shortcutRecordingObserver = ShortcutRecordingObserver()

private var cycleSizeCheckboxes = [NSButton]()

Expand Down Expand Up @@ -811,6 +812,26 @@ class SettingsViewController: NSViewController {
twelfthsCyclingShortcutView.shortcutValidator = passThroughValidator
sixteenthsCyclingShortcutView.shortcutValidator = passThroughValidator
}
shortcutRecordingObserver.observe([
largerWidthShortcutView,
smallerWidthShortcutView,
topVerticalThirdShortcutView,
middleVerticalThirdShortcutView,
bottomVerticalThirdShortcutView,
topVerticalTwoThirdsShortcutView,
bottomVerticalTwoThirdsShortcutView,
topLeftEighthShortcutView,
topCenterLeftEighthShortcutView,
topCenterRightEighthShortcutView,
topRightEighthShortcutView,
bottomLeftEighthShortcutView,
bottomCenterLeftEighthShortcutView,
bottomCenterRightEighthShortcutView,
bottomRightEighthShortcutView,
ninthsCyclingShortcutView,
twelfthsCyclingShortcutView,
sixteenthsCyclingShortcutView
])

mainStackView.addArrangedSubview(gridHeaderLabel)
mainStackView.setCustomSpacing(4, after: gridHeaderLabel)
Expand Down Expand Up @@ -936,6 +957,7 @@ class SettingsViewController: NSViewController {
updateCheckForUpdatesTitle()

initializeTodoModeSettings()
shortcutRecordingObserver.observe([toggleTodoShortcutView, reflowTodoShortcutView])

self.cycleSizeCheckboxes.forEach {
$0.removeFromSuperview()
Expand Down Expand Up @@ -980,6 +1002,8 @@ class SettingsViewController: NSViewController {
todoAppSidePopUpButton.selectItem(withTag: Defaults.todoSidebarSide.value.rawValue)
TodoManager.initToggleShortcut()
TodoManager.initReflowShortcut()
toggleTodoShortcutView.shortcutValidator = TodoShortcutValidator(defaultsKey: TodoManager.toggleDefaultsKey)
reflowTodoShortcutView.shortcutValidator = TodoShortcutValidator(defaultsKey: TodoManager.reflowDefaultsKey)
toggleTodoShortcutView.setAssociatedUserDefaultsKey(TodoManager.toggleDefaultsKey, withTransformerName: MASDictionaryTransformerName)
reflowTodoShortcutView.setAssociatedUserDefaultsKey(TodoManager.reflowDefaultsKey, withTransformerName: MASDictionaryTransformerName)
showHideTodoModeSettings(animated: false)
Expand Down
67 changes: 67 additions & 0 deletions Rectangle/PrefsWindow/ShortcutRecordingObserver.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
//
// ShortcutRecordingObserver.swift
// Rectangle
//

import Cocoa
import MASShortcut

class ShortcutRecordingObserver: NSObject {

private static var recordingObservationContext = 0
private var observedViews = [ObjectIdentifier: MASShortcutView]()
private var recordingViews = Set<ObjectIdentifier>()

func observe(_ views: [MASShortcutView]) {
for view in views {
let viewId = ObjectIdentifier(view)
guard observedViews[viewId] == nil else { continue }

observedViews[viewId] = view
view.addObserver(self,
forKeyPath: "recording",
options: [.new],
context: &Self.recordingObservationContext)
}
}

deinit {
for view in observedViews.values {
view.removeObserver(self,
forKeyPath: "recording",
context: &Self.recordingObservationContext)
}
}

override func observeValue(forKeyPath keyPath: String?,
of object: Any?,
change: [NSKeyValueChangeKey : Any]?,
context: UnsafeMutableRawPointer?) {
guard context == &Self.recordingObservationContext,
keyPath == "recording",
let view = object as? MASShortcutView
else {
super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
return
}

let newValue = change?[.newKey]
let isRecording = (newValue as? Bool) ?? (newValue as? NSNumber)?.boolValue ?? false
recordingChanged(for: view, isRecording: isRecording)
}

func recordingChanged(for view: MASShortcutView, isRecording: Bool) {
let wasRecording = !recordingViews.isEmpty
let viewId = ObjectIdentifier(view)
if isRecording {
recordingViews.insert(viewId)
} else {
recordingViews.remove(viewId)
}

let isRecordingAnyView = !recordingViews.isEmpty
guard wasRecording != isRecordingAnyView else { return }
Notification.Name.shortcutRecording.post(object: isRecordingAnyView)
}

}
Loading
Loading