├── artwork ├── 1.png ├── 2.png ├── 3.png ├── Icon-72.png ├── iTunesArtwork ├── Icon-Small.png ├── Default~ipad.png ├── Icon-Small-50.png ├── Default-Landscape.png └── github_browser_icon.psd ├── iTunesArtwork ├── GithubBrowser ├── en.lproj │ ├── InfoPlist.strings │ └── DetailView.xib ├── zoomin.jpg ├── zoomout.jpg ├── Images │ ├── public.png │ ├── 19-gear.png │ ├── 53-house.png │ ├── Icon-72.png │ ├── private.png │ ├── 06-magnify.png │ ├── Icon-Small.png │ ├── full_screen.png │ ├── public-fork.png │ ├── Default~ipad.png │ ├── Icon-Small-50.png │ ├── private-fork.png │ └── Default-Landscape.png ├── UIWebViewBasicAuth │ ├── NSMutableURLRequest+BasicAuth.h │ ├── NSData+Additions.h │ ├── NSMutableURLRequest+BasicAuth.m │ └── NSData+Additions.m ├── UAGithubEngine │ ├── UAGithubEngine_Prefix.pch │ ├── NSString+UUID.h │ ├── UAGithubEngineConstants.m │ ├── UAGithubSimpleJSONParser.h │ ├── UAGithubUsersJSONParser.h │ ├── UAGithubIssuesJSONParser.h │ ├── UAGithubOrganizationsJSONParser.h │ ├── UAGithubCommitsJSONParser.h │ ├── NSArray+Utilities.h │ ├── UAGithubRepositoriesJSONParser.h │ ├── UAGithubIssueCommentsJSONParser.h │ ├── NSString+UAGithubEngineUtilities.h │ ├── UAGithubEngineConstants.h │ ├── NSString+UUID.m │ ├── UAReachability.h │ ├── UAGithubParserDelegate.h │ ├── UAGithubSimpleJSONParser.m │ ├── UAGithubOrganizationsJSONParser.m │ ├── NSArray+Utilities.m │ ├── UAGithubCommitsJSONParser.m │ ├── UAGithubIssuesJSONParser.m │ ├── UAGithubIssueCommentsJSONParser.m │ ├── UAGithubJSONParser.h │ ├── UAGithubUsersJSONParser.m │ ├── NSData+Base64.h │ ├── UAGithubRepositoriesJSONParser.m │ ├── UAGithubURLConnection.h │ ├── UAGithubURLConnection.m │ ├── Extensions │ │ ├── NSCharacterSet_Extensions.h │ │ ├── NSDictionary_JSONExtensions.h │ │ ├── CDataScanner_Extensions.h │ │ ├── NSDictionary_JSONExtensions.m │ │ ├── NSScanner_Extensions.h │ │ ├── NSCharacterSet_Extensions.m │ │ ├── CDataScanner_Extensions.m │ │ └── NSScanner_Extensions.m │ ├── JSON │ │ ├── CSerializedJSONData.h │ │ ├── CSerializedJSONData.m │ │ ├── CJSONDeserializer.h │ │ ├── CJSONDataSerializer.h │ │ ├── CJSONSerializer.h │ │ ├── CJSONScanner.h │ │ ├── CJSONSerializer.m │ │ ├── CJSONDeserializer.m │ │ └── CJSONDataSerializer.m │ ├── UAReachability.m │ ├── NSString+UAGithubEngineUtilities.m │ ├── CDataScanner.h │ ├── UAGithubEngineDelegate.h │ ├── README │ ├── UAGithubJSONParser.m │ ├── UAGithubEngineRequestTypes.h │ ├── UAGithubEngine.h │ ├── CDataScanner.m │ └── NSData+Base64.m ├── NSStringExtensions │ ├── NSString+DBExtensions.h │ └── NSString+DBExtensions.m ├── main.m ├── SearchViewController.h ├── Constants.h ├── GithubBrowser-Prefix.pch ├── SettingsViewController.h ├── RootViewController.h ├── MGSplitDividerView.h ├── Constants.m ├── GithubBrowserAppDelegate.h ├── ApplicationHelper.h ├── ReposViewController.h ├── GithubBrowserAppDelegate.m ├── DetailViewController.h ├── MGSplitCornersView.h ├── GithubBrowser-Info.plist ├── SearchViewController.m ├── SettingsViewController.m ├── ApplicationHelper.m ├── RootViewController.m ├── MGSplitDividerView.m ├── MGSplitCornersView.m ├── MGSplitViewController.h ├── ReposViewController.m ├── DetailViewController.m └── SearchViewController.xib ├── Default-Landscape~ipad.png ├── Default-Portrait~ipad.png ├── Readme.md ├── GithubBrowser.xcodeproj └── project.xcworkspace │ └── contents.xcworkspacedata └── .gitignore /artwork/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oscardelben/GithubBrowser/HEAD/artwork/1.png -------------------------------------------------------------------------------- /artwork/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oscardelben/GithubBrowser/HEAD/artwork/2.png -------------------------------------------------------------------------------- /artwork/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oscardelben/GithubBrowser/HEAD/artwork/3.png -------------------------------------------------------------------------------- /iTunesArtwork: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oscardelben/GithubBrowser/HEAD/iTunesArtwork -------------------------------------------------------------------------------- /GithubBrowser/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /artwork/Icon-72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oscardelben/GithubBrowser/HEAD/artwork/Icon-72.png -------------------------------------------------------------------------------- /artwork/iTunesArtwork: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oscardelben/GithubBrowser/HEAD/artwork/iTunesArtwork -------------------------------------------------------------------------------- /artwork/Icon-Small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oscardelben/GithubBrowser/HEAD/artwork/Icon-Small.png -------------------------------------------------------------------------------- /Default-Landscape~ipad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oscardelben/GithubBrowser/HEAD/Default-Landscape~ipad.png -------------------------------------------------------------------------------- /Default-Portrait~ipad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oscardelben/GithubBrowser/HEAD/Default-Portrait~ipad.png -------------------------------------------------------------------------------- /GithubBrowser/zoomin.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oscardelben/GithubBrowser/HEAD/GithubBrowser/zoomin.jpg -------------------------------------------------------------------------------- /GithubBrowser/zoomout.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oscardelben/GithubBrowser/HEAD/GithubBrowser/zoomout.jpg -------------------------------------------------------------------------------- /artwork/Default~ipad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oscardelben/GithubBrowser/HEAD/artwork/Default~ipad.png -------------------------------------------------------------------------------- /artwork/Icon-Small-50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oscardelben/GithubBrowser/HEAD/artwork/Icon-Small-50.png -------------------------------------------------------------------------------- /GithubBrowser/Images/public.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oscardelben/GithubBrowser/HEAD/GithubBrowser/Images/public.png -------------------------------------------------------------------------------- /artwork/Default-Landscape.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oscardelben/GithubBrowser/HEAD/artwork/Default-Landscape.png -------------------------------------------------------------------------------- /artwork/github_browser_icon.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oscardelben/GithubBrowser/HEAD/artwork/github_browser_icon.psd -------------------------------------------------------------------------------- /GithubBrowser/Images/19-gear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oscardelben/GithubBrowser/HEAD/GithubBrowser/Images/19-gear.png -------------------------------------------------------------------------------- /GithubBrowser/Images/53-house.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oscardelben/GithubBrowser/HEAD/GithubBrowser/Images/53-house.png -------------------------------------------------------------------------------- /GithubBrowser/Images/Icon-72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oscardelben/GithubBrowser/HEAD/GithubBrowser/Images/Icon-72.png -------------------------------------------------------------------------------- /GithubBrowser/Images/private.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oscardelben/GithubBrowser/HEAD/GithubBrowser/Images/private.png -------------------------------------------------------------------------------- /GithubBrowser/Images/06-magnify.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oscardelben/GithubBrowser/HEAD/GithubBrowser/Images/06-magnify.png -------------------------------------------------------------------------------- /GithubBrowser/Images/Icon-Small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oscardelben/GithubBrowser/HEAD/GithubBrowser/Images/Icon-Small.png -------------------------------------------------------------------------------- /GithubBrowser/Images/full_screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oscardelben/GithubBrowser/HEAD/GithubBrowser/Images/full_screen.png -------------------------------------------------------------------------------- /GithubBrowser/Images/public-fork.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oscardelben/GithubBrowser/HEAD/GithubBrowser/Images/public-fork.png -------------------------------------------------------------------------------- /GithubBrowser/Images/Default~ipad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oscardelben/GithubBrowser/HEAD/GithubBrowser/Images/Default~ipad.png -------------------------------------------------------------------------------- /GithubBrowser/Images/Icon-Small-50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oscardelben/GithubBrowser/HEAD/GithubBrowser/Images/Icon-Small-50.png -------------------------------------------------------------------------------- /GithubBrowser/Images/private-fork.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oscardelben/GithubBrowser/HEAD/GithubBrowser/Images/private-fork.png -------------------------------------------------------------------------------- /GithubBrowser/Images/Default-Landscape.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oscardelben/GithubBrowser/HEAD/GithubBrowser/Images/Default-Landscape.png -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | Github Browser 2 | ============== 3 | 4 | A minimalistic Github Browser for your iPad. 5 | 6 | Coming Soon. 7 | 8 | Icon by [@michelegera](http://twitter.com/michelegera) 9 | -------------------------------------------------------------------------------- /GithubBrowser/UIWebViewBasicAuth/NSMutableURLRequest+BasicAuth.h: -------------------------------------------------------------------------------- 1 | @interface NSMutableURLRequest (BasicAuth) 2 | 3 | - (void)addBasicAuth:(NSString *)username andPassword:(NSString *)password; 4 | 5 | @end 6 | -------------------------------------------------------------------------------- /GithubBrowser/UAGithubEngine/UAGithubEngine_Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'UAGithubEngine' target in the 'UAGithubEngine' project 3 | // 4 | 5 | #ifdef __OBJC__ 6 | #import 7 | #endif 8 | -------------------------------------------------------------------------------- /GithubBrowser.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /GithubBrowser/UAGithubEngine/NSString+UUID.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+UUID.h 3 | // MGTwitterEngine 4 | // 5 | // Created by Matt Gemmell on 16/09/2007. 6 | // Copyright 2008 Instinctive Code. 7 | // 8 | 9 | 10 | @interface NSString (UUID) 11 | 12 | + (NSString*)stringWithNewUUID; 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /GithubBrowser/UAGithubEngine/UAGithubEngineConstants.m: -------------------------------------------------------------------------------- 1 | // 2 | // UAGithubEngineConstants.m 3 | // IssuesHub 4 | // 5 | // Created by Owain Hunt on 11/11/2010. 6 | // Copyright 2010 Owain R Hunt. All rights reserved. 7 | // 8 | 9 | #import "UAGithubEngineConstants.h" 10 | 11 | 12 | NSString * const UAGithubAPILimitReached = @"UAGithubAPILimitReached"; 13 | 14 | 15 | -------------------------------------------------------------------------------- /GithubBrowser/NSStringExtensions/NSString+DBExtensions.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+DBExtensions.h 3 | // NSStringExtensions 4 | // 5 | // Created by Oscar Del Ben on 3/13/11. 6 | // Copyright 2011 DibiStore. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | @interface NSString (DBExtensions) 13 | 14 | - (NSString *)trim; 15 | 16 | - (BOOL)blank; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /GithubBrowser/UAGithubEngine/UAGithubSimpleJSONParser.h: -------------------------------------------------------------------------------- 1 | // 2 | // UAGithubSimpleJSONParser.h 3 | // UAGithubEngine 4 | // 5 | // Created by Owain Hunt on 02/08/2010. 6 | // Copyright 2010 Owain R Hunt. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | #import "UAGithubJSONParser.h" 13 | 14 | @interface UAGithubSimpleJSONParser : UAGithubJSONParser { 15 | 16 | } 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /GithubBrowser/UAGithubEngine/UAGithubUsersJSONParser.h: -------------------------------------------------------------------------------- 1 | // 2 | // UAGithubUsersJSONParser.h 3 | // UAGithubEngine 4 | // 5 | // Created by Owain Hunt on 27/07/2010. 6 | // Copyright 2010 Owain R Hunt. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | #import "UAGithubJSONParser.h" 13 | 14 | @interface UAGithubUsersJSONParser : UAGithubJSONParser { 15 | 16 | } 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /GithubBrowser/UAGithubEngine/UAGithubIssuesJSONParser.h: -------------------------------------------------------------------------------- 1 | // 2 | // UAGithubIssuesJSONParser.h 3 | // UAGithubEngine 4 | // 5 | // Created by Owain Hunt on 28/07/2010. 6 | // Copyright 2010 Owain R Hunt. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | #import "UAGithubJSONParser.h" 13 | 14 | 15 | @interface UAGithubIssuesJSONParser : UAGithubJSONParser { 16 | 17 | } 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /GithubBrowser/UAGithubEngine/UAGithubOrganizationsJSONParser.h: -------------------------------------------------------------------------------- 1 | // 2 | // UAGithubOrganizationsJSONParser.h 3 | // UAGithubEngine 4 | // 5 | // Created by Oscar Del Ben on 9/13/11. 6 | // Copyright (c) 2011 Fructivity. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "UAGithubJSONParser.h" 12 | 13 | @interface UAGithubOrganizationsJSONParser : UAGithubJSONParser 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /GithubBrowser/UAGithubEngine/UAGithubCommitsJSONParser.h: -------------------------------------------------------------------------------- 1 | // 2 | // UAGithubCommitsJSONParser.h 3 | // UAGithubEngine 4 | // 5 | // Created by Owain Hunt on 28/07/2010. 6 | // Copyright 2010 Owain R Hunt. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | #import "UAGithubJSONParser.h" 13 | 14 | 15 | @interface UAGithubCommitsJSONParser : UAGithubJSONParser { 16 | 17 | } 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /GithubBrowser/UAGithubEngine/NSArray+Utilities.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSArray+Utilities.h 3 | // UAGithubEngine 4 | // 5 | // Created by Owain Hunt on 27/07/2010. 6 | // Copyright 2010 Owain R Hunt. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface NSArray (Utilities) 12 | 13 | - (id)firstObject; 14 | - (NSArray *)sortedWithKey:(NSString *)theKey ascending:(BOOL)ascending; 15 | 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /GithubBrowser/UAGithubEngine/UAGithubRepositoriesJSONParser.h: -------------------------------------------------------------------------------- 1 | // 2 | // UAGithubRepositoriesJSONParser.h 3 | // UAGithubEngine 4 | // 5 | // Created by Owain Hunt on 27/07/2010. 6 | // Copyright 2010 Owain R Hunt. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | #import "UAGithubJSONParser.h" 13 | 14 | @interface UAGithubRepositoriesJSONParser : UAGithubJSONParser { 15 | 16 | } 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /GithubBrowser/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // GithubBrowser 4 | // 5 | // Created by Oscar Del Ben on 4/6/11. 6 | // Copyright 2011 DibiStore. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | int main(int argc, char *argv[]) 12 | { 13 | NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 14 | int retVal = UIApplicationMain(argc, argv, nil, nil); 15 | [pool release]; 16 | return retVal; 17 | } 18 | -------------------------------------------------------------------------------- /GithubBrowser/UAGithubEngine/UAGithubIssueCommentsJSONParser.h: -------------------------------------------------------------------------------- 1 | // 2 | // UAGithubIssueCommentsJSONParser.h 3 | // UAGithubEngine 4 | // 5 | // Created by Owain Hunt on 28/07/2010. 6 | // Copyright 2010 Owain R Hunt. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | #import "UAGithubJSONParser.h" 13 | 14 | 15 | @interface UAGithubIssueCommentsJSONParser : UAGithubJSONParser { 16 | 17 | } 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /GithubBrowser/UAGithubEngine/NSString+UAGithubEngineUtilities.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+UAGithubEngineUtilities.h 3 | // UAGithubEngine 4 | // 5 | // Created by Owain Hunt on 08/04/2010. 6 | // Copyright 2010 Owain R Hunt. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | 13 | @interface NSString(UAGithubEngineUtilities) 14 | 15 | - (NSDate *)dateFromGithubDateString; 16 | - (NSString *)encodedString; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /GithubBrowser/UAGithubEngine/UAGithubEngineConstants.h: -------------------------------------------------------------------------------- 1 | // 2 | // UAGithubEngineConstants.h 3 | // IssuesHub 4 | // 5 | // Created by Owain Hunt on 11/11/2010. 6 | // Copyright 2010 Owain R Hunt. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | extern NSString * const UAGithubAPILimitReached; 13 | 14 | #define UAGithubReachabilityStatusDidChangeNotification @"UAGithubReachabilityStatusDidChangeNotification" 15 | 16 | -------------------------------------------------------------------------------- /GithubBrowser/SearchViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // SearchViewController.h 3 | // GithubBrowser 4 | // 5 | // Created by Oscar Del Ben on 4/14/11. 6 | // Copyright 2011 DibiStore. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | @interface SearchViewController : UIViewController { 13 | 14 | } 15 | 16 | @property (nonatomic, retain) IBOutlet UITextField *usernameTextField; 17 | 18 | - (IBAction)cancel; 19 | - (IBAction)save; 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /GithubBrowser/UIWebViewBasicAuth/NSData+Additions.h: -------------------------------------------------------------------------------- 1 | //NSData additions from colloquy project 2 | 3 | @interface NSData (NSDataAdditions) 4 | + (NSData *) dataWithBase64EncodedString:(NSString *) string; 5 | - (id) initWithBase64EncodedString:(NSString *) string; 6 | 7 | - (NSString *) base64Encoding; 8 | - (NSString *) base64EncodingWithLineLength:(unsigned int) lineLength; 9 | 10 | - (BOOL) hasPrefix:(NSData *) prefix; 11 | - (BOOL) hasPrefixBytes:(void *) prefix length:(unsigned int) length; 12 | @end 13 | -------------------------------------------------------------------------------- /GithubBrowser/Constants.h: -------------------------------------------------------------------------------- 1 | // 2 | // Constants.h 3 | // GithubBrowser 4 | // 5 | // Created by Oscar Del Ben on 4/10/11. 6 | // Copyright 2011 DibiStore. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | extern NSString * const GBGithubUsername; 12 | extern NSString * const GBGithubPassword; 13 | 14 | extern NSString * const GBGithubCurrentUsername; 15 | 16 | extern NSString * const GBCredentialsChanged; 17 | extern NSString * const GBShowLoadIndicator; 18 | extern NSString * const GBHideLoadIndicator; -------------------------------------------------------------------------------- /GithubBrowser/GithubBrowser-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'GithubBrowser' target in the 'GithubBrowser' project 3 | // 4 | 5 | #import 6 | 7 | #ifndef __IPHONE_3_0 8 | #warning "This project uses features only available in iPhone SDK 3.0 and later." 9 | #endif 10 | 11 | #ifdef __OBJC__ 12 | #import 13 | #import 14 | #endif 15 | 16 | #import "UAGithubEngine.h" 17 | #import "Constants.h" 18 | #import "NSString+DBExtensions.h" 19 | #import "ApplicationHelper.h" -------------------------------------------------------------------------------- /GithubBrowser/SettingsViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // SettingsViewController.h 3 | // GithubBrowser 4 | // 5 | // Created by Oscar Del Ben on 4/9/11. 6 | // Copyright 2011 DibiStore. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class DetailViewController; 12 | 13 | @interface SettingsViewController : UIViewController { 14 | } 15 | 16 | @property (nonatomic, retain) IBOutlet UITextField *usernameTextField; 17 | @property (nonatomic, retain) IBOutlet UITextField *passwordTextField; 18 | 19 | - (void)cancel; 20 | - (IBAction)save; 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /GithubBrowser/NSStringExtensions/NSString+DBExtensions.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+DBExtensions.m 3 | // NSStringExtensions 4 | // 5 | // Created by Oscar Del Ben on 3/13/11. 6 | // Copyright 2011 DibiStore. All rights reserved. 7 | // 8 | 9 | #import "NSString+DBExtensions.h" 10 | 11 | 12 | @implementation NSString (DBExtensions) 13 | 14 | - (NSString *)trim 15 | { 16 | return [self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; 17 | } 18 | 19 | - (BOOL)blank 20 | { 21 | return [[self trim] isEqualToString:@""]; 22 | } 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /GithubBrowser/RootViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // RootViewController.h 3 | // GithubBrowser 4 | // 5 | // Created by Oscar Del Ben on 4/6/11. 6 | // Copyright 2011 DibiStore. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class DetailViewController; 12 | 13 | @interface RootViewController : UITableViewController { 14 | } 15 | 16 | @property (nonatomic, retain) IBOutlet DetailViewController *detailViewController; 17 | @property (nonatomic, retain) UAGithubEngine *githubEngine; 18 | @property (nonatomic, retain) NSString *username; 19 | - (void)showSettings; 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /GithubBrowser/MGSplitDividerView.h: -------------------------------------------------------------------------------- 1 | // 2 | // MGSplitDividerView.h 3 | // MGSplitView 4 | // 5 | // Created by Matt Gemmell on 26/07/2010. 6 | // Copyright 2010 Instinctive Code. 7 | // 8 | 9 | #import 10 | 11 | @class MGSplitViewController; 12 | @interface MGSplitDividerView : UIView { 13 | MGSplitViewController *splitViewController; 14 | BOOL allowsDragging; 15 | } 16 | 17 | @property (nonatomic, assign) MGSplitViewController *splitViewController; // weak ref. 18 | @property (nonatomic, assign) BOOL allowsDragging; 19 | 20 | - (void)drawGripThumbInRect:(CGRect)rect; 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /GithubBrowser/UIWebViewBasicAuth/NSMutableURLRequest+BasicAuth.m: -------------------------------------------------------------------------------- 1 | #import "NSMutableURLRequest+BasicAuth.h" 2 | #import "NSData+Additions.h" 3 | 4 | @implementation NSMutableURLRequest (BasicAuth) 5 | 6 | - (void)addBasicAuth:(NSString *)username andPassword:(NSString *)password 7 | { 8 | NSString *authString = [[[NSString stringWithFormat:@"%@:%@", username, password] dataUsingEncoding:NSUTF8StringEncoding] base64Encoding]; 9 | 10 | authString = [NSString stringWithFormat: @"Basic %@", authString]; 11 | 12 | [self setValue:authString forHTTPHeaderField:@"Authorization"]; 13 | } 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /GithubBrowser/UAGithubEngine/NSString+UUID.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+UUID.m 3 | // MGTwitterEngine 4 | // 5 | // Created by Matt Gemmell on 16/09/2007. 6 | // Copyright 2008 Instinctive Code. 7 | // 8 | 9 | #import "NSString+UUID.h" 10 | 11 | 12 | @implementation NSString (UUID) 13 | 14 | 15 | + (NSString*)stringWithNewUUID 16 | { 17 | // Create a new UUID 18 | CFUUIDRef uuidObj = CFUUIDCreate(nil); 19 | 20 | // Get the string representation of the UUID 21 | NSString *newUUID = (NSString*)CFUUIDCreateString(nil, uuidObj); 22 | CFRelease(uuidObj); 23 | return [newUUID autorelease]; 24 | } 25 | 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /GithubBrowser/UAGithubEngine/UAReachability.h: -------------------------------------------------------------------------------- 1 | // 2 | // UAReachability.h 3 | // ReachTest 4 | // 5 | // Created by Owain Hunt on 10/01/2011. 6 | // Copyright 2011 Owain R Hunt. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | typedef enum { 13 | NotReachable = 0, 14 | Reachable, 15 | } NetworkStatus; 16 | 17 | 18 | @interface UAReachability : NSObject { 19 | SCNetworkReachabilityRef reachabilityRef; 20 | } 21 | 22 | 23 | - (NetworkStatus)networkStatusForFlags:(SCNetworkReachabilityFlags)flags; 24 | - (NetworkStatus)currentReachabilityStatus; 25 | 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /GithubBrowser/Constants.m: -------------------------------------------------------------------------------- 1 | // 2 | // Constants.m 3 | // GithubBrowser 4 | // 5 | // Created by Oscar Del Ben on 4/10/11. 6 | // Copyright 2011 DibiStore. All rights reserved. 7 | // 8 | 9 | #import "Constants.h" 10 | 11 | NSString * const GBGithubUsername = @"GBGithubUsername"; 12 | NSString * const GBGithubPassword = @"GBGithubPassword"; 13 | 14 | NSString * const GBGithubCurrentUsername = @"GBGithubCurrentUsername"; 15 | 16 | NSString * const GBCredentialsChanged = @"GBCredentialsChanged"; 17 | NSString * const GBShowLoadIndicator = @"GBShowLoadIndicator"; 18 | NSString * const GBHideLoadIndicator = @"GBHideLoadIndicator"; 19 | -------------------------------------------------------------------------------- /GithubBrowser/UAGithubEngine/UAGithubParserDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // UAGithubParserDelegate.h 3 | // UAGithubEngine 4 | // 5 | // Created by Owain Hunt on 05/04/2010. 6 | // Copyright 2010 Owain R Hunt. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "UAGithubEngineRequestTypes.h" 11 | 12 | 13 | @protocol UAGithubParserDelegate 14 | 15 | - (void)parsingSucceededForConnection:(NSString *)connectionIdentifier ofResponseType:(UAGithubResponseType)responseType withParsedObjects:(NSArray *)parsedObjects; 16 | - (void)parsingFailedForConnection:(NSString *)connectionIdentifier ofResponseType:(UAGithubResponseType)responseType withError:(NSError *)parseError; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /GithubBrowser/UAGithubEngine/UAGithubSimpleJSONParser.m: -------------------------------------------------------------------------------- 1 | // 2 | // UAGithubSimpleJSONParser.m 3 | // UAGithubEngine 4 | // 5 | // Created by Owain Hunt on 02/08/2010. 6 | // Copyright 2010 Owain R Hunt. All rights reserved. 7 | // 8 | 9 | #import "UAGithubSimpleJSONParser.h" 10 | 11 | @implementation UAGithubSimpleJSONParser 12 | 13 | - (id)initWithJSON:(NSData *)theJSON delegate:(id)theDelegate connectionIdentifier:(NSString *)theIdentifier requestType:(UAGithubRequestType)reqType responseType:(UAGithubResponseType)respType 14 | { 15 | 16 | self = [super initWithJSON:theJSON delegate:theDelegate connectionIdentifier:theIdentifier requestType:reqType responseType:respType]; 17 | [self parse]; 18 | 19 | return self; 20 | } 21 | 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /GithubBrowser/GithubBrowserAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // GithubBrowserAppDelegate.h 3 | // GithubBrowser 4 | // 5 | // Created by Oscar Del Ben on 4/6/11. 6 | // Copyright 2011 DibiStore. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class MGSplitViewController; 12 | @class RootViewController; 13 | @class DetailViewController; 14 | 15 | @interface GithubBrowserAppDelegate : NSObject { 16 | 17 | } 18 | 19 | @property (nonatomic, retain) IBOutlet UIWindow *window; 20 | 21 | @property (nonatomic, retain) IBOutlet MGSplitViewController *splitViewController; 22 | 23 | @property (nonatomic, retain) IBOutlet RootViewController *rootViewController; 24 | 25 | @property (nonatomic, retain) IBOutlet DetailViewController *detailViewController; 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /GithubBrowser/UAGithubEngine/UAGithubOrganizationsJSONParser.m: -------------------------------------------------------------------------------- 1 | // 2 | // UAGithubOrganizationsJSONParser.m 3 | // UAGithubEngine 4 | // 5 | // Created by Oscar Del Ben on 9/13/11. 6 | // Copyright (c) 2011 Fructivity. All rights reserved. 7 | // 8 | 9 | #import "UAGithubOrganizationsJSONParser.h" 10 | 11 | @implementation UAGithubOrganizationsJSONParser 12 | 13 | - (id)initWithJSON:(NSData *)theJSON delegate:(id)theDelegate connectionIdentifier:(NSString *)theIdentifier requestType:(UAGithubRequestType)reqType responseType:(UAGithubResponseType)respType 14 | { 15 | 16 | if ((self = [super initWithJSON:theJSON delegate:theDelegate connectionIdentifier:theIdentifier requestType:reqType responseType:respType])) 17 | { 18 | 19 | } 20 | 21 | [self parse]; 22 | 23 | return self; 24 | } 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /GithubBrowser/ApplicationHelper.h: -------------------------------------------------------------------------------- 1 | // 2 | // ApplicationHelper.h 3 | // GithubBrowser 4 | // 5 | // Created by Oscar Del Ben on 4/11/11. 6 | // Copyright 2011 DibiStore. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | @interface ApplicationHelper : NSObject { 13 | 14 | } 15 | 16 | + (NSString *)currentUsername; 17 | + (NSString *)username; 18 | + (NSString *)password; 19 | 20 | + (BOOL)validUsername:(NSString *)username; 21 | + (BOOL)usingDefaultUser; 22 | 23 | + (void)sendCredentialsChangedNotification; 24 | + (void)saveCredentials:(NSString *)username password:(NSString *)password notifyOfChange:(BOOL)notify; 25 | + (void)setCurrentUsername:(NSString *)username notifyOfChange:(BOOL)notify; 26 | 27 | + (void)loadWebViewFromUrl:(UIWebView *)webView url:(NSString *)string; 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /GithubBrowser/ReposViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ReposViewController.h 3 | // GithubBrowser 4 | // 5 | // Created by Oscar Del Ben on 9/13/11. 6 | // Copyright (c) 2011 DibiStore. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class DetailViewController; 12 | 13 | @interface ReposViewController : UITableViewController { 14 | } 15 | 16 | 17 | @property (nonatomic, retain) DetailViewController *detailViewController; 18 | 19 | @property (nonatomic, retain) UAGithubEngine *githubEngine; 20 | @property (nonatomic, retain) NSMutableArray *repos; 21 | 22 | @property (nonatomic, retain) UIBarButtonItem *searchButton; 23 | @property (nonatomic, assign) int currentPage; 24 | 25 | - (void)showSearchSheet; 26 | - (void)reloadRepos; 27 | - (void)loadUsername:(NSString *)username; 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /GithubBrowser/UAGithubEngine/NSArray+Utilities.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSArray+Utilities.m 3 | // UAGithubEngine 4 | // 5 | // Created by Owain Hunt on 27/07/2010. 6 | // Copyright 2010 Owain R Hunt. All rights reserved. 7 | // 8 | // Credit: http://troybrant.net/blog/2010/02/adding-firstobject-to-nsarray/ 9 | 10 | #import "NSArray+Utilities.h" 11 | 12 | 13 | @implementation NSArray (Utilities) 14 | 15 | - (id)firstObject 16 | { 17 | if ([self count] > 0) 18 | { 19 | return [self objectAtIndex:0]; 20 | } 21 | return nil; 22 | } 23 | 24 | 25 | - (NSArray *)sortedWithKey:(NSString *)theKey ascending:(BOOL)ascending 26 | { 27 | return [self sortedArrayUsingDescriptors:[NSArray arrayWithObject:[[[NSSortDescriptor alloc] initWithKey:theKey ascending:ascending selector:@selector(caseInsensitiveCompare:)] autorelease]]]; 28 | } 29 | 30 | 31 | @end -------------------------------------------------------------------------------- /GithubBrowser/UAGithubEngine/UAGithubCommitsJSONParser.m: -------------------------------------------------------------------------------- 1 | // 2 | // UAGithubCommitsJSONParser.m 3 | // UAGithubEngine 4 | // 5 | // Created by Owain Hunt on 28/07/2010. 6 | // Copyright 2010 Owain R Hunt. All rights reserved. 7 | // 8 | 9 | #import "UAGithubCommitsJSONParser.h" 10 | 11 | 12 | @implementation UAGithubCommitsJSONParser 13 | 14 | - (id)initWithJSON:(NSData *)theJSON delegate:(id)theDelegate connectionIdentifier:(NSString *)theIdentifier requestType:(UAGithubRequestType)reqType responseType:(UAGithubResponseType)respType 15 | { 16 | 17 | if ((self = [super initWithJSON:theJSON delegate:theDelegate connectionIdentifier:theIdentifier requestType:reqType responseType:respType])) 18 | { 19 | dateElements = [NSArray arrayWithObjects:@"committed_date", @"authored_date", nil]; 20 | } 21 | 22 | [self parse]; 23 | 24 | return self; 25 | } 26 | 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /GithubBrowser/UAGithubEngine/UAGithubIssuesJSONParser.m: -------------------------------------------------------------------------------- 1 | // 2 | // UAGithubIssuesJSONParser.m 3 | // UAGithubEngine 4 | // 5 | // Created by Owain Hunt on 28/07/2010. 6 | // Copyright 2010 Owain R Hunt. All rights reserved. 7 | // 8 | 9 | #import "UAGithubIssuesJSONParser.h" 10 | 11 | 12 | @implementation UAGithubIssuesJSONParser 13 | 14 | - (id)initWithJSON:(NSData *)theJSON delegate:(id)theDelegate connectionIdentifier:(NSString *)theIdentifier requestType:(UAGithubRequestType)reqType responseType:(UAGithubResponseType)respType 15 | { 16 | 17 | if ((self = [super initWithJSON:theJSON delegate:theDelegate connectionIdentifier:theIdentifier requestType:reqType responseType:respType])) 18 | { 19 | dateElements = [NSArray arrayWithObjects:@"created_at", @"updated_at", @"closed_at", nil]; 20 | } 21 | 22 | [self parse]; 23 | 24 | return self; 25 | } 26 | 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /GithubBrowser/UAGithubEngine/UAGithubIssueCommentsJSONParser.m: -------------------------------------------------------------------------------- 1 | // 2 | // UAGithubIssueCommentsJSONParser.m 3 | // UAGithubEngine 4 | // 5 | // Created by Owain Hunt on 28/07/2010. 6 | // Copyright 2010 Owain R Hunt. All rights reserved. 7 | // 8 | 9 | #import "UAGithubIssueCommentsJSONParser.h" 10 | 11 | 12 | @implementation UAGithubIssueCommentsJSONParser 13 | 14 | - (id)initWithJSON:(NSData *)theJSON delegate:(id)theDelegate connectionIdentifier:(NSString *)theIdentifier requestType:(UAGithubRequestType)reqType responseType:(UAGithubResponseType)respType 15 | { 16 | 17 | if ((self = [super initWithJSON:theJSON delegate:theDelegate connectionIdentifier:theIdentifier requestType:reqType responseType:respType])) 18 | { 19 | dateElements = [NSArray arrayWithObjects:@"created_at", @"updated_at", nil]; 20 | } 21 | 22 | [self parse]; 23 | 24 | return self; 25 | } 26 | 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /GithubBrowser/UAGithubEngine/UAGithubJSONParser.h: -------------------------------------------------------------------------------- 1 | // 2 | // UAGithubJSONParser.h 3 | // UAGithubEngine 4 | // 5 | // Created by Owain Hunt on 27/07/2010. 6 | // Copyright 2010 Owain R Hunt. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "UAGithubParserDelegate.h" 12 | #import "UAGithubEngineRequestTypes.h" 13 | 14 | @interface UAGithubJSONParser : NSObject { 15 | id delegate; 16 | NSString *connectionIdentifier; 17 | UAGithubRequestType requestType; 18 | UAGithubResponseType responseType; 19 | NSData *json; 20 | 21 | NSArray *boolElements; 22 | NSArray *dateElements; 23 | 24 | } 25 | 26 | - (id)initWithJSON:(NSData *)theJSON delegate:(id)theDelegate connectionIdentifier:(NSString *)theIdentifier requestType:(UAGithubRequestType)reqType responseType:(UAGithubResponseType)respType; 27 | - (void)parse; 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /GithubBrowser/UAGithubEngine/UAGithubUsersJSONParser.m: -------------------------------------------------------------------------------- 1 | // 2 | // UAGithubUsersJSONParser.m 3 | // UAGithubEngine 4 | // 5 | // Created by Owain Hunt on 27/07/2010. 6 | // Copyright 2010 Owain R Hunt. All rights reserved. 7 | // 8 | 9 | #import "UAGithubUsersJSONParser.h" 10 | #import "CJSONDeserializer.h" 11 | 12 | @implementation UAGithubUsersJSONParser 13 | 14 | - (id)initWithJSON:(NSData *)theJSON delegate:(id)theDelegate connectionIdentifier:(NSString *)theIdentifier requestType:(UAGithubRequestType)reqType responseType:(UAGithubResponseType)respType 15 | { 16 | 17 | if ((self = [super initWithJSON:theJSON delegate:theDelegate connectionIdentifier:theIdentifier requestType:reqType responseType:respType])) 18 | { 19 | dateElements = [NSArray arrayWithObjects:@"created_at", @"created", @"pushed", nil]; 20 | } 21 | 22 | [self parse]; 23 | 24 | return self; 25 | } 26 | 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # taken from http://blog.illuminex.com/2009/10/better-sample-gitignore-file-for-xcode.html 2 | 3 | # Mac OS X Finder and whatnot 4 | .DS_Store 5 | 6 | 7 | # Sparkle distribution Private Key (Don't check me in!) 8 | dsa_priv.pem 9 | 10 | 11 | # XCode (and ancestors) per-user config (very noisy, and not relevant) 12 | *.mode1 13 | *.mode1v3 14 | *.mode2v3 15 | *.perspective 16 | *.perspectivev3 17 | *.pbxuser 18 | 19 | # Xcode 4 http://stackoverflow.com/questions/49478/git-ignore-file-for-xcode-projects 20 | xcuserdata 21 | 22 | 23 | # Generated files 24 | VersionX-revision.h 25 | 26 | 27 | # build products 28 | build/ 29 | *.[oa] 30 | 31 | # Other source repository archive directories (protects when importing) 32 | .hg 33 | .svn 34 | CVS 35 | 36 | 37 | # automatic backup files 38 | *~.nib 39 | *.swp 40 | *~ 41 | *(Autosaved).rtfd/ 42 | Backup[ ]of[ ]*.pages/ 43 | Backup[ ]of[ ]*.key/ 44 | Backup[ ]of[ ]*.numbers/ 45 | 46 | -------------------------------------------------------------------------------- /GithubBrowser/UAGithubEngine/NSData+Base64.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSData+Base64.h 3 | // base64 4 | // 5 | // Created by Matt Gallagher on 2009/06/03. 6 | // Copyright 2009 Matt Gallagher. All rights reserved. 7 | // 8 | // Permission is given to use this source code file, free of charge, in any 9 | // project, commercial or otherwise, entirely at your risk, with the condition 10 | // that any redistribution (in part or whole) of source code must retain 11 | // this copyright and permission notice. Attribution in compiled projects is 12 | // appreciated but not required. 13 | // 14 | 15 | #import 16 | 17 | void *NewBase64Decode( 18 | const char *inputBuffer, 19 | size_t length, 20 | size_t *outputLength); 21 | 22 | char *NewBase64Encode( 23 | const void *inputBuffer, 24 | size_t length, 25 | bool separateLines, 26 | size_t *outputLength); 27 | 28 | @interface NSData (Base64) 29 | 30 | + (NSData *)dataFromBase64String:(NSString *)aString; 31 | - (NSString *)base64EncodedString; 32 | 33 | @end 34 | -------------------------------------------------------------------------------- /GithubBrowser/UAGithubEngine/UAGithubRepositoriesJSONParser.m: -------------------------------------------------------------------------------- 1 | // 2 | // UAGithubRepositoriesJSONParser.m 3 | // UAGithubEngine 4 | // 5 | // Created by Owain Hunt on 27/07/2010. 6 | // Copyright 2010 Owain R Hunt. All rights reserved. 7 | // 8 | 9 | #import "UAGithubRepositoriesJSONParser.h" 10 | 11 | 12 | @implementation UAGithubRepositoriesJSONParser 13 | 14 | - (id)initWithJSON:(NSData *)theJSON delegate:(id)theDelegate connectionIdentifier:(NSString *)theIdentifier requestType:(UAGithubRequestType)reqType responseType:(UAGithubResponseType)respType 15 | { 16 | if ((self = [super initWithJSON:theJSON delegate:theDelegate connectionIdentifier:theIdentifier requestType:reqType responseType:respType])) 17 | { 18 | boolElements = [NSArray arrayWithObjects:@"has_issues", @"has_downloads", @"fork", @"has_wiki", @"private", nil]; 19 | dateElements = [NSArray arrayWithObjects:@"created_at", @"pushed_at", @"created", @"pushed", nil]; 20 | } 21 | 22 | [self parse]; 23 | 24 | return self; 25 | } 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /GithubBrowser/UAGithubEngine/UAGithubURLConnection.h: -------------------------------------------------------------------------------- 1 | // 2 | // UAGithubURLConnection.h 3 | // UAGithubEngine 4 | // 5 | // Created by Owain Hunt on 26/04/2010. 6 | // Copyright 2010 Owain R Hunt. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "UAGithubEngineRequestTypes.h" 11 | 12 | @interface UAGithubURLConnection : NSURLConnection 13 | { 14 | NSMutableData *data; 15 | UAGithubRequestType requestType; 16 | UAGithubResponseType responseType; 17 | NSString *identifier; 18 | } 19 | 20 | 21 | @property (nonatomic, retain) NSMutableData *data; 22 | @property (nonatomic, assign) UAGithubRequestType requestType; 23 | @property (nonatomic, assign) UAGithubResponseType responseType; 24 | @property (nonatomic, retain) NSString *identifier; 25 | 26 | - (id)initWithRequest:(NSURLRequest *)request delegate:(id)delegate requestType:(UAGithubRequestType)reqType responseType:(UAGithubResponseType)respType; 27 | - (void)resetDataLength; 28 | - (void)appendData:(NSData *)newData; 29 | 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /GithubBrowser/GithubBrowserAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // GithubBrowserAppDelegate.m 3 | // GithubBrowser 4 | // 5 | // Created by Oscar Del Ben on 4/6/11. 6 | // Copyright 2011 DibiStore. All rights reserved. 7 | // 8 | 9 | #import "GithubBrowserAppDelegate.h" 10 | 11 | #import "MGSplitViewController.h" 12 | #import "RootViewController.h" 13 | #import "DetailViewController.h" 14 | 15 | @implementation GithubBrowserAppDelegate 16 | 17 | 18 | @synthesize window=_window; 19 | 20 | @synthesize splitViewController=_splitViewController; 21 | 22 | @synthesize rootViewController=_rootViewController; 23 | 24 | @synthesize detailViewController=_detailViewController; 25 | 26 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 27 | { 28 | [_window addSubview:_splitViewController.view]; 29 | [self.window makeKeyAndVisible]; 30 | 31 | return YES; 32 | } 33 | 34 | - (void)dealloc 35 | { 36 | [_window release]; 37 | [_splitViewController release]; 38 | [_rootViewController release]; 39 | [_detailViewController release]; 40 | [super dealloc]; 41 | } 42 | 43 | @end 44 | -------------------------------------------------------------------------------- /GithubBrowser/DetailViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // DetailViewController.h 3 | // GithubBrowser 4 | // 5 | // Created by Oscar Del Ben on 4/6/11. 6 | // Copyright 2011 DibiStore. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "MGSplitViewController.h" 11 | 12 | @interface DetailViewController : UIViewController 13 | 14 | @property (nonatomic, retain) IBOutlet MGSplitViewController *splitController; 15 | @property (nonatomic, retain) IBOutlet UIToolbar *toolbar; 16 | @property (nonatomic, retain) id detailItem; 17 | @property (nonatomic, retain) IBOutlet UIWebView *webView; 18 | @property (nonatomic, retain) UIBarButtonItem *titleBarButtonItem; 19 | @property (nonatomic, retain) UIBarButtonItem *loadUserItem; 20 | @property (nonatomic, retain) UIActivityIndicatorView *activityIndicator; 21 | @property (nonatomic, retain) NSString *matchedUsername; 22 | 23 | - (void)showGithubHomepage; 24 | - (void)showHome; 25 | - (void)showSearch; 26 | - (void)showRandomRepo; 27 | - (void)loadMatchedUserRepos; 28 | - (void)loadUserPage; 29 | 30 | - (void)showLoadIndicator; 31 | - (void)hideLoadIndicator; 32 | 33 | @end 34 | -------------------------------------------------------------------------------- /GithubBrowser/MGSplitCornersView.h: -------------------------------------------------------------------------------- 1 | // 2 | // MGSplitCornersView.h 3 | // MGSplitView 4 | // 5 | // Created by Matt Gemmell on 28/07/2010. 6 | // Copyright 2010 Instinctive Code. 7 | // 8 | 9 | #import 10 | 11 | typedef enum _MGCornersPosition { 12 | MGCornersPositionLeadingVertical = 0, // top of screen for a left/right split. 13 | MGCornersPositionTrailingVertical = 1, // bottom of screen for a left/right split. 14 | MGCornersPositionLeadingHorizontal = 2, // left of screen for a top/bottom split. 15 | MGCornersPositionTrailingHorizontal = 3 // right of screen for a top/bottom split. 16 | } MGCornersPosition; 17 | 18 | @class MGSplitViewController; 19 | @interface MGSplitCornersView : UIView { 20 | float cornerRadius; 21 | MGSplitViewController *splitViewController; 22 | MGCornersPosition cornersPosition; 23 | UIColor *cornerBackgroundColor; 24 | } 25 | 26 | @property (nonatomic, assign) float cornerRadius; 27 | @property (nonatomic, assign) MGSplitViewController *splitViewController; // weak ref. 28 | @property (nonatomic, assign) MGCornersPosition cornersPosition; // don't change this manually; let the splitViewController manage it. 29 | @property (nonatomic, retain) UIColor *cornerBackgroundColor; 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /GithubBrowser/UAGithubEngine/UAGithubURLConnection.m: -------------------------------------------------------------------------------- 1 | // 2 | // UAGithubURLConnection.m 3 | // UAGithubEngine 4 | // 5 | // Created by Owain Hunt on 26/04/2010. 6 | // Copyright 2010 Owain R Hunt. All rights reserved. 7 | // 8 | 9 | #import "UAGithubURLConnection.h" 10 | #import "NSString+UUID.h" 11 | 12 | 13 | @implementation UAGithubURLConnection 14 | 15 | @synthesize data, requestType, responseType, identifier; 16 | 17 | - (id)initWithRequest:(NSURLRequest *)request delegate:(id)delegate requestType:(UAGithubRequestType)reqType responseType:(UAGithubResponseType)respType 18 | { 19 | if ((self = [super initWithRequest:request delegate:delegate])) { 20 | data = [[NSMutableData alloc] initWithCapacity:0]; 21 | identifier = [[NSString stringWithNewUUID] retain]; 22 | requestType = reqType; 23 | responseType = respType; 24 | } 25 | NSLog(@"New %@ connection: %@, %@", request.HTTPMethod, request, identifier); 26 | 27 | return self; 28 | } 29 | 30 | - (void)resetDataLength 31 | { 32 | [data setLength:0]; 33 | } 34 | 35 | 36 | - (void)appendData:(NSData *)newData 37 | { 38 | [data appendData:newData]; 39 | } 40 | 41 | - (void)dealloc 42 | { 43 | [data release]; 44 | [identifier release]; 45 | 46 | [super dealloc]; 47 | } 48 | 49 | 50 | @end 51 | -------------------------------------------------------------------------------- /GithubBrowser/UAGithubEngine/Extensions/NSCharacterSet_Extensions.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSCharacterSet_Extensions.h 3 | // TouchCode 4 | // 5 | // Created by Jonathan Wight on 12/08/2005. 6 | // Copyright 2005 toxicsoftware.com. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person 9 | // obtaining a copy of this software and associated documentation 10 | // files (the "Software"), to deal in the Software without 11 | // restriction, including without limitation the rights to use, 12 | // copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the 14 | // Software is furnished to do so, subject to the following 15 | // conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be 18 | // included in all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 22 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 24 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 25 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 26 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 27 | // OTHER DEALINGS IN THE SOFTWARE. 28 | // 29 | 30 | #import 31 | 32 | @interface NSCharacterSet (NSCharacterSet_Extensions) 33 | 34 | + (NSCharacterSet *)linebreaksCharacterSet; 35 | 36 | @end 37 | -------------------------------------------------------------------------------- /GithubBrowser/GithubBrowser-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIconFile 12 | 13 | CFBundleIconFiles 14 | 15 | Icon-72.png 16 | Icon-Small-50.png 17 | Icon-Small 18 | 19 | CFBundleIdentifier 20 | com.oscardelben.foo${PRODUCT_NAME:rfc1034identifier} 21 | CFBundleInfoDictionaryVersion 22 | 6.0 23 | CFBundleName 24 | ${PRODUCT_NAME} 25 | CFBundlePackageType 26 | APPL 27 | CFBundleShortVersionString 28 | 1.0 29 | CFBundleSignature 30 | ???? 31 | CFBundleVersion 32 | 1.0 33 | LSRequiresIPhoneOS 34 | 35 | NSMainNibFile 36 | MainWindow 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /GithubBrowser/UAGithubEngine/Extensions/NSDictionary_JSONExtensions.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSDictionary_JSONExtensions.h 3 | // TouchCode 4 | // 5 | // Created by Jonathan Wight on 04/17/08. 6 | // Copyright 2008 toxicsoftware.com. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person 9 | // obtaining a copy of this software and associated documentation 10 | // files (the "Software"), to deal in the Software without 11 | // restriction, including without limitation the rights to use, 12 | // copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the 14 | // Software is furnished to do so, subject to the following 15 | // conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be 18 | // included in all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 22 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 24 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 25 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 26 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 27 | // OTHER DEALINGS IN THE SOFTWARE. 28 | // 29 | 30 | #import 31 | 32 | @interface NSDictionary (NSDictionary_JSONExtensions) 33 | 34 | + (id)dictionaryWithJSONData:(NSData *)inData error:(NSError **)outError; 35 | 36 | @end 37 | -------------------------------------------------------------------------------- /GithubBrowser/UAGithubEngine/Extensions/CDataScanner_Extensions.h: -------------------------------------------------------------------------------- 1 | // 2 | // CDataScanner_Extensions.h 3 | // TouchCode 4 | // 5 | // Created by Jonathan Wight on 12/08/2005. 6 | // Copyright 2005 toxicsoftware.com. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person 9 | // obtaining a copy of this software and associated documentation 10 | // files (the "Software"), to deal in the Software without 11 | // restriction, including without limitation the rights to use, 12 | // copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the 14 | // Software is furnished to do so, subject to the following 15 | // conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be 18 | // included in all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 22 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 24 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 25 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 26 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 27 | // OTHER DEALINGS IN THE SOFTWARE. 28 | // 29 | 30 | #import "CDataScanner.h" 31 | 32 | @interface CDataScanner (CDataScanner_Extensions) 33 | 34 | - (BOOL)scanCStyleComment:(NSString **)outComment; 35 | - (BOOL)scanCPlusPlusStyleComment:(NSString **)outComment; 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /GithubBrowser/UAGithubEngine/JSON/CSerializedJSONData.h: -------------------------------------------------------------------------------- 1 | // 2 | // CSerializedJSONData.h 3 | // TouchCode 4 | // 5 | // Created by Jonathan Wight on 10/23/09. 6 | // Copyright 2009 toxicsoftware.com. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person 9 | // obtaining a copy of this software and associated documentation 10 | // files (the "Software"), to deal in the Software without 11 | // restriction, including without limitation the rights to use, 12 | // copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the 14 | // Software is furnished to do so, subject to the following 15 | // conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be 18 | // included in all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 22 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 24 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 25 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 26 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 27 | // OTHER DEALINGS IN THE SOFTWARE. 28 | // 29 | 30 | #import 31 | 32 | @interface CSerializedJSONData : NSObject { 33 | NSData *data; 34 | } 35 | 36 | @property (readonly, nonatomic, retain) NSData *data; 37 | 38 | - (id)initWithData:(NSData *)inData; 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /GithubBrowser/UAGithubEngine/Extensions/NSDictionary_JSONExtensions.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSDictionary_JSONExtensions.m 3 | // TouchCode 4 | // 5 | // Created by Jonathan Wight on 04/17/08. 6 | // Copyright 2008 toxicsoftware.com. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person 9 | // obtaining a copy of this software and associated documentation 10 | // files (the "Software"), to deal in the Software without 11 | // restriction, including without limitation the rights to use, 12 | // copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the 14 | // Software is furnished to do so, subject to the following 15 | // conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be 18 | // included in all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 22 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 24 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 25 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 26 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 27 | // OTHER DEALINGS IN THE SOFTWARE. 28 | // 29 | 30 | #import "NSDictionary_JSONExtensions.h" 31 | 32 | #import "CJSONDeserializer.h" 33 | 34 | @implementation NSDictionary (NSDictionary_JSONExtensions) 35 | 36 | + (id)dictionaryWithJSONData:(NSData *)inData error:(NSError **)outError 37 | { 38 | return([[CJSONDeserializer deserializer] deserialize:inData error:outError]); 39 | } 40 | 41 | @end 42 | -------------------------------------------------------------------------------- /GithubBrowser/UAGithubEngine/UAReachability.m: -------------------------------------------------------------------------------- 1 | // 2 | // UAReachability.m 3 | // ReachTest 4 | // 5 | // Created by Owain Hunt on 10/01/2011. 6 | // Copyright 2011 Owain R Hunt. All rights reserved. 7 | // 8 | 9 | #import "UAReachability.h" 10 | #import "UAGithubEngineConstants.h" 11 | #import 12 | 13 | @implementation UAReachability 14 | 15 | // http://www.cocoabuilder.com/archive/cocoa/166350-detecting-internet-code-part-1.html#166364 16 | 17 | static void reachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void* info) 18 | { 19 | [[NSNotificationCenter defaultCenter] postNotificationName:UAGithubReachabilityStatusDidChangeNotification object:info]; 20 | } 21 | 22 | 23 | - (id)init 24 | { 25 | if ((self = [super init])) 26 | { 27 | reachabilityRef = SCNetworkReachabilityCreateWithName(NULL, [@"www.github.com" UTF8String]); 28 | SCNetworkReachabilityContext context = {0, self, CFRetain, CFRelease, NULL}; 29 | SCNetworkReachabilitySetCallback(reachabilityRef, reachabilityCallback, &context); 30 | SCNetworkReachabilityScheduleWithRunLoop(reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); 31 | } 32 | 33 | return self; 34 | } 35 | 36 | 37 | - (NetworkStatus)currentReachabilityStatus 38 | { 39 | SCNetworkReachabilityFlags flags; 40 | return (SCNetworkReachabilityGetFlags(reachabilityRef, &flags) && (flags & kSCNetworkReachabilityFlagsReachable) && !(flags & kSCNetworkReachabilityFlagsConnectionRequired)); 41 | } 42 | 43 | 44 | - (NetworkStatus)networkStatusForFlags:(SCNetworkReachabilityFlags)flags 45 | { 46 | return (flags & kSCNetworkReachabilityFlagsReachable) && !(flags & kSCNetworkReachabilityFlagsConnectionRequired); 47 | } 48 | 49 | 50 | @end 51 | -------------------------------------------------------------------------------- /GithubBrowser/SearchViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // SearchViewController.m 3 | // GithubBrowser 4 | // 5 | // Created by Oscar Del Ben on 4/14/11. 6 | // Copyright 2011 DibiStore. All rights reserved. 7 | // 8 | 9 | #import "SearchViewController.h" 10 | 11 | 12 | @implementation SearchViewController 13 | 14 | @synthesize usernameTextField; 15 | 16 | 17 | - (void)dealloc 18 | { 19 | [usernameTextField release]; 20 | [super dealloc]; 21 | } 22 | 23 | #pragma mark - View lifecycle 24 | 25 | - (void)viewDidLoad 26 | { 27 | UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(cancel)]; 28 | UIBarButtonItem *saveButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(save)]; 29 | 30 | self.navigationItem.leftBarButtonItem = cancelButton; 31 | self.navigationItem.rightBarButtonItem = saveButton; 32 | 33 | [cancelButton release]; 34 | [saveButton release]; 35 | } 36 | 37 | - (void)viewDidUnload 38 | { 39 | self.usernameTextField = nil; 40 | [super viewDidUnload]; 41 | // Release any retained subviews of the main view. 42 | // e.g. self.myOutlet = nil; 43 | } 44 | 45 | - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation 46 | { 47 | // Return YES for supported orientations 48 | return YES; 49 | } 50 | 51 | - (IBAction)cancel 52 | { 53 | [self dismissModalViewControllerAnimated:YES]; 54 | } 55 | 56 | - (IBAction)save 57 | { 58 | // TODO: if username is blank.. 59 | [ApplicationHelper setCurrentUsername:usernameTextField.text notifyOfChange:YES]; 60 | 61 | [self dismissModalViewControllerAnimated:YES]; 62 | } 63 | 64 | @end 65 | -------------------------------------------------------------------------------- /GithubBrowser/UAGithubEngine/JSON/CSerializedJSONData.m: -------------------------------------------------------------------------------- 1 | // 2 | // CSerializedJSONData.m 3 | // TouchCode 4 | // 5 | // Created by Jonathan Wight on 10/23/09. 6 | // Copyright 2009 toxicsoftware.com. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person 9 | // obtaining a copy of this software and associated documentation 10 | // files (the "Software"), to deal in the Software without 11 | // restriction, including without limitation the rights to use, 12 | // copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the 14 | // Software is furnished to do so, subject to the following 15 | // conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be 18 | // included in all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 22 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 24 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 25 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 26 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 27 | // OTHER DEALINGS IN THE SOFTWARE. 28 | // 29 | 30 | #import "CSerializedJSONData.h" 31 | 32 | @implementation CSerializedJSONData 33 | 34 | @synthesize data; 35 | 36 | - (id)initWithData:(NSData *)inData; 37 | { 38 | if ((self = [self init]) != NULL) 39 | { 40 | data = inData; 41 | } 42 | return(self); 43 | } 44 | 45 | - (void)dealloc 46 | { 47 | [data release]; 48 | data = NULL; 49 | // 50 | [super dealloc]; 51 | } 52 | 53 | 54 | @end 55 | -------------------------------------------------------------------------------- /GithubBrowser/UAGithubEngine/Extensions/NSScanner_Extensions.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSScanner_Extensions.h 3 | // TouchCode 4 | // 5 | // Created by Jonathan Wight on 12/08/2005. 6 | // Copyright 2005 toxicsoftware.com. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person 9 | // obtaining a copy of this software and associated documentation 10 | // files (the "Software"), to deal in the Software without 11 | // restriction, including without limitation the rights to use, 12 | // copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the 14 | // Software is furnished to do so, subject to the following 15 | // conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be 18 | // included in all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 22 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 24 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 25 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 26 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 27 | // OTHER DEALINGS IN THE SOFTWARE. 28 | // 29 | 30 | #import 31 | 32 | @interface NSScanner (NSScanner_Extensions) 33 | 34 | - (NSString *)remainingString; 35 | 36 | - (unichar)currentCharacter; 37 | - (unichar)scanCharacter; 38 | - (BOOL)scanCharacter:(unichar)inCharacter; 39 | - (void)backtrack:(unsigned)inCount; 40 | 41 | - (BOOL)scanCStyleComment:(NSString **)outComment; 42 | - (BOOL)scanCPlusPlusStyleComment:(NSString **)outComment; 43 | 44 | @end 45 | -------------------------------------------------------------------------------- /GithubBrowser/UAGithubEngine/JSON/CJSONDeserializer.h: -------------------------------------------------------------------------------- 1 | // 2 | // CJSONDeserializer.h 3 | // TouchCode 4 | // 5 | // Created by Jonathan Wight on 12/15/2005. 6 | // Copyright 2005 toxicsoftware.com. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person 9 | // obtaining a copy of this software and associated documentation 10 | // files (the "Software"), to deal in the Software without 11 | // restriction, including without limitation the rights to use, 12 | // copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the 14 | // Software is furnished to do so, subject to the following 15 | // conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be 18 | // included in all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 22 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 24 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 25 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 26 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 27 | // OTHER DEALINGS IN THE SOFTWARE. 28 | // 29 | 30 | #import 31 | 32 | extern NSString *const kJSONDeserializerErrorDomain /* = @"CJSONDeserializerErrorDomain" */; 33 | 34 | @interface CJSONDeserializer : NSObject { 35 | 36 | } 37 | 38 | + (id)deserializer; 39 | 40 | - (id)deserialize:(NSData *)inData error:(NSError **)outError; 41 | 42 | - (id)deserializeAsDictionary:(NSData *)inData error:(NSError **)outError; 43 | - (id)deserializeAsArray:(NSData *)inData error:(NSError **)outError; 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /GithubBrowser/UAGithubEngine/NSString+UAGithubEngineUtilities.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+UAGithubEngineUtilities.m 3 | // UAGithubEngine 4 | // 5 | // Created by Owain Hunt on 08/04/2010. 6 | // Copyright 2010 Owain R Hunt. All rights reserved. 7 | // 8 | 9 | #import "NSString+UAGithubEngineUtilities.h" 10 | 11 | 12 | @implementation NSString(UAGithubEngineUtilities) 13 | 14 | - (NSDate *)dateFromGithubDateString { 15 | 16 | NSDateFormatter *df = [[[NSDateFormatter alloc] init] autorelease]; 17 | NSString *dateString = self; 18 | 19 | // Because Github returns three different date string formats throughout the API, 20 | // we need to check how to process the string based on the format used 21 | if ([[self substringWithRange:NSMakeRange(10, 1)] isEqualToString:@"T"]) 22 | { 23 | if ([[self substringWithRange:NSMakeRange([self length] - 1, 1)] isEqualToString:@"Z"]) 24 | { 25 | // eg 2010-05-23T21:26:03.921Z (UTC with milliseconds) 26 | if([[self substringWithRange:NSMakeRange(19, 1)] isEqualToString:@"."]){ 27 | [df setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"]; 28 | // eg 2010-05-23T21:26:03Z (UTC without milliseconds) 29 | } else { 30 | [df setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss'Z'"]; 31 | } 32 | } 33 | else 34 | // eg 2010-04-07T12:50:15-07:00 35 | { 36 | NSMutableString *newDate = [self mutableCopy]; 37 | [newDate deleteCharactersInRange:NSMakeRange(22, 1)]; 38 | [df setDateFormat:@"yyyy-MM-dd'T'HH:mm:ssZZZ"]; 39 | [dateString release]; 40 | dateString = newDate; 41 | [newDate release]; 42 | } 43 | } else { 44 | // eg 2010/07/28 21:21:00 +0100 45 | [df setDateFormat:@"yyyy/MM/dd HH:mm:ss ZZZ"]; 46 | } 47 | 48 | return [df dateFromString:dateString]; 49 | 50 | } 51 | 52 | 53 | - (NSString *)encodedString 54 | { 55 | return (NSString *)CFURLCreateStringByAddingPercentEscapes(NULL, (CFStringRef)self, NULL, (CFStringRef)@";/?:@&=$+{}<>,", kCFStringEncodingUTF8); 56 | 57 | } 58 | 59 | 60 | @end 61 | -------------------------------------------------------------------------------- /GithubBrowser/UAGithubEngine/Extensions/NSCharacterSet_Extensions.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSCharacterSet_Extensions.m 3 | // TouchCode 4 | // 5 | // Created by Jonathan Wight on 12/08/2005. 6 | // Copyright 2005 toxicsoftware.com. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person 9 | // obtaining a copy of this software and associated documentation 10 | // files (the "Software"), to deal in the Software without 11 | // restriction, including without limitation the rights to use, 12 | // copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the 14 | // Software is furnished to do so, subject to the following 15 | // conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be 18 | // included in all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 22 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 24 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 25 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 26 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 27 | // OTHER DEALINGS IN THE SOFTWARE. 28 | // 29 | 30 | #import "NSCharacterSet_Extensions.h" 31 | 32 | @implementation NSCharacterSet (NSCharacterSet_Extensions) 33 | 34 | #define LF 0x000a // Line Feed 35 | #define FF 0x000c // Form Feed 36 | #define CR 0x000d // Carriage Return 37 | #define NEL 0x0085 // Next Line 38 | #define LS 0x2028 // Line Separator 39 | #define PS 0x2029 // Paragraph Separator 40 | 41 | + (NSCharacterSet *)linebreaksCharacterSet 42 | { 43 | unichar theCharacters[] = { LF, FF, CR, NEL, LS, PS, }; 44 | 45 | return([NSCharacterSet characterSetWithCharactersInString:[NSString stringWithCharacters:theCharacters length:sizeof(theCharacters) / sizeof(*theCharacters)]]); 46 | } 47 | 48 | @end 49 | -------------------------------------------------------------------------------- /GithubBrowser/UAGithubEngine/JSON/CJSONDataSerializer.h: -------------------------------------------------------------------------------- 1 | // 2 | // CJSONDataSerializer.h 3 | // TouchCode 4 | // 5 | // Created by Jonathan Wight on 12/07/2005. 6 | // Copyright 2005 toxicsoftware.com. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person 9 | // obtaining a copy of this software and associated documentation 10 | // files (the "Software"), to deal in the Software without 11 | // restriction, including without limitation the rights to use, 12 | // copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the 14 | // Software is furnished to do so, subject to the following 15 | // conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be 18 | // included in all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 22 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 24 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 25 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 26 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 27 | // OTHER DEALINGS IN THE SOFTWARE. 28 | // 29 | 30 | #import 31 | 32 | @interface CJSONDataSerializer : NSObject { 33 | } 34 | 35 | + (id)serializer; 36 | 37 | /// Take any JSON compatible object (generally NSNull, NSNumber, NSString, NSArray and NSDictionary) and produce an NSData containing the serialized JSON. 38 | - (NSData *)serializeObject:(id)inObject error:(NSError **)outError; 39 | 40 | - (NSData *)serializeNull:(NSNull *)inNull error:(NSError **)outError; 41 | - (NSData *)serializeNumber:(NSNumber *)inNumber error:(NSError **)outError; 42 | - (NSData *)serializeString:(NSString *)inString error:(NSError **)outError; 43 | - (NSData *)serializeArray:(NSArray *)inArray error:(NSError **)outError; 44 | - (NSData *)serializeDictionary:(NSDictionary *)inDictionary error:(NSError **)outError; 45 | 46 | @end 47 | -------------------------------------------------------------------------------- /GithubBrowser/UAGithubEngine/JSON/CJSONSerializer.h: -------------------------------------------------------------------------------- 1 | // 2 | // CJSONSerializer.h 3 | // TouchCode 4 | // 5 | // Created by Jonathan Wight on 12/07/2005. 6 | // Copyright 2005 toxicsoftware.com. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person 9 | // obtaining a copy of this software and associated documentation 10 | // files (the "Software"), to deal in the Software without 11 | // restriction, including without limitation the rights to use, 12 | // copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the 14 | // Software is furnished to do so, subject to the following 15 | // conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be 18 | // included in all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 22 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 24 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 25 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 26 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 27 | // OTHER DEALINGS IN THE SOFTWARE. 28 | // 29 | 30 | #import 31 | 32 | @class CJSONDataSerializer; 33 | 34 | /// Serialize JSON compatible objects (NSNull, NSNumber, NSString, NSArray, NSDictionary) into a JSON formatted string. Note this class is just a wrapper around CJSONDataSerializer which you really should be using instead. 35 | @interface CJSONSerializer : NSObject { 36 | CJSONDataSerializer *serializer; 37 | } 38 | 39 | + (id)serializer; 40 | 41 | /// Take any JSON compatible object (generally NSNull, NSNumber, NSString, NSArray and NSDictionary) and produce a JSON string. 42 | - (NSString *)serializeObject:(id)inObject error:(NSError **)outError; 43 | 44 | - (NSString *)serializeArray:(NSArray *)inArray error:(NSError **)outError; 45 | - (NSString *)serializeDictionary:(NSDictionary *)inDictionary error:(NSError **)outError; 46 | 47 | @end 48 | -------------------------------------------------------------------------------- /GithubBrowser/SettingsViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // SettingsViewController.m 3 | // GithubBrowser 4 | // 5 | // Created by Oscar Del Ben on 4/9/11. 6 | // Copyright 2011 DibiStore. All rights reserved. 7 | // 8 | 9 | #import "SettingsViewController.h" 10 | #import "DetailViewController.h" 11 | #import "Constants.h" 12 | 13 | @implementation SettingsViewController 14 | 15 | @synthesize usernameTextField, passwordTextField; 16 | 17 | - (void)dealloc 18 | { 19 | [usernameTextField release]; 20 | [passwordTextField release]; 21 | [super dealloc]; 22 | } 23 | 24 | 25 | - (void)viewDidLoad 26 | { 27 | NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; 28 | 29 | usernameTextField.text = [userDefaults valueForKey:GBGithubUsername]; 30 | passwordTextField.text = [userDefaults valueForKey:GBGithubPassword]; 31 | 32 | UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(cancel)]; 33 | UIBarButtonItem *saveButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(save)]; 34 | 35 | self.navigationItem.leftBarButtonItem = cancelButton; 36 | self.navigationItem.rightBarButtonItem = saveButton; 37 | 38 | [cancelButton release]; 39 | [saveButton release]; 40 | } 41 | 42 | - (void)viewDidUnload 43 | { 44 | [self setUsernameTextField:nil]; 45 | [self setPasswordTextField:nil]; 46 | [super viewDidUnload]; 47 | // Release any retained subviews of the main view. 48 | // e.g. self.myOutlet = nil; 49 | } 50 | 51 | - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation 52 | { 53 | // Return YES for supported orientations 54 | return YES; 55 | } 56 | 57 | - (void)cancel 58 | { 59 | [self dismissModalViewControllerAnimated:YES]; 60 | } 61 | 62 | - (IBAction)save { 63 | // TODO: disable save button if username or password is blank 64 | 65 | NSString *username = usernameTextField.text; 66 | NSString *password = passwordTextField.text; 67 | 68 | [ApplicationHelper saveCredentials:username password:password notifyOfChange:YES]; 69 | 70 | [self dismissModalViewControllerAnimated:YES]; 71 | } 72 | 73 | @end 74 | -------------------------------------------------------------------------------- /GithubBrowser/UAGithubEngine/JSON/CJSONScanner.h: -------------------------------------------------------------------------------- 1 | // 2 | // CJSONScanner.h 3 | // TouchCode 4 | // 5 | // Created by Jonathan Wight on 12/07/2005. 6 | // Copyright 2005 toxicsoftware.com. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person 9 | // obtaining a copy of this software and associated documentation 10 | // files (the "Software"), to deal in the Software without 11 | // restriction, including without limitation the rights to use, 12 | // copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the 14 | // Software is furnished to do so, subject to the following 15 | // conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be 18 | // included in all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 22 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 24 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 25 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 26 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 27 | // OTHER DEALINGS IN THE SOFTWARE. 28 | // 29 | 30 | #import "CDataScanner.h" 31 | 32 | /// CDataScanner subclass that understands JSON syntax natively. You should generally use CJSONDeserializer instead of this class. (TODO - this could have been a category?) 33 | @interface CJSONScanner : CDataScanner { 34 | BOOL strictEscapeCodes; 35 | } 36 | 37 | @property (readonly, nonatomic, assign) BOOL strictEscapeCodes; 38 | 39 | - (BOOL)scanJSONObject:(id *)outObject error:(NSError **)outError; 40 | - (BOOL)scanJSONDictionary:(NSMutableDictionary **)outDictionary error:(NSError **)outError; 41 | - (BOOL)scanJSONArray:(NSArray **)outArray error:(NSError **)outError; 42 | - (BOOL)scanJSONStringConstant:(NSString **)outStringConstant error:(NSError **)outError; 43 | - (BOOL)scanJSONNumberConstant:(NSNumber **)outNumberConstant error:(NSError **)outError; 44 | 45 | @end 46 | 47 | extern NSString *const kJSONScannerErrorDomain /* = @"CJSONScannerErrorDomain" */; 48 | -------------------------------------------------------------------------------- /GithubBrowser/UAGithubEngine/CDataScanner.h: -------------------------------------------------------------------------------- 1 | // 2 | // CDataScanner.h 3 | // TouchCode 4 | // 5 | // Created by Jonathan Wight on 04/16/08. 6 | // Copyright 2008 toxicsoftware.com. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person 9 | // obtaining a copy of this software and associated documentation 10 | // files (the "Software"), to deal in the Software without 11 | // restriction, including without limitation the rights to use, 12 | // copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the 14 | // Software is furnished to do so, subject to the following 15 | // conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be 18 | // included in all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 22 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 24 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 25 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 26 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 27 | // OTHER DEALINGS IN THE SOFTWARE. 28 | // 29 | 30 | #import 31 | 32 | // NSScanner 33 | 34 | @interface CDataScanner : NSObject { 35 | NSData *data; 36 | 37 | u_int8_t *start; 38 | u_int8_t *end; 39 | u_int8_t *current; 40 | NSUInteger length; 41 | 42 | NSCharacterSet *doubleCharacters; 43 | } 44 | 45 | @property (readwrite, nonatomic, retain) NSData *data; 46 | @property (readwrite, nonatomic, assign) NSUInteger scanLocation; 47 | @property (readonly, nonatomic, assign) BOOL isAtEnd; 48 | 49 | + (id)scannerWithData:(NSData *)inData; 50 | 51 | - (unichar)currentCharacter; 52 | - (unichar)scanCharacter; 53 | - (BOOL)scanCharacter:(unichar)inCharacter; 54 | 55 | - (BOOL)scanUTF8String:(const char *)inString intoString:(NSString **)outValue; 56 | - (BOOL)scanString:(NSString *)inString intoString:(NSString **)outValue; 57 | - (BOOL)scanCharactersFromSet:(NSCharacterSet *)inSet intoString:(NSString **)outValue; // inSet must only contain 7-bit ASCII characters 58 | 59 | - (BOOL)scanUpToString:(NSString *)string intoString:(NSString **)outValue; 60 | - (BOOL)scanUpToCharactersFromSet:(NSCharacterSet *)set intoString:(NSString **)outValue; // inSet must only contain 7-bit ASCII characters 61 | 62 | - (BOOL)scanNumber:(NSNumber **)outValue; 63 | 64 | - (void)skipWhitespace; 65 | 66 | - (NSString *)remainingString; 67 | 68 | @end 69 | -------------------------------------------------------------------------------- /GithubBrowser/UAGithubEngine/UAGithubEngineDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // UAGithubEngineDelegate.h 3 | // UAGithubEngine 4 | // 5 | // Created by Owain Hunt on 02/04/2010. 6 | // Copyright 2010 Owain R Hunt. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | @protocol UAGithubEngineDelegate 13 | 14 | - (void)requestSucceeded:(NSString *)connectionIdentifier; 15 | - (void)requestFailed:(NSString *)connectionIdentifier withError:(NSError *)error; 16 | 17 | 18 | @optional 19 | 20 | #pragma mark Connections 21 | 22 | - (void)connectionStarted:(NSString *)connectionIdentifier; 23 | - (void)connectionFinished:(NSString *)connectionIdentifier; 24 | 25 | 26 | #pragma mark Users 27 | 28 | - (void)usersReceived:(NSArray *)users forConnection:(NSString *)connectionIdentifier; 29 | - (void)followingReceived:(NSArray *)following forConnection:(NSString *)connectionIdentifier; 30 | - (void)followersReceived:(NSArray *)followers forConnection:(NSString *)connectionIdentifier; 31 | 32 | 33 | #pragma mark Repositories 34 | 35 | - (void)repositoriesReceived:(NSArray *)repositories forConnection:(NSString *)connectionIdentifier; 36 | - (void)deployKeysReceived:(NSArray *)deployKeys forConnection:(NSString *)connectionIdentifier; 37 | - (void)collaboratorsReceived:(NSArray *)collaborators forConnection:(NSString *)connectionIdentifier; 38 | - (void)languagesReceived:(NSArray *)languages forConnection:(NSString *)connectionIdentifier; 39 | - (void)tagsReceived:(NSArray *)tags forConnection:(NSString *)connectionIdentifier; 40 | - (void)branchesReceived:(NSArray *)branches forConnection:(NSString *)connectionIdentifier; 41 | 42 | 43 | #pragma mark Commits 44 | 45 | - (void)commitsReceived:(NSArray *)commits forConnection:(NSString *)connectionIdentifier; 46 | 47 | 48 | #pragma mark Issues 49 | 50 | - (void)issuesReceived:(NSArray *)issues forConnection:(NSString *)connectionIdentifier; 51 | 52 | 53 | #pragma mark Labels 54 | 55 | - (void)labelsReceived:(NSArray *)labels forConnection:(NSString *)connectionIdentifier; 56 | 57 | 58 | #pragma mark Comments 59 | 60 | - (void)issueCommentsReceived:(NSArray *)issueComments forConnection:(NSString *)connectionIdentifier; 61 | 62 | 63 | #pragma mark Trees 64 | 65 | - (void)treeReceived:(NSArray *)treeContents forConnection:(NSString *)connectionIdentifier; 66 | 67 | 68 | #pragma mark Blobs 69 | 70 | - (void)blobsReceieved:(NSArray *)blobs forConnection:(NSString *)connectionIdentifier; 71 | - (void)blobReceived:(NSArray *)blob forConnection:(NSString *)connectionIdentifier; 72 | - (void)rawBlobReceived:(NSData *)blob forConnection:(NSString *)connectionIdentifier; 73 | 74 | 75 | #pragma mark Organizations 76 | 77 | - (void)organizationsReceived:(NSArray *)organizations forConnection:(NSString *)connectionIdentifier; 78 | 79 | @end 80 | -------------------------------------------------------------------------------- /GithubBrowser/UAGithubEngine/JSON/CJSONSerializer.m: -------------------------------------------------------------------------------- 1 | // 2 | // CJSONSerializer.m 3 | // TouchCode 4 | // 5 | // Created by Jonathan Wight on 12/07/2005. 6 | // Copyright 2005 toxicsoftware.com. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person 9 | // obtaining a copy of this software and associated documentation 10 | // files (the "Software"), to deal in the Software without 11 | // restriction, including without limitation the rights to use, 12 | // copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the 14 | // Software is furnished to do so, subject to the following 15 | // conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be 18 | // included in all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 22 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 24 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 25 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 26 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 27 | // OTHER DEALINGS IN THE SOFTWARE. 28 | // 29 | 30 | #import "CJSONSerializer.h" 31 | 32 | #import "CJSONDataSerializer.h" 33 | 34 | @implementation CJSONSerializer 35 | 36 | + (id)serializer 37 | { 38 | return([[[self alloc] init] autorelease]); 39 | } 40 | 41 | - (id)init 42 | { 43 | if ((self = [super init]) != NULL) 44 | { 45 | serializer = [[CJSONDataSerializer alloc] init]; 46 | } 47 | return(self); 48 | } 49 | 50 | - (void)dealloc 51 | { 52 | [serializer release]; 53 | serializer = NULL; 54 | // 55 | [super dealloc]; 56 | } 57 | 58 | - (NSString *)serializeObject:(id)inObject error:(NSError **)outError 59 | { 60 | NSData *theData = [serializer serializeObject:inObject error:outError]; 61 | if (theData == NULL) 62 | return(NULL); 63 | return([[[NSString alloc] initWithData:theData encoding:NSUTF8StringEncoding] autorelease]); 64 | } 65 | 66 | - (NSString *)serializeArray:(NSArray *)inArray error:(NSError **)outError 67 | { 68 | NSData *theData = [serializer serializeArray:inArray error:outError]; 69 | if (theData == NULL) 70 | return(NULL); 71 | return([[[NSString alloc] initWithData:theData encoding:NSUTF8StringEncoding] autorelease]); 72 | } 73 | 74 | - (NSString *)serializeDictionary:(NSDictionary *)inDictionary error:(NSError **)outError 75 | { 76 | NSData *theData = [serializer serializeDictionary:inDictionary error:outError]; 77 | if (theData == NULL) 78 | return(NULL); 79 | return([[[NSString alloc] initWithData:theData encoding:NSUTF8StringEncoding] autorelease]); 80 | } 81 | @end 82 | -------------------------------------------------------------------------------- /GithubBrowser/UAGithubEngine/Extensions/CDataScanner_Extensions.m: -------------------------------------------------------------------------------- 1 | // 2 | // CDataScanner_Extensions.m 3 | // TouchCode 4 | // 5 | // Created by Jonathan Wight on 12/08/2005. 6 | // Copyright 2005 toxicsoftware.com. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person 9 | // obtaining a copy of this software and associated documentation 10 | // files (the "Software"), to deal in the Software without 11 | // restriction, including without limitation the rights to use, 12 | // copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the 14 | // Software is furnished to do so, subject to the following 15 | // conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be 18 | // included in all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 22 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 24 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 25 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 26 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 27 | // OTHER DEALINGS IN THE SOFTWARE. 28 | // 29 | 30 | #import "CDataScanner_Extensions.h" 31 | 32 | #import "NSCharacterSet_Extensions.h" 33 | 34 | @implementation CDataScanner (CDataScanner_Extensions) 35 | 36 | - (BOOL)scanCStyleComment:(NSString **)outComment 37 | { 38 | if ([self scanString:@"/*" intoString:NULL] == YES) 39 | { 40 | NSString *theComment = NULL; 41 | if ([self scanUpToString:@"*/" intoString:&theComment] == NO) 42 | [NSException raise:NSGenericException format:@"Started to scan a C style comment but it wasn't terminated."]; 43 | 44 | if ([theComment rangeOfString:@"/*"].location != NSNotFound) 45 | [NSException raise:NSGenericException format:@"C style comments should not be nested."]; 46 | 47 | if ([self scanString:@"*/" intoString:NULL] == NO) 48 | [NSException raise:NSGenericException format:@"C style comment did not end correctly."]; 49 | 50 | if (outComment != NULL) 51 | *outComment = theComment; 52 | 53 | return(YES); 54 | } 55 | else 56 | { 57 | return(NO); 58 | } 59 | } 60 | 61 | - (BOOL)scanCPlusPlusStyleComment:(NSString **)outComment 62 | { 63 | if ([self scanString:@"//" intoString:NULL] == YES) 64 | { 65 | NSString *theComment = NULL; 66 | [self scanUpToCharactersFromSet:[NSCharacterSet linebreaksCharacterSet] intoString:&theComment]; 67 | [self scanCharactersFromSet:[NSCharacterSet linebreaksCharacterSet] intoString:NULL]; 68 | 69 | if (outComment != NULL) 70 | *outComment = theComment; 71 | 72 | return(YES); 73 | } 74 | else 75 | { 76 | return(NO); 77 | } 78 | } 79 | 80 | @end 81 | -------------------------------------------------------------------------------- /GithubBrowser/UAGithubEngine/JSON/CJSONDeserializer.m: -------------------------------------------------------------------------------- 1 | // 2 | // CJSONDeserializer.m 3 | // TouchCode 4 | // 5 | // Created by Jonathan Wight on 12/15/2005. 6 | // Copyright 2005 toxicsoftware.com. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person 9 | // obtaining a copy of this software and associated documentation 10 | // files (the "Software"), to deal in the Software without 11 | // restriction, including without limitation the rights to use, 12 | // copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the 14 | // Software is furnished to do so, subject to the following 15 | // conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be 18 | // included in all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 22 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 24 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 25 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 26 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 27 | // OTHER DEALINGS IN THE SOFTWARE. 28 | // 29 | 30 | #import "CJSONDeserializer.h" 31 | 32 | #import "CJSONScanner.h" 33 | #import "CDataScanner.h" 34 | 35 | NSString *const kJSONDeserializerErrorDomain = @"CJSONDeserializerErrorDomain"; 36 | 37 | @implementation CJSONDeserializer 38 | 39 | + (id)deserializer 40 | { 41 | return([[[self alloc] init] autorelease]); 42 | } 43 | 44 | - (id)deserialize:(NSData *)inData error:(NSError **)outError 45 | { 46 | if (inData == NULL || [inData length] == 0) 47 | { 48 | if (outError) 49 | *outError = [NSError errorWithDomain:kJSONDeserializerErrorDomain code:-1 userInfo:NULL]; 50 | 51 | return(NULL); 52 | } 53 | CJSONScanner *theScanner = [CJSONScanner scannerWithData:inData]; 54 | id theObject = NULL; 55 | if ([theScanner scanJSONObject:&theObject error:outError] == YES) 56 | return(theObject); 57 | else 58 | return(NULL); 59 | } 60 | 61 | - (id)deserializeAsDictionary:(NSData *)inData error:(NSError **)outError; 62 | { 63 | if (inData == NULL || [inData length] == 0) 64 | { 65 | if (outError) 66 | *outError = [NSError errorWithDomain:kJSONDeserializerErrorDomain code:-1 userInfo:NULL]; 67 | 68 | return(NULL); 69 | } 70 | CJSONScanner *theScanner = [CJSONScanner scannerWithData:inData]; 71 | NSMutableDictionary *theDictionary = NULL; 72 | if ([theScanner scanJSONDictionary:&theDictionary error:outError] == YES) 73 | return(theDictionary); 74 | else 75 | return(NULL); 76 | } 77 | 78 | - (id)deserializeAsArray:(NSData *)inData error:(NSError **)outError; 79 | { 80 | if (inData == NULL || [inData length] == 0) 81 | { 82 | if (outError) 83 | *outError = [NSError errorWithDomain:kJSONDeserializerErrorDomain code:-1 userInfo:NULL]; 84 | 85 | return(NULL); 86 | } 87 | CJSONScanner *theScanner = [CJSONScanner scannerWithData:inData]; 88 | NSMutableArray *theArray = NULL; 89 | if ([theScanner scanJSONArray:&theArray error:outError] == YES) 90 | return(theArray); 91 | else 92 | return(NULL); 93 | } 94 | 95 | @end 96 | -------------------------------------------------------------------------------- /GithubBrowser/ApplicationHelper.m: -------------------------------------------------------------------------------- 1 | // 2 | // ApplicationHelper.m 3 | // GithubBrowser 4 | // 5 | // Created by Oscar Del Ben on 4/11/11. 6 | // Copyright 2011 DibiStore. All rights reserved. 7 | // 8 | 9 | #import "ApplicationHelper.h" 10 | #import "NSMutableURLRequest+BasicAuth.h" 11 | 12 | @implementation ApplicationHelper 13 | 14 | + (NSString *)currentUsername 15 | { 16 | NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; 17 | NSString *currentUsername = [userDefaults valueForKey:GBGithubCurrentUsername]; 18 | 19 | if (!currentUsername || [currentUsername blank]) 20 | { 21 | return [userDefaults valueForKey:GBGithubUsername]; 22 | } 23 | else 24 | { 25 | return currentUsername; 26 | } 27 | } 28 | 29 | + (NSString *)username 30 | { 31 | NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; 32 | return [userDefaults valueForKey:GBGithubUsername]; 33 | } 34 | 35 | + (NSString *)password 36 | { 37 | // Only return password if we're fetching the primary user 38 | NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; 39 | 40 | 41 | if ([self usingDefaultUser]) 42 | { 43 | return [userDefaults valueForKey:GBGithubPassword]; 44 | } 45 | else 46 | { 47 | return nil; 48 | } 49 | } 50 | 51 | + (BOOL)usingDefaultUser 52 | { 53 | NSString *currentUsername = [self currentUsername]; 54 | NSString *username = [self username]; 55 | 56 | return [currentUsername isEqualToString:username]; 57 | } 58 | 59 | + (BOOL)validUsername:(NSString *)username 60 | { 61 | return [username rangeOfString:@"/"].location == NSNotFound; 62 | } 63 | 64 | + (void)sendCredentialsChangedNotification 65 | { 66 | NSNotification *notification = [NSNotification notificationWithName:GBCredentialsChanged object:nil]; 67 | 68 | NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; 69 | [notificationCenter postNotification:notification]; 70 | } 71 | 72 | + (void)saveCredentials:(NSString *)username password:(NSString *)password notifyOfChange:(BOOL)notify 73 | { 74 | NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; 75 | 76 | [userDefaults setObject:username forKey:GBGithubUsername]; 77 | [userDefaults setObject:password forKey:GBGithubPassword]; 78 | 79 | if (notify) 80 | { 81 | [self sendCredentialsChangedNotification]; 82 | } 83 | } 84 | 85 | + (void)setCurrentUsername:(NSString *)username notifyOfChange:(BOOL)notify 86 | { 87 | NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; 88 | [userDefaults setValue:username forKey:GBGithubCurrentUsername]; 89 | 90 | if (notify) 91 | { 92 | [self sendCredentialsChangedNotification]; 93 | } 94 | } 95 | 96 | + (void)loadWebViewFromUrl:(UIWebView *)webView url:(NSString *)string; 97 | { 98 | NSURL *url = [NSURL URLWithString:string]; 99 | NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:url]; 100 | 101 | // Add auth 102 | 103 | NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; 104 | NSString *username = [userDefaults valueForKey:GBGithubUsername]; 105 | NSString *password = [userDefaults valueForKey:GBGithubPassword];; 106 | 107 | [req addBasicAuth:username andPassword:password]; 108 | 109 | // Load request 110 | 111 | [webView loadRequest:req]; 112 | } 113 | 114 | @end 115 | -------------------------------------------------------------------------------- /GithubBrowser/UAGithubEngine/README: -------------------------------------------------------------------------------- 1 | UAGithubEngine 2 | by Owain R Hunt, http://owainrhunt.com 3 | ================= 4 | 5 | UAGithubEngine is a practically-complete wrapper around version 2 of the Github API (the exceptions being the network graph and Gist APIs, which are not currently implemented). Check out the API documentation (http://develop.github.com/) for full details of what the API can do. 6 | 7 | UAGithubEngine is compatible with Mac OS X 10.5 and above, and iOS 4.0. 8 | 9 | How do I use it? 10 | ================= 11 | 12 | * Copy across all the files in the 'Engine' group from the UAGithubEngine project into your app's project. 13 | 14 | * Where you want to use the engine, follow the example from the included AppController class, making sure you #import "UAGithubEngine.h", and that your class adopts the UAGithubEngineDelegate protocol. 15 | 16 | * Implement *at least* the following delegate methods: 17 | 18 | - (void)requestSucceeded:(NSString *)connectionIdentifier; 19 | - (void)requestFailed:(NSString *)connectionIdentifier withError:(NSError *)error; 20 | 21 | * Implement your choice of the remaining delegate methods, depending on your particular needs: 22 | 23 | - (void)connectionStarted:(NSString *)connectionIdentifier; 24 | - (void)connectionFinished:(NSString *)connectionIdentifier; 25 | - (void)usersReceived:(NSArray *)users forConnection:(NSString *)connectionIdentifier; 26 | - (void)repositoriesReceived:(NSArray *)repositories forConnection:(NSString *)connectionIdentifier; 27 | - (void)deployKeysReceived:(NSArray *)deployKeys forConnection:(NSString *)connectionIdentifier; 28 | - (void)collaboratorsReceived:(NSArray *)collaborators forConnection:(NSString *)connectionIdentifier; 29 | - (void)languagesReceived:(NSArray *)languages forConnection:(NSString *)connectionIdentifier; 30 | - (void)tagsReceived:(NSArray *)tags forConnection:(NSString *)connectionIdentifier; 31 | - (void)branchesReceived:(NSArray *)branches forConnection:(NSString *)connectionIdentifier; 32 | - (void)commitsReceived:(NSArray *)commits forConnection:(NSString *)connectionIdentifier; 33 | - (void)issuesReceived:(NSArray *)issues forConnection:(NSString *)connectionIdentifier; 34 | - (void)labelsReceived:(NSArray *)labels forConnection:(NSString *)connectionIdentifier; 35 | - (void)issueCommentsReceived:(NSArray *)issueComments forConnection:(NSString *)connectionIdentifier; 36 | - (void)treeReceived:(NSArray *)treeContents forConnection:(NSString *)connectionIdentifier; 37 | - (void)blobsReceieved:(NSArray *)blobs forConnection:(NSString *)connectionIdentifier; 38 | - (void)blobReceived:(NSArray *)blob forConnection:(NSString *)connectionIdentifier; 39 | - (void)rawBlobReceived:(NSData *)blob forConnection:(NSString *)connectionIdentifier; 40 | 41 | * Instantiate an engine, passing a username and password, then call some methods. If you want to receive notifications when reachability status changes (UAGithubReachabilityStatusDidChangeNotification), pass YES as the final argument. For example: 42 | 43 | UAGithubEngine *engine = [[UAGithubEngine alloc] initWithUsername:@"aUser" password:@"aPassword" delegate:self withReachability:YES]; 44 | [engine user:@"owainhunt"]; 45 | 46 | * Enjoy. The included AppController class will log the received data from any API calls the engine makes, so have a play around and see what happens - and happy app building! 47 | 48 | Any questions, comments, improvements and so on, you can find me on Twitter (@orhunt) or send me an email (owain@underscoreapps.com). 49 | 50 | Acknowledgements 51 | ================= 52 | UAGithubEngine is heavily based on the structure (and in some places the code) of Matt Gemmell's MGTwitterEngine. 53 | UAGithubEngine uses a barely modified version of Jonathan Wight's TouchJSON parser. -------------------------------------------------------------------------------- /GithubBrowser/UAGithubEngine/UAGithubJSONParser.m: -------------------------------------------------------------------------------- 1 | // 2 | // UAGithubJSONParser.m 3 | // UAGithubEngine 4 | // 5 | // Created by Owain Hunt on 27/07/2010. 6 | // Copyright 2010 Owain R Hunt. All rights reserved. 7 | // 8 | 9 | #import "UAGithubJSONParser.h" 10 | #import "CJSONDeserializer.h" 11 | #import "NSArray+Utilities.h" 12 | #import "NSString+UAGithubEngineUtilities.h" 13 | 14 | @implementation UAGithubJSONParser 15 | 16 | - (id)initWithJSON:(NSData *)theJSON delegate:(id)theDelegate connectionIdentifier:(NSString *)theIdentifier requestType:(UAGithubRequestType)reqType responseType:(UAGithubResponseType)respType 17 | { 18 | if ((self = [super init])) 19 | { 20 | json = [theJSON retain]; 21 | delegate = theDelegate; 22 | connectionIdentifier = [theIdentifier retain]; 23 | requestType = reqType; 24 | responseType = respType; 25 | } 26 | 27 | return self; 28 | 29 | } 30 | 31 | 32 | - (void)dealloc 33 | { 34 | [json release]; 35 | [connectionIdentifier release]; 36 | [super dealloc]; 37 | 38 | } 39 | 40 | 41 | - (void)parse 42 | { 43 | NSError *error = nil; 44 | NSMutableDictionary *dictionary = [[[CJSONDeserializer deserializer] deserializeAsDictionary:json error:&error] mutableCopy]; 45 | 46 | if (!error) 47 | { 48 | if ([[dictionary allKeys] containsObject:@"error"]) 49 | { 50 | error = [NSError errorWithDomain:@"UAGithubEngineGithubError" code:0 userInfo:[NSDictionary dictionaryWithObject:[dictionary objectForKey:@"error"] forKey:@"errorMessage"]]; 51 | [delegate parsingFailedForConnection:connectionIdentifier ofResponseType:responseType withError:error]; 52 | [dictionary release]; 53 | return; 54 | } 55 | 56 | NSArray *parsedObjects = nil; 57 | 58 | // parsedObjects is expected to be an NSArray, so we have to check if the parser has returned an array or a dictionary. 59 | // This would be the case if there is only one result for our API call, such as for a single user. 60 | // If we're dealing with a single object, we have to wrap it in an array before we return it. 61 | if ([[[dictionary allValues] firstObject] isKindOfClass:[NSDictionary class]]) 62 | { 63 | parsedObjects = [NSArray arrayWithObject:[[dictionary allValues] firstObject]]; 64 | } 65 | else 66 | { 67 | parsedObjects = [[dictionary allValues] firstObject]; 68 | } 69 | 70 | 71 | 72 | // Numbers and 'TRUE'/'FALSE' boolean are handled by the parser 73 | // We need to handle date elements and 0/1 boolean values 74 | for (NSMutableDictionary *theDictionary in parsedObjects) 75 | { 76 | for (NSString *keyString in dateElements) 77 | { 78 | if ([theDictionary objectForKey:keyString] && ![[theDictionary objectForKey:keyString] isEqual:nil]) { 79 | if ([[theDictionary objectForKey:keyString] respondsToSelector:@selector(dateFromGithubDateString)]) 80 | { 81 | NSDate *date = [[theDictionary objectForKey:keyString] dateFromGithubDateString]; 82 | if (date != nil) 83 | { 84 | [theDictionary setObject:date forKey:keyString]; 85 | } 86 | } 87 | } 88 | } 89 | 90 | for (NSString *keyString in boolElements) 91 | { 92 | if ([theDictionary objectForKey:keyString] && ![[theDictionary objectForKey:keyString] isEqual:nil]) { 93 | [theDictionary setObject:[NSNumber numberWithBool:[[theDictionary objectForKey:keyString] intValue]] forKey:keyString]; 94 | } 95 | } 96 | 97 | } 98 | 99 | [delegate parsingSucceededForConnection:connectionIdentifier ofResponseType:responseType withParsedObjects:parsedObjects]; 100 | } 101 | else 102 | { 103 | [delegate parsingFailedForConnection:connectionIdentifier ofResponseType:responseType withError:error]; 104 | } 105 | 106 | [dictionary release]; 107 | 108 | } 109 | 110 | 111 | 112 | @end 113 | -------------------------------------------------------------------------------- /GithubBrowser/UAGithubEngine/Extensions/NSScanner_Extensions.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSScanner_Extensions.m 3 | // TouchCode 4 | // 5 | // Created by Jonathan Wight on 12/08/2005. 6 | // Copyright 2005 toxicsoftware.com. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person 9 | // obtaining a copy of this software and associated documentation 10 | // files (the "Software"), to deal in the Software without 11 | // restriction, including without limitation the rights to use, 12 | // copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the 14 | // Software is furnished to do so, subject to the following 15 | // conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be 18 | // included in all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 22 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 24 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 25 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 26 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 27 | // OTHER DEALINGS IN THE SOFTWARE. 28 | // 29 | 30 | #import "NSScanner_Extensions.h" 31 | 32 | #import "NSCharacterSet_Extensions.h" 33 | 34 | @implementation NSScanner (NSScanner_Extensions) 35 | 36 | - (NSString *)remainingString 37 | { 38 | return([[self string] substringFromIndex:[self scanLocation]]); 39 | } 40 | 41 | - (unichar)currentCharacter 42 | { 43 | return([[self string] characterAtIndex:[self scanLocation]]); 44 | } 45 | 46 | - (unichar)scanCharacter 47 | { 48 | unsigned theScanLocation = [self scanLocation]; 49 | unichar theCharacter = [[self string] characterAtIndex:theScanLocation]; 50 | [self setScanLocation:theScanLocation + 1]; 51 | return(theCharacter); 52 | } 53 | 54 | - (BOOL)scanCharacter:(unichar)inCharacter 55 | { 56 | unsigned theScanLocation = [self scanLocation]; 57 | if ([[self string] characterAtIndex:theScanLocation] == inCharacter) 58 | { 59 | [self setScanLocation:theScanLocation + 1]; 60 | return(YES); 61 | } 62 | else 63 | return(NO); 64 | } 65 | 66 | - (void)backtrack:(unsigned)inCount 67 | { 68 | unsigned theScanLocation = [self scanLocation]; 69 | if (inCount > theScanLocation) 70 | [NSException raise:NSGenericException format:@"Backtracked too far."]; 71 | [self setScanLocation:theScanLocation - inCount]; 72 | } 73 | 74 | - (BOOL)scanCStyleComment:(NSString **)outComment 75 | { 76 | if ([self scanString:@"/*" intoString:NULL] == YES) 77 | { 78 | NSString *theComment = NULL; 79 | if ([self scanUpToString:@"*/" intoString:&theComment] == NO) 80 | [NSException raise:NSGenericException format:@"Started to scan a C style comment but it wasn't terminated."]; 81 | 82 | if ([theComment rangeOfString:@"/*"].location != NSNotFound) 83 | [NSException raise:NSGenericException format:@"C style comments should not be nested."]; 84 | 85 | if ([self scanString:@"*/" intoString:NULL] == NO) 86 | [NSException raise:NSGenericException format:@"C style comment did not end correctly."]; 87 | 88 | if (outComment != NULL) 89 | *outComment = theComment; 90 | 91 | return(YES); 92 | } 93 | else 94 | { 95 | return(NO); 96 | } 97 | } 98 | 99 | - (BOOL)scanCPlusPlusStyleComment:(NSString **)outComment 100 | { 101 | if ([self scanString:@"//" intoString:NULL] == YES) 102 | { 103 | NSString *theComment = NULL; 104 | [self scanUpToCharactersFromSet:[NSCharacterSet linebreaksCharacterSet] intoString:&theComment]; 105 | [self scanCharactersFromSet:[NSCharacterSet linebreaksCharacterSet] intoString:NULL]; 106 | 107 | if (outComment != NULL) 108 | *outComment = theComment; 109 | 110 | return(YES); 111 | } 112 | else 113 | { 114 | return(NO); 115 | } 116 | } 117 | 118 | @end 119 | -------------------------------------------------------------------------------- /GithubBrowser/UIWebViewBasicAuth/NSData+Additions.m: -------------------------------------------------------------------------------- 1 | //NSData additions from colloquy project 2 | 3 | // Created by khammond on Mon Oct 29 2001. 4 | // Formatted by Timothy Hatcher on Sun Jul 4 2004. 5 | // Copyright (c) 2001 Kyle Hammond. All rights reserved. 6 | // Original development by Dave Winer. 7 | 8 | #import "NSData+Additions.h" 9 | 10 | static char encodingTable[64] = { 11 | 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P', 12 | 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f', 13 | 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v', 14 | 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/' }; 15 | 16 | @implementation NSData (NSDataAdditions) 17 | + (NSData *) dataWithBase64EncodedString:(NSString *) string { 18 | return [[[NSData allocWithZone:nil] initWithBase64EncodedString:string] autorelease]; 19 | } 20 | 21 | - (id) initWithBase64EncodedString:(NSString *) string { 22 | NSMutableData *mutableData = nil; 23 | 24 | if( string ) { 25 | unsigned long ixtext = 0; 26 | unsigned long lentext = 0; 27 | unsigned char ch = 0; 28 | unsigned char inbuf[4], outbuf[3]; 29 | short i = 0, ixinbuf = 0; 30 | BOOL flignore = NO; 31 | BOOL flendtext = NO; 32 | NSData *base64Data = nil; 33 | const unsigned char *base64Bytes = nil; 34 | 35 | // Convert the string to ASCII data. 36 | base64Data = [string dataUsingEncoding:NSASCIIStringEncoding]; 37 | base64Bytes = [base64Data bytes]; 38 | mutableData = [NSMutableData dataWithCapacity:[base64Data length]]; 39 | lentext = [base64Data length]; 40 | 41 | while( YES ) { 42 | if( ixtext >= lentext ) break; 43 | ch = base64Bytes[ixtext++]; 44 | flignore = NO; 45 | 46 | if( ( ch >= 'A' ) && ( ch <= 'Z' ) ) ch = ch - 'A'; 47 | else if( ( ch >= 'a' ) && ( ch <= 'z' ) ) ch = ch - 'a' + 26; 48 | else if( ( ch >= '0' ) && ( ch <= '9' ) ) ch = ch - '0' + 52; 49 | else if( ch == '+' ) ch = 62; 50 | else if( ch == '=' ) flendtext = YES; 51 | else if( ch == '/' ) ch = 63; 52 | else flignore = YES; 53 | 54 | if( ! flignore ) { 55 | short ctcharsinbuf = 3; 56 | BOOL flbreak = NO; 57 | 58 | if( flendtext ) { 59 | if( ! ixinbuf ) break; 60 | if( ( ixinbuf == 1 ) || ( ixinbuf == 2 ) ) ctcharsinbuf = 1; 61 | else ctcharsinbuf = 2; 62 | ixinbuf = 3; 63 | flbreak = YES; 64 | } 65 | 66 | inbuf [ixinbuf++] = ch; 67 | 68 | if( ixinbuf == 4 ) { 69 | ixinbuf = 0; 70 | outbuf [0] = ( inbuf[0] << 2 ) | ( ( inbuf[1] & 0x30) >> 4 ); 71 | outbuf [1] = ( ( inbuf[1] & 0x0F ) << 4 ) | ( ( inbuf[2] & 0x3C ) >> 2 ); 72 | outbuf [2] = ( ( inbuf[2] & 0x03 ) << 6 ) | ( inbuf[3] & 0x3F ); 73 | 74 | for( i = 0; i < ctcharsinbuf; i++ ) 75 | [mutableData appendBytes:&outbuf[i] length:1]; 76 | } 77 | 78 | if( flbreak ) break; 79 | } 80 | } 81 | } 82 | 83 | self = [self initWithData:mutableData]; 84 | return self; 85 | } 86 | 87 | #pragma mark - 88 | 89 | - (NSString *) base64Encoding { 90 | return [self base64EncodingWithLineLength:0]; 91 | } 92 | 93 | - (NSString *) base64EncodingWithLineLength:(unsigned int) lineLength { 94 | const unsigned char *bytes = [self bytes]; 95 | NSMutableString *result = [NSMutableString stringWithCapacity:[self length]]; 96 | unsigned long ixtext = 0; 97 | unsigned long lentext = [self length]; 98 | long ctremaining = 0; 99 | unsigned char inbuf[3], outbuf[4]; 100 | unsigned short i = 0; 101 | unsigned short charsonline = 0, ctcopy = 0; 102 | unsigned long ix = 0; 103 | 104 | while( YES ) { 105 | ctremaining = lentext - ixtext; 106 | if( ctremaining <= 0 ) break; 107 | 108 | for( i = 0; i < 3; i++ ) { 109 | ix = ixtext + i; 110 | if( ix < lentext ) inbuf[i] = bytes[ix]; 111 | else inbuf [i] = 0; 112 | } 113 | 114 | outbuf [0] = (inbuf [0] & 0xFC) >> 2; 115 | outbuf [1] = ((inbuf [0] & 0x03) << 4) | ((inbuf [1] & 0xF0) >> 4); 116 | outbuf [2] = ((inbuf [1] & 0x0F) << 2) | ((inbuf [2] & 0xC0) >> 6); 117 | outbuf [3] = inbuf [2] & 0x3F; 118 | ctcopy = 4; 119 | 120 | switch( ctremaining ) { 121 | case 1: 122 | ctcopy = 2; 123 | break; 124 | case 2: 125 | ctcopy = 3; 126 | break; 127 | } 128 | 129 | for( i = 0; i < ctcopy; i++ ) 130 | [result appendFormat:@"%c", encodingTable[outbuf[i]]]; 131 | 132 | for( i = ctcopy; i < 4; i++ ) 133 | [result appendString:@"="]; 134 | 135 | ixtext += 3; 136 | charsonline += 4; 137 | 138 | if( lineLength > 0 ) { 139 | if( charsonline >= lineLength ) { 140 | charsonline = 0; 141 | [result appendString:@"\n"]; 142 | } 143 | } 144 | } 145 | 146 | return [NSString stringWithString:result]; 147 | } 148 | 149 | #pragma mark - 150 | 151 | - (BOOL) hasPrefix:(NSData *) prefix { 152 | unsigned int length = [prefix length]; 153 | if( ! prefix || ! length || [self length] < length ) return NO; 154 | return ( memcmp( [self bytes], [prefix bytes], length ) == 0 ); 155 | } 156 | 157 | - (BOOL) hasPrefixBytes:(void *) prefix length:(unsigned int) length { 158 | if( ! prefix || ! length || [self length] < length ) return NO; 159 | return ( memcmp( [self bytes], prefix, length ) == 0 ); 160 | } 161 | @end 162 | -------------------------------------------------------------------------------- /GithubBrowser/UAGithubEngine/UAGithubEngineRequestTypes.h: -------------------------------------------------------------------------------- 1 | // 2 | // UAGithubEngineRequestTypes.h 3 | // UAGithubEngine 4 | // 5 | // Created by Owain Hunt on 05/04/2010. 6 | // Copyright 2010 Owain R Hunt. All rights reserved. 7 | // 8 | 9 | 10 | 11 | typedef enum UAGithubRequestType 12 | { 13 | UAGithubUsersRequest = 0, // Get more than one non-specific user 14 | UAGithubUserRequest, // Get exactly one specific user 15 | UAGithubRepositoriesRequest, // Get more than one non-specific repository 16 | UAGithubRepositoryRequest, // Get exactly one specific repository 17 | UAGithubRepositoryUpdateRequest, // Update repository metadata 18 | UAGithubRepositoryWatchRequest, // Watch a repository 19 | UAGithubRepositoryUnwatchRequest, // Unwatch a repository 20 | UAGithubRepositoryForkRequest, // Fork a repository 21 | UAGithubRepositoryCreateRequest, // Create a repository 22 | UAGithubRepositoryPrivatiseRequest, // Make a repository private 23 | UAGithubRepositoryPubliciseRequest, // Make a repository public 24 | UAGithubRepositoryDeleteRequest, // Delete a repository 25 | UAGithubRepositoryDeleteConfirmationRequest, // Confirm deletion of a repository 26 | UAGithubDeployKeysRequest, // Get repository-specific deploy keys 27 | UAGithubDeployKeyAddRequest, // Add a repository-specific deploy key 28 | UAGithubDeployKeyDeleteRequest, // Delete a repository-specific deploy key 29 | UAGithubRepositoryLanguageBreakdownRequest, // Get the language breakdown for a repository 30 | UAGithubTagsRequest, // Tags for a repository 31 | UAGithubBranchesRequest, // Branches for a repository 32 | UAGithubCollaboratorsRequest, // Collaborators for a repository 33 | UAGithubCollaboratorAddRequest, // Add a collaborator 34 | UAGithubCollaboratorRemoveRequest, // Remove a collaborator 35 | UAGithubCommitsRequest, // Get more than one non-specific commit 36 | UAGithubCommitRequest, // Get exactly one specific commit 37 | UAGithubIssuesOpenRequest, // Get open issues 38 | UAGithubIssuesClosedRequest, // Get closed issues 39 | UAGithubIssueRequest, // Get exactly one specific issue 40 | UAGithubIssueAddRequest, // Add an issue 41 | UAGithubIssueEditRequest, // Edit an issue 42 | UAGithubIssueCloseRequest, // Close an issue 43 | UAGithubIssueReopenRequest, // Reopen a closed issue 44 | UAGithubRepositoryLabelsRequest, // Get repository-wide issue labels 45 | UAGithubRepositoryLabelAddRequest, // Add a repository-wide issue label 46 | UAGithubRepositoryLabelRemoveRequest, // Remove a repository-wide issue label 47 | UAGithubIssueLabelAddRequest, // Add a label to a specific issue 48 | UAGithubIssueLabelRemoveRequest, // Remove a label from a specific issue 49 | UAGithubIssueCommentsRequest, // Get more than one non-specific issue comment 50 | UAGithubIssueCommentRequest, // Get exactly one specific issue comment 51 | UAGithubIssueCommentAddRequest, // Add a comment to an issue 52 | UAGithubTreeRequest, // Get the listing of a tree by SHA 53 | UAGithubBlobsRequest, // Get the names and SHAs of all blobs for a specific tree SHA 54 | UAGithubBlobRequest, // Get data about a single blob by tree SHA and path 55 | UAGithubRawBlobRequest, // Get the raw data for a blob 56 | UAGithubFollowingRequest, // Following 57 | UAGithubFollowersRequest, // Followers 58 | UAGithubFollowRequest, // Follow or UnFollow a User 59 | UAGithubOrganizationsRequest, // Get more than one organizations 60 | 61 | } UAGithubRequestType; 62 | 63 | 64 | typedef enum UAGithubResponseType 65 | { 66 | UAGithubUsersResponse = 0, // One or more users 67 | UAGithubUserResponse, // Exactly one user 68 | UAGithubRepositoriesResponse, // One or more repositories 69 | UAGithubRepositoryResponse, // Exactly one repository 70 | UAGithubDeleteRepositoryResponse, // Token to send in delete confirmation request 71 | UAGithubDeleteRepositoryConfirmationResponse, // Confirmation of deletion 72 | UAGithubDeployKeysResponse, // One or more deploy keys 73 | UAGithubRepositoryLanguageBreakdownResponse, // Breakdown in language-bytes pairs 74 | UAGithubTagsResponse, // Tags in name-SHA pairs 75 | UAGithubBranchesResponse, // Branches in name-SHA pairs 76 | UAGithubCollaboratorsResponse, // One or more usernames 77 | UAGithubCommitsResponse, // One or more commits 78 | UAGithubCommitResponse, // Exactly one commit 79 | UAGithubIssuesResponse, // One or more issues 80 | UAGithubIssueResponse, // Exactly one issue 81 | UAGithubIssueCommentsResponse, // One or more issue comments 82 | UAGithubIssueCommentResponse, // Exactly one issue comment 83 | UAGithubIssueLabelsResponse, // One or more issue labels 84 | UAGithubRepositoryLabelsResponse, // One or more repository-wide issue labels 85 | UAGithubTreeResponse, // Metadata for all files in given commit 86 | UAGithubBlobsResponse, // Name and SHA for all files in given tree SHA 87 | UAGithubBlobResponse, // Metadata and file data for given tree SHA and path 88 | UAGithubRawBlobResponse, // Raw file 89 | UAGithubFollowingResponse, // Following 90 | UAGithubFollowersResponse, // Followers 91 | UAGithubFollowResponse, // Follow or UnFollow a User 92 | UAGithubOrganizationsResponse, // Organizations 93 | 94 | } UAGithubResponseType; 95 | -------------------------------------------------------------------------------- /GithubBrowser/RootViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // RootViewController.m 3 | // GithubBrowser 4 | // 5 | // Created by Oscar Del Ben on 4/6/11. 6 | // Copyright 2011 DibiStore. All rights reserved. 7 | // 8 | 9 | #import "RootViewController.h" 10 | 11 | #import "DetailViewController.h" 12 | #import "SearchViewController.h" 13 | #import "SettingsViewController.h" 14 | #import "ReposViewController.h" 15 | 16 | @implementation RootViewController 17 | 18 | @synthesize detailViewController; 19 | @synthesize githubEngine; 20 | @synthesize username; 21 | 22 | - (void)fetchUsername 23 | { 24 | self.githubEngine = [[UAGithubEngine alloc] initWithUsername:nil password:nil delegate:self withReachability:NO]; 25 | self.username = [ApplicationHelper username]; 26 | 27 | if (!username || [username blank]) { 28 | return; 29 | } 30 | 31 | NSString *password = [ApplicationHelper password]; 32 | 33 | self.githubEngine.username = username; 34 | self.githubEngine.password = password; 35 | 36 | self.navigationItem.title = username; 37 | } 38 | 39 | - (void)viewDidLoad 40 | { 41 | [super viewDidLoad]; 42 | self.clearsSelectionOnViewWillAppear = NO; 43 | self.contentSizeForViewInPopover = CGSizeMake(320.0, 600.0); 44 | 45 | [detailViewController showGithubHomepage]; 46 | 47 | [self fetchUsername]; 48 | 49 | NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; 50 | [notificationCenter addObserver:self selector:@selector(reloadData) name:GBCredentialsChanged object:nil]; 51 | 52 | // toolbar 53 | 54 | UIBarButtonItem *homeButton = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"53-house.png"] style:UIBarButtonItemStylePlain target:self.detailViewController action:@selector(showGithubHomepage)]; 55 | 56 | self.toolbarItems = [NSArray arrayWithObjects:homeButton, nil]; 57 | self.navigationController.toolbarHidden = NO; 58 | 59 | // force gradient 60 | [self.navigationController.toolbar setBarStyle:UIBarStyleDefault]; 61 | 62 | [homeButton release]; 63 | } 64 | 65 | 66 | 67 | - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { 68 | return YES; 69 | } 70 | 71 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 72 | { 73 | return 1; 74 | 75 | } 76 | 77 | 78 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 79 | { 80 | // Username 81 | // Organizations 82 | // Add Account 83 | 84 | return (!username || [username blank]) ? 1 :2; 85 | } 86 | 87 | 88 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 89 | { 90 | static NSString *CellIdentifier = @"Cell"; 91 | 92 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 93 | if (cell == nil) { 94 | cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease]; 95 | 96 | cell.textLabel.backgroundColor = [UIColor clearColor]; 97 | cell.detailTextLabel.backgroundColor = [UIColor clearColor]; 98 | } 99 | 100 | // Configure the cell. 101 | 102 | if (!username || [username blank]) 103 | { 104 | cell.textLabel.text = @"Add Account"; 105 | } 106 | else 107 | { 108 | if (indexPath.row == 0) 109 | { 110 | cell.textLabel.text = username; 111 | cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; 112 | } 113 | else 114 | { 115 | cell.textLabel.text = @"Manage Account"; 116 | } 117 | } 118 | 119 | return cell; 120 | } 121 | 122 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 123 | { 124 | if (!username || [username blank]) 125 | { 126 | [self showSettings]; 127 | } 128 | else 129 | { 130 | 131 | if (indexPath.row == 0) 132 | { 133 | // reset current username 134 | [ApplicationHelper setCurrentUsername:[ApplicationHelper username] notifyOfChange:NO]; 135 | 136 | ReposViewController *reposViewController = [[[ReposViewController alloc] initWithStyle:UITableViewStylePlain] autorelease]; 137 | reposViewController.detailViewController = self.detailViewController; 138 | [self.navigationController pushViewController:reposViewController animated:YES]; 139 | } 140 | else 141 | { 142 | [self showSettings]; 143 | } 144 | } 145 | } 146 | 147 | - (void)dealloc 148 | { 149 | [detailViewController release]; 150 | [githubEngine release]; 151 | [username release]; 152 | 153 | [super dealloc]; 154 | } 155 | 156 | #pragma mark Utility methods 157 | 158 | - (void)showSettings 159 | { 160 | SettingsViewController *viewController = [[SettingsViewController alloc] initWithNibName:@"SettingsViewController" bundle:nil]; 161 | UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:viewController]; 162 | navController.modalPresentationStyle = UIModalPresentationFormSheet; 163 | 164 | [self presentModalViewController:navController animated:YES]; 165 | 166 | [viewController release]; 167 | } 168 | 169 | - (void)reloadData 170 | { 171 | [self fetchUsername]; 172 | [self.tableView reloadData]; 173 | } 174 | 175 | @end 176 | -------------------------------------------------------------------------------- /GithubBrowser/UAGithubEngine/UAGithubEngine.h: -------------------------------------------------------------------------------- 1 | // 2 | // UAGithubEngine.h 3 | // UAGithubEngine 4 | // 5 | // Created by Owain Hunt on 02/04/2010. 6 | // Copyright 2010 Owain R Hunt. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "UAReachability.h" 11 | #import "UAGithubEngineDelegate.h" 12 | #import "UAGithubEngineRequestTypes.h" 13 | #import "UAGithubEngineConstants.h" 14 | #import "UAGithubParserDelegate.h" 15 | 16 | @interface UAGithubEngine : NSObject { 17 | id delegate; 18 | NSString *username; 19 | NSString *password; 20 | NSMutableDictionary *connections; 21 | UAReachability *reachability; 22 | BOOL isReachable; 23 | } 24 | 25 | @property (assign) id delegate; 26 | @property (nonatomic, retain) NSString *username; 27 | @property (nonatomic, retain) NSString *password; 28 | @property (nonatomic, retain) NSMutableDictionary *connections; 29 | @property (nonatomic, retain) UAReachability *reachability; 30 | @property (nonatomic, assign, readonly) BOOL isReachable; 31 | 32 | - (id)initWithUsername:(NSString *)aUsername password:(NSString *)aPassword delegate:(id)theDelegate withReachability:(BOOL)withReach; 33 | - (NSString *)sendRequest:(NSString *)path requestType:(UAGithubRequestType)requestType responseType:(UAGithubResponseType)responseType withParameters:(NSDictionary *)params; 34 | 35 | /* 36 | Where methods take a 'whateverPath' argument, supply the full path to 'whatever'. 37 | For example, if the method calls for 'repositoryPath', supply @"username/repository". 38 | 39 | Where methods take a 'whateverName' argument, supply just the name of 'whatever'. The username used will be that set in the engine instance. 40 | 41 | For methods that take an NSDictionary as an argument, this should contain the relevant keys and values for the required API call. 42 | See the documentation for more details on updating repositories, and adding and editing issues. 43 | */ 44 | 45 | #pragma mark Users 46 | 47 | - (NSString *)user:(NSString *)user; 48 | - (NSString *)searchUsers:(NSString *)query byEmail:(BOOL)email; 49 | - (NSString *)following:(NSString *)user; 50 | - (NSString *)followers:(NSString *)user; 51 | - (NSString *)follow:(NSString *)user; 52 | - (NSString *)unfollow:(NSString *)user; 53 | 54 | 55 | #pragma mark Repositories 56 | 57 | - (NSString *)repositoriesForUser:(NSString *)aUser includeWatched:(BOOL)watched; 58 | - (NSString *)repositoriesForUser:(NSString *)aUser includeWatched:(BOOL)watched page:(int)page; 59 | - (NSString *)repository:(NSString *)repositoryPath; 60 | - (NSString *)searchRepositories:(NSString *)query; 61 | - (NSString *)updateRepository:(NSString *)repositoryPath withInfo:(NSDictionary *)infoDictionary; 62 | - (NSString *)watchRepository:(NSString *)repositoryPath; 63 | - (NSString *)unwatchRepository:(NSString *)repositoryPath; 64 | - (NSString *)forkRepository:(NSString *)repositoryPath; 65 | - (NSString *)createRepositoryWithInfo:(NSDictionary *)infoDictionary; 66 | - (NSString *)deleteRepository:(NSString *)repositoryName; 67 | - (NSString *)confirmDeletionOfRepository:(NSString *)repositoryName withToken:(NSString *)deleteToken; 68 | - (NSString *)privatiseRepository:(NSString *)repositoryName; 69 | - (NSString *)publiciseRepository:(NSString *)repositoryName; 70 | - (NSString *)deployKeysForRepository:(NSString *)repositoryName; 71 | - (NSString *)addDeployKey:(NSString *)keyData withTitle:(NSString *)keyTitle ToRepository:(NSString *)repositoryName; 72 | - (NSString *)removeDeployKey:(NSString *)keyID fromRepository:(NSString *)repositoryName; 73 | - (NSString *)collaboratorsForRepository:(NSString *)repositoryName; 74 | - (NSString *)addCollaborator:(NSString *)collaborator toRepository:(NSString *)repositoryName; 75 | - (NSString *)removeCollaborator:(NSString *)collaborator fromRepository:(NSString *)repositoryPath; 76 | - (NSString *)pushableRepositories; 77 | - (NSString *)networkForRepository:(NSString *)repositoryPath; 78 | - (NSString *)languageBreakdownForRepository:(NSString *)repositoryPath; 79 | - (NSString *)tagsForRepository:(NSString *)repositoryPath; 80 | - (NSString *)branchesForRepository:(NSString *)repositoryPath; 81 | - (NSString *)organizationsForUser:(NSString *)aUser; 82 | 83 | 84 | #pragma mark Commits 85 | 86 | - (NSString *)commitsForBranch:(NSString *)branchPath; 87 | - (NSString *)commit:(NSString *)commitPath; 88 | 89 | 90 | #pragma mark Issues 91 | 92 | - (NSString *)issuesForRepository:(NSString *)repositoryPath withRequestType:(UAGithubRequestType)requestType; 93 | - (NSString *)issue:(NSString *)issuePath; 94 | - (NSString *)editIssue:(NSString *)issuePath withDictionary:(NSDictionary *)issueDictionary; 95 | - (NSString *)addIssueForRepository:(NSString *)repositoryPath withDictionary:(NSDictionary *)issueDictionary; 96 | - (NSString *)closeIssue:(NSString *)issuePath; 97 | - (NSString *)reopenIssue:(NSString *)issuePath; 98 | 99 | 100 | #pragma mark Labels 101 | 102 | - (NSString *)labelsForRepository:(NSString *)repositoryPath; 103 | - (NSString *)addLabel:(NSString *)label toRepository:(NSString *)repositoryPath; 104 | - (NSString *)removeLabel:(NSString *)label fromRepository:(NSString *)repositoryPath; 105 | - (NSString *)addLabel:(NSString *)label toIssue:(NSInteger)issueNumber inRepository:(NSString *)repositoryPath; 106 | - (NSString *)removeLabel:(NSString *)label fromIssue:(NSInteger)issueNumber inRepository:(NSString *)repositoryPath; 107 | 108 | 109 | #pragma mark Comments 110 | 111 | - (NSString *)commentsForIssue:(NSString *)issuePath; 112 | - (NSString *)addComment:(NSString *)comment toIssue:(NSString *)issuePath; 113 | 114 | 115 | #pragma mark Trees 116 | 117 | - (NSString *)tree:(NSString *)treePath; 118 | 119 | 120 | #pragma mark Blobs 121 | 122 | - (NSString *)blobsForSHA:(NSString *)shaPath; 123 | - (NSString *)blob:(NSString *)blobPath; 124 | - (NSString *)rawBlob:(NSString *)blobPath; 125 | 126 | 127 | @end 128 | -------------------------------------------------------------------------------- /GithubBrowser/MGSplitDividerView.m: -------------------------------------------------------------------------------- 1 | // 2 | // MGSplitDividerView.m 3 | // MGSplitView 4 | // 5 | // Created by Matt Gemmell on 26/07/2010. 6 | // Copyright 2010 Instinctive Code. 7 | // 8 | 9 | #import "MGSplitDividerView.h" 10 | #import "MGSplitViewController.h" 11 | 12 | 13 | @implementation MGSplitDividerView 14 | 15 | 16 | #pragma mark - 17 | #pragma mark Setup and teardown 18 | 19 | 20 | - (id)initWithFrame:(CGRect)frame 21 | { 22 | if ((self = [super initWithFrame:frame])) { 23 | self.userInteractionEnabled = NO; 24 | self.allowsDragging = NO; 25 | self.contentMode = UIViewContentModeRedraw; 26 | } 27 | return self; 28 | } 29 | 30 | 31 | - (void)dealloc 32 | { 33 | self.splitViewController = nil; 34 | [super dealloc]; 35 | } 36 | 37 | 38 | #pragma mark - 39 | #pragma mark Drawing 40 | 41 | 42 | - (void)drawRect:(CGRect)rect 43 | { 44 | if (splitViewController.dividerStyle == MGSplitViewDividerStyleThin) { 45 | [super drawRect:rect]; 46 | 47 | } else if (splitViewController.dividerStyle == MGSplitViewDividerStylePaneSplitter) { 48 | // Draw gradient background. 49 | CGRect bounds = self.bounds; 50 | CGColorSpaceRef rgb = CGColorSpaceCreateDeviceRGB(); 51 | CGFloat locations[2] = {0, 1}; 52 | CGFloat components[8] = { 0.988, 0.988, 0.988, 1.0, // light 53 | 0.875, 0.875, 0.875, 1.0 };// dark 54 | CGGradientRef gradient = CGGradientCreateWithColorComponents (rgb, components, locations, 2); 55 | CGContextRef context = UIGraphicsGetCurrentContext(); 56 | CGPoint start, end; 57 | if (splitViewController.vertical) { 58 | // Light left to dark right. 59 | start = CGPointMake(CGRectGetMinX(bounds), CGRectGetMidY(bounds)); 60 | end = CGPointMake(CGRectGetMaxX(bounds), CGRectGetMidY(bounds)); 61 | } else { 62 | // Light top to dark bottom. 63 | start = CGPointMake(CGRectGetMidX(bounds), CGRectGetMinY(bounds)); 64 | end = CGPointMake(CGRectGetMidX(bounds), CGRectGetMaxY(bounds)); 65 | } 66 | CGContextDrawLinearGradient(context, gradient, start, end, 0); 67 | CGColorSpaceRelease(rgb); 68 | CGGradientRelease(gradient); 69 | 70 | // Draw borders. 71 | float borderThickness = 1.0; 72 | [[UIColor colorWithWhite:0.7 alpha:1.0] set]; 73 | CGRect borderRect = bounds; 74 | if (splitViewController.vertical) { 75 | borderRect.size.width = borderThickness; 76 | UIRectFill(borderRect); 77 | borderRect.origin.x = CGRectGetMaxX(bounds) - borderThickness; 78 | UIRectFill(borderRect); 79 | 80 | } else { 81 | borderRect.size.height = borderThickness; 82 | UIRectFill(borderRect); 83 | borderRect.origin.y = CGRectGetMaxY(bounds) - borderThickness; 84 | UIRectFill(borderRect); 85 | } 86 | 87 | // Draw grip. 88 | [self drawGripThumbInRect:bounds]; 89 | } 90 | } 91 | 92 | 93 | - (void)drawGripThumbInRect:(CGRect)rect 94 | { 95 | float width = 9.0; 96 | float height; 97 | if (splitViewController.vertical) { 98 | height = 30.0; 99 | } else { 100 | height = width; 101 | width = 30.0; 102 | } 103 | 104 | // Draw grip in centred in rect. 105 | CGRect gripRect = CGRectMake(0, 0, width, height); 106 | gripRect.origin.x = ((rect.size.width - gripRect.size.width) / 2.0); 107 | gripRect.origin.y = ((rect.size.height - gripRect.size.height) / 2.0); 108 | 109 | float stripThickness = 1.0; 110 | UIColor *stripColor = [UIColor colorWithWhite:0.35 alpha:1.0]; 111 | UIColor *lightColor = [UIColor colorWithWhite:1.0 alpha:1.0]; 112 | float space = 3.0; 113 | if (splitViewController.vertical) { 114 | gripRect.size.width = stripThickness; 115 | [stripColor set]; 116 | UIRectFill(gripRect); 117 | 118 | gripRect.origin.x += stripThickness; 119 | gripRect.origin.y += 1; 120 | [lightColor set]; 121 | UIRectFill(gripRect); 122 | gripRect.origin.x -= stripThickness; 123 | gripRect.origin.y -= 1; 124 | 125 | gripRect.origin.x += space + stripThickness; 126 | [stripColor set]; 127 | UIRectFill(gripRect); 128 | 129 | gripRect.origin.x += stripThickness; 130 | gripRect.origin.y += 1; 131 | [lightColor set]; 132 | UIRectFill(gripRect); 133 | gripRect.origin.x -= stripThickness; 134 | gripRect.origin.y -= 1; 135 | 136 | gripRect.origin.x += space + stripThickness; 137 | [stripColor set]; 138 | UIRectFill(gripRect); 139 | 140 | gripRect.origin.x += stripThickness; 141 | gripRect.origin.y += 1; 142 | [lightColor set]; 143 | UIRectFill(gripRect); 144 | 145 | } else { 146 | gripRect.size.height = stripThickness; 147 | [stripColor set]; 148 | UIRectFill(gripRect); 149 | 150 | gripRect.origin.y += stripThickness; 151 | gripRect.origin.x -= 1; 152 | [lightColor set]; 153 | UIRectFill(gripRect); 154 | gripRect.origin.y -= stripThickness; 155 | gripRect.origin.x += 1; 156 | 157 | gripRect.origin.y += space + stripThickness; 158 | [stripColor set]; 159 | UIRectFill(gripRect); 160 | 161 | gripRect.origin.y += stripThickness; 162 | gripRect.origin.x -= 1; 163 | [lightColor set]; 164 | UIRectFill(gripRect); 165 | gripRect.origin.y -= stripThickness; 166 | gripRect.origin.x += 1; 167 | 168 | gripRect.origin.y += space + stripThickness; 169 | [stripColor set]; 170 | UIRectFill(gripRect); 171 | 172 | gripRect.origin.y += stripThickness; 173 | gripRect.origin.x -= 1; 174 | [lightColor set]; 175 | UIRectFill(gripRect); 176 | } 177 | } 178 | 179 | 180 | #pragma mark - 181 | #pragma mark Interaction 182 | 183 | 184 | - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event 185 | { 186 | UITouch *touch = [touches anyObject]; 187 | if (touch) { 188 | CGPoint lastPt = [touch previousLocationInView:self]; 189 | CGPoint pt = [touch locationInView:self]; 190 | float offset = (splitViewController.vertical) ? pt.x - lastPt.x : pt.y - lastPt.y; 191 | if (!splitViewController.masterBeforeDetail) { 192 | offset = -offset; 193 | } 194 | splitViewController.splitPosition = splitViewController.splitPosition + offset; 195 | } 196 | } 197 | 198 | 199 | #pragma mark - 200 | #pragma mark Accessors and properties 201 | 202 | 203 | - (void)setAllowsDragging:(BOOL)flag 204 | { 205 | if (flag != allowsDragging) { 206 | allowsDragging = flag; 207 | self.userInteractionEnabled = allowsDragging; 208 | } 209 | } 210 | 211 | 212 | @synthesize splitViewController; 213 | @synthesize allowsDragging; 214 | 215 | 216 | @end 217 | -------------------------------------------------------------------------------- /GithubBrowser/UAGithubEngine/CDataScanner.m: -------------------------------------------------------------------------------- 1 | // 2 | // CDataScanner.m 3 | // TouchCode 4 | // 5 | // Created by Jonathan Wight on 04/16/08. 6 | // Copyright 2008 toxicsoftware.com. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person 9 | // obtaining a copy of this software and associated documentation 10 | // files (the "Software"), to deal in the Software without 11 | // restriction, including without limitation the rights to use, 12 | // copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the 14 | // Software is furnished to do so, subject to the following 15 | // conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be 18 | // included in all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 22 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 24 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 25 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 26 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 27 | // OTHER DEALINGS IN THE SOFTWARE. 28 | // 29 | 30 | #import "CDataScanner.h" 31 | 32 | #import "CDataScanner_Extensions.h" 33 | 34 | @interface CDataScanner () 35 | @property (readwrite, nonatomic, retain) NSCharacterSet *doubleCharacters; 36 | @end 37 | 38 | #pragma mark - 39 | 40 | inline static unichar CharacterAtPointer(void *start, void *end) 41 | { 42 | #pragma unused(end) 43 | 44 | const u_int8_t theByte = *(u_int8_t *)start; 45 | if (theByte & 0x80) 46 | { 47 | // TODO -- UNICODE!!!! (well in theory nothing todo here) 48 | } 49 | const unichar theCharacter = theByte; 50 | return(theCharacter); 51 | } 52 | 53 | @implementation CDataScanner 54 | 55 | @synthesize doubleCharacters; 56 | 57 | + (id)scannerWithData:(NSData *)inData 58 | { 59 | CDataScanner *theScanner = [[[self alloc] init] autorelease]; 60 | theScanner.data = inData; 61 | return(theScanner); 62 | } 63 | 64 | - (id)init 65 | { 66 | if ((self = [super init]) != nil) 67 | { 68 | self.doubleCharacters = [NSCharacterSet characterSetWithCharactersInString:@"0123456789eE-."]; 69 | } 70 | return(self); 71 | } 72 | 73 | - (void)dealloc 74 | { 75 | self.data = NULL; 76 | self.doubleCharacters = NULL; 77 | // 78 | [super dealloc]; 79 | } 80 | 81 | - (NSUInteger)scanLocation 82 | { 83 | return(current - start); 84 | } 85 | 86 | - (NSData *)data 87 | { 88 | return(data); 89 | } 90 | 91 | - (void)setData:(NSData *)inData 92 | { 93 | if (data != inData) 94 | { 95 | if (data) 96 | { 97 | [data release]; 98 | data = NULL; 99 | } 100 | 101 | if (inData) 102 | { 103 | data = [inData retain]; 104 | // 105 | start = (u_int8_t *)data.bytes; 106 | end = start + data.length; 107 | current = start; 108 | length = data.length; 109 | } 110 | } 111 | } 112 | 113 | - (void)setScanLocation:(NSUInteger)inScanLocation 114 | { 115 | current = start + inScanLocation; 116 | } 117 | 118 | - (BOOL)isAtEnd 119 | { 120 | return(self.scanLocation >= length); 121 | } 122 | 123 | - (unichar)currentCharacter 124 | { 125 | return(CharacterAtPointer(current, end)); 126 | } 127 | 128 | #pragma mark - 129 | 130 | - (unichar)scanCharacter 131 | { 132 | const unichar theCharacter = CharacterAtPointer(current++, end); 133 | return(theCharacter); 134 | } 135 | 136 | - (BOOL)scanCharacter:(unichar)inCharacter 137 | { 138 | unichar theCharacter = CharacterAtPointer(current, end); 139 | if (theCharacter == inCharacter) 140 | { 141 | ++current; 142 | return(YES); 143 | } 144 | else 145 | return(NO); 146 | } 147 | 148 | - (BOOL)scanUTF8String:(const char *)inString intoString:(NSString **)outValue; 149 | { 150 | const size_t theLength = strlen(inString); 151 | if ((size_t)(end - current) < theLength) 152 | return(NO); 153 | if (strncmp((char *)current, inString, theLength) == 0) 154 | { 155 | current += theLength; 156 | if (outValue) 157 | *outValue = [NSString stringWithUTF8String:inString]; 158 | return(YES); 159 | } 160 | return(NO); 161 | } 162 | 163 | - (BOOL)scanString:(NSString *)inString intoString:(NSString **)outValue 164 | { 165 | if ((size_t)(end - current) < inString.length) 166 | return(NO); 167 | if (strncmp((char *)current, [inString UTF8String], inString.length) == 0) 168 | { 169 | current += inString.length; 170 | if (outValue) 171 | *outValue = inString; 172 | return(YES); 173 | } 174 | return(NO); 175 | } 176 | 177 | - (BOOL)scanCharactersFromSet:(NSCharacterSet *)inSet intoString:(NSString **)outValue 178 | { 179 | u_int8_t *P; 180 | for (P = current; P < end && [inSet characterIsMember:*P] == YES; ++P) 181 | ; 182 | 183 | if (P == current) 184 | { 185 | return(NO); 186 | } 187 | 188 | if (outValue) 189 | { 190 | *outValue = [[[NSString alloc] initWithBytes:current length:P - current encoding:NSUTF8StringEncoding] autorelease]; 191 | } 192 | 193 | current = P; 194 | 195 | return(YES); 196 | } 197 | 198 | - (BOOL)scanUpToString:(NSString *)inString intoString:(NSString **)outValue 199 | { 200 | const char *theToken = [inString UTF8String]; 201 | const char *theResult = strnstr((char *)current, theToken, end - current); 202 | if (theResult == NULL) 203 | { 204 | return(NO); 205 | } 206 | 207 | if (outValue) 208 | { 209 | *outValue = [[[NSString alloc] initWithBytes:current length:theResult - (char *)current encoding:NSUTF8StringEncoding] autorelease]; 210 | } 211 | 212 | current = (u_int8_t *)theResult; 213 | 214 | return(YES); 215 | } 216 | 217 | - (BOOL)scanUpToCharactersFromSet:(NSCharacterSet *)inSet intoString:(NSString **)outValue 218 | { 219 | u_int8_t *P; 220 | for (P = current; P < end && [inSet characterIsMember:*P] == NO; ++P) 221 | ; 222 | 223 | if (P == current) 224 | { 225 | return(NO); 226 | } 227 | 228 | if (outValue) 229 | { 230 | *outValue = [[[NSString alloc] initWithBytes:current length:P - current encoding:NSUTF8StringEncoding] autorelease]; 231 | } 232 | 233 | current = P; 234 | 235 | return(YES); 236 | } 237 | 238 | - (BOOL)scanNumber:(NSNumber **)outValue 239 | { 240 | // Replace all of this with a strtod call 241 | NSString *theString = NULL; 242 | if ([self scanCharactersFromSet:doubleCharacters intoString:&theString]) 243 | { 244 | if (outValue) 245 | *outValue = [NSNumber numberWithDouble:[theString doubleValue]]; // TODO dont use doubleValue 246 | return(YES); 247 | } 248 | return(NO); 249 | } 250 | 251 | - (void)skipWhitespace 252 | { 253 | u_int8_t *P; 254 | for (P = current; P < end && (isspace(*P)); ++P) 255 | ; 256 | 257 | current = P; 258 | } 259 | 260 | - (NSString *)remainingString 261 | { 262 | NSData *theRemainingData = [NSData dataWithBytes:current length:end - current]; 263 | NSString *theString = [[[NSString alloc] initWithData:theRemainingData encoding:NSUTF8StringEncoding] autorelease]; 264 | return(theString); 265 | } 266 | 267 | @end 268 | -------------------------------------------------------------------------------- /GithubBrowser/MGSplitCornersView.m: -------------------------------------------------------------------------------- 1 | // 2 | // MGSplitCornersView.m 3 | // MGSplitView 4 | // 5 | // Created by Matt Gemmell on 28/07/2010. 6 | // Copyright 2010 Instinctive Code. 7 | // 8 | 9 | #import "MGSplitCornersView.h" 10 | 11 | 12 | @implementation MGSplitCornersView 13 | 14 | 15 | #pragma mark - 16 | #pragma mark Setup and teardown 17 | 18 | 19 | - (id)initWithFrame:(CGRect)frame 20 | { 21 | if ((self = [super initWithFrame:frame])) { 22 | self.contentMode = UIViewContentModeRedraw; 23 | self.userInteractionEnabled = NO; 24 | self.opaque = NO; 25 | self.backgroundColor = [UIColor clearColor]; 26 | cornerRadius = 0.0; // actual value is set by the splitViewController. 27 | cornersPosition = MGCornersPositionLeadingVertical; 28 | } 29 | 30 | return self; 31 | } 32 | 33 | 34 | - (void)dealloc 35 | { 36 | self.cornerBackgroundColor = nil; 37 | 38 | [super dealloc]; 39 | } 40 | 41 | 42 | #pragma mark - 43 | #pragma mark Geometry helpers 44 | 45 | 46 | double deg2Rad(double degrees) 47 | { 48 | // Converts degrees to radians. 49 | return degrees * (M_PI / 180.0); 50 | } 51 | 52 | 53 | double rad2Deg(double radians) 54 | { 55 | // Converts radians to degrees. 56 | return radians * (180 / M_PI); 57 | } 58 | 59 | 60 | #pragma mark - 61 | #pragma mark Drawing 62 | 63 | 64 | - (void)drawRect:(CGRect)rect 65 | { 66 | // Draw two appropriate corners, with cornerBackgroundColor behind them. 67 | if (cornerRadius > 0) { 68 | if (NO) { // just for debugging. 69 | [[UIColor redColor] set]; 70 | UIRectFill(self.bounds); 71 | } 72 | 73 | float maxX = CGRectGetMaxX(self.bounds); 74 | float maxY = CGRectGetMaxY(self.bounds); 75 | UIBezierPath *path = [UIBezierPath bezierPath]; 76 | CGPoint pt = CGPointZero; 77 | switch (cornersPosition) { 78 | case MGCornersPositionLeadingVertical: // top of screen for a left/right split 79 | [path moveToPoint:pt]; 80 | pt.y += cornerRadius; 81 | [path appendPath:[UIBezierPath bezierPathWithArcCenter:pt radius:cornerRadius startAngle:deg2Rad(90) endAngle:0 clockwise:YES]]; 82 | pt.x += cornerRadius; 83 | pt.y -= cornerRadius; 84 | [path addLineToPoint:pt]; 85 | [path addLineToPoint:CGPointZero]; 86 | [path closePath]; 87 | 88 | pt.x = maxX - cornerRadius; 89 | pt.y = 0; 90 | [path moveToPoint:pt]; 91 | pt.y = maxY; 92 | [path addLineToPoint:pt]; 93 | pt.x += cornerRadius; 94 | [path appendPath:[UIBezierPath bezierPathWithArcCenter:pt radius:cornerRadius startAngle:deg2Rad(180) endAngle:deg2Rad(90) clockwise:YES]]; 95 | pt.y -= cornerRadius; 96 | [path addLineToPoint:pt]; 97 | pt.x -= cornerRadius; 98 | [path addLineToPoint:pt]; 99 | [path closePath]; 100 | 101 | break; 102 | 103 | case MGCornersPositionTrailingVertical: // bottom of screen for a left/right split 104 | pt.y = maxY; 105 | [path moveToPoint:pt]; 106 | pt.y -= cornerRadius; 107 | [path appendPath:[UIBezierPath bezierPathWithArcCenter:pt radius:cornerRadius startAngle:deg2Rad(270) endAngle:deg2Rad(360) clockwise:NO]]; 108 | pt.x += cornerRadius; 109 | pt.y += cornerRadius; 110 | [path addLineToPoint:pt]; 111 | pt.x -= cornerRadius; 112 | [path addLineToPoint:pt]; 113 | [path closePath]; 114 | 115 | pt.x = maxX - cornerRadius; 116 | pt.y = maxY; 117 | [path moveToPoint:pt]; 118 | pt.y -= cornerRadius; 119 | [path addLineToPoint:pt]; 120 | pt.x += cornerRadius; 121 | [path appendPath:[UIBezierPath bezierPathWithArcCenter:pt radius:cornerRadius startAngle:deg2Rad(180) endAngle:deg2Rad(270) clockwise:NO]]; 122 | pt.y += cornerRadius; 123 | [path addLineToPoint:pt]; 124 | pt.x -= cornerRadius; 125 | [path addLineToPoint:pt]; 126 | [path closePath]; 127 | 128 | break; 129 | 130 | case MGCornersPositionLeadingHorizontal: // left of screen for a top/bottom split 131 | pt.x = 0; 132 | pt.y = cornerRadius; 133 | [path moveToPoint:pt]; 134 | pt.y -= cornerRadius; 135 | [path addLineToPoint:pt]; 136 | pt.x += cornerRadius; 137 | [path appendPath:[UIBezierPath bezierPathWithArcCenter:pt radius:cornerRadius startAngle:deg2Rad(180) endAngle:deg2Rad(270) clockwise:NO]]; 138 | pt.y += cornerRadius; 139 | [path addLineToPoint:pt]; 140 | pt.x -= cornerRadius; 141 | [path addLineToPoint:pt]; 142 | [path closePath]; 143 | 144 | pt.x = 0; 145 | pt.y = maxY - cornerRadius; 146 | [path moveToPoint:pt]; 147 | pt.y = maxY; 148 | [path addLineToPoint:pt]; 149 | pt.x += cornerRadius; 150 | [path appendPath:[UIBezierPath bezierPathWithArcCenter:pt radius:cornerRadius startAngle:deg2Rad(180) endAngle:deg2Rad(90) clockwise:YES]]; 151 | pt.y -= cornerRadius; 152 | [path addLineToPoint:pt]; 153 | pt.x -= cornerRadius; 154 | [path addLineToPoint:pt]; 155 | [path closePath]; 156 | 157 | break; 158 | 159 | case MGCornersPositionTrailingHorizontal: // right of screen for a top/bottom split 160 | pt.y = cornerRadius; 161 | [path moveToPoint:pt]; 162 | pt.y -= cornerRadius; 163 | [path appendPath:[UIBezierPath bezierPathWithArcCenter:pt radius:cornerRadius startAngle:deg2Rad(270) endAngle:deg2Rad(360) clockwise:NO]]; 164 | pt.x += cornerRadius; 165 | pt.y += cornerRadius; 166 | [path addLineToPoint:pt]; 167 | pt.x -= cornerRadius; 168 | [path addLineToPoint:pt]; 169 | [path closePath]; 170 | 171 | pt.y = maxY - cornerRadius; 172 | [path moveToPoint:pt]; 173 | pt.y += cornerRadius; 174 | [path appendPath:[UIBezierPath bezierPathWithArcCenter:pt radius:cornerRadius startAngle:deg2Rad(90) endAngle:0 clockwise:YES]]; 175 | pt.x += cornerRadius; 176 | pt.y -= cornerRadius; 177 | [path addLineToPoint:pt]; 178 | pt.x -= cornerRadius; 179 | [path addLineToPoint:pt]; 180 | [path closePath]; 181 | 182 | break; 183 | 184 | default: 185 | break; 186 | } 187 | 188 | [self.cornerBackgroundColor set]; 189 | [path fill]; 190 | } 191 | } 192 | 193 | 194 | #pragma mark - 195 | #pragma mark Accessors and properties 196 | 197 | 198 | - (void)setCornerRadius:(float)newRadius 199 | { 200 | if (newRadius != cornerRadius) { 201 | cornerRadius = newRadius; 202 | [self setNeedsDisplay]; 203 | } 204 | } 205 | 206 | 207 | - (void)setSplitViewController:(MGSplitViewController *)theController 208 | { 209 | if (theController != splitViewController) { 210 | splitViewController = theController; 211 | [self setNeedsDisplay]; 212 | } 213 | } 214 | 215 | 216 | - (void)setCornersPosition:(MGCornersPosition)posn 217 | { 218 | if (cornersPosition != posn) { 219 | cornersPosition = posn; 220 | [self setNeedsDisplay]; 221 | } 222 | } 223 | 224 | 225 | - (void)setCornerBackgroundColor:(UIColor *)color 226 | { 227 | if (color != cornerBackgroundColor) { 228 | [cornerBackgroundColor release]; 229 | cornerBackgroundColor = [color retain]; 230 | [self setNeedsDisplay]; 231 | } 232 | } 233 | 234 | 235 | @synthesize cornerRadius; 236 | @synthesize splitViewController; 237 | @synthesize cornersPosition; 238 | @synthesize cornerBackgroundColor; 239 | 240 | 241 | @end 242 | -------------------------------------------------------------------------------- /GithubBrowser/MGSplitViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // MGSplitViewController.h 3 | // MGSplitView 4 | // 5 | // Created by Matt Gemmell on 26/07/2010. 6 | // Copyright 2010 Instinctive Code. 7 | // 8 | 9 | #import 10 | 11 | typedef enum _MGSplitViewDividerStyle { 12 | // These names have been chosen to be conceptually similar to those of NSSplitView on Mac OS X. 13 | MGSplitViewDividerStyleThin = 0, // Thin divider, like UISplitViewController (default). 14 | MGSplitViewDividerStylePaneSplitter = 1 // Thick divider, drawn with a grey gradient and a grab-strip. 15 | } MGSplitViewDividerStyle; 16 | 17 | @class MGSplitDividerView; 18 | @protocol MGSplitViewControllerDelegate; 19 | @interface MGSplitViewController : UIViewController { 20 | BOOL _showsMasterInPortrait; 21 | BOOL _showsMasterInLandscape; 22 | float _splitWidth; 23 | id _delegate; 24 | BOOL _vertical; 25 | BOOL _masterBeforeDetail; 26 | NSMutableArray *_viewControllers; 27 | UIBarButtonItem *_barButtonItem; // To be compliant with wacky UISplitViewController behaviour. 28 | UIPopoverController *_hiddenPopoverController; // Popover used to hold the master view if it's not always visible. 29 | MGSplitDividerView *_dividerView; // View that draws the divider between the master and detail views. 30 | NSArray *_cornerViews; // Views to draw the inner rounded corners between master and detail views. 31 | float _splitPosition; 32 | BOOL _reconfigurePopup; 33 | MGSplitViewDividerStyle _dividerStyle; // Meta-setting which configures several aspects of appearance and behaviour. 34 | } 35 | 36 | @property (nonatomic, assign) IBOutlet id delegate; 37 | @property (nonatomic, assign) BOOL showsMasterInPortrait; // applies to both portrait orientations (default NO) 38 | @property (nonatomic, assign) BOOL showsMasterInLandscape; // applies to both landscape orientations (default YES) 39 | @property (nonatomic, assign, getter=isVertical) BOOL vertical; // if NO, split is horizontal, i.e. master above detail (default YES) 40 | @property (nonatomic, assign, getter=isMasterBeforeDetail) BOOL masterBeforeDetail; // if NO, master view is below/right of detail (default YES) 41 | @property (nonatomic, assign) float splitPosition; // starting position of split in pixels, relative to top/left (depending on .isVertical setting) if masterBeforeDetail is YES, else relative to bottom/right. 42 | @property (nonatomic, assign) float splitWidth; // width of split in pixels. 43 | @property (nonatomic, assign) BOOL allowsDraggingDivider; // whether to let the user drag the divider to alter the split position (default NO). 44 | 45 | @property (nonatomic, copy) NSArray *viewControllers; // array of UIViewControllers; master is at index 0, detail is at index 1. 46 | @property (nonatomic, retain) IBOutlet UIViewController *masterViewController; // convenience. 47 | @property (nonatomic, retain) IBOutlet UIViewController *detailViewController; // convenience. 48 | @property (nonatomic, retain) MGSplitDividerView *dividerView; // the view which draws the divider/split between master and detail. 49 | @property (nonatomic, assign) MGSplitViewDividerStyle dividerStyle; // style (and behaviour) of the divider between master and detail. 50 | 51 | @property (nonatomic, readonly, getter=isLandscape) BOOL landscape; // returns YES if this view controller is in either of the two Landscape orientations, else NO. 52 | 53 | // Actions 54 | - (IBAction)toggleSplitOrientation:(id)sender; // toggles split axis between vertical (left/right; default) and horizontal (top/bottom). 55 | - (IBAction)toggleMasterBeforeDetail:(id)sender; // toggles position of master view relative to detail view. 56 | - (IBAction)toggleMasterView:(id)sender; // toggles display of the master view in the current orientation. 57 | - (IBAction)showMasterPopover:(id)sender; // shows the master view in a popover spawned from the provided barButtonItem, if it's currently hidden. 58 | - (void)notePopoverDismissed; // should rarely be needed, because you should not change the popover's delegate. If you must, then call this when it's dismissed. 59 | 60 | // Conveniences for you, because I care. 61 | - (BOOL)isShowingMaster; 62 | - (void)setSplitPosition:(float)posn animated:(BOOL)animate; // Allows for animation of splitPosition changes. The property's regular setter is not animated. 63 | /* Note: splitPosition is the width (in a left/right split, or height in a top/bottom split) of the master view. 64 | It is relative to the appropriate side of the splitView, which can be any of the four sides depending on the values in isMasterBeforeDetail and isVertical: 65 | isVertical = YES, isMasterBeforeDetail = YES: splitPosition is relative to the LEFT edge. (Default) 66 | isVertical = YES, isMasterBeforeDetail = NO: splitPosition is relative to the RIGHT edge. 67 | isVertical = NO, isMasterBeforeDetail = YES: splitPosition is relative to the TOP edge. 68 | isVertical = NO, isMasterBeforeDetail = NO: splitPosition is relative to the BOTTOM edge. 69 | 70 | This implementation was chosen so you don't need to recalculate equivalent splitPositions if the user toggles masterBeforeDetail themselves. 71 | */ 72 | - (void)setDividerStyle:(MGSplitViewDividerStyle)newStyle animated:(BOOL)animate; // Allows for animation of dividerStyle changes. The property's regular setter is not animated. 73 | - (NSArray *)cornerViews; 74 | /* 75 | -cornerViews returns an NSArray of two MGSplitCornersView objects, used to draw the inner corners. 76 | The first view is the "leading" corners (top edge of screen for left/right split, left edge of screen for top/bottom split). 77 | The second view is the "trailing" corners (bottom edge of screen for left/right split, right edge of screen for top/bottom split). 78 | Do NOT modify them, except to: 79 | 1. Change their .cornerBackgroundColor 80 | 2. Change their .cornerRadius 81 | */ 82 | 83 | @end 84 | 85 | 86 | @protocol MGSplitViewControllerDelegate 87 | 88 | @optional 89 | 90 | // Called when a button should be added to a toolbar for a hidden view controller. 91 | - (void)splitViewController:(MGSplitViewController*)svc 92 | willHideViewController:(UIViewController *)aViewController 93 | withBarButtonItem:(UIBarButtonItem*)barButtonItem 94 | forPopoverController: (UIPopoverController*)pc; 95 | 96 | // Called when the master view is shown again in the split view, invalidating the button and popover controller. 97 | - (void)splitViewController:(MGSplitViewController*)svc 98 | willShowViewController:(UIViewController *)aViewController 99 | invalidatingBarButtonItem:(UIBarButtonItem *)barButtonItem; 100 | 101 | // Called when the master view is shown in a popover, so the delegate can take action like hiding other popovers. 102 | - (void)splitViewController:(MGSplitViewController*)svc 103 | popoverController:(UIPopoverController*)pc 104 | willPresentViewController:(UIViewController *)aViewController; 105 | 106 | // Called when the split orientation will change (from vertical to horizontal, or vice versa). 107 | - (void)splitViewController:(MGSplitViewController*)svc willChangeSplitOrientationToVertical:(BOOL)isVertical; 108 | 109 | // Called when split position will change to the given pixel value (relative to left if split is vertical, or to top if horizontal). 110 | - (void)splitViewController:(MGSplitViewController*)svc willMoveSplitToPosition:(float)position; 111 | 112 | // Called before split position is changed to the given pixel value (relative to left if split is vertical, or to top if horizontal). 113 | // Note that viewSize is the current size of the entire split-view; i.e. the area enclosing the master, divider and detail views. 114 | - (float)splitViewController:(MGSplitViewController *)svc constrainSplitPosition:(float)proposedPosition splitViewSize:(CGSize)viewSize; 115 | 116 | @end 117 | -------------------------------------------------------------------------------- /GithubBrowser/ReposViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ReposViewController.m 3 | // GithubBrowser 4 | // 5 | // Created by Oscar Del Ben on 9/13/11. 6 | // Copyright (c) 2011 DibiStore. All rights reserved. 7 | // 8 | 9 | #import "ReposViewController.h" 10 | 11 | #import "DetailViewController.h" 12 | #import "SearchViewController.h" 13 | #import "SettingsViewController.h" 14 | 15 | @implementation ReposViewController 16 | 17 | @synthesize detailViewController; 18 | 19 | @synthesize githubEngine; 20 | @synthesize repos; 21 | 22 | @synthesize searchButton; 23 | @synthesize currentPage; 24 | 25 | - (void)viewDidAppear:(BOOL)animated 26 | { 27 | [super viewDidAppear:animated]; 28 | 29 | // toolbar 30 | 31 | UIBarButtonItem *homeButton = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"53-house.png"] style:UIBarButtonItemStylePlain target:self.detailViewController action:@selector(showHome)]; 32 | searchButton = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"06-magnify.png"] style:UIBarButtonItemStylePlain target:detailViewController action:@selector(showSearch)]; 33 | 34 | UIBarButtonItem *spacer = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil]; 35 | 36 | self.toolbarItems = [NSArray arrayWithObjects:homeButton, spacer, searchButton, nil]; 37 | self.navigationController.toolbarHidden = NO; 38 | 39 | // force gradient 40 | [self.navigationController.toolbar setBarStyle:UIBarStyleDefault]; 41 | 42 | [homeButton release]; 43 | [spacer release]; 44 | } 45 | 46 | - (void)viewDidLoad 47 | { 48 | [super viewDidLoad]; 49 | self.clearsSelectionOnViewWillAppear = NO; 50 | self.contentSizeForViewInPopover = CGSizeMake(320.0, 600.0); 51 | 52 | NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; 53 | [notificationCenter addObserver:self selector:@selector(reloadRepos) name:GBCredentialsChanged object:nil]; 54 | 55 | self.githubEngine = [[UAGithubEngine alloc] initWithUsername:nil password:nil delegate:self withReachability:NO]; 56 | [self reloadRepos]; 57 | 58 | // Todo: add pagination for repos 59 | // TODO: add error handling (no internet, error loading repos, etc) 60 | } 61 | 62 | - (void)viewDidUnload 63 | { 64 | NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; 65 | [notificationCenter removeObserver:self]; 66 | 67 | [super viewDidUnload]; 68 | } 69 | 70 | - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { 71 | return YES; 72 | } 73 | 74 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 75 | { 76 | return 1; 77 | 78 | } 79 | 80 | 81 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 82 | { 83 | return [repos count]; 84 | 85 | } 86 | 87 | 88 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 89 | { 90 | static NSString *CellIdentifier = @"Cell"; 91 | 92 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 93 | if (cell == nil) { 94 | cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease]; 95 | 96 | cell.textLabel.backgroundColor = [UIColor clearColor]; 97 | cell.detailTextLabel.backgroundColor = [UIColor clearColor]; 98 | } 99 | 100 | // Configure the cell. 101 | NSDictionary *repo = [repos objectAtIndex:indexPath.row]; 102 | 103 | cell.textLabel.text = [repo valueForKey:@"name"]; 104 | cell.detailTextLabel.text = [repo valueForKey:@"description"]; 105 | 106 | int private = [[repo valueForKey:@"private"] intValue]; 107 | int fork = [[repo valueForKey:@"fork"] intValue]; 108 | 109 | if (private == 1) 110 | { 111 | if (fork == 1) 112 | { 113 | cell.imageView.image = [UIImage imageNamed:@"private-fork.png"]; 114 | } 115 | else 116 | { 117 | cell.imageView.image = [UIImage imageNamed:@"private.png"]; 118 | } 119 | 120 | // background color 121 | UIView *bg = [[UIView alloc] initWithFrame:cell.frame]; 122 | bg.backgroundColor = [UIColor colorWithRed:255/255.0 green:254/255.0 blue:235/255.0 alpha:1]; 123 | cell.backgroundView = bg; 124 | [bg release]; 125 | } 126 | else 127 | { 128 | if (fork == 1) 129 | { 130 | cell.imageView.image = [UIImage imageNamed:@"public-fork.png"]; 131 | } 132 | else 133 | { 134 | cell.imageView.image = [UIImage imageNamed:@"public.png"]; 135 | } 136 | 137 | UIView *bg = [[UIView alloc] initWithFrame:cell.frame]; 138 | bg.backgroundColor = [UIColor whiteColor]; 139 | cell.backgroundView = bg; 140 | [bg release]; 141 | } 142 | 143 | // TODO: try to change cell height 144 | 145 | return cell; 146 | } 147 | 148 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 149 | { 150 | NSDictionary *currentRepo = [self.repos objectAtIndex:indexPath.row]; 151 | 152 | detailViewController.detailItem = currentRepo; 153 | } 154 | 155 | - (void)dealloc 156 | { 157 | [detailViewController release]; 158 | [githubEngine release]; 159 | [repos release]; 160 | [searchButton release]; 161 | [super dealloc]; 162 | } 163 | 164 | #pragma mark Utility methods 165 | 166 | /* 167 | - (void)showSearchSheet 168 | { 169 | NSArray *otherTitles = [NSArray arrayWithObjects:@"Search user", @"Random repo", nil]; 170 | 171 | UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:@"" delegate:self cancelButtonTitle:nil destructiveButtonTitle:nil otherButtonTitles:nil]; 172 | 173 | for (int i = 0; i < [otherTitles count]; i++) 174 | { 175 | [actionSheet addButtonWithTitle:[otherTitles objectAtIndex:i]]; 176 | } 177 | 178 | [actionSheet showFromBarButtonItem:self.searchButton animated:YES]; 179 | 180 | [actionSheet release]; 181 | } 182 | */ 183 | 184 | - (void)reloadRepos 185 | { 186 | [detailViewController showLoadIndicator]; 187 | 188 | NSString *username = [ApplicationHelper currentUsername]; 189 | 190 | if (!username || [username blank]) { 191 | return; 192 | } 193 | 194 | NSString *password = [ApplicationHelper password]; 195 | 196 | self.githubEngine.username = username; 197 | self.githubEngine.password = password; 198 | 199 | self.navigationItem.title = username; 200 | 201 | self.currentPage = 1; 202 | self.repos = [NSMutableArray array]; 203 | 204 | [self.detailViewController loadUserPage]; 205 | [self.githubEngine repositoriesForUser:githubEngine.username includeWatched:NO page:self.currentPage]; 206 | } 207 | 208 | 209 | 210 | #pragma mark UAGithubEngineDelegate Methods 211 | 212 | - (void)requestSucceeded:(NSString *)connectionIdentifier 213 | { 214 | NSLog(@"Request succeeded: %@", connectionIdentifier); 215 | } 216 | 217 | 218 | - (void)requestFailed:(NSString *)connectionIdentifier withError:(NSError *)error 219 | { 220 | NSLog(@"Request failed: %@, error: %@ (%@)", connectionIdentifier, [error localizedDescription], [error userInfo]); 221 | } 222 | 223 | 224 | #pragma mark Github api 225 | 226 | #define MAX_PAGES 10 227 | 228 | - (void)repositoriesReceived:(NSArray *)repositories forConnection:(NSString *)connectionIdentifier 229 | { 230 | [self.repos addObjectsFromArray:repositories]; 231 | 232 | if ([repositories count] == 0 || self.currentPage > MAX_PAGES) 233 | { 234 | 235 | NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"pushed_at" ascending:NO]; 236 | NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor]; 237 | 238 | [self.repos sortUsingDescriptors:sortDescriptors]; 239 | 240 | [self.tableView reloadData]; 241 | 242 | [detailViewController hideLoadIndicator]; 243 | } 244 | else 245 | { 246 | self.currentPage += 1; 247 | [self.githubEngine repositoriesForUser:githubEngine.username includeWatched:NO page:self.currentPage]; 248 | } 249 | } 250 | 251 | #pragma mark UIActionSheetDelegate Methods 252 | 253 | - (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex 254 | { 255 | switch (buttonIndex) { 256 | case 0: 257 | [self.detailViewController showSearch]; 258 | break; 259 | 260 | case 1: 261 | [self.detailViewController showRandomRepo]; 262 | break; 263 | } 264 | } 265 | 266 | @end 267 | -------------------------------------------------------------------------------- /GithubBrowser/UAGithubEngine/JSON/CJSONDataSerializer.m: -------------------------------------------------------------------------------- 1 | // 2 | // CJSONDataSerializer.m 3 | // TouchCode 4 | // 5 | // Created by Jonathan Wight on 12/07/2005. 6 | // Copyright 2005 toxicsoftware.com. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person 9 | // obtaining a copy of this software and associated documentation 10 | // files (the "Software"), to deal in the Software without 11 | // restriction, including without limitation the rights to use, 12 | // copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the 14 | // Software is furnished to do so, subject to the following 15 | // conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be 18 | // included in all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 22 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 24 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 25 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 26 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 27 | // OTHER DEALINGS IN THE SOFTWARE. 28 | // 29 | 30 | #import "CJSONDataSerializer.h" 31 | 32 | #import "CSerializedJSONData.h" 33 | 34 | static NSData *kNULL = NULL; 35 | static NSData *kFalse = NULL; 36 | static NSData *kTrue = NULL; 37 | 38 | @implementation CJSONDataSerializer 39 | 40 | + (void)initialize 41 | { 42 | NSAutoreleasePool *thePool = [[NSAutoreleasePool alloc] init]; 43 | 44 | @synchronized(@"CJSONDataSerializer") 45 | { 46 | if (kNULL == NULL) 47 | kNULL = [[NSData alloc] initWithBytesNoCopy:"null" length:4 freeWhenDone:NO]; 48 | if (kFalse == NULL) 49 | kFalse = [[NSData alloc] initWithBytesNoCopy:"false" length:5 freeWhenDone:NO]; 50 | if (kTrue == NULL) 51 | kTrue = [[NSData alloc] initWithBytesNoCopy:"true" length:4 freeWhenDone:NO]; 52 | } 53 | 54 | [thePool release]; 55 | } 56 | 57 | + (id)serializer 58 | { 59 | return([[[self alloc] init] autorelease]); 60 | } 61 | 62 | - (NSData *)serializeObject:(id)inObject error:(NSError **)outError 63 | { 64 | NSData *theResult = NULL; 65 | 66 | if ([inObject isKindOfClass:[NSNull class]]) 67 | { 68 | theResult = [self serializeNull:inObject error:outError]; 69 | } 70 | else if ([inObject isKindOfClass:[NSNumber class]]) 71 | { 72 | theResult = [self serializeNumber:inObject error:outError]; 73 | } 74 | else if ([inObject isKindOfClass:[NSString class]]) 75 | { 76 | theResult = [self serializeString:inObject error:outError]; 77 | } 78 | else if ([inObject isKindOfClass:[NSArray class]]) 79 | { 80 | theResult = [self serializeArray:inObject error:outError]; 81 | } 82 | else if ([inObject isKindOfClass:[NSDictionary class]]) 83 | { 84 | theResult = [self serializeDictionary:inObject error:outError]; 85 | } 86 | else if ([inObject isKindOfClass:[NSData class]]) 87 | { 88 | NSString *theString = [[[NSString alloc] initWithData:inObject encoding:NSUTF8StringEncoding] autorelease]; 89 | theResult = [self serializeString:theString error:outError]; 90 | } 91 | else if ([inObject isKindOfClass:[CSerializedJSONData class]]) 92 | { 93 | theResult = [inObject data]; 94 | } 95 | else 96 | { 97 | if (outError) 98 | { 99 | NSDictionary *theUserInfo = [NSDictionary dictionaryWithObjectsAndKeys: 100 | [NSString stringWithFormat:@"Cannot serialize data of type '%@'", NSStringFromClass([inObject class])], NSLocalizedDescriptionKey, 101 | NULL]; 102 | *outError = [NSError errorWithDomain:@"TODO_DOMAIN" code:-1 userInfo:theUserInfo]; 103 | } 104 | return(NULL); 105 | } 106 | if (theResult == NULL) 107 | { 108 | if (outError) 109 | { 110 | NSDictionary *theUserInfo = [NSDictionary dictionaryWithObjectsAndKeys: 111 | [NSString stringWithFormat:@"Could not serialize object '%@'", inObject], NSLocalizedDescriptionKey, 112 | NULL]; 113 | *outError = [NSError errorWithDomain:@"TODO_DOMAIN" code:-1 userInfo:theUserInfo]; 114 | } 115 | return(NULL); 116 | } 117 | return(theResult); 118 | } 119 | 120 | - (NSData *)serializeNull:(NSNull *)inNull error:(NSError **)outError 121 | { 122 | #pragma unused (inNull) 123 | return(kNULL); 124 | } 125 | 126 | - (NSData *)serializeNumber:(NSNumber *)inNumber error:(NSError **)outError 127 | { 128 | NSData *theResult = NULL; 129 | switch (CFNumberGetType((CFNumberRef)inNumber)) 130 | { 131 | case kCFNumberCharType: 132 | { 133 | int theValue = [inNumber intValue]; 134 | if (theValue == 0) 135 | theResult = kFalse; 136 | else if (theValue == 1) 137 | theResult = kTrue; 138 | else 139 | theResult = [[inNumber stringValue] dataUsingEncoding:NSASCIIStringEncoding]; 140 | } 141 | break; 142 | case kCFNumberFloat32Type: 143 | case kCFNumberFloat64Type: 144 | case kCFNumberFloatType: 145 | case kCFNumberDoubleType: 146 | case kCFNumberSInt8Type: 147 | case kCFNumberSInt16Type: 148 | case kCFNumberSInt32Type: 149 | case kCFNumberSInt64Type: 150 | case kCFNumberShortType: 151 | case kCFNumberIntType: 152 | case kCFNumberLongType: 153 | case kCFNumberLongLongType: 154 | case kCFNumberCFIndexType: 155 | default: 156 | theResult = [[inNumber stringValue] dataUsingEncoding:NSASCIIStringEncoding]; 157 | break; 158 | } 159 | return(theResult); 160 | } 161 | 162 | - (NSData *)serializeString:(NSString *)inString error:(NSError **)outError 163 | { 164 | NSMutableString *theMutableCopy = [[inString mutableCopy] autorelease]; 165 | [theMutableCopy replaceOccurrencesOfString:@"\\" withString:@"\\\\" options:0 range:NSMakeRange(0, [theMutableCopy length])]; 166 | [theMutableCopy replaceOccurrencesOfString:@"\"" withString:@"\\\"" options:0 range:NSMakeRange(0, [theMutableCopy length])]; 167 | [theMutableCopy replaceOccurrencesOfString:@"/" withString:@"\\/" options:0 range:NSMakeRange(0, [theMutableCopy length])]; 168 | [theMutableCopy replaceOccurrencesOfString:@"\b" withString:@"\\b" options:0 range:NSMakeRange(0, [theMutableCopy length])]; 169 | [theMutableCopy replaceOccurrencesOfString:@"\f" withString:@"\\f" options:0 range:NSMakeRange(0, [theMutableCopy length])]; 170 | [theMutableCopy replaceOccurrencesOfString:@"\n" withString:@"\\n" options:0 range:NSMakeRange(0, [theMutableCopy length])]; 171 | [theMutableCopy replaceOccurrencesOfString:@"\r" withString:@"\\r" options:0 range:NSMakeRange(0, [theMutableCopy length])]; 172 | [theMutableCopy replaceOccurrencesOfString:@"\t" withString:@"\\t" options:0 range:NSMakeRange(0, [theMutableCopy length])]; 173 | /* 174 | case 'u': 175 | { 176 | theCharacter = 0; 177 | 178 | int theShift; 179 | for (theShift = 12; theShift >= 0; theShift -= 4) 180 | { 181 | int theDigit = HexToInt([self scanCharacter]); 182 | if (theDigit == -1) 183 | { 184 | [self setScanLocation:theScanLocation]; 185 | return(NO); 186 | } 187 | theCharacter |= (theDigit << theShift); 188 | } 189 | } 190 | */ 191 | return([[NSString stringWithFormat:@"\"%@\"", theMutableCopy] dataUsingEncoding:NSUTF8StringEncoding]); 192 | } 193 | 194 | - (NSData *)serializeArray:(NSArray *)inArray error:(NSError **)outError 195 | { 196 | NSMutableData *theData = [NSMutableData data]; 197 | 198 | [theData appendBytes:"[" length:1]; 199 | 200 | NSEnumerator *theEnumerator = [inArray objectEnumerator]; 201 | id theValue = NULL; 202 | NSUInteger i = 0; 203 | while ((theValue = [theEnumerator nextObject]) != NULL) 204 | { 205 | NSData *theValueData = [self serializeObject:theValue error:outError]; 206 | if (theValueData == NULL) 207 | { 208 | return(NULL); 209 | } 210 | [theData appendData:theValueData]; 211 | if (++i < [inArray count]) 212 | [theData appendBytes:"," length:1]; 213 | } 214 | 215 | [theData appendBytes:"]" length:1]; 216 | 217 | return(theData); 218 | } 219 | 220 | - (NSData *)serializeDictionary:(NSDictionary *)inDictionary error:(NSError **)outError 221 | { 222 | NSMutableData *theData = [NSMutableData data]; 223 | 224 | [theData appendBytes:"{" length:1]; 225 | 226 | NSArray *theKeys = [inDictionary allKeys]; 227 | NSEnumerator *theEnumerator = [theKeys objectEnumerator]; 228 | NSString *theKey = NULL; 229 | while ((theKey = [theEnumerator nextObject]) != NULL) 230 | { 231 | id theValue = [inDictionary objectForKey:theKey]; 232 | 233 | NSData *theKeyData = [self serializeString:theKey error:outError]; 234 | if (theKeyData == NULL) 235 | { 236 | return(NULL); 237 | } 238 | NSData *theValueData = [self serializeObject:theValue error:outError]; 239 | if (theValueData == NULL) 240 | { 241 | return(NULL); 242 | } 243 | 244 | 245 | [theData appendData:theKeyData]; 246 | [theData appendBytes:":" length:1]; 247 | [theData appendData:theValueData]; 248 | 249 | if (theKey != [theKeys lastObject]) 250 | [theData appendData:[@"," dataUsingEncoding:NSASCIIStringEncoding]]; 251 | } 252 | 253 | [theData appendBytes:"}" length:1]; 254 | 255 | return(theData); 256 | } 257 | 258 | @end 259 | -------------------------------------------------------------------------------- /GithubBrowser/UAGithubEngine/NSData+Base64.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSData+Base64.m 3 | // base64 4 | // 5 | // Created by Matt Gallagher on 2009/06/03. 6 | // Copyright 2009 Matt Gallagher. All rights reserved. 7 | // 8 | // Permission is given to use this source code file, free of charge, in any 9 | // project, commercial or otherwise, entirely at your risk, with the condition 10 | // that any redistribution (in part or whole) of source code must retain 11 | // this copyright and permission notice. Attribution in compiled projects is 12 | // appreciated but not required. 13 | // 14 | 15 | #import "NSData+Base64.h" 16 | 17 | // 18 | // Mapping from 6 bit pattern to ASCII character. 19 | // 20 | static unsigned char base64EncodeLookup[65] = 21 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 22 | 23 | // 24 | // Definition for "masked-out" areas of the base64DecodeLookup mapping 25 | // 26 | #define xx 65 27 | 28 | // 29 | // Mapping from ASCII character to 6 bit pattern. 30 | // 31 | static unsigned char base64DecodeLookup[256] = 32 | { 33 | xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, 34 | xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, 35 | xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, 62, xx, xx, xx, 63, 36 | 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, xx, xx, xx, xx, xx, xx, 37 | xx, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 38 | 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, xx, xx, xx, xx, xx, 39 | xx, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 40 | 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, xx, xx, xx, xx, xx, 41 | xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, 42 | xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, 43 | xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, 44 | xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, 45 | xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, 46 | xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, 47 | xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, 48 | xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, 49 | }; 50 | 51 | // 52 | // Fundamental sizes of the binary and base64 encode/decode units in bytes 53 | // 54 | #define BINARY_UNIT_SIZE 3 55 | #define BASE64_UNIT_SIZE 4 56 | 57 | // 58 | // NewBase64Decode 59 | // 60 | // Decodes the base64 ASCII string in the inputBuffer to a newly malloced 61 | // output buffer. 62 | // 63 | // inputBuffer - the source ASCII string for the decode 64 | // length - the length of the string or -1 (to specify strlen should be used) 65 | // outputLength - if not-NULL, on output will contain the decoded length 66 | // 67 | // returns the decoded buffer. Must be free'd by caller. Length is given by 68 | // outputLength. 69 | // 70 | void *NewBase64Decode( 71 | const char *inputBuffer, 72 | size_t length, 73 | size_t *outputLength) 74 | { 75 | if (length == -1) 76 | { 77 | length = strlen(inputBuffer); 78 | } 79 | 80 | size_t outputBufferSize = 81 | ((length+BASE64_UNIT_SIZE-1) / BASE64_UNIT_SIZE) * BINARY_UNIT_SIZE; 82 | unsigned char *outputBuffer = (unsigned char *)malloc(outputBufferSize); 83 | 84 | size_t i = 0; 85 | size_t j = 0; 86 | while (i < length) 87 | { 88 | // 89 | // Accumulate 4 valid characters (ignore everything else) 90 | // 91 | unsigned char accumulated[BASE64_UNIT_SIZE]; 92 | size_t accumulateIndex = 0; 93 | while (i < length) 94 | { 95 | unsigned char decode = base64DecodeLookup[inputBuffer[i++]]; 96 | if (decode != xx) 97 | { 98 | accumulated[accumulateIndex] = decode; 99 | accumulateIndex++; 100 | 101 | if (accumulateIndex == BASE64_UNIT_SIZE) 102 | { 103 | break; 104 | } 105 | } 106 | } 107 | 108 | // 109 | // Store the 6 bits from each of the 4 characters as 3 bytes 110 | // 111 | outputBuffer[j] = (accumulated[0] << 2) | (accumulated[1] >> 4); 112 | outputBuffer[j + 1] = (accumulated[1] << 4) | (accumulated[2] >> 2); 113 | outputBuffer[j + 2] = (accumulated[2] << 6) | accumulated[3]; 114 | j += accumulateIndex - 1; 115 | } 116 | 117 | if (outputLength) 118 | { 119 | *outputLength = j; 120 | } 121 | return outputBuffer; 122 | } 123 | 124 | // 125 | // NewBase64Decode 126 | // 127 | // Encodes the arbitrary data in the inputBuffer as base64 into a newly malloced 128 | // output buffer. 129 | // 130 | // inputBuffer - the source data for the encode 131 | // length - the length of the input in bytes 132 | // separateLines - if zero, no CR/LF characters will be added. Otherwise 133 | // a CR/LF pair will be added every 64 encoded chars. 134 | // outputLength - if not-NULL, on output will contain the encoded length 135 | // (not including terminating 0 char) 136 | // 137 | // returns the encoded buffer. Must be free'd by caller. Length is given by 138 | // outputLength. 139 | // 140 | char *NewBase64Encode( 141 | const void *buffer, 142 | size_t length, 143 | bool separateLines, 144 | size_t *outputLength) 145 | { 146 | const unsigned char *inputBuffer = (const unsigned char *)buffer; 147 | 148 | #define MAX_NUM_PADDING_CHARS 2 149 | #define OUTPUT_LINE_LENGTH 64 150 | #define INPUT_LINE_LENGTH ((OUTPUT_LINE_LENGTH / BASE64_UNIT_SIZE) * BINARY_UNIT_SIZE) 151 | #define CR_LF_SIZE 2 152 | 153 | // 154 | // Byte accurate calculation of final buffer size 155 | // 156 | size_t outputBufferSize = 157 | ((length / BINARY_UNIT_SIZE) 158 | + ((length % BINARY_UNIT_SIZE) ? 1 : 0)) 159 | * BASE64_UNIT_SIZE; 160 | if (separateLines) 161 | { 162 | outputBufferSize += 163 | (outputBufferSize / OUTPUT_LINE_LENGTH) * CR_LF_SIZE; 164 | } 165 | 166 | // 167 | // Include space for a terminating zero 168 | // 169 | outputBufferSize += 1; 170 | 171 | // 172 | // Allocate the output buffer 173 | // 174 | char *outputBuffer = (char *)malloc(outputBufferSize); 175 | if (!outputBuffer) 176 | { 177 | return NULL; 178 | } 179 | 180 | size_t i = 0; 181 | size_t j = 0; 182 | const size_t lineLength = separateLines ? INPUT_LINE_LENGTH : length; 183 | size_t lineEnd = lineLength; 184 | 185 | while (true) 186 | { 187 | if (lineEnd > length) 188 | { 189 | lineEnd = length; 190 | } 191 | 192 | for (; i + BINARY_UNIT_SIZE - 1 < lineEnd; i += BINARY_UNIT_SIZE) 193 | { 194 | // 195 | // Inner loop: turn 48 bytes into 64 base64 characters 196 | // 197 | outputBuffer[j++] = base64EncodeLookup[(inputBuffer[i] & 0xFC) >> 2]; 198 | outputBuffer[j++] = base64EncodeLookup[((inputBuffer[i] & 0x03) << 4) 199 | | ((inputBuffer[i + 1] & 0xF0) >> 4)]; 200 | outputBuffer[j++] = base64EncodeLookup[((inputBuffer[i + 1] & 0x0F) << 2) 201 | | ((inputBuffer[i + 2] & 0xC0) >> 6)]; 202 | outputBuffer[j++] = base64EncodeLookup[inputBuffer[i + 2] & 0x3F]; 203 | } 204 | 205 | if (lineEnd == length) 206 | { 207 | break; 208 | } 209 | 210 | // 211 | // Add the newline 212 | // 213 | outputBuffer[j++] = '\r'; 214 | outputBuffer[j++] = '\n'; 215 | lineEnd += lineLength; 216 | } 217 | 218 | if (i + 1 < length) 219 | { 220 | // 221 | // Handle the single '=' case 222 | // 223 | outputBuffer[j++] = base64EncodeLookup[(inputBuffer[i] & 0xFC) >> 2]; 224 | outputBuffer[j++] = base64EncodeLookup[((inputBuffer[i] & 0x03) << 4) 225 | | ((inputBuffer[i + 1] & 0xF0) >> 4)]; 226 | outputBuffer[j++] = base64EncodeLookup[(inputBuffer[i + 1] & 0x0F) << 2]; 227 | outputBuffer[j++] = '='; 228 | } 229 | else if (i < length) 230 | { 231 | // 232 | // Handle the double '=' case 233 | // 234 | outputBuffer[j++] = base64EncodeLookup[(inputBuffer[i] & 0xFC) >> 2]; 235 | outputBuffer[j++] = base64EncodeLookup[(inputBuffer[i] & 0x03) << 4]; 236 | outputBuffer[j++] = '='; 237 | outputBuffer[j++] = '='; 238 | } 239 | outputBuffer[j] = 0; 240 | 241 | // 242 | // Set the output length and return the buffer 243 | // 244 | if (outputLength) 245 | { 246 | *outputLength = j; 247 | } 248 | return outputBuffer; 249 | } 250 | 251 | @implementation NSData (Base64) 252 | 253 | // 254 | // dataFromBase64String: 255 | // 256 | // Creates an NSData object containing the base64 decoded representation of 257 | // the base64 string 'aString' 258 | // 259 | // Parameters: 260 | // aString - the base64 string to decode 261 | // 262 | // returns the autoreleased NSData representation of the base64 string 263 | // 264 | + (NSData *)dataFromBase64String:(NSString *)aString 265 | { 266 | NSData *data = [aString dataUsingEncoding:NSASCIIStringEncoding]; 267 | size_t outputLength; 268 | void *outputBuffer = NewBase64Decode([data bytes], [data length], &outputLength); 269 | NSData *result = [NSData dataWithBytes:outputBuffer length:outputLength]; 270 | free(outputBuffer); 271 | return result; 272 | } 273 | 274 | // 275 | // base64EncodedString 276 | // 277 | // Creates an NSString object that contains the base 64 encoding of the 278 | // receiver's data. Lines are broken at 64 characters long. 279 | // 280 | // returns an autoreleased NSString being the base 64 representation of the 281 | // receiver. 282 | // 283 | - (NSString *)base64EncodedString 284 | { 285 | size_t outputLength; 286 | char *outputBuffer = 287 | NewBase64Encode([self bytes], [self length], true, &outputLength); 288 | 289 | NSString *result = 290 | [[[NSString alloc] 291 | initWithBytes:outputBuffer 292 | length:outputLength 293 | encoding:NSASCIIStringEncoding] 294 | autorelease]; 295 | free(outputBuffer); 296 | return result; 297 | } 298 | 299 | @end 300 | -------------------------------------------------------------------------------- /GithubBrowser/DetailViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // DetailViewController.m 3 | // GithubBrowser 4 | // 5 | // Created by Oscar Del Ben on 4/6/11. 6 | // Copyright 2011 DibiStore. All rights reserved. 7 | // 8 | 9 | #import "DetailViewController.h" 10 | 11 | #import "RootViewController.h" 12 | #import "SettingsViewController.h" 13 | #import "NSString+DBExtensions.h" 14 | #import "SearchViewController.h" 15 | #import "GithubBrowserAppDelegate.h" 16 | 17 | @interface DetailViewController () 18 | @property (nonatomic, retain) UIPopoverController *popoverController; 19 | - (void)configureView; 20 | @end 21 | 22 | @implementation DetailViewController 23 | 24 | @synthesize splitController; 25 | 26 | @synthesize toolbar=_toolbar; 27 | @synthesize detailItem=_detailItem; 28 | @synthesize webView = _webView; 29 | @synthesize popoverController=_myPopoverController; 30 | 31 | @synthesize titleBarButtonItem; 32 | @synthesize loadUserItem; 33 | @synthesize activityIndicator; 34 | @synthesize matchedUsername; 35 | 36 | #pragma mark - Managing the detail item 37 | 38 | /* 39 | When setting the detail item, update the view and dismiss the popover controller if it's showing. 40 | */ 41 | - (void)setDetailItem:(id)newDetailItem 42 | { 43 | if (_detailItem != newDetailItem) { 44 | [_detailItem release]; 45 | _detailItem = [newDetailItem retain]; 46 | 47 | // Update the view. 48 | [self configureView]; 49 | } 50 | 51 | if (self.popoverController != nil) { 52 | [self.popoverController dismissPopoverAnimated:YES]; 53 | } 54 | } 55 | 56 | - (void)configureView 57 | { 58 | // Update the user interface for the detail item. 59 | [ApplicationHelper loadWebViewFromUrl:self.webView url:[self.detailItem valueForKey:@"url"]]; 60 | } 61 | 62 | - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { 63 | return YES; 64 | } 65 | 66 | #pragma mark - Split view support 67 | 68 | - (void)setTitle 69 | { 70 | NSString *username = [ApplicationHelper currentUsername]; 71 | titleBarButtonItem.title = (username && ![username blank]) ? username : @"Select username"; 72 | } 73 | 74 | - (void)splitViewController:(MGSplitViewController*)svc 75 | willHideViewController:(UIViewController *)aViewController 76 | withBarButtonItem:(UIBarButtonItem*)barButtonItem 77 | forPopoverController: (UIPopoverController*)pc 78 | { 79 | self.titleBarButtonItem = barButtonItem; 80 | [self setTitle]; 81 | 82 | NSMutableArray *items = [[self.toolbar items] mutableCopy]; 83 | [items insertObject:barButtonItem atIndex:0]; 84 | [self.toolbar setItems:items animated:YES]; 85 | [items release]; 86 | self.popoverController = pc; 87 | } 88 | 89 | // Called when the view is shown again in the split view, invalidating the button and popover controller. 90 | - (void)splitViewController:(MGSplitViewController*)svc 91 | willShowViewController:(UIViewController *)aViewController 92 | invalidatingBarButtonItem:(UIBarButtonItem *)barButtonItem 93 | { 94 | NSMutableArray *items = [[self.toolbar items] mutableCopy]; 95 | [items removeObjectAtIndex:0]; 96 | [self.toolbar setItems:items animated:YES]; 97 | [items release]; 98 | self.popoverController = nil; 99 | } 100 | 101 | - (void)configureToolbar 102 | { 103 | UIBarButtonItem *loadButton = [[UIBarButtonItem alloc] initWithCustomView:activityIndicator]; 104 | 105 | UIBarButtonItem *fullScreenItem = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"full_screen"] style:UIBarButtonItemStylePlain target:self action:@selector(toggleFullScreen)]; 106 | 107 | UIBarButtonItem *spacer = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil]; 108 | 109 | loadUserItem = [[UIBarButtonItem alloc] initWithTitle:nil style:UIBarButtonItemStylePlain target:self action:@selector(loadMatchedUserRepos)]; 110 | loadUserItem.enabled = NO; 111 | 112 | self.toolbar.items = [NSArray arrayWithObjects:loadButton, loadUserItem, spacer, fullScreenItem, nil]; 113 | 114 | [spacer release]; 115 | [fullScreenItem release]; 116 | } 117 | 118 | // Implement viewDidLoad to do additional setup after loading the view, typically from a nib. 119 | - (void)viewDidLoad 120 | { 121 | [super viewDidLoad]; 122 | 123 | self.webView.delegate = self; 124 | 125 | self.activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray]; 126 | self.activityIndicator.hidesWhenStopped = YES; 127 | 128 | [self configureToolbar]; 129 | 130 | NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; 131 | [notificationCenter addObserver:self selector:@selector(setTitle) name:GBCredentialsChanged object:nil]; 132 | [notificationCenter addObserver:self selector:@selector(showLoadIndicator) name:GBShowLoadIndicator object:nil]; 133 | [notificationCenter addObserver:self selector:@selector(hideLoadIndicator) name:GBHideLoadIndicator object:nil]; 134 | 135 | } 136 | 137 | - (void)viewDidUnload 138 | { 139 | [self setWebView:nil]; 140 | [super viewDidUnload]; 141 | 142 | // Release any retained subviews of the main view. 143 | // e.g. self.myOutlet = nil; 144 | self.popoverController = nil; 145 | } 146 | 147 | #pragma mark loadButtonItem 148 | 149 | - (void)hideLoadButtonItem 150 | { 151 | self.matchedUsername = @""; 152 | loadUserItem.title = @""; 153 | loadUserItem.enabled = NO; 154 | loadUserItem.style = UIBarButtonItemStylePlain; 155 | } 156 | 157 | - (void)showLoadButtonItem 158 | { 159 | // Only show if different than current username 160 | if ([self.matchedUsername isEqualToString:[ApplicationHelper currentUsername]]) 161 | return; 162 | 163 | loadUserItem.title = [NSString stringWithFormat:@"Load %@", self.matchedUsername]; 164 | loadUserItem.enabled = YES; 165 | loadUserItem.style = UIBarButtonItemStyleBordered; 166 | } 167 | 168 | # pragma mark actions 169 | 170 | - (void)showGithubHomepage 171 | { 172 | [self.webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://github.com"]]]; 173 | } 174 | 175 | - (void)showHome 176 | { 177 | NSString *username = [ApplicationHelper username]; 178 | 179 | [ApplicationHelper setCurrentUsername:username notifyOfChange:YES]; 180 | } 181 | 182 | - (void)showSearch 183 | { 184 | /* 185 | SearchViewController *viewController = [[SearchViewController alloc] initWithNibName:@"SearchViewController" bundle:nil]; 186 | UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:viewController]; 187 | navController.modalPresentationStyle = UIModalPresentationFormSheet; 188 | 189 | [self presentModalViewController:navController animated:YES]; 190 | 191 | [viewController release]; 192 | */ 193 | [self.webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://github.com/search"]]]; 194 | } 195 | 196 | /* 197 | - (void)showRandomRepo 198 | { 199 | [ApplicationHelper loadWebViewFromUrl:self.webView url:@"https://github.com/repositories/random"]; 200 | } 201 | */ 202 | 203 | - (void)loadUsernameFromWebView:(UIWebView *)webView 204 | { 205 | NSError *error; 206 | NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"https://github.com/(.+)/(.+)" 207 | options:NSRegularExpressionCaseInsensitive 208 | error:&error]; 209 | 210 | NSString *string = [[webView.request URL] absoluteString]; 211 | 212 | NSArray *matches = [regex matchesInString:string 213 | options:0 214 | range:NSMakeRange(0, [string length])]; 215 | 216 | if ([matches count] > 0) 217 | { 218 | // show button 219 | NSTextCheckingResult *match = [matches objectAtIndex:0]; 220 | 221 | NSRange firstHalfRange = [match rangeAtIndex:1]; 222 | NSString *username = [string substringWithRange:firstHalfRange]; 223 | 224 | // Check if username is valid 225 | if ([ApplicationHelper validUsername:username]) 226 | { 227 | self.matchedUsername = [string substringWithRange:firstHalfRange]; 228 | 229 | [self showLoadButtonItem]; 230 | } 231 | } else 232 | { 233 | [self hideLoadButtonItem]; 234 | } 235 | 236 | } 237 | 238 | - (void)loadUserPage 239 | { 240 | NSString *url 241 | ; 242 | if ([ApplicationHelper usingDefaultUser]) 243 | { 244 | url = @"https://github.com"; 245 | } 246 | else 247 | { 248 | url = [NSString stringWithFormat:@"https://github.com/%@", [ApplicationHelper currentUsername]]; 249 | } 250 | 251 | [ApplicationHelper loadWebViewFromUrl:self.webView url:url]; 252 | } 253 | 254 | - (void)loadMatchedUserRepos 255 | { 256 | [ApplicationHelper setCurrentUsername:self.matchedUsername notifyOfChange:YES]; 257 | [self hideLoadButtonItem]; 258 | } 259 | 260 | - (void)toggleFullScreen 261 | { 262 | [splitController toggleMasterView:self]; 263 | } 264 | 265 | - (void)showLoadIndicator 266 | { 267 | [self.activityIndicator startAnimating]; 268 | } 269 | 270 | - (void)hideLoadIndicator 271 | { 272 | [self.activityIndicator stopAnimating]; 273 | } 274 | 275 | #pragma mark - Memory management 276 | 277 | - (void)dealloc 278 | { 279 | [[NSNotificationCenter defaultCenter] removeObserver:self]; 280 | [_myPopoverController release]; 281 | [_toolbar release]; 282 | [_detailItem release]; 283 | [_webView release]; 284 | [loadUserItem release]; 285 | [matchedUsername release]; 286 | [super dealloc]; 287 | } 288 | 289 | #pragma mark - UIWebViewDelegate methods 290 | 291 | - (void)webViewDidStartLoad:(UIWebView *)webView 292 | { 293 | NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; 294 | NSNotification *notification = [NSNotification notificationWithName:GBShowLoadIndicator object:nil]; 295 | 296 | [notificationCenter postNotification:notification]; 297 | } 298 | 299 | - (void)webViewDidFinishLoad:(UIWebView *)webView 300 | { 301 | [self loadUsernameFromWebView:webView]; 302 | 303 | NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; 304 | NSNotification *notification = [NSNotification notificationWithName:GBHideLoadIndicator object:nil]; 305 | 306 | [notificationCenter postNotification:notification]; 307 | } 308 | 309 | @end 310 | -------------------------------------------------------------------------------- /GithubBrowser/en.lproj/DetailView.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 800 5 | 10J869 6 | 1305 7 | 1038.35 8 | 461.00 9 | 10 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 11 | 300 12 | 13 | 14 | YES 15 | IBUIWebView 16 | IBUIToolbar 17 | IBUIView 18 | IBProxyObject 19 | 20 | 21 | YES 22 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 23 | 24 | 25 | YES 26 | 27 | YES 28 | 29 | 30 | 31 | 32 | YES 33 | 34 | IBFilesOwner 35 | IBIPadFramework 36 | 37 | 38 | IBFirstResponder 39 | IBIPadFramework 40 | 41 | 42 | 43 | 274 44 | 45 | YES 46 | 47 | 48 | 290 49 | {768, 44} 50 | 51 | 52 | NO 53 | NO 54 | IBIPadFramework 55 | 56 | YES 57 | 58 | 59 | 60 | 61 | 274 62 | {{0, 44}, {775, 960}} 63 | 64 | 65 | 66 | 1 67 | MSAxIDEAA 68 | 69 | IBIPadFramework 70 | YES 71 | 1 72 | YES 73 | 74 | 75 | {{0, 20}, {768, 1004}} 76 | 77 | 78 | 79 | 3 80 | MQA 81 | 82 | NO 83 | 84 | 2 85 | 86 | IBIPadFramework 87 | 88 | 89 | 90 | 91 | YES 92 | 93 | 94 | view 95 | 96 | 97 | 98 | 12 99 | 100 | 101 | 102 | toolbar 103 | 104 | 105 | 106 | 65 107 | 108 | 109 | 110 | webView 111 | 112 | 113 | 114 | 68 115 | 116 | 117 | 118 | 119 | YES 120 | 121 | 0 122 | 123 | 124 | 125 | 126 | 127 | -1 128 | 129 | 130 | File's Owner 131 | 132 | 133 | -2 134 | 135 | 136 | 137 | 138 | 8 139 | 140 | 141 | YES 142 | 143 | 144 | 145 | 146 | 147 | 148 | 63 149 | 150 | 151 | YES 152 | 153 | 154 | 155 | 156 | 67 157 | 158 | 159 | 160 | 161 | 162 | 163 | YES 164 | 165 | YES 166 | -1.CustomClassName 167 | -2.CustomClassName 168 | 63.IBPluginDependency 169 | 67.IBPluginDependency 170 | 8.IBEditorWindowLastContentRect 171 | 8.IBPluginDependency 172 | 173 | 174 | YES 175 | DetailViewController 176 | UIResponder 177 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 178 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 179 | {{194, 0}, {783, 856}} 180 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 181 | 182 | 183 | 184 | YES 185 | 186 | 187 | 188 | 189 | 190 | YES 191 | 192 | 193 | 194 | 195 | 68 196 | 197 | 198 | 199 | YES 200 | 201 | DetailViewController 202 | UIViewController 203 | 204 | YES 205 | 206 | YES 207 | toolbar 208 | webView 209 | 210 | 211 | YES 212 | UIToolbar 213 | UIWebView 214 | 215 | 216 | 217 | YES 218 | 219 | YES 220 | toolbar 221 | webView 222 | 223 | 224 | YES 225 | 226 | toolbar 227 | UIToolbar 228 | 229 | 230 | webView 231 | UIWebView 232 | 233 | 234 | 235 | 236 | IBProjectSource 237 | ./Classes/DetailViewController.h 238 | 239 | 240 | 241 | 242 | 0 243 | IBIPadFramework 244 | 245 | com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS 246 | 247 | 248 | 249 | com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 250 | 251 | 252 | YES 253 | 3 254 | 300 255 | 256 | 257 | -------------------------------------------------------------------------------- /GithubBrowser/SearchViewController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1056 5 | 10J869 6 | 1305 7 | 1038.35 8 | 461.00 9 | 10 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 11 | 300 12 | 13 | 14 | YES 15 | IBUILabel 16 | IBUIView 17 | IBUITextField 18 | IBProxyObject 19 | 20 | 21 | YES 22 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 23 | 24 | 25 | YES 26 | 27 | YES 28 | 29 | 30 | 31 | 32 | YES 33 | 34 | IBFilesOwner 35 | IBIPadFramework 36 | 37 | 38 | IBFirstResponder 39 | IBIPadFramework 40 | 41 | 42 | 43 | 256 44 | 45 | YES 46 | 47 | 48 | 256 49 | {{197, 188}, {147, 31}} 50 | 51 | 52 | NO 53 | YES 54 | IBIPadFramework 55 | 0 56 | 57 | 3 58 | 59 | 3 60 | MAA 61 | 62 | 2 63 | 64 | 65 | YES 66 | 17 67 | 68 | IBCocoaTouchFramework 69 | 70 | 71 | 72 | 73 | 292 74 | {{153, 114}, {234, 21}} 75 | 76 | 77 | 78 | NO 79 | YES 80 | 7 81 | NO 82 | IBIPadFramework 83 | Search for a Github Username 84 | 85 | Helvetica 86 | 17 87 | 16 88 | 89 | 90 | 1 91 | MCAwIDAAA 92 | 93 | 94 | 1 95 | 10 96 | 97 | 98 | {540, 576} 99 | 100 | 101 | 102 | 103 | 3 104 | MQA 105 | 106 | 107 | NO 108 | 109 | 3 110 | 3 111 | 112 | IBIPadFramework 113 | 114 | 115 | 116 | 117 | YES 118 | 119 | 120 | view 121 | 122 | 123 | 124 | 3 125 | 126 | 127 | 128 | usernameTextField 129 | 130 | 131 | 132 | 7 133 | 134 | 135 | 136 | 137 | YES 138 | 139 | 0 140 | 141 | 142 | 143 | 144 | 145 | -1 146 | 147 | 148 | File's Owner 149 | 150 | 151 | -2 152 | 153 | 154 | 155 | 156 | 2 157 | 158 | 159 | YES 160 | 161 | 162 | 163 | 164 | 165 | 166 | 4 167 | 168 | 169 | 170 | 171 | 5 172 | 173 | 174 | 175 | 176 | 177 | 178 | YES 179 | 180 | YES 181 | -1.CustomClassName 182 | -2.CustomClassName 183 | 2.IBEditorWindowLastContentRect 184 | 2.IBPluginDependency 185 | 4.IBPluginDependency 186 | 5.IBPluginDependency 187 | 188 | 189 | YES 190 | SearchViewController 191 | UIResponder 192 | {{353, 156}, {1024, 768}} 193 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 194 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 195 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 196 | 197 | 198 | 199 | YES 200 | 201 | 202 | 203 | 204 | 205 | YES 206 | 207 | 208 | 209 | 210 | 9 211 | 212 | 213 | 214 | YES 215 | 216 | SearchViewController 217 | UIViewController 218 | 219 | YES 220 | 221 | YES 222 | cancel 223 | save 224 | 225 | 226 | YES 227 | id 228 | id 229 | 230 | 231 | 232 | YES 233 | 234 | YES 235 | cancel 236 | save 237 | 238 | 239 | YES 240 | 241 | cancel 242 | id 243 | 244 | 245 | save 246 | id 247 | 248 | 249 | 250 | 251 | usernameTextField 252 | UITextField 253 | 254 | 255 | usernameTextField 256 | 257 | usernameTextField 258 | UITextField 259 | 260 | 261 | 262 | IBProjectSource 263 | ./Classes/SearchViewController.h 264 | 265 | 266 | 267 | 268 | 0 269 | IBIPadFramework 270 | 271 | com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 272 | 273 | 274 | YES 275 | 3 276 | 300 277 | 278 | 279 | --------------------------------------------------------------------------------