root / Classes / FolderViewController.m @ ef74c42f
History | View | Annotate | Download (40.2 kB)
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 "StorageObject.h" |
13 |
#import "StorageObjectViewController.h" |
14 |
#import "ContainerDetailViewController.h" |
15 |
#import "AccountManager.h" |
16 |
#import "ActivityIndicatorView.h" |
17 |
#import "ContainersViewController.h" |
18 |
#import "UIViewController+Conveniences.h" |
19 |
#import "AddObjectViewController.h" |
20 |
#import "OpenStackAppDelegate.h" |
21 |
#import "RootViewController.h" |
22 |
#import "FolderDetailViewController.h" |
23 |
#import "AccountHomeViewController.h" |
24 |
#import "PithosImageViewController.h" |
25 |
#import "OpenStackRequest.h" |
26 |
#import "JSON.h" |
27 |
#import "APICallback.h" |
28 |
#import <MobileCoreServices/MobileCoreServices.h> |
29 |
#import "ComputeModel.h" |
30 |
#import "MediaViewController.h" |
31 |
|
32 |
static NSString *kSortTypeKey = @"sortType"; |
33 |
static NSString *kSortNameDirectionKey = @"sortNameDirection"; |
34 |
static NSString *kSortDateDirectionKey = @"sortDateDirection"; |
35 |
|
36 |
@implementation FolderViewController |
37 |
|
38 |
@synthesize account, container, folder, name, containersViewController, parentFolderViewController, refreshWhenAppeared, deletedObject; |
39 |
@synthesize searchDisplayController, tableView ,searchBar, refreshButton, sortTypeButton, sortDirectionButton; |
40 |
@synthesize searchFilter, searchActiveOnRotation, sortType, sortNameDirection, sortDateDirection;; |
41 |
@synthesize folderDetailVC, selectedObjectViewController, documentInteractionController; |
42 |
|
43 |
#pragma mark - View lifecycle |
44 |
|
45 |
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { |
46 |
if (([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) && |
47 |
self.searchDisplayController.active && self.searchBar.isFirstResponder) { |
48 |
UIInterfaceOrientation statusBarOrientation = [[UIApplication sharedApplication] statusBarOrientation]; |
49 |
if (UIInterfaceOrientationIsPortrait(toInterfaceOrientation) && UIInterfaceOrientationIsLandscape(statusBarOrientation)) { |
50 |
[self.searchBar resignFirstResponder]; |
51 |
} else if (UIInterfaceOrientationIsLandscape(toInterfaceOrientation) && UIInterfaceOrientationIsPortrait(statusBarOrientation)) { |
52 |
self.searchActiveOnRotation = YES; |
53 |
} |
54 |
} |
55 |
|
56 |
[super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration]; |
57 |
} |
58 |
|
59 |
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation { |
60 |
[super didRotateFromInterfaceOrientation:fromInterfaceOrientation]; |
61 |
|
62 |
if (([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) && |
63 |
UIInterfaceOrientationIsPortrait(fromInterfaceOrientation) && |
64 |
UIInterfaceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation])) { |
65 |
if (self.searchDisplayController.active && self.searchActiveOnRotation) { |
66 |
[self.searchBar becomeFirstResponder]; |
67 |
CGRect tableViewFrame = self.tableView.frame; |
68 |
tableViewFrame.size.height = self.toolbar.frame.origin.y - tableViewFrame.origin.y; |
69 |
self.tableView.frame = tableViewFrame; |
70 |
self.searchDisplayController.searchResultsTableView.frame = tableViewFrame; |
71 |
} |
72 |
self.searchActiveOnRotation = NO; |
73 |
} |
74 |
} |
75 |
|
76 |
- (void)viewDidLoad { |
77 |
[super viewDidLoad]; |
78 |
[self addAddButton]; |
79 |
} |
80 |
|
81 |
- (void)viewWillAppear:(BOOL)animated { |
82 |
[super viewWillAppear:animated]; |
83 |
|
84 |
self.navigationItem.title = (self.name.length ? self.name : self.container.name); |
85 |
|
86 |
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; |
87 |
|
88 |
self.sortType = [userDefaults integerForKey:kSortTypeKey]; |
89 |
self.sortTypeButton.title = (self.sortType == FolderSortTypeDate) ? @"date" : @"name"; |
90 |
|
91 |
self.sortNameDirection = [userDefaults integerForKey:kSortNameDirectionKey]; |
92 |
self.sortDateDirection = [userDefaults integerForKey:kSortDateDirectionKey]; |
93 |
if (self.sortType == FolderSortTypeDate) { |
94 |
self.sortDirectionButton.title = (self.sortDateDirection == FolderSortDateDirectionNewestFirst) ? @"newest first" : @"oldest first"; |
95 |
} else { |
96 |
self.sortDirectionButton.title = (self.sortNameDirection == FolderSortNameDirectionZA) ? @"Z-A" : @"A-Z"; |
97 |
} |
98 |
|
99 |
if (!container.rootFolder || !deletedObject) { |
100 |
self.deletedObject = nil; |
101 |
[self reloadData]; |
102 |
} else if ([[deletedObject class] isEqual:[Folder class]]) { |
103 |
Folder *deletedFolder = (Folder *)deletedObject; |
104 |
if (![folder.folders objectForKey:deletedFolder.name] || |
105 |
([[self searchResults] indexOfObject:[folder.folders objectForKey:deletedFolder.name]] == NSNotFound)) { |
106 |
self.deletedObject = nil; |
107 |
[self reloadData]; |
108 |
} else if (folder.objectsAndFoldersCount == 1) { |
109 |
[self deleteAnimatedObject:deletedObject]; |
110 |
} |
111 |
} else if ([[deletedObject class] isEqual:[StorageObject class]]) { |
112 |
StorageObject *deletedStorageObject = (StorageObject *)deletedObject; |
113 |
if (![folder.objects objectForKey:deletedStorageObject.name] || |
114 |
([[self searchResults] indexOfObject:[folder.objects objectForKey:deletedStorageObject.name]] == NSNotFound)) { |
115 |
self.deletedObject = nil; |
116 |
[self reloadData]; |
117 |
} else if (folder.objectsAndFoldersCount == 1) { |
118 |
[self deleteAnimatedObject:deletedObject]; |
119 |
} |
120 |
} else { |
121 |
self.deletedObject = nil; |
122 |
} |
123 |
} |
124 |
|
125 |
- (void)viewDidAppear:(BOOL)animated { |
126 |
[super viewDidAppear:animated]; |
127 |
|
128 |
if (!container.rootFolder) { |
129 |
// Container objects not fetched yet. |
130 |
refreshWhenAppeared = YES; |
131 |
} else if (!folder) { |
132 |
// This controller's folder has been deleted. |
133 |
parentFolderViewController.refreshWhenAppeared = YES; |
134 |
[self.navigationController popViewControllerAnimated:YES]; |
135 |
return; |
136 |
} else if (account.shared && !folder.objectsAndFoldersCount) { |
137 |
// The shared folder is empty, probably after a delete. |
138 |
[self.navigationController popViewControllerAnimated:YES]; |
139 |
return; |
140 |
} else if (deletedObject) { |
141 |
[self deleteAnimatedObject:deletedObject]; |
142 |
} |
143 |
|
144 |
if (refreshWhenAppeared) { |
145 |
refreshWhenAppeared = NO; |
146 |
[self refreshButtonPressed:nil]; |
147 |
} |
148 |
} |
149 |
|
150 |
- (void)viewWillDisappear:(BOOL)animated { |
151 |
[super viewWillDisappear:animated]; |
152 |
if (![self.navigationController.viewControllers containsObject:self] && self.parentViewController) { |
153 |
[parentFolderViewController setDetailViewController]; |
154 |
} |
155 |
} |
156 |
|
157 |
#pragma mark - Memory management |
158 |
|
159 |
- (void)dealloc { |
160 |
[account release]; |
161 |
[container release]; |
162 |
[folder release]; |
163 |
[name release]; |
164 |
[containersViewController release]; |
165 |
[parentFolderViewController release]; |
166 |
[searchDisplayController release]; |
167 |
[searchBar release]; |
168 |
[refreshButton release]; |
169 |
[sortTypeButton release]; |
170 |
[sortDirectionButton release]; |
171 |
[deletedObject release]; |
172 |
[searchFilter release]; |
173 |
[documentInteractionController release]; |
174 |
[super dealloc]; |
175 |
} |
176 |
|
177 |
#pragma mark - Internal |
178 |
|
179 |
- (void)showSearchBar:(BOOL)show { |
180 |
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPhone) { |
181 |
if (show && !self.tableView.tableHeaderView) { |
182 |
self.tableView.tableHeaderView = self.searchBar; |
183 |
self.tableView.contentOffset = CGPointMake(0.0, 44.0); |
184 |
} else if (!show) { |
185 |
if (self.searchDisplayController.active) |
186 |
[self.searchDisplayController setActive:NO animated:NO]; |
187 |
self.tableView.tableHeaderView = nil; |
188 |
} |
189 |
} else { |
190 |
if (show && self.searchBar.hidden) { |
191 |
self.searchBar.hidden = NO; |
192 |
self.searchBar.frame = CGRectMake(0.0, 0.0, self.searchBar.frame.size.width, self.searchBar.frame.size.height); |
193 |
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); |
194 |
} else if (!show && !self.searchBar.hidden) { |
195 |
self.searchBar.frame = CGRectMake(0.0, -self.searchBar.frame.size.height, self.searchBar.frame.size.width, self.searchBar.frame.size.height); |
196 |
self.tableView.frame = CGRectMake(0.0, 0, self.tableView.frame.size.width, self.tableView.frame.size.height + self.searchBar.frame.size.height); |
197 |
self.searchBar.hidden = YES; |
198 |
if (self.searchDisplayController.active) |
199 |
[self.searchDisplayController setActive:NO animated:NO]; |
200 |
} |
201 |
} |
202 |
} |
203 |
|
204 |
- (void)reloadFolderViewControllers { |
205 |
NSArray *viewControllers = [self.navigationController viewControllers]; |
206 |
|
207 |
int rootFolderControllerIndex = [viewControllers indexOfObject:self.containersViewController] + 1; |
208 |
FolderViewController *rootFolderViewController = [viewControllers objectAtIndex:rootFolderControllerIndex]; |
209 |
rootFolderViewController.folder = self.container.rootFolder; |
210 |
|
211 |
for (int i = rootFolderControllerIndex + 1; i < [viewControllers count]; i++) { |
212 |
FolderViewController *folderViewController = [viewControllers objectAtIndex:i]; |
213 |
Folder *parentFolder = folderViewController.parentFolderViewController.folder; |
214 |
|
215 |
folderViewController.folder = [parentFolder.folders objectForKey:folderViewController.folder.name]; |
216 |
} |
217 |
if (!self.folder || (account.shared && !folder.objectsAndFoldersCount)) { |
218 |
[self.navigationController popViewControllerAnimated:YES]; |
219 |
} else if (account.shared) { |
220 |
[self setDetailViewController]; |
221 |
} |
222 |
} |
223 |
|
224 |
//- (void)deleteObjectRow:(NSTimer *)timer { |
225 |
// [self.folder removeObject:[timer.userInfo objectForKey:@"object"]]; |
226 |
// if (folder == container.rootFolder) { |
227 |
// container.count -= 1; |
228 |
// } |
229 |
// [account persist]; |
230 |
// [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:[timer.userInfo objectForKey:@"indexPath"]] |
231 |
// withRowAnimation:UITableViewRowAnimationLeft]; |
232 |
// if (self.searchDisplayController.active && self.searchFilter && self.searchFilter.length) |
233 |
// [self.searchDisplayController.searchResultsTableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:[timer.userInfo objectForKey:@"indexPath"]] |
234 |
// withRowAnimation:UITableViewRowAnimationLeft]; |
235 |
// self.refreshButton.enabled = YES; |
236 |
//} |
237 |
|
238 |
- (NSArray *)searchResults { |
239 |
return [self.folder sortedContentsUsingFilter:self.searchFilter |
240 |
scope:[self.searchBar.scopeButtonTitles objectAtIndex:self.searchBar.selectedScopeButtonIndex] |
241 |
sortType:self.sortType |
242 |
sortDirection:((self.sortType == FolderSortTypeDate) ? self.sortDateDirection : self.sortNameDirection)]; |
243 |
} |
244 |
|
245 |
- (void)delete { |
246 |
parentFolderViewController.deletedObject = folder; |
247 |
[self.navigationController popViewControllerAnimated:YES]; |
248 |
[parentFolderViewController setDetailViewController]; |
249 |
} |
250 |
|
251 |
#pragma mark - Properties |
252 |
|
253 |
- (void)setFolder:(Folder *)aFolder { |
254 |
[folder release]; |
255 |
folder = [aFolder retain]; |
256 |
[self showSearchBar:(self.container.rootFolder && self.folder && self.folder.objectsAndFoldersCount)]; |
257 |
if (([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) && self.selectedObjectViewController && folder) { |
258 |
StorageObject *newObject = [folder.objects objectForKey:self.selectedObjectViewController.object.name]; |
259 |
if (newObject) |
260 |
self.selectedObjectViewController.object = newObject; |
261 |
// We don't set nil otherwise, this will be done in reloadData, when setDetailViewController is called. |
262 |
} |
263 |
[self reloadData]; |
264 |
} |
265 |
|
266 |
#pragma mark - Actions |
267 |
|
268 |
- (void)reloadData { |
269 |
[self.tableView reloadData]; |
270 |
BOOL searchResultsShown = self.searchDisplayController.active && self.searchFilter && self.searchFilter.length; |
271 |
if (searchResultsShown) |
272 |
[self.searchDisplayController.searchResultsTableView reloadData]; |
273 |
if (([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) && self.selectedObjectViewController) { |
274 |
NSUInteger selectedIndex = [[self searchResults] indexOfObject:self.selectedObjectViewController.object]; |
275 |
if (selectedIndex == NSNotFound) { |
276 |
[self setDetailViewController]; |
277 |
} else { |
278 |
NSIndexPath *selectIndexPath = [NSIndexPath indexPathForRow:selectedIndex inSection:0]; |
279 |
[self.tableView selectRowAtIndexPath:selectIndexPath animated:NO scrollPosition:UITableViewScrollPositionNone]; |
280 |
if (searchResultsShown) |
281 |
[self.searchDisplayController.searchResultsTableView selectRowAtIndexPath:selectIndexPath |
282 |
animated:NO |
283 |
scrollPosition:UITableViewScrollPositionNone]; |
284 |
} |
285 |
} |
286 |
} |
287 |
|
288 |
- (void)setDetailViewController { |
289 |
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) { |
290 |
self.selectedObjectViewController = nil; |
291 |
if (self.folder) { |
292 |
if ([self.folder isEqual:self.container.rootFolder]) { |
293 |
[containersViewController setDetailViewControllerForContainer:container]; |
294 |
} else { |
295 |
FolderDetailViewController *vc = [[FolderDetailViewController alloc] initWithNibName:@"FolderDetailViewController" bundle:nil]; |
296 |
vc.account = self.account; |
297 |
vc.container = self.container; |
298 |
vc.folder = self.folder; |
299 |
vc.folderViewController = self.parentFolderViewController; |
300 |
[self presentPrimaryViewController:vc]; |
301 |
self.parentFolderViewController.folderDetailVC = vc; |
302 |
[vc release]; |
303 |
containersViewController.containerDetailViewController = nil; |
304 |
} |
305 |
} |
306 |
} |
307 |
} |
308 |
|
309 |
//- (void)deleteAnimatedObject:(StorageObject *)object { |
310 |
// NSIndexPath *deleteIndexPath = [NSIndexPath indexPathForRow:[[self searchResults] indexOfObject:object] inSection:0]; |
311 |
// [self.tableView selectRowAtIndexPath:deleteIndexPath animated:YES scrollPosition:UITableViewScrollPositionNone]; |
312 |
// if (self.searchDisplayController.active && self.searchFilter && self.searchFilter.length) |
313 |
// [self.searchDisplayController.searchResultsTableView selectRowAtIndexPath:deleteIndexPath |
314 |
// animated:YES |
315 |
// scrollPosition:UITableViewScrollPositionNone]; |
316 |
// NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:object, @"object", deleteIndexPath, @"indexPath", nil]; |
317 |
// [NSTimer scheduledTimerWithTimeInterval:0.75 target:self selector:@selector(deleteObjectRow:) userInfo:userInfo repeats:NO]; |
318 |
//} |
319 |
|
320 |
- (void)deleteAnimatedObject:(id)object { |
321 |
NSIndexPath *deletedObjectIndexPath = nil; |
322 |
if ([[object class] isEqual:[Folder class]]) { |
323 |
Folder *deletedFolder = [folder.folders objectForKey:[object name]]; |
324 |
if (deletedFolder) { |
325 |
if (folder.objectsAndFoldersCount == 1) { |
326 |
// If the deleted folder is the sole object of the folder, remove and reload to show the empty folder cell. |
327 |
[folder removeFolder:deletedFolder]; |
328 |
if (folder == container.rootFolder) { |
329 |
container.count -= 1; |
330 |
} |
331 |
[account persist]; |
332 |
self.folder = self.folder; |
333 |
} else { |
334 |
NSUInteger deletedFolderIndex = [[self searchResults] indexOfObject:deletedFolder]; |
335 |
if (deletedFolderIndex != NSNotFound) { |
336 |
deletedObjectIndexPath = [NSIndexPath indexPathForRow:deletedFolderIndex inSection:0]; |
337 |
} |
338 |
[folder removeFolder:deletedFolder]; |
339 |
if (folder == container.rootFolder) { |
340 |
container.count -= 1; |
341 |
} |
342 |
[account persist]; |
343 |
} |
344 |
} |
345 |
} else if ([[object class] isEqual:[StorageObject class]]) { |
346 |
StorageObject *deletedStorageObject = [folder.objects objectForKey:[object name]]; |
347 |
if (deletedStorageObject) { |
348 |
if (folder.objectsAndFoldersCount == 1) { |
349 |
// If the deleted storage object is the sole object of the folder, remove and reload to show the empty folder cell. |
350 |
[folder removeObject:deletedStorageObject]; |
351 |
if (folder == container.rootFolder) { |
352 |
container.count -= 1; |
353 |
} |
354 |
[account persist]; |
355 |
self.folder = self.folder; |
356 |
} else { |
357 |
NSUInteger deletedStorageObjectIndex = [[self searchResults] indexOfObject:deletedStorageObject]; |
358 |
if (deletedStorageObjectIndex != NSNotFound) { |
359 |
deletedObjectIndexPath = [NSIndexPath indexPathForRow:deletedStorageObjectIndex inSection:0]; |
360 |
} |
361 |
[folder removeObject:deletedStorageObject]; |
362 |
if (folder == container.rootFolder) { |
363 |
container.count -= 1; |
364 |
} |
365 |
[account persist]; |
366 |
} |
367 |
} |
368 |
} |
369 |
if (deletedObjectIndexPath) { |
370 |
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:deletedObjectIndexPath] withRowAnimation:UITableViewRowAnimationLeft]; |
371 |
if (searchDisplayController.active && searchFilter && searchFilter.length) { |
372 |
[searchDisplayController.searchResultsTableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:deletedObjectIndexPath] |
373 |
withRowAnimation:UITableViewRowAnimationLeft]; |
374 |
} |
375 |
} |
376 |
self.deletedObject = nil; |
377 |
refreshWhenAppeared = NO; |
378 |
[self refreshButtonPressed:nil]; |
379 |
} |
380 |
|
381 |
- (IBAction)toggleSortType:(id)sender { |
382 |
if (self.sortType == FolderSortTypeDate) { |
383 |
self.sortType = FolderSortTypeName; |
384 |
self.sortTypeButton.title = @"name"; |
385 |
self.sortDirectionButton.title = (self.sortNameDirection == FolderSortNameDirectionZA) ? @"Z-A" : @"A-Z"; |
386 |
} else { |
387 |
self.sortType = FolderSortTypeDate; |
388 |
self.sortTypeButton.title = @"date"; |
389 |
self.sortDirectionButton.title = (self.sortDateDirection == FolderSortDateDirectionNewestFirst) ? @"newest first" : @"oldest first"; |
390 |
} |
391 |
[self reloadData]; |
392 |
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; |
393 |
[userDefaults setInteger:self.sortType forKey:kSortTypeKey]; |
394 |
[userDefaults synchronize]; |
395 |
} |
396 |
|
397 |
- (IBAction)toggleSortDirection:(id)sender { |
398 |
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; |
399 |
if (self.sortType == FolderSortTypeDate) { |
400 |
if (self.sortDateDirection == FolderSortDateDirectionNewestFirst) { |
401 |
self.sortDateDirection = FolderSortDateDirectionOldestFirst; |
402 |
self.sortDirectionButton.title = @"oldest first"; |
403 |
} else { |
404 |
self.sortDateDirection = FolderSortDateDirectionNewestFirst; |
405 |
self.sortDirectionButton.title = @"newest first"; |
406 |
} |
407 |
[userDefaults setInteger:self.sortDateDirection forKey:kSortDateDirectionKey]; |
408 |
} else { |
409 |
if (self.sortNameDirection == FolderSortNameDirectionZA) { |
410 |
self.sortNameDirection = FolderSortNameDirectionAZ; |
411 |
self.sortDirectionButton.title = @"A-Z"; |
412 |
} else { |
413 |
self.sortNameDirection = FolderSortNameDirectionZA; |
414 |
self.sortDirectionButton.title = @"Z-A"; |
415 |
} |
416 |
[userDefaults setInteger:self.sortNameDirection forKey:kSortNameDirectionKey]; |
417 |
} |
418 |
[self reloadData]; |
419 |
[userDefaults synchronize]; |
420 |
} |
421 |
|
422 |
#pragma mark - UITableViewDataSource |
423 |
|
424 |
- (NSInteger)tableView:(UITableView *)aTableView numberOfRowsInSection:(NSInteger)section { |
425 |
if (self.folder.objectsAndFoldersCount) { |
426 |
// For the search results tableView this will be returned because search is allowed only when the folder is not empty. |
427 |
return [[self searchResults] count]; |
428 |
} else if (self.container.rootFolder) { |
429 |
return 1; |
430 |
} else { |
431 |
return 0; |
432 |
} |
433 |
} |
434 |
|
435 |
- (CGFloat)tableView:(UITableView *)aTableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { |
436 |
if (self.folder.objectsAndFoldersCount) { |
437 |
// For the search results tableView this will be returned because search is allowed only when the folder is not empty. |
438 |
aTableView.scrollEnabled = YES; |
439 |
aTableView.allowsSelection = YES; |
440 |
return aTableView.rowHeight; |
441 |
} else { |
442 |
aTableView.scrollEnabled = NO; |
443 |
aTableView.allowsSelection = NO; |
444 |
return aTableView.frame.size.height; |
445 |
} |
446 |
} |
447 |
|
448 |
- (UITableViewCell *)tableView:(UITableView *)aTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { |
449 |
if (!self.folder.objectsAndFoldersCount) { |
450 |
NSString *noFoldersTitle = (self.account.shared || self.account.sharingAccount) ? |
451 |
@"No shared Files or Folders" : @"No Files or Folders"; |
452 |
NSString *noFoldersSubtitle = (self.account.shared || self.account.sharingAccount || [self.folder.name hasSuffix:@"/"]) ? |
453 |
@"" : @"Tap the + button to create a new one"; |
454 |
NSString *deleteFolderButtonTitle = (self.account.shared || self.account.sharingAccount) ? nil : @"Delete Folder"; |
455 |
SEL deleteButtonSelector = (self.account.shared || self.account.sharingAccount) ? nil : @selector(deleteButtonPressed:); |
456 |
self.navigationItem.rightBarButtonItem.enabled = (self.account.shared || [self.folder.name hasSuffix:@"/"]) ? NO : YES; |
457 |
|
458 |
if ([self.container.rootFolder isEqual:self.folder]) { |
459 |
return [self tableView:aTableView |
460 |
emptyCellWithImage:[UIImage imageNamed:@"empty-files.png"] |
461 |
title:noFoldersTitle |
462 |
subtitle:noFoldersSubtitle]; |
463 |
} else { |
464 |
return [self tableView:aTableView |
465 |
emptyCellWithImage:[UIImage imageNamed:@"empty-files.png"] |
466 |
title:noFoldersTitle |
467 |
subtitle:noFoldersSubtitle |
468 |
deleteButtonTitle:deleteFolderButtonTitle |
469 |
deleteButtonSelector:deleteButtonSelector]; |
470 |
} |
471 |
} else { |
472 |
// For the search results tableView this will be returned because search is allowed only when the folder is not empty. |
473 |
static NSString *CellIdentifier = @"Cell"; |
474 |
UITableViewCell *cell = [aTableView dequeueReusableCellWithIdentifier:CellIdentifier]; |
475 |
if (!cell) |
476 |
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease]; |
477 |
|
478 |
id item = [[self searchResults] objectAtIndex:indexPath.row]; |
479 |
if ([[item class] isEqual:[Folder class]]) { |
480 |
Folder *cellFolder = (Folder *)item; |
481 |
cell.textLabel.text = cellFolder.name; |
482 |
[cell.textLabel setLineBreakMode:UILineBreakModeTailTruncation]; |
483 |
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) { |
484 |
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; |
485 |
} else { |
486 |
cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton; |
487 |
} |
488 |
|
489 |
cell.imageView.image = [UIImage imageNamed:@"folder-icon.png"]; |
490 |
|
491 |
// NSString *folderString = @""; |
492 |
// if (cellFolder.folders.count > 1) { |
493 |
// folderString = [NSString stringWithFormat:@"%u folders, ", cellFolder.folders.count]; |
494 |
// } else if (cellFolder.folders.count > 0) { |
495 |
// folderString = @"1 folder, "; |
496 |
// } |
497 |
// NSString *objectString = @""; |
498 |
// if (cellFolder.objects.count != 1) { |
499 |
// objectString = [NSString stringWithFormat:@"%u objects", cellFolder.objects.count]; |
500 |
// } else { |
501 |
// objectString = @"1 object"; |
502 |
// } |
503 |
// cell.detailTextLabel.text = [NSString stringWithFormat:@"%@%@", folderString, objectString]; |
504 |
|
505 |
if ([[UIDevice currentDevice].systemVersion hasPrefix:@"4"]) { |
506 |
// iOS 4.3 |
507 |
if (cellFolder.lastModifiedString) { |
508 |
cell.detailTextLabel.text = [NSString stringWithFormat:@"%u fold. %u obj. %@", |
509 |
cellFolder.folders.count, cellFolder.objects.count, cellFolder.lastModifiedString]; |
510 |
} else { |
511 |
cell.detailTextLabel.text = [NSString stringWithFormat:@"%u folders %u objects", cellFolder.folders.count, cellFolder.objects.count]; |
512 |
} |
513 |
} else { |
514 |
// iOS 5.0+ |
515 |
if (cellFolder.lastModifiedString) { |
516 |
cell.detailTextLabel.text = [NSString stringWithFormat:@"%u ๐ %u ๐ %@", |
517 |
cellFolder.folders.count, cellFolder.objects.count, cellFolder.lastModifiedString]; |
518 |
} else { |
519 |
cell.detailTextLabel.text = [NSString stringWithFormat:@"%u ๐ %u ๐", cellFolder.folders.count, cellFolder.objects.count]; |
520 |
} |
521 |
} |
522 |
} else if ([[item class] isEqual:[StorageObject class]]) { |
523 |
StorageObject *cellObject = (StorageObject *)item; |
524 |
cell.textLabel.text = cellObject.name; |
525 |
[cell.textLabel setLineBreakMode:UILineBreakModeMiddleTruncation]; |
526 |
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) { |
527 |
cell.accessoryType = UITableViewCellAccessoryNone; |
528 |
} else { |
529 |
cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton; |
530 |
} |
531 |
|
532 |
CFStringRef mimeType = (CFStringRef)cellObject.contentType; |
533 |
CFStringRef uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, mimeType, NULL); |
534 |
NSString *emptyPath = [[NSBundle mainBundle] pathForResource:@"empty-file" ofType:@""]; |
535 |
UIDocumentInteractionController *udic = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:emptyPath]]; |
536 |
if (((NSString *)uti).length > 0) |
537 |
udic.UTI = (NSString *)uti; |
538 |
CFRelease(uti); |
539 |
if (udic.icons.count > 0) |
540 |
cell.imageView.image = [udic.icons objectAtIndex:0]; |
541 |
|
542 |
if (cellObject.lastModifiedString) { |
543 |
cell.detailTextLabel.text = [NSString stringWithFormat:@"%@, %@", cellObject.humanizedBytes, cellObject.lastModifiedString]; |
544 |
} else { |
545 |
cell.detailTextLabel.text = cellObject.humanizedBytes; |
546 |
} |
547 |
|
548 |
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) { |
549 |
|
550 |
} |
551 |
} |
552 |
|
553 |
return cell; |
554 |
} |
555 |
} |
556 |
|
557 |
#pragma mark - UITableViewDelegate |
558 |
|
559 |
- (void)tableView:(UITableView *)aTableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { |
560 |
if (folder.objectsAndFoldersCount) { |
561 |
id item = [[self searchResults] objectAtIndex:indexPath.row]; |
562 |
if ([[item class] isEqual:[Folder class]]) { |
563 |
FolderViewController *vc = (([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) ? |
564 |
[[FolderViewController alloc] initWithNibName:@"FolderViewController-iPad" bundle:nil] : |
565 |
[[FolderViewController alloc] initWithNibName:@"FolderViewController" bundle:nil]); |
566 |
vc.account = self.account; |
567 |
vc.container = self.container; |
568 |
vc.name = [item name]; |
569 |
vc.parentFolderViewController = self; |
570 |
vc.containersViewController = self.containersViewController; |
571 |
[self.navigationController pushViewController:vc animated:YES]; |
572 |
vc.folder = item; |
573 |
[aTableView deselectRowAtIndexPath:indexPath animated:YES]; |
574 |
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) { |
575 |
self.selectedObjectViewController = nil; |
576 |
FolderDetailViewController *folderDetailViewController = [[FolderDetailViewController alloc] initWithNibName:@"FolderDetailViewController" bundle:nil]; |
577 |
folderDetailViewController.account = account; |
578 |
folderDetailViewController.container = container; |
579 |
folderDetailViewController.folder = item; |
580 |
folderDetailViewController.folderViewController = vc; |
581 |
[self presentPrimaryViewController:folderDetailViewController]; |
582 |
self.folderDetailVC = folderDetailViewController; |
583 |
[folderDetailViewController release]; |
584 |
} |
585 |
[vc release]; |
586 |
} else if ([[item class] isEqual:[StorageObject class]]) { |
587 |
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) { |
588 |
StorageObjectViewController *vc = [[StorageObjectViewController alloc] initWithNibName:@"StorageObjectViewController" bundle:nil]; |
589 |
vc.account = self.account; |
590 |
vc.container = self.container; |
591 |
vc.folder = self.folder; |
592 |
vc.object = item; |
593 |
vc.folderViewController = self; |
594 |
[self presentPrimaryViewController:vc]; |
595 |
self.selectedObjectViewController = vc; |
596 |
OpenStackAppDelegate *app = [[UIApplication sharedApplication] delegate]; |
597 |
if (app.rootViewController.popoverController) { |
598 |
[app.rootViewController.popoverController dismissPopoverAnimated:YES]; |
599 |
} |
600 |
[vc release]; |
601 |
} else { |
602 |
StorageObject *cellObject = (StorageObject *)item; |
603 |
OpenStackAppDelegate *app = [[UIApplication sharedApplication] delegate]; |
604 |
NSString *filePath = [app cacheFilePathForHash:cellObject.hash]; |
605 |
if (filePath) { |
606 |
self.documentInteractionController = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:filePath]]; |
607 |
self.documentInteractionController.delegate = self; |
608 |
self.documentInteractionController.name = cellObject.name; |
609 |
|
610 |
UITableViewCell *openFileCell = [self.tableView cellForRowAtIndexPath:indexPath]; |
611 |
CGRect frameToPresentMenuFrom = CGRectMake(openFileCell.frame.origin.x, |
612 |
openFileCell.frame.origin.y - self.tableView.contentOffset.y, |
613 |
openFileCell.frame.size.width, |
614 |
openFileCell.frame.size.height); |
615 |
if (![self.documentInteractionController presentOptionsMenuFromRect:frameToPresentMenuFrom inView:self.view animated:YES]) { |
616 |
if ([cellObject isPlayableMedia]) { |
617 |
MediaViewController *vc = [[MediaViewController alloc] initWithNibName:@"MediaViewController" bundle:nil]; |
618 |
vc.container = self.container; |
619 |
vc.object = cellObject; |
620 |
[self.navigationController pushViewController:vc animated:YES]; |
621 |
[vc release]; |
622 |
} else { |
623 |
[self alert:@"Error" message:@"This file could not be opened."]; |
624 |
} |
625 |
} |
626 |
} else { |
627 |
StorageObjectViewController *vc = [[StorageObjectViewController alloc] initWithNibName:@"StorageObjectViewController" bundle:nil]; |
628 |
vc.account = self.account; |
629 |
vc.container = self.container; |
630 |
vc.folder = self.folder; |
631 |
vc.object = cellObject; |
632 |
vc.folderViewController = self; |
633 |
[self.navigationController pushViewController:vc animated:YES]; |
634 |
[vc downloadFileForAction:StorageObjectActionOpenFile]; |
635 |
[vc release]; |
636 |
} |
637 |
[aTableView deselectRowAtIndexPath:indexPath animated:YES]; |
638 |
} |
639 |
} |
640 |
} |
641 |
} |
642 |
|
643 |
- (void)tableView:(UITableView *)aTableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath { |
644 |
if (folder.objectsAndFoldersCount) { |
645 |
id item = [[self searchResults] objectAtIndex:indexPath.row]; |
646 |
if ([[item class] isEqual:[Folder class]]) { |
647 |
FolderDetailViewController *vc = [[FolderDetailViewController alloc] initWithNibName:@"FolderDetailViewController" bundle:nil]; |
648 |
vc.account = account; |
649 |
vc.container = container; |
650 |
vc.folder = item; |
651 |
vc.folderViewController = self; |
652 |
[self.navigationController pushViewController:vc animated:YES]; |
653 |
[vc release]; |
654 |
} else if ([[item class] isEqual:[StorageObject class]]) { |
655 |
StorageObjectViewController *vc = [[StorageObjectViewController alloc] initWithNibName:@"StorageObjectViewController" bundle:nil]; |
656 |
vc.account = self.account; |
657 |
vc.container = self.container; |
658 |
vc.folder = self.folder; |
659 |
vc.object = item; |
660 |
vc.folderViewController = self; |
661 |
[self.navigationController pushViewController:vc animated:YES]; |
662 |
[vc release]; |
663 |
} |
664 |
} |
665 |
} |
666 |
|
667 |
#pragma mark - UISearchDisplayDelegate |
668 |
|
669 |
- (void)updateSearchBarPlaceholder:(NSInteger)selectedScope { |
670 |
NSMutableDictionary *threadDict = [[NSThread currentThread] threadDictionary]; |
671 |
NSDateFormatter *dateFormatterSearchPlaceholder = [threadDict objectForKey:@"dateFormatterSearchPlaceholder"]; |
672 |
if (!dateFormatterSearchPlaceholder) { |
673 |
dateFormatterSearchPlaceholder = [[NSDateFormatter alloc] init]; |
674 |
[dateFormatterSearchPlaceholder setTimeZone:[NSTimeZone localTimeZone]]; |
675 |
[dateFormatterSearchPlaceholder setDateFormat:@"yyyy-MM-dd"]; |
676 |
[threadDict setObject:dateFormatterSearchPlaceholder forKey:@"dateFormatterSearchPlaceholder"]; |
677 |
[dateFormatterSearchPlaceholder release]; |
678 |
} |
679 |
|
680 |
if (selectedScope == 0) { |
681 |
// all |
682 |
self.searchBar.placeholder = [NSString stringWithFormat:@"e.g. .pdf or %@", |
683 |
[dateFormatterSearchPlaceholder stringFromDate:[NSDate date]]]; |
684 |
} else if (selectedScope == 1) { |
685 |
// name |
686 |
self.searchBar.placeholder = @"e.g.: .pdf"; |
687 |
} else if (selectedScope == 2) { |
688 |
// date |
689 |
self.searchBar.placeholder = [NSString stringWithFormat:@"e.g.: %@", |
690 |
[dateFormatterSearchPlaceholder stringFromDate:[NSDate date]]]; |
691 |
} else if (selectedScope == 3) { |
692 |
// type |
693 |
self.searchBar.placeholder = @"e.g.: .pdf or text/plain"; |
694 |
} else { |
695 |
// default |
696 |
self.searchBar.placeholder = @"Search Folder"; |
697 |
} |
698 |
} |
699 |
|
700 |
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString { |
701 |
self.searchFilter = searchString; |
702 |
[self reloadData]; |
703 |
return NO; |
704 |
} |
705 |
|
706 |
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchScope:(NSInteger)searchOption { |
707 |
[self reloadData]; |
708 |
[self updateSearchBarPlaceholder:searchOption]; |
709 |
return NO; |
710 |
} |
711 |
|
712 |
- (void)searchDisplayController:(UISearchDisplayController *)controller didShowSearchResultsTableView:(UITableView *)aTableView { |
713 |
CGRect tableViewFrame = self.searchDisplayController.searchResultsTableView.frame; |
714 |
tableViewFrame.size.height -= self.toolbar.frame.size.height; |
715 |
self.searchDisplayController.searchResultsTableView.frame = tableViewFrame; |
716 |
} |
717 |
|
718 |
- (void)searchDisplayControllerWillBeginSearch:(UISearchDisplayController *)controller { |
719 |
[self updateSearchBarPlaceholder:controller.searchBar.selectedScopeButtonIndex]; |
720 |
} |
721 |
|
722 |
- (void)searchDisplayControllerWillEndSearch:(UISearchDisplayController *)controller { |
723 |
self.searchFilter = nil; |
724 |
[self reloadData]; |
725 |
[self updateSearchBarPlaceholder:-1]; |
726 |
} |
727 |
|
728 |
#pragma mark - Button Handlers |
729 |
|
730 |
- (void)addButtonPressed:(id)sender { |
731 |
AddObjectViewController *vc = [[AddObjectViewController alloc] initWithNibName:@"AddObjectViewController" bundle:nil]; |
732 |
vc.account = self.account; |
733 |
vc.container = self.container; |
734 |
vc.folder = self.folder; |
735 |
vc.folderViewController = self; |
736 |
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) { |
737 |
vc.modalPresentationStyle = UIModalPresentationFormSheet; |
738 |
OpenStackAppDelegate *app = [[UIApplication sharedApplication] delegate]; |
739 |
if (app.rootViewController.popoverController != nil) { |
740 |
[app.rootViewController.popoverController dismissPopoverAnimated:YES]; |
741 |
} |
742 |
} |
743 |
[self presentModalViewControllerWithNavigation:vc animated:YES]; |
744 |
[vc release]; |
745 |
} |
746 |
|
747 |
- (void)refreshButtonPressed:(id)sender { |
748 |
__block ActivityIndicatorView *activityIndicatorView = [ActivityIndicatorView activityIndicatorViewWithText:@"Loading..." |
749 |
andAddToView:self.view]; |
750 |
[[self.account.manager getObjects:self.container] success:^(OpenStackRequest *request) { |
751 |
[activityIndicatorView stopAnimatingAndRemoveFromSuperview]; |
752 |
[self reloadFolderViewControllers]; |
753 |
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) { |
754 |
if (self.selectedObjectViewController) { |
755 |
[self.selectedObjectViewController reloadMetadataSection]; |
756 |
} else if ([self.folder isEqual:container.rootFolder]) { |
757 |
[containersViewController.containerDetailViewController reloadMetadataSection]; |
758 |
} else if ([parentFolderViewController.folderDetailVC.navigationController.topViewController |
759 |
isEqual:parentFolderViewController.folderDetailVC]) { |
760 |
[parentFolderViewController.folderDetailVC reloadMetadataSection]; |
761 |
} |
762 |
} |
763 |
} failure:^(OpenStackRequest *request) { |
764 |
[activityIndicatorView stopAnimatingAndRemoveFromSuperview]; |
765 |
[self reloadData]; |
766 |
[self alert:@"Error" message:@"Failed to retrieve files from server."]; |
767 |
}]; |
768 |
} |
769 |
|
770 |
- (void)homeButtonPressed:(id)sender { |
771 |
[self.navigationController popToViewController:containersViewController.accountHomeViewController animated:YES]; |
772 |
} |
773 |
|
774 |
- (void)deleteButtonPressed:(id)sender { |
775 |
UIActionSheet *deleteActionSheet = [[[UIActionSheet alloc] initWithTitle:@"Are you sure you want to delete this folder? This operation cannot be undone." |
776 |
delegate:self |
777 |
cancelButtonTitle:@"Cancel" |
778 |
destructiveButtonTitle:@"Delete Folder" |
779 |
otherButtonTitles:nil] autorelease]; |
780 |
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) { |
781 |
OpenStackAppDelegate *app = [[UIApplication sharedApplication] delegate]; |
782 |
[deleteActionSheet showInView:app.masterNavigationController.view]; |
783 |
} else { |
784 |
[deleteActionSheet showInView:self.view]; |
785 |
} |
786 |
} |
787 |
|
788 |
#pragma mark - UIActionSheetDelegate |
789 |
|
790 |
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex { |
791 |
if (buttonIndex == 0) { |
792 |
StorageObject *object = [[[StorageObject alloc] init] autorelease]; |
793 |
object.name = object.fullPath = [self.folder fullPath]; |
794 |
__block ActivityIndicatorView *activityIndicatorView = [ActivityIndicatorView activityIndicatorViewWithText:@"Deleting folder..." |
795 |
andAddToView:self.view |
796 |
scrollOffset:self.tableView.contentOffset.y]; |
797 |
[[self.account.manager deleteObject:self.container object:object] |
798 |
success:^(OpenStackRequest *request) { |
799 |
[activityIndicatorView stopAnimatingAndRemoveFromSuperview]; |
800 |
[self delete]; |
801 |
} |
802 |
failure:^(OpenStackRequest *request) { |
803 |
[activityIndicatorView stopAnimatingAndRemoveFromSuperview]; |
804 |
// 404 Not Found means it's not there, so we can show the user that it's deleted |
805 |
if (request.responseStatusCode == 404) { |
806 |
[self delete]; |
807 |
} else { |
808 |
[self alert:@"There was a problem deleting this folder." request:request]; |
809 |
} |
810 |
}]; |
811 |
} |
812 |
} |
813 |
|
814 |
#pragma mark - UIDocumentInteractionControllerDelegate |
815 |
|
816 |
- (UIViewController *)documentInteractionControllerViewControllerForPreview:(UIDocumentInteractionController *)controller { |
817 |
return self.navigationController; |
818 |
} |
819 |
|
820 |
@end |