├── .gitignore ├── .gitmodules ├── Demo ├── .gitignore ├── Classes │ ├── DetailViewController.h │ ├── DetailViewController.m │ ├── EGOPhotoViewer_DemoAppDelegate.h │ ├── EGOPhotoViewer_DemoAppDelegate.m │ ├── Model │ │ ├── MyPhoto.h │ │ ├── MyPhoto.m │ │ ├── MyPhotoSource.h │ │ └── MyPhotoSource.m │ ├── RootViewController.h │ ├── RootViewController.m │ └── iPhone_Controller │ │ ├── RootViewController_iPhone.h │ │ ├── RootViewController_iPhone.m │ │ └── RootViewController_iPhone.xib ├── DetailView.xib ├── EGOPhotoViewer_Demo-Info.plist ├── EGOPhotoViewer_Demo.xcodeproj │ └── project.pbxproj ├── EGOPhotoViewer_Demo_Prefix.pch ├── Libraries │ ├── EGOCache │ │ ├── EGOCache.h │ │ └── EGOCache.m │ └── EGOImageLoader │ │ ├── EGOImageLoadConnection.h │ │ ├── EGOImageLoadConnection.m │ │ ├── EGOImageLoader.h │ │ └── EGOImageLoader.m ├── MainWindow.xib ├── MainWindowiPhone.xib ├── local_image_1.jpg ├── local_image_2.jpg ├── main.m └── photosButton.png ├── EGOPhotoViewer ├── Controller │ └── EGOPhotoViewController │ │ ├── EGOPhotoViewController.h │ │ └── EGOPhotoViewController.m ├── EGOPhotoGlobal.h ├── Model │ ├── EGOPhotoSource │ │ └── EGOPhotoSource.h │ └── EGOQuickPhoto │ │ ├── EGOQuickPhoto.h │ │ ├── EGOQuickPhoto.m │ │ ├── EGOQuickPhotoSource.h │ │ └── EGOQuickPhotoSource.m ├── Resources │ ├── egopv_error_placeholder.png │ ├── egopv_error_placeholder@2x.png │ ├── egopv_fullscreen_button.png │ ├── egopv_fullscreen_button@2x.png │ ├── egopv_left.png │ ├── egopv_left@2x.png │ ├── egopv_minimize_fullscreen_button.png │ ├── egopv_photo_placeholder.png │ ├── egopv_photo_placeholder@2x.png │ ├── egopv_right.png │ └── egopv_right@2x.png └── Views │ ├── EGOPhotoCaptionView │ ├── EGOPhotoCaptionView.h │ └── EGOPhotoCaptionView.m │ ├── EGOPhotoImageView │ ├── EGOPhotoImageView.h │ └── EGOPhotoImageView.m │ └── EGOPhotoScrollView │ ├── EGOPhotoScrollView.h │ └── EGOPhotoScrollView.m └── README.mdown /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | build 3 | *.pbxuser 4 | *.perspectivev3 5 | *.mode1v3 6 | .DS_Store 7 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "Library/EGOCache"] 2 | path = Library/EGOCache 3 | url = git@github.com:enormego/EGOCache.git 4 | [submodule "Library/EGOImageLoading"] 5 | path = Library/EGOImageLoading 6 | url = git@github.com:enormego/EGOImageLoading.git 7 | -------------------------------------------------------------------------------- /Demo/.gitignore: -------------------------------------------------------------------------------- 1 | EGOPhotoViewer_Demo.xcodeproj/project.xcworkspace/ 2 | EGOPhotoViewer_Demo.xcodeproj/xcuserdata/ 3 | -------------------------------------------------------------------------------- /Demo/Classes/DetailViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // DetailViewController.h 3 | // EGOPhotoViewerDemo_iPad 4 | // 5 | // Created by enormego on 4/10/10April10. 6 | // Copyright __MyCompanyName__ 2010. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface DetailViewController : UIViewController { 12 | 13 | UIPopoverController *popoverController; 14 | UIToolbar *toolbar; 15 | 16 | id detailItem; 17 | UILabel *detailDescriptionLabel; 18 | } 19 | 20 | @property (nonatomic, retain) IBOutlet UIToolbar *toolbar; 21 | 22 | @property (nonatomic, retain) id detailItem; 23 | @property (nonatomic, retain) IBOutlet UILabel *detailDescriptionLabel; 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /Demo/Classes/DetailViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // DetailViewController.m 3 | // EGOPhotoViewerDemo_iPad 4 | // 5 | // Created by enormego on 4/10/10April10. 6 | // Copyright __MyCompanyName__ 2010. All rights reserved. 7 | // 8 | 9 | #import "DetailViewController.h" 10 | #import "RootViewController.h" 11 | #import "EGOPhotoViewController.h" 12 | 13 | #import "MyPhotoSource.h" 14 | #import "MyPhoto.h" 15 | 16 | @interface DetailViewController () 17 | @property (nonatomic, retain) UIPopoverController *popoverController; 18 | - (void)configureView; 19 | @end 20 | 21 | 22 | 23 | @implementation DetailViewController 24 | 25 | @synthesize toolbar, popoverController, detailItem, detailDescriptionLabel; 26 | 27 | - (void)viewDidLoad{ 28 | [super viewDidLoad]; 29 | 30 | UIBarButtonItem *imagesButton = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"photosButton.png"] style:UIBarButtonItemStylePlain target:self action:@selector(showPhotoView:)]; 31 | UIBarButtonItem *fixed = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil]; 32 | fixed.width = 40.0f; 33 | UIBarButtonItem *flex = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil]; 34 | 35 | [self.toolbar setItems:[NSArray arrayWithObjects:flex, imagesButton, fixed, nil]]; 36 | 37 | [imagesButton release]; 38 | [flex release]; 39 | 40 | } 41 | 42 | #pragma mark - 43 | #pragma mark Managing the detail item 44 | 45 | /* 46 | When setting the detail item, update the view and dismiss the popover controller if it's showing. 47 | */ 48 | - (void)setDetailItem:(id)newDetailItem { 49 | if (detailItem != newDetailItem) { 50 | [detailItem release]; 51 | detailItem = [newDetailItem retain]; 52 | 53 | // Update the view. 54 | [self configureView]; 55 | } 56 | 57 | if (popoverController != nil) { 58 | [popoverController dismissPopoverAnimated:YES]; 59 | } 60 | } 61 | 62 | 63 | - (void)configureView { 64 | // Update the user interface for the detail item. 65 | detailDescriptionLabel.text = [detailItem description]; 66 | } 67 | 68 | 69 | #pragma mark - 70 | #pragma mark Split view support 71 | 72 | - (void)splitViewController: (UISplitViewController*)svc willHideViewController:(UIViewController *)aViewController withBarButtonItem:(UIBarButtonItem*)barButtonItem forPopoverController: (UIPopoverController*)pc { 73 | 74 | 75 | self.popoverController = pc; 76 | } 77 | 78 | 79 | // Called when the view is shown again in the split view, invalidating the button and popover controller. 80 | - (void)splitViewController: (UISplitViewController*)svc willShowViewController:(UIViewController *)aViewController invalidatingBarButtonItem:(UIBarButtonItem *)barButtonItem { 81 | 82 | 83 | self.popoverController = nil; 84 | } 85 | 86 | 87 | #pragma mark - 88 | #pragma mark Rotation support 89 | 90 | // Ensure that the view controller supports rotation and that the split view can therefore show in both portrait and landscape. 91 | - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { 92 | return YES; 93 | } 94 | 95 | - (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration{ 96 | 97 | if (popoverController) { 98 | [popoverController dismissPopoverAnimated:YES]; 99 | } 100 | 101 | } 102 | 103 | #pragma mark - 104 | #pragma mark EGOPhotoViewer Popover 105 | 106 | - (void)showPhotoView:(UIBarButtonItem*)sender{ 107 | 108 | MyPhoto *webPhoto = [[MyPhoto alloc] initWithImageURL:[NSURL URLWithString:@"http://a3.twimg.com/profile_images/66601193/cactus.jpg"] name:@" laksd;lkas;dlkaslkd ;a"]; 109 | MyPhoto *filePathPhoto = [[MyPhoto alloc] initWithImageURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"local_image_2" ofType:@"jpg"]]]; 110 | MyPhoto *inMemoryPhoto = [[MyPhoto alloc] initWithImage:[UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"local_image_1" ofType:@"jpg"]]]; 111 | 112 | MyPhotoSource *source = [[MyPhotoSource alloc] initWithPhotos:[NSArray arrayWithObjects:webPhoto, filePathPhoto, inMemoryPhoto, nil]]; 113 | 114 | EGOPhotoViewController *photoController = [[EGOPhotoViewController alloc] initWithPhotoSource:source]; 115 | photoController.contentSizeForViewInPopover = CGSizeMake(480.0f, 480.0f); 116 | 117 | [webPhoto release]; 118 | [filePathPhoto release]; 119 | [inMemoryPhoto release]; 120 | [source release]; 121 | 122 | UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:photoController]; 123 | UIPopoverController *popover = [[UIPopoverController alloc] initWithContentViewController:navController]; 124 | popover.delegate = self; 125 | [popover presentPopoverFromBarButtonItem:sender permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES]; 126 | self.popoverController = popover; 127 | 128 | [photoController release]; 129 | [navController release]; 130 | 131 | 132 | } 133 | 134 | #pragma mark - 135 | #pragma mark Popover Delegate Methods 136 | 137 | - (void)popoverControllerDidDismissPopover:(UIPopoverController *)aPopoverController{ 138 | [aPopoverController release]; 139 | popoverController=nil; 140 | } 141 | 142 | 143 | #pragma mark - 144 | #pragma mark View lifecycle 145 | 146 | /* 147 | // Implement viewDidLoad to do additional setup after loading the view, typically from a nib. 148 | - (void)viewDidLoad { 149 | [super viewDidLoad]; 150 | } 151 | */ 152 | 153 | /* 154 | - (void)viewWillAppear:(BOOL)animated { 155 | [super viewWillAppear:animated]; 156 | } 157 | */ 158 | /* 159 | - (void)viewDidAppear:(BOOL)animated { 160 | [super viewDidAppear:animated]; 161 | } 162 | */ 163 | /* 164 | - (void)viewWillDisappear:(BOOL)animated { 165 | [super viewWillDisappear:animated]; 166 | } 167 | */ 168 | /* 169 | - (void)viewDidDisappear:(BOOL)animated { 170 | [super viewDidDisappear:animated]; 171 | } 172 | */ 173 | 174 | - (void)viewDidUnload { 175 | // Release any retained subviews of the main view. 176 | // e.g. self.myOutlet = nil; 177 | self.popoverController = nil; 178 | } 179 | 180 | 181 | #pragma mark - 182 | #pragma mark Memory management 183 | 184 | /* 185 | - (void)didReceiveMemoryWarning { 186 | // Releases the view if it doesn't have a superview. 187 | [super didReceiveMemoryWarning]; 188 | 189 | // Release any cached data, images, etc that aren't in use. 190 | } 191 | */ 192 | 193 | - (void)dealloc { 194 | [popoverController release]; 195 | [toolbar release]; 196 | 197 | [detailItem release]; 198 | [detailDescriptionLabel release]; 199 | [super dealloc]; 200 | } 201 | 202 | @end 203 | -------------------------------------------------------------------------------- /Demo/Classes/EGOPhotoViewer_DemoAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // EGOPhotoViewer_DemoAppDelegate.h 3 | // EGOPhotoViewer_Demo 4 | // 5 | // Created by Devin Doty on 7/3/10July3. 6 | // Copyright __MyCompanyName__ 2010. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | @class RootViewController; 13 | @class DetailViewController; 14 | @class RootViewController_iPhone; 15 | 16 | @interface EGOPhotoViewer_DemoAppDelegate : NSObject { 17 | 18 | UIWindow *window; 19 | 20 | UISplitViewController *splitViewController; 21 | 22 | RootViewController *rootViewController; 23 | DetailViewController *detailViewController; 24 | 25 | RootViewController_iPhone *rootViewController_iPhone; 26 | } 27 | 28 | @property (nonatomic, retain) IBOutlet UIWindow *window; 29 | 30 | @property (nonatomic, retain) IBOutlet UISplitViewController *splitViewController; 31 | @property (nonatomic, retain) IBOutlet UIViewController *rootViewController; 32 | @property (nonatomic, retain) IBOutlet DetailViewController *detailViewController; 33 | 34 | @property (nonatomic, retain) IBOutlet RootViewController_iPhone *rootViewController_iPhone; 35 | 36 | @end 37 | -------------------------------------------------------------------------------- /Demo/Classes/EGOPhotoViewer_DemoAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // EGOPhotoViewer_DemoAppDelegate.m 3 | // EGOPhotoViewer_Demo 4 | // 5 | // Created by Devin Doty on 7/3/10July3. 6 | // Copyright __MyCompanyName__ 2010. All rights reserved. 7 | // 8 | 9 | #import "EGOPhotoViewer_DemoAppDelegate.h" 10 | 11 | 12 | #import "RootViewController.h" 13 | #import "DetailViewController.h" 14 | #import "RootViewController_iPhone.h" 15 | 16 | 17 | @implementation EGOPhotoViewer_DemoAppDelegate 18 | 19 | @synthesize window, splitViewController, rootViewController, detailViewController; 20 | @synthesize rootViewController_iPhone; 21 | 22 | #pragma mark - 23 | #pragma mark Application lifecycle 24 | 25 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 26 | 27 | // Override point for customization after app launch. 28 | 29 | // Add the split view controller's view to the window and display. 30 | 31 | #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 30200 32 | if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) { 33 | 34 | UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:rootViewController_iPhone]; 35 | [window addSubview:navController.view]; 36 | 37 | } else { 38 | 39 | [window addSubview:splitViewController.view]; 40 | 41 | } 42 | 43 | #else 44 | 45 | UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:rootViewController_iPhone]; 46 | [window addSubview:navController.view]; 47 | 48 | #endif 49 | 50 | 51 | [window makeKeyAndVisible]; 52 | 53 | return YES; 54 | } 55 | 56 | 57 | - (void)applicationWillResignActive:(UIApplication *)application { 58 | /* 59 | Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 60 | Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 61 | */ 62 | } 63 | 64 | 65 | - (void)applicationDidBecomeActive:(UIApplication *)application { 66 | /* 67 | Restart any tasks that were paused (or not yet started) while the application was inactive. 68 | */ 69 | } 70 | 71 | 72 | - (void)applicationWillTerminate:(UIApplication *)application { 73 | /* 74 | Called when the application is about to terminate. 75 | */ 76 | } 77 | 78 | 79 | #pragma mark - 80 | #pragma mark Memory management 81 | 82 | - (void)applicationDidReceiveMemoryWarning:(UIApplication *)application { 83 | /* 84 | Free up as much memory as possible by purging cached data objects that can be recreated (or reloaded from disk) later. 85 | */ 86 | } 87 | 88 | 89 | - (void)dealloc { 90 | 91 | if (splitViewController) { 92 | [splitViewController release]; 93 | } 94 | 95 | if (rootViewController_iPhone) { 96 | [rootViewController_iPhone release]; 97 | } 98 | 99 | [window release]; 100 | [super dealloc]; 101 | } 102 | 103 | 104 | @end 105 | 106 | -------------------------------------------------------------------------------- /Demo/Classes/Model/MyPhoto.h: -------------------------------------------------------------------------------- 1 | // 2 | // MyPhoto.h 3 | // EGOPhotoViewerDemo_iPad 4 | // 5 | // Created by Devin Doty on 7/3/10July3. 6 | // Copyright 2010 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "EGOPhotoGlobal.h" 11 | 12 | 13 | @interface MyPhoto : NSObject { 14 | 15 | NSURL *_URL; 16 | NSString *_caption; 17 | CGSize _size; 18 | UIImage *_image; 19 | 20 | BOOL _failed; 21 | 22 | } 23 | 24 | - (id)initWithImageURL:(NSURL*)aURL name:(NSString*)aName image:(UIImage*)aImage; 25 | - (id)initWithImageURL:(NSURL*)aURL name:(NSString*)aName; 26 | - (id)initWithImageURL:(NSURL*)aURL; 27 | - (id)initWithImage:(UIImage*)aImage; 28 | @end 29 | -------------------------------------------------------------------------------- /Demo/Classes/Model/MyPhoto.m: -------------------------------------------------------------------------------- 1 | // 2 | // MyPhoto.m 3 | // EGOPhotoViewerDemo_iPad 4 | // 5 | // Created by Devin Doty on 7/3/10July3. 6 | // Copyright 2010 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import "MyPhoto.h" 10 | 11 | @implementation MyPhoto 12 | 13 | @synthesize URL=_URL; 14 | @synthesize caption=_caption; 15 | @synthesize image=_image; 16 | @synthesize size=_size; 17 | @synthesize failed=_failed; 18 | 19 | - (id)initWithImageURL:(NSURL*)aURL name:(NSString*)aName image:(UIImage*)aImage{ 20 | 21 | if (self = [super init]) { 22 | 23 | _URL=[aURL retain]; 24 | _caption=[aName retain]; 25 | _image=[aImage retain]; 26 | 27 | } 28 | 29 | return self; 30 | } 31 | 32 | - (id)initWithImageURL:(NSURL*)aURL name:(NSString*)aName{ 33 | return [self initWithImageURL:aURL name:aName image:nil]; 34 | } 35 | 36 | - (id)initWithImageURL:(NSURL*)aURL{ 37 | return [self initWithImageURL:aURL name:nil image:nil]; 38 | } 39 | 40 | - (id)initWithImage:(UIImage*)aImage{ 41 | return [self initWithImageURL:nil name:nil image:aImage]; 42 | } 43 | 44 | - (void)dealloc{ 45 | 46 | [_URL release], _URL=nil; 47 | [_image release], _image=nil; 48 | [_caption release], _caption=nil; 49 | 50 | [super dealloc]; 51 | } 52 | 53 | 54 | @end 55 | -------------------------------------------------------------------------------- /Demo/Classes/Model/MyPhotoSource.h: -------------------------------------------------------------------------------- 1 | // 2 | // MyPhotoSource.h 3 | // EGOPhotoViewerDemo_iPad 4 | // 5 | // Created by Devin Doty on 7/3/10July3. 6 | // Copyright 2010 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "EGOPhotoGlobal.h" 11 | 12 | @interface MyPhotoSource : NSObject { 13 | 14 | NSArray *_photos; 15 | NSInteger _numberOfPhotos; 16 | 17 | } 18 | 19 | - (id)initWithPhotos:(NSArray*)photos; 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /Demo/Classes/Model/MyPhotoSource.m: -------------------------------------------------------------------------------- 1 | // 2 | // MyPhotoSource.m 3 | // EGOPhotoViewerDemo_iPad 4 | // 5 | // Created by Devin Doty on 7/3/10July3. 6 | // Copyright 2010 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import "MyPhotoSource.h" 10 | 11 | 12 | @implementation MyPhotoSource 13 | 14 | @synthesize photos=_photos; 15 | @synthesize numberOfPhotos=_numberOfPhotos; 16 | 17 | 18 | - (id)initWithPhotos:(NSArray*)photos{ 19 | 20 | if (self = [super init]) { 21 | 22 | _photos = [photos retain]; 23 | _numberOfPhotos = [_photos count]; 24 | 25 | } 26 | 27 | return self; 28 | 29 | } 30 | 31 | - (id )photoAtIndex:(NSInteger)index{ 32 | 33 | return [_photos objectAtIndex:index]; 34 | 35 | } 36 | 37 | - (void)dealloc{ 38 | 39 | [_photos release], _photos=nil; 40 | [super dealloc]; 41 | } 42 | 43 | @end 44 | -------------------------------------------------------------------------------- /Demo/Classes/RootViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // RootViewController.h 3 | // EGOPhotoViewerDemo_iPad 4 | // 5 | // Created by enormego on 4/10/10April10. 6 | // Copyright __MyCompanyName__ 2010. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class DetailViewController; 12 | 13 | @interface RootViewController : UITableViewController { 14 | DetailViewController *detailViewController; 15 | } 16 | 17 | @property (nonatomic, retain) IBOutlet DetailViewController *detailViewController; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /Demo/Classes/RootViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // RootViewController.m 3 | // MyPhotoViewerDemo_iPad 4 | // 5 | // Created by enormego on 4/10/10April10. 6 | // Copyright __MyCompanyName__ 2010. All rights reserved. 7 | // 8 | 9 | #import "RootViewController.h" 10 | #import "DetailViewController.h" 11 | #import "EGOPhotoGlobal.h" 12 | #import "MyPhotoSource.h" 13 | #import "MyPhoto.h" 14 | 15 | @implementation RootViewController 16 | 17 | @synthesize detailViewController; 18 | 19 | 20 | #pragma mark - 21 | #pragma mark View lifecycle 22 | 23 | - (void)viewDidLoad { 24 | [super viewDidLoad]; 25 | 26 | self.title = @"MyPhotoViewer"; 27 | 28 | self.clearsSelectionOnViewWillAppear = NO; 29 | self.contentSizeForViewInPopover = CGSizeMake(320.0, 600.0); 30 | } 31 | 32 | /* 33 | - (void)viewWillAppear:(BOOL)animated { 34 | [super viewWillAppear:animated]; 35 | } 36 | */ 37 | /* 38 | - (void)viewDidAppear:(BOOL)animated { 39 | [super viewDidAppear:animated]; 40 | } 41 | */ 42 | /* 43 | - (void)viewWillDisappear:(BOOL)animated { 44 | [super viewWillDisappear:animated]; 45 | } 46 | */ 47 | /* 48 | - (void)viewDidDisappear:(BOOL)animated { 49 | [super viewDidDisappear:animated]; 50 | } 51 | */ 52 | 53 | // Ensure that the view controller supports rotation and that the split view can therefore show in both portrait and landscape. 54 | - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { 55 | return YES; 56 | } 57 | 58 | 59 | #pragma mark - 60 | #pragma mark Table view data source 61 | 62 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)aTableView { 63 | // Return the number of sections. 64 | return 1; 65 | } 66 | 67 | 68 | - (NSInteger)tableView:(UITableView *)aTableView numberOfRowsInSection:(NSInteger)section { 69 | // Return the number of rows in the section. 70 | return 2; 71 | } 72 | 73 | 74 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 75 | 76 | static NSString *CellIdentifier = @"CellIdentifier"; 77 | 78 | // Dequeue or create a cell of the appropriate type. 79 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 80 | if (cell == nil) { 81 | cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease]; 82 | cell.accessoryType = UITableViewCellAccessoryNone; 83 | } 84 | 85 | // Configure the cell. 86 | cell.textLabel.text = indexPath.row == 0 ? @"Photos" : @"Single Photo"; 87 | 88 | return cell; 89 | } 90 | 91 | 92 | /* 93 | // Override to support conditional editing of the table view. 94 | - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath { 95 | // Return NO if you do not want the specified item to be editable. 96 | return YES; 97 | } 98 | */ 99 | 100 | 101 | /* 102 | // Override to support editing the table view. 103 | - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { 104 | 105 | if (editingStyle == UITableViewCellEditingStyleDelete) { 106 | // Delete the row from the data source 107 | [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:YES]; 108 | } 109 | else if (editingStyle == UITableViewCellEditingStyleInsert) { 110 | // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view 111 | } 112 | } 113 | */ 114 | 115 | 116 | /* 117 | // Override to support rearranging the table view. 118 | - (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath { 119 | } 120 | */ 121 | 122 | 123 | /* 124 | // Override to support conditional rearranging of the table view. 125 | - (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath { 126 | // Return NO if you do not want the item to be re-orderable. 127 | return YES; 128 | } 129 | */ 130 | 131 | 132 | #pragma mark - 133 | #pragma mark Table view delegate 134 | 135 | - (void)tableView:(UITableView *)aTableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 136 | 137 | 138 | if (indexPath.row == 0) { 139 | 140 | MyPhoto *photo = [[MyPhoto alloc] initWithImageURL:[NSURL URLWithString:@"http://a3.twimg.com/profile_images/66601193/cactus.jpg"] name:@" laksd;lkas;dlkaslkd ;a"]; 141 | MyPhoto *photo2 = [[MyPhoto alloc] initWithImageURL:[NSURL URLWithString:@"https://s3.amazonaws.com/twitter_production/profile_images/425948730/DF-Star-Logo.png"] name:@"lskdjf lksjdhfk jsdfh ksjdhf sjdhf ksjdhf ksdjfh ksdjh skdjfh skdfjh "]; 142 | MyPhotoSource *source = [[MyPhotoSource alloc] initWithPhotos:[NSArray arrayWithObjects:photo, photo2, photo, photo2, photo, photo2, photo, photo2, nil]]; 143 | 144 | EGOPhotoViewController *photoController = [[EGOPhotoViewController alloc] initWithPhotoSource:source]; 145 | UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:photoController]; 146 | 147 | navController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve; 148 | navController.modalPresentationStyle = UIModalPresentationFullScreen; 149 | [self presentModalViewController:navController animated:YES]; 150 | 151 | [navController release]; 152 | [photoController release]; 153 | [photo release]; 154 | [photo2 release]; 155 | [source release]; 156 | 157 | 158 | } else if (indexPath.row == 1) { 159 | 160 | MyPhoto *photo = [[MyPhoto alloc] initWithImageURL:[NSURL URLWithString:@"https://s3.amazonaws.com/twitter_production/profile_images/425948730/DF-Star-Logo.png"]]; 161 | MyPhotoSource *source = [[MyPhotoSource alloc] initWithPhotos:[NSArray arrayWithObjects:photo, nil]]; 162 | EGOPhotoViewController *photoController = [[EGOPhotoViewController alloc] initWithPhotoSource:source]; 163 | 164 | UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:photoController]; 165 | navController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve; 166 | navController.modalPresentationStyle = UIModalPresentationFullScreen; 167 | [self presentModalViewController:navController animated:YES]; 168 | 169 | [navController release]; 170 | [photoController release]; 171 | [photo release]; 172 | [source release]; 173 | 174 | } 175 | } 176 | 177 | 178 | #pragma mark - 179 | #pragma mark Memory management 180 | 181 | - (void)didReceiveMemoryWarning { 182 | // Releases the view if it doesn't have a superview. 183 | [super didReceiveMemoryWarning]; 184 | 185 | // Relinquish ownership any cached data, images, etc. that aren't in use. 186 | } 187 | 188 | - (void)viewDidUnload { 189 | // Relinquish ownership of anything that can be recreated in viewDidLoad or on demand. 190 | // For example: self.myOutlet = nil; 191 | } 192 | 193 | 194 | - (void)dealloc { 195 | [detailViewController release]; 196 | [super dealloc]; 197 | } 198 | 199 | 200 | @end 201 | 202 | -------------------------------------------------------------------------------- /Demo/Classes/iPhone_Controller/RootViewController_iPhone.h: -------------------------------------------------------------------------------- 1 | // 2 | // RootViewController_iPhone.h 3 | // EGOPhotoViewer_Demo 4 | // 5 | // Created by Devin Doty on 7/3/10July3. 6 | // Copyright 2010 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | @interface RootViewController_iPhone : UITableViewController { 13 | 14 | } 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /Demo/Classes/iPhone_Controller/RootViewController_iPhone.m: -------------------------------------------------------------------------------- 1 | // 2 | // RootViewController_iPhone.m 3 | // EGOPhotoViewer_Demo 4 | // 5 | // Created by Devin Doty on 7/3/10July3. 6 | // Copyright 2010 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import "RootViewController_iPhone.h" 10 | #import "EGOPhotoGlobal.h" 11 | #import "MyPhoto.h" 12 | #import "MyPhotoSource.h" 13 | 14 | @implementation RootViewController_iPhone 15 | 16 | 17 | #pragma mark - 18 | #pragma mark View lifecycle 19 | 20 | 21 | - (void)viewDidLoad { 22 | [super viewDidLoad]; 23 | 24 | // Uncomment the following line to display an Edit button in the navigation bar for this view controller. 25 | // self.navigationItem.rightBarButtonItem = self.editButtonItem; 26 | 27 | self.title = @"EGOPhotoViewer Demo"; 28 | } 29 | 30 | 31 | /* 32 | - (void)viewWillAppear:(BOOL)animated { 33 | [super viewWillAppear:animated]; 34 | } 35 | */ 36 | /* 37 | - (void)viewDidAppear:(BOOL)animated { 38 | [super viewDidAppear:animated]; 39 | } 40 | */ 41 | /* 42 | - (void)viewWillDisappear:(BOOL)animated { 43 | [super viewWillDisappear:animated]; 44 | } 45 | */ 46 | /* 47 | - (void)viewDidDisappear:(BOOL)animated { 48 | [super viewDidDisappear:animated]; 49 | } 50 | */ 51 | /* 52 | // Override to allow orientations other than the default portrait orientation. 53 | - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { 54 | // Return YES for supported orientations 55 | return (interfaceOrientation == UIInterfaceOrientationPortrait); 56 | } 57 | */ 58 | 59 | 60 | #pragma mark - 61 | #pragma mark Table view data source 62 | 63 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 64 | // Return the number of sections. 65 | return 1; 66 | } 67 | 68 | 69 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 70 | // Return the number of rows in the section. 71 | return 2; 72 | } 73 | 74 | 75 | // Customize the appearance of table view cells. 76 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 77 | 78 | static NSString *CellIdentifier = @"Cell"; 79 | 80 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 81 | if (cell == nil) { 82 | cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease]; 83 | } 84 | 85 | if (indexPath.row == 0) { 86 | cell.textLabel.text = @"Photos"; 87 | } else { 88 | cell.textLabel.text = @"Single Photo"; 89 | } 90 | 91 | cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; 92 | 93 | return cell; 94 | } 95 | 96 | 97 | /* 98 | // Override to support conditional editing of the table view. 99 | - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath { 100 | // Return NO if you do not want the specified item to be editable. 101 | return YES; 102 | } 103 | */ 104 | 105 | 106 | /* 107 | // Override to support editing the table view. 108 | - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { 109 | 110 | if (editingStyle == UITableViewCellEditingStyleDelete) { 111 | // Delete the row from the data source 112 | [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:YES]; 113 | } 114 | else if (editingStyle == UITableViewCellEditingStyleInsert) { 115 | // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view 116 | } 117 | } 118 | */ 119 | 120 | 121 | /* 122 | // Override to support rearranging the table view. 123 | - (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath { 124 | } 125 | */ 126 | 127 | 128 | /* 129 | // Override to support conditional rearranging of the table view. 130 | - (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath { 131 | // Return NO if you do not want the item to be re-orderable. 132 | return YES; 133 | } 134 | */ 135 | 136 | 137 | #pragma mark - 138 | #pragma mark Table view delegate 139 | 140 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 141 | 142 | if (indexPath.row == 0) { 143 | 144 | MyPhoto *photo = [[MyPhoto alloc] initWithImageURL:[NSURL URLWithString:@"http://a3.twimg.com/profile_images/66601193/cactus.jpg"] name:@" laksd;lkas;dlkaslkd ;a"]; 145 | MyPhoto *photo2 = [[MyPhoto alloc] initWithImageURL:[NSURL URLWithString:@"https://s3.amazonaws.com/twitter_production/profile_images/425948730/DF-Star-Logo.png"] name:@"lskdjf lksjdhfk jsdfh ksjdhf sjdhf ksjdhf ksdjfh ksdjh skdjfh skdfjh "]; 146 | MyPhotoSource *source = [[MyPhotoSource alloc] initWithPhotos:[NSArray arrayWithObjects:photo, photo2, photo, photo2, photo, photo2, photo, photo2, nil]]; 147 | 148 | EGOPhotoViewController *photoController = [[EGOPhotoViewController alloc] initWithPhotoSource:source]; 149 | [self.navigationController pushViewController:photoController animated:YES]; 150 | 151 | [photoController release]; 152 | [photo release]; 153 | [photo2 release]; 154 | [source release]; 155 | 156 | } else if (indexPath.row == 1) { 157 | 158 | MyPhoto *photo = [[MyPhoto alloc] initWithImageURL:[NSURL URLWithString:@"https://s3.amazonaws.com/twitter_production/profile_images/425948730/DF-Star-Logo.png"]]; 159 | MyPhotoSource *source = [[MyPhotoSource alloc] initWithPhotos:[NSArray arrayWithObjects:photo, nil]]; 160 | 161 | EGOPhotoViewController *photoController = [[EGOPhotoViewController alloc] initWithPhotoSource:source]; 162 | [self.navigationController pushViewController:photoController animated:YES]; 163 | 164 | [photoController release]; 165 | [photo release]; 166 | [source release]; 167 | 168 | } 169 | } 170 | 171 | 172 | #pragma mark - 173 | #pragma mark Memory management 174 | 175 | - (void)didReceiveMemoryWarning { 176 | // Releases the view if it doesn't have a superview. 177 | [super didReceiveMemoryWarning]; 178 | 179 | // Relinquish ownership any cached data, images, etc that aren't in use. 180 | } 181 | 182 | - (void)viewDidUnload { 183 | // Relinquish ownership of anything that can be recreated in viewDidLoad or on demand. 184 | // For example: self.myOutlet = nil; 185 | } 186 | 187 | 188 | - (void)dealloc { 189 | [super dealloc]; 190 | } 191 | 192 | 193 | @end 194 | 195 | -------------------------------------------------------------------------------- /Demo/Classes/iPhone_Controller/RootViewController_iPhone.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1024 5 | 10D573 6 | 788 7 | 1038.29 8 | 460.00 9 | 10 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 11 | 117 12 | 13 | 14 | YES 15 | 16 | 17 | 18 | YES 19 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 20 | 21 | 22 | YES 23 | 24 | YES 25 | 26 | 27 | YES 28 | 29 | 30 | 31 | YES 32 | 33 | IBFilesOwner 34 | IBCocoaTouchFramework 35 | 36 | 37 | IBFirstResponder 38 | IBCocoaTouchFramework 39 | 40 | 41 | 42 | 274 43 | {320, 460} 44 | 45 | 46 | 3 47 | MQA 48 | 49 | NO 50 | YES 51 | NO 52 | 53 | IBCocoaTouchFramework 54 | NO 55 | 1 56 | 0 57 | YES 58 | 44 59 | 22 60 | 22 61 | 62 | 63 | 64 | 65 | YES 66 | 67 | 68 | view 69 | 70 | 71 | 72 | 5 73 | 74 | 75 | 76 | dataSource 77 | 78 | 79 | 80 | 6 81 | 82 | 83 | 84 | delegate 85 | 86 | 87 | 88 | 7 89 | 90 | 91 | 92 | 93 | YES 94 | 95 | 0 96 | 97 | 98 | 99 | 100 | 101 | -1 102 | 103 | 104 | File's Owner 105 | 106 | 107 | -2 108 | 109 | 110 | 111 | 112 | 4 113 | 114 | 115 | 116 | 117 | 118 | 119 | YES 120 | 121 | YES 122 | -1.CustomClassName 123 | -2.CustomClassName 124 | 4.IBEditorWindowLastContentRect 125 | 4.IBPluginDependency 126 | 127 | 128 | YES 129 | RootViewController_iPhone 130 | UIResponder 131 | {{329, 276}, {320, 480}} 132 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 133 | 134 | 135 | 136 | YES 137 | 138 | 139 | YES 140 | 141 | 142 | 143 | 144 | YES 145 | 146 | 147 | YES 148 | 149 | 150 | 151 | 7 152 | 153 | 154 | 155 | YES 156 | 157 | RootViewController_iPhone 158 | UITableViewController 159 | 160 | IBProjectSource 161 | Classes/iPhone_Controller/RootViewController_iPhone.h 162 | 163 | 164 | 165 | 166 | YES 167 | 168 | NSObject 169 | 170 | IBFrameworkSource 171 | Foundation.framework/Headers/NSError.h 172 | 173 | 174 | 175 | NSObject 176 | 177 | IBFrameworkSource 178 | Foundation.framework/Headers/NSFileManager.h 179 | 180 | 181 | 182 | NSObject 183 | 184 | IBFrameworkSource 185 | Foundation.framework/Headers/NSKeyValueCoding.h 186 | 187 | 188 | 189 | NSObject 190 | 191 | IBFrameworkSource 192 | Foundation.framework/Headers/NSKeyValueObserving.h 193 | 194 | 195 | 196 | NSObject 197 | 198 | IBFrameworkSource 199 | Foundation.framework/Headers/NSKeyedArchiver.h 200 | 201 | 202 | 203 | NSObject 204 | 205 | IBFrameworkSource 206 | Foundation.framework/Headers/NSObject.h 207 | 208 | 209 | 210 | NSObject 211 | 212 | IBFrameworkSource 213 | Foundation.framework/Headers/NSRunLoop.h 214 | 215 | 216 | 217 | NSObject 218 | 219 | IBFrameworkSource 220 | Foundation.framework/Headers/NSThread.h 221 | 222 | 223 | 224 | NSObject 225 | 226 | IBFrameworkSource 227 | Foundation.framework/Headers/NSURL.h 228 | 229 | 230 | 231 | NSObject 232 | 233 | IBFrameworkSource 234 | Foundation.framework/Headers/NSURLConnection.h 235 | 236 | 237 | 238 | NSObject 239 | 240 | IBFrameworkSource 241 | QuartzCore.framework/Headers/CAAnimation.h 242 | 243 | 244 | 245 | NSObject 246 | 247 | IBFrameworkSource 248 | QuartzCore.framework/Headers/CALayer.h 249 | 250 | 251 | 252 | NSObject 253 | 254 | IBFrameworkSource 255 | UIKit.framework/Headers/UIAccessibility.h 256 | 257 | 258 | 259 | NSObject 260 | 261 | IBFrameworkSource 262 | UIKit.framework/Headers/UINibLoading.h 263 | 264 | 265 | 266 | NSObject 267 | 268 | IBFrameworkSource 269 | UIKit.framework/Headers/UIResponder.h 270 | 271 | 272 | 273 | UIResponder 274 | NSObject 275 | 276 | 277 | 278 | UIScrollView 279 | UIView 280 | 281 | IBFrameworkSource 282 | UIKit.framework/Headers/UIScrollView.h 283 | 284 | 285 | 286 | UISearchBar 287 | UIView 288 | 289 | IBFrameworkSource 290 | UIKit.framework/Headers/UISearchBar.h 291 | 292 | 293 | 294 | UISearchDisplayController 295 | NSObject 296 | 297 | IBFrameworkSource 298 | UIKit.framework/Headers/UISearchDisplayController.h 299 | 300 | 301 | 302 | UITableView 303 | UIScrollView 304 | 305 | IBFrameworkSource 306 | UIKit.framework/Headers/UITableView.h 307 | 308 | 309 | 310 | UITableViewController 311 | UIViewController 312 | 313 | IBFrameworkSource 314 | UIKit.framework/Headers/UITableViewController.h 315 | 316 | 317 | 318 | UIView 319 | 320 | IBFrameworkSource 321 | UIKit.framework/Headers/UITextField.h 322 | 323 | 324 | 325 | UIView 326 | UIResponder 327 | 328 | IBFrameworkSource 329 | UIKit.framework/Headers/UIView.h 330 | 331 | 332 | 333 | UIViewController 334 | 335 | IBFrameworkSource 336 | UIKit.framework/Headers/UINavigationController.h 337 | 338 | 339 | 340 | UIViewController 341 | 342 | IBFrameworkSource 343 | UIKit.framework/Headers/UIPopoverController.h 344 | 345 | 346 | 347 | UIViewController 348 | 349 | IBFrameworkSource 350 | UIKit.framework/Headers/UISplitViewController.h 351 | 352 | 353 | 354 | UIViewController 355 | 356 | IBFrameworkSource 357 | UIKit.framework/Headers/UITabBarController.h 358 | 359 | 360 | 361 | UIViewController 362 | UIResponder 363 | 364 | IBFrameworkSource 365 | UIKit.framework/Headers/UIViewController.h 366 | 367 | 368 | 369 | 370 | 0 371 | IBCocoaTouchFramework 372 | 373 | com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS 374 | 375 | 376 | 377 | com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 378 | 379 | 380 | YES 381 | 382 | 3 383 | 117 384 | 385 | 386 | -------------------------------------------------------------------------------- /Demo/DetailView.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 800 5 | 10D559 6 | 761 7 | 1038.29 8 | 460.00 9 | 10 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 11 | 84 12 | 13 | 14 | YES 15 | 16 | 17 | 18 | YES 19 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 20 | 21 | 22 | YES 23 | 24 | YES 25 | 26 | 27 | YES 28 | 29 | 30 | 31 | YES 32 | 33 | IBFilesOwner 34 | IBIPadFramework 35 | 36 | 37 | IBFirstResponder 38 | IBIPadFramework 39 | 40 | 41 | 42 | 274 43 | 44 | YES 45 | 46 | 47 | 298 48 | {{20, 475}, {728, 21}} 49 | 50 | 51 | 3 52 | MQA 53 | 54 | YES 55 | NO 56 | IBIPadFramework 57 | Detail view content goes here 58 | 59 | 1 60 | MCAwIDAAA 61 | 62 | 63 | 1 64 | 10 65 | 1 66 | 67 | 68 | 69 | 290 70 | {768, 44} 71 | 72 | NO 73 | NO 74 | IBIPadFramework 75 | 76 | YES 77 | 78 | 79 | 80 | {768, 1004} 81 | 82 | 83 | NO 84 | 85 | 2 86 | 87 | IBIPadFramework 88 | 89 | 90 | 91 | 92 | YES 93 | 94 | 95 | view 96 | 97 | 98 | 99 | 12 100 | 101 | 102 | 103 | toolbar 104 | 105 | 106 | 107 | 65 108 | 109 | 110 | 111 | detailDescriptionLabel 112 | 113 | 114 | 115 | 66 116 | 117 | 118 | 119 | 120 | YES 121 | 122 | 0 123 | 124 | 125 | 126 | 127 | 128 | -1 129 | 130 | 131 | File's Owner 132 | 133 | 134 | -2 135 | 136 | 137 | 138 | 139 | 8 140 | 141 | 142 | YES 143 | 144 | 145 | 146 | 147 | 148 | 149 | 45 150 | 151 | 152 | 153 | 154 | 63 155 | 156 | 157 | YES 158 | 159 | 160 | 161 | 162 | 163 | 164 | YES 165 | 166 | YES 167 | -1.CustomClassName 168 | -2.CustomClassName 169 | 45.IBPluginDependency 170 | 63.IBPluginDependency 171 | 8.IBEditorWindowLastContentRect 172 | 8.IBPluginDependency 173 | 174 | 175 | YES 176 | DetailViewController 177 | UIResponder 178 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 179 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 180 | {{194, 0}, {783, 856}} 181 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 182 | 183 | 184 | 185 | YES 186 | 187 | 188 | YES 189 | 190 | 191 | 192 | 193 | YES 194 | 195 | 196 | YES 197 | 198 | 199 | 200 | 66 201 | 202 | 203 | 204 | YES 205 | 206 | DetailViewController 207 | UIViewController 208 | 209 | YES 210 | 211 | YES 212 | detailDescriptionLabel 213 | detailItem 214 | toolbar 215 | 216 | 217 | YES 218 | UILabel 219 | id 220 | UIToolbar 221 | 222 | 223 | 224 | IBProjectSource 225 | Classes/DetailViewController.h 226 | 227 | 228 | 229 | 230 | YES 231 | 232 | NSObject 233 | 234 | IBFrameworkSource 235 | Foundation.framework/Headers/NSError.h 236 | 237 | 238 | 239 | NSObject 240 | 241 | IBFrameworkSource 242 | Foundation.framework/Headers/NSFileManager.h 243 | 244 | 245 | 246 | NSObject 247 | 248 | IBFrameworkSource 249 | Foundation.framework/Headers/NSKeyValueCoding.h 250 | 251 | 252 | 253 | NSObject 254 | 255 | IBFrameworkSource 256 | Foundation.framework/Headers/NSKeyValueObserving.h 257 | 258 | 259 | 260 | NSObject 261 | 262 | IBFrameworkSource 263 | Foundation.framework/Headers/NSKeyedArchiver.h 264 | 265 | 266 | 267 | NSObject 268 | 269 | IBFrameworkSource 270 | Foundation.framework/Headers/NSNetServices.h 271 | 272 | 273 | 274 | NSObject 275 | 276 | IBFrameworkSource 277 | Foundation.framework/Headers/NSObject.h 278 | 279 | 280 | 281 | NSObject 282 | 283 | IBFrameworkSource 284 | Foundation.framework/Headers/NSPort.h 285 | 286 | 287 | 288 | NSObject 289 | 290 | IBFrameworkSource 291 | Foundation.framework/Headers/NSRunLoop.h 292 | 293 | 294 | 295 | NSObject 296 | 297 | IBFrameworkSource 298 | Foundation.framework/Headers/NSStream.h 299 | 300 | 301 | 302 | NSObject 303 | 304 | IBFrameworkSource 305 | Foundation.framework/Headers/NSThread.h 306 | 307 | 308 | 309 | NSObject 310 | 311 | IBFrameworkSource 312 | Foundation.framework/Headers/NSURL.h 313 | 314 | 315 | 316 | NSObject 317 | 318 | IBFrameworkSource 319 | Foundation.framework/Headers/NSURLConnection.h 320 | 321 | 322 | 323 | NSObject 324 | 325 | IBFrameworkSource 326 | Foundation.framework/Headers/NSXMLParser.h 327 | 328 | 329 | 330 | NSObject 331 | 332 | IBFrameworkSource 333 | UIKit.framework/Headers/UIAccessibility.h 334 | 335 | 336 | 337 | NSObject 338 | 339 | IBFrameworkSource 340 | UIKit.framework/Headers/UINibLoading.h 341 | 342 | 343 | 344 | NSObject 345 | 346 | IBFrameworkSource 347 | UIKit.framework/Headers/UIResponder.h 348 | 349 | 350 | 351 | UILabel 352 | UIView 353 | 354 | IBFrameworkSource 355 | UIKit.framework/Headers/UILabel.h 356 | 357 | 358 | 359 | UIResponder 360 | NSObject 361 | 362 | 363 | 364 | UISearchBar 365 | UIView 366 | 367 | IBFrameworkSource 368 | UIKit.framework/Headers/UISearchBar.h 369 | 370 | 371 | 372 | UISearchDisplayController 373 | NSObject 374 | 375 | IBFrameworkSource 376 | UIKit.framework/Headers/UISearchDisplayController.h 377 | 378 | 379 | 380 | UIToolbar 381 | UIView 382 | 383 | IBFrameworkSource 384 | UIKit.framework/Headers/UIToolbar.h 385 | 386 | 387 | 388 | UIView 389 | 390 | IBFrameworkSource 391 | UIKit.framework/Headers/UITextField.h 392 | 393 | 394 | 395 | UIView 396 | UIResponder 397 | 398 | IBFrameworkSource 399 | UIKit.framework/Headers/UIView.h 400 | 401 | 402 | 403 | UIViewController 404 | 405 | IBFrameworkSource 406 | UIKit.framework/Headers/UINavigationController.h 407 | 408 | 409 | 410 | UIViewController 411 | 412 | IBFrameworkSource 413 | UIKit.framework/Headers/UIPopoverController.h 414 | 415 | 416 | 417 | UIViewController 418 | 419 | IBFrameworkSource 420 | UIKit.framework/Headers/UISplitViewController.h 421 | 422 | 423 | 424 | UIViewController 425 | 426 | IBFrameworkSource 427 | UIKit.framework/Headers/UITabBarController.h 428 | 429 | 430 | 431 | UIViewController 432 | UIResponder 433 | 434 | IBFrameworkSource 435 | UIKit.framework/Headers/UIViewController.h 436 | 437 | 438 | 439 | 440 | 0 441 | IBIPadFramework 442 | 443 | com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS 444 | 445 | 446 | 447 | com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 448 | 449 | 450 | YES 451 | EGOPhotoViewer_Demo.xcodeproj 452 | 3 453 | 84 454 | 455 | 456 | -------------------------------------------------------------------------------- /Demo/EGOPhotoViewer_Demo-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIconFile 12 | 13 | CFBundleIdentifier 14 | com.yourcompany.${PRODUCT_NAME:rfc1034identifier} 15 | CFBundleInfoDictionaryVersion 16 | 6.0 17 | CFBundleName 18 | ${PRODUCT_NAME} 19 | CFBundlePackageType 20 | APPL 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | LSRequiresIPhoneOS 26 | 27 | NSMainNibFile~iphone 28 | MainWindowiPhone 29 | NSMainNibFile~ipad 30 | MainWindow 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationPortraitUpsideDown 35 | UIInterfaceOrientationLandscapeLeft 36 | UIInterfaceOrientationLandscapeRight 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /Demo/EGOPhotoViewer_Demo_Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'EGOPhotoViewer_Demo' target in the 'EGOPhotoViewer_Demo' project 3 | // 4 | #import 5 | 6 | #ifndef __IPHONE_3_2 7 | #warning "This project uses features only available in iPhone SDK 3.2 and later." 8 | #endif 9 | 10 | 11 | #ifdef __OBJC__ 12 | #import 13 | #import 14 | #endif 15 | -------------------------------------------------------------------------------- /Demo/Libraries/EGOCache/EGOCache.h: -------------------------------------------------------------------------------- 1 | // 2 | // EGOCache.h 3 | // enormego 4 | // 5 | // Created by Shaun Harrison on 7/4/09. 6 | // Copyright (c) 2009-2010 enormego 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | // 26 | 27 | #import 28 | 29 | 30 | @interface EGOCache : NSObject { 31 | @private 32 | NSMutableDictionary* cacheDictionary; 33 | NSOperationQueue* diskOperationQueue; 34 | NSTimeInterval defaultTimeoutInterval; 35 | } 36 | 37 | + (EGOCache*)currentCache; 38 | 39 | - (void)clearCache; 40 | - (void)removeCacheForKey:(NSString*)key; 41 | 42 | - (BOOL)hasCacheForKey:(NSString*)key; 43 | 44 | - (NSData*)dataForKey:(NSString*)key; 45 | - (void)setData:(NSData*)data forKey:(NSString*)key; 46 | - (void)setData:(NSData*)data forKey:(NSString*)key withTimeoutInterval:(NSTimeInterval)timeoutInterval; 47 | 48 | - (NSString*)stringForKey:(NSString*)key; 49 | - (void)setString:(NSString*)aString forKey:(NSString*)key; 50 | - (void)setString:(NSString*)aString forKey:(NSString*)key withTimeoutInterval:(NSTimeInterval)timeoutInterval; 51 | 52 | #if TARGET_OS_IPHONE 53 | - (UIImage*)imageForKey:(NSString*)key; 54 | - (void)setImage:(UIImage*)anImage forKey:(NSString*)key; 55 | - (void)setImage:(UIImage*)anImage forKey:(NSString*)key withTimeoutInterval:(NSTimeInterval)timeoutInterval; 56 | #else 57 | - (NSImage*)imageForKey:(NSString*)key; 58 | - (void)setImage:(NSImage*)anImage forKey:(NSString*)key; 59 | - (void)setImage:(NSImage*)anImage forKey:(NSString*)key withTimeoutInterval:(NSTimeInterval)timeoutInterval; 60 | #endif 61 | 62 | - (NSData*)plistForKey:(NSString*)key; 63 | - (void)setPlist:(id)plistObject forKey:(NSString*)key; 64 | - (void)setPlist:(id)plistObject forKey:(NSString*)key withTimeoutInterval:(NSTimeInterval)timeoutInterval; 65 | 66 | - (void)copyFilePath:(NSString*)filePath asKey:(NSString*)key; 67 | - (void)copyFilePath:(NSString*)filePath asKey:(NSString*)key withTimeoutInterval:(NSTimeInterval)timeoutInterval; 68 | 69 | @property(nonatomic,assign) NSTimeInterval defaultTimeoutInterval; // Default is 1 day 70 | @end -------------------------------------------------------------------------------- /Demo/Libraries/EGOCache/EGOCache.m: -------------------------------------------------------------------------------- 1 | // 2 | // EGOCache.m 3 | // enormego 4 | // 5 | // Created by Shaun Harrison on 7/4/09. 6 | // Copyright (c) 2009-2010 enormego 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | // 26 | 27 | #import "EGOCache.h" 28 | 29 | #if DEBUG 30 | #define CHECK_FOR_EGOCACHE_PLIST() if([key isEqualToString:@"EGOCache.plist"]) { \ 31 | NSLog(@"EGOCache.plist is a reserved key and can not be modified."); \ 32 | return; } 33 | #else 34 | #define CHECK_FOR_EGOCACHE_PLIST() if([key isEqualToString:@"EGOCache.plist"]) return; 35 | #endif 36 | 37 | 38 | 39 | static NSString* _EGOCacheDirectory; 40 | 41 | static inline NSString* EGOCacheDirectory() { 42 | if(!_EGOCacheDirectory) { 43 | NSString* cachesDirectory = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0]; 44 | _EGOCacheDirectory = [[[cachesDirectory stringByAppendingPathComponent:[[NSProcessInfo processInfo] processName]] stringByAppendingPathComponent:@"EGOCache"] copy]; 45 | } 46 | 47 | return _EGOCacheDirectory; 48 | } 49 | 50 | static inline NSString* cachePathForKey(NSString* key) { 51 | return [EGOCacheDirectory() stringByAppendingPathComponent:key]; 52 | } 53 | 54 | static EGOCache* __instance; 55 | 56 | @interface EGOCache () 57 | - (void)removeItemFromCache:(NSString*)key; 58 | - (void)performDiskWriteOperation:(NSInvocation *)invoction; 59 | - (void)saveCacheDictionary; 60 | @end 61 | 62 | #pragma mark - 63 | 64 | @implementation EGOCache 65 | @synthesize defaultTimeoutInterval; 66 | 67 | + (EGOCache*)currentCache { 68 | @synchronized(self) { 69 | if(!__instance) { 70 | __instance = [[EGOCache alloc] init]; 71 | __instance.defaultTimeoutInterval = 86400; 72 | } 73 | } 74 | 75 | return __instance; 76 | } 77 | 78 | - (id)init { 79 | if((self = [super init])) { 80 | NSDictionary* dict = [NSDictionary dictionaryWithContentsOfFile:cachePathForKey(@"EGOCache.plist")]; 81 | 82 | if([dict isKindOfClass:[NSDictionary class]]) { 83 | cacheDictionary = [dict mutableCopy]; 84 | } else { 85 | cacheDictionary = [[NSMutableDictionary alloc] init]; 86 | } 87 | 88 | diskOperationQueue = [[NSOperationQueue alloc] init]; 89 | 90 | [[NSFileManager defaultManager] createDirectoryAtPath:EGOCacheDirectory() 91 | withIntermediateDirectories:YES 92 | attributes:nil 93 | error:NULL]; 94 | 95 | for(NSString* key in cacheDictionary) { 96 | NSDate* date = [cacheDictionary objectForKey:key]; 97 | if([[[NSDate date] earlierDate:date] isEqualToDate:date]) { 98 | [[NSFileManager defaultManager] removeItemAtPath:cachePathForKey(key) error:NULL]; 99 | } 100 | } 101 | } 102 | 103 | return self; 104 | } 105 | 106 | - (void)clearCache { 107 | for(NSString* key in [cacheDictionary allKeys]) { 108 | [self removeItemFromCache:key]; 109 | } 110 | 111 | [self saveCacheDictionary]; 112 | } 113 | 114 | - (void)removeCacheForKey:(NSString*)key { 115 | CHECK_FOR_EGOCACHE_PLIST(); 116 | 117 | [self removeItemFromCache:key]; 118 | [self saveCacheDictionary]; 119 | } 120 | 121 | - (void)removeItemFromCache:(NSString*)key { 122 | NSString* cachePath = cachePathForKey(key); 123 | 124 | NSInvocation* deleteInvocation = [NSInvocation invocationWithMethodSignature:[self methodSignatureForSelector:@selector(deleteDataAtPath:)]]; 125 | [deleteInvocation setTarget:self]; 126 | [deleteInvocation setSelector:@selector(deleteDataAtPath:)]; 127 | [deleteInvocation setArgument:&cachePath atIndex:2]; 128 | 129 | [self performDiskWriteOperation:deleteInvocation]; 130 | [cacheDictionary removeObjectForKey:key]; 131 | } 132 | 133 | - (BOOL)hasCacheForKey:(NSString*)key { 134 | NSDate* date = [cacheDictionary objectForKey:key]; 135 | if(!date) return NO; 136 | if([[[NSDate date] earlierDate:date] isEqualToDate:date]) return NO; 137 | return [[NSFileManager defaultManager] fileExistsAtPath:cachePathForKey(key)]; 138 | } 139 | 140 | #pragma mark - 141 | #pragma mark Copy file methods 142 | 143 | - (void)copyFilePath:(NSString*)filePath asKey:(NSString*)key { 144 | [self copyFilePath:filePath asKey:key withTimeoutInterval:self.defaultTimeoutInterval]; 145 | } 146 | 147 | - (void)copyFilePath:(NSString*)filePath asKey:(NSString*)key withTimeoutInterval:(NSTimeInterval)timeoutInterval { 148 | [[NSFileManager defaultManager] copyItemAtPath:filePath toPath:cachePathForKey(key) error:NULL]; 149 | [cacheDictionary setObject:[NSDate dateWithTimeIntervalSinceNow:timeoutInterval] forKey:key]; 150 | [self performSelectorOnMainThread:@selector(saveAfterDelay) withObject:nil waitUntilDone:YES]; 151 | } 152 | 153 | #pragma mark - 154 | #pragma mark Data methods 155 | 156 | - (void)setData:(NSData*)data forKey:(NSString*)key { 157 | [self setData:data forKey:key withTimeoutInterval:self.defaultTimeoutInterval]; 158 | } 159 | 160 | - (void)setData:(NSData*)data forKey:(NSString*)key withTimeoutInterval:(NSTimeInterval)timeoutInterval { 161 | CHECK_FOR_EGOCACHE_PLIST(); 162 | 163 | NSString* cachePath = cachePathForKey(key); 164 | NSInvocation* writeInvocation = [NSInvocation invocationWithMethodSignature:[self methodSignatureForSelector:@selector(writeData:toPath:)]]; 165 | [writeInvocation setTarget:self]; 166 | [writeInvocation setSelector:@selector(writeData:toPath:)]; 167 | [writeInvocation setArgument:&data atIndex:2]; 168 | [writeInvocation setArgument:&cachePath atIndex:3]; 169 | 170 | [self performDiskWriteOperation:writeInvocation]; 171 | [cacheDictionary setObject:[NSDate dateWithTimeIntervalSinceNow:timeoutInterval] forKey:key]; 172 | 173 | [self performSelectorOnMainThread:@selector(saveAfterDelay) withObject:nil waitUntilDone:YES]; // Need to make sure the save delay get scheduled in the main runloop, not the current threads 174 | } 175 | 176 | - (void)saveAfterDelay { // Prevents multiple-rapid saves from happening, which will slow down your app 177 | [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(saveCacheDictionary) object:nil]; 178 | [self performSelector:@selector(saveCacheDictionary) withObject:nil afterDelay:0.3]; 179 | } 180 | 181 | - (NSData*)dataForKey:(NSString*)key { 182 | if([self hasCacheForKey:key]) { 183 | return [NSData dataWithContentsOfFile:cachePathForKey(key) options:0 error:NULL]; 184 | } else { 185 | return nil; 186 | } 187 | } 188 | 189 | - (void)writeData:(NSData*)data toPath:(NSString *)path; { 190 | [data writeToFile:path atomically:YES]; 191 | } 192 | 193 | - (void)deleteDataAtPath:(NSString *)path { 194 | [[NSFileManager defaultManager] removeItemAtPath:path error:NULL]; 195 | } 196 | 197 | - (void)saveCacheDictionary { 198 | @synchronized(self) { 199 | [cacheDictionary writeToFile:cachePathForKey(@"EGOCache.plist") atomically:YES]; 200 | } 201 | } 202 | 203 | #pragma mark - 204 | #pragma mark String methods 205 | 206 | - (NSString*)stringForKey:(NSString*)key { 207 | return [[[NSString alloc] initWithData:[self dataForKey:key] encoding:NSUTF8StringEncoding] autorelease]; 208 | } 209 | 210 | - (void)setString:(NSString*)aString forKey:(NSString*)key { 211 | [self setString:aString forKey:key withTimeoutInterval:self.defaultTimeoutInterval]; 212 | } 213 | 214 | - (void)setString:(NSString*)aString forKey:(NSString*)key withTimeoutInterval:(NSTimeInterval)timeoutInterval { 215 | [self setData:[aString dataUsingEncoding:NSUTF8StringEncoding] forKey:key withTimeoutInterval:timeoutInterval]; 216 | } 217 | 218 | #pragma mark - 219 | #pragma mark Image methds 220 | 221 | #if TARGET_OS_IPHONE 222 | 223 | - (UIImage*)imageForKey:(NSString*)key { 224 | return [UIImage imageWithData:[self dataForKey:key]]; 225 | } 226 | 227 | - (void)setImage:(UIImage*)anImage forKey:(NSString*)key { 228 | [self setImage:anImage forKey:key withTimeoutInterval:self.defaultTimeoutInterval]; 229 | } 230 | 231 | - (void)setImage:(UIImage*)anImage forKey:(NSString*)key withTimeoutInterval:(NSTimeInterval)timeoutInterval { 232 | [self setData:UIImagePNGRepresentation(anImage) forKey:key withTimeoutInterval:timeoutInterval]; 233 | } 234 | 235 | 236 | #else 237 | 238 | - (NSImage*)imageForKey:(NSString*)key { 239 | return [[[NSImage alloc] initWithData:[self dataForKey:key]] autorelease]; 240 | } 241 | 242 | - (void)setImage:(NSImage*)anImage forKey:(NSString*)key { 243 | [self setImage:anImage forKey:key withTimeoutInterval:self.defaultTimeoutInterval]; 244 | } 245 | 246 | - (void)setImage:(NSImage*)anImage forKey:(NSString*)key withTimeoutInterval:(NSTimeInterval)timeoutInterval { 247 | [self setData:[[[anImage representations] objectAtIndex:0] representationUsingType:NSPNGFileType properties:nil] 248 | forKey:key withTimeoutInterval:timeoutInterval]; 249 | } 250 | 251 | #endif 252 | 253 | #pragma mark - 254 | #pragma mark Property List methods 255 | 256 | - (NSData*)plistForKey:(NSString*)key; { 257 | NSData* plistData = [self dataForKey:key]; 258 | 259 | return [NSPropertyListSerialization propertyListFromData:plistData 260 | mutabilityOption:NSPropertyListImmutable 261 | format:nil 262 | errorDescription:nil]; 263 | } 264 | 265 | - (void)setPlist:(id)plistObject forKey:(NSString*)key; { 266 | [self setPlist:plistObject forKey:key withTimeoutInterval:self.defaultTimeoutInterval]; 267 | } 268 | 269 | - (void)setPlist:(id)plistObject forKey:(NSString*)key withTimeoutInterval:(NSTimeInterval)timeoutInterval; { 270 | // Binary plists are used over XML for better performance 271 | NSData* plistData = [NSPropertyListSerialization dataFromPropertyList:plistObject 272 | format:NSPropertyListBinaryFormat_v1_0 273 | errorDescription:NULL]; 274 | 275 | [self setData:plistData forKey:key withTimeoutInterval:timeoutInterval]; 276 | } 277 | 278 | #pragma mark - 279 | #pragma mark Disk writing operations 280 | 281 | - (void)performDiskWriteOperation:(NSInvocation *)invoction { 282 | NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithInvocation:invoction]; 283 | [diskOperationQueue addOperation:operation]; 284 | [operation release]; 285 | } 286 | 287 | #pragma mark - 288 | 289 | - (void)dealloc { 290 | [diskOperationQueue release]; 291 | [cacheDictionary release]; 292 | [super dealloc]; 293 | } 294 | 295 | @end -------------------------------------------------------------------------------- /Demo/Libraries/EGOImageLoader/EGOImageLoadConnection.h: -------------------------------------------------------------------------------- 1 | // 2 | // EGOImageLoadConnection.h 3 | // EGOImageLoading 4 | // 5 | // Created by Shaun Harrison on 12/1/09. 6 | // Copyright (c) 2009-2010 enormego 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | // 26 | 27 | #import 28 | 29 | @protocol EGOImageLoadConnectionDelegate; 30 | 31 | @interface EGOImageLoadConnection : NSObject { 32 | @private 33 | NSURL* _imageURL; 34 | NSURLResponse* _response; 35 | NSMutableData* _responseData; 36 | NSURLConnection* _connection; 37 | NSTimeInterval _timeoutInterval; 38 | 39 | id _delegate; 40 | } 41 | 42 | - (id)initWithImageURL:(NSURL*)aURL delegate:(id)delegate; 43 | 44 | - (void)start; 45 | - (void)cancel; 46 | 47 | @property(nonatomic,readonly) NSData* responseData; 48 | @property(nonatomic,readonly,getter=imageURL) NSURL* imageURL; 49 | 50 | @property(nonatomic,retain) NSURLResponse* response; 51 | @property(nonatomic,assign) id delegate; 52 | 53 | @property(nonatomic,assign) NSTimeInterval timeoutInterval; // Default is 30 seconds 54 | 55 | @end 56 | 57 | @protocol EGOImageLoadConnectionDelegate 58 | - (void)imageLoadConnectionDidFinishLoading:(EGOImageLoadConnection *)connection; 59 | - (void)imageLoadConnection:(EGOImageLoadConnection *)connection didFailWithError:(NSError *)error; 60 | @end -------------------------------------------------------------------------------- /Demo/Libraries/EGOImageLoader/EGOImageLoadConnection.m: -------------------------------------------------------------------------------- 1 | // 2 | // EGOImageLoadConnection.m 3 | // EGOImageLoading 4 | // 5 | // Created by Shaun Harrison on 12/1/09. 6 | // Copyright (c) 2009-2010 enormego 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | // 26 | 27 | #import "EGOImageLoadConnection.h" 28 | 29 | 30 | @implementation EGOImageLoadConnection 31 | @synthesize imageURL=_imageURL, response=_response, delegate=_delegate, timeoutInterval=_timeoutInterval; 32 | 33 | - (id)initWithImageURL:(NSURL*)aURL delegate:(id)delegate { 34 | if((self = [super init])) { 35 | _imageURL = [aURL retain]; 36 | self.delegate = delegate; 37 | _responseData = [[NSMutableData alloc] init]; 38 | self.timeoutInterval = 30; 39 | } 40 | 41 | return self; 42 | } 43 | 44 | - (void)start { 45 | NSMutableURLRequest* request = [[NSMutableURLRequest alloc] initWithURL:self.imageURL 46 | cachePolicy:NSURLRequestReturnCacheDataElseLoad 47 | timeoutInterval:self.timeoutInterval]; 48 | [request setValue:@"gzip" forHTTPHeaderField:@"Accept-Encoding"]; 49 | _connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES]; 50 | [request release]; 51 | } 52 | 53 | - (void)cancel { 54 | [_connection cancel]; 55 | } 56 | 57 | - (NSData*)responseData { 58 | return _responseData; 59 | } 60 | 61 | - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { 62 | if(connection != _connection) return; 63 | [_responseData appendData:data]; 64 | } 65 | 66 | - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { 67 | if(connection != _connection) return; 68 | self.response = response; 69 | } 70 | 71 | - (void)connectionDidFinishLoading:(NSURLConnection *)connection { 72 | if(connection != _connection) return; 73 | 74 | if([self.delegate respondsToSelector:@selector(imageLoadConnectionDidFinishLoading:)]) { 75 | [self.delegate imageLoadConnectionDidFinishLoading:self]; 76 | } 77 | } 78 | 79 | - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { 80 | if(connection != _connection) return; 81 | 82 | if([self.delegate respondsToSelector:@selector(imageLoadConnection:didFailWithError:)]) { 83 | [self.delegate imageLoadConnection:self didFailWithError:error]; 84 | } 85 | } 86 | 87 | 88 | - (void)dealloc { 89 | self.response = nil; 90 | self.delegate = nil; 91 | [_connection release]; 92 | [_imageURL release]; 93 | [_responseData release]; 94 | [super dealloc]; 95 | } 96 | 97 | @end 98 | -------------------------------------------------------------------------------- /Demo/Libraries/EGOImageLoader/EGOImageLoader.h: -------------------------------------------------------------------------------- 1 | // 2 | // EGOImageLoader.h 3 | // EGOImageLoading 4 | // 5 | // Created by Shaun Harrison on 9/15/09. 6 | // Copyright (c) 2009-2010 enormego 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | // 26 | 27 | #import 28 | 29 | @protocol EGOImageLoaderObserver; 30 | @interface EGOImageLoader : NSObject/**/ { 31 | @private 32 | NSDictionary* _currentConnections; 33 | NSMutableDictionary* currentConnections; 34 | 35 | NSLock* connectionsLock; 36 | } 37 | 38 | + (EGOImageLoader*)sharedImageLoader; 39 | 40 | - (BOOL)isLoadingImageURL:(NSURL*)aURL; 41 | - (void)loadImageForURL:(NSURL*)aURL observer:(id)observer; 42 | - (UIImage*)imageForURL:(NSURL*)aURL shouldLoadWithObserver:(id)observer; 43 | - (BOOL)hasLoadedImageURL:(NSURL*)aURL; 44 | 45 | - (void)cancelLoadForURL:(NSURL*)aURL; 46 | 47 | - (void)removeObserver:(id)observer; 48 | - (void)removeObserver:(id)observer forURL:(NSURL*)aURL; 49 | 50 | @property(nonatomic,retain) NSDictionary* currentConnections; 51 | @end 52 | 53 | @protocol EGOImageLoaderObserver 54 | @optional 55 | - (void)imageLoaderDidLoad:(NSNotification*)notification; // Object will be EGOImageLoader, userInfo will contain imageURL and image 56 | - (void)imageLoaderDidFailToLoad:(NSNotification*)notification; // Object will be EGOImageLoader, userInfo will contain error 57 | @end -------------------------------------------------------------------------------- /Demo/Libraries/EGOImageLoader/EGOImageLoader.m: -------------------------------------------------------------------------------- 1 | // 2 | // EGOImageLoader.m 3 | // EGOImageLoading 4 | // 5 | // Created by Shaun Harrison on 9/15/09. 6 | // Copyright (c) 2009-2010 enormego 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | // 26 | 27 | #import "EGOImageLoader.h" 28 | #import "EGOImageLoadConnection.h" 29 | #import "EGOCache.h" 30 | 31 | static EGOImageLoader* __imageLoader; 32 | 33 | inline static NSString* keyForURL(NSURL* url) { 34 | return [NSString stringWithFormat:@"EGOImageLoader-%u", [[url description] hash]]; 35 | } 36 | 37 | #define kImageNotificationLoaded(s) [@"kEGOImageLoaderNotificationLoaded-" stringByAppendingString:keyForURL(s)] 38 | #define kImageNotificationLoadFailed(s) [@"kEGOImageLoaderNotificationLoadFailed-" stringByAppendingString:keyForURL(s)] 39 | 40 | @implementation EGOImageLoader 41 | @synthesize currentConnections=_currentConnections; 42 | 43 | + (EGOImageLoader*)sharedImageLoader { 44 | @synchronized(self) { 45 | if(!__imageLoader) { 46 | __imageLoader = [[[self class] alloc] init]; 47 | } 48 | } 49 | 50 | return __imageLoader; 51 | } 52 | 53 | - (id)init { 54 | if((self = [super init])) { 55 | connectionsLock = [[NSLock alloc] init]; 56 | currentConnections = [[NSMutableDictionary alloc] init]; 57 | } 58 | 59 | return self; 60 | } 61 | 62 | - (EGOImageLoadConnection*)loadingConnectionForURL:(NSURL*)aURL { 63 | EGOImageLoadConnection* connection = [[self.currentConnections objectForKey:aURL] retain]; 64 | if(!connection) return nil; 65 | else return [connection autorelease]; 66 | } 67 | 68 | - (void)cleanUpConnection:(EGOImageLoadConnection*)connection { 69 | if(!connection.imageURL) return; 70 | 71 | connection.delegate = nil; 72 | 73 | [connectionsLock lock]; 74 | [currentConnections removeObjectForKey:connection.imageURL]; 75 | self.currentConnections = [[currentConnections copy] autorelease]; 76 | [connectionsLock unlock]; 77 | } 78 | 79 | - (BOOL)isLoadingImageURL:(NSURL*)aURL { 80 | return [self loadingConnectionForURL:aURL] ? YES : NO; 81 | } 82 | 83 | - (void)cancelLoadForURL:(NSURL*)aURL { 84 | EGOImageLoadConnection* connection = [self loadingConnectionForURL:aURL]; 85 | [NSObject cancelPreviousPerformRequestsWithTarget:connection selector:@selector(start) object:nil]; 86 | [connection cancel]; 87 | [self cleanUpConnection:connection]; 88 | } 89 | 90 | - (void)loadImageForURL:(NSURL*)aURL observer:(id)observer { 91 | if(!aURL) return; 92 | 93 | if([observer respondsToSelector:@selector(imageLoaderDidLoad:)]) { 94 | [[NSNotificationCenter defaultCenter] addObserver:observer selector:@selector(imageLoaderDidLoad:) name:kImageNotificationLoaded(aURL) object:self]; 95 | } 96 | 97 | if([observer respondsToSelector:@selector(imageLoaderDidFailToLoad:)]) { 98 | [[NSNotificationCenter defaultCenter] addObserver:observer selector:@selector(imageLoaderDidFailToLoad:) name:kImageNotificationLoadFailed(aURL) object:self]; 99 | } 100 | 101 | if([self loadingConnectionForURL:aURL]) { 102 | return; 103 | } 104 | 105 | EGOImageLoadConnection* connection = [[EGOImageLoadConnection alloc] initWithImageURL:aURL delegate:self]; 106 | 107 | [connectionsLock lock]; 108 | [currentConnections setObject:connection forKey:aURL]; 109 | self.currentConnections = [[currentConnections copy] autorelease]; 110 | [connectionsLock unlock]; 111 | [connection performSelector:@selector(start) withObject:nil afterDelay:0.01]; 112 | [connection release]; 113 | } 114 | 115 | - (UIImage*)imageForURL:(NSURL*)aURL shouldLoadWithObserver:(id)observer { 116 | if(!aURL) return nil; 117 | 118 | UIImage* anImage = [[EGOCache currentCache] imageForKey:keyForURL(aURL)]; 119 | 120 | if(anImage) { 121 | return anImage; 122 | } else { 123 | [self loadImageForURL:(NSURL*)aURL observer:observer]; 124 | return nil; 125 | } 126 | } 127 | 128 | - (BOOL)hasLoadedImageURL:(NSURL*)aURL { 129 | return [[EGOCache currentCache] hasCacheForKey:keyForURL(aURL)]; 130 | } 131 | 132 | - (void)removeObserver:(id)observer { 133 | [[NSNotificationCenter defaultCenter] removeObserver:observer name:nil object:self]; 134 | } 135 | 136 | - (void)removeObserver:(id)observer forURL:(NSURL*)aURL { 137 | [[NSNotificationCenter defaultCenter] removeObserver:observer name:kImageNotificationLoaded(aURL) object:self]; 138 | [[NSNotificationCenter defaultCenter] removeObserver:observer name:kImageNotificationLoadFailed(aURL) object:self]; 139 | } 140 | 141 | #pragma mark - 142 | #pragma mark URL Connection delegate methods 143 | 144 | - (void)imageLoadConnectionDidFinishLoading:(EGOImageLoadConnection *)connection { 145 | UIImage* anImage = [UIImage imageWithData:connection.responseData]; 146 | 147 | if(!anImage) { 148 | NSError* error = [NSError errorWithDomain:[connection.imageURL host] code:406 userInfo:nil]; 149 | NSNotification* notification = [NSNotification notificationWithName:kImageNotificationLoadFailed(connection.imageURL) 150 | object:self 151 | userInfo:[NSDictionary dictionaryWithObjectsAndKeys:error,@"error",connection.imageURL,@"imageURL",nil]]; 152 | 153 | [[NSNotificationCenter defaultCenter] performSelectorOnMainThread:@selector(postNotification:) withObject:notification waitUntilDone:YES]; 154 | } else { 155 | [[EGOCache currentCache] setData:connection.responseData forKey:keyForURL(connection.imageURL) withTimeoutInterval:604800]; 156 | 157 | [currentConnections removeObjectForKey:connection.imageURL]; 158 | self.currentConnections = [[currentConnections copy] autorelease]; 159 | 160 | NSNotification* notification = [NSNotification notificationWithName:kImageNotificationLoaded(connection.imageURL) 161 | object:self 162 | userInfo:[NSDictionary dictionaryWithObjectsAndKeys:anImage,@"image",connection.imageURL,@"imageURL",nil]]; 163 | 164 | [[NSNotificationCenter defaultCenter] performSelectorOnMainThread:@selector(postNotification:) withObject:notification waitUntilDone:YES]; 165 | } 166 | 167 | [self cleanUpConnection:connection]; 168 | } 169 | 170 | - (void)imageLoadConnection:(EGOImageLoadConnection *)connection didFailWithError:(NSError *)error { 171 | [currentConnections removeObjectForKey:connection.imageURL]; 172 | self.currentConnections = [[currentConnections copy] autorelease]; 173 | 174 | NSNotification* notification = [NSNotification notificationWithName:kImageNotificationLoadFailed(connection.imageURL) 175 | object:self 176 | userInfo:[NSDictionary dictionaryWithObjectsAndKeys:error,@"error",connection.imageURL,@"imageURL",nil]]; 177 | 178 | [[NSNotificationCenter defaultCenter] performSelectorOnMainThread:@selector(postNotification:) withObject:notification waitUntilDone:YES]; 179 | 180 | [self cleanUpConnection:connection]; 181 | } 182 | 183 | #pragma mark - 184 | 185 | - (void)dealloc { 186 | self.currentConnections = nil; 187 | [currentConnections release]; 188 | [connectionsLock release]; 189 | [super dealloc]; 190 | } 191 | 192 | @end -------------------------------------------------------------------------------- /Demo/MainWindow.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1024 5 | 10D573 6 | 788 7 | 1038.29 8 | 460.00 9 | 10 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 11 | 117 12 | 13 | 14 | 15 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 16 | 17 | 18 | 19 | 20 | IBFilesOwner 21 | IBIPadFramework 22 | 23 | 24 | IBFirstResponder 25 | IBIPadFramework 26 | 27 | 28 | 29 | 292 30 | {768, 1024} 31 | 32 | 1 33 | MSAxIDEAA 34 | 35 | NO 36 | NO 37 | 38 | 2 39 | 40 | IBIPadFramework 41 | YES 42 | 43 | 44 | IBIPadFramework 45 | 46 | 47 | 48 | 49 | 2 50 | 51 | 52 | 3 53 | 54 | IBIPadFramework 55 | YES 56 | 57 | 58 | 59 | 2 60 | 61 | 62 | 1 63 | 64 | IBIPadFramework 65 | NO 66 | 67 | 68 | 256 69 | {0, 0} 70 | YES 71 | YES 72 | IBIPadFramework 73 | 74 | 75 | 76 | 77 | Root View Controller 78 | IBIPadFramework 79 | 80 | 81 | 82 | 2 83 | 84 | 85 | 1 86 | 87 | IBIPadFramework 88 | NO 89 | 90 | 91 | 92 | 93 | 94 | 95 | DetailView 96 | 97 | 1 98 | 99 | IBIPadFramework 100 | NO 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | window 109 | 110 | 111 | 112 | 4 113 | 114 | 115 | 116 | delegate 117 | 118 | 119 | 120 | 17 121 | 122 | 123 | 124 | splitViewController 125 | 126 | 127 | 128 | 43 129 | 130 | 131 | 132 | rootViewController 133 | 134 | 135 | 136 | 44 137 | 138 | 139 | 140 | detailViewController 141 | 142 | 143 | 144 | 45 145 | 146 | 147 | 148 | detailViewController 149 | 150 | 151 | 152 | 46 153 | 154 | 155 | 156 | delegate 157 | 158 | 159 | 160 | 49 161 | 162 | 163 | 164 | 165 | 166 | 0 167 | 168 | 169 | 170 | 171 | 172 | -1 173 | 174 | 175 | File's Owner 176 | 177 | 178 | -2 179 | 180 | 181 | 182 | 183 | 2 184 | 185 | 186 | 187 | 188 | 3 189 | 190 | 191 | 192 | 193 | 37 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 38 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 39 212 | 213 | 214 | 215 | 216 | 40 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 41 225 | 226 | 227 | 228 | 229 | 42 230 | 231 | 232 | 233 | 234 | 235 | 236 | UIApplication 237 | UIResponder 238 | {{190, 57}, {783, 799}} 239 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 240 | EGOPhotoViewer_DemoAppDelegate 241 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 242 | {{794, 594}, {1024, 768}} 243 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 244 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 245 | DetailViewController 246 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 247 | RootViewController 248 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 249 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 250 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 251 | 252 | 253 | 254 | 255 | 256 | 49 257 | 258 | 259 | 260 | 261 | DetailViewController 262 | UIViewController 263 | 264 | UILabel 265 | id 266 | UIToolbar 267 | 268 | 269 | 270 | detailDescriptionLabel 271 | UILabel 272 | 273 | 274 | detailItem 275 | id 276 | 277 | 278 | toolbar 279 | UIToolbar 280 | 281 | 282 | 283 | IBProjectSource 284 | Classes/DetailViewController.h 285 | 286 | 287 | 288 | EGOPhotoViewer_DemoAppDelegate 289 | NSObject 290 | 291 | DetailViewController 292 | UIViewController 293 | RootViewController_iPhone 294 | UISplitViewController 295 | UIWindow 296 | 297 | 298 | 299 | detailViewController 300 | DetailViewController 301 | 302 | 303 | rootViewController 304 | UIViewController 305 | 306 | 307 | rootViewController_iPhone 308 | RootViewController_iPhone 309 | 310 | 311 | splitViewController 312 | UISplitViewController 313 | 314 | 315 | window 316 | UIWindow 317 | 318 | 319 | 320 | IBProjectSource 321 | Classes/EGOPhotoViewer_DemoAppDelegate.h 322 | 323 | 324 | 325 | RootViewController 326 | UITableViewController 327 | 328 | detailViewController 329 | DetailViewController 330 | 331 | 332 | detailViewController 333 | 334 | detailViewController 335 | DetailViewController 336 | 337 | 338 | 339 | IBProjectSource 340 | Classes/RootViewController.h 341 | 342 | 343 | 344 | RootViewController 345 | UITableViewController 346 | 347 | IBUserSource 348 | 349 | 350 | 351 | 352 | RootViewController_iPhone 353 | UITableViewController 354 | 355 | IBProjectSource 356 | Classes/iPhone_Controller/RootViewController_iPhone.h 357 | 358 | 359 | 360 | 361 | 362 | NSObject 363 | 364 | IBFrameworkSource 365 | Foundation.framework/Headers/NSError.h 366 | 367 | 368 | 369 | NSObject 370 | 371 | IBFrameworkSource 372 | Foundation.framework/Headers/NSFileManager.h 373 | 374 | 375 | 376 | NSObject 377 | 378 | IBFrameworkSource 379 | Foundation.framework/Headers/NSKeyValueCoding.h 380 | 381 | 382 | 383 | NSObject 384 | 385 | IBFrameworkSource 386 | Foundation.framework/Headers/NSKeyValueObserving.h 387 | 388 | 389 | 390 | NSObject 391 | 392 | IBFrameworkSource 393 | Foundation.framework/Headers/NSKeyedArchiver.h 394 | 395 | 396 | 397 | NSObject 398 | 399 | IBFrameworkSource 400 | Foundation.framework/Headers/NSObject.h 401 | 402 | 403 | 404 | NSObject 405 | 406 | IBFrameworkSource 407 | Foundation.framework/Headers/NSRunLoop.h 408 | 409 | 410 | 411 | NSObject 412 | 413 | IBFrameworkSource 414 | Foundation.framework/Headers/NSThread.h 415 | 416 | 417 | 418 | NSObject 419 | 420 | IBFrameworkSource 421 | Foundation.framework/Headers/NSURL.h 422 | 423 | 424 | 425 | NSObject 426 | 427 | IBFrameworkSource 428 | Foundation.framework/Headers/NSURLConnection.h 429 | 430 | 431 | 432 | NSObject 433 | 434 | IBFrameworkSource 435 | QuartzCore.framework/Headers/CAAnimation.h 436 | 437 | 438 | 439 | NSObject 440 | 441 | IBFrameworkSource 442 | QuartzCore.framework/Headers/CALayer.h 443 | 444 | 445 | 446 | NSObject 447 | 448 | IBFrameworkSource 449 | UIKit.framework/Headers/UIAccessibility.h 450 | 451 | 452 | 453 | NSObject 454 | 455 | IBFrameworkSource 456 | UIKit.framework/Headers/UINibLoading.h 457 | 458 | 459 | 460 | NSObject 461 | 462 | IBFrameworkSource 463 | UIKit.framework/Headers/UIResponder.h 464 | 465 | 466 | 467 | UIApplication 468 | UIResponder 469 | 470 | IBFrameworkSource 471 | UIKit.framework/Headers/UIApplication.h 472 | 473 | 474 | 475 | UIBarButtonItem 476 | UIBarItem 477 | 478 | IBFrameworkSource 479 | UIKit.framework/Headers/UIBarButtonItem.h 480 | 481 | 482 | 483 | UIBarItem 484 | NSObject 485 | 486 | IBFrameworkSource 487 | UIKit.framework/Headers/UIBarItem.h 488 | 489 | 490 | 491 | UILabel 492 | UIView 493 | 494 | IBFrameworkSource 495 | UIKit.framework/Headers/UILabel.h 496 | 497 | 498 | 499 | UINavigationBar 500 | UIView 501 | 502 | IBFrameworkSource 503 | UIKit.framework/Headers/UINavigationBar.h 504 | 505 | 506 | 507 | UINavigationController 508 | UIViewController 509 | 510 | IBFrameworkSource 511 | UIKit.framework/Headers/UINavigationController.h 512 | 513 | 514 | 515 | UINavigationItem 516 | NSObject 517 | 518 | 519 | 520 | UIResponder 521 | NSObject 522 | 523 | 524 | 525 | UISearchBar 526 | UIView 527 | 528 | IBFrameworkSource 529 | UIKit.framework/Headers/UISearchBar.h 530 | 531 | 532 | 533 | UISearchDisplayController 534 | NSObject 535 | 536 | IBFrameworkSource 537 | UIKit.framework/Headers/UISearchDisplayController.h 538 | 539 | 540 | 541 | UISplitViewController 542 | UIViewController 543 | 544 | IBFrameworkSource 545 | UIKit.framework/Headers/UISplitViewController.h 546 | 547 | 548 | 549 | UITableViewController 550 | UIViewController 551 | 552 | IBFrameworkSource 553 | UIKit.framework/Headers/UITableViewController.h 554 | 555 | 556 | 557 | UIToolbar 558 | UIView 559 | 560 | IBFrameworkSource 561 | UIKit.framework/Headers/UIToolbar.h 562 | 563 | 564 | 565 | UIView 566 | 567 | IBFrameworkSource 568 | UIKit.framework/Headers/UITextField.h 569 | 570 | 571 | 572 | UIView 573 | UIResponder 574 | 575 | IBFrameworkSource 576 | UIKit.framework/Headers/UIView.h 577 | 578 | 579 | 580 | UIViewController 581 | 582 | 583 | 584 | UIViewController 585 | 586 | IBFrameworkSource 587 | UIKit.framework/Headers/UIPopoverController.h 588 | 589 | 590 | 591 | UIViewController 592 | 593 | 594 | 595 | UIViewController 596 | 597 | IBFrameworkSource 598 | UIKit.framework/Headers/UITabBarController.h 599 | 600 | 601 | 602 | UIViewController 603 | UIResponder 604 | 605 | IBFrameworkSource 606 | UIKit.framework/Headers/UIViewController.h 607 | 608 | 609 | 610 | UIWindow 611 | UIView 612 | 613 | IBFrameworkSource 614 | UIKit.framework/Headers/UIWindow.h 615 | 616 | 617 | 618 | 619 | 0 620 | IBIPadFramework 621 | 622 | com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS 623 | 624 | 625 | 626 | com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 627 | 628 | 629 | YES 630 | EGOPhotoViewer_Demo.xcodeproj 631 | 3 632 | 117 633 | 634 | 635 | -------------------------------------------------------------------------------- /Demo/MainWindowiPhone.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1024 5 | 10D573 6 | 788 7 | 1038.29 8 | 460.00 9 | 10 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 11 | 117 12 | 13 | 14 | YES 15 | 16 | 17 | 18 | YES 19 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 20 | 21 | 22 | YES 23 | 24 | YES 25 | 26 | 27 | YES 28 | 29 | 30 | 31 | YES 32 | 33 | IBFilesOwner 34 | IBCocoaTouchFramework 35 | 36 | 37 | IBFirstResponder 38 | IBCocoaTouchFramework 39 | 40 | 41 | 42 | 1316 43 | 44 | {320, 480} 45 | 46 | 47 | 1 48 | MSAxIDEAA 49 | 50 | NO 51 | NO 52 | 53 | IBCocoaTouchFramework 54 | YES 55 | 56 | 57 | IBCocoaTouchFramework 58 | 59 | 60 | 61 | Item 62 | IBCocoaTouchFramework 63 | 64 | RootViewController_iPhone 65 | 66 | 67 | 1 68 | 69 | IBCocoaTouchFramework 70 | NO 71 | 72 | 73 | 74 | 75 | YES 76 | 77 | 78 | window 79 | 80 | 81 | 82 | 7 83 | 84 | 85 | 86 | rootViewController_iPhone 87 | 88 | 89 | 90 | 10 91 | 92 | 93 | 94 | delegate 95 | 96 | 97 | 98 | 11 99 | 100 | 101 | 102 | 103 | YES 104 | 105 | 0 106 | 107 | 108 | 109 | 110 | 111 | 2 112 | 113 | 114 | 115 | 116 | -1 117 | 118 | 119 | File's Owner 120 | 121 | 122 | -2 123 | 124 | 125 | 126 | 127 | 6 128 | 129 | 130 | 131 | 132 | 4 133 | 134 | 135 | YES 136 | 137 | 138 | 139 | 140 | 141 | 16 142 | 143 | 144 | 145 | 146 | 147 | 148 | YES 149 | 150 | YES 151 | -1.CustomClassName 152 | -2.CustomClassName 153 | 2.IBAttributePlaceholdersKey 154 | 2.IBEditorWindowLastContentRect 155 | 2.IBPluginDependency 156 | 2.UIWindow.visibleAtLaunch 157 | 4.CustomClassName 158 | 4.IBEditorWindowLastContentRect 159 | 4.IBPluginDependency 160 | 6.CustomClassName 161 | 6.IBPluginDependency 162 | 163 | 164 | YES 165 | UIApplication 166 | UIResponder 167 | 168 | YES 169 | 170 | 171 | YES 172 | 173 | 174 | {{341, 276}, {320, 480}} 175 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 176 | 177 | RootViewController_iPhone 178 | {{0, 265}, {320, 480}} 179 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 180 | EGOPhotoViewer_DemoAppDelegate 181 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 182 | 183 | 184 | 185 | YES 186 | 187 | 188 | YES 189 | 190 | 191 | 192 | 193 | YES 194 | 195 | 196 | YES 197 | 198 | 199 | 200 | 16 201 | 202 | 203 | 204 | YES 205 | 206 | DetailViewController 207 | UIViewController 208 | 209 | YES 210 | 211 | YES 212 | detailDescriptionLabel 213 | detailItem 214 | toolbar 215 | 216 | 217 | YES 218 | UILabel 219 | id 220 | UIToolbar 221 | 222 | 223 | 224 | YES 225 | 226 | YES 227 | detailDescriptionLabel 228 | detailItem 229 | toolbar 230 | 231 | 232 | YES 233 | 234 | detailDescriptionLabel 235 | UILabel 236 | 237 | 238 | detailItem 239 | id 240 | 241 | 242 | toolbar 243 | UIToolbar 244 | 245 | 246 | 247 | 248 | IBProjectSource 249 | Classes/DetailViewController.h 250 | 251 | 252 | 253 | EGOPhotoViewer_DemoAppDelegate 254 | NSObject 255 | 256 | YES 257 | 258 | YES 259 | detailViewController 260 | rootViewController 261 | rootViewController_iPhone 262 | splitViewController 263 | window 264 | 265 | 266 | YES 267 | DetailViewController 268 | UIViewController 269 | RootViewController_iPhone 270 | UISplitViewController 271 | UIWindow 272 | 273 | 274 | 275 | YES 276 | 277 | YES 278 | detailViewController 279 | rootViewController 280 | rootViewController_iPhone 281 | splitViewController 282 | window 283 | 284 | 285 | YES 286 | 287 | detailViewController 288 | DetailViewController 289 | 290 | 291 | rootViewController 292 | UIViewController 293 | 294 | 295 | rootViewController_iPhone 296 | RootViewController_iPhone 297 | 298 | 299 | splitViewController 300 | UISplitViewController 301 | 302 | 303 | window 304 | UIWindow 305 | 306 | 307 | 308 | 309 | IBProjectSource 310 | Classes/EGOPhotoViewer_DemoAppDelegate.h 311 | 312 | 313 | 314 | RootViewController_iPhone 315 | UITableViewController 316 | 317 | IBProjectSource 318 | Classes/iPhone_Controller/RootViewController_iPhone.h 319 | 320 | 321 | 322 | 323 | YES 324 | 325 | NSObject 326 | 327 | IBFrameworkSource 328 | Foundation.framework/Headers/NSError.h 329 | 330 | 331 | 332 | NSObject 333 | 334 | IBFrameworkSource 335 | Foundation.framework/Headers/NSFileManager.h 336 | 337 | 338 | 339 | NSObject 340 | 341 | IBFrameworkSource 342 | Foundation.framework/Headers/NSKeyValueCoding.h 343 | 344 | 345 | 346 | NSObject 347 | 348 | IBFrameworkSource 349 | Foundation.framework/Headers/NSKeyValueObserving.h 350 | 351 | 352 | 353 | NSObject 354 | 355 | IBFrameworkSource 356 | Foundation.framework/Headers/NSKeyedArchiver.h 357 | 358 | 359 | 360 | NSObject 361 | 362 | IBFrameworkSource 363 | Foundation.framework/Headers/NSObject.h 364 | 365 | 366 | 367 | NSObject 368 | 369 | IBFrameworkSource 370 | Foundation.framework/Headers/NSRunLoop.h 371 | 372 | 373 | 374 | NSObject 375 | 376 | IBFrameworkSource 377 | Foundation.framework/Headers/NSThread.h 378 | 379 | 380 | 381 | NSObject 382 | 383 | IBFrameworkSource 384 | Foundation.framework/Headers/NSURL.h 385 | 386 | 387 | 388 | NSObject 389 | 390 | IBFrameworkSource 391 | Foundation.framework/Headers/NSURLConnection.h 392 | 393 | 394 | 395 | NSObject 396 | 397 | IBFrameworkSource 398 | QuartzCore.framework/Headers/CAAnimation.h 399 | 400 | 401 | 402 | NSObject 403 | 404 | IBFrameworkSource 405 | QuartzCore.framework/Headers/CALayer.h 406 | 407 | 408 | 409 | NSObject 410 | 411 | IBFrameworkSource 412 | UIKit.framework/Headers/UIAccessibility.h 413 | 414 | 415 | 416 | NSObject 417 | 418 | IBFrameworkSource 419 | UIKit.framework/Headers/UINibLoading.h 420 | 421 | 422 | 423 | NSObject 424 | 425 | IBFrameworkSource 426 | UIKit.framework/Headers/UIResponder.h 427 | 428 | 429 | 430 | UIApplication 431 | UIResponder 432 | 433 | IBFrameworkSource 434 | UIKit.framework/Headers/UIApplication.h 435 | 436 | 437 | 438 | UIBarButtonItem 439 | UIBarItem 440 | 441 | IBFrameworkSource 442 | UIKit.framework/Headers/UIBarButtonItem.h 443 | 444 | 445 | 446 | UIBarItem 447 | NSObject 448 | 449 | IBFrameworkSource 450 | UIKit.framework/Headers/UIBarItem.h 451 | 452 | 453 | 454 | UILabel 455 | UIView 456 | 457 | IBFrameworkSource 458 | UIKit.framework/Headers/UILabel.h 459 | 460 | 461 | 462 | UINavigationItem 463 | NSObject 464 | 465 | IBFrameworkSource 466 | UIKit.framework/Headers/UINavigationBar.h 467 | 468 | 469 | 470 | UIResponder 471 | NSObject 472 | 473 | 474 | 475 | UISearchBar 476 | UIView 477 | 478 | IBFrameworkSource 479 | UIKit.framework/Headers/UISearchBar.h 480 | 481 | 482 | 483 | UISearchDisplayController 484 | NSObject 485 | 486 | IBFrameworkSource 487 | UIKit.framework/Headers/UISearchDisplayController.h 488 | 489 | 490 | 491 | UISplitViewController 492 | UIViewController 493 | 494 | IBFrameworkSource 495 | UIKit.framework/Headers/UISplitViewController.h 496 | 497 | 498 | 499 | UITableViewController 500 | UIViewController 501 | 502 | IBFrameworkSource 503 | UIKit.framework/Headers/UITableViewController.h 504 | 505 | 506 | 507 | UIToolbar 508 | UIView 509 | 510 | IBFrameworkSource 511 | UIKit.framework/Headers/UIToolbar.h 512 | 513 | 514 | 515 | UIView 516 | 517 | IBFrameworkSource 518 | UIKit.framework/Headers/UITextField.h 519 | 520 | 521 | 522 | UIView 523 | UIResponder 524 | 525 | IBFrameworkSource 526 | UIKit.framework/Headers/UIView.h 527 | 528 | 529 | 530 | UIViewController 531 | 532 | IBFrameworkSource 533 | UIKit.framework/Headers/UINavigationController.h 534 | 535 | 536 | 537 | UIViewController 538 | 539 | IBFrameworkSource 540 | UIKit.framework/Headers/UIPopoverController.h 541 | 542 | 543 | 544 | UIViewController 545 | 546 | 547 | 548 | UIViewController 549 | 550 | IBFrameworkSource 551 | UIKit.framework/Headers/UITabBarController.h 552 | 553 | 554 | 555 | UIViewController 556 | UIResponder 557 | 558 | IBFrameworkSource 559 | UIKit.framework/Headers/UIViewController.h 560 | 561 | 562 | 563 | UIWindow 564 | UIView 565 | 566 | IBFrameworkSource 567 | UIKit.framework/Headers/UIWindow.h 568 | 569 | 570 | 571 | 572 | 0 573 | IBCocoaTouchFramework 574 | 575 | com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS 576 | 577 | 578 | 579 | com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 580 | 581 | 582 | YES 583 | EGOPhotoViewer_Demo.xcodeproj 584 | 3 585 | 117 586 | 587 | 588 | -------------------------------------------------------------------------------- /Demo/local_image_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enormego/PhotoViewer/54f84c971bd9a8188f8913f48dc3cab26ae61d39/Demo/local_image_1.jpg -------------------------------------------------------------------------------- /Demo/local_image_2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enormego/PhotoViewer/54f84c971bd9a8188f8913f48dc3cab26ae61d39/Demo/local_image_2.jpg -------------------------------------------------------------------------------- /Demo/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // EGOPhotoViewer_Demo 4 | // 5 | // Created by Devin Doty on 7/3/10July3. 6 | // Copyright __MyCompanyName__ 2010. 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 | -------------------------------------------------------------------------------- /Demo/photosButton.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enormego/PhotoViewer/54f84c971bd9a8188f8913f48dc3cab26ae61d39/Demo/photosButton.png -------------------------------------------------------------------------------- /EGOPhotoViewer/Controller/EGOPhotoViewController/EGOPhotoViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // EGOPhotoController.h 3 | // EGOPhotoViewer 4 | // 5 | // Created by Devin Doty on 1/8/10. 6 | // Copyright 2010 enormego. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | // 26 | 27 | #import 28 | #import "EGOPhotoSource.h" 29 | #import "EGOPhotoGlobal.h" 30 | 31 | @class EGOPhotoImageView, EGOPhotoCaptionView; 32 | @interface EGOPhotoViewController : UIViewController { 33 | @private 34 | id _photoSource; 35 | EGOPhotoCaptionView *_captionView; 36 | NSMutableArray *_photoViews; 37 | UIScrollView *_scrollView; 38 | 39 | NSInteger _pageIndex; 40 | BOOL _rotating; 41 | BOOL _barsHidden; 42 | 43 | UIBarButtonItem *_leftButton; 44 | UIBarButtonItem *_rightButton; 45 | UIBarButtonItem *_actionButton; 46 | 47 | BOOL _storedOldStyles; 48 | UIStatusBarStyle _oldStatusBarSyle; 49 | UIBarStyle _oldNavBarStyle; 50 | BOOL _oldNavBarTranslucent; 51 | UIColor* _oldNavBarTintColor; 52 | UIBarStyle _oldToolBarStyle; 53 | BOOL _oldToolBarTranslucent; 54 | UIColor* _oldToolBarTintColor; 55 | BOOL _oldToolBarHidden; 56 | 57 | BOOL _autoresizedPopover; 58 | id _popover; 59 | 60 | BOOL _fullScreen; 61 | BOOL _fromPopover; 62 | UIView *_popoverOverlay; 63 | UIView *_transferView; 64 | 65 | } 66 | 67 | - (id)initWithPhoto:(id)aPhoto; 68 | 69 | - (id)initWithImage:(UIImage*)anImage; 70 | - (id)initWithImageURL:(NSURL*)anImageURL; 71 | 72 | - (id)initWithPhotoSource:(id )aPhotoSource; 73 | - (id)initWithPopoverController:(id)aPopoverController photoSource:(id )aPhotoSource; 74 | 75 | @property(nonatomic,readonly) id photoSource; 76 | @property(nonatomic,retain) NSMutableArray *photoViews; 77 | @property(nonatomic,retain) UIScrollView *scrollView; 78 | @property(nonatomic,assign) BOOL _fromPopover; 79 | 80 | - (NSInteger)currentPhotoIndex; 81 | - (void)moveToPhotoAtIndex:(NSInteger)index animated:(BOOL)animated; 82 | 83 | @end -------------------------------------------------------------------------------- /EGOPhotoViewer/EGOPhotoGlobal.h: -------------------------------------------------------------------------------- 1 | // 2 | // EGOPhotoGlobal.h 3 | // EGOPhotoViewer 4 | // 5 | // Created by Devin Doty on 7/3/10. 6 | // Copyright 2010 enormego. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | // 26 | 27 | // Frameworks 28 | #import 29 | #import 30 | #import 31 | 32 | // Controller 33 | #import "EGOPhotoViewController.h" 34 | 35 | // Views 36 | #import "EGOPhotoScrollView.h" 37 | #import "EGOPhotoImageView.h" 38 | #import "EGOPhotoCaptionView.h" 39 | 40 | // Model 41 | #import "EGOPhotoSource.h" 42 | #import "EGOQuickPhoto.h" 43 | #import "EGOQuickPhotoSource.h" 44 | 45 | // Loading and Disk I/O 46 | #import "EGOImageLoadConnection.h" 47 | #import "EGOImageLoader.h" 48 | #import "EGOCache.h" 49 | 50 | // Definitions used interally. 51 | // ifndef checks are so you can easily override them in your project. 52 | #ifndef kEGOPhotoErrorPlaceholder 53 | #define kEGOPhotoErrorPlaceholder [UIImage imageNamed:@"egopv_error_placeholder.png"] 54 | #endif 55 | 56 | #ifndef kEGOPhotoLoadingPlaceholder 57 | #define kEGOPhotoLoadingPlaceholder [UIImage imageNamed:@"egopv_photo_placeholder.png"] 58 | #endif 59 | 60 | #ifndef EGOPV_IMAGE_GAP 61 | #define EGOPV_IMAGE_GAP 30 62 | #endif 63 | 64 | #ifndef EGOPV_ZOOM_SCALE 65 | #define EGOPV_ZOOM_SCALE 2.5 66 | #endif 67 | 68 | #ifndef EGOPV_MAX_POPOVER_SIZE 69 | #define EGOPV_MAX_POPOVER_SIZE CGSizeMake(480.0f, 480.0f) 70 | #endif 71 | 72 | #ifndef EGOPV_MIN_POPOVER_SIZE 73 | #define EGOPV_MIN_POPOVER_SIZE CGSizeMake(320.0f, 320.0f) 74 | #endif -------------------------------------------------------------------------------- /EGOPhotoViewer/Model/EGOPhotoSource/EGOPhotoSource.h: -------------------------------------------------------------------------------- 1 | // 2 | // EGOPhotoSource.h 3 | // EGOPhotoViewer 4 | // 5 | // Created by Devin Doty on 7/3/10. 6 | // Copyright 2010 enormego. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | // 26 | 27 | #pragma mark EGOPhotoSource 28 | 29 | @protocol EGOPhotoSource 30 | 31 | /* 32 | * Array containing photo data objects. 33 | */ 34 | @property(nonatomic,readonly,retain) NSArray *photos; 35 | 36 | /* 37 | * Number of photos. 38 | */ 39 | @property(nonatomic,readonly) NSInteger numberOfPhotos; 40 | 41 | /* 42 | * Should return a photo from the photos array, at the index passed. 43 | */ 44 | - (id)photoAtIndex:(NSInteger)index; 45 | 46 | @end 47 | 48 | 49 | #pragma mark - 50 | #pragma mark EGOPhoto 51 | 52 | @protocol EGOPhoto 53 | 54 | /* 55 | * URL of the image, varied URL size should set according to display size. 56 | */ 57 | @property(nonatomic,readonly,retain) NSURL *URL; 58 | 59 | /* 60 | * The caption of the image. 61 | */ 62 | @property(nonatomic,readonly,retain) NSString *caption; 63 | 64 | /* 65 | * Size of the image, CGRectZero if image is nil. 66 | */ 67 | @property(nonatomic) CGSize size; 68 | 69 | /* 70 | * The image after being loaded, or local. 71 | */ 72 | @property(nonatomic,retain) UIImage *image; 73 | 74 | /* 75 | * Returns true if the image failed to load. 76 | */ 77 | @property(nonatomic,assign,getter=didFail) BOOL failed; 78 | 79 | 80 | @end 81 | -------------------------------------------------------------------------------- /EGOPhotoViewer/Model/EGOQuickPhoto/EGOQuickPhoto.h: -------------------------------------------------------------------------------- 1 | // 2 | // EGOQuickPhoto.h 3 | // EGOPhotoViewer 4 | // 5 | // Created by Devin Doty on 7/3/10. 6 | // Copyright 2010 enormego. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | // 26 | 27 | #import 28 | #import "EGOPhotoGlobal.h" 29 | 30 | 31 | @interface EGOQuickPhoto : NSObject { 32 | @private 33 | NSURL *_URL; 34 | NSString *_caption; 35 | CGSize _size; 36 | UIImage *_image; 37 | 38 | BOOL _failed; 39 | } 40 | 41 | - (id)initWithImageURL:(NSURL*)aURL name:(NSString*)aName image:(UIImage*)aImage; 42 | - (id)initWithImageURL:(NSURL*)aURL name:(NSString*)aName; 43 | - (id)initWithImageURL:(NSURL*)aURL; 44 | - (id)initWithImage:(UIImage*)aImage; 45 | 46 | @end 47 | -------------------------------------------------------------------------------- /EGOPhotoViewer/Model/EGOQuickPhoto/EGOQuickPhoto.m: -------------------------------------------------------------------------------- 1 | // 2 | // EGOQuickPhoto.m 3 | // EGOPhotoViewer 4 | // 5 | // Created by Devin Doty on 7/3/10. 6 | // Copyright 2010 enormego. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | // 26 | 27 | #import "EGOQuickPhoto.h" 28 | 29 | @implementation EGOQuickPhoto 30 | @synthesize URL=_URL, caption=_caption, image=_image, size=_size, failed=_failed; 31 | 32 | - (id)initWithImageURL:(NSURL*)aURL name:(NSString*)aName image:(UIImage*)aImage { 33 | if (self = [super init]) { 34 | _URL = [aURL retain]; 35 | _caption = [aName retain]; 36 | _image = [aImage retain]; 37 | 38 | } 39 | 40 | return self; 41 | } 42 | 43 | - (id)initWithImageURL:(NSURL*)aURL name:(NSString*)aName { 44 | return [self initWithImageURL:aURL name:aName image:nil]; 45 | } 46 | 47 | - (id)initWithImageURL:(NSURL*)aURL { 48 | return [self initWithImageURL:aURL name:nil image:nil]; 49 | } 50 | 51 | - (id)initWithImage:(UIImage*)aImage { 52 | return [self initWithImageURL:nil name:nil image:aImage]; 53 | } 54 | 55 | - (void)dealloc { 56 | [_URL release], _URL=nil; 57 | [_image release], _image=nil; 58 | [_caption release], _caption=nil; 59 | 60 | [super dealloc]; 61 | } 62 | 63 | @end 64 | -------------------------------------------------------------------------------- /EGOPhotoViewer/Model/EGOQuickPhoto/EGOQuickPhotoSource.h: -------------------------------------------------------------------------------- 1 | // 2 | // EGOQuickPhotoSource.h 3 | // EGOPhotoViewer 4 | // 5 | // Created by Devin Doty on 7/3/10. 6 | // Copyright 2010 enormego. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | // 26 | 27 | #import 28 | #import "EGOPhotoGlobal.h" 29 | 30 | @interface EGOQuickPhotoSource : NSObject { 31 | @private 32 | NSArray* _photos; 33 | NSInteger _numberOfPhotos; 34 | } 35 | 36 | - (id)initWithPhotos:(NSArray*)photos; 37 | 38 | @end 39 | -------------------------------------------------------------------------------- /EGOPhotoViewer/Model/EGOQuickPhoto/EGOQuickPhotoSource.m: -------------------------------------------------------------------------------- 1 | // 2 | // EGOQuickPhotoSource.m 3 | // EGOPhotoViewer 4 | // 5 | // Created by Devin Doty on 7/3/10. 6 | // Copyright 2010 enormego. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | // 26 | 27 | #import "EGOQuickPhotoSource.h" 28 | 29 | 30 | @implementation EGOQuickPhotoSource 31 | @synthesize photos=_photos, numberOfPhotos=_numberOfPhotos; 32 | 33 | 34 | - (id)initWithPhotos:(NSArray*)photos { 35 | if (self = [super init]) { 36 | _photos = [photos retain]; 37 | _numberOfPhotos = [_photos count]; 38 | 39 | } 40 | 41 | return self; 42 | } 43 | 44 | - (id)photoAtIndex:(NSInteger)index { 45 | return [_photos objectAtIndex:index]; 46 | } 47 | 48 | - (void)dealloc{ 49 | [_photos release], _photos=nil; 50 | [super dealloc]; 51 | } 52 | 53 | @end 54 | -------------------------------------------------------------------------------- /EGOPhotoViewer/Resources/egopv_error_placeholder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enormego/PhotoViewer/54f84c971bd9a8188f8913f48dc3cab26ae61d39/EGOPhotoViewer/Resources/egopv_error_placeholder.png -------------------------------------------------------------------------------- /EGOPhotoViewer/Resources/egopv_error_placeholder@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enormego/PhotoViewer/54f84c971bd9a8188f8913f48dc3cab26ae61d39/EGOPhotoViewer/Resources/egopv_error_placeholder@2x.png -------------------------------------------------------------------------------- /EGOPhotoViewer/Resources/egopv_fullscreen_button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enormego/PhotoViewer/54f84c971bd9a8188f8913f48dc3cab26ae61d39/EGOPhotoViewer/Resources/egopv_fullscreen_button.png -------------------------------------------------------------------------------- /EGOPhotoViewer/Resources/egopv_fullscreen_button@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enormego/PhotoViewer/54f84c971bd9a8188f8913f48dc3cab26ae61d39/EGOPhotoViewer/Resources/egopv_fullscreen_button@2x.png -------------------------------------------------------------------------------- /EGOPhotoViewer/Resources/egopv_left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enormego/PhotoViewer/54f84c971bd9a8188f8913f48dc3cab26ae61d39/EGOPhotoViewer/Resources/egopv_left.png -------------------------------------------------------------------------------- /EGOPhotoViewer/Resources/egopv_left@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enormego/PhotoViewer/54f84c971bd9a8188f8913f48dc3cab26ae61d39/EGOPhotoViewer/Resources/egopv_left@2x.png -------------------------------------------------------------------------------- /EGOPhotoViewer/Resources/egopv_minimize_fullscreen_button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enormego/PhotoViewer/54f84c971bd9a8188f8913f48dc3cab26ae61d39/EGOPhotoViewer/Resources/egopv_minimize_fullscreen_button.png -------------------------------------------------------------------------------- /EGOPhotoViewer/Resources/egopv_photo_placeholder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enormego/PhotoViewer/54f84c971bd9a8188f8913f48dc3cab26ae61d39/EGOPhotoViewer/Resources/egopv_photo_placeholder.png -------------------------------------------------------------------------------- /EGOPhotoViewer/Resources/egopv_photo_placeholder@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enormego/PhotoViewer/54f84c971bd9a8188f8913f48dc3cab26ae61d39/EGOPhotoViewer/Resources/egopv_photo_placeholder@2x.png -------------------------------------------------------------------------------- /EGOPhotoViewer/Resources/egopv_right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enormego/PhotoViewer/54f84c971bd9a8188f8913f48dc3cab26ae61d39/EGOPhotoViewer/Resources/egopv_right.png -------------------------------------------------------------------------------- /EGOPhotoViewer/Resources/egopv_right@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enormego/PhotoViewer/54f84c971bd9a8188f8913f48dc3cab26ae61d39/EGOPhotoViewer/Resources/egopv_right@2x.png -------------------------------------------------------------------------------- /EGOPhotoViewer/Views/EGOPhotoCaptionView/EGOPhotoCaptionView.h: -------------------------------------------------------------------------------- 1 | // 2 | // EGOPhotoCaptionView.h 3 | // EGOPhotoViewer 4 | // 5 | // Created by Devin Doty on 1/13/2010. 6 | // Copyright (c) 2008-2009 enormego 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | // 26 | 27 | 28 | @interface EGOPhotoCaptionView : UIView { 29 | @private 30 | UILabel *_textLabel; 31 | BOOL _hidden; 32 | 33 | } 34 | 35 | - (void)setCaptionText:(NSString*)text hidden:(BOOL)val; 36 | - (void)setCaptionHidden:(BOOL)hidden; 37 | @end 38 | -------------------------------------------------------------------------------- /EGOPhotoViewer/Views/EGOPhotoCaptionView/EGOPhotoCaptionView.m: -------------------------------------------------------------------------------- 1 | // 2 | // EGOPhotoCaptionView.m 3 | // EGOPhotoViewer 4 | // 5 | // Created by Devin Doty on 1/13/2010. 6 | // Copyright (c) 2008-2009 enormego 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | // 26 | 27 | #import "EGOPhotoCaptionView.h" 28 | 29 | #import 30 | 31 | @implementation EGOPhotoCaptionView 32 | 33 | - (id)initWithFrame:(CGRect)frame { 34 | if (self = [super initWithFrame:frame]) { 35 | 36 | self.backgroundColor = [UIColor colorWithWhite:0.0f alpha:0.3f]; 37 | self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin; 38 | 39 | _textLabel = [[UILabel alloc] initWithFrame:CGRectMake(20.0f, 0.0f, self.frame.size.width - 40.0f, 40.0f)]; 40 | _textLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin; 41 | _textLabel.backgroundColor = [UIColor clearColor]; 42 | _textLabel.textAlignment = UITextAlignmentCenter; 43 | _textLabel.textColor = [UIColor whiteColor]; 44 | _textLabel.shadowColor = [UIColor blackColor]; 45 | _textLabel.shadowOffset = CGSizeMake(0.0f, 1.0f); 46 | [self addSubview:_textLabel]; 47 | [_textLabel release]; 48 | 49 | 50 | } 51 | return self; 52 | } 53 | 54 | - (void)layoutSubviews{ 55 | 56 | [self setNeedsDisplay]; 57 | _textLabel.frame = CGRectMake(20.0f, 0.0f, self.frame.size.width - 40.0f, 40.0f); 58 | 59 | } 60 | 61 | - (void)drawRect:(CGRect)rect { 62 | 63 | CGContextRef ctx = UIGraphicsGetCurrentContext(); 64 | [[UIColor colorWithWhite:1.0f alpha:0.8f] setStroke]; 65 | CGContextMoveToPoint(ctx, 0.0f, 0.0f); 66 | CGContextAddLineToPoint(ctx, self.frame.size.width, 0.0f); 67 | CGContextStrokePath(ctx); 68 | 69 | } 70 | 71 | - (void)setCaptionText:(NSString*)text hidden:(BOOL)val{ 72 | 73 | if (text == nil || [text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]].length == 0) { 74 | 75 | _textLabel.text = nil; 76 | [self setHidden:YES]; 77 | 78 | } else { 79 | 80 | [self setHidden:val]; 81 | _textLabel.text = text; 82 | 83 | } 84 | 85 | 86 | } 87 | 88 | - (void)setCaptionHidden:(BOOL)hidden{ 89 | if (_hidden==hidden) return; 90 | 91 | #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 30200 92 | if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { 93 | 94 | [UIView beginAnimations:nil context:NULL]; 95 | [UIView setAnimationDuration:0.3f]; 96 | self.alpha= hidden ? 0.0f : 1.0f; 97 | [UIView commitAnimations]; 98 | 99 | _hidden=hidden; 100 | 101 | return; 102 | 103 | } 104 | #endif 105 | 106 | [UIView beginAnimations:nil context:NULL]; 107 | [UIView setAnimationDuration:0.2f]; 108 | 109 | if (hidden) { 110 | 111 | [UIView setAnimationCurve:UIViewAnimationCurveEaseIn]; 112 | self.frame = CGRectMake(0.0f, self.superview.frame.size.height, self.frame.size.width, self.frame.size.height); 113 | 114 | } else { 115 | 116 | [UIView setAnimationCurve:UIViewAnimationCurveEaseOut]; 117 | 118 | CGFloat toolbarSize = UIInterfaceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation]) ? 32.0f : 44.0f; 119 | self.frame = CGRectMake(0.0f, self.superview.frame.size.height - (toolbarSize + self.frame.size.height), self.frame.size.width, self.frame.size.height); 120 | 121 | } 122 | 123 | [UIView commitAnimations]; 124 | 125 | _hidden=hidden; 126 | 127 | } 128 | 129 | 130 | #pragma mark - 131 | #pragma mark Dealloc 132 | 133 | - (void)dealloc { 134 | _textLabel=nil; 135 | [super dealloc]; 136 | } 137 | 138 | 139 | @end 140 | -------------------------------------------------------------------------------- /EGOPhotoViewer/Views/EGOPhotoImageView/EGOPhotoImageView.h: -------------------------------------------------------------------------------- 1 | // 2 | // EGOPhotoImageView.h 3 | // EGOPhotoViewer 4 | // 5 | // Created by Devin Doty on 1/13/2010. 6 | // Copyright (c) 2008-2009 enormego 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | // 26 | 27 | 28 | #import "EGOPhotoGlobal.h" 29 | #import "EGOPhotoSource.h" 30 | #import "EGOImageLoader.h" 31 | 32 | @class EGOPhotoScrollView, EGOPhotoCaptionView; 33 | 34 | @interface EGOPhotoImageView : UIView { 35 | @private 36 | EGOPhotoScrollView *_scrollView; 37 | id _photo; 38 | UIImageView *_imageView; 39 | UIActivityIndicatorView *_activityView; 40 | 41 | BOOL _loading; 42 | CGRect _currentRect; 43 | CGFloat _beginRadians; 44 | CGPoint _midPos; 45 | 46 | } 47 | 48 | @property(nonatomic,readonly) id photo; 49 | @property(nonatomic,readonly) UIImageView *imageView; 50 | @property(nonatomic,readonly) EGOPhotoScrollView *scrollView; 51 | @property(nonatomic,assign,getter=isLoading) BOOL loading; 52 | 53 | - (void)setPhoto:(id )aPhoto; 54 | - (void)killScrollViewZoom; 55 | - (void)layoutScrollViewAnimated:(BOOL)animated; 56 | - (void)prepareForReusue; 57 | - (void)rotateToOrientation:(UIInterfaceOrientation)orientation; 58 | - (CGSize)sizeForPopover; 59 | 60 | @end 61 | -------------------------------------------------------------------------------- /EGOPhotoViewer/Views/EGOPhotoImageView/EGOPhotoImageView.m: -------------------------------------------------------------------------------- 1 | // 2 | // EGOPhotoImageView.m 3 | // EGOPhotoViewer 4 | // 5 | // Created by Devin Doty on 1/13/2010. 6 | // Copyright (c) 2008-2009 enormego 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | // 26 | 27 | #import "EGOPhotoImageView.h" 28 | 29 | #define ZOOM_VIEW_TAG 0x101 30 | 31 | @interface RotateGesture : UIRotationGestureRecognizer {} 32 | @end 33 | 34 | @implementation RotateGesture 35 | - (BOOL)canBePreventedByGestureRecognizer:(UIGestureRecognizer*)gesture{ 36 | return NO; 37 | } 38 | - (BOOL)canPreventGestureRecognizer:(UIGestureRecognizer *)preventedGestureRecognizer{ 39 | return YES; 40 | } 41 | @end 42 | 43 | 44 | @interface EGOPhotoImageView (Private) 45 | - (void)layoutScrollViewAnimated:(BOOL)animated; 46 | - (void)handleFailedImage; 47 | - (void)setupImageViewWithImage:(UIImage *)aImage; 48 | - (CABasicAnimation*)fadeAnimation; 49 | @end 50 | 51 | 52 | @implementation EGOPhotoImageView 53 | 54 | @synthesize photo=_photo; 55 | @synthesize imageView=_imageView; 56 | @synthesize scrollView=_scrollView; 57 | @synthesize loading=_loading; 58 | 59 | - (id)initWithFrame:(CGRect)frame { 60 | if (self = [super initWithFrame:frame]) { 61 | 62 | self.backgroundColor = [UIColor blackColor]; 63 | self.userInteractionEnabled = NO; 64 | self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; 65 | self.opaque = YES; 66 | 67 | EGOPhotoScrollView *scrollView = [[EGOPhotoScrollView alloc] initWithFrame:self.bounds]; 68 | scrollView.backgroundColor = [UIColor blackColor]; 69 | scrollView.opaque = YES; 70 | scrollView.delegate = self; 71 | [self addSubview:scrollView]; 72 | _scrollView = [scrollView retain]; 73 | [scrollView release]; 74 | 75 | UIImageView *imageView = [[UIImageView alloc] initWithFrame:self.bounds]; 76 | imageView.opaque = YES; 77 | imageView.contentMode = UIViewContentModeScaleAspectFit; 78 | imageView.tag = ZOOM_VIEW_TAG; 79 | [_scrollView addSubview:imageView]; 80 | _imageView = [imageView retain]; 81 | [imageView release]; 82 | 83 | UIActivityIndicatorView *activityView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite]; 84 | activityView.frame = CGRectMake((CGRectGetWidth(self.frame) / 2) - 11.0f, CGRectGetHeight(self.frame) - 100.0f , 22.0f, 22.0f); 85 | activityView.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleTopMargin; 86 | [self addSubview:activityView]; 87 | _activityView = [activityView retain]; 88 | [activityView release]; 89 | 90 | RotateGesture *gesture = [[RotateGesture alloc] initWithTarget:self action:@selector(rotate:)]; 91 | [self addGestureRecognizer:gesture]; 92 | [gesture release]; 93 | 94 | } 95 | return self; 96 | } 97 | 98 | - (void)layoutSubviews{ 99 | [super layoutSubviews]; 100 | 101 | if (_scrollView.zoomScale == 1.0f) { 102 | [self layoutScrollViewAnimated:YES]; 103 | } 104 | 105 | } 106 | 107 | - (void)setPhoto:(id )aPhoto{ 108 | 109 | if (!aPhoto) return; 110 | if ([aPhoto isEqual:self.photo]) return; 111 | 112 | if (self.photo != nil) { 113 | [[EGOImageLoader sharedImageLoader] cancelLoadForURL:self.photo.URL]; 114 | } 115 | 116 | [_photo release], _photo = nil; 117 | _photo = [aPhoto retain]; 118 | 119 | if (self.photo.image) { 120 | 121 | self.imageView.image = self.photo.image; 122 | 123 | } else { 124 | 125 | if ([self.photo.URL isFileURL]) { 126 | 127 | #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 40000 128 | 129 | NSError *error = nil; 130 | NSDictionary *attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:[self.photo.URL path] error:&error]; 131 | NSInteger fileSize = [[attributes objectForKey:NSFileSize] integerValue]; 132 | 133 | if (fileSize >= 1048576 && [[[UIDevice currentDevice] systemVersion] floatValue] >= 4.0) { 134 | 135 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ 136 | 137 | UIImage *_image = nil; 138 | NSData *_data = [NSData dataWithContentsOfURL:self.photo.URL]; 139 | if (!_data) { 140 | [self handleFailedImage]; 141 | } else { 142 | _image = [UIImage imageWithData:_data]; 143 | } 144 | 145 | dispatch_async(dispatch_get_main_queue(), ^{ 146 | 147 | if (_image!=nil) { 148 | [self setupImageViewWithImage:_image]; 149 | } 150 | 151 | 152 | }); 153 | 154 | }); 155 | 156 | } else { 157 | 158 | self.imageView.image = [UIImage imageWithData:[NSData dataWithContentsOfURL:self.photo.URL]]; 159 | 160 | } 161 | 162 | #else 163 | self.imageView.image = [UIImage imageWithData:[NSData dataWithContentsOfURL:self.photo.URL]]; 164 | #endif 165 | 166 | 167 | } else { 168 | self.imageView.image = [[EGOImageLoader sharedImageLoader] imageForURL:self.photo.URL shouldLoadWithObserver:self]; 169 | } 170 | 171 | } 172 | 173 | if (self.imageView.image) { 174 | 175 | [_activityView stopAnimating]; 176 | self.userInteractionEnabled = YES; 177 | 178 | _loading=NO; 179 | [[NSNotificationCenter defaultCenter] postNotificationName:@"EGOPhotoDidFinishLoading" object:[NSDictionary dictionaryWithObjectsAndKeys:self.photo, @"photo", [NSNumber numberWithBool:NO], @"failed", nil]]; 180 | 181 | 182 | } else { 183 | 184 | _loading = YES; 185 | [_activityView startAnimating]; 186 | self.userInteractionEnabled= NO; 187 | self.imageView.image = kEGOPhotoLoadingPlaceholder; 188 | } 189 | 190 | [self layoutScrollViewAnimated:NO]; 191 | } 192 | 193 | - (void)setupImageViewWithImage:(UIImage*)aImage { 194 | if (!aImage) return; 195 | 196 | _loading = NO; 197 | [_activityView stopAnimating]; 198 | self.imageView.image = aImage; 199 | [self layoutScrollViewAnimated:NO]; 200 | 201 | [[self layer] addAnimation:[self fadeAnimation] forKey:@"opacity"]; 202 | self.userInteractionEnabled = YES; 203 | [[NSNotificationCenter defaultCenter] postNotificationName:@"EGOPhotoDidFinishLoading" object:[NSDictionary dictionaryWithObjectsAndKeys:self.photo, @"photo", [NSNumber numberWithBool:NO], @"failed", nil]]; 204 | 205 | } 206 | 207 | - (void)prepareForReusue{ 208 | 209 | // reset view 210 | self.tag = -1; 211 | 212 | } 213 | 214 | - (void)handleFailedImage{ 215 | 216 | self.imageView.image = kEGOPhotoErrorPlaceholder; 217 | self.photo.failed = YES; 218 | [self layoutScrollViewAnimated:NO]; 219 | self.userInteractionEnabled = NO; 220 | [_activityView stopAnimating]; 221 | [[NSNotificationCenter defaultCenter] postNotificationName:@"EGOPhotoDidFinishLoading" object:[NSDictionary dictionaryWithObjectsAndKeys:self.photo, @"photo", [NSNumber numberWithBool:YES], @"failed", nil]]; 222 | 223 | } 224 | 225 | 226 | #pragma mark - 227 | #pragma mark Parent Controller Fading 228 | 229 | - (void)fadeView{ 230 | 231 | self.backgroundColor = [UIColor clearColor]; 232 | self.superview.backgroundColor = self.backgroundColor; 233 | self.superview.superview.backgroundColor = self.backgroundColor; 234 | 235 | CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"backgroundColor"]; 236 | [animation setValue:[NSNumber numberWithInt:101] forKey:@"AnimationType"]; 237 | animation.delegate = self; 238 | animation.fromValue = (id)[UIColor clearColor].CGColor; 239 | animation.toValue = (id)[UIColor blackColor].CGColor; 240 | animation.duration = 0.4f; 241 | [self.layer addAnimation:animation forKey:@"FadeAnimation"]; 242 | 243 | 244 | } 245 | 246 | - (void)resetBackgroundColors{ 247 | 248 | self.backgroundColor = [UIColor blackColor]; 249 | self.superview.backgroundColor = self.backgroundColor; 250 | self.superview.superview.backgroundColor = self.backgroundColor; 251 | 252 | } 253 | 254 | 255 | #pragma mark - 256 | #pragma mark Layout 257 | 258 | - (void)rotateToOrientation:(UIInterfaceOrientation)orientation{ 259 | 260 | if (self.scrollView.zoomScale > 1.0f) { 261 | 262 | CGFloat height, width; 263 | height = MIN(CGRectGetHeight(self.imageView.frame) + self.imageView.frame.origin.x, CGRectGetHeight(self.bounds)); 264 | width = MIN(CGRectGetWidth(self.imageView.frame) + self.imageView.frame.origin.y, CGRectGetWidth(self.bounds)); 265 | self.scrollView.frame = CGRectMake((self.bounds.size.width / 2) - (width / 2), (self.bounds.size.height / 2) - (height / 2), width, height); 266 | 267 | } else { 268 | 269 | [self layoutScrollViewAnimated:NO]; 270 | 271 | } 272 | } 273 | 274 | - (void)layoutScrollViewAnimated:(BOOL)animated{ 275 | 276 | if (animated) { 277 | [UIView beginAnimations:nil context:NULL]; 278 | [UIView setAnimationDuration:0.0001]; 279 | } 280 | 281 | CGFloat hfactor = self.imageView.image.size.width / self.frame.size.width; 282 | CGFloat vfactor = self.imageView.image.size.height / self.frame.size.height; 283 | 284 | CGFloat factor = MAX(hfactor, vfactor); 285 | 286 | CGFloat newWidth = self.imageView.image.size.width / factor; 287 | CGFloat newHeight = self.imageView.image.size.height / factor; 288 | 289 | CGFloat leftOffset = (self.frame.size.width - newWidth) / 2; 290 | CGFloat topOffset = (self.frame.size.height - newHeight) / 2; 291 | 292 | self.scrollView.frame = CGRectMake(leftOffset, topOffset, newWidth, newHeight); 293 | self.scrollView.layer.position = CGPointMake(self.bounds.size.width/2, self.bounds.size.height/2); 294 | self.scrollView.contentSize = CGSizeMake(self.scrollView.bounds.size.width, self.scrollView.bounds.size.height); 295 | self.scrollView.contentOffset = CGPointMake(0.0f, 0.0f); 296 | self.imageView.frame = self.scrollView.bounds; 297 | 298 | 299 | if (animated) { 300 | [UIView commitAnimations]; 301 | } 302 | } 303 | 304 | - (CGSize)sizeForPopover{ 305 | 306 | CGSize popoverSize = EGOPV_MAX_POPOVER_SIZE; 307 | 308 | if (!self.imageView.image) { 309 | return popoverSize; 310 | } 311 | 312 | CGSize imageSize = self.imageView.image.size; 313 | 314 | if(imageSize.width > popoverSize.width || imageSize.height > popoverSize.height) { 315 | 316 | if(imageSize.width > imageSize.height) { 317 | popoverSize.height = floorf((popoverSize.width * imageSize.height) / imageSize.width); 318 | } else { 319 | popoverSize.width = floorf((popoverSize.height * imageSize.width) / imageSize.height); 320 | } 321 | 322 | } else { 323 | 324 | popoverSize = imageSize; 325 | 326 | } 327 | 328 | if (popoverSize.width < EGOPV_MIN_POPOVER_SIZE.width || popoverSize.height < EGOPV_MIN_POPOVER_SIZE.height) { 329 | 330 | CGFloat hfactor = popoverSize.width / EGOPV_MIN_POPOVER_SIZE.width; 331 | CGFloat vfactor = popoverSize.height / EGOPV_MIN_POPOVER_SIZE.height; 332 | 333 | CGFloat factor = MAX(hfactor, vfactor); 334 | 335 | CGFloat newWidth = popoverSize.width / factor; 336 | CGFloat newHeight = popoverSize.height / factor; 337 | 338 | popoverSize.width = newWidth; 339 | popoverSize.height = newHeight; 340 | 341 | } 342 | 343 | 344 | return popoverSize; 345 | 346 | } 347 | 348 | 349 | #pragma mark - 350 | #pragma mark Animation 351 | 352 | - (CABasicAnimation*)fadeAnimation{ 353 | 354 | CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"opacity"]; 355 | animation.fromValue = [NSNumber numberWithFloat:0.0f]; 356 | animation.toValue = [NSNumber numberWithFloat:1.0f]; 357 | animation.duration = .3f; 358 | animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]; 359 | 360 | return animation; 361 | } 362 | 363 | 364 | #pragma mark - 365 | #pragma mark EGOImageLoader Callbacks 366 | 367 | - (void)imageLoaderDidLoad:(NSNotification*)notification { 368 | 369 | if ([notification userInfo] == nil) return; 370 | if(![[[notification userInfo] objectForKey:@"imageURL"] isEqual:self.photo.URL]) return; 371 | 372 | [self setupImageViewWithImage:[[notification userInfo] objectForKey:@"image"]]; 373 | 374 | } 375 | 376 | - (void)imageLoaderDidFailToLoad:(NSNotification*)notification { 377 | 378 | if ([notification userInfo] == nil) return; 379 | if(![[[notification userInfo] objectForKey:@"imageURL"] isEqual:self.photo.URL]) return; 380 | 381 | [self handleFailedImage]; 382 | 383 | } 384 | 385 | 386 | #pragma mark - 387 | #pragma mark UIScrollView Delegate Methods 388 | 389 | - (void)killZoomAnimationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context{ 390 | 391 | if([finished boolValue]){ 392 | 393 | [self.scrollView setZoomScale:1.0f animated:NO]; 394 | self.imageView.frame = self.scrollView.bounds; 395 | [self layoutScrollViewAnimated:NO]; 396 | 397 | } 398 | 399 | } 400 | 401 | - (void)killScrollViewZoom{ 402 | 403 | if (!self.scrollView.zoomScale > 1.0f) return; 404 | 405 | [UIView beginAnimations:nil context:NULL]; 406 | [UIView setAnimationDuration:0.3]; 407 | [UIView setAnimationDidStopSelector:@selector(killZoomAnimationDidStop:finished:context:)]; 408 | [UIView setAnimationDelegate:self]; 409 | 410 | CGFloat hfactor = self.imageView.image.size.width / self.frame.size.width; 411 | CGFloat vfactor = self.imageView.image.size.height / self.frame.size.height; 412 | 413 | CGFloat factor = MAX(hfactor, vfactor); 414 | 415 | CGFloat newWidth = self.imageView.image.size.width / factor; 416 | CGFloat newHeight = self.imageView.image.size.height / factor; 417 | 418 | CGFloat leftOffset = (self.frame.size.width - newWidth) / 2; 419 | CGFloat topOffset = (self.frame.size.height - newHeight) / 2; 420 | 421 | self.scrollView.frame = CGRectMake(leftOffset, topOffset, newWidth, newHeight); 422 | self.imageView.frame = self.scrollView.bounds; 423 | [UIView commitAnimations]; 424 | 425 | } 426 | 427 | - (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView{ 428 | return [self.scrollView viewWithTag:ZOOM_VIEW_TAG]; 429 | } 430 | 431 | - (CGRect)frameToFitCurrentView{ 432 | 433 | CGFloat heightFactor = self.imageView.image.size.height / self.frame.size.height; 434 | CGFloat widthFactor = self.imageView.image.size.width / self.frame.size.width; 435 | 436 | CGFloat scaleFactor = MAX(heightFactor, widthFactor); 437 | 438 | CGFloat newHeight = self.imageView.image.size.height / scaleFactor; 439 | CGFloat newWidth = self.imageView.image.size.width / scaleFactor; 440 | 441 | 442 | CGRect rect = CGRectMake((self.frame.size.width - newWidth)/2, (self.frame.size.height-newHeight)/2, newWidth, newHeight); 443 | 444 | return rect; 445 | 446 | } 447 | 448 | - (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale{ 449 | 450 | if (scrollView.zoomScale > 1.0f) { 451 | 452 | 453 | CGFloat height, width, originX, originY; 454 | height = MIN(CGRectGetHeight(self.imageView.frame) + self.imageView.frame.origin.x, CGRectGetHeight(self.bounds)); 455 | width = MIN(CGRectGetWidth(self.imageView.frame) + self.imageView.frame.origin.y, CGRectGetWidth(self.bounds)); 456 | 457 | 458 | if (CGRectGetMaxX(self.imageView.frame) > self.bounds.size.width) { 459 | width = CGRectGetWidth(self.bounds); 460 | originX = 0.0f; 461 | } else { 462 | width = CGRectGetMaxX(self.imageView.frame); 463 | 464 | if (self.imageView.frame.origin.x < 0.0f) { 465 | originX = 0.0f; 466 | } else { 467 | originX = self.imageView.frame.origin.x; 468 | } 469 | } 470 | 471 | if (CGRectGetMaxY(self.imageView.frame) > self.bounds.size.height) { 472 | height = CGRectGetHeight(self.bounds); 473 | originY = 0.0f; 474 | } else { 475 | height = CGRectGetMaxY(self.imageView.frame); 476 | 477 | if (self.imageView.frame.origin.y < 0.0f) { 478 | originY = 0.0f; 479 | } else { 480 | originY = self.imageView.frame.origin.y; 481 | } 482 | } 483 | 484 | CGRect frame = self.scrollView.frame; 485 | self.scrollView.frame = CGRectMake((self.bounds.size.width / 2) - (width / 2), (self.bounds.size.height / 2) - (height / 2), width, height); 486 | self.scrollView.layer.position = CGPointMake(self.bounds.size.width/2, self.bounds.size.height/2); 487 | if (!CGRectEqualToRect(frame, self.scrollView.frame)) { 488 | 489 | CGFloat offsetY, offsetX; 490 | 491 | if (frame.origin.y < self.scrollView.frame.origin.y) { 492 | offsetY = self.scrollView.contentOffset.y - (self.scrollView.frame.origin.y - frame.origin.y); 493 | } else { 494 | offsetY = self.scrollView.contentOffset.y - (frame.origin.y - self.scrollView.frame.origin.y); 495 | } 496 | 497 | if (frame.origin.x < self.scrollView.frame.origin.x) { 498 | offsetX = self.scrollView.contentOffset.x - (self.scrollView.frame.origin.x - frame.origin.x); 499 | } else { 500 | offsetX = self.scrollView.contentOffset.x - (frame.origin.x - self.scrollView.frame.origin.x); 501 | } 502 | 503 | if (offsetY < 0) offsetY = 0; 504 | if (offsetX < 0) offsetX = 0; 505 | 506 | self.scrollView.contentOffset = CGPointMake(offsetX, offsetY); 507 | } 508 | 509 | } else { 510 | [self layoutScrollViewAnimated:YES]; 511 | } 512 | } 513 | 514 | 515 | #pragma mark - 516 | #pragma mark RotateGesture 517 | 518 | - (void)rotate:(UIRotationGestureRecognizer*)gesture{ 519 | 520 | if (gesture.state == UIGestureRecognizerStateBegan) { 521 | 522 | [self.layer removeAllAnimations]; 523 | _beginRadians = gesture.rotation; 524 | self.layer.transform = CATransform3DMakeRotation(_beginRadians, 0.0f, 0.0f, 1.0f); 525 | 526 | } else if (gesture.state == UIGestureRecognizerStateChanged) { 527 | 528 | self.layer.transform = CATransform3DMakeRotation((_beginRadians + gesture.rotation), 0.0f, 0.0f, 1.0f); 529 | 530 | } else { 531 | 532 | CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform"]; 533 | animation.toValue = [NSValue valueWithCATransform3D:CATransform3DIdentity]; 534 | animation.duration = 0.3f; 535 | animation.removedOnCompletion = NO; 536 | animation.fillMode = kCAFillModeForwards; 537 | animation.delegate = self; 538 | [animation setValue:[NSNumber numberWithInt:202] forKey:@"AnimationType"]; 539 | [self.layer addAnimation:animation forKey:@"RotateAnimation"]; 540 | 541 | } 542 | 543 | 544 | } 545 | 546 | - (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag{ 547 | 548 | if (flag) { 549 | 550 | if ([[anim valueForKey:@"AnimationType"] integerValue] == 101) { 551 | 552 | [self resetBackgroundColors]; 553 | 554 | } else if ([[anim valueForKey:@"AnimationType"] integerValue] == 202) { 555 | 556 | self.layer.transform = CATransform3DIdentity; 557 | 558 | } 559 | } 560 | 561 | } 562 | 563 | 564 | #pragma mark - 565 | #pragma mark Dealloc 566 | 567 | - (void)dealloc { 568 | 569 | if (_photo) { 570 | [[EGOImageLoader sharedImageLoader] cancelLoadForURL:self.photo.URL]; 571 | } 572 | 573 | [[NSNotificationCenter defaultCenter] removeObserver:self]; 574 | 575 | [_activityView release], _activityView=nil; 576 | [_imageView release]; _imageView=nil; 577 | [_scrollView release]; _scrollView=nil; 578 | [_photo release]; _photo=nil; 579 | [super dealloc]; 580 | 581 | } 582 | 583 | 584 | @end 585 | -------------------------------------------------------------------------------- /EGOPhotoViewer/Views/EGOPhotoScrollView/EGOPhotoScrollView.h: -------------------------------------------------------------------------------- 1 | // 2 | // EGOPhotoScrollView.h 3 | // EGOPhotoViewer 4 | // 5 | // Created by Devin Doty on 1/13/2010. 6 | // Copyright (c) 2008-2009 enormego 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | // 26 | 27 | 28 | #import "EGOPhotoGlobal.h" 29 | 30 | @interface EGOPhotoScrollView : UIScrollView { 31 | 32 | } 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /EGOPhotoViewer/Views/EGOPhotoScrollView/EGOPhotoScrollView.m: -------------------------------------------------------------------------------- 1 | // 2 | // EGOPhotoScrollView.m 3 | // EGOPhotoViewer 4 | // 5 | // Created by Devin Doty on 1/13/2010. 6 | // Copyright (c) 2008-2009 enormego 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | // 26 | 27 | #import "EGOPhotoScrollView.h" 28 | 29 | @implementation EGOPhotoScrollView 30 | 31 | 32 | - (id)initWithFrame:(CGRect)frame { 33 | if (self = [super initWithFrame:frame]) { 34 | 35 | self.scrollEnabled = YES; 36 | self.pagingEnabled = NO; 37 | self.clipsToBounds = NO; 38 | self.maximumZoomScale = 3.0f; 39 | self.minimumZoomScale = 1.0f; 40 | self.showsVerticalScrollIndicator = NO; 41 | self.showsHorizontalScrollIndicator = NO; 42 | self.alwaysBounceVertical = NO; 43 | self.alwaysBounceHorizontal = NO; 44 | self.bouncesZoom = YES; 45 | self.bounces = YES; 46 | self.scrollsToTop = NO; 47 | self.backgroundColor = [UIColor blackColor]; 48 | self.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleTopMargin; 49 | self.decelerationRate = UIScrollViewDecelerationRateFast; 50 | 51 | } 52 | return self; 53 | } 54 | 55 | - (void)zoomRectWithCenter:(CGPoint)center{ 56 | 57 | if (self.zoomScale > 1.0f) { 58 | 59 | [((EGOPhotoImageView*)self.superview) killScrollViewZoom]; 60 | 61 | return; 62 | } 63 | 64 | CGRect rect; 65 | rect.size = CGSizeMake(self.frame.size.width / EGOPV_ZOOM_SCALE, self.frame.size.height / EGOPV_ZOOM_SCALE); 66 | rect.origin.x = MAX((center.x - (rect.size.width / 2.0f)), 0.0f); 67 | rect.origin.y = MAX((center.y - (rect.size.height / 2.0f)), 0.0f); 68 | 69 | CGRect frame = [self.superview convertRect:self.frame toView:self.superview]; 70 | CGFloat borderX = frame.origin.x; 71 | CGFloat borderY = frame.origin.y; 72 | 73 | if (borderX > 0.0f && (center.x < borderX || center.x > self.frame.size.width - borderX)) { 74 | 75 | if (center.x < (self.frame.size.width / 2.0f)) { 76 | 77 | rect.origin.x += (borderX/EGOPV_ZOOM_SCALE); 78 | 79 | } else { 80 | 81 | rect.origin.x -= ((borderX/EGOPV_ZOOM_SCALE) + rect.size.width); 82 | 83 | } 84 | } 85 | 86 | if (borderY > 0.0f && (center.y < borderY || center.y > self.frame.size.height - borderY)) { 87 | 88 | if (center.y < (self.frame.size.height / 2.0f)) { 89 | 90 | rect.origin.y += (borderY/EGOPV_ZOOM_SCALE); 91 | 92 | } else { 93 | 94 | rect.origin.y -= ((borderY/EGOPV_ZOOM_SCALE) + rect.size.height); 95 | 96 | } 97 | 98 | } 99 | 100 | [self zoomToRect:rect animated:YES]; 101 | 102 | } 103 | 104 | - (void)toggleBars{ 105 | [[NSNotificationCenter defaultCenter] postNotificationName:@"EGOPhotoViewToggleBars" object:nil]; 106 | } 107 | 108 | 109 | #pragma mark - 110 | #pragma mark Touches 111 | 112 | - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ 113 | [super touchesBegan:touches withEvent:event]; 114 | } 115 | 116 | - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{ 117 | [super touchesEnded:touches withEvent:event]; 118 | UITouch *touch = [touches anyObject]; 119 | 120 | if (touch.tapCount == 1) { 121 | [self performSelector:@selector(toggleBars) withObject:nil afterDelay:.2]; 122 | } else if (touch.tapCount == 2) { 123 | [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(toggleBars) object:nil]; 124 | [self zoomRectWithCenter:[[touches anyObject] locationInView:self]]; 125 | } 126 | } 127 | 128 | 129 | #pragma mark - 130 | #pragma mark Dealloc 131 | 132 | - (void)dealloc { 133 | [super dealloc]; 134 | } 135 | 136 | 137 | @end 138 | -------------------------------------------------------------------------------- /README.mdown: -------------------------------------------------------------------------------- 1 | # EGOPhotoViewer 2 | 3 | Created by **enormego** 4 | 5 | **EGOPhotoViewer** is a quick and easy to use photo viewer for iOS, with full support for iPhone, iPhone, and iPad. **EGOPhotoViewer** was originally started as a stripped down version of **three20**'s PhotoViewer. We ultimately decided the **three20** code base wasn't flexible enough and scrapped the project all together. We rewrote PhotoViewer as EGOPhotoViewer from scratch, based upon our reliable open source libraries **EGOCache** and **EGOImageLoading**. 6 | 7 | # Documentation 8 | We haven't yet had a chance to document **EGOPhotoViewer**, but you should be able to find everything you need in the header files and demo app. 9 | 10 | # License 11 | 12 | **EGOPhotoViewer** is available under the MIT license: 13 | 14 | *Copyright (c) 2010 enormego* 15 | 16 | *Permission is hereby granted, free of charge, to any person obtaining a copy* 17 | *of this software and associated documentation files (the "Software"), to deal* 18 | *in the Software without restriction, including without limitation the rights* 19 | *to use, copy, modify, merge, publish, distribute, sublicense, and/or sell* 20 | *copies of the Software, and to permit persons to whom the Software is* 21 | *furnished to do so, subject to the following conditions:* 22 | 23 | *The above copyright notice and this permission notice shall be included in* 24 | *all copies or substantial portions of the Software.* 25 | 26 | *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR* 27 | *IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,* 28 | *FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE* 29 | *AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER* 30 | *LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,* 31 | *OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN* 32 | *THE SOFTWARE.* --------------------------------------------------------------------------------