UI changes.
[pithos-ios] / Classes / FolderViewController.m
1 //
2 //  FolderViewController.m
3 //  OpenStack
4 //
5 //  Created by Mike Mayo on 12/15/10.
6 //  The OpenStack project is provided under the Apache 2.0 license.
7 //
8
9 #import "FolderViewController.h"
10 #import "OpenStackAccount.h"
11 #import "Container.h"
12 #import "Folder.h"
13 #import "StorageObject.h"
14 #import "StorageObjectViewController.h"
15 #import "ContainerDetailViewController.h"
16 #import "AccountManager.h"
17 #import "ActivityIndicatorView.h"
18 #import "ContainersViewController.h"
19 #import "UIViewController+Conveniences.h"
20 #import "AddObjectViewController.h"
21 #import "OpenStackAppDelegate.h"
22 #import "RootViewController.h"
23 #import "FolderDetailViewController.h"
24
25
26 @implementation FolderViewController
27
28 @synthesize account, container, folder, containersViewController, selectedContainerIndexPath, contentsLoaded, parentFolderViewController, selectedFolderIndexPath, tableView;
29
30 - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
31     return (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) || (toInterfaceOrientation == UIInterfaceOrientationPortrait);
32 }
33
34 #pragma mark -
35 #pragma mark View lifecycle
36
37 - (void)viewDidLoad {
38     [super viewDidLoad];
39     [self addAddButton];
40     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];
41 }
42
43 - (void)viewWillAppear:(BOOL)animated {
44     [super viewWillAppear:animated];
45     
46     if (folder.name && ![@"" isEqualToString:folder.name]) {
47         self.navigationItem.title = self.folder.name;
48     } else {
49         self.navigationItem.title = self.container.name;
50     }
51 }
52
53 - (void)viewDidAppear:(BOOL)animated {
54     [super viewDidAppear:animated];
55     
56     if (!self.folder) {
57         activityIndicatorView = [[ActivityIndicatorView alloc] initWithFrame:[ActivityIndicatorView frameForText:@"Loading..."] text:@"Loading..."];
58         [activityIndicatorView addToView:self.view];
59         
60         [self.account.manager getObjects:self.container];
61         
62     }
63
64     successObserver = [[NSNotificationCenter defaultCenter] addObserverForName:@"getObjectsSucceeded" object:self.container
65                                                                          queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification* notification) 
66        {           
67            self.folder = self.container.rootFolder;
68            contentsLoaded = YES;
69            [self.tableView reloadData];                           
70            [[NSNotificationCenter defaultCenter] removeObserver:successObserver];
71            [activityIndicatorView removeFromSuperviewAndRelease];
72        }];
73
74     failureObserver = [[NSNotificationCenter defaultCenter] addObserverForName:@"renameServerSucceeded" object:self.container
75                                                                          queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification* notification) 
76        {
77            [self.tableView reloadData];                           
78            [[NSNotificationCenter defaultCenter] removeObserver:failureObserver];
79            [activityIndicatorView removeFromSuperviewAndRelease];
80        }];
81     
82 }
83
84 - (void)viewWillDisappear:(BOOL)animated {
85     [super viewWillDisappear:animated];
86     
87     if (!(folder.name && ![@"" isEqualToString:folder.name])) {
88 //        [self.containersViewController.tableView deselectRowAtIndexPath:self.selectedContainerIndexPath animated:YES];
89     }
90 }
91
92 - (IBAction)homeButtonPressed:(id)sender {
93     [self.navigationController popToRootViewControllerAnimated:YES];
94 }
95
96 #pragma mark -
97 #pragma mark Table view data source
98
99 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
100     return 1;
101 }
102
103
104 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
105     return MAX(contentsLoaded ? 1 : 0, [folder.objects count] + [folder.folders count]);
106 }
107
108 - (CGFloat)tableView:(UITableView *)aTableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
109     if ([folder.objects count] + [folder.folders count] == 0) {
110         aTableView.scrollEnabled = NO;
111         aTableView.allowsSelection = NO;
112         return aTableView.frame.size.height;
113     } else {
114         aTableView.scrollEnabled = YES;
115         aTableView.allowsSelection = YES;
116         return aTableView.rowHeight;
117     }
118 }
119
120 // Customize the appearance of table view cells.
121 - (UITableViewCell *)tableView:(UITableView *)aTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
122     if ([folder.objects count] + [folder.folders count] == 0) {
123         if ([self.container.rootFolder isEqual:self.folder]) {
124             return [self tableView:aTableView emptyCellWithImage:[UIImage imageNamed:@"empty-files.png"] title:@"No Files or Folders" subtitle:@"Tap the + button to add a new file or folder."];
125         } else {
126             return [self tableView:aTableView emptyCellWithImage:[UIImage imageNamed:@"empty-files.png"] title:@"No Files or Folders" subtitle:@"Tap the + button to add a new file or folder." deleteButtonTitle:@"Delete Folder" deleteButtonSelector:@selector(deleteButtonPressed:)];
127         }
128     } else {
129         static NSString *CellIdentifier = @"Cell";
130         
131         UITableViewCell *cell = [aTableView dequeueReusableCellWithIdentifier:CellIdentifier];
132         if (cell == nil) {
133             cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
134         }
135         
136         id item = [self.folder.sortedContents objectAtIndex:indexPath.row];    
137         cell.textLabel.text = [item name];
138         
139         if ([[item class] isEqual:[Folder class]]) {
140             if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
141                 cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
142             } else {
143                 cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
144             }
145             cell.imageView.image = [UIImage imageNamed:@"folder-icon.png"];
146             
147             NSString *folderString = @"";
148             NSString *objectString = @"";
149             if ([[item folders] count] > 1) {
150                 folderString = [NSString stringWithFormat:@"%i folders, ", [[item folders] count]];
151             } else if ([[item folders] count] > 0) {
152                 folderString = @"1 folder, ";
153             }
154             if ([[item objects] count] != 1) {
155                 objectString = [NSString stringWithFormat:@"%i objects", [[item objects] count]];
156             } else if ([[item objects] count]) {
157                 objectString = @"1 object";
158             }
159             cell.detailTextLabel.text = [NSString stringWithFormat:@"%@%@", folderString, objectString];
160         } else if ([[item class] isEqual:[StorageObject class]]) {
161             cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
162             
163             StorageObject *object = item;
164             NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
165             NSString *documentsDirectory = [paths objectAtIndex:0];
166             NSString *shortPath = [NSString stringWithFormat:@"/%@/%@", self.container.name, object.fullPath];
167             NSString *filePath = [documentsDirectory stringByAppendingString:shortPath];
168
169             
170             if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
171                 UIDocumentInteractionController *udic = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:filePath]];
172                 if ([udic.icons count] > 0) {
173                     cell.imageView.image = [udic.icons objectAtIndex:0];                    
174                 }
175             } else {
176                 NSString *emptyPath = [[NSBundle mainBundle] pathForResource:@"empty-file" ofType:@""];
177                 UIDocumentInteractionController *udic = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:emptyPath]];
178                 if ([udic.icons count] > 0) {
179                     cell.imageView.image = [udic.icons objectAtIndex:0]; //[UIImage imageNamed:@"file-icon.png"];        
180                 }
181             }
182             
183             cell.detailTextLabel.text = [NSString stringWithFormat:@"%@, %@", [item humanizedBytes], [item contentType]];
184         }
185         
186         return cell;
187     }        
188 }
189
190 #pragma mark -
191 #pragma mark Table view delegate
192
193 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
194     if ([folder.objects count] + [folder.folders count] > 0) {
195         id item = [self.folder.sortedContents objectAtIndex:indexPath.row];        
196         if ([[item class] isEqual:[Folder class]]) {
197             FolderViewController *vc = [[FolderViewController alloc] initWithNibName:@"FolderViewController" bundle:nil];
198             vc.account = self.account;
199             vc.container = self.container;
200             vc.folder = item;
201             vc.contentsLoaded = YES;
202             vc.selectedFolderIndexPath = indexPath;
203             vc.parentFolderViewController = self;
204             [self.navigationController pushViewController:vc animated:YES];
205             [vc release];
206             [self.tableView deselectRowAtIndexPath:indexPath animated:YES];
207             if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
208                 Folder *folderForDetailView;
209                 if ([folder.sortedContents count] > 0) {
210                     folderForDetailView = [self.folder.sortedContents objectAtIndex:indexPath.row];
211                 }
212                 FolderDetailViewController *folderDetailViewController = [[FolderDetailViewController alloc] initWithNibName:@"FolderDetailViewController" bundle:nil];
213                 folderDetailViewController.account = account;
214                 folderDetailViewController.container = container;
215                 folderDetailViewController.folder = folderForDetailView;
216                 [self presentPrimaryViewController:folderDetailViewController];
217                 [folderDetailViewController release];
218             }
219         } else if ([[item class] isEqual:[StorageObject class]]) {
220             StorageObjectViewController *vc = [[StorageObjectViewController alloc] initWithNibName:@"StorageObjectViewController" bundle:nil];
221             vc.account = self.account;
222             vc.container = self.container;
223             vc.folder = self.folder;
224             vc.object = item;
225             vc.folderViewController = self;
226             vc.selectedIndexPath = indexPath;
227             if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
228                 [self.navigationController presentPrimaryViewController:vc];
229                 OpenStackAppDelegate *app = [[UIApplication sharedApplication] delegate];
230                 if (app.rootViewController.popoverController != nil) {
231                     [app.rootViewController.popoverController dismissPopoverAnimated:YES];
232                 }
233             } else {
234                 [self.navigationController pushViewController:vc animated:YES];
235                 [self.tableView deselectRowAtIndexPath:indexPath animated:YES];
236             }
237             [vc release];
238         }
239     }
240 }
241
242 - (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath {
243     Folder *folderForDetailView;
244     if ([folder.sortedContents count] > 0) {
245         folderForDetailView = [self.folder.sortedContents objectAtIndex:indexPath.row];
246     }
247     FolderDetailViewController *vc = [[FolderDetailViewController alloc] initWithNibName:@"FolderDetailViewController" bundle:nil];
248     vc.account = account;
249     vc.container = container;
250     vc.folder = folderForDetailView;
251
252     [self.navigationController pushViewController:vc animated:YES];
253     [vc release];
254 }
255
256 #pragma mark -
257 #pragma mark Buttons
258
259 - (void)addButtonPressed:(id)sender {
260     AddObjectViewController *vc = [[AddObjectViewController alloc] initWithNibName:@"AddObjectViewController" bundle:nil];
261     vc.account = self.account;
262     vc.container = self.container;
263     vc.folder = self.folder;
264     vc.folderViewController = self;
265     if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
266         vc.modalPresentationStyle = UIModalPresentationFormSheet;
267         OpenStackAppDelegate *app = [[UIApplication sharedApplication] delegate];
268         if (app.rootViewController.popoverController != nil) {
269             [app.rootViewController.popoverController dismissPopoverAnimated:YES];
270         }
271     }
272     [self presentModalViewControllerWithNavigation:vc animated:YES];
273     [vc release];
274 }
275
276 - (void)deleteButtonPressed:(id)sender {
277     [deleteActionSheet showInView:self.view];    
278 }
279
280 #pragma mark -
281 #pragma mark Action Sheet Delegate
282
283 - (void)deleteFolderRow {
284     [self.parentFolderViewController.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:selectedFolderIndexPath] withRowAnimation:UITableViewRowAnimationLeft];
285 }
286
287 - (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
288     if (buttonIndex == 0) {
289         StorageObject *object = [[StorageObject alloc] init];
290         object.name = object.fullPath = [self.folder fullPath];
291         
292         NSString *activityMessage = @"Deleting folder...";
293         activityIndicatorView = [[ActivityIndicatorView alloc] initWithFrame:[ActivityIndicatorView frameForText:activityMessage] text:activityMessage];
294         [activityIndicatorView addToView:self.view scrollOffset:self.tableView.contentOffset.y];    
295
296         [self.account.manager deleteObject:self.container object:object];
297         
298         
299         successObserver = [[NSNotificationCenter defaultCenter] addObserverForName:@"deleteObjectSucceeded" object:object
300                                                                              queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification* notification) 
301         {
302             if (self.folder.parent) {
303                 [self.folder.parent.folders removeObjectForKey:self.folder.name];
304             } else {
305                 [self.container.rootFolder.folders removeObjectForKey:self.folder.name];
306             }
307             [self.account persist];
308
309             [activityIndicatorView removeFromSuperviewAndRelease];
310             [self.navigationController popViewControllerAnimated:YES];
311
312             if (self.folder.parent) {
313                 if ([self.folder.parent.folders count] + [self.folder.parent.objects count] == 0) {
314                     [self.parentFolderViewController.tableView reloadData];
315                 } else {
316                     [self.parentFolderViewController.tableView selectRowAtIndexPath:selectedFolderIndexPath animated:YES scrollPosition:UITableViewScrollPositionNone];
317                     [NSTimer scheduledTimerWithTimeInterval:0.75 target:self selector:@selector(deleteFolderRow) userInfo:nil repeats:NO];
318                 }
319             } else {
320                 if ([self.container.rootFolder.folders count] + [self.container.rootFolder.objects count] == 0) {
321                     [self.parentFolderViewController.tableView reloadData];
322                 } else {
323                     [self.parentFolderViewController.tableView selectRowAtIndexPath:selectedFolderIndexPath animated:YES scrollPosition:UITableViewScrollPositionNone];
324                     [NSTimer scheduledTimerWithTimeInterval:0.75 target:self selector:@selector(deleteFolderRow) userInfo:nil repeats:NO];
325                 }
326             }
327             
328             
329             
330             [[NSNotificationCenter defaultCenter] removeObserver:successObserver];
331             [object release];
332         }];
333         
334         failureObserver = [[NSNotificationCenter defaultCenter] addObserverForName:@"deleteObjectFailed" object:object
335                                                                              queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification* notification) 
336         {
337             [activityIndicatorView removeFromSuperviewAndRelease];
338             [self alert:@"There was a problem deleting this folder." request:[notification.userInfo objectForKey:@"request"]];
339             [[NSNotificationCenter defaultCenter] removeObserver:failureObserver];
340             [object release];
341         }];
342     }
343 }
344
345 #pragma mark -
346 #pragma mark Memory management
347
348 - (void)dealloc {
349     [account release];
350     [container release];
351     [folder release];
352     [containersViewController release];
353     [selectedContainerIndexPath release];
354     [deleteActionSheet release];
355     [parentFolderViewController release];
356     [selectedFolderIndexPath release];
357     [super dealloc];
358 }
359
360
361 @end
362