Permalink
Browse files

add Growl.framework and popup support

  • Loading branch information...
1 parent 721af09 commit 7f84f26b45084bf5fc4f422d2957e67d2135c2c7 @ghewgill committed Feb 29, 2012
View
View
Binary file not shown.
@@ -0,0 +1,5 @@
+#include <Growl/GrowlDefines.h>
+
+#ifdef __OBJC__
+# include <Growl/GrowlApplicationBridge.h>
+#endif

Large diffs are not rendered by default.

Oops, something went wrong.

Large diffs are not rendered by default.

Oops, something went wrong.
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>BuildMachineOSBuild</key>
+ <string>11C74</string>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleExecutable</key>
+ <string>Growl</string>
+ <key>CFBundleIdentifier</key>
+ <string>com.growl.growlframework</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundlePackageType</key>
+ <string>FMWK</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.3.1</string>
+ <key>CFBundleSignature</key>
+ <string>GRRR</string>
+ <key>CFBundleVersion</key>
+ <string>1.3.1</string>
+ <key>DTCompiler</key>
+ <string>com.apple.compilers.llvm.clang.1_0</string>
+ <key>DTPlatformBuild</key>
+ <string>4D199</string>
+ <key>DTPlatformVersion</key>
+ <string>GM</string>
+ <key>DTSDKBuild</key>
+ <string>11C63</string>
+ <key>DTSDKName</key>
+ <string>macosx10.7</string>
+ <key>DTXcode</key>
+ <string>0420</string>
+ <key>DTXcodeBuild</key>
+ <string>4D199</string>
+ <key>NSPrincipalClass</key>
+ <string>GrowlApplicationBridge</string>
+</dict>
+</plist>
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>files</key>
+ <dict>
+ <key>Resources/Info.plist</key>
+ <data>
+ SwzGt9RQsuVafBBrfBalB75dCwU=
+ </data>
+ </dict>
+ <key>rules</key>
+ <dict>
+ <key>^Resources/</key>
+ <true/>
+ <key>^Resources/.*\.lproj/</key>
+ <dict>
+ <key>optional</key>
+ <true/>
+ <key>weight</key>
+ <real>1000</real>
+ </dict>
+ <key>^Resources/.*\.lproj/locversion.plist$</key>
+ <dict>
+ <key>omit</key>
+ <true/>
+ <key>weight</key>
+ <real>1100</real>
+ </dict>
+ <key>^version.plist$</key>
+ <true/>
+ </dict>
+</dict>
+</plist>
@@ -39,11 +39,27 @@
3735B21614D50BD6002B0428 /* SBJsonTokeniser.m in Sources */ = {isa = PBXBuildFile; fileRef = 3735B20814D50BD6002B0428 /* SBJsonTokeniser.m */; };
3735B21714D50BD6002B0428 /* SBJsonUTF8Stream.m in Sources */ = {isa = PBXBuildFile; fileRef = 3735B20A14D50BD6002B0428 /* SBJsonUTF8Stream.m */; };
3735B21814D50BD6002B0428 /* SBJsonWriter.m in Sources */ = {isa = PBXBuildFile; fileRef = 3735B20C14D50BD6002B0428 /* SBJsonWriter.m */; };
+ 37F54B5814FD4ECD003F4E0D /* Growl Registration Ticket.growlRegDict in Resources */ = {isa = PBXBuildFile; fileRef = 37F54B5714FD4ECD003F4E0D /* Growl Registration Ticket.growlRegDict */; };
+ 37F54B5A14FE9F70003F4E0D /* Growl.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 37F54B5914FE9F70003F4E0D /* Growl.framework */; };
+ 37F54B5B14FE9F8E003F4E0D /* Growl.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 37F54B5914FE9F70003F4E0D /* Growl.framework */; };
37F9D5FE14D5F39C00DA4B70 /* NSString+html.m in Sources */ = {isa = PBXBuildFile; fileRef = 37F9D5FD14D5F39C00DA4B70 /* NSString+html.m */; };
37F9D60014D9113C00DA4B70 /* favicon.ico in Resources */ = {isa = PBXBuildFile; fileRef = 37F9D5FF14D9113C00DA4B70 /* favicon.ico */; };
37F9D60214DA7D2300DA4B70 /* Credits.html in Resources */ = {isa = PBXBuildFile; fileRef = 37F9D60114DA7D2300DA4B70 /* Credits.html */; };
/* End PBXBuildFile section */
+/* Begin PBXCopyFilesBuildPhase section */
+ 37F54B5514FCD8A2003F4E0D /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = "";
+ dstSubfolderSpec = 10;
+ files = (
+ 37F54B5B14FE9F8E003F4E0D /* Growl.framework in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXCopyFilesBuildPhase section */
+
/* Begin PBXFileReference section */
3735B1B814D3CF94002B0428 /* Stack Exchange Notifier.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Stack Exchange Notifier.app"; sourceTree = BUILT_PRODUCTS_DIR; };
3735B1BC14D3CF94002B0428 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
@@ -84,6 +100,8 @@
3735B20A14D50BD6002B0428 /* SBJsonUTF8Stream.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBJsonUTF8Stream.m; sourceTree = "<group>"; };
3735B20B14D50BD6002B0428 /* SBJsonWriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJsonWriter.h; sourceTree = "<group>"; };
3735B20C14D50BD6002B0428 /* SBJsonWriter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBJsonWriter.m; sourceTree = "<group>"; };
+ 37F54B5714FD4ECD003F4E0D /* Growl Registration Ticket.growlRegDict */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = "Growl Registration Ticket.growlRegDict"; sourceTree = "<group>"; };
+ 37F54B5914FE9F70003F4E0D /* Growl.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Growl.framework; sourceTree = "<group>"; };
37F9D5FC14D5F39C00DA4B70 /* NSString+html.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+html.h"; sourceTree = "<group>"; };
37F9D5FD14D5F39C00DA4B70 /* NSString+html.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+html.m"; sourceTree = "<group>"; };
37F9D5FF14D9113C00DA4B70 /* favicon.ico */ = {isa = PBXFileReference; lastKnownFileType = image.ico; path = favicon.ico; sourceTree = "<group>"; };
@@ -97,6 +115,7 @@
files = (
3735B1F214D4B57A002B0428 /* WebKit.framework in Frameworks */,
3735B1BD14D3CF94002B0428 /* Cocoa.framework in Frameworks */,
+ 37F54B5A14FE9F70003F4E0D /* Growl.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -123,6 +142,7 @@
3735B1BB14D3CF94002B0428 /* Frameworks */ = {
isa = PBXGroup;
children = (
+ 37F54B5914FE9F70003F4E0D /* Growl.framework */,
3735B1F114D4B57A002B0428 /* WebKit.framework */,
3735B1BC14D3CF94002B0428 /* Cocoa.framework */,
3735B1DA14D3CF95002B0428 /* SenTestingKit.framework */,
@@ -164,6 +184,7 @@
3735B1C814D3CF94002B0428 /* main.m */,
3735B1CA14D3CF95002B0428 /* Stack Exchange Notifier-Prefix.pch */,
37F9D60114DA7D2300DA4B70 /* Credits.html */,
+ 37F54B5714FD4ECD003F4E0D /* Growl Registration Ticket.growlRegDict */,
);
name = "Supporting Files";
sourceTree = "<group>";
@@ -210,6 +231,7 @@
3735B1B414D3CF94002B0428 /* Sources */,
3735B1B514D3CF94002B0428 /* Frameworks */,
3735B1B614D3CF94002B0428 /* Resources */,
+ 37F54B5514FCD8A2003F4E0D /* CopyFiles */,
);
buildRules = (
);
@@ -255,6 +277,7 @@
3735B1D314D3CF95002B0428 /* MainMenu.xib in Resources */,
37F9D60014D9113C00DA4B70 /* favicon.ico in Resources */,
37F9D60214DA7D2300DA4B70 /* Credits.html in Resources */,
+ 37F54B5814FD4ECD003F4E0D /* Growl Registration Ticket.growlRegDict in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -370,6 +393,11 @@
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_OBJC_ARC = YES;
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(inherited)",
+ "\"$(SRCROOT)/Stack Exchange Notifier\"",
+ "\"$(SRCROOT)\"",
+ );
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "Stack Exchange Notifier/Stack Exchange Notifier-Prefix.pch";
INFOPLIST_FILE = "Stack Exchange Notifier/Stack Exchange Notifier-Info.plist";
@@ -382,6 +410,11 @@
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_OBJC_ARC = YES;
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(inherited)",
+ "\"$(SRCROOT)/Stack Exchange Notifier\"",
+ "\"$(SRCROOT)\"",
+ );
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "Stack Exchange Notifier/Stack Exchange Notifier-Prefix.pch";
INFOPLIST_FILE = "Stack Exchange Notifier/Stack Exchange Notifier-Info.plist";
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>TicketVersion</key>
+ <integer>1</integer>
+ <key>AllNotifications</key>
+ <array>
+ <string>NewInbox</string>
+ </array>
+</dict>
+</plist>
@@ -8,8 +8,9 @@
#import <Cocoa/Cocoa.h>
#import <WebKit/WebKit.h>
+#import "Growl/GrowlApplicationBridge.h"
-@interface Stack_Exchange_NotifierAppDelegate : NSObject <NSApplicationDelegate> {
+@interface Stack_Exchange_NotifierAppDelegate : NSObject <NSApplicationDelegate, GrowlApplicationBridgeDelegate> {
NSWindow *__unsafe_unretained window;
// Timer for periodically updating the menu ("checked n minutes ago")
NSTimer *menuUpdateTimer;
@@ -25,6 +26,8 @@
NSString *access_token;
// Accumulated received data from an API request
NSMutableData *receivedData;
+ // Array of all items that we've seen from the server
+ NSArray *allItems;
// Array of items already marked as "read"
NSArray *readItems;
// Current unread items from the site
@@ -14,6 +14,8 @@
// (don't use this one, register to get your own
// at http://stackapps.com/apps/oauth/register )
NSString *CLIENT_KEY = @"JBpdN2wRVnHTq9E*uuyTPQ((";
+// Name of key to store all items in defaults
+NSString *DEFAULTS_KEY_ALL_ITEMS = @"com.hewgill.senotifier.allitems";
// Name of key to store read items in defaults
NSString *DEFAULTS_KEY_READ_ITEMS = @"com.hewgill.senotifier.readitems";
@@ -222,9 +224,14 @@ - (void)applicationDidFinishLaunching:(NSNotification *)aNotification
loginError = nil;
lastCheckError = nil;
+ // read the list of all items from defaults
+ allItems = [[NSUserDefaults standardUserDefaults] arrayForKey:DEFAULTS_KEY_ALL_ITEMS];
// read the list of items already read from defaults
readItems = [[NSUserDefaults standardUserDefaults] arrayForKey:DEFAULTS_KEY_READ_ITEMS];
+ // register ourselves with growl
+ [GrowlApplicationBridge setGrowlDelegate:self];
+
// create the status bar item
statusItem = createStatusItem();
[self resetMenu];
@@ -403,6 +410,25 @@ -(void)connectionDidFinishLoading:(NSURLConnection *)connection
// Get the unread inbox items according to the server.
items = [r objectForKey:@"items"];
+
+ // First copy all server items into our local copy, notifying for each new one
+ NSMutableArray *newAllItems = [[NSMutableArray alloc] initWithCapacity:[items count]];
+ for (NSDictionary *item in [items objectEnumerator]) {
+ NSString *link = [item objectForKey:@"link"];
+ if (![allItems containsObject:link]) {
+ [GrowlApplicationBridge
+ notifyWithTitle:[[item objectForKey:@"site"] objectForKey:@"name"]
+ description:[[item objectForKey:@"body"] stringByDecodingXMLEntities]
+ notificationName:@"NewInbox"
+ iconData:[NSData alloc]
+ priority:0
+ isSticky:NO
+ clickContext:[item objectForKey:@"link"]];
+ }
+ [newAllItems addObject:link];
+ }
+ allItems = newAllItems;
+ [[NSUserDefaults standardUserDefaults] setObject:allItems forKey:DEFAULTS_KEY_ALL_ITEMS];
// We only need to keep the "read" items in our local defaults
// list for those items where the server still thinks they're
@@ -450,4 +476,20 @@ -(void)openUrlFromItem:(NSNumber *)index
[self resetMenu];
}
+-(NSString *)applicationNameForGrowl
+{
+ return @"Stack Exchange Notifier";
+}
+
+// Selector called by growl when item is clicked
+-(void)growlNotificationWasClicked:(id)clickContext
+{
+ NSString *link = clickContext;
+ for (unsigned int i = 0; i < [items count]; i++) {
+ if ([link compare:[[items objectAtIndex:i] objectForKey:@"link"]] == NSOrderedSame) {
+ [self openUrlFromItem:[NSNumber numberWithUnsignedInt:i]];
+ }
+ }
+}
+
@end

0 comments on commit 7f84f26

Please sign in to comment.