From 814a8d8fbea00a19f43551f2e35d101a0bc8d982 Mon Sep 17 00:00:00 2001 From: Miltiadis Vasilakis Date: Fri, 28 Dec 2012 21:58:21 +0200 Subject: [PATCH] Improve open file UX Allow cancelation of download, or removal from cache, from file details. When opening a non downloaded file, load file details view and start downloading. Improve cache management. Fix bugs. Improve open file menu placement in iPad, in iOS 6. --- Classes/AccountManager.h | 2 - Classes/AccountManager.m | 31 ++-- Classes/FolderViewController.m | 21 ++- Classes/OpenStackAppDelegate.h | 19 +- Classes/OpenStackAppDelegate.m | 121 ++++++++++++- Classes/SettingsViewController.m | 19 +- Classes/StorageObjectViewController.h | 9 +- Classes/StorageObjectViewController.m | 312 +++++++++++++++++++++------------ OpenStack-Info.plist | 4 +- 9 files changed, 362 insertions(+), 176 deletions(-) diff --git a/Classes/AccountManager.h b/Classes/AccountManager.h index 3475180..57009a3 100755 --- a/Classes/AccountManager.h +++ b/Classes/AccountManager.h @@ -16,13 +16,11 @@ @interface AccountManager : NSObject { OpenStackAccount *account; ASINetworkQueue *queue; - NSMutableDictionary *objectDownloadRequests; } @property (nonatomic, retain) ASINetworkQueue *queue; @property (nonatomic, assign) OpenStackAccount *account; -@property (nonatomic, retain) NSMutableDictionary *objectDownloadRequests; - (NSString *)notificationName:(NSString *)key identifier:(NSString *)identifier; - (void)notify:(NSString *)name request:(OpenStackRequest *)request; diff --git a/Classes/AccountManager.m b/Classes/AccountManager.m index 4e89a6a..66f68f6 100755 --- a/Classes/AccountManager.m +++ b/Classes/AccountManager.m @@ -22,7 +22,7 @@ @implementation AccountManager -@synthesize account, queue, objectDownloadRequests; +@synthesize account, queue; #pragma mark - Callbacks @@ -224,23 +224,22 @@ if (requestUserInfo) { request.userInfo = requestUserInfo; } - if (!objectDownloadRequests) - self.objectDownloadRequests = [NSMutableDictionary dictionary]; - [objectDownloadRequests setObject:request forKey:object.fullPath]; - return [self callbackWithRequest:request success:^(OpenStackRequest *request) { + + OpenStackAppDelegate *app = [[UIApplication sharedApplication] delegate]; + [app setObjectDownloadRequest:request forAccount:account container:container object:object]; + return [self callbackWithRequest:request + success:^(OpenStackRequest *request) { if (!object.hash) object.hash = [request.responseHeaders objectForKey:@"X-Object-Hash"]; - OpenStackAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate]; - NSString *filePath = [appDelegate.cacheDirectoryPath stringByAppendingFormat:@"/%@.%@", object.hash, object.name.pathExtension]; + OpenStackAppDelegate *app = [[UIApplication sharedApplication] delegate]; + NSString *filePath = [app.cacheDirectoryPath stringByAppendingFormat:@"/%@.%@", object.hash, object.name.pathExtension]; [[request responseData] writeToFile:filePath atomically:YES]; - @synchronized(appDelegate.cachedObjectsDictionary) { - [appDelegate.cachedObjectsDictionary setObject:filePath forKey:object.hash]; - [appDelegate saveCacheDictionary]; - } - [objectDownloadRequests removeObjectForKey:object.fullPath]; + [app setCacheFilePath:filePath forHash:object.hash]; + [app removeObjectDownloadRequestForAccount:account container:container object:object]; } - failure:^(OpenStackRequest *request) { - [objectDownloadRequests removeObjectForKey:object.fullPath]; + failure:^(OpenStackRequest *request) { + OpenStackAppDelegate *app = [[UIApplication sharedApplication] delegate]; + [app removeObjectDownloadRequestForAccount:account container:container object:object]; }]; } @@ -273,11 +272,9 @@ return [self callbackWithRequest:request]; } -#pragma mark - -#pragma mark Memory Management +#pragma mark - Memory Management - (void)dealloc { - [objectDownloadRequests release]; [super dealloc]; } diff --git a/Classes/FolderViewController.m b/Classes/FolderViewController.m index f8a3f5f..d73d3a1 100755 --- a/Classes/FolderViewController.m +++ b/Classes/FolderViewController.m @@ -527,18 +527,9 @@ return [self.folder sortedContentsUsingFilter:self.searchFilter [vc release]; } else { StorageObject *cellObject = (StorageObject *)item; - BOOL fileDownloaded = NO; OpenStackAppDelegate *app = [[UIApplication sharedApplication] delegate]; - NSString *filePath = [app.cachedObjectsDictionary objectForKey:cellObject.hash]; + NSString *filePath = [app cacheFilePathForHash:cellObject.hash]; if (filePath) { - if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) { - fileDownloaded = YES; - } else { - [app.cachedObjectsDictionary removeObjectForKey:cellObject.hash]; - [app saveCacheDictionary]; - } - } - if (fileDownloaded) { self.documentInteractionController = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:filePath]]; self.documentInteractionController.delegate = self; self.documentInteractionController.name = cellObject.name; @@ -560,7 +551,15 @@ return [self.folder sortedContentsUsingFilter:self.searchFilter } } } else { - // XXX else load download view controller + StorageObjectViewController *vc = [[StorageObjectViewController alloc] initWithNibName:@"StorageObjectViewController" bundle:nil]; + vc.account = self.account; + vc.container = self.container; + vc.folder = self.folder; + vc.object = cellObject; + vc.folderViewController = self; + [self.navigationController pushViewController:vc animated:YES]; + [vc downloadFileForAction:StorageObjectActionOpenFile]; + [vc release]; } [aTableView deselectRowAtIndexPath:indexPath animated:YES]; } diff --git a/Classes/OpenStackAppDelegate.h b/Classes/OpenStackAppDelegate.h index cefbac3..e3a35c4 100755 --- a/Classes/OpenStackAppDelegate.h +++ b/Classes/OpenStackAppDelegate.h @@ -6,7 +6,7 @@ // The OpenStack project is provided under the Apache 2.0 license. // -@class RootViewController; +@class RootViewController, OpenStackRequest, OpenStackAccount, Container, StorageObject; #define CACHED_OBJECTS_ARCHIVE_KEY @"cachedObjectsDictionary" #define CACHE_DICT_ARCHIVE_NAME @"cache.dict" @@ -22,6 +22,7 @@ NSMutableDictionary *cachedObjectsDictionary; NSString *cacheDictionaryFilePath; NSString *cacheDirectoryPath; + NSMutableDictionary *objectDownloadRequests; BOOL gotToken; } @@ -35,8 +36,24 @@ @property (nonatomic, retain) NSMutableDictionary *cachedObjectsDictionary; @property (nonatomic, copy) NSString *cacheDictionaryFilePath; @property (nonatomic, copy) NSString *cacheDirectoryPath; +@property (nonatomic, readonly) NSMutableDictionary *objectDownloadRequests; +- (NSString *)cacheFilePathForHash:(NSString *)hash; +- (void)setCacheFilePath:(NSString *)filePath forHash:(NSString *)hash; +- (BOOL)removeCacheObjectForHash:(NSString *)hash; +- (void)removeAllCacheObjects; - (void)saveCacheDictionary; +- (OpenStackRequest *)objectDownloadRequestForAccount:(OpenStackAccount *)account + container:(Container *)container + object:(StorageObject *)object; +- (void)setObjectDownloadRequest:(OpenStackRequest *)request + forAccount:(OpenStackAccount *)account + container:(Container *)container + object:(StorageObject *)object; +- (void)removeObjectDownloadRequestForAccount:(OpenStackAccount *)account + container:(Container *)container + object:(StorageObject *)object; + @end diff --git a/Classes/OpenStackAppDelegate.m b/Classes/OpenStackAppDelegate.m index 31b5d92..a073ff1 100755 --- a/Classes/OpenStackAppDelegate.m +++ b/Classes/OpenStackAppDelegate.m @@ -8,17 +8,15 @@ #import "OpenStackAppDelegate.h" #import "RootViewController.h" -#import "OpenStackAccount.h" #import "Keychain.h" - #import "JSON.h" #import "Archiver.h" #import "Provider.h" - #import "OpenStackAccount.h" - +#import "Container.h" +#import "StorageObject.h" +#import "OpenStackRequest.h" #import "PithosImageViewController.h" - #import "RootViewController.h" #import "PasscodeViewController.h" #import "AccountDetailsViewController.h" @@ -37,6 +35,7 @@ @synthesize cachedObjectsDictionary; @synthesize cacheDictionaryFilePath; @synthesize cacheDirectoryPath; +@synthesize objectDownloadRequests; - (void)loadSettingsDefaults { // if settings haven't been set up yet, let's go ahead and set some sensible defaults @@ -59,6 +58,8 @@ [userDefaults setValue:cachedObjectsDictionary forKey:@"cachedObjectsDictionary"]; } + objectDownloadRequests = [[NSMutableDictionary alloc] init]; + [userDefaults synchronize]; } @@ -101,8 +102,7 @@ animated:NO]; } -#pragma mark - -#pragma mark Application lifecycle +#pragma mark - Application lifecycle - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { [self loadSettingsDefaults]; @@ -255,12 +255,116 @@ #pragma mark - Persistence +- (NSString *)cacheFilePathForHash:(NSString *)hash { + NSString *filePath = [self.cachedObjectsDictionary objectForKey:hash]; + if (![[NSFileManager defaultManager] fileExistsAtPath:filePath]) { + @synchronized(self.cachedObjectsDictionary) { + [self.cachedObjectsDictionary removeObjectForKey:hash]; + } + [self saveCacheDictionary]; + filePath = nil; + } + return filePath; +} + +- (void)setCacheFilePath:(NSString *)filePath forHash:(NSString *)hash { + @synchronized(self.cachedObjectsDictionary) { + [self.cachedObjectsDictionary setObject:filePath forKey:hash]; + [self saveCacheDictionary]; + } +} + +- (BOOL)removeCacheObjectForHash:(NSString *)hash { + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSError *error = nil; + NSString *filePath = [self.cachedObjectsDictionary objectForKey:hash]; + BOOL removed = NO; + @synchronized(self.cachedObjectsDictionary) { + [fileManager removeItemAtPath:filePath error:&error]; + if (error) { + UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error" + message:[NSString stringWithFormat:@"Error in removing cached file, %@", error.localizedDescription] + delegate:nil + cancelButtonTitle:@"OK" + otherButtonTitles:nil]; + [alert show]; + [alert release]; + } else { + removed = YES; + [self.cachedObjectsDictionary removeObjectForKey:hash]; + } + } + [self saveCacheDictionary]; + return removed; +} + +- (void)removeAllCacheObjects { + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSError *error = nil; + NSString *filePath; + NSDirectoryEnumerator *directoryEnumerator = [fileManager enumeratorAtPath:self.cacheDirectoryPath]; + @synchronized(self.cachedObjectsDictionary) { + while (filePath = [directoryEnumerator nextObject]) { + [fileManager removeItemAtPath:[NSString stringWithFormat:@"%@/%@", self.cacheDirectoryPath, filePath] error:&error]; + if (error) { + UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error" + message:[NSString stringWithFormat:@"Error in removing cached file, %@", error.localizedDescription] + delegate:nil + cancelButtonTitle:@"OK" + otherButtonTitles:nil]; + [alert show]; + [alert release]; + } else { + for (NSString *hash in [self.cachedObjectsDictionary allKeys]) + if ([[self.cachedObjectsDictionary objectForKey:hash] isEqualToString:filePath]) + [self.cachedObjectsDictionary removeObjectForKey:hash]; + } + } + } + [self saveCacheDictionary]; +} + - (void)saveCacheDictionary { NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; - [userDefaults setObject:cachedObjectsDictionary forKey:@"cachedObjectsDictionary"]; + [userDefaults setObject:self.cachedObjectsDictionary forKey:@"cachedObjectsDictionary"]; [userDefaults synchronize]; } +- (OpenStackRequest *)objectDownloadRequestForAccount:(OpenStackAccount *)account + container:(Container *)container + object:(StorageObject *)object { + return [[[self.objectDownloadRequests objectForKey:account.uuid] objectForKey:container.name] objectForKey:object.fullPath]; +} + +- (void)setObjectDownloadRequest:(OpenStackRequest *)request + forAccount:(OpenStackAccount *)account + container:(Container *)container + object:(StorageObject *)object { + NSMutableDictionary *accountObjectDownloadRequests = [self.objectDownloadRequests objectForKey:account.uuid]; + if (!accountObjectDownloadRequests) { + accountObjectDownloadRequests = [NSMutableDictionary dictionary]; + [self.objectDownloadRequests setObject:accountObjectDownloadRequests forKey:account.uuid]; + } + NSMutableDictionary *containerObjectDownloadRequests = [accountObjectDownloadRequests objectForKey:container.name]; + if (!containerObjectDownloadRequests) { + containerObjectDownloadRequests = [NSMutableDictionary dictionary]; + [accountObjectDownloadRequests setObject:containerObjectDownloadRequests forKey:container.name]; + } + [containerObjectDownloadRequests setObject:request forKey:object.fullPath]; +} + +- (void)removeObjectDownloadRequestForAccount:(OpenStackAccount *)account + container:(Container *)container + object:(StorageObject *)object { + NSMutableDictionary *accountObjectDownloadRequests = [self.objectDownloadRequests objectForKey:account.uuid]; + if (accountObjectDownloadRequests) { + NSMutableDictionary *containerObjectDownloadRequests = [accountObjectDownloadRequests objectForKey:container.name]; + if (containerObjectDownloadRequests) { + [containerObjectDownloadRequests removeObjectForKey:object.fullPath]; + } + } +} + #pragma mark - Memory management - (void)dealloc { @@ -271,6 +375,7 @@ [rootViewController release]; [window release]; [cachedObjectsDictionary release]; + [objectDownloadRequests release]; [super dealloc]; } diff --git a/Classes/SettingsViewController.m b/Classes/SettingsViewController.m index bb9087d..46465a8 100755 --- a/Classes/SettingsViewController.m +++ b/Classes/SettingsViewController.m @@ -92,23 +92,8 @@ [self.navigationController pushViewController:vc animated:YES]; [vc release]; } else if (indexPath.section == kCache) { - OpenStackAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate]; - NSFileManager *fileManager = [NSFileManager defaultManager]; - NSError *error = nil; - NSString *file; - NSDirectoryEnumerator *directoryEnumerator = [fileManager enumeratorAtPath:appDelegate.cacheDirectoryPath]; - @synchronized(appDelegate.cachedObjectsDictionary) { - while (file = [directoryEnumerator nextObject]) { - [fileManager removeItemAtPath:[NSString stringWithFormat:@"%@/%@",appDelegate.cacheDirectoryPath,file] error:&error]; - if (error) { - [self alert:@"Error" message:[NSString stringWithFormat:@"Error in removing cached file, %@", error.localizedDescription]]; - } else { - for (NSString *key in [appDelegate.cachedObjectsDictionary allKeys]) - if ([[appDelegate.cachedObjectsDictionary objectForKey:key] isEqualToString:file]) - [appDelegate.cachedObjectsDictionary removeObjectForKey:key]; - } - } - } + OpenStackAppDelegate *app = [[UIApplication sharedApplication] delegate]; + [app removeAllCacheObjects]; [self.tableView deselectRowAtIndexPath:indexPath animated:YES]; [self.tableView reloadData]; } else if (indexPath.section == kAbout) { diff --git a/Classes/StorageObjectViewController.h b/Classes/StorageObjectViewController.h index f122fb6..3336f1c 100755 --- a/Classes/StorageObjectViewController.h +++ b/Classes/StorageObjectViewController.h @@ -9,6 +9,12 @@ #import "ASIProgressDelegate.h" #import +enum { + StorageObjectActionOpenFile = 0, + StorageObjectActionMailFile = 1, +}; +typedef NSInteger StorageObjectAction; + @class OpenStackAccount, Container, Folder, StorageObject, AnimatedProgressView, FolderViewController; @interface StorageObjectViewController : UITableViewController { @@ -36,7 +42,6 @@ NSString *oldObjectSharingString; NSString *oldPublicURI; NSMutableDictionary *permissions; - NSIndexPath *actionSelectedIndexPath; NSString *versionID; } @@ -47,11 +52,11 @@ @property (nonatomic, retain) FolderViewController *folderViewController; @property (nonatomic, retain) NSString *oldPubicURI; @property (nonatomic, retain) UIDocumentInteractionController *documentInteractionController; -@property (nonatomic, retain) NSIndexPath *actionSelectedIndexPath; @property (nonatomic, assign) BOOL objectIsReadOnly; @property (nonatomic, retain) NSString *versionID; - (void)setProgress:(float)newProgress; - (void)reloadMetadataSection; +- (void)downloadFileForAction:(StorageObjectAction)action; @end diff --git a/Classes/StorageObjectViewController.m b/Classes/StorageObjectViewController.m index 8f68994..d203288 100755 --- a/Classes/StorageObjectViewController.m +++ b/Classes/StorageObjectViewController.m @@ -46,8 +46,18 @@ Size 123 KB Type text/plain Last Modified 2012-12-21 11:11:00 -Download File (if downloaded, Open File and Mail File as Attachment) -"After you download the file, you'll be able to attempt to open it and mail is as an attachment." +if fileDownloaded: + Open File + Mail File + Delete from Cache +else if fileDownloading: + Open File (disabled) + Mail File (disabled) + Downloading (progress view) + Cancel +else: + Open File + Mail File Metadata Key Value -> tap goes to a metadata item VC to edit or delete @@ -66,7 +76,7 @@ Delete Object @implementation StorageObjectViewController @synthesize account, container, folder, object, folderViewController; -@synthesize oldPubicURI, documentInteractionController, actionSelectedIndexPath, objectIsReadOnly, versionID; +@synthesize oldPubicURI, documentInteractionController, objectIsReadOnly, versionID; #pragma mark - View lifecycle @@ -104,12 +114,15 @@ Delete Object } downloadProgressView = [[AnimatedProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleDefault]; - fileDownloading = ([self.account.manager.objectDownloadRequests objectForKey:object.fullPath] != nil) ? YES : NO; - if (fileDownloading) { - OpenStackRequest *request = [self.account.manager.objectDownloadRequests objectForKey:object.fullPath]; - self.actionSelectedIndexPath = [request.userInfo objectForKey:@"actionSelectedIndexPath"]; - [request setDownloadProgressDelegate:self]; + fileDownloading = NO; + OpenStackAppDelegate *app = [[UIApplication sharedApplication] delegate]; + OpenStackRequest *request = [app objectDownloadRequestForAccount:account container:container object:object]; + if (request) { + fileDownloading = YES; + request.downloadProgressDelegate = self; + [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:kActions] withRowAnimation:UITableViewRowAnimationNone]; } + } - (void)viewWillAppear:(BOOL)animated { @@ -119,15 +132,10 @@ Delete Object NSIndexPath *selection = [self.tableView indexPathForSelectedRow]; if (selection) [self.tableView deselectRowAtIndexPath:selection animated:YES]; + OpenStackAppDelegate *app = [[UIApplication sharedApplication] delegate]; - if ([app.cachedObjectsDictionary objectForKey:object.hash] != nil) { - if ([[NSFileManager defaultManager] fileExistsAtPath:[app.cachedObjectsDictionary objectForKey:object.hash]]) { - fileDownloaded = YES; - } else { - fileDownloaded = NO; - [app.cachedObjectsDictionary removeObjectForKey:object.hash]; - [app saveCacheDictionary]; - } + if ([app cacheFilePathForHash:object.hash]) { + fileDownloaded = YES; } else { fileDownloaded = NO; } @@ -164,14 +172,20 @@ Delete Object if (object.metadata == nil) { [self reloadMetadataSection]; } + if (fileDownloading) { + [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:2 inSection:kActions] + atScrollPosition:UITableViewScrollPositionMiddle + animated:YES]; + } } #pragma mark - Memory management - (void)dealloc { if (fileDownloading) { - OpenStackRequest *request = [self.account.manager.objectDownloadRequests objectForKey:object.fullPath]; - [request setDownloadProgressDelegate:nil]; + OpenStackAppDelegate *app = [[UIApplication sharedApplication] delegate]; + OpenStackRequest *request = [app objectDownloadRequestForAccount:account container:container object:object]; + request.downloadProgressDelegate = nil; } [account release]; [downloadProgressView release]; @@ -180,7 +194,6 @@ Delete Object [objectIsPublicSwitch release]; [permissions release]; [documentInteractionController release]; - [actionSelectedIndexPath release]; [versionID release]; [super dealloc]; } @@ -232,6 +245,59 @@ Delete Object }]; } +- (void)openFile { + OpenStackAppDelegate *app = [[UIApplication sharedApplication] delegate]; + NSString *filePath = [app cacheFilePathForHash:object.hash]; + self.documentInteractionController = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:filePath]]; + self.documentInteractionController.delegate = self; + self.documentInteractionController.name = object.name; + + CGRect frameToPresentMenuFrom; + if ([[UIDevice currentDevice].systemVersion hasPrefix:@"6"]) { + frameToPresentMenuFrom = CGRectMake(0.0, + self.tableView.contentOffset.y, + self.view.frame.size.width, + 1.0); + } else { + UITableViewCell *openFileCell = [self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:kActions]]; + frameToPresentMenuFrom = CGRectMake(openFileCell.frame.origin.x, + openFileCell.frame.origin.y - self.tableView.contentOffset.y, + openFileCell.frame.size.width, + openFileCell.frame.size.height); + } + if (![self.documentInteractionController presentOptionsMenuFromRect:frameToPresentMenuFrom inView:self.view animated:YES]) { + if ([self.object isPlayableMedia]) { + MediaViewController *vc = [[MediaViewController alloc] initWithNibName:@"MediaViewController" bundle:nil]; + vc.container = self.container; + vc.object = self.object; + [self.navigationController pushViewController:vc animated:YES]; + [vc release]; + } else { + [self alert:@"Error" message:@"This file could not be opened."]; + } + } +} + +- (void)mailFile { + if (![MFMailComposeViewController canSendMail]) { + [self alert:@"Cannot send mail" message:@"Your device has not been configured for sending mail"]; + } else { + OpenStackAppDelegate *app = [[UIApplication sharedApplication] delegate]; + NSString *filePath = [app cacheFilePathForHash:object.hash]; + NSData *data = [NSData dataWithContentsOfURL:[NSURL fileURLWithPath:filePath]]; + + MFMailComposeViewController *vc = [[MFMailComposeViewController alloc] init]; + vc.mailComposeDelegate = self; + [vc setSubject:object.name]; + [vc addAttachmentData:data mimeType:object.contentType fileName:object.name]; + [vc setMessageBody:@"" isHTML:NO]; + if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) + vc.modalPresentationStyle = UIModalPresentationPageSheet; + [self presentModalViewController:vc animated:YES]; + [vc release]; + } +} + #pragma mark - Actions - (void)reloadMetadataSection { @@ -259,6 +325,44 @@ Delete Object }]; } +- (void)downloadFileForAction:(StorageObjectAction)action { + if (fileDownloading) + return; + fileDownloading = YES; + [downloadProgressView setProgress:0.0 animated:NO]; + [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:kActions] withRowAnimation:UITableViewRowAnimationNone]; + [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:2 inSection:kActions] + atScrollPosition:UITableViewScrollPositionMiddle + animated:YES]; + NSMutableDictionary *requestUserInfo = [NSDictionary dictionaryWithObject:[NSNumber numberWithInteger:action] forKey:@"action"]; + [[self.account.manager getObject:self.container object:self.object downloadProgressDelegate:self requestUserInfo:requestUserInfo version:versionID] + success:^(OpenStackRequest *request) { + if (request.isCancelled) { + fileDownloaded = NO; + fileDownloading = NO; + [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:kActions] withRowAnimation:UITableViewRowAnimationNone]; + } else { + fileDownloaded = YES; + fileDownloading = NO; + if ([self.navigationController.visibleViewController isEqual:self]) { + if ([[request.userInfo objectForKey:@"action"] integerValue] == StorageObjectActionMailFile) { + [self mailFile]; + } else { + [self openFile]; + } + } + [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:kActions] withRowAnimation:UITableViewRowAnimationNone]; + [self.folderViewController reloadData]; + } + } + failure:^(OpenStackRequest *request) { + fileDownloaded = NO; + fileDownloading = NO; + [self alert:@"File failed to download." request:request]; + [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:kActions] withRowAnimation:UITableViewRowAnimationNone]; + }]; +} + #pragma mark - UITableViewDataSource - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { @@ -279,7 +383,13 @@ Delete Object if (section == kDetails) { return (object.lastModifiedString ? 5: 4); } else if (section == kActions) { - return 2; + if (fileDownloaded) { + return 3; + } else if (fileDownloading) { + return 4; + } else { + return 2; + } } else if (section == kMetadata) { if (objectIsReadOnly) { return [object.metadata count]; @@ -466,26 +576,44 @@ Delete Object cell.detailTextLabel.text = accessType; } } else if (indexPath.section == kActions) { - if (fileDownloading) { - if (actionSelectedIndexPath.row == indexPath.row) { - cell.accessoryView = downloadProgressView; - } else { - cell.textLabel.textColor = [UIColor grayColor]; - cell.selectionStyle = UITableViewCellSelectionStyleNone; - } - } else { - cell.selectionStyle = UITableViewCellSelectionStyleBlue; - cell.accessoryView = nil; - } if (indexPath.row == 0) { - cell.textLabel.text = @"Open File"; + cell.textLabel.text = @"Open File"; cell.accessoryType = UITableViewCellAccessoryNone; cell.detailTextLabel.text = @""; - + if (fileDownloading) { + cell.textLabel.textColor = [UIColor grayColor]; + cell.selectionStyle = UITableViewCellSelectionStyleNone; + } else { + cell.selectionStyle = UITableViewCellSelectionStyleBlue; + } } else if (indexPath.row == 1) { cell.textLabel.text = @"Email File as Attachment"; cell.detailTextLabel.text = @""; - cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; + cell.accessoryType = UITableViewCellAccessoryNone; + if (fileDownloading) { + cell.textLabel.textColor = [UIColor grayColor]; + cell.selectionStyle = UITableViewCellSelectionStyleNone; + } else { + cell.selectionStyle = UITableViewCellSelectionStyleBlue; + } + } else if (indexPath.row == 2) { + if (fileDownloaded) { + cell.textLabel.text = @"Remove from Cache"; + cell.accessoryType = UITableViewCellAccessoryNone; + cell.detailTextLabel.text = @""; + } else if (fileDownloading) { + cell.textLabel.text = @"Downloading"; + cell.accessoryType = UITableViewCellAccessoryNone; + cell.detailTextLabel.text = @""; + cell.selectionStyle = UITableViewCellSelectionStyleNone; + cell.accessoryView = downloadProgressView; + } + } else if (indexPath.row == 3) { + if (fileDownloading) { + cell.textLabel.text = @"Cancel"; + cell.accessoryType = UITableViewCellAccessoryNone; + cell.detailTextLabel.text = @""; + } } } else if (indexPath.section == versionsSection) { cell.selectionStyle = UITableViewCellSelectionStyleBlue; @@ -558,88 +686,41 @@ Delete Object [self.navigationController pushViewController:vc animated:YES]; [vc release]; } else if (indexPath.section == kActions) { - if (!fileDownloaded) { - if (!fileDownloading) { - // download the file - fileDownloading = YES; - self.actionSelectedIndexPath = indexPath; - [self.tableView reloadData]; - NSMutableDictionary *requestUserInfo = [NSDictionary dictionaryWithObject:indexPath forKey:@"actionSelectedIndexPath"]; - [[self.account.manager getObject:self.container object:self.object downloadProgressDelegate:self requestUserInfo:requestUserInfo version:versionID] - success:^(OpenStackRequest *request) { - fileDownloaded = YES; - fileDownloading = NO; - if ([self.navigationController.visibleViewController isEqual:self]) - [self.tableView.delegate tableView:self.tableView didSelectRowAtIndexPath:indexPath]; - [self.tableView reloadData]; - [self.folderViewController reloadData]; - } - failure:^(OpenStackRequest *request) { - fileDownloaded = NO; - fileDownloading = NO; - [self alert:@"File failed to download." request:request]; - [self.tableView reloadData]; - }]; - [self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:indexPath.row inSection:kActions]] withRowAnimation:UITableViewRowAnimationNone]; - } - } else if (indexPath.row == 0) { + if (indexPath.row == 0) { if (fileDownloaded) { - OpenStackAppDelegate *app = [[UIApplication sharedApplication] delegate]; - NSString *filePath = [app.cachedObjectsDictionary objectForKey:object.hash]; - self.documentInteractionController = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:filePath]]; - self.documentInteractionController.delegate = self; - self.documentInteractionController.name = object.name; - - UITableViewCell *openFileCell = [self.tableView cellForRowAtIndexPath:indexPath]; - CGRect frameToPresentMenuFrom = CGRectMake(openFileCell.frame.origin.x, - openFileCell.frame.origin.y - self.tableView.contentOffset.y, - openFileCell.frame.size.width, - openFileCell.frame.size.height); - if (![self.documentInteractionController presentOptionsMenuFromRect:frameToPresentMenuFrom inView:self.view animated:YES]) { - if ([self.object isPlayableMedia]) { - MediaViewController *vc = [[MediaViewController alloc] initWithNibName:@"MediaViewController" bundle:nil]; - vc.container = self.container; - vc.object = self.object; - [self.navigationController pushViewController:vc animated:YES]; - [vc release]; - } else { - [self alert:@"Error" message:@"This file could not be opened."]; - [self.tableView deselectRowAtIndexPath:indexPath animated:YES]; - } - } - - [self.tableView deselectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:kActions] animated:YES]; - - } + [self openFile]; + [self.tableView deselectRowAtIndexPath:indexPath animated:YES]; + } else if (!fileDownloading) { + [self downloadFileForAction:StorageObjectActionOpenFile]; + [self.tableView deselectRowAtIndexPath:indexPath animated:YES]; + } } else if (indexPath.row == 1) { - - NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); - NSString *documentsDirectory = [paths objectAtIndex:0]; - NSString *shortPath = @""; - - if (self.container && [self.container respondsToSelector:@selector(name)] && self.object && [self.object respondsToSelector:@selector(fullPath)]) { - shortPath = [NSString stringWithFormat:@"/%@/%@", self.container.name, self.object.fullPath]; + if (fileDownloaded) { + [self mailFile]; + [self.tableView deselectRowAtIndexPath:indexPath animated:YES]; + } else if (!fileDownloading) { + [self downloadFileForAction:StorageObjectActionMailFile]; + [self.tableView deselectRowAtIndexPath:indexPath animated:YES]; } - - NSString *filePath = [documentsDirectory stringByAppendingString:shortPath]; - NSData *data = [NSData dataWithContentsOfURL:[NSURL fileURLWithPath:filePath]]; - - - if (![MFMailComposeViewController canSendMail]) { - [self alert:@"Cannot send mail" message:@"Your device has not been configured for sending email"]; - [self.tableView deselectRowAtIndexPath:indexPath animated:NO]; - } else { - MFMailComposeViewController *vc = [[MFMailComposeViewController alloc] init]; - - vc.mailComposeDelegate = self; - [vc setSubject:self.object.name]; - [vc addAttachmentData:data mimeType:self.object.contentType fileName:self.object.name]; - [vc setMessageBody:@"" isHTML:NO]; - if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) { - vc.modalPresentationStyle = UIModalPresentationPageSheet; - } - [self presentModalViewController:vc animated:YES]; - [vc release]; + } else if ((indexPath.row == 2) && fileDownloaded) { + OpenStackAppDelegate *app = [[UIApplication sharedApplication] delegate]; + BOOL removed = [app removeCacheObjectForHash:object.hash]; + [self.tableView deselectRowAtIndexPath:indexPath animated:YES]; + if (removed) { + fileDownloaded = NO; + fileDownloading = NO; + [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:kActions] withRowAnimation:UITableViewRowAnimationNone]; + } + } else if ((indexPath.row == 3) && fileDownloading) { + OpenStackAppDelegate *app = [[UIApplication sharedApplication] delegate]; + OpenStackRequest *request = [app objectDownloadRequestForAccount:account container:container object:object]; + [self.tableView deselectRowAtIndexPath:indexPath animated:YES]; + if (request) { + request.downloadProgressDelegate = nil; + [request cancel]; + fileDownloaded = NO; + fileDownloading = NO; + [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:kActions] withRowAnimation:UITableViewRowAnimationNone]; } } } else if (indexPath.section == deleteSection) { @@ -664,7 +745,7 @@ Delete Object if (newProgress >= 1.0) { fileDownloading = NO; fileDownloaded = YES; - [self.tableView reloadData]; + [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:kActions] withRowAnimation:UITableViewRowAnimationNone]; } } @@ -718,9 +799,8 @@ Delete Object #pragma mark - MFMailComposeViewControllerDelegate // Dismisses the email composition interface when users tap Cancel or Send. -- (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error { +- (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error { [self dismissModalViewControllerAnimated:YES]; - [self.tableView deselectRowAtIndexPath:[NSIndexPath indexPathForRow:1 inSection:kActions] animated:YES]; } @end diff --git a/OpenStack-Info.plist b/OpenStack-Info.plist index 1d12d86..30d6a6d 100755 --- a/OpenStack-Info.plist +++ b/OpenStack-Info.plist @@ -43,7 +43,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.1.5 + 1.1.6 CFBundleSignature ???? CFBundleURLTypes @@ -58,7 +58,7 @@ CFBundleVersion - 20121220.0 + 20121228.0 LSRequiresIPhoneOS NSMainNibFile -- 1.7.10.4