diff --git a/.gitignore b/.gitignore index 20d4ce3..5cf374a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ # Xcode .DS_Store +Release */build/* *.pbxuser !default.pbxuser @@ -14,4 +15,4 @@ profile *.moved-aside DerivedData .idea/ -*.hmap \ No newline at end of file +*.hmap diff --git a/README.md b/README.md index 5a65505..b540a02 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ btcbar ====== -A tiny status bar widget for OS X that displays the latest USD/BTC spot price from MtGox, Bitstamp, and Coinbase. +A tiny status bar widget for OS X that displays the latest USD/BTC spot price from BitStamp, BTCe, Coinbase, and MtGox. ## Screenshot @@ -19,14 +19,21 @@ Simply place btcbar.app in your `/Applications` folder, and optionally add it to ## Download -The current version of btcbar (2.0.0) can be downloaded here: +The current version of btcbar (2.1.0) can be downloaded here: -https://github.com/nearengine/btcbar/releases/download/v2.0.0/btcbar_2_0_0.zip +https://github.com/nearengine/btcbar/releases/download/v2.1.0/btcbar_2_1_0.zip It requires OS X 10.7+ and a 64-bit processor. ## Changelog +### 2.1.0 + +* New BTCe/USD ticker +* Manually refreshes when a ticker is clicked +* Decreased disk io/cpu time/power usage +* Greatly increased modularity (tickers now have a protocol, menu is dynamically generated) + ### 2.0.0 Adds Bitstamp and Coinbase, and a little better backend abstraction so it will be easier to add future tickers. diff --git a/Release/btcbar_1_0_0.zip b/Release/btcbar_1_0_0.zip deleted file mode 100644 index e1df551..0000000 Binary files a/Release/btcbar_1_0_0.zip and /dev/null differ diff --git a/Release/btcbar_2_0_0.zip b/Release/btcbar_2_0_0.zip deleted file mode 100644 index 65a5194..0000000 Binary files a/Release/btcbar_2_0_0.zip and /dev/null differ diff --git a/Resources/screenshot.png b/Resources/screenshot.png index 8056290..e7f273a 100644 Binary files a/Resources/screenshot.png and b/Resources/screenshot.png differ diff --git a/Resources/screenshot2.png b/Resources/screenshot2.png index 365f678..3ba3cbf 100644 Binary files a/Resources/screenshot2.png and b/Resources/screenshot2.png differ diff --git a/btcbar.xcodeproj/project.pbxproj b/btcbar.xcodeproj/project.pbxproj index 9818927..c1e1220 100644 --- a/btcbar.xcodeproj/project.pbxproj +++ b/btcbar.xcodeproj/project.pbxproj @@ -11,15 +11,16 @@ 830CE09B171B6C3E00DDD525 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 830CE099171B6C3E00DDD525 /* InfoPlist.strings */; }; 830CE09D171B6C3E00DDD525 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 830CE09C171B6C3E00DDD525 /* main.m */; }; 830CE0A4171B6C3E00DDD525 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 830CE0A3171B6C3E00DDD525 /* AppDelegate.m */; }; - 830CE0A7171B6C3E00DDD525 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 830CE0A5171B6C3E00DDD525 /* MainMenu.xib */; }; 830CE0E6171B914300DDD525 /* Icon.icns in Resources */ = {isa = PBXBuildFile; fileRef = 830CE0E5171B914300DDD525 /* Icon.icns */; }; 830CE101171B9A5A00DDD525 /* btclogoAlternate.png in Resources */ = {isa = PBXBuildFile; fileRef = 830CE0FD171B9A5A00DDD525 /* btclogoAlternate.png */; }; 830CE102171B9A5A00DDD525 /* btclogo.png in Resources */ = {isa = PBXBuildFile; fileRef = 830CE0FE171B9A5A00DDD525 /* btclogo.png */; }; 830CE103171B9A5A00DDD525 /* btclogoAlternate@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 830CE0FF171B9A5A00DDD525 /* btclogoAlternate@2x.png */; }; 830CE104171B9A5A00DDD525 /* btclogo@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 830CE100171B9A5A00DDD525 /* btclogo@2x.png */; }; - 831EB77C18133CF900AE6C10 /* MtGoxFetcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 831EB77B18133CF900AE6C10 /* MtGoxFetcher.m */; }; + 831EB77C18133CF900AE6C10 /* MtGoxUSDFetcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 831EB77B18133CF900AE6C10 /* MtGoxUSDFetcher.m */; }; + 838F429B182E639F00B4FC58 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 838F429A182E639F00B4FC58 /* MainMenu.xib */; }; 83A7942D1813742500BB3953 /* BitStampUSDFetcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 83A7942C1813742500BB3953 /* BitStampUSDFetcher.m */; }; 83A79430181385DC00BB3953 /* CoinbaseUSDFetcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 83A7942F181385DC00BB3953 /* CoinbaseUSDFetcher.m */; }; + 83CD78D6182E66E50071F27A /* BTCeUSDFetcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 83CD78D5182E66E50071F27A /* BTCeUSDFetcher.m */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -34,19 +35,22 @@ 830CE09E171B6C3E00DDD525 /* btcbar-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "btcbar-Prefix.pch"; sourceTree = ""; }; 830CE0A2171B6C3E00DDD525 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 830CE0A3171B6C3E00DDD525 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; - 830CE0A6171B6C3E00DDD525 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/MainMenu.xib; sourceTree = ""; }; 830CE0AE171B6C3F00DDD525 /* SenTestingKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SenTestingKit.framework; path = Library/Frameworks/SenTestingKit.framework; sourceTree = DEVELOPER_DIR; }; 830CE0E5171B914300DDD525 /* Icon.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = Icon.icns; sourceTree = ""; }; 830CE0FD171B9A5A00DDD525 /* btclogoAlternate.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = btclogoAlternate.png; sourceTree = ""; }; 830CE0FE171B9A5A00DDD525 /* btclogo.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = btclogo.png; sourceTree = ""; }; 830CE0FF171B9A5A00DDD525 /* btclogoAlternate@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "btclogoAlternate@2x.png"; sourceTree = ""; }; 830CE100171B9A5A00DDD525 /* btclogo@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "btclogo@2x.png"; sourceTree = ""; }; - 831EB77A18133CF900AE6C10 /* MtGoxFetcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MtGoxFetcher.h; sourceTree = ""; }; - 831EB77B18133CF900AE6C10 /* MtGoxFetcher.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MtGoxFetcher.m; sourceTree = ""; }; + 831EB77A18133CF900AE6C10 /* MtGoxUSDFetcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MtGoxUSDFetcher.h; sourceTree = ""; }; + 831EB77B18133CF900AE6C10 /* MtGoxUSDFetcher.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MtGoxUSDFetcher.m; sourceTree = ""; }; + 838F4296182E2F6E00B4FC58 /* Fetcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Fetcher.h; sourceTree = ""; }; + 838F429A182E639F00B4FC58 /* MainMenu.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MainMenu.xib; sourceTree = ""; }; 83A7942B1813742500BB3953 /* BitStampUSDFetcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BitStampUSDFetcher.h; sourceTree = ""; }; 83A7942C1813742500BB3953 /* BitStampUSDFetcher.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BitStampUSDFetcher.m; sourceTree = ""; }; 83A7942E181385DC00BB3953 /* CoinbaseUSDFetcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CoinbaseUSDFetcher.h; sourceTree = ""; }; 83A7942F181385DC00BB3953 /* CoinbaseUSDFetcher.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CoinbaseUSDFetcher.m; sourceTree = ""; }; + 83CD78D4182E66E50071F27A /* BTCeUSDFetcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BTCeUSDFetcher.h; sourceTree = ""; }; + 83CD78D5182E66E50071F27A /* BTCeUSDFetcher.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BTCeUSDFetcher.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -104,15 +108,10 @@ children = ( 830CE0C4171B714E00DDD525 /* Icons */, 830CE097171B6C3E00DDD525 /* Supporting Files */, - 830CE0A5171B6C3E00DDD525 /* MainMenu.xib */, + 838F429A182E639F00B4FC58 /* MainMenu.xib */, 830CE0A2171B6C3E00DDD525 /* AppDelegate.h */, 830CE0A3171B6C3E00DDD525 /* AppDelegate.m */, - 83A7942E181385DC00BB3953 /* CoinbaseUSDFetcher.h */, - 83A7942F181385DC00BB3953 /* CoinbaseUSDFetcher.m */, - 831EB77A18133CF900AE6C10 /* MtGoxFetcher.h */, - 831EB77B18133CF900AE6C10 /* MtGoxFetcher.m */, - 83A7942B1813742500BB3953 /* BitStampUSDFetcher.h */, - 83A7942C1813742500BB3953 /* BitStampUSDFetcher.m */, + 838F4297182E5A5000B4FC58 /* Fetchers */, ); path = btcbar; sourceTree = ""; @@ -139,6 +138,22 @@ name = Icons; sourceTree = ""; }; + 838F4297182E5A5000B4FC58 /* Fetchers */ = { + isa = PBXGroup; + children = ( + 838F4296182E2F6E00B4FC58 /* Fetcher.h */, + 83A7942B1813742500BB3953 /* BitStampUSDFetcher.h */, + 83A7942C1813742500BB3953 /* BitStampUSDFetcher.m */, + 83CD78D4182E66E50071F27A /* BTCeUSDFetcher.h */, + 83CD78D5182E66E50071F27A /* BTCeUSDFetcher.m */, + 83A7942E181385DC00BB3953 /* CoinbaseUSDFetcher.h */, + 83A7942F181385DC00BB3953 /* CoinbaseUSDFetcher.m */, + 831EB77A18133CF900AE6C10 /* MtGoxUSDFetcher.h */, + 831EB77B18133CF900AE6C10 /* MtGoxUSDFetcher.m */, + ); + name = Fetchers; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -191,11 +206,11 @@ buildActionMask = 2147483647; files = ( 830CE09B171B6C3E00DDD525 /* InfoPlist.strings in Resources */, - 830CE0A7171B6C3E00DDD525 /* MainMenu.xib in Resources */, 830CE0E6171B914300DDD525 /* Icon.icns in Resources */, 830CE101171B9A5A00DDD525 /* btclogoAlternate.png in Resources */, 830CE102171B9A5A00DDD525 /* btclogo.png in Resources */, 830CE103171B9A5A00DDD525 /* btclogoAlternate@2x.png in Resources */, + 838F429B182E639F00B4FC58 /* MainMenu.xib in Resources */, 830CE104171B9A5A00DDD525 /* btclogo@2x.png in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -209,8 +224,9 @@ files = ( 83A7942D1813742500BB3953 /* BitStampUSDFetcher.m in Sources */, 830CE09D171B6C3E00DDD525 /* main.m in Sources */, + 83CD78D6182E66E50071F27A /* BTCeUSDFetcher.m in Sources */, 83A79430181385DC00BB3953 /* CoinbaseUSDFetcher.m in Sources */, - 831EB77C18133CF900AE6C10 /* MtGoxFetcher.m in Sources */, + 831EB77C18133CF900AE6C10 /* MtGoxUSDFetcher.m in Sources */, 830CE0A4171B6C3E00DDD525 /* AppDelegate.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -226,14 +242,6 @@ name = InfoPlist.strings; sourceTree = ""; }; - 830CE0A5171B6C3E00DDD525 /* MainMenu.xib */ = { - isa = PBXVariantGroup; - children = ( - 830CE0A6171B6C3E00DDD525 /* en */, - ); - name = MainMenu.xib; - sourceTree = ""; - }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ @@ -301,7 +309,7 @@ GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "btcbar/btcbar-Prefix.pch"; INFOPLIST_FILE = "btcbar/btcbar-Info.plist"; - MACOSX_DEPLOYMENT_TARGET = 10.6; + MACOSX_DEPLOYMENT_TARGET = 10.7; PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = app; }; @@ -314,7 +322,7 @@ GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "btcbar/btcbar-Prefix.pch"; INFOPLIST_FILE = "btcbar/btcbar-Info.plist"; - MACOSX_DEPLOYMENT_TARGET = 10.6; + MACOSX_DEPLOYMENT_TARGET = 10.7; PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = app; }; diff --git a/btcbar/AppDelegate.h b/btcbar/AppDelegate.h index 2929e48..d9f3051 100644 --- a/btcbar/AppDelegate.h +++ b/btcbar/AppDelegate.h @@ -5,31 +5,29 @@ #import -#import "MtGoxFetcher.h" +#import "MtGoxUSDFetcher.h" #import "BitStampUSDFetcher.h" #import "CoinbaseUSDFetcher.h" +#import "BTCeUSDFetcher.h" @interface AppDelegate : NSObject { - IBOutlet NSMenu *btcbarMenu; + NSMenu *btcbarMainMenu; + NSInteger currentFetcherTag; + NSStatusItem *btcbarStatusItem; - NSImage *btcbarStatusImage; - NSImage *btcbarHighlightStatusImage; + NSTimer *updateViewTimer; NSTimer *updateDataTimer; + + NSMutableArray *tickers; NSUserDefaults *prefs; - NSString *webUrl; - MtGoxFetcher *mt_gox; - BitStampUSDFetcher *bitstamp_usd; - CoinbaseUSDFetcher *coinbase_usd; } -@property (assign) IBOutlet NSMenu *menu; +- (void)menuActionSetTicker:(id)sender; +- (void)menuActionBrowser:(id)sender; +- (void)menuActionQuit:(id)sender; -- (IBAction)menuActionSetTicker:(id)sender; -- (IBAction)menuActionBrowser:(id)sender; -- (IBAction)menuActionQuit:(id)sender; - -- (void)updateViewTimerAction:(NSTimer*)timer; +- (void)handleTickerNotification:(NSNotification *)pNotification; - (void)updateDataTimerAction:(NSTimer*)timer; @end diff --git a/btcbar/AppDelegate.m b/btcbar/AppDelegate.m index dfeabc9..b0ac058 100644 --- a/btcbar/AppDelegate.m +++ b/btcbar/AppDelegate.m @@ -9,46 +9,70 @@ @implementation AppDelegate // -// INITIALIZE STATUS BAR ITEM +// ENTRY & EXIT // +// Status item initialization - (void)awakeFromNib { - // Load ticker preference + // Load ticker preference from disk prefs = [NSUserDefaults standardUserDefaults]; - // If preference does not exist, default to MtGoxUSD - if (![prefs objectForKey:@"btcbar_ticker"]) - [prefs setObject:@"MtGoxUSD" forKey:@"btcbar_ticker"]; + // Register update notifications for tickers + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(handleTickerNotification:) + name:@"ticker_update" + object:nil]; - // Set NSOnState for the selected ticker in the menu - for (NSMenuItem *menuitem in _menu.itemArray) - if ([menuitem.title isEqualToString:[prefs objectForKey:@"btcbar_ticker"]]) - [menuitem setState:NSOnState]; + // Pass each ticker object into a dictionary, get first updates + tickers = [NSMutableArray arrayWithObjects: + [[BitStampUSDFetcher alloc] init], + [[BTCeUSDFetcher alloc] init], + [[CoinbaseUSDFetcher alloc] init], + [[MtGoxUSDFetcher alloc] init], + nil]; - // Initialize each ticker and get first updates - mt_gox = [[MtGoxFetcher alloc] init]; - bitstamp_usd = [[BitStampUSDFetcher alloc] init]; - coinbase_usd = [[CoinbaseUSDFetcher alloc] init]; - // Initialize our status bar item with flexible width + // If ticker preference does not exist, default to 0 + if (![prefs integerForKey:@"btcbar_ticker"]) + [prefs setInteger:0 forKey:@"btcbar_ticker"]; + currentFetcherTag = [prefs integerForKey:@"btcbar_ticker"]; + + // If ticker preference exceeds the bounds of `tickers`, default to 0 + if (currentFetcherTag < 0 || currentFetcherTag >= [tickers count]) + currentFetcherTag = 0; + + // Initialize main menu + btcbarMainMenu = [[NSMenu alloc] initWithTitle:@"loading..."]; + + // Add each loaded ticker object to main menu + for(id ticker in tickers) + { + NSUInteger tag = [tickers indexOfObject:ticker]; + NSMenuItem *new_menuitem = [[NSMenuItem alloc] initWithTitle:[ticker ticker_menu] action:@selector(menuActionSetTicker:) keyEquivalent:[NSString stringWithFormat:@"%lu", (unsigned long)tag+1]]; + [new_menuitem setTag:tag]; + [btcbarMainMenu addItem:new_menuitem]; + } + + // Add the separator, Open in Browser, and Quit items to main menu + [btcbarMainMenu addItem:[NSMenuItem separatorItem]]; + [btcbarMainMenu addItem:[[NSMenuItem alloc] initWithTitle:@"Open in Browser" action:@selector(menuActionBrowser:) keyEquivalent:@"o"]]; + [btcbarMainMenu addItem:[[NSMenuItem alloc] initWithTitle:@"Quit" action:@selector(menuActionQuit:) keyEquivalent:@"q"]]; + + // Set the default ticker's menu item state to checked + [[btcbarMainMenu.itemArray objectAtIndex:currentFetcherTag] setState:NSOnState]; + + // Initialize status bar item with flexible width btcbarStatusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength]; - // Set Image - btcbarStatusImage = [NSImage imageNamed:@"btclogo"]; - [btcbarStatusItem setImage:btcbarStatusImage]; - - // Set Alternate (Highlighted state) Image - btcbarHighlightStatusImage = [NSImage imageNamed:@"btclogoAlternate"]; - [btcbarStatusItem setAlternateImage:btcbarHighlightStatusImage]; + // Set status bar image and highlighted image + [btcbarStatusItem setImage:[NSImage imageNamed:@"btclogo"]]; + [btcbarStatusItem setAlternateImage:[NSImage imageNamed:@"btclogoAlternate"]]; - // Set options on click + // Set menu options on click [btcbarStatusItem setHighlightMode:YES]; - [btcbarStatusItem setMenu:btcbarMenu]; - - // Setup timer to update menu bar every other second - updateViewTimer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(updateViewTimerAction:) userInfo:nil repeats:YES]; - [self updateViewTimerAction:updateViewTimer]; + [btcbarStatusItem setMenu:btcbarMainMenu]; // Setup timer to update all tickers every 10 seconds updateDataTimer = [NSTimer scheduledTimerWithTimeInterval:10 target:self selector:@selector(updateDataTimerAction:) userInfo:nil repeats:YES]; @@ -56,37 +80,39 @@ - (void)awakeFromNib // -// MENU OUTLETS -// +// MENUITEM ACTIONS // -// Outlet for menu items which change current ticker +// Action for menu items which change current ticker - (void)menuActionSetTicker:(id)sender { - // Cast sender to a menu item - NSMenuItem *senderItem = (NSMenuItem *)sender; - // Set all menu items to "off" state - for (NSMenuItem *menuitem in _menu.itemArray) + for (NSMenuItem *menuitem in btcbarMainMenu.itemArray) [menuitem setState:NSOffState]; // Set this menu item to "on" state [sender setState:NSOnState]; // Update ticker preference - [prefs setObject:senderItem.title forKey:@"btcbar_ticker"]; + currentFetcherTag = [sender tag]; + [prefs setInteger:currentFetcherTag forKey:@"btcbar_ticker"]; + [prefs synchronize]; - // Force the status item value and website button to update - [self updateViewTimerAction:updateViewTimer]; + // Update the requested ticker immediately + [[tickers objectAtIndex:currentFetcherTag] requestUpdate]; + + //Force the status item value to update + [[NSNotificationCenter defaultCenter] postNotificationName:@"ticker_update" object:self]; + } -// "Open in Browser" outlet +// "Open in Browser" action - (void)menuActionBrowser:(id)sender { - [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:webUrl]]; + [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[(id )[tickers objectAtIndex:currentFetcherTag] url]]]; } -// "Quit" outlet +// "Quit" action - (void)menuActionQuit:(id)sender { [NSApp performSelector:@selector(terminate:) withObject:nil afterDelay:0.0]; @@ -94,43 +120,20 @@ - (void)menuActionQuit:(id)sender // -// TIMER CALLBACKS +// CALLBACKS // -// Updates the status item with one of the tickers, depending on which one the user has selected -// Updates the link that the "Open in Browser" menu item uses -- (void)updateViewTimerAction:(NSTimer*)timer +// Updates the status item with the latest ticker value +-(void)handleTickerNotification:(NSNotification *)pNotification { - NSString *tickerSetting = [prefs stringForKey:@"btcbar_ticker"]; - - if ([tickerSetting isEqualToString:@"MtGoxUSD"]) - { - [btcbarStatusItem setTitle:mt_gox.ticker]; - webUrl = mt_gox.url; - } - else if ([tickerSetting isEqualToString:@"BitstampUSD"]) - { - [btcbarStatusItem setTitle:bitstamp_usd.ticker]; - webUrl = bitstamp_usd.url; - } - else if ([tickerSetting isEqualToString:@"CoinbaseUSD"]) - { - [btcbarStatusItem setTitle:coinbase_usd.ticker]; - webUrl = coinbase_usd.url; - } - else - { - [btcbarStatusItem setTitle:@"invalid default"]; - webUrl = @""; - } + [btcbarStatusItem setTitle:[(id )[tickers objectAtIndex:currentFetcherTag] ticker]]; } // Requests for each ticker to update itself - (void)updateDataTimerAction:(NSTimer*)timer { - [mt_gox requestUpdate]; - [bitstamp_usd requestUpdate]; - [coinbase_usd requestUpdate]; + for (id ticker in tickers) + [ticker requestUpdate]; } @end diff --git a/btcbar/BTCeUSDFetcher.h b/btcbar/BTCeUSDFetcher.h new file mode 100644 index 0000000..f28a35c --- /dev/null +++ b/btcbar/BTCeUSDFetcher.h @@ -0,0 +1,20 @@ +// +// BTCeUSDFetcher.h +// btcbar +// + +#import +#import "Fetcher.h" + +@interface BTCeUSDFetcher : NSObject +{ + NSMutableData *_responseData; +} + +@property (nonatomic) NSString* ticker; +@property (nonatomic) NSString* ticker_menu; +@property (nonatomic) NSString* url; + +- (void)requestUpdate; + +@end diff --git a/btcbar/BTCeUSDFetcher.m b/btcbar/BTCeUSDFetcher.m new file mode 100644 index 0000000..b7730ba --- /dev/null +++ b/btcbar/BTCeUSDFetcher.m @@ -0,0 +1,110 @@ +// +// BTCeUSDFetcher.m +// btcbar +// + +#import "BTCeUSDFetcher.h" + +@implementation BTCeUSDFetcher + +- (id) init +{ + if (self = [super init]) + { + // Menu Item Name + [self setTicker_menu:@"BTCeUSD"]; + + // Default ticker value + [self setTicker:@""]; + + // Website location + [self setUrl:@"https://btc-e.com/"]; + + // Immediately request first update + [self requestUpdate]; + } + + return self; +} + +// Override Ticker setter to trigger status item update +- (void)setTicker:(NSString *)tickerString +{ + // Update the ticker value + _ticker = tickerString; + + // Trigger notification to update ticker + [[NSNotificationCenter defaultCenter] postNotificationName:@"ticker_update" object:self]; +} + +// Initiates an asyncronous HTTP connection +- (void)requestUpdate +{ + NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://btc-e.com/api/2/btc_usd/ticker"]]; + + // Set the request's user agent + [request addValue:@"btcbar/2.0 (BTCeUSDFetcher)" forHTTPHeaderField:@"User-Agent"]; + + // Initialize a connection from our request + NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self]; + + // Go go go + [connection start]; +} + +// Initializes data storage on request response +- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response +{ + _responseData = [[NSMutableData alloc] init]; +} + +// Appends response data +- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data +{ + [_responseData appendData:data]; +} + +// Indiciate no caching +- (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse*)cachedResponse +{ + return nil; +} + +// Parse data after load +- (void)connectionDidFinishLoading:(NSURLConnection *)connection +{ + // Parse the JSON into results + NSError *jsonParsingError = nil; + NSDictionary *results = [[NSDictionary alloc] init]; + results = [NSJSONSerialization JSONObjectWithData:_responseData options:0 error:&jsonParsingError]; + + // Results parsed successfully from JSON + if(results) + { + + if ([[results objectForKey:@"ticker"] objectForKey:@"last"]) + { + [self setTicker:[NSString localizedStringWithFormat:@"$%.2f",[[[results objectForKey:@"ticker"] objectForKey:@"last"] floatValue]]]; + } + else + { + NSLog(@"BTCeUSDFetcher: api error"); + [self setTicker:@"api error"]; + } + } + // JSON parsing failed + else + { + NSLog(@"BTCeUSDFetcher: json error"); + [self setTicker:@"json error"]; + } +} + +// HTTP request failed +- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error +{ + NSLog(@"BTCeUSDFetcher: %@", error); + [self setTicker:@"connection error"]; +} + +@end diff --git a/btcbar/BitStampUSDFetcher.h b/btcbar/BitStampUSDFetcher.h index 82ecddc..f626769 100644 --- a/btcbar/BitStampUSDFetcher.h +++ b/btcbar/BitStampUSDFetcher.h @@ -4,14 +4,16 @@ // #import +#import "Fetcher.h" -@interface BitStampUSDFetcher : NSObject +@interface BitStampUSDFetcher : NSObject { NSMutableData *_responseData; } -@property NSString* ticker; -@property NSString* url; +@property (nonatomic) NSString* ticker; +@property (nonatomic) NSString* ticker_menu; +@property (nonatomic) NSString* url; - (void)requestUpdate; diff --git a/btcbar/BitStampUSDFetcher.m b/btcbar/BitStampUSDFetcher.m index 8fd8c0c..d62f9fd 100644 --- a/btcbar/BitStampUSDFetcher.m +++ b/btcbar/BitStampUSDFetcher.m @@ -7,12 +7,13 @@ @implementation BitStampUSDFetcher -@synthesize ticker; - - (id) init { if (self = [super init]) { + // Menu Item Name + [self setTicker_menu:@"BitStampUSD"]; + // Default ticker value [self setTicker:@""]; @@ -26,6 +27,16 @@ - (id) init return self; } +// Override Ticker setter to trigger status item update +- (void)setTicker:(NSString *)tickerString +{ + // Update the ticker value + _ticker = tickerString; + + // Trigger notification to update ticker + [[NSNotificationCenter defaultCenter] postNotificationName:@"ticker_update" object:self]; +} + // Initiates an asyncronous HTTP connection - (void)requestUpdate { @@ -70,7 +81,7 @@ - (void)connectionDidFinishLoading:(NSURLConnection *)connection // Results parsed successfully from JSON if(results) { - // Get MtGox API status + // Get API status NSString *resultsStatus = [results objectForKey:@"last"]; // If API call succeeded update the ticker... @@ -82,14 +93,14 @@ - (void)connectionDidFinishLoading:(NSURLConnection *)connection else { NSLog(@"BitStampUSDFetcher: api error"); - [self setTicker:@"BitStampUSDFetcher: api error"]; + [self setTicker:@"api error"]; } } // JSON parsing failed else { NSLog(@"BitStampUSDFetcher: json error"); - [self setTicker:@"BitStampUSDFetcher: json error"]; + [self setTicker:@"json error"]; } } @@ -97,7 +108,7 @@ - (void)connectionDidFinishLoading:(NSURLConnection *)connection - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { NSLog(@"BitStampUSDFetcher: %@", error); - [self setTicker:@"BitStampUSDFetcher: connection error"]; + [self setTicker:@"connection error"]; } @end diff --git a/btcbar/CoinbaseUSDFetcher.h b/btcbar/CoinbaseUSDFetcher.h index ec8bb64..fb38f14 100644 --- a/btcbar/CoinbaseUSDFetcher.h +++ b/btcbar/CoinbaseUSDFetcher.h @@ -4,14 +4,16 @@ // #import +#import "Fetcher.h" -@interface CoinbaseUSDFetcher : NSObject +@interface CoinbaseUSDFetcher : NSObject { NSMutableData *_responseData; } -@property NSString* ticker; -@property NSString* url; +@property (nonatomic) NSString* ticker; +@property (nonatomic) NSString* ticker_menu; +@property (nonatomic) NSString* url; - (void)requestUpdate; diff --git a/btcbar/CoinbaseUSDFetcher.m b/btcbar/CoinbaseUSDFetcher.m index a058544..57e0eba 100644 --- a/btcbar/CoinbaseUSDFetcher.m +++ b/btcbar/CoinbaseUSDFetcher.m @@ -7,12 +7,13 @@ @implementation CoinbaseUSDFetcher -@synthesize ticker; - -- (id) init +- (id)init { if (self = [super init]) { + // Menu Item Name + [self setTicker_menu:@"CoinbaseUSD"]; + // Default ticker value [self setTicker:@""]; @@ -26,6 +27,16 @@ - (id) init return self; } +// Override Ticker setter to trigger status item update +- (void)setTicker:(NSString *)tickerString +{ + // Update the ticker value + _ticker = tickerString; + + // Trigger notification to update ticker + [[NSNotificationCenter defaultCenter] postNotificationName:@"ticker_update" object:self]; +} + // Initiates an asyncronous HTTP connection - (void)requestUpdate { @@ -70,7 +81,7 @@ - (void)connectionDidFinishLoading:(NSURLConnection *)connection // Results parsed successfully from JSON if(results) { - // Get MtGox API status + // Get API status NSString *resultsStatus = [results objectForKey:@"amount"]; // If API call succeeded update the ticker... @@ -82,14 +93,14 @@ - (void)connectionDidFinishLoading:(NSURLConnection *)connection else { NSLog(@"CoinbaseUSDFetcher: api error"); - [self setTicker:@"CoinbaseUSDFetcher: api error"]; + [self setTicker:@"api error"]; } } // JSON parsing failed else { NSLog(@"CoinbaseUSDFetcher: json error"); - [self setTicker:@"CoinbaseUSDFetcher: json error"]; + [self setTicker:@"json error"]; } } @@ -97,7 +108,7 @@ - (void)connectionDidFinishLoading:(NSURLConnection *)connection - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { NSLog(@"CoinbaseUSDFetcher: %@", error); - [self setTicker:@"CoinbaseUSDFetcher: connection error"]; + [self setTicker:@"connection error"]; } @end diff --git a/btcbar/Fetcher.h b/btcbar/Fetcher.h new file mode 100644 index 0000000..be5ecb4 --- /dev/null +++ b/btcbar/Fetcher.h @@ -0,0 +1,22 @@ +// +// Fetcher.h +// btcbar +// + +#import + +@protocol Fetcher + +// Current title in the menu +@property (nonatomic) NSString* ticker_menu; + +// Current price of the ticker, including currency symbol +@property (nonatomic) NSString* ticker; + +// URL that the "Open in Browser" option opens +@property (nonatomic) NSString* url; + +// Trigger a refresh, update `ticker` when it completes +- (void)requestUpdate; + +@end diff --git a/btcbar/en.lproj/MainMenu.xib b/btcbar/MainMenu.xib similarity index 58% rename from btcbar/en.lproj/MainMenu.xib rename to btcbar/MainMenu.xib index d0da4e3..99957a4 100644 --- a/btcbar/en.lproj/MainMenu.xib +++ b/btcbar/MainMenu.xib @@ -1,8 +1,8 @@ - + - - + + @@ -52,47 +52,7 @@ - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/btcbar/MtGoxFetcher.h b/btcbar/MtGoxFetcher.h deleted file mode 100644 index 8e36e24..0000000 --- a/btcbar/MtGoxFetcher.h +++ /dev/null @@ -1,18 +0,0 @@ -// -// MtGoxFetcher.h -// btcbar -// - -#import - -@interface MtGoxFetcher : NSObject -{ - NSMutableData *_responseData; -} - -@property NSString* ticker; -@property NSString* url; - -- (void)requestUpdate; - -@end diff --git a/btcbar/MtGoxUSDFetcher.h b/btcbar/MtGoxUSDFetcher.h new file mode 100644 index 0000000..fd319af --- /dev/null +++ b/btcbar/MtGoxUSDFetcher.h @@ -0,0 +1,20 @@ +// +// MtGoxUSDFetcher.h +// btcbar +// + +#import +#import "Fetcher.h" + +@interface MtGoxUSDFetcher : NSObject +{ + NSMutableData *_responseData; +} + +@property (nonatomic) NSString* ticker; +@property (nonatomic) NSString* ticker_menu; +@property (nonatomic) NSString* url; + +- (void)requestUpdate; + +@end diff --git a/btcbar/MtGoxFetcher.m b/btcbar/MtGoxUSDFetcher.m similarity index 75% rename from btcbar/MtGoxFetcher.m rename to btcbar/MtGoxUSDFetcher.m index 2dce010..c738258 100644 --- a/btcbar/MtGoxFetcher.m +++ b/btcbar/MtGoxUSDFetcher.m @@ -1,18 +1,19 @@ // -// MtGoxFetcher.m +// MtGoxUSDFetcher.m // btcbar // -#import "MtGoxFetcher.h" +#import "MtGoxUSDFetcher.h" -@implementation MtGoxFetcher - -@synthesize ticker; +@implementation MtGoxUSDFetcher - (id) init { if (self = [super init]) { + // Menu Item Name + [self setTicker_menu:@"MtGoxUSD"]; + // Default ticker value [self setTicker:@""]; @@ -26,13 +27,23 @@ - (id) init return self; } +// Override Ticker setter to trigger status item update +- (void)setTicker:(NSString *)tickerString +{ + // Update the ticker value + _ticker = tickerString; + + // Trigger notification to update ticker + [[NSNotificationCenter defaultCenter] postNotificationName:@"ticker_update" object:self]; +} + // Initiates an asyncronous HTTP connection - (void)requestUpdate { NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://data.mtgox.com/api/2/BTCUSD/money/ticker_fast"]]; // Set the request's user agent - [request addValue:@"btcbar/2.0 (MtGoxFetcher)" forHTTPHeaderField:@"User-Agent"]; + [request addValue:@"btcbar/2.0 (MtGoxUSDFetcher)" forHTTPHeaderField:@"User-Agent"]; // Initialize a connection from our request NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self]; @@ -70,7 +81,7 @@ - (void)connectionDidFinishLoading:(NSURLConnection *)connection // Results parsed successfully from JSON if(results) { - // Get MtGox API status + // Get API status NSString *resultsStatus = [results objectForKey:@"result"]; // If API call succeeded update the ticker... @@ -82,15 +93,15 @@ - (void)connectionDidFinishLoading:(NSURLConnection *)connection // Otherwise log an error... else { - NSLog(@"MtGoxFetcher: api error"); - [self setTicker:@"MtGoxFetcher: api error"]; + NSLog(@"MtGoxUSDFetcher: api error"); + [self setTicker:@"api error"]; } } // JSON parsing failed else { - NSLog(@"MtGoxFetcher: json error"); - [self setTicker:@"MtGoxFetcher: json error"]; + NSLog(@"MtGoxUSDFetcher: json error"); + [self setTicker:@"json error"]; } } @@ -98,7 +109,7 @@ - (void)connectionDidFinishLoading:(NSURLConnection *)connection - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { NSLog(@"MtGoxFetcher: %@", error); - [self setTicker:@"MtGoxFetcher: connection error"]; + [self setTicker:@"connection error"]; } @end diff --git a/btcbar/btcbar-Info.plist b/btcbar/btcbar-Info.plist index f7cd4d5..3188a32 100644 --- a/btcbar/btcbar-Info.plist +++ b/btcbar/btcbar-Info.plist @@ -9,7 +9,7 @@ CFBundleIconFile Icon CFBundleIdentifier - nearengine.${PRODUCT_NAME:rfc1034identifier} + com.nearengine.${PRODUCT_NAME:rfc1034identifier} CFBundleInfoDictionaryVersion 6.0 CFBundleName @@ -17,7 +17,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 2.0 + 2.1 CFBundleSignature ???? CFBundleVersion