Mikhail Kuznetsov avatar Mikhail Kuznetsov committed 3c81da6

image loading (not done);

Comments (0)

Files changed (15)

MyShows.xcodeproj/project.pbxproj

 	objects = {
 
 /* Begin PBXBuildFile section */
+		1829F18D14546E4700B98707 /* ImageManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1829F18C14546E4700B98707 /* ImageManager.m */; };
+		1829F1921454720F00B98707 /* SVProgressHUD.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 1829F18F1454720F00B98707 /* SVProgressHUD.bundle */; };
+		1829F1931454720F00B98707 /* SVProgressHUD.m in Sources */ = {isa = PBXBuildFile; fileRef = 1829F1911454720F00B98707 /* SVProgressHUD.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; };
+		1829F195145473DD00B98707 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1829F194145473DD00B98707 /* QuartzCore.framework */; };
+		1829F1981454843700B98707 /* AsyncImageCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 1829F1971454843700B98707 /* AsyncImageCell.m */; };
 		1866084B144AEC120050B8E1 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1866084A144AEC120050B8E1 /* UIKit.framework */; };
 		1866084D144AEC120050B8E1 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1866084C144AEC120050B8E1 /* Foundation.framework */; };
 		1866084F144AEC120050B8E1 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1866084E144AEC120050B8E1 /* CoreGraphics.framework */; };
 /* End PBXContainerItemProxy section */
 
 /* Begin PBXFileReference section */
+		1829F18B14546E4700B98707 /* ImageManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ImageManager.h; path = Classes/ImageManager.h; sourceTree = "<group>"; };
+		1829F18C14546E4700B98707 /* ImageManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ImageManager.m; path = Classes/ImageManager.m; sourceTree = "<group>"; };
+		1829F18F1454720F00B98707 /* SVProgressHUD.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = SVProgressHUD.bundle; sourceTree = "<group>"; };
+		1829F1901454720F00B98707 /* SVProgressHUD.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SVProgressHUD.h; sourceTree = "<group>"; };
+		1829F1911454720F00B98707 /* SVProgressHUD.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SVProgressHUD.m; sourceTree = "<group>"; };
+		1829F194145473DD00B98707 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
+		1829F1961454843700B98707 /* AsyncImageCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AsyncImageCell.h; path = Classes/AsyncImageCell.h; sourceTree = "<group>"; };
+		1829F1971454843700B98707 /* AsyncImageCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AsyncImageCell.m; path = Classes/AsyncImageCell.m; sourceTree = "<group>"; };
 		18660846144AEC120050B8E1 /* MyShows.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MyShows.app; sourceTree = BUILT_PRODUCTS_DIR; };
 		1866084A144AEC120050B8E1 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
 		1866084C144AEC120050B8E1 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				1829F195145473DD00B98707 /* QuartzCore.framework in Frameworks */,
 				1866084B144AEC120050B8E1 /* UIKit.framework in Frameworks */,
 				1866084D144AEC120050B8E1 /* Foundation.framework in Frameworks */,
 				186608D5144AFFEF0050B8E1 /* CFNetwork.framework in Frameworks */,
 /* End PBXFrameworksBuildPhase section */
 
 /* Begin PBXGroup section */
