271 lines
10 KiB
Objective-C
Executable File
271 lines
10 KiB
Objective-C
Executable File
//
|
|
// NYTAppDelegate.m
|
|
// Notifications for YouTube
|
|
//
|
|
// Created by Kim Wittenburg on 09.07.13.
|
|
// Copyright (c) 2013 Kim Wittenburg. All rights reserved.
|
|
//
|
|
|
|
#import "NYTAppDelegate.h"
|
|
|
|
// Core Imports
|
|
#import "NYTAuthentication.h"
|
|
#import "NYTUpdateManager.h"
|
|
|
|
// Other Imports
|
|
#import "NumberValueTransformer.h"
|
|
#import "NYTRulesWindowController.h"
|
|
|
|
@interface NYTAppDelegate ()
|
|
|
|
// Outlets etc.
|
|
@property (weak) IBOutlet NSButton *loginButton;
|
|
@property (readwrite, strong) NSStatusItem *statusItem;
|
|
|
|
// Login
|
|
@property (readwrite) BOOL loggingIn;
|
|
|
|
@end
|
|
|
|
// Notifications used for KVO
|
|
static void* const NYTLoginChangedNotification = @"NYTLoginChangedNotification";
|
|
static void* const NYTUpdateManagerPropertyDidChangeNotification = @"NYTUpdateManagerPropertyDidChangeNotification";
|
|
|
|
@implementation NYTAppDelegate {
|
|
NYTRulesWindowController *_rulesController;
|
|
}
|
|
|
|
+ (void)initialize
|
|
{
|
|
[super initialize];
|
|
// Register our value transformers
|
|
[NSValueTransformer setValueTransformer:[NumberValueTransformer new] forName:@"NumberValueTransformer"];
|
|
}
|
|
|
|
- (void)dealloc
|
|
{
|
|
// Make sure this object gets removed from any observed object
|
|
NYTUpdateManager *manager = [NYTUpdateManager sharedManager];
|
|
[manager removeObserver:self forKeyPath:@"autoRefreshEnabled"];
|
|
[manager removeObserver:self forKeyPath:@"autoRefreshInterval"];
|
|
[manager removeObserver:self forKeyPath:@"coalescesNotifications"];
|
|
[manager removeObserver:self forKeyPath:@"maximumVideoAge"];
|
|
[[NYTAuthentication sharedAuthentication] removeObserver:self forKeyPath:@"isLoggedIn"];
|
|
}
|
|
|
|
#pragma mark - Application Delegate
|
|
|
|
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
|
|
{
|
|
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
|
NYTUpdateManager *manager = [NYTUpdateManager sharedManager];
|
|
NYTAuthentication *auth = [NYTAuthentication sharedAuthentication];
|
|
|
|
// Configure the User Defaults
|
|
NSDictionary *userDefaults = @{@"autoRefreshEnabled": @YES, @"autoRefreshInterval": @600, @"coalescesNotifications": @YES, @"maximumVideoAge": @3600};
|
|
[defaults registerDefaults:userDefaults];
|
|
|
|
// Configure Notification Centers
|
|
[NSUserNotificationCenter defaultUserNotificationCenter].delegate = self;
|
|
// Notification Startup
|
|
NSUserNotification *startNotification = aNotification.userInfo[NSApplicationLaunchUserNotificationKey];
|
|
if (startNotification) {
|
|
[self userNotificationCenter:[NSUserNotificationCenter defaultUserNotificationCenter] didActivateNotification:startNotification];
|
|
}
|
|
|
|
// Configure the status item
|
|
self.statusItemVisible = YES;
|
|
|
|
// Configure the login (and log in). Do so before configuring notifications or auto refresh because this can take a while
|
|
[auth addObserver:self forKeyPath:@"isLoggedIn" options:0 context:NYTLoginChangedNotification];
|
|
self.loggingIn = YES;
|
|
[auth tryLoginFromKeychainWithCompletionHandler:^{
|
|
self.loggingIn = NO;
|
|
// If there is no login in the keychain show the preferences
|
|
if (!auth.isLoggedIn) {
|
|
[[NSApplication sharedApplication] activateIgnoringOtherApps:YES];
|
|
[self.window makeKeyAndOrderFront:self];
|
|
}
|
|
}];
|
|
|
|
// Configure the update manager
|
|
manager.maximumVideoAge = [defaults integerForKey:@"maximumVideoAge"];
|
|
manager.coalescesNotifications = [defaults boolForKey:@"coalescesNotifications"];
|
|
manager.autoRefreshInterval = [defaults integerForKey:@"autoRefreshInterval"];
|
|
[manager addObserver:self forKeyPath:@"maximumVideoAge" options:NSKeyValueObservingOptionNew context:NYTUpdateManagerPropertyDidChangeNotification];
|
|
[manager addObserver:self forKeyPath:@"coalescesNotifications" options:NSKeyValueObservingOptionNew context:NYTUpdateManagerPropertyDidChangeNotification];
|
|
[manager addObserver:self forKeyPath:@"autoRefreshInterval" options:NSKeyValueObservingOptionNew context:NYTUpdateManagerPropertyDidChangeNotification];
|
|
|
|
// Configure (Auto) Refresh
|
|
manager.autoRefreshEnabled = [defaults boolForKey:@"autoRefreshEnabled"];
|
|
[manager addObserver:self forKeyPath:@"autoRefreshEnabled" options:NSKeyValueObservingOptionNew context:NYTUpdateManagerPropertyDidChangeNotification];
|
|
}
|
|
|
|
- (BOOL)applicationShouldHandleReopen:(NSApplication *)sender hasVisibleWindows:(BOOL)flag
|
|
{
|
|
// Open the preferences on reopen (if no other window is visible)
|
|
if (!flag) {
|
|
[self.window makeKeyAndOrderFront:nil];
|
|
}
|
|
return YES;
|
|
}
|
|
|
|
- (void)applicationWillTerminate:(NSNotification *)notification
|
|
{
|
|
[[NSUserDefaults standardUserDefaults] synchronize];
|
|
}
|
|
|
|
#pragma mark - User Notification Center Delegate
|
|
|
|
- (void)userNotificationCenter:(NSUserNotificationCenter *)center didActivateNotification:(NSUserNotification *)notification
|
|
{
|
|
// Show the URL
|
|
NSString *videoURL = notification.userInfo[NYTUserNotificationURLKey];
|
|
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:videoURL]];
|
|
// Remove the notification
|
|
[center removeDeliveredNotification:notification];
|
|
}
|
|
|
|
- (BOOL)userNotificationCenter:(NSUserNotificationCenter *)center shouldPresentNotification:(NSUserNotification *)notification
|
|
{
|
|
return YES;
|
|
}
|
|
|
|
#pragma mark -
|
|
#pragma mark *** Handling the Status Item ***
|
|
|
|
- (void)setStatusItemVisible:(BOOL)visible
|
|
{
|
|
if (visible) {
|
|
self.statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength];
|
|
//NSMutableAttributedString *title = [[NSMutableAttributedString alloc] initWithString:@"(4)"];
|
|
//[title addAttribute:NSStrokeWidthAttributeName value:@-5.0 range:NSMakeRange/*(3, 4)*/(1, 1)];
|
|
//self.statusItem.attributedTitle = title;
|
|
self.statusItem.image = [NSImage imageNamed:@"play-icon-bw"];
|
|
self.statusItem.alternateImage = [NSImage imageNamed:@"play-icon-s"];
|
|
self.statusItem.menu = self.statusMenu;
|
|
self.statusItem.highlightMode = YES;
|
|
} else {
|
|
[[NSStatusBar systemStatusBar] removeStatusItem:self.statusItem];
|
|
self.statusItem = nil;
|
|
}
|
|
}
|
|
|
|
- (BOOL)isStatusItemVisible
|
|
{
|
|
return self.statusItem != nil;
|
|
}
|
|
|
|
#pragma mark *** Handling Login ***
|
|
|
|
- (IBAction)login:(id)sender {
|
|
if ([NYTAuthentication sharedAuthentication].isLoggedIn) {
|
|
// Logout: Present a sheet giving the following options: Logout, Cancel, Switch user
|
|
NSString *title = NSLocalizedString(@"Do you want to log out or switch to another user?", nil);
|
|
NSString *switchUser = NSLocalizedString(@"Switch User…", nil);
|
|
NSString *logout = NSLocalizedString(@"Logout", nil);
|
|
NSString *cancel = NSLocalizedString(@"Cancel", nil);
|
|
NSString *msg = NSLocalizedString(@"If you logout the login stored in your keychain will be removed. You would have to log in agin the next time you want to use Notifications for YouTube.", nil);
|
|
NSBeginAlertSheet(title, switchUser, logout, cancel, self.window, self, NULL, @selector(sheetDidDismiss:returnCode:contextInfo:), NULL, @"%@", msg);
|
|
} else {
|
|
[self doLogin];
|
|
}
|
|
}
|
|
|
|
- (void)sheetDidDismiss:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
|
|
{
|
|
if (returnCode == NSAlertDefaultReturn) {
|
|
// Switch User
|
|
[self doLogin];
|
|
} else if (returnCode == NSAlertAlternateReturn) {
|
|
// Logout: Redirect to Update Manager
|
|
[[NYTAuthentication sharedAuthentication] discardLogin];
|
|
}
|
|
}
|
|
|
|
- (void)doLogin
|
|
{
|
|
// Login: Redirect to Update Manager
|
|
self.loggingIn = YES;
|
|
[[NYTAuthentication sharedAuthentication] beginLoginSheetForWindow:self.window completionHandler:^(NSError *error) {
|
|
if (error) {
|
|
// Show the error as sheet if possible
|
|
if (self.window.isVisible) {
|
|
[NSApp presentError:error modalForWindow:self.window delegate:nil didPresentSelector:NULL contextInfo:NULL];
|
|
} else {
|
|
[NSApp presentError:error];
|
|
}
|
|
}
|
|
self.loggingIn = NO;
|
|
}];
|
|
}
|
|
|
|
#pragma mark *** Handling Refreshing ***
|
|
|
|
- (IBAction)performRefresh:(id)sender {
|
|
// Refresh with notifications
|
|
[[NYTUpdateManager sharedManager] refreshFeedsWithErrorHandler:^(NSError *error) {
|
|
// Show the error if the refresh was triggered manually
|
|
// Possibly show it in a modal sheet otherwise a modal window
|
|
if (error) {
|
|
if ([sender respondsToSelector:@selector(window)] && [sender window].isVisible) {
|
|
NSAlert *alert = [NSAlert alertWithError:error];
|
|
[alert beginSheetModalForWindow:[sender window] modalDelegate:nil didEndSelector:NULL contextInfo:NULL];
|
|
} else {
|
|
[NSApp presentError:error];
|
|
}
|
|
}
|
|
} notify:YES];
|
|
}
|
|
|
|
#pragma mark *** Configure Notifications ***
|
|
|
|
- (IBAction)editRules:(id)sender {
|
|
_rulesController = [[NYTRulesWindowController alloc] init];
|
|
[NSApp beginSheet:_rulesController.window modalForWindow:self.window modalDelegate:self didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:) contextInfo:NULL];
|
|
}
|
|
|
|
- (void)sheetDidEnd:(NSWindow *)sheet returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo
|
|
{
|
|
// For efficiency reasons
|
|
_rulesController = nil;
|
|
}
|
|
|
|
#pragma mark *** Other Actions ***
|
|
|
|
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
|
|
{
|
|
if (context == NYTUpdateManagerPropertyDidChangeNotification) {
|
|
id value = change[NSKeyValueChangeNewKey];
|
|
[[NSUserDefaults standardUserDefaults] setObject:value forKey:keyPath];
|
|
}else if (context == NYTLoginChangedNotification) {
|
|
// Manage the title of the login/logout button based on wether login information is present (using KVO)
|
|
if ([NYTAuthentication sharedAuthentication].isLoggedIn) {
|
|
self.loginButton.title = NSLocalizedString(@"Logout…", nil);
|
|
} else {
|
|
self.loginButton.title = NSLocalizedString(@"Login…", nil);
|
|
}
|
|
} else {
|
|
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
|
|
}
|
|
}
|
|
|
|
- (IBAction)showPreferenceWindow:(id)sender
|
|
{
|
|
// Activate the app first
|
|
[[NSApplication sharedApplication] activateIgnoringOtherApps:YES];
|
|
[self.window makeKeyAndOrderFront:sender];
|
|
[self.window makeMainWindow];
|
|
}
|
|
|
|
- (IBAction)showAboutPanel:(id)sender {
|
|
[NSApp activateIgnoringOtherApps:YES];
|
|
[NSApp orderFrontStandardAboutPanel:sender];
|
|
}
|
|
|
|
- (IBAction)browseYouTube:(id)sender {
|
|
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"http://www.youtube.com/"]];
|
|
}
|
|
|
|
@end
|