// // FolderViewController.m // OpenStack // // Created by Mike Mayo on 12/15/10. // The OpenStack project is provided under the Apache 2.0 license. // #import "FolderViewController.h" #import "OpenStackAccount.h" #import "Container.h" #import "StorageObject.h" #import "StorageObjectViewController.h" #import "ContainerDetailViewController.h" #import "AccountManager.h" #import "ActivityIndicatorView.h" #import "ContainersViewController.h" #import "UIViewController+Conveniences.h" #import "AddObjectViewController.h" #import "OpenStackAppDelegate.h" #import "RootViewController.h" #import "FolderDetailViewController.h" #import "AccountHomeViewController.h" #import "PithosImageViewController.h" #import "OpenStackRequest.h" #import "JSON.h" #import "APICallback.h" #import #import "ComputeModel.h" #import "MediaViewController.h" static NSString *kSortTypeKey = @"sortType"; static NSString *kSortNameDirectionKey = @"sortNameDirection"; static NSString *kSortDateDirectionKey = @"sortDateDirection"; @implementation FolderViewController @synthesize account, container, folder, name, containersViewController, parentFolderViewController, refreshWhenAppeared, deletedObject; @synthesize searchDisplayController, tableView ,searchBar, refreshButton, sortTypeButton, sortDirectionButton; @synthesize searchFilter, searchActiveOnRotation, sortType, sortNameDirection, sortDateDirection;; @synthesize folderDetailVC, selectedObjectViewController, documentInteractionController; #pragma mark - View lifecycle - (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { if (([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) && self.searchDisplayController.active && self.searchBar.isFirstResponder) { UIInterfaceOrientation statusBarOrientation = [[UIApplication sharedApplication] statusBarOrientation]; if (UIInterfaceOrientationIsPortrait(toInterfaceOrientation) && UIInterfaceOrientationIsLandscape(statusBarOrientation)) { [self.searchBar resignFirstResponder]; } else if (UIInterfaceOrientationIsLandscape(toInterfaceOrientation) && UIInterfaceOrientationIsPortrait(statusBarOrientation)) { self.searchActiveOnRotation = YES; } } [super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration]; } - (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation { [super didRotateFromInterfaceOrientation:fromInterfaceOrientation]; if (([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) && UIInterfaceOrientationIsPortrait(fromInterfaceOrientation) && UIInterfaceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation])) { if (self.searchDisplayController.active && self.searchActiveOnRotation) { [self.searchBar becomeFirstResponder]; CGRect tableViewFrame = self.tableView.frame; tableViewFrame.size.height = self.toolbar.frame.origin.y - tableViewFrame.origin.y; self.tableView.frame = tableViewFrame; self.searchDisplayController.searchResultsTableView.frame = tableViewFrame; } self.searchActiveOnRotation = NO; } } - (void)viewDidLoad { [super viewDidLoad]; [self addAddButton]; } - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; self.navigationItem.title = (self.name.length ? self.name : self.container.name); NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; self.sortType = [userDefaults integerForKey:kSortTypeKey]; self.sortTypeButton.title = (self.sortType == FolderSortTypeDate) ? @"date" : @"name"; self.sortNameDirection = [userDefaults integerForKey:kSortNameDirectionKey]; self.sortDateDirection = [userDefaults integerForKey:kSortDateDirectionKey]; if (self.sortType == FolderSortTypeDate) { self.sortDirectionButton.title = (self.sortDateDirection == FolderSortDateDirectionNewestFirst) ? @"newest first" : @"oldest first"; } else { self.sortDirectionButton.title = (self.sortNameDirection == FolderSortNameDirectionZA) ? @"Z-A" : @"A-Z"; } if (!container.rootFolder || !deletedObject) { self.deletedObject = nil; [self reloadData]; } else if ([[deletedObject class] isEqual:[Folder class]]) { Folder *deletedFolder = (Folder *)deletedObject; if (![folder.folders objectForKey:deletedFolder.name] || ([[self searchResults] indexOfObject:[folder.folders objectForKey:deletedFolder.name]] == NSNotFound)) { self.deletedObject = nil; [self reloadData]; } else if (folder.objectsAndFoldersCount == 1) { [self deleteAnimatedObject:deletedObject]; } } else if ([[deletedObject class] isEqual:[StorageObject class]]) { StorageObject *deletedStorageObject = (StorageObject *)deletedObject; if (![folder.objects objectForKey:deletedStorageObject.name] || ([[self searchResults] indexOfObject:[folder.objects objectForKey:deletedStorageObject.name]] == NSNotFound)) { self.deletedObject = nil; [self reloadData]; } else if (folder.objectsAndFoldersCount == 1) { [self deleteAnimatedObject:deletedObject]; } } else { self.deletedObject = nil; } } - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; if (!container.rootFolder) { // Container objects not fetched yet. refreshWhenAppeared = YES; } else if (!folder) { // This controller's folder has been deleted. parentFolderViewController.refreshWhenAppeared = YES; [self.navigationController popViewControllerAnimated:YES]; return; } else if (account.shared && !folder.objectsAndFoldersCount) { // The shared folder is empty, probably after a delete. [self.navigationController popViewControllerAnimated:YES]; return; } else if (deletedObject) { [self deleteAnimatedObject:deletedObject]; } if (refreshWhenAppeared) { refreshWhenAppeared = NO; [self refreshButtonPressed:nil]; } } - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; if (![self.navigationController.viewControllers containsObject:self] && self.parentViewController) { [parentFolderViewController setDetailViewController]; } } #pragma mark - Memory management - (void)dealloc { [account release]; [container release]; [folder release]; [name release]; [containersViewController release]; [parentFolderViewController release]; [searchDisplayController release]; [searchBar release]; [refreshButton release]; [sortTypeButton release]; [sortDirectionButton release]; [deletedObject release]; [searchFilter release]; [documentInteractionController release]; [super dealloc]; } #pragma mark - Internal - (void)showSearchBar:(BOOL)show { if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPhone) { if (show && !self.tableView.tableHeaderView) { self.tableView.tableHeaderView = self.searchBar; self.tableView.contentOffset = CGPointMake(0.0, 44.0); } else if (!show) { if (self.searchDisplayController.active) [self.searchDisplayController setActive:NO animated:NO]; self.tableView.tableHeaderView = nil; } } else { if (show && self.searchBar.hidden) { self.searchBar.hidden = NO; self.searchBar.frame = CGRectMake(0.0, 0.0, self.searchBar.frame.size.width, self.searchBar.frame.size.height); self.tableView.frame = CGRectMake(0.0, self.searchBar.frame.size.height, self.tableView.frame.size.width, self.tableView.frame.size.height - self.searchBar.frame.size.height); } else if (!show && !self.searchBar.hidden) { self.searchBar.frame = CGRectMake(0.0, -self.searchBar.frame.size.height, self.searchBar.frame.size.width, self.searchBar.frame.size.height); self.tableView.frame = CGRectMake(0.0, 0, self.tableView.frame.size.width, self.tableView.frame.size.height + self.searchBar.frame.size.height); self.searchBar.hidden = YES; if (self.searchDisplayController.active) [self.searchDisplayController setActive:NO animated:NO]; } } } - (void)reloadFolderViewControllers { NSArray *viewControllers = [self.navigationController viewControllers]; int rootFolderControllerIndex = [viewControllers indexOfObject:self.containersViewController] + 1; FolderViewController *rootFolderViewController = [viewControllers objectAtIndex:rootFolderControllerIndex]; rootFolderViewController.folder = self.container.rootFolder; for (int i = rootFolderControllerIndex + 1; i < [viewControllers count]; i++) { FolderViewController *folderViewController = [viewControllers objectAtIndex:i]; Folder *parentFolder = folderViewController.parentFolderViewController.folder; folderViewController.folder = [parentFolder.folders objectForKey:folderViewController.folder.name]; } if (!self.folder || (account.shared && !folder.objectsAndFoldersCount)) { [self.navigationController popViewControllerAnimated:YES]; } else if (account.shared) { [self setDetailViewController]; } } //- (void)deleteObjectRow:(NSTimer *)timer { // [self.folder removeObject:[timer.userInfo objectForKey:@"object"]]; // if (folder == container.rootFolder) { // container.count -= 1; // } // [account persist]; // [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:[timer.userInfo objectForKey:@"indexPath"]] // withRowAnimation:UITableViewRowAnimationLeft]; // if (self.searchDisplayController.active && self.searchFilter && self.searchFilter.length) // [self.searchDisplayController.searchResultsTableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:[timer.userInfo objectForKey:@"indexPath"]] // withRowAnimation:UITableViewRowAnimationLeft]; // self.refreshButton.enabled = YES; //} - (NSArray *)searchResults { return [self.folder sortedContentsUsingFilter:self.searchFilter scope:[self.searchBar.scopeButtonTitles objectAtIndex:self.searchBar.selectedScopeButtonIndex] sortType:self.sortType sortDirection:((self.sortType == FolderSortTypeDate) ? self.sortDateDirection : self.sortNameDirection)]; } - (void)delete { parentFolderViewController.deletedObject = folder; [self.navigationController popViewControllerAnimated:YES]; [parentFolderViewController setDetailViewController]; } #pragma mark - Properties - (void)setFolder:(Folder *)aFolder { [folder release]; folder = [aFolder retain]; [self showSearchBar:(self.container.rootFolder && self.folder && self.folder.objectsAndFoldersCount)]; if (([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) && self.selectedObjectViewController && folder) { StorageObject *newObject = [folder.objects objectForKey:self.selectedObjectViewController.object.name]; if (newObject) self.selectedObjectViewController.object = newObject; // We don't set nil otherwise, this will be done in reloadData, when setDetailViewController is called. } [self reloadData]; } #pragma mark - Actions - (void)reloadData { [self.tableView reloadData]; BOOL searchResultsShown = self.searchDisplayController.active && self.searchFilter && self.searchFilter.length; if (searchResultsShown) [self.searchDisplayController.searchResultsTableView reloadData]; if (([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) && self.selectedObjectViewController) { NSUInteger selectedIndex = [[self searchResults] indexOfObject:self.selectedObjectViewController.object]; if (selectedIndex == NSNotFound) { [self setDetailViewController]; } else { NSIndexPath *selectIndexPath = [NSIndexPath indexPathForRow:selectedIndex inSection:0]; [self.tableView selectRowAtIndexPath:selectIndexPath animated:NO scrollPosition:UITableViewScrollPositionNone]; if (searchResultsShown) [self.searchDisplayController.searchResultsTableView selectRowAtIndexPath:selectIndexPath animated:NO scrollPosition:UITableViewScrollPositionNone]; } } } - (void)setDetailViewController { if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) { self.selectedObjectViewController = nil; if (self.folder) { if ([self.folder isEqual:self.container.rootFolder]) { [containersViewController setDetailViewControllerForContainer:container]; } else { FolderDetailViewController *vc = [[FolderDetailViewController alloc] initWithNibName:@"FolderDetailViewController" bundle:nil]; vc.account = self.account; vc.container = self.container; vc.folder = self.folder; vc.folderViewController = self.parentFolderViewController; [self presentPrimaryViewController:vc]; self.parentFolderViewController.folderDetailVC = vc; [vc release]; containersViewController.containerDetailViewController = nil; } } } } //- (void)deleteAnimatedObject:(StorageObject *)object { // NSIndexPath *deleteIndexPath = [NSIndexPath indexPathForRow:[[self searchResults] indexOfObject:object] inSection:0]; // [self.tableView selectRowAtIndexPath:deleteIndexPath animated:YES scrollPosition:UITableViewScrollPositionNone]; // if (self.searchDisplayController.active && self.searchFilter && self.searchFilter.length) // [self.searchDisplayController.searchResultsTableView selectRowAtIndexPath:deleteIndexPath // animated:YES // scrollPosition:UITableViewScrollPositionNone]; // NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:object, @"object", deleteIndexPath, @"indexPath", nil]; // [NSTimer scheduledTimerWithTimeInterval:0.75 target:self selector:@selector(deleteObjectRow:) userInfo:userInfo repeats:NO]; //} - (void)deleteAnimatedObject:(id)object { NSIndexPath *deletedObjectIndexPath = nil; if ([[object class] isEqual:[Folder class]]) { Folder *deletedFolder = [folder.folders objectForKey:[object name]]; if (deletedFolder) { if (folder.objectsAndFoldersCount == 1) { // If the deleted folder is the sole object of the folder, remove and reload to show the empty folder cell. [folder removeFolder:deletedFolder]; if (folder == container.rootFolder) { container.count -= 1; } [account persist]; self.folder = self.folder; } else { NSUInteger deletedFolderIndex = [[self searchResults] indexOfObject:deletedFolder]; if (deletedFolderIndex != NSNotFound) { deletedObjectIndexPath = [NSIndexPath indexPathForRow:deletedFolderIndex inSection:0]; } [folder removeFolder:deletedFolder]; if (folder == container.rootFolder) { container.count -= 1; } [account persist]; } } } else if ([[object class] isEqual:[StorageObject class]]) { StorageObject *deletedStorageObject = [folder.objects objectForKey:[object name]]; if (deletedStorageObject) { if (folder.objectsAndFoldersCount == 1) { // If the deleted storage object is the sole object of the folder, remove and reload to show the empty folder cell. [folder removeObject:deletedStorageObject]; if (folder == container.rootFolder) { container.count -= 1; } [account persist]; self.folder = self.folder; } else { NSUInteger deletedStorageObjectIndex = [[self searchResults] indexOfObject:deletedStorageObject]; if (deletedStorageObjectIndex != NSNotFound) { deletedObjectIndexPath = [NSIndexPath indexPathForRow:deletedStorageObjectIndex inSection:0]; } [folder removeObject:deletedStorageObject]; if (folder == container.rootFolder) { container.count -= 1; } [account persist]; } } } if (deletedObjectIndexPath) { [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:deletedObjectIndexPath] withRowAnimation:UITableViewRowAnimationLeft]; if (searchDisplayController.active && searchFilter && searchFilter.length) { [searchDisplayController.searchResultsTableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:deletedObjectIndexPath] withRowAnimation:UITableViewRowAnimationLeft]; } } self.deletedObject = nil; refreshWhenAppeared = NO; [self refreshButtonPressed:nil]; } - (IBAction)toggleSortType:(id)sender { if (self.sortType == FolderSortTypeDate) { self.sortType = FolderSortTypeName; self.sortTypeButton.title = @"name"; self.sortDirectionButton.title = (self.sortNameDirection == FolderSortNameDirectionZA) ? @"Z-A" : @"A-Z"; } else { self.sortType = FolderSortTypeDate; self.sortTypeButton.title = @"date"; self.sortDirectionButton.title = (self.sortDateDirection == FolderSortDateDirectionNewestFirst) ? @"newest first" : @"oldest first"; } [self reloadData]; NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; [userDefaults setInteger:self.sortType forKey:kSortTypeKey]; [userDefaults synchronize]; } - (IBAction)toggleSortDirection:(id)sender { NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; if (self.sortType == FolderSortTypeDate) { if (self.sortDateDirection == FolderSortDateDirectionNewestFirst) { self.sortDateDirection = FolderSortDateDirectionOldestFirst; self.sortDirectionButton.title = @"oldest first"; } else { self.sortDateDirection = FolderSortDateDirectionNewestFirst; self.sortDirectionButton.title = @"newest first"; } [userDefaults setInteger:self.sortDateDirection forKey:kSortDateDirectionKey]; } else { if (self.sortNameDirection == FolderSortNameDirectionZA) { self.sortNameDirection = FolderSortNameDirectionAZ; self.sortDirectionButton.title = @"A-Z"; } else { self.sortNameDirection = FolderSortNameDirectionZA; self.sortDirectionButton.title = @"Z-A"; } [userDefaults setInteger:self.sortNameDirection forKey:kSortNameDirectionKey]; } [self reloadData]; [userDefaults synchronize]; } #pragma mark - UITableViewDataSource - (NSInteger)tableView:(UITableView *)aTableView numberOfRowsInSection:(NSInteger)section { if (self.folder.objectsAndFoldersCount) { // For the search results tableView this will be returned because search is allowed only when the folder is not empty. return [[self searchResults] count]; } else if (self.container.rootFolder) { return 1; } else { return 0; } } - (CGFloat)tableView:(UITableView *)aTableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { if (self.folder.objectsAndFoldersCount) { // For the search results tableView this will be returned because search is allowed only when the folder is not empty. aTableView.scrollEnabled = YES; aTableView.allowsSelection = YES; return aTableView.rowHeight; } else { aTableView.scrollEnabled = NO; aTableView.allowsSelection = NO; return aTableView.frame.size.height; } } - (UITableViewCell *)tableView:(UITableView *)aTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { if (!self.folder.objectsAndFoldersCount) { NSString *noFoldersTitle = (self.account.shared || self.account.sharingAccount) ? @"No shared Files or Folders" : @"No Files or Folders"; NSString *noFoldersSubtitle = (self.account.shared || self.account.sharingAccount || [self.folder.name hasSuffix:@"/"]) ? @"" : @"Tap the + button to create a new one"; NSString *deleteFolderButtonTitle = (self.account.shared || self.account.sharingAccount) ? nil : @"Delete Folder"; SEL deleteButtonSelector = (self.account.shared || self.account.sharingAccount) ? nil : @selector(deleteButtonPressed:); self.navigationItem.rightBarButtonItem.enabled = (self.account.shared || [self.folder.name hasSuffix:@"/"]) ? NO : YES; if ([self.container.rootFolder isEqual:self.folder]) { return [self tableView:aTableView emptyCellWithImage:[UIImage imageNamed:@"empty-files.png"] title:noFoldersTitle subtitle:noFoldersSubtitle]; } else { return [self tableView:aTableView emptyCellWithImage:[UIImage imageNamed:@"empty-files.png"] title:noFoldersTitle subtitle:noFoldersSubtitle deleteButtonTitle:deleteFolderButtonTitle deleteButtonSelector:deleteButtonSelector]; } } else { // For the search results tableView this will be returned because search is allowed only when the folder is not empty. static NSString *CellIdentifier = @"Cell"; UITableViewCell *cell = [aTableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (!cell) cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease]; id item = [[self searchResults] objectAtIndex:indexPath.row]; if ([[item class] isEqual:[Folder class]]) { Folder *cellFolder = (Folder *)item; cell.textLabel.text = cellFolder.name; [cell.textLabel setLineBreakMode:UILineBreakModeTailTruncation]; if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) { cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; } else { cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton; } cell.imageView.image = [UIImage imageNamed:@"folder-icon.png"]; // NSString *folderString = @""; // if (cellFolder.folders.count > 1) { // folderString = [NSString stringWithFormat:@"%u folders, ", cellFolder.folders.count]; // } else if (cellFolder.folders.count > 0) { // folderString = @"1 folder, "; // } // NSString *objectString = @""; // if (cellFolder.objects.count != 1) { // objectString = [NSString stringWithFormat:@"%u objects", cellFolder.objects.count]; // } else { // objectString = @"1 object"; // } // cell.detailTextLabel.text = [NSString stringWithFormat:@"%@%@", folderString, objectString]; if ([[UIDevice currentDevice].systemVersion hasPrefix:@"4"]) { // iOS 4.3 if (cellFolder.lastModifiedString) { cell.detailTextLabel.text = [NSString stringWithFormat:@"%u fold. %u obj. %@", cellFolder.folders.count, cellFolder.objects.count, cellFolder.lastModifiedString]; } else { cell.detailTextLabel.text = [NSString stringWithFormat:@"%u folders %u objects", cellFolder.folders.count, cellFolder.objects.count]; } } else { // iOS 5.0+ if (cellFolder.lastModifiedString) { cell.detailTextLabel.text = [NSString stringWithFormat:@"%u 📁 %u 📄 %@", cellFolder.folders.count, cellFolder.objects.count, cellFolder.lastModifiedString]; } else { cell.detailTextLabel.text = [NSString stringWithFormat:@"%u 📁 %u 📄", cellFolder.folders.count, cellFolder.objects.count]; } } } else if ([[item class] isEqual:[StorageObject class]]) { StorageObject *cellObject = (StorageObject *)item; cell.textLabel.text = cellObject.name; [cell.textLabel setLineBreakMode:UILineBreakModeMiddleTruncation]; if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) { cell.accessoryType = UITableViewCellAccessoryNone; } else { cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton; } CFStringRef mimeType = (CFStringRef)cellObject.contentType; CFStringRef uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, mimeType, NULL); NSString *emptyPath = [[NSBundle mainBundle] pathForResource:@"empty-file" ofType:@""]; UIDocumentInteractionController *udic = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:emptyPath]]; if (((NSString *)uti).length > 0) udic.UTI = (NSString *)uti; CFRelease(uti); if (udic.icons.count > 0) cell.imageView.image = [udic.icons objectAtIndex:0]; if (cellObject.lastModifiedString) { cell.detailTextLabel.text = [NSString stringWithFormat:@"%@, %@", cellObject.humanizedBytes, cellObject.lastModifiedString]; } else { cell.detailTextLabel.text = cellObject.humanizedBytes; } if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) { } } return cell; } } #pragma mark - UITableViewDelegate - (void)tableView:(UITableView *)aTableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { if (folder.objectsAndFoldersCount) { id item = [[self searchResults] objectAtIndex:indexPath.row]; if ([[item class] isEqual:[Folder class]]) { FolderViewController *vc = (([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) ? [[FolderViewController alloc] initWithNibName:@"FolderViewController-iPad" bundle:nil] : [[FolderViewController alloc] initWithNibName:@"FolderViewController" bundle:nil]); vc.account = self.account; vc.container = self.container; vc.name = [item name]; vc.parentFolderViewController = self; vc.containersViewController = self.containersViewController; [self.navigationController pushViewController:vc animated:YES]; vc.folder = item; [aTableView deselectRowAtIndexPath:indexPath animated:YES]; if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) { self.selectedObjectViewController = nil; FolderDetailViewController *folderDetailViewController = [[FolderDetailViewController alloc] initWithNibName:@"FolderDetailViewController" bundle:nil]; folderDetailViewController.account = account; folderDetailViewController.container = container; folderDetailViewController.folder = item; folderDetailViewController.folderViewController = vc; [self presentPrimaryViewController:folderDetailViewController]; self.folderDetailVC = folderDetailViewController; [folderDetailViewController release]; } [vc release]; } else if ([[item class] isEqual:[StorageObject class]]) { if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) { StorageObjectViewController *vc = [[StorageObjectViewController alloc] initWithNibName:@"StorageObjectViewController" bundle:nil]; vc.account = self.account; vc.container = self.container; vc.folder = self.folder; vc.object = item; vc.folderViewController = self; [self presentPrimaryViewController:vc]; self.selectedObjectViewController = vc; OpenStackAppDelegate *app = [[UIApplication sharedApplication] delegate]; if (app.rootViewController.popoverController) { [app.rootViewController.popoverController dismissPopoverAnimated:YES]; } [vc release]; } else { StorageObject *cellObject = (StorageObject *)item; OpenStackAppDelegate *app = [[UIApplication sharedApplication] delegate]; NSString *filePath = [app cacheFilePathForHash:cellObject.hash]; if (filePath) { self.documentInteractionController = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:filePath]]; self.documentInteractionController.delegate = self; self.documentInteractionController.name = cellObject.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 ([cellObject isPlayableMedia]) { MediaViewController *vc = [[MediaViewController alloc] initWithNibName:@"MediaViewController" bundle:nil]; vc.container = self.container; vc.object = cellObject; [self.navigationController pushViewController:vc animated:YES]; [vc release]; } else { [self alert:@"Error" message:@"This file could not be opened."]; } } } else { 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]; } } } } - (void)tableView:(UITableView *)aTableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath { if (folder.objectsAndFoldersCount) { id item = [[self searchResults] objectAtIndex:indexPath.row]; if ([[item class] isEqual:[Folder class]]) { FolderDetailViewController *vc = [[FolderDetailViewController alloc] initWithNibName:@"FolderDetailViewController" bundle:nil]; vc.account = account; vc.container = container; vc.folder = item; vc.folderViewController = self; [self.navigationController pushViewController:vc animated:YES]; [vc release]; } else if ([[item class] isEqual:[StorageObject class]]) { StorageObjectViewController *vc = [[StorageObjectViewController alloc] initWithNibName:@"StorageObjectViewController" bundle:nil]; vc.account = self.account; vc.container = self.container; vc.folder = self.folder; vc.object = item; vc.folderViewController = self; [self.navigationController pushViewController:vc animated:YES]; [vc release]; } } } #pragma mark - UISearchDisplayDelegate - (void)updateSearchBarPlaceholder:(NSInteger)selectedScope { NSMutableDictionary *threadDict = [[NSThread currentThread] threadDictionary]; NSDateFormatter *dateFormatterSearchPlaceholder = [threadDict objectForKey:@"dateFormatterSearchPlaceholder"]; if (!dateFormatterSearchPlaceholder) { dateFormatterSearchPlaceholder = [[NSDateFormatter alloc] init]; [dateFormatterSearchPlaceholder setTimeZone:[NSTimeZone localTimeZone]]; [dateFormatterSearchPlaceholder setDateFormat:@"yyyy-MM-dd"]; [threadDict setObject:dateFormatterSearchPlaceholder forKey:@"dateFormatterSearchPlaceholder"]; [dateFormatterSearchPlaceholder release]; } if (selectedScope == 0) { // all self.searchBar.placeholder = [NSString stringWithFormat:@"e.g. .pdf or %@", [dateFormatterSearchPlaceholder stringFromDate:[NSDate date]]]; } else if (selectedScope == 1) { // name self.searchBar.placeholder = @"e.g.: .pdf"; } else if (selectedScope == 2) { // date self.searchBar.placeholder = [NSString stringWithFormat:@"e.g.: %@", [dateFormatterSearchPlaceholder stringFromDate:[NSDate date]]]; } else if (selectedScope == 3) { // type self.searchBar.placeholder = @"e.g.: .pdf or text/plain"; } else { // default self.searchBar.placeholder = @"Search Folder"; } } - (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString { self.searchFilter = searchString; [self reloadData]; return NO; } - (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchScope:(NSInteger)searchOption { [self reloadData]; [self updateSearchBarPlaceholder:searchOption]; return NO; } - (void)searchDisplayController:(UISearchDisplayController *)controller didShowSearchResultsTableView:(UITableView *)aTableView { CGRect tableViewFrame = self.searchDisplayController.searchResultsTableView.frame; tableViewFrame.size.height -= self.toolbar.frame.size.height; self.searchDisplayController.searchResultsTableView.frame = tableViewFrame; } - (void)searchDisplayControllerWillBeginSearch:(UISearchDisplayController *)controller { [self updateSearchBarPlaceholder:controller.searchBar.selectedScopeButtonIndex]; } - (void)searchDisplayControllerWillEndSearch:(UISearchDisplayController *)controller { self.searchFilter = nil; [self reloadData]; [self updateSearchBarPlaceholder:-1]; } #pragma mark - Button Handlers - (void)addButtonPressed:(id)sender { AddObjectViewController *vc = [[AddObjectViewController alloc] initWithNibName:@"AddObjectViewController" bundle:nil]; vc.account = self.account; vc.container = self.container; vc.folder = self.folder; vc.folderViewController = self; if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) { vc.modalPresentationStyle = UIModalPresentationFormSheet; OpenStackAppDelegate *app = [[UIApplication sharedApplication] delegate]; if (app.rootViewController.popoverController != nil) { [app.rootViewController.popoverController dismissPopoverAnimated:YES]; } } [self presentModalViewControllerWithNavigation:vc animated:YES]; [vc release]; } - (void)refreshButtonPressed:(id)sender { __block ActivityIndicatorView *activityIndicatorView = [ActivityIndicatorView activityIndicatorViewWithText:@"Loading..." andAddToView:self.view]; [[self.account.manager getObjects:self.container] success:^(OpenStackRequest *request) { [activityIndicatorView stopAnimatingAndRemoveFromSuperview]; [self reloadFolderViewControllers]; if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) { if (self.selectedObjectViewController) { [self.selectedObjectViewController reloadMetadataSection]; } else if ([self.folder isEqual:container.rootFolder]) { [containersViewController.containerDetailViewController reloadMetadataSection]; } else if ([parentFolderViewController.folderDetailVC.navigationController.topViewController isEqual:parentFolderViewController.folderDetailVC]) { [parentFolderViewController.folderDetailVC reloadMetadataSection]; } } } failure:^(OpenStackRequest *request) { [activityIndicatorView stopAnimatingAndRemoveFromSuperview]; [self reloadData]; [self alert:@"Error" message:@"Failed to retrieve files from server."]; }]; } - (void)homeButtonPressed:(id)sender { [self.navigationController popToViewController:containersViewController.accountHomeViewController animated:YES]; } - (void)deleteButtonPressed:(id)sender { UIActionSheet *deleteActionSheet = [[[UIActionSheet alloc] initWithTitle:@"Are you sure you want to delete this folder? This operation cannot be undone." delegate:self cancelButtonTitle:@"Cancel" destructiveButtonTitle:@"Delete Folder" otherButtonTitles:nil] autorelease]; if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) { OpenStackAppDelegate *app = [[UIApplication sharedApplication] delegate]; [deleteActionSheet showInView:app.masterNavigationController.view]; } else { [deleteActionSheet showInView:self.view]; } } #pragma mark - UIActionSheetDelegate - (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex { if (buttonIndex == 0) { StorageObject *object = [[[StorageObject alloc] init] autorelease]; object.name = object.fullPath = [self.folder fullPath]; __block ActivityIndicatorView *activityIndicatorView = [ActivityIndicatorView activityIndicatorViewWithText:@"Deleting folder..." andAddToView:self.view scrollOffset:self.tableView.contentOffset.y]; [[self.account.manager deleteObject:self.container object:object] success:^(OpenStackRequest *request) { [activityIndicatorView stopAnimatingAndRemoveFromSuperview]; [self delete]; } failure:^(OpenStackRequest *request) { [activityIndicatorView stopAnimatingAndRemoveFromSuperview]; // 404 Not Found means it's not there, so we can show the user that it's deleted if (request.responseStatusCode == 404) { [self delete]; } else { [self alert:@"There was a problem deleting this folder." request:request]; } }]; } } #pragma mark - UIDocumentInteractionControllerDelegate - (UIViewController *)documentInteractionControllerViewControllerForPreview:(UIDocumentInteractionController *)controller { return self.navigationController; } @end