// // StorageObjectViewController.m // OpenStack // // Created by Mike Mayo on 12/19/10. // The OpenStack project is provided under the Apache 2.0 license. // #import "StorageObjectViewController.h" #import "OpenStackAccount.h" #import "OpenStackRequest.h" #import "Container.h" #import "Folder.h" #import "StorageObject.h" #import "AccountManager.h" #import "AnimatedProgressView.h" #import "UIViewController+Conveniences.h" #import "MediaViewController.h" #import "FolderViewController.h" #import "UIColor+MoreColors.h" #import "OpenStackAppDelegate.h" #import "EditMetadataViewController.h" #import "Provider.h" #import "EditPermissionsViewController.h" #import "TextViewCell.h" #import "NSString+Conveniences.h" #import "APICallback.h" #import "ObjectVersionsViewController.h" #define kDetails 0 #define kMetadata 2 #define maxMetadataViewableLength 12 // TODO: use etag to reset download // TODO: try downloading directly to the file to save memory. don't use object.data /* Name whatever.txt Full Path Size 123 KB Content Type text/plain Metadata Key Value -> tap goes to a metadata item VC to edit or delete Key Value Add Metadata... (if max not already reached) 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." Delete Object */ @implementation StorageObjectViewController @synthesize account, container, folder, object, tableView, folderViewController; @synthesize oldPubicURI, documentInteractionController, actionSelectedIndexPath, objectIsReadOnly, versionID; - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation { return (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) || (toInterfaceOrientation == UIInterfaceOrientationPortrait); } - (void)setBackgroundView { UIImageView *logo = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"cloudfiles-large.png"]]; if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { UIView *backgroundContainer = [[UIView alloc] init]; backgroundContainer.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth; backgroundContainer.backgroundColor = [UIColor iPadTableBackgroundColor]; logo.contentMode = UIViewContentModeScaleAspectFit; logo.frame = CGRectMake(100.0, 100.0, 1000.0, 1000.0); logo.alpha = 0.5; [backgroundContainer addSubview:logo]; tableView.backgroundView = backgroundContainer; [backgroundContainer release]; } else { self.tableView.backgroundView = nil; } [logo release]; } - (IBAction)homeButtonPressed:(id)sender { [self.navigationController popToRootViewControllerAnimated:YES]; } #pragma mark - #pragma mark View lifecycle - (void)viewDidLoad { [super viewDidLoad]; objectIsPublicSwitch = [[UISwitch alloc] init]; [objectIsPublicSwitch addTarget:self action:@selector(objectIsPublicSwitchChanged:) forControlEvents:UIControlEventValueChanged]; permissions = [[NSMutableDictionary alloc] init]; if (object.sharing.length > 0) { NSArray *sharingArray = [object.sharing componentsSeparatedByString:@";"]; for (NSString *typeSpecificPermissions in sharingArray) { NSArray *array=[typeSpecificPermissions componentsSeparatedByString:@"="]; NSString *permissionsType = [array objectAtIndex:0]; if ([permissionsType hasPrefix:@" "]) permissionsType = [permissionsType substringFromIndex:1]; NSArray *users = [[array objectAtIndex:1] componentsSeparatedByString:@","]; for (NSString *user in users) { [permissions setObject:permissionsType forKey:user]; } } } objectIsReadOnly = NO; if (account.sharingAccount) { if ([permissions count] > 0) { objectIsReadOnly = [[permissions objectForKey:[account username]] isEqualToString:@"read"]; } objectIsPublicSwitch.enabled = NO; } 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]; } appDelegate = [[UIApplication sharedApplication] delegate]; } - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; self.navigationItem.title = object.name; NSIndexPath *selection = [self.tableView indexPathForSelectedRow]; if (selection) [self.tableView deselectRowAtIndexPath:selection animated:YES]; if ([appDelegate.cachedObjectsDictionary objectForKey:object.hash] != nil) { if ([[NSFileManager defaultManager] fileExistsAtPath:[appDelegate.cachedObjectsDictionary objectForKey:object.hash]]) fileDownloaded = YES; else { fileDownloaded = NO; [appDelegate.cachedObjectsDictionary removeObjectForKey:object.hash]; [appDelegate saveCacheDictionary]; } } else { fileDownloaded = NO; } if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { CGRect rect = downloadProgressView.frame; rect.size.width = 440.0; downloadProgressView.frame = rect; } //[self setBackgroundView]; actionsSection = 1; publicLinkSection = 3; permissionsSection = 4; versionsSection = 5; deleteSection = 6; if (versionID) { publicLinkSection = -1; permissionsSection = -1; versionsSection = -1; deleteSection = -1; objectIsReadOnly = YES; } if (account.sharingAccount || account.shared) { versionsSection = -1; deleteSection = -1; } objectIsPublic = ([object.publicURI length]); objectIsPublicSwitch.on = objectIsPublic; [self.tableView reloadData]; } - (void)viewDidAppear:(BOOL)animated { if (object.metadata == nil) { [self reloadMetadataSection]; } } #pragma mark - #pragma mark Table view data source - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { int numberOfSections = 7; if (deleteSection < 0) numberOfSections--; if (versionsSection < 0) numberOfSections--; if (publicLinkSection < 0) numberOfSections--; if (permissionsSection < 0) numberOfSections--; return numberOfSections; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { if (section == kDetails) { return 4; } else if (section == kMetadata) { if (objectIsReadOnly) { return [object.metadata count]; } else { return 1 + [object.metadata count]; } } else if (section == actionsSection) { return 2; } else if (section == publicLinkSection) { return objectIsPublic ? 2 : 1; } else if (section == permissionsSection) { if (account.sharingAccount || objectIsReadOnly) return [permissions count]; else return 1 + [permissions count]; } else { return 1; } } - (CGFloat)findLabelHeight:(NSString*)text font:(UIFont *)font { CGSize textLabelSize; if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { // 616, 678 textLabelSize = CGSizeMake(596.0, 9000.0f); } else { textLabelSize = CGSizeMake(280.0, 9000.0f); } CGSize stringSize = [text sizeWithFont:font constrainedToSize:textLabelSize lineBreakMode:UILineBreakModeCharacterWrap]; return stringSize.height; } - (CGFloat)tableView:(UITableView *)aTableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { CGFloat result = aTableView.rowHeight; if (indexPath.section == kDetails && indexPath.row == 1) { CGSize textLabelSize; if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { textLabelSize = CGSizeMake(537.0, 9000.0f); } else { textLabelSize = CGSizeMake(221.0, 9000.0f); } CGSize stringSize = [object.fullPath sizeWithFont:[UIFont systemFontOfSize:18.0] constrainedToSize:textLabelSize lineBreakMode:UILineBreakModeWordWrap]; return 22.0 + stringSize.height; } else if (indexPath.section == kDetails && indexPath.row == 0) { CGSize textLabelSize; if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { textLabelSize = CGSizeMake(537.0, 9000.0f); } else { textLabelSize = CGSizeMake(221.0, 9000.0f); } CGSize stringSize = [object.name sizeWithFont:[UIFont systemFontOfSize:18.0] constrainedToSize:textLabelSize lineBreakMode:UILineBreakModeWordWrap]; return 22.0 + stringSize.height; } else if (indexPath.section == publicLinkSection && indexPath.row == 1) { NSString *publicLinkUrl = [NSString stringWithFormat:@"%@%@", account.pithosPublicLinkURLPrefix, self.object.publicURI]; result = 30.0 + [self findLabelHeight:publicLinkUrl font:[UIFont systemFontOfSize:15.0]]; } return MAX(aTableView.rowHeight, result); } - (UITableViewCell *)tableView:(UITableView *)aTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { if ((indexPath.section == publicLinkSection) && (indexPath.row == 1)) { static NSString *CellIdentifier = @"TextViewCell"; TextViewCell *cell = [aTableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (cell == nil) { cell = [[[TextViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease]; cell.textView.frame = cell.contentView.frame; } cell.selectionStyle = UITableViewCellSelectionStyleNone; cell.textView.backgroundColor = [UIColor clearColor]; cell.textView.font = [UIFont systemFontOfSize:15.0]; cell.textView.dataDetectorTypes = UIDataDetectorTypeLink; cell.textView.text = [NSString stringWithFormat:@"%@%@", account.pithosPublicLinkURLPrefix, [NSString encodeToPercentEscape:self.object.publicURI charactersToEncode:@"!*'();:@&=+$,?%#[]"]]; cell.selectionStyle = UITableViewCellSelectionStyleNone; cell.accessoryView = UITableViewCellAccessoryNone; return cell; } if (indexPath.section == deleteSection) { static NSString *CellIdentifier = @"DeleteCell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (cell == nil) { cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease]; cell.selectionStyle = UITableViewCellSelectionStyleBlue; cell.textLabel.textAlignment = UITextAlignmentCenter; cell.textLabel.text = @"Delete Object"; } return cell; } static NSString *CellIdentifier = @"Cell"; UITableViewCell *cell = [aTableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (cell == nil) { cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease]; cell.textLabel.backgroundColor = [UIColor clearColor]; cell.detailTextLabel.backgroundColor = [UIColor clearColor]; cell.detailTextLabel.lineBreakMode = UILineBreakModeWordWrap; } cell.textLabel.textColor = [UIColor blackColor]; cell.detailTextLabel.numberOfLines = 0; if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { cell.backgroundColor = [UIColor colorWithRed:1 green:1 blue:1 alpha:0.8]; } cell.userInteractionEnabled = YES; cell.detailTextLabel.textAlignment = UITextAlignmentRight; cell.accessoryView = nil; cell.textLabel.font = [UIFont boldSystemFontOfSize:17.0]; // Configure the cell... if (indexPath.section == kDetails) { cell.accessoryType = UITableViewCellAccessoryNone; cell.selectionStyle = UITableViewCellSelectionStyleNone; cell.accessoryView = nil; if (indexPath.row == 0) { cell.textLabel.text = @"Name"; cell.detailTextLabel.text = object.name; } else if (indexPath.row == 1) { cell.textLabel.text = @"Full Path"; cell.detailTextLabel.text = object.fullPath; } else if (indexPath.row == 2) { cell.textLabel.text = @"Size"; cell.detailTextLabel.text = [object humanizedBytes]; } else if (indexPath.row == 3) { cell.textLabel.text = @"Type"; cell.detailTextLabel.text = object.contentType; } } else if (indexPath.section == kMetadata) { if (objectIsReadOnly) { cell.accessoryType = UITableViewCellAccessoryNone; cell.selectionStyle = UITableViewCellSelectionStyleNone; cell.userInteractionEnabled = NO; } else { cell.selectionStyle = UITableViewCellSelectionStyleBlue; cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; } cell.accessoryView = nil; if (indexPath.row == [object.metadata count]) { cell.textLabel.text = @"Add Metadata"; cell.detailTextLabel.text = @""; } else { NSString *key = [[object.metadata allKeys] objectAtIndex:indexPath.row]; NSString *value = [object.metadata objectForKey:key]; NSString *metadataKeyCellText = key; NSString *metadataValueCellText = value; if ([metadataKeyCellText length] > maxMetadataViewableLength) { metadataKeyCellText = [metadataKeyCellText substringToIndex:(maxMetadataViewableLength - 3)]; metadataKeyCellText = [metadataKeyCellText stringByAppendingString:@"..."]; } if ([metadataValueCellText length] > maxMetadataViewableLength) { metadataValueCellText = [metadataValueCellText substringToIndex:(maxMetadataViewableLength - 3)]; metadataValueCellText = [metadataValueCellText stringByAppendingString:@"..."]; } cell.textLabel.text = metadataKeyCellText; cell.detailTextLabel.text = metadataValueCellText; } } else if (indexPath.section == publicLinkSection) { if (indexPath.row == 0) { cell.textLabel.text = @"Public URL"; cell.detailTextLabel.text = @""; cell.accessoryView = objectIsPublicSwitch; cell.accessoryType = UITableViewCellAccessoryNone; cell.selectionStyle = UITableViewCellSelectionStyleNone; } } else if (indexPath.section == permissionsSection) { if (account.sharingAccount) { cell.accessoryType = UITableViewCellAccessoryNone; cell.selectionStyle = UITableViewCellSelectionStyleNone; cell.userInteractionEnabled = NO; } else { cell.selectionStyle = UITableViewCellSelectionStyleBlue; cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; } cell.accessoryView = nil; if (indexPath.row == [permissions count]) { cell.textLabel.text = @"Share"; cell.detailTextLabel.text = @""; } else { NSString *user = [[permissions allKeys] objectAtIndex:indexPath.row]; cell.textLabel.text = user; NSString *accessType; if ([[permissions objectForKey:user] isEqualToString:@"write"]) accessType = @"Read/Write"; else accessType = @"Read Only"; cell.detailTextLabel.numberOfLines = 1; cell.detailTextLabel.lineBreakMode = UILineBreakModeTailTruncation; cell.detailTextLabel.text = accessType; } } else if (indexPath.section == actionsSection) { 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.accessoryType = UITableViewCellAccessoryNone; cell.detailTextLabel.text = @""; } else if (indexPath.row == 1) { cell.textLabel.text = @"Email File as Attachment"; cell.detailTextLabel.text = @""; cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; } } else if (indexPath.section == versionsSection) { cell.selectionStyle = UITableViewCellSelectionStyleBlue; cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; cell.textLabel.text = @"Versions"; cell.detailTextLabel.text = @""; } return cell; } #pragma mark - #pragma mark Table view delegate - (void)reloadActionsTitleRow:(NSTimer *)timer { [[timer.userInfo objectForKey:@"tableView"] reloadRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:0 inSection:actionsSection]] withRowAnimation:UITableViewRowAnimationNone]; } - (void)tableView:(UITableView *)aTableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { if (indexPath.section == kMetadata) { EditMetadataViewController *vc = [[EditMetadataViewController alloc] initWithNibName:@"EditMetadataViewController" bundle:nil]; NSString *metadataKey; NSString *metadataValue; if (indexPath.row == [self.object.metadata count]) { metadataKey = @""; metadataValue = @""; vc.removeMetadataEnabled = FALSE; vc.navigationItem.title = @"Add Metadata"; } else { metadataKey = [[self.object.metadata allKeys] objectAtIndex:indexPath.row]; metadataValue = [self.object.metadata objectForKey:metadataKey]; vc.removeMetadataEnabled = YES; vc.navigationItem.title = @"Edit Metadata"; } vc.metadataKey = metadataKey; vc.metadataValue = metadataValue; vc.account = account; vc.container = container; vc.object = object; [self.navigationController pushViewController:vc animated:YES]; [vc release]; } else if (indexPath.section == permissionsSection) { EditPermissionsViewController *vc = [[EditPermissionsViewController alloc] initWithNibName:@"EditPermissionsViewController" bundle:nil]; NSString *user; if (indexPath.row == [permissions count]) { user = @""; vc.removePermissionsEnabled = NO; vc.navigationItem.title = @"Share"; } else { user = [[permissions allKeys] objectAtIndex:indexPath.row]; NSString *userPermissions = [permissions objectForKey:user]; if ([userPermissions rangeOfString:@"read"].location != NSNotFound) vc.readPermissionSelected = YES; else vc.readPermissionSelected = NO; if ([userPermissions rangeOfString:@"write"].location != NSNotFound) vc.writePermissionSelected = YES; else vc.writePermissionSelected = NO; vc.removePermissionsEnabled = YES; vc.navigationItem.title = @"Edit Sharing"; } vc.user = user; vc.permissions = permissions; vc.account = account; vc.container = container; vc.object = object; vc.folderViewController = folderViewController; [self.navigationController pushViewController:vc animated:YES]; [vc release]; } else if (indexPath.section == actionsSection) { 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.tableView 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:actionsSection]] withRowAnimation:UITableViewRowAnimationNone]; } } else if (indexPath.row == 0) { if (fileDownloaded) { NSString *filePath = [appDelegate.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:actionsSection] 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]; } 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 (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { vc.modalPresentationStyle = UIModalPresentationPageSheet; } [self presentModalViewController:vc animated:YES]; [vc release]; } } } else if (indexPath.section == deleteSection) { UIActionSheet *deleteActionSheet = [[[UIActionSheet alloc] initWithTitle:@"Are you sure you want to delete this file? This operation cannot be undone." delegate:self cancelButtonTitle:@"Cancel" destructiveButtonTitle:@"Delete File" otherButtonTitles:nil] autorelease]; [deleteActionSheet showInView:self.view]; } else if (indexPath.section == versionsSection) { ObjectVersionsViewController *vc = [[ObjectVersionsViewController alloc] initWithNibName:@"ObjectVersionsViewController" bundle:nil]; vc.account = account; vc.container = container; vc.object = object; [self.navigationController pushViewController:vc animated:YES]; [vc release]; } } - (void)setProgress:(float)newProgress { [downloadProgressView setProgress:newProgress animated:YES]; if (newProgress >= 1.0) { fileDownloading = NO; fileDownloaded = YES; [self.tableView reloadData]; } } #pragma mark - #pragma mark Document Interation Controller Delegate - (UIViewController *)documentInteractionControllerViewControllerForPreview:(UIDocumentInteractionController *) controller { return self.navigationController; } - (void)documentInteractionControllerDidEndPreview:(UIDocumentInteractionController *)controllers { [self.tableView deselectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:actionsSection] animated:YES]; } #pragma mark - #pragma mark Action Sheet Delegate - (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex { if (buttonIndex == 0) { // delete the file and pop out NSString *activityMessage = @"Deleting file"; [activityIndicatorView release]; activityIndicatorView = [[ActivityIndicatorView alloc] initWithFrame:[ActivityIndicatorView frameForText:activityMessage] text:activityMessage]; [activityIndicatorView addToView:self.view]; self.folderViewController.refreshButton.enabled = NO; [[self.account.manager deleteObject:self.container object:self.object] success:^(OpenStackRequest *request) { [activityIndicatorView removeFromSuperview]; if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) { [self.navigationController popViewControllerAnimated:YES]; if (account.shared) self.folderViewController.needsRefreshing = YES; } else if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { self.folderViewController.selectedObjectViewController = nil; if (!account.shared) [self.folderViewController setDetailViewController]; else [self.folderViewController refreshButtonPressed:nil]; self.folderViewController.refreshButton.enabled = YES; } if (self.folder.objectsAndFoldersCount == 1) { [self.folder removeObject:self.object]; [self.folderViewController.tableView reloadData]; self.folderViewController.folder = self.folderViewController.folder; } else { [self.folderViewController deleteAnimatedObject:self.object]; } } failure:^(OpenStackRequest *request) { [activityIndicatorView removeFromSuperview]; [self hideToolbarActivityMessage]; [self alert:@"There was a problem deleting this file." request:request]; }]; } NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:deleteSection]; [self.tableView deselectRowAtIndexPath:indexPath animated:YES]; } #pragma mark - #pragma mark Mail Composer Delegate // Dismisses the email composition interface when users tap Cancel or Send. - (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error { [self dismissModalViewControllerAnimated:YES]; [self.tableView deselectRowAtIndexPath:[NSIndexPath indexPathForRow:1 inSection:actionsSection] animated:YES]; } #pragma mark - #pragma mark Switches - (void)objectIsPublicSwitchChanged:(id)sender { NSString *activityMessage = [NSString stringWithFormat:@"Enabling public link.."]; self.oldPubicURI = object.publicURI; if (objectIsPublic) { activityMessage = [NSString stringWithFormat:@"Disabling public link.."]; object.publicURI = @""; } else { object.publicURI = @"TRUE"; } [activityIndicatorView release]; activityIndicatorView = [[ActivityIndicatorView alloc] initWithFrame:[ActivityIndicatorView frameForText:activityMessage] text:activityMessage]; [activityIndicatorView addToView:self.view scrollOffset:self.tableView.contentOffset.y]; objectIsPublic = !objectIsPublic; [[self.account.manager writeObjectMetadata:container object:object] success:^(OpenStackRequest *request) { NSIndexPath *publicURICellIndexPath = [NSIndexPath indexPathForRow:1 inSection:publicLinkSection]; if (objectIsPublic) { [[self.account.manager getObjectInfo:container object:object version:versionID] success:^(OpenStackRequest *request) { [activityIndicatorView removeFromSuperview]; object.publicURI = [request.responseHeaders objectForKey:@"X-Object-Public"]; NSIndexPath *publicURICellIndexPath = [NSIndexPath indexPathForRow:1 inSection:publicLinkSection]; [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:publicURICellIndexPath] withRowAnimation:UITableViewRowAnimationBottom]; } failure:^(OpenStackRequest *request) { [activityIndicatorView removeFromSuperview]; [self alert:@"There was a problem retrieving the public link from the server." request:request]; }]; } else { [activityIndicatorView removeFromSuperview]; [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:publicURICellIndexPath] withRowAnimation:UITableViewRowAnimationTop]; } } failure:^(OpenStackRequest *request) { [activityIndicatorView removeFromSuperview]; objectIsPublic = !objectIsPublic; objectIsPublicSwitch.on = !objectIsPublicSwitch.on; object.publicURI = oldPubicURI; [self alert:@"There was a problem enabling the public link." request:request]; }]; } #pragma mark - #pragma mark Memory management - (void)dealloc { if (fileDownloading) { OpenStackRequest *request = [self.account.manager.objectDownloadRequests objectForKey:object.fullPath]; [request setDownloadProgressDelegate:nil]; } [account release]; [downloadProgressView release]; [cdnURLActionSheet release]; [tableView release]; [folderViewController release]; [objectIsPublicSwitch release]; [permissions release]; [documentInteractionController release]; [actionSelectedIndexPath release]; [versionID release]; [activityIndicatorView release]; [super dealloc]; } #pragma mark - #pragma mark Helper functions - (void)reloadMetadataSection { NSString *activityMessage = @"Loading metadata..."; [activityIndicatorView release]; activityIndicatorView = [[ActivityIndicatorView alloc] initWithFrame:[ActivityIndicatorView frameForText:activityMessage] text:activityMessage]; [activityIndicatorView addToView:self.view]; [[self.account.manager getObjectInfo:container object:object version:versionID] success:^(OpenStackRequest *request) { [activityIndicatorView removeFromSuperview]; object.metadata = [NSMutableDictionary dictionary]; for (NSString *header in request.responseHeaders) { NSString *metadataKey; NSString *metadataValue; if ([header rangeOfString:@"X-Object-Meta-"].location != NSNotFound) { metadataKey = [NSString decodeFromPercentEscape:[header substringFromIndex:14]]; metadataValue = [NSString decodeFromPercentEscape:[request.responseHeaders objectForKey:header]]; [object.metadata setObject:metadataValue forKey:metadataKey]; } } NSIndexSet *metadataSections = [NSIndexSet indexSetWithIndex:kMetadata]; [self.tableView reloadSections:metadataSections withRowAnimation:UITableViewRowAnimationFade]; } failure:^(OpenStackRequest *request) { [activityIndicatorView removeFromSuperview]; [self alert:@"There was a problem retrieving the object's metadata." request:request]; }]; } @end