diff options
Diffstat (limited to 'MASShortcutView+UserDefaults.m')
| -rw-r--r-- | MASShortcutView+UserDefaults.m | 115 | 
1 files changed, 115 insertions, 0 deletions
| diff --git a/MASShortcutView+UserDefaults.m b/MASShortcutView+UserDefaults.m new file mode 100644 index 0000000..133453e --- /dev/null +++ b/MASShortcutView+UserDefaults.m @@ -0,0 +1,115 @@ +#import "MASShortcutView+UserDefaults.h" +#import "MASShortcut.h" +#import <objc/runtime.h> + +@interface MASShortcutDefaultsObserver : NSObject + +@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 +{ +    MASShortcutDefaultsObserver *defaultsObserver = [[MASShortcutDefaultsObserver alloc] initWithShortcutView:self userDefaultsKey:associatedUserDefaultsKey]; +    objc_setAssociatedObject(self, kDefaultsObserver, defaultsObserver, OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + +@end + +#pragma mark - + +@implementation MASShortcutDefaultsObserver { +    MASShortcut *_originalShortcut; +    BOOL _internalPreferenceChange; +    BOOL _internalShortcutChange; +} + +- (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]; +} + +#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 standardUserDefaults] setObject:shortcut.data forKey:_userDefaultsKey]; +        _internalPreferenceChange = NO; +    } +    else { +        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; +    } +} + +@end | 