+		1829F18E1454720F00B98707 /* SVProgressHUD */ = {
+			isa = PBXGroup;
+			children = (
+				1829F18F1454720F00B98707 /* SVProgressHUD.bundle */,
+				1829F1901454720F00B98707 /* SVProgressHUD.h */,
+				1829F1911454720F00B98707 /* SVProgressHUD.m */,
+			);
+			path = SVProgressHUD;
+			sourceTree = "<group>";
+		};
 		1866083B144AEC120050B8E1 = {
 			isa = PBXGroup;
 			children = (
 		18660849144AEC120050B8E1 /* Frameworks */ = {
 			isa = PBXGroup;
 			children = (
+				1829F194145473DD00B98707 /* QuartzCore.framework */,
 				186608D6144B002C0050B8E1 /* libz.dylib */,
 				186608D4144AFFEF0050B8E1 /* CFNetwork.framework */,
 				186608D8144B002C0050B8E1 /* SystemConfiguration.framework */,
 		18660887144AF4D10050B8E1 /* Libraries */ = {
 			isa = PBXGroup;
 			children = (
+				1829F18E1454720F00B98707 /* SVProgressHUD */,
 				186608E0144B150A0050B8E1 /* ASIHttp */,
 				186608AE144AF7DB0050B8E1 /* SBJson */,
 			);
 		186608DF144B14D10050B8E1 /* Classes */ = {
 			isa = PBXGroup;
 			children = (
+				1829F18B14546E4700B98707 /* ImageManager.h */,
+				1829F18C14546E4700B98707 /* ImageManager.m */,
 				18C1DFC21453441300687C0B /* ShowTableViewCell.h */,
 				18C1DFC31453441400687C0B /* ShowTableViewCell.m */,
 				186608DC144B14920050B8E1 /* MyShowsApi.h */,
 				186608DD144B14930050B8E1 /* MyShowsApi.m */,
+				1829F1961454843700B98707 /* AsyncImageCell.h */,
+				1829F1971454843700B98707 /* AsyncImageCell.m */,
 			);
 			name = Classes;
 			sourceTree = "<group>";
 				18660855144AEC120050B8E1 /* InfoPlist.strings in Resources */,
 				1866085E144AEC120050B8E1 /* MainStoryboard.storyboard in Resources */,
 				18660886144AEF2D0050B8E1 /* logo-tv.gif in Resources */,
+				1829F1921454720F00B98707 /* SVProgressHUD.bundle in Resources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
 				18C1DFBB1453136F00687C0B /* LoginViewController.m in Sources */,
 				18C1DFC1145315B500687C0B /* ShowsListTableViewController.m in Sources */,
 				18C1DFC41453441400687C0B /* ShowTableViewCell.m in Sources */,
+				1829F18D14546E4700B98707 /* ImageManager.m in Sources */,
+				1829F1931454720F00B98707 /* SVProgressHUD.m in Sources */,
+				1829F1981454843700B98707 /* AsyncImageCell.m in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};

MyShows/AppDelegate.m

 //
 
 #import "AppDelegate.h"
+#import "ImageManager.h"
 
 @implementation AppDelegate
 
      */
 }
 
+- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
+    [ImageManager clearMemoryCache];
+}
+
 @end

MyShows/Classes/AsyncImageCell.h

+//
+//  AsyncImageCell.h
+//  MyShows
+//
+//  Created by Mikhail Kuznetsov on 23.10.11.
+//  Copyright (c) 2011 __MyCompanyName__. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+@interface AsyncImageCell : UITableViewCell
+
+@property (nonatomic, retain) NSURL *imageURL;
+
+@end

MyShows/Classes/AsyncImageCell.m

+//
+//  AsyncImageCell.m
+//  MyShows
+//
+//  Created by Mikhail Kuznetsov on 23.10.11.
+//  Copyright (c) 2011 __MyCompanyName__. All rights reserved.
+//
+
+#import "AsyncImageCell.h"
+#import "ImageManager.h"
+
+@implementation AsyncImageCell
+
+@synthesize imageURL;
+
+- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
+{
+    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
+    if (self) {
+        // Initialization code
+    }
+    return self;
+}
+
+- (void)setSelected:(BOOL)selected animated:(BOOL)animated
+{
+    [super setSelected:selected animated:animated];
+
+    // Configure the view for the selected state
+}
+
+- (void)drawRect:(CGRect)rect {
+    [super drawRect:rect];
+    if (imageURL) {
+		UIImage *img = [ImageManager loadImage:imageURL];
+		if (img) {
+            self.imageView.image = img;
+		}
+	}
+}
+
+- (void) imageLoaded:(UIImage*)image withURL:(NSURL*)url {
+	if ([imageURL isEqual:url]) {
+		[self setNeedsDisplay];
+	}
+}
+
+@end

MyShows/Classes/ImageManager.h

+//
+//  ImageManager.h
+//  IOSBoilerplate
+//
+//  Copyright (c) 2011 Alberto Gimeno Brieba
+//  
+//  Permission is hereby granted, free of charge, to any person
+//  obtaining a copy of this software and associated documentation
+//  files (the "Software"), to deal in the Software without
+//  restriction, including without limitation the rights to use,
+//  copy, modify, merge, publish, distribute, sublicense, and/or sell
+//  copies of the Software, and to permit persons to whom the
+//  Software is furnished to do so, subject to the following
+//  conditions:
+//  
+//  The above copyright notice and this permission notice shall be
+//  included in all copies or substantial portions of the Software.
+//  
+//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+//  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+//  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+//  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+//  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+//  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+//  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+//  OTHER DEALINGS IN THE SOFTWARE.
+//  
+
+#import <Foundation/Foundation.h>
+#import "ASIDownloadCache.h"
+
+@protocol AsyncImageDelegate <NSObject>
+- (void) imageLoaded:(UIImage *)image withUrl:(NSURL *)url;
+@end
+
+@interface ImageManager : NSObject {
+    
+    NSMutableArray* pendingImages;
+	NSMutableDictionary* loadedImages;
+	NSOperationQueue *downloadQueue;
+	ASIDownloadCache *cache;
+    
+}
+
++ (UIImage*)loadImage:(NSURL *)url;
+- (UIImage*)loadImage:(NSURL *)url;
+
++ (void) clearMemoryCache;
+- (void) clearMemoryCache;
+
++ (void) clearCache;
+- (void) clearCache;
+
+- (NSString*) cacheDirectory;
+@end

MyShows/Classes/ImageManager.m

+//
+//  ImageManager.m
+//  IOSBoilerplate
+//
+//  Copyright (c) 2011 Alberto Gimeno Brieba
+//  
+//  Permission is hereby granted, free of charge, to any person
+//  obtaining a copy of this software and associated documentation
+//  files (the "Software"), to deal in the Software without
+//  restriction, including without limitation the rights to use,
+//  copy, modify, merge, publish, distribute, sublicense, and/or sell
+//  copies of the Software, and to permit persons to whom the
+//  Software is furnished to do so, subject to the following
+//  conditions:
+//  
+//  The above copyright notice and this permission notice shall be
+//  included in all copies or substantial portions of the Software.
+//  
+//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+//  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+//  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+//  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+//  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+//  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+//  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+//  OTHER DEALINGS IN THE SOFTWARE.
+//  
+
+#import "ImageManager.h"
+#import "ASIHTTPRequest.h"
+#import "AppDelegate.h"
+
+@implementation ImageManager
+
+- (id)init
+{
+    self = [super init];
+    if (self) {
+        pendingImages = [[NSMutableArray alloc] initWithCapacity:10];
+        loadedImages = [[NSMutableDictionary alloc] initWithCapacity:50];
+        downloadQueue = [[NSOperationQueue alloc] init];
+        [downloadQueue setMaxConcurrentOperationCount:3];
+    }
+    
+    return self;
+}
+
+static ImageManager *sharedSingleton;
+
++ (void)initialize {
+    static BOOL initialized = NO;
+    if(!initialized) {
+        initialized = YES;
+        sharedSingleton = [[ImageManager alloc] init];
+    }
+}
+
+- (NSString*) cacheDirectory {
+	return [NSHomeDirectory() stringByAppendingString:@"/Library/Caches/images/"];
+}
+
++ (UIImage*)loadImage:(NSURL *)url {
+    return [sharedSingleton loadImage:url];
+}
+
+- (UIImage*)loadImage:(NSURL *)url {
+	// NSLog(@"url = %@", url);
+	UIImage* img = [loadedImages objectForKey:url];
+    if (img) {
+        return img;
+    }
+    
+    if ([pendingImages containsObject:url]) {
+        // already being downloaded
+        return nil;
+    }
+    
+    [pendingImages addObject:url];
+    
+    ASIHTTPRequest *request = [[ASIHTTPRequest alloc] initWithURL:url];
+    /*
+     Here you can configure a cache system
+     
+     if (!cache) {
+     ASIDownloadCache* _cache = [[ASIDownloadCache alloc] init];
+     self.cache = _cache;
+     [_cache release];
+     [cache setStoragePath:[self cacheDirectory]];
+     }
+     // [request setDownloadCache:cache];
+     // [request setCachePolicy:ASIOnlyLoadIfNotCachedCachePolicy];
+     // [request setCacheStoragePolicy:ASICachePermanentlyCacheStoragePolicy];
+     
+     */
+    
+    [request setDelegate:self];
+    [request setDidFinishSelector:@selector(imageDone:)];
+    [request setDidFailSelector:@selector(imageWentWrong:)];
+    [downloadQueue addOperation:request];
+    return nil;
+}
+
+- (void)imageDone:(ASIHTTPRequest*)request {
+	UIImage* image = [UIImage imageWithData:[request responseData]];
+	if (!image) {
+		return;
+	}
+	
+	// NSLog(@"image done. %@ cached = %d", request.originalURL, [request didUseCachedResponse]);
+	
+	[pendingImages removeObject:request.originalURL];
+	[loadedImages setObject:image forKey:request.originalURL];
+	
+	SEL selector = @selector(imageLoaded:withURL:);
+        
+    AppDelegate *delegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
+    UIViewController *controller = [[delegate window] rootViewController]; 
+	
+    if ([controller respondsToSelector:selector]) {
+			[controller performSelector:selector withObject:image withObject:request.originalURL];
+    }
+}
+
+- (void)imageWentWrong:(ASIHTTPRequest*)request {
+	NSLog(@"image went wrong %@", [[request error] localizedDescription]);
+	[pendingImages removeObject:request.originalURL]; // TODO should not try to load the image again for a while
+}
+
++ (void) clearMemoryCache {
+    [sharedSingleton clearMemoryCache];
+}
+
+- (void) clearMemoryCache {
+	[loadedImages removeAllObjects];
+	[pendingImages removeAllObjects];
+}
+
++ (void) clearCache {
+    [sharedSingleton clearCache];
+}
+
+- (void) clearCache {
+    NSFileManager* fs = [NSFileManager defaultManager];
+	// BOOL b = 
+	[fs removeItemAtPath:[self cacheDirectory] error:NULL];
+    
+}
+
+@end

MyShows/Controllers/LoginViewController.m

 
 #import "LoginViewController.h"
 #import "NSString+Hash.h"
+#import "SVProgressHUD.h"
+
 
 @implementation LoginViewController
 @synthesize login, password;
 
-- (IBAction)signInButtonPressed:(id)sender {
-    NSLog(@"Signing in...");
-    
-    if ([login.text length] != 0 && [password.text length] != 0){
-        NSDictionary *params = [[NSDictionary alloc] initWithObjectsAndKeys:
-                                login.text, @"login",
-                                [NSString Md5Hash:password.text], @"password", 
-                                nil];
-        
-        [api sendRequest:@"login" queryParams:params];
-    }
-    else {
-        UIAlertView *alert = [[UIAlertView alloc]
-                              initWithTitle:@"Please, enter your username and password"
-														message:nil
-													   delegate:nil
-                                              cancelButtonTitle:@"OK"
-											  otherButtonTitles:nil];
-        [alert show];
-    }
-}
-
-- (IBAction)signUpButtonPressed:(id)sender {
-    NSLog(@"Signing up...");
-}
-
-- (void) didRequestSucceed:(NSDictionary *) data {
-    NSLog(@"Returned to view after successful request with data %@", data);
-    int status = [(NSNumber *)[data objectForKey:@"status"] intValue];
-    
-    if (status == 200 ) {
-        [self performSegueWithIdentifier:@"login_to_main_controller" sender:nil];
-    }
-    else {
-        UIAlertView *alert = [[UIAlertView alloc]
-                              initWithTitle:@""
-                              message:nil
-                              delegate:nil
-                              cancelButtonTitle:@"OK"
-                              otherButtonTitles:nil];
-        if (status == 404) {
-            [alert setTitle:@"User not found"];
-        }
-        else if (status == 403) {
-            [alert setTitle:@"Wrong credentials"];
-        }
-        [alert show];
-    }
-}
-
-- (void) didRequestFailed:(NSDictionary *) data {
-}
-
-- (IBAction)closeKeyBoard:(id)sender {
-    [login resignFirstResponder];
-    [password resignFirstResponder];
-}
-
 - (void)didReceiveMemoryWarning
 {
     [super didReceiveMemoryWarning];
     return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
 }
 
+#pragma mark - ApiDelegate
+
+- (void) didRequestSucceed:(NSDictionary *) data {
+    NSLog(@"Returned to view after successful request with data %@", data);
+    int status = [(NSNumber *)[data objectForKey:@"status"] intValue];
+    
+    if (status == 200 ) {
+        [SVProgressHUD dismiss];
+        [self performSegueWithIdentifier:@"login_to_main_controller" sender:nil];
+    }
+    else {
+        if (status == 404) {
+            [SVProgressHUD dismissWithError:@"User not found"];
+        }
+        else if (status == 403) {
+            [SVProgressHUD dismissWithError:@"Wrong credentials"];
+        }
+        else {
+            [SVProgressHUD dismiss];
+        }
+    }
+}
+
+- (void) didRequestFailed:(NSDictionary *) data {
+    
+}
+
+#pragma mark - Actions
+- (IBAction)signInButtonPressed:(id)sender {
+    NSLog(@"Signing in...");
+    
+    if ([login.text length] != 0 && [password.text length] != 0){
+        NSDictionary *params = [[NSDictionary alloc] initWithObjectsAndKeys:
+                                login.text, @"login",
+                                [NSString Md5Hash:password.text], @"password", 
+                                nil];
+        
+        [SVProgressHUD showInView:self.view];
+        [api sendRequest:@"login" queryParams:params];
+    }
+    else {
+        UIAlertView *alert = [[UIAlertView alloc]
+                              initWithTitle:@"Please, enter your username and password"
+                              message:nil
+                              delegate:nil
+                              cancelButtonTitle:@"OK"
+                              otherButtonTitles:nil];
+        [alert show];
+    }
+}
+
+- (IBAction)signUpButtonPressed:(id)sender {
+    NSLog(@"Signing up...");
+}
+
+- (IBAction)closeKeyBoard:(id)sender {
+    [login resignFirstResponder];
+    [password resignFirstResponder];
+}
+
+
 @end

MyShows/Controllers/ShowsListTableViewController.h

 
 #import <UIKit/UIKit.h>
 #import "MyShowsApi.h"
+#import "ImageManager.h"
 
-@interface ShowsListTableViewController : UITableViewController <ApiDelegate> {
+@interface ShowsListTableViewController : UITableViewController <ApiDelegate, AsyncImageDelegate> {
     MyShowsApi *api;
     NSMutableArray *shows;
     
     IBOutlet UITableView *showsTable;
 }
 
+- (void)refreshCellsWithImage:(UIImage*)image fromURL:(NSURL*)url;
+
 @end

MyShows/Controllers/ShowsListTableViewController.m

 //
 
 #import "ShowsListTableViewController.h"
+#import "SVProgressHUD.h"
+#import "AsyncImageCell.h"
 
 
 @implementation ShowsListTableViewController
 {
     [super viewDidAppear:animated];
     
+    [SVProgressHUD showInView:self.view];
     [api sendRequest:@"shows" queryParams:nil];
 }
 
     return (interfaceOrientation == UIInterfaceOrientationPortrait);
 }
 
-#pragma mark ApiDelegate
+#pragma mark - ApiDelegate
 
 - (void)didRequestSucceed:(NSDictionary *)data {
     NSLog(@"Returned to view after successful request");
     int status = [(NSNumber *)[data objectForKey:@"status"] intValue];
     
     if (status == 200 ) {
+        [SVProgressHUD dismiss];
+        
         id key;
         
         NSDictionary *loaded_shows = [[data objectForKey:@"data"] copy];
         [showsTable reloadData];
     }
     else {
-        UIAlertView *alert = [[UIAlertView alloc]
-                              initWithTitle:@""
-                              message:nil
-                              delegate:nil
-                              cancelButtonTitle:@"OK"
-                              otherButtonTitles:nil];
         if (status == 401) {
-            [alert setTitle:@"Log in, please"];
+            [SVProgressHUD dismissWithError:@"Log in, please"];
+        }
+        else {
+            [SVProgressHUD dismiss];
         }
-        [alert show];
     }
 }
 
+- (void)didRequestFailed:(NSDictionary *)data {
+    
+}
+
+#pragma mark - AsyncImageDelegate
+- (void) imageLoaded:(UIImage *)image withUrl:(NSURL *)url {
+    [self refreshCellsWithImage:image fromURL:url];
+}
+
+#pragma mark - Custom methods
+
+- (void) refreshCellsWithImage:(UIImage *)image fromURL:(NSURL *)url {
+    NSArray *cells = [showsTable visibleCells];
+
+    SEL selector = @selector(imageLoaded:withURL:);
+    
+    for (id cell in cells) {
+        if ([cell respondsToSelector:selector]) {
+            [cell performSelector:selector withObject:image withObject:url];
+        }
+    }
+}
 #pragma mark - Table view data source
 
 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
 {
     static NSString *CellIdentifier = @"Cell";
     
-    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
+    AsyncImageCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
     if (cell == nil) {
-        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
+        cell = [[AsyncImageCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
     }
     
     // Configure the cell...
     }
     
     cell.textLabel.text = [(NSDictionary *)[shows objectAtIndex:[indexPath row]] objectForKey:@"title"];
-    
-    //UIImage *showImage = [UIImage 
-    
+        
+    cell.imageURL = [NSURL URLWithString:[(NSDictionary *)[shows objectAtIndex:[indexPath row]] objectForKey:@"image"]];
     return cell;
 }
 
Add a comment to this file

MyShows/Libraries/SVProgressHUD/SVProgressHUD.bundle/error.png

Added
New image
Add a comment to this file

MyShows/Libraries/SVProgressHUD/SVProgressHUD.bundle/error@2x.png

Added
New image
Add a comment to this file

MyShows/Libraries/SVProgressHUD/SVProgressHUD.bundle/success.png

Added
New image
Add a comment to this file

MyShows/Libraries/SVProgressHUD/SVProgressHUD.bundle/success@2x.png

Added
New image

MyShows/Libraries/SVProgressHUD/SVProgressHUD.h

+//
+//  SVProgressHUD.h
+//
+//  Created by Sam Vermette on 27.03.11.
+//  Copyright 2011 Sam Vermette. All rights reserved.
+//
+
+typedef enum {
+    SVProgressHUDMaskTypeNone, // allow user interactions while HUD is displayed
+    SVProgressHUDMaskTypeClear, // don't allow
+    SVProgressHUDMaskTypeBlack // don't allow and dim the UI in the back of the HUD
+} SVProgressHUDMaskType;
+
+@interface SVProgressHUD : UIView {
+    UIView *_maskView;
+}
+
+/* 
+showInView:(UIView*)                -> the view you're adding the HUD to. By default, it's added to the keyWindow rootViewController, or the keyWindow if the rootViewController is nil
+status:(NSString*)                  -> a loading status for the HUD (different from the success and error messages)
+networkIndicator:(BOOL)             -> whether or not the HUD also triggers the UIApplication's network activity indicator (default is YES)
+posY:(CGFloat)                      -> the vertical position of the HUD (default is viewHeight/2-viewHeight/8)
+maskType:(SVProgressHUDMaskType)    -> set whether to allow user interactions while HUD is displayed
+*/
+ 
++ (void)show;
++ (void)showInView:(UIView*)view;
++ (void)showInView:(UIView*)view status:(NSString*)string;
++ (void)showInView:(UIView*)view status:(NSString*)string networkIndicator:(BOOL)show;
++ (void)showInView:(UIView*)view status:(NSString*)string networkIndicator:(BOOL)show posY:(CGFloat)posY;
++ (void)showInView:(UIView*)view status:(NSString*)string networkIndicator:(BOOL)show posY:(CGFloat)posY maskType:(SVProgressHUDMaskType)maskType;
+
++ (void)setStatus:(NSString*)string; // change the HUD loading status while it's showing
+
++ (void)dismiss; // simply dismiss the HUD with a fade+scale out animation
++ (void)dismissWithSuccess:(NSString*)successString; // also displays the success icon image
++ (void)dismissWithSuccess:(NSString*)successString afterDelay:(NSTimeInterval)seconds;
++ (void)dismissWithError:(NSString*)errorString; // also displays the error icon image
++ (void)dismissWithError:(NSString*)errorString afterDelay:(NSTimeInterval)seconds;
+
+@end

MyShows/Libraries/SVProgressHUD/SVProgressHUD.m

+//
+//  SVProgressHUD.m
+//
+//  Created by Sam Vermette on 27.03.11.
+//  Copyright 2011 Sam Vermette. All rights reserved.
+//
+
+#import "SVProgressHUD.h"
+#import <QuartzCore/QuartzCore.h>
+
+@interface SVProgressHUD ()
+
+@property (nonatomic, retain) NSTimer *fadeOutTimer;
+@property (nonatomic, retain) UILabel *stringLabel;
+@property (nonatomic, retain) UIImageView *imageView;
+@property (nonatomic, retain) UIActivityIndicatorView *spinnerView;
+
+- (void)showInView:(UIView*)view status:(NSString*)string networkIndicator:(BOOL)show posY:(CGFloat)posY maskType:(SVProgressHUDMaskType)maskType;
+- (void)setStatus:(NSString*)string;
+
+- (void)dismiss;
+- (void)dismissWithStatus:(NSString*)string error:(BOOL)error;
+- (void)dismissWithStatus:(NSString*)string error:(BOOL)error afterDelay:(NSTimeInterval)seconds;
+
+- (void)memoryWarning:(NSNotification*)notification;
+
+@end
+
+
+@implementation SVProgressHUD
+
+@synthesize fadeOutTimer, stringLabel, imageView, spinnerView;
+
+static SVProgressHUD *sharedView = nil;
+
++ (SVProgressHUD*)sharedView {
+	
+	if(sharedView == nil)
+		sharedView = [[SVProgressHUD alloc] initWithFrame:CGRectZero];
+	
+	return sharedView;
+}
+
++ (void)setStatus:(NSString *)string {
+	[[SVProgressHUD sharedView] setStatus:string];
+}
+
+
+#pragma mark - Show Methods
+
++ (void)show {
+	[SVProgressHUD showInView:nil status:nil];
+}
+
+
++ (void)showInView:(UIView*)view {
+	[SVProgressHUD showInView:view status:nil];
+}
+
+
++ (void)showInView:(UIView*)view status:(NSString*)string {
+	[SVProgressHUD showInView:view status:string networkIndicator:YES];
+}
+
+
++ (void)showInView:(UIView*)view status:(NSString*)string networkIndicator:(BOOL)show {
+	[SVProgressHUD showInView:view status:string networkIndicator:show posY:-1];
+}
+
++ (void)showInView:(UIView*)view status:(NSString*)string networkIndicator:(BOOL)show posY:(CGFloat)posY {
+    [SVProgressHUD showInView:view status:string networkIndicator:show posY:posY maskType:SVProgressHUDMaskTypeNone];
+}
+
+
++ (void)showInView:(UIView*)view status:(NSString*)string networkIndicator:(BOOL)show posY:(CGFloat)posY maskType:(SVProgressHUDMaskType)maskType {
+	
+    BOOL addingToWindow;
+    
+    if(!view) {
+        UIWindow* keyWindow = [UIApplication sharedApplication].keyWindow;
+        addingToWindow = YES;
+        
+        if ([keyWindow respondsToSelector:@selector(rootViewController)]) {
+            //Use the rootViewController to reflect the device orientation
+            view = keyWindow.rootViewController.view;
+        }
+        
+        if (view == nil) view = keyWindow;
+    }
+	
+	if(posY == -1) {
+		posY = floor(CGRectGetHeight(view.bounds)/2);
+        
+        if(addingToWindow)
+            posY -= floor(CGRectGetHeight(view.bounds)/18); // move slightly towards the top
+    }
+
+	[[SVProgressHUD sharedView] showInView:view status:string networkIndicator:show posY:posY maskType:maskType];
+}
+
+
+#pragma mark - Dismiss Methods
+
++ (void)dismiss {
+	[[SVProgressHUD sharedView] dismiss];
+}
+
++ (void)dismissWithSuccess:(NSString*)successString {
+	[[SVProgressHUD sharedView] dismissWithStatus:successString error:NO];
+}
+
++ (void)dismissWithSuccess:(NSString *)successString afterDelay:(NSTimeInterval)seconds {
+    [[SVProgressHUD sharedView] dismissWithStatus:successString error:NO afterDelay:seconds];
+}
+
++ (void)dismissWithError:(NSString*)errorString {
+	[[SVProgressHUD sharedView] dismissWithStatus:errorString error:YES];
+}
+
++ (void)dismissWithError:(NSString *)errorString afterDelay:(NSTimeInterval)seconds {
+    [[SVProgressHUD sharedView] dismissWithStatus:errorString error:YES afterDelay:seconds];
+}
+
+
+#pragma mark - Instance Methods
+
+- (void)dealloc {
+	
+	if(fadeOutTimer != nil)
+		[fadeOutTimer invalidate], [fadeOutTimer release], fadeOutTimer = nil;
+	
+    [[NSNotificationCenter defaultCenter] removeObserver:self];
+    
+    [super dealloc];
+}
+
+- (id)initWithFrame:(CGRect)frame {
+	
+    if ((self = [super initWithFrame:frame])) {
+		self.layer.cornerRadius = 10;
+		self.backgroundColor = [UIColor colorWithWhite:0 alpha:0.8];
+		self.userInteractionEnabled = NO;
+		self.layer.opacity = 0;
+        self.autoresizingMask = (UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleTopMargin |
+                                 UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleLeftMargin);
+        
+        [[NSNotificationCenter defaultCenter] addObserver:self 
+                                                 selector:@selector(memoryWarning:) 
+                                                     name:UIApplicationDidReceiveMemoryWarningNotification
+                                                   object:nil];
+    }
+	
+    return self;
+}
+
+- (void)setStatus:(NSString *)string {
+	
+    CGFloat hudWidth = 100;
+    
+	CGFloat stringWidth = [string sizeWithFont:self.stringLabel.font].width+28;
+	
+	if(stringWidth > hudWidth)
+		hudWidth = ceil(stringWidth/2)*2;
+	
+	self.bounds = CGRectMake(0, 0, hudWidth, 100);
+	
+	self.imageView.center = CGPointMake(CGRectGetWidth(self.bounds)/2, 36);
+	
+	self.stringLabel.hidden = NO;
+	self.stringLabel.text = string;
+	self.stringLabel.frame = CGRectMake(0, 66, CGRectGetWidth(self.bounds), 20);
+	
+	if(string)
+		self.spinnerView.center = CGPointMake(ceil(CGRectGetWidth(self.bounds)/2)+0.5, 40.5);
+	else
+		self.spinnerView.center = CGPointMake(ceil(CGRectGetWidth(self.bounds)/2)+0.5, ceil(self.bounds.size.height/2)+0.5);
+}
+
+
+- (void)showInView:(UIView*)view status:(NSString*)string networkIndicator:(BOOL)show posY:(CGFloat)posY maskType:(SVProgressHUDMaskType)maskType {
+	
+	if(fadeOutTimer != nil)
+		[fadeOutTimer invalidate], [fadeOutTimer release], fadeOutTimer = nil;
+	
+	if(show)
+		[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
+	else
+		[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
+	
+	self.imageView.hidden = YES;
+	
+	[self setStatus:string];
+	[spinnerView startAnimating];
+	
+    if (!_maskView && maskType != SVProgressHUDMaskTypeNone) {
+        _maskView = [[UIView alloc] initWithFrame:view.bounds];
+        _maskView.backgroundColor = [UIColor clearColor];
+        _maskView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
+        [view addSubview:_maskView];
+        [_maskView release];
+    }
+    
+	if(![sharedView isDescendantOfView:view]) {
+		sharedView.layer.opacity = 0;
+		[view addSubview:sharedView];
+	}
+	
+	if(sharedView.layer.opacity != 1) {
+		
+		self.center = CGPointMake(CGRectGetWidth(self.superview.bounds)/2, posY);
+		
+		self.layer.transform = CATransform3DScale(CATransform3DMakeTranslation(0, 0, 0), 1.3, 1.3, 1);
+		self.layer.opacity = 0.3;
+		
+		[UIView animateWithDuration:0.15
+							  delay:0
+							options:UIViewAnimationOptionAllowUserInteraction | UIViewAnimationCurveEaseOut
+						 animations:^{	
+							 self.layer.transform = CATransform3DScale(CATransform3DMakeTranslation(0, 0, 0), 1, 1, 1);
+							 self.layer.opacity = 1;
+                             
+                             if (_maskView && maskType == SVProgressHUDMaskTypeBlack) {
+                                 _maskView.backgroundColor = [UIColor colorWithWhite:0 alpha:0.5];
+                             }
+                             
+						 }
+						 completion:NULL];
+	}
+}
+
+
+- (void)dismiss {
+	
+	[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
+	
+	[UIView animateWithDuration:0.15
+						  delay:0
+						options:UIViewAnimationCurveEaseIn | UIViewAnimationOptionAllowUserInteraction
+					 animations:^{	
+						 self.layer.transform = CATransform3DScale(CATransform3DMakeTranslation(0, 0, 0), 0.8, 0.8, 1.0);
+						 self.layer.opacity = 0;
+                         if (_maskView) {
+                             _maskView.backgroundColor = [UIColor clearColor];
+                         }
+					 }
+					 completion:^(BOOL finished){ 
+                         if(self.layer.opacity == 0) {
+                             [_maskView removeFromSuperview];
+                             _maskView = nil;
+                             [self removeFromSuperview]; 
+                         }
+                     }];
+}
+
+
+- (void)dismissWithStatus:(NSString*)string error:(BOOL)error {
+	[self dismissWithStatus:string error:error afterDelay:0.9];
+}
+
+
+- (void)dismissWithStatus:(NSString *)string error:(BOOL)error afterDelay:(NSTimeInterval)seconds {
+    [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
+	
+	if(error)
+		self.imageView.image = [UIImage imageNamed:@"SVProgressHUD.bundle/error.png"];
+	else
+		self.imageView.image = [UIImage imageNamed:@"SVProgressHUD.bundle/success.png"];
+	
+	self.imageView.hidden = NO;
+	
+	[self setStatus:string];
+	
+	[self.spinnerView stopAnimating];
+    
+	if(fadeOutTimer != nil)
+		[fadeOutTimer invalidate], [fadeOutTimer release], fadeOutTimer = nil;
+	
+	fadeOutTimer = [[NSTimer scheduledTimerWithTimeInterval:seconds target:self selector:@selector(dismiss) userInfo:nil repeats:NO] retain];
+}
+
+#pragma mark - Getters
+
+- (UILabel *)stringLabel {
+    
+    if (stringLabel == nil) {
+        stringLabel = [[UILabel alloc] initWithFrame:CGRectZero];
+		stringLabel.textColor = [UIColor whiteColor];
+		stringLabel.backgroundColor = [UIColor clearColor];
+		stringLabel.adjustsFontSizeToFitWidth = YES;
+		stringLabel.textAlignment = UITextAlignmentCenter;
+		stringLabel.baselineAdjustment = UIBaselineAdjustmentAlignCenters;
+		stringLabel.font = [UIFont boldSystemFontOfSize:16];
+		stringLabel.shadowColor = [UIColor blackColor];
+		stringLabel.shadowOffset = CGSizeMake(0, -1);
+		[self addSubview:stringLabel];
+		[stringLabel release];
+    }
+    
+    return stringLabel;
+}
+
+- (UIImageView *)imageView {
+    
+    if (imageView == nil) {
+        imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 28, 28)];
+		[self addSubview:imageView];
+		[imageView release];
+    }
+    
+    return imageView;
+}
+
+- (UIActivityIndicatorView *)spinnerView {
+    
+    if (spinnerView == nil) {
+        spinnerView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
+		spinnerView.hidesWhenStopped = YES;
+		spinnerView.bounds = CGRectMake(0, 0, 37, 37);
+		[self addSubview:spinnerView];
+		[spinnerView release];
+    }
+    
+    return spinnerView;
+}
+
+#pragma mark - MemoryWarning
+
+- (void)memoryWarning:(NSNotification *)notification {
+	
+    if (sharedView.superview == nil) {
+        [sharedView release];
+        sharedView = nil;
+    }
+}
+
+@end
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.