#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"
@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
[userDefaults setValue:cachedObjectsDictionary forKey:@"cachedObjectsDictionary"];
}
+ objectDownloadRequests = [[NSMutableDictionary alloc] init];
+
[userDefaults synchronize];
}
animated:NO];
}
-#pragma mark -
-#pragma mark Application lifecycle
+#pragma mark - Application lifecycle
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[self loadSettingsDefaults];
#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 {
[rootViewController release];
[window release];
[cachedObjectsDictionary release];
+ [objectDownloadRequests release];
[super dealloc];
}
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
@implementation StorageObjectViewController
@synthesize account, container, folder, object, folderViewController;
-@synthesize oldPubicURI, documentInteractionController, actionSelectedIndexPath, objectIsReadOnly, versionID;
+@synthesize oldPubicURI, documentInteractionController, objectIsReadOnly, versionID;
#pragma mark - View lifecycle
}
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 {
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;
}
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];
[objectIsPublicSwitch release];
[permissions release];
[documentInteractionController release];
- [actionSelectedIndexPath release];
[versionID release];
[super dealloc];
}
}];
}
+- (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 {
}];
}
+- (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 {
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];
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;
[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) {
if (newProgress >= 1.0) {
fileDownloading = NO;
fileDownloaded = YES;
- [self.tableView reloadData];
+ [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:kActions] withRowAnimation:UITableViewRowAnimationNone];
}
}
#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