forked from aptonic/frenzy
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathMASShortcutView+UserDefaults.m
executable file
·134 lines (101 loc) · 4.42 KB
/
MASShortcutView+UserDefaults.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#import "MASShortcutView+UserDefaults.h"
#import "MASShortcut.h"
#import <objc/runtime.h>
@interface MASShortcutDefaultsObserver : NSObject {
MASShortcut *_originalShortcut;
BOOL _internalPreferenceChange;
BOOL _internalShortcutChange;
NSString *_userDefaultsKey;
MASShortcutView *_shortcutView;
}
@property (nonatomic, readonly) NSString *userDefaultsKey;
@property (nonatomic, readonly, weak) MASShortcutView *shortcutView;
- (id)initWithShortcutView:(MASShortcutView *)shortcutView userDefaultsKey:(NSString *)userDefaultsKey;
@end
#pragma mark -
@implementation MASShortcutView (UserDefaults)
void *kDefaultsObserver = &kDefaultsObserver;
- (NSString *)associatedUserDefaultsKey
{
MASShortcutDefaultsObserver *defaultsObserver = objc_getAssociatedObject(self, kDefaultsObserver);
return defaultsObserver.userDefaultsKey;
}
- (void)setAssociatedUserDefaultsKey:(NSString *)associatedUserDefaultsKey
{
// First, stop observing previous shortcut view
objc_setAssociatedObject(self, kDefaultsObserver, nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
// Next, start observing current shortcut view
MASShortcutDefaultsObserver *defaultsObserver = [[MASShortcutDefaultsObserver alloc] initWithShortcutView:self userDefaultsKey:associatedUserDefaultsKey];
objc_setAssociatedObject(self, kDefaultsObserver, defaultsObserver, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
[defaultsObserver release];
}
@end
#pragma mark -
@implementation MASShortcutDefaultsObserver
@synthesize userDefaultsKey = _userDefaultsKey;
@synthesize shortcutView = _shortcutView;
#pragma mark -
- (id)initWithShortcutView:(MASShortcutView *)shortcutView userDefaultsKey:(NSString *)userDefaultsKey
{
self = [super init];
if (self) {
_originalShortcut = shortcutView.shortcutValue;
_shortcutView = shortcutView;
_userDefaultsKey = userDefaultsKey.copy;
[self startObservingShortcutView];
}
return self;
}
- (void)dealloc
{
// __weak _shortcutView is not yet deallocated because it refers MASShortcutDefaultsObserver
[self stopObservingShortcutView];
[super dealloc];
}
#pragma mark -
void *kShortcutValueObserver = &kShortcutValueObserver;
- (void)startObservingShortcutView
{
// Read initial shortcut value from user preferences
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSData *data = [defaults dataForKey:_userDefaultsKey];
_shortcutView.shortcutValue = [MASShortcut shortcutWithData:data];
// Observe user preferences to update shortcut value when it changed
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(userDefaultsDidChange:) name:NSUserDefaultsDidChangeNotification object:defaults];
// Observe the keyboard shortcut that user inputs by hand
[_shortcutView addObserver:self forKeyPath:@"shortcutValue" options:0 context:kShortcutValueObserver];
}
- (void)userDefaultsDidChange:(NSNotification *)note
{
// Ignore notifications posted from -[self observeValueForKeyPath:]
if (_internalPreferenceChange) return;
_internalShortcutChange = YES;
NSData *data = [note.object dataForKey:_userDefaultsKey];
_shortcutView.shortcutValue = [MASShortcut shortcutWithData:data];
_internalShortcutChange = NO;
}
- (void)stopObservingShortcutView
{
// Stop observing keyboard hotkeys entered by user in the shortcut view
[_shortcutView removeObserver:self forKeyPath:@"shortcutValue" context:kShortcutValueObserver];
// Stop observing user preferences
[[NSNotificationCenter defaultCenter] removeObserver:self name:NSUserDefaultsDidChangeNotification object:[NSUserDefaults standardUserDefaults]];
// Restore original hotkey in the shortcut view
_shortcutView.shortcutValue = _originalShortcut;
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if (context == kShortcutValueObserver) {
if (_internalShortcutChange) return;
MASShortcut *shortcut = [object valueForKey:keyPath];
_internalPreferenceChange = YES;
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:(shortcut.data ?: [NSKeyedArchiver archivedDataWithRootObject:nil]) forKey:_userDefaultsKey];
[defaults synchronize];
_internalPreferenceChange = NO;
}
else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
@end