diff --git a/src/Tomighty/Base.lproj/PreferencesWindow.xib b/src/Tomighty/Base.lproj/PreferencesWindow.xib index 3c5e657..6e864b2 100644 --- a/src/Tomighty/Base.lproj/PreferencesWindow.xib +++ b/src/Tomighty/Base.lproj/PreferencesWindow.xib @@ -1,8 +1,8 @@ - - + + - + @@ -11,6 +11,7 @@ + @@ -31,7 +32,7 @@ - + @@ -267,8 +268,8 @@ - - + + @@ -278,8 +279,8 @@ - - + + @@ -316,8 +317,8 @@ - - - + diff --git a/src/Tomighty/Core/Agent/TYUserInterfaceAgent.m b/src/Tomighty/Core/Agent/TYUserInterfaceAgent.m index fe2b6f3..09d5d1e 100644 --- a/src/Tomighty/Core/Agent/TYUserInterfaceAgent.m +++ b/src/Tomighty/Core/Agent/TYUserInterfaceAgent.m @@ -49,9 +49,36 @@ - (void)updateAppUiInResponseToEventsFrom:(id )eventBus [eventBus subscribeTo:POMODORO_START subscriber:^(id eventData) { [ui switchToPomodoroState]; [self dispatchNewNotification:@"Pomodoro started"]; + + if ([preferences getInt:PREF_ENABLE_DO_NOT_DISTURB_DURING_POMODORO]) { + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, + 1 * NSEC_PER_SEC), + dispatch_get_main_queue(), + ^{ + turnDoNotDisturbOn(); + }); + + } + }]; + + [eventBus subscribeTo:POMODORO_COMPLETE subscriber:^(id eventData) { + + if ([preferences getInt:PREF_ENABLE_DO_NOT_DISTURB_DURING_POMODORO]) { + turnDoNotDisturbOff(); + } + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, + 1 * NSEC_PER_SEC), + dispatch_get_main_queue(), + ^{ + [self dispatchNewNotification:@"Pomodoro completed"]; + }); + }]; [eventBus subscribeTo:TIMER_STOP subscriber:^(id eventData) { + if ([preferences getInt:PREF_ENABLE_DO_NOT_DISTURB_DURING_POMODORO]) { + turnDoNotDisturbOff(); + } [ui switchToIdleState]; }]; @@ -84,4 +111,60 @@ - (void)updateAppUiInResponseToEventsFrom:(id )eventBus }]; } +/// +/// This block of code for turning Do Not Disturb on and off +/// is directly from https://stackoverflow.com/a/36385778/518130 +/// +void turnDoNotDisturbOn(void) +{ + // The trick is to set DND time range from 00:00 (0 minutes) to 23:59 (1439 minutes), + // so it will always be on + CFPreferencesSetValue(CFSTR("dndStart"), (__bridge CFPropertyListRef)(@(0.0f)), + CFSTR("com.apple.notificationcenterui"), + kCFPreferencesCurrentUser, kCFPreferencesCurrentHost); + + CFPreferencesSetValue(CFSTR("dndEnd"), (__bridge CFPropertyListRef)(@(1440.f)), + CFSTR("com.apple.notificationcenterui"), + kCFPreferencesCurrentUser, kCFPreferencesCurrentHost); + + CFPreferencesSetValue(CFSTR("doNotDisturb"), (__bridge CFPropertyListRef)(@(YES)), + CFSTR("com.apple.notificationcenterui"), + kCFPreferencesCurrentUser, kCFPreferencesCurrentHost); + + // Notify all the related daemons that we have changed Do Not Disturb preferences + commitDoNotDisturbChanges(); +} + + +void turnDoNotDisturbOff() +{ + CFPreferencesSetValue(CFSTR("dndStart"), NULL, + CFSTR("com.apple.notificationcenterui"), + kCFPreferencesCurrentUser, kCFPreferencesCurrentHost); + + CFPreferencesSetValue(CFSTR("dndEnd"), NULL, + CFSTR("com.apple.notificationcenterui"), + kCFPreferencesCurrentUser, kCFPreferencesCurrentHost); + + CFPreferencesSetValue(CFSTR("doNotDisturb"), (__bridge CFPropertyListRef)(@(NO)), + CFSTR("com.apple.notificationcenterui"), + kCFPreferencesCurrentUser, kCFPreferencesCurrentHost); + + commitDoNotDisturbChanges(); +} + +void commitDoNotDisturbChanges(void) +{ + /// XXX: I'm using kCFPreferencesCurrentUser placeholder here which means that this code must + /// be run under regular user's account (not root/admin). If you're going to run this code + /// from a privileged helper, use kCFPreferencesAnyUser in order to toggle DND for all users + /// or drop privileges and use kCFPreferencesCurrentUser. + CFPreferencesSynchronize(CFSTR("com.apple.notificationcenterui"), kCFPreferencesCurrentUser, kCFPreferencesCurrentHost); + [[NSDistributedNotificationCenter defaultCenter] postNotificationName: @"com.apple.notificationcenterui.dndprefs_changed" + object: nil userInfo: nil + deliverImmediately: YES]; +} + + + @end diff --git a/src/Tomighty/Core/Preferences/TYPreferences.h b/src/Tomighty/Core/Preferences/TYPreferences.h index 49a2e17..1fd30db 100644 --- a/src/Tomighty/Core/Preferences/TYPreferences.h +++ b/src/Tomighty/Core/Preferences/TYPreferences.h @@ -23,6 +23,7 @@ extern NSString * const PREF_HOTKEY_START; extern NSString * const PREF_HOTKEY_STOP; extern NSString * const PREF_CONTINUOUS_MODE; extern NSString * const PREF_ENABLE_NOTIFICATIONS; +extern NSString * const PREF_ENABLE_DO_NOT_DISTURB_DURING_POMODORO; @protocol TYPreferences diff --git a/src/Tomighty/Core/Preferences/TYUserDefaultsPreferences.m b/src/Tomighty/Core/Preferences/TYUserDefaultsPreferences.m index a511acb..b6917cb 100644 --- a/src/Tomighty/Core/Preferences/TYUserDefaultsPreferences.m +++ b/src/Tomighty/Core/Preferences/TYUserDefaultsPreferences.m @@ -26,6 +26,8 @@ NSString * const PREF_HOTKEY_START = @"org.tomighty.hotkey.start"; NSString * const PREF_HOTKEY_STOP = @"org.tomighty.hotkey.stop"; NSString * const PREF_ENABLE_NOTIFICATIONS = @"org.tomighty.enable_notifications"; +NSString * const PREF_ENABLE_DO_NOT_DISTURB_DURING_POMODORO = @"org.tomighty.enable_do_not_disturb_during_pomodoro"; + @implementation TYUserDefaultsPreferences { @@ -51,6 +53,7 @@ - (id)initWith:(id )anEventBus [defaultValues setObject:[NSNumber numberWithInt:true] forKey:PREF_PLAY_TICKTOCK_SOUND_DURING_BREAK]; [defaultValues setObject:[NSNumber numberWithInt:true] forKey:PREF_CONTINUOUS_MODE]; [defaultValues setObject:[NSNumber numberWithInt:false] forKey:PREF_ENABLE_NOTIFICATIONS]; + [defaultValues setObject:[NSNumber numberWithInt:false] forKey:PREF_ENABLE_DO_NOT_DISTURB_DURING_POMODORO]; [defaultValues setObject:[NSNumber numberWithInt:PREF_STATUS_ICON_TIME_FORMAT_NONE] forKey:PREF_STATUS_ICON_TIME_FORMAT]; [defaultValues setObject:@"^⌘P" forKey:PREF_HOTKEY_START]; [defaultValues setObject:@"^⌘S" forKey:PREF_HOTKEY_STOP]; diff --git a/src/Tomighty/Core/UI/TYPreferencesWindowController.h b/src/Tomighty/Core/UI/TYPreferencesWindowController.h index 3c1c1f7..5191257 100644 --- a/src/Tomighty/Core/UI/TYPreferencesWindowController.h +++ b/src/Tomighty/Core/UI/TYPreferencesWindowController.h @@ -22,6 +22,7 @@ @property (weak) IBOutlet NSButton *check_play_ticktock_sound_during_pomodoro; @property (weak) IBOutlet NSButton *check_play_ticktock_sound_during_break; @property (weak) IBOutlet NSButton *check_show_notifications; +@property (weak) IBOutlet NSButton *check_enable_do_not_disturb_during_pomodoro; @property (weak) IBOutlet NSButton *check_continuous_mode; @property (weak) IBOutlet NSPopUpButton *popup_status_icon_time_format; @property (weak) IBOutlet TYHotkeyControl *text_hotkey_start; @@ -40,5 +41,6 @@ - (IBAction)save_hotkey_start:(id)sender; - (IBAction)save_hotkey_stop:(id)sender; - (IBAction)save_show_notifications:(id)sender; +- (IBAction)save_enable_do_not_disturb_during_pomodoro:(id)sender; @end diff --git a/src/Tomighty/Core/UI/TYPreferencesWindowController.m b/src/Tomighty/Core/UI/TYPreferencesWindowController.m index 77daa34..ea612e3 100644 --- a/src/Tomighty/Core/UI/TYPreferencesWindowController.m +++ b/src/Tomighty/Core/UI/TYPreferencesWindowController.m @@ -39,6 +39,7 @@ - (void)windowDidLoad [self.check_play_ticktock_sound_during_pomodoro setState:[preferences getInt:PREF_PLAY_TICKTOCK_SOUND_DURING_POMODORO]]; [self.check_play_ticktock_sound_during_break setState:[preferences getInt:PREF_PLAY_TICKTOCK_SOUND_DURING_BREAK]]; [self.check_show_notifications setState:[preferences getInt:PREF_ENABLE_NOTIFICATIONS]]; + [self.check_enable_do_not_disturb_during_pomodoro setState:[preferences getInt:PREF_ENABLE_DO_NOT_DISTURB_DURING_POMODORO]]; [self.check_continuous_mode setState:[preferences getInt:PREF_CONTINUOUS_MODE]]; [self.popup_status_icon_time_format selectItemAtIndex:[preferences getInt:PREF_STATUS_ICON_TIME_FORMAT]]; [self.text_hotkey_start @@ -90,6 +91,10 @@ - (IBAction)save_show_notifications:(id)sender { [preferences setInt:PREF_ENABLE_NOTIFICATIONS value:(int)[self.check_show_notifications state]]; } +- (IBAction)save_enable_do_not_disturb_during_pomodoro:(id)sender { + [preferences setInt:PREF_ENABLE_DO_NOT_DISTURB_DURING_POMODORO value:(int)[self.check_enable_do_not_disturb_during_pomodoro state]]; +} + - (IBAction)save_continuous_mode:(id)sender { [preferences setInt:PREF_CONTINUOUS_MODE value:(int)[self.check_continuous_mode state]]; }