root / Classes / StorageObjectViewController.m @ 54fd5c36
History | View | Annotate | Download (37.8 kB)
1 |
// |
---|---|
2 |
// StorageObjectViewController.m |
3 |
// OpenStack |
4 |
// |
5 |
// Created by Mike Mayo on 12/19/10. |
6 |
// The OpenStack project is provided under the Apache 2.0 license. |
7 |
// |
8 |
|
9 |
#import "StorageObjectViewController.h" |
10 |
#import "OpenStackAccount.h" |
11 |
#import "OpenStackRequest.h" |
12 |
#import "Container.h" |
13 |
#import "Folder.h" |
14 |
#import "StorageObject.h" |
15 |
#import "AccountManager.h" |
16 |
#import "AnimatedProgressView.h" |
17 |
#import "UIViewController+Conveniences.h" |
18 |
#import "MediaViewController.h" |
19 |
#import "FolderViewController.h" |
20 |
#import "UIColor+MoreColors.h" |
21 |
#import "OpenStackAppDelegate.h" |
22 |
#import "EditMetadataViewController.h" |
23 |
#import "Provider.h" |
24 |
#import "EditPermissionsViewController.h" |
25 |
#import "TextViewCell.h" |
26 |
#import "NSString+Conveniences.h" |
27 |
#import "APICallback.h" |
28 |
#import "ObjectVersionsViewController.h" |
29 |
|
30 |
#define kDetails 0 |
31 |
#define kMetadata 1 |
32 |
|
33 |
#define maxMetadataViewableLength 12 |
34 |
|
35 |
|
36 |
// TODO: use etag to reset download |
37 |
// TODO: try downloading directly to the file to save memory. don't use object.data |
38 |
|
39 |
/* |
40 |
Name whatever.txt |
41 |
Full Path |
42 |
Size 123 KB |
43 |
Content Type text/plain |
44 |
|
45 |
Metadata |
46 |
Key Value -> tap goes to a metadata item VC to edit or delete |
47 |
Key Value |
48 |
Add Metadata... (if max not already reached) |
49 |
|
50 |
CDN URL sections (action sheet to copy, open in safari, and email link) |
51 |
|
52 |
Download File (if downloaded, Open File and Mail File as Attachment) |
53 |
"After you download the file, you'll be able to attempt to open it and mail is as an attachment." |
54 |
|
55 |
Delete Object |
56 |
*/ |
57 |
|
58 |
@implementation StorageObjectViewController |
59 |
|
60 |
@synthesize account, container, folder, object, tableView, folderViewController; |
61 |
@synthesize oldPubicURI, documentInteractionController, actionSelectedIndexPath, objectIsReadOnly, versionID; |
62 |
|
63 |
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation { |
64 |
return (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) || (toInterfaceOrientation == UIInterfaceOrientationPortrait); |
65 |
} |
66 |
|
67 |
- (void)setBackgroundView { |
68 |
|
69 |
UIImageView *logo = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"cloudfiles-large.png"]]; |
70 |
|
71 |
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { |
72 |
UIView *backgroundContainer = [[UIView alloc] init]; |
73 |
backgroundContainer.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth; |
74 |
backgroundContainer.backgroundColor = [UIColor iPadTableBackgroundColor]; |
75 |
logo.contentMode = UIViewContentModeScaleAspectFit; |
76 |
logo.frame = CGRectMake(100.0, 100.0, 1000.0, 1000.0); |
77 |
logo.alpha = 0.5; |
78 |
[backgroundContainer addSubview:logo]; |
79 |
tableView.backgroundView = backgroundContainer; |
80 |
[backgroundContainer release]; |
81 |
} else { |
82 |
self.tableView.backgroundView = nil; |
83 |
} |
84 |
[logo release]; |
85 |
} |
86 |
|
87 |
- (IBAction)homeButtonPressed:(id)sender { |
88 |
[self.navigationController popToRootViewControllerAnimated:YES]; |
89 |
} |
90 |
|
91 |
#pragma mark - |
92 |
#pragma mark View lifecycle |
93 |
|
94 |
- (void)viewDidLoad { |
95 |
[super viewDidLoad]; |
96 |
|
97 |
objectIsPublicSwitch = [[UISwitch alloc] init]; |
98 |
[objectIsPublicSwitch addTarget:self action:@selector(objectIsPublicSwitchChanged:) forControlEvents:UIControlEventValueChanged]; |
99 |
|
100 |
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]; |
101 |
permissions = [[NSMutableDictionary alloc] init]; |
102 |
if (object.sharing.length > 0) { |
103 |
NSArray *sharingArray = [object.sharing componentsSeparatedByString:@";"]; |
104 |
for (NSString *typeSpecificPermissions in sharingArray) { |
105 |
NSArray *array=[typeSpecificPermissions componentsSeparatedByString:@"="]; |
106 |
NSString *permissionsType = [array objectAtIndex:0]; |
107 |
if ([permissionsType hasPrefix:@" "]) |
108 |
permissionsType = [permissionsType substringFromIndex:1]; |
109 |
|
110 |
NSArray *users = [[array objectAtIndex:1] componentsSeparatedByString:@","]; |
111 |
for (NSString *user in users) { |
112 |
[permissions setObject:permissionsType forKey:user]; |
113 |
} |
114 |
} |
115 |
} |
116 |
objectIsReadOnly = NO; |
117 |
if (account.sharingAccount) { |
118 |
if ([permissions count] > 0) { |
119 |
objectIsReadOnly = [[permissions objectForKey:[account username]] isEqualToString:@"read"]; |
120 |
} |
121 |
objectIsPublicSwitch.enabled = NO; |
122 |
} |
123 |
|
124 |
downloadProgressView = [[AnimatedProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleDefault]; |
125 |
fileDownloading = ([self.account.manager.objectDownloadRequests objectForKey:object.fullPath] != nil) ? YES : NO; |
126 |
if (fileDownloading) { |
127 |
OpenStackRequest *request = [self.account.manager.objectDownloadRequests objectForKey:object.fullPath]; |
128 |
self.actionSelectedIndexPath = [request.userInfo objectForKey:@"actionSelectedIndexPath"]; |
129 |
[request setDownloadProgressDelegate:self]; |
130 |
} |
131 |
appDelegate = [[UIApplication sharedApplication] delegate]; |
132 |
} |
133 |
|
134 |
- (void)viewWillAppear:(BOOL)animated { |
135 |
[super viewWillAppear:animated]; |
136 |
self.navigationItem.title = object.name; |
137 |
|
138 |
NSIndexPath *selection = [self.tableView indexPathForSelectedRow]; |
139 |
if (selection) |
140 |
[self.tableView deselectRowAtIndexPath:selection animated:YES]; |
141 |
if ([appDelegate.cachedObjectsDictionary objectForKey:object.hash] != nil) { |
142 |
if ([[NSFileManager defaultManager] fileExistsAtPath:[appDelegate.cachedObjectsDictionary objectForKey:object.hash]]) |
143 |
fileDownloaded = YES; |
144 |
else { |
145 |
fileDownloaded = NO; |
146 |
[appDelegate.cachedObjectsDictionary removeObjectForKey:object.hash]; |
147 |
[appDelegate saveCacheDictionary]; |
148 |
} |
149 |
} else { |
150 |
fileDownloaded = NO; |
151 |
} |
152 |
|
153 |
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { |
154 |
CGRect rect = downloadProgressView.frame; |
155 |
rect.size.width = 440.0; |
156 |
downloadProgressView.frame = rect; |
157 |
} |
158 |
|
159 |
//[self setBackgroundView]; |
160 |
publicLinkSection = 2; |
161 |
permissionsSection = 3; |
162 |
if (self.container.cdnEnabled) { |
163 |
cdnURLSection = 4; |
164 |
actionsSection = 5; |
165 |
deleteSection = 6; |
166 |
versionsSection = 7; |
167 |
} else { |
168 |
cdnURLSection = -1; |
169 |
actionsSection = 4; |
170 |
deleteSection = 5; |
171 |
versionsSection = 6; |
172 |
} |
173 |
|
174 |
if (versionID) { |
175 |
publicLinkSection = -1; |
176 |
permissionsSection = -1; |
177 |
versionsSection = -1; |
178 |
deleteSection = -1; |
179 |
actionsSection = 2; |
180 |
objectIsReadOnly = YES; |
181 |
} |
182 |
if (account.sharingAccount || account.shared) |
183 |
deleteSection = -1; |
184 |
|
185 |
|
186 |
// let's see if we can tweet |
187 |
UIApplication *app = [UIApplication sharedApplication]; |
188 |
NSURL *twitterURL = [NSURL URLWithString:@"twitter://post?message=test"]; |
189 |
|
190 |
if ([app canOpenURL:twitterURL]) { |
191 |
cdnURLActionSheet = [[UIActionSheet alloc] initWithTitle:[[NSString stringWithFormat:@"%@/%@", self.container.cdnURL, self.object.fullPath] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding] delegate:self cancelButtonTitle:@"Cancel" destructiveButtonTitle:nil otherButtonTitles:@"Copy to Pasteboard", @"Open in Safari", @"Email Link to File", @"Tweet Link to File", nil]; |
192 |
} else { |
193 |
cdnURLActionSheet = [[UIActionSheet alloc] initWithTitle:[[NSString stringWithFormat:@"%@/%@", self.container.cdnURL, self.object.fullPath] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding] delegate:self cancelButtonTitle:@"Cancel" destructiveButtonTitle:nil otherButtonTitles:@"Copy to Pasteboard", @"Open in Safari", @"Email Link to File", nil]; |
194 |
} |
195 |
objectIsPublic = ([object.publicURI length]); |
196 |
objectIsPublicSwitch.on = objectIsPublic; |
197 |
[self.tableView reloadData]; |
198 |
} |
199 |
|
200 |
- (void)viewDidAppear:(BOOL)animated { |
201 |
if (object.metadata == nil) { |
202 |
[self reloadMetadataSection]; |
203 |
} |
204 |
} |
205 |
|
206 |
#pragma mark - |
207 |
#pragma mark Table view data source |
208 |
|
209 |
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { |
210 |
|
211 |
int numberOfSections = 8; |
212 |
if (!self.container.cdnEnabled) |
213 |
numberOfSections--; |
214 |
if (deleteSection < 0) |
215 |
numberOfSections--; |
216 |
if (versionsSection < 0) |
217 |
numberOfSections--; |
218 |
if (publicLinkSection < 0) |
219 |
numberOfSections--; |
220 |
if (permissionsSection < 0) |
221 |
numberOfSections--; |
222 |
|
223 |
return numberOfSections; |
224 |
} |
225 |
|
226 |
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { |
227 |
if (section == kDetails) { |
228 |
return 4; |
229 |
} else if (section == kMetadata) { |
230 |
if (objectIsReadOnly) { |
231 |
return [object.metadata count]; |
232 |
} else { |
233 |
return 1 + [object.metadata count]; |
234 |
} |
235 |
} else if (section == cdnURLSection) { |
236 |
return 1; |
237 |
} else if (section == actionsSection) { |
238 |
return 2; |
239 |
} else if (section == publicLinkSection) { |
240 |
return objectIsPublic ? 2 : 1; |
241 |
} else if (section == permissionsSection) { |
242 |
if (account.sharingAccount || objectIsReadOnly) |
243 |
return [permissions count]; |
244 |
else |
245 |
return 1 + [permissions count]; |
246 |
} else { |
247 |
return 1; |
248 |
} |
249 |
} |
250 |
|
251 |
- (CGFloat)findLabelHeight:(NSString*)text font:(UIFont *)font { |
252 |
CGSize textLabelSize; |
253 |
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { |
254 |
// 616, 678 |
255 |
textLabelSize = CGSizeMake(596.0, 9000.0f); |
256 |
} else { |
257 |
textLabelSize = CGSizeMake(280.0, 9000.0f); |
258 |
} |
259 |
CGSize stringSize = [text sizeWithFont:font constrainedToSize:textLabelSize lineBreakMode:UILineBreakModeCharacterWrap]; |
260 |
return stringSize.height; |
261 |
} |
262 |
|
263 |
- (CGFloat)tableView:(UITableView *)aTableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { |
264 |
CGFloat result = aTableView.rowHeight; |
265 |
|
266 |
if (indexPath.section == cdnURLSection) { |
267 |
result = 22.0 + [self findLabelHeight:[[NSString stringWithFormat:@"%@/%@", self.container.cdnURL, self.object.fullPath] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding] font:[UIFont systemFontOfSize:18.0]]; |
268 |
} else if (indexPath.section == kDetails && indexPath.row == 1) { |
269 |
CGSize textLabelSize; |
270 |
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { |
271 |
textLabelSize = CGSizeMake(537.0, 9000.0f); |
272 |
} else { |
273 |
textLabelSize = CGSizeMake(221.0, 9000.0f); |
274 |
} |
275 |
CGSize stringSize = [object.fullPath sizeWithFont:[UIFont systemFontOfSize:18.0] constrainedToSize:textLabelSize lineBreakMode:UILineBreakModeWordWrap]; |
276 |
return 22.0 + stringSize.height; |
277 |
} else if (indexPath.section == kDetails && indexPath.row == 0) { |
278 |
CGSize textLabelSize; |
279 |
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { |
280 |
textLabelSize = CGSizeMake(537.0, 9000.0f); |
281 |
} else { |
282 |
textLabelSize = CGSizeMake(221.0, 9000.0f); |
283 |
} |
284 |
CGSize stringSize = [object.name sizeWithFont:[UIFont systemFontOfSize:18.0] constrainedToSize:textLabelSize lineBreakMode:UILineBreakModeWordWrap]; |
285 |
return 22.0 + stringSize.height; |
286 |
} else if (indexPath.section == publicLinkSection && indexPath.row == 1) { |
287 |
NSString *publicLinkUrl = [NSString stringWithFormat:@"%@%@", |
288 |
account.pithosPublicLinkURLPrefix, |
289 |
self.object.publicURI]; |
290 |
|
291 |
result = 30.0 + [self findLabelHeight:publicLinkUrl font:[UIFont systemFontOfSize:15.0]]; |
292 |
} |
293 |
return MAX(aTableView.rowHeight, result); |
294 |
} |
295 |
|
296 |
- (UITableViewCell *)tableView:(UITableView *)aTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { |
297 |
|
298 |
static NSString *CellIdentifier = @"Cell"; |
299 |
static NSString *TextViewCellIdentifier = @"TextViewCell"; |
300 |
|
301 |
if (indexPath.section == publicLinkSection) { |
302 |
if (indexPath.row == 1) { |
303 |
TextViewCell *cell = [aTableView dequeueReusableCellWithIdentifier:TextViewCellIdentifier]; |
304 |
if (cell == nil) { |
305 |
cell = [[[TextViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:TextViewCellIdentifier] autorelease]; |
306 |
cell.textView.frame = cell.contentView.frame; |
307 |
|
308 |
} |
309 |
cell.selectionStyle = UITableViewCellSelectionStyleNone; |
310 |
cell.textView.backgroundColor = [UIColor clearColor]; |
311 |
cell.textView.font = [UIFont systemFontOfSize:15.0]; |
312 |
cell.textView.dataDetectorTypes = UIDataDetectorTypeLink; |
313 |
cell.textView.text = [NSString stringWithFormat:@"%@%@", |
314 |
account.pithosPublicLinkURLPrefix, |
315 |
[NSString encodeToPercentEscape:self.object.publicURI charactersToEncode:@"!*'();:@&=+$,?%#[]"]]; |
316 |
|
317 |
cell.selectionStyle = UITableViewCellSelectionStyleNone; |
318 |
cell.accessoryView = UITableViewCellAccessoryNone; |
319 |
return cell; |
320 |
} |
321 |
} |
322 |
|
323 |
UITableViewCell *cell = [aTableView dequeueReusableCellWithIdentifier:CellIdentifier]; |
324 |
if (cell == nil) { |
325 |
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease]; |
326 |
cell.textLabel.backgroundColor = [UIColor clearColor]; |
327 |
cell.detailTextLabel.backgroundColor = [UIColor clearColor]; |
328 |
cell.detailTextLabel.numberOfLines = 0; |
329 |
cell.detailTextLabel.lineBreakMode = UILineBreakModeWordWrap; |
330 |
} |
331 |
cell.textLabel.textColor = [UIColor blackColor]; |
332 |
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { |
333 |
cell.backgroundColor = [UIColor colorWithRed:1 green:1 blue:1 alpha:0.8]; |
334 |
} |
335 |
cell.userInteractionEnabled = YES; |
336 |
cell.detailTextLabel.textAlignment = UITextAlignmentRight; |
337 |
cell.accessoryView = nil; |
338 |
cell.textLabel.font = [UIFont boldSystemFontOfSize:17.0]; |
339 |
|
340 |
// Configure the cell... |
341 |
if (indexPath.section == kDetails) { |
342 |
cell.accessoryType = UITableViewCellAccessoryNone; |
343 |
cell.selectionStyle = UITableViewCellSelectionStyleNone; |
344 |
cell.accessoryView = nil; |
345 |
if (indexPath.row == 0) { |
346 |
cell.textLabel.text = @"Name"; |
347 |
cell.detailTextLabel.text = object.name; |
348 |
} else if (indexPath.row == 1) { |
349 |
cell.textLabel.text = @"Full Path"; |
350 |
cell.detailTextLabel.text = object.fullPath; |
351 |
} else if (indexPath.row == 2) { |
352 |
cell.textLabel.text = @"Size"; |
353 |
cell.detailTextLabel.text = [object humanizedBytes]; |
354 |
} else if (indexPath.row == 3) { |
355 |
cell.textLabel.text = @"Type"; |
356 |
cell.detailTextLabel.text = object.contentType; |
357 |
} |
358 |
} else if (indexPath.section == kMetadata) { |
359 |
if (objectIsReadOnly) { |
360 |
cell.accessoryType = UITableViewCellAccessoryNone; |
361 |
cell.selectionStyle = UITableViewCellSelectionStyleNone; |
362 |
cell.userInteractionEnabled = NO; |
363 |
} |
364 |
else { |
365 |
cell.selectionStyle = UITableViewCellSelectionStyleBlue; |
366 |
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; |
367 |
} |
368 |
|
369 |
cell.accessoryView = nil; |
370 |
if (indexPath.row == [object.metadata count]) { |
371 |
cell.textLabel.text = @"Add Metadata"; |
372 |
cell.detailTextLabel.text = @""; |
373 |
} else { |
374 |
NSString *key = [[object.metadata allKeys] objectAtIndex:indexPath.row]; |
375 |
NSString *value = [object.metadata objectForKey:key]; |
376 |
NSString *metadataKeyCellText = key; |
377 |
NSString *metadataValueCellText = value; |
378 |
if ([metadataKeyCellText length] > maxMetadataViewableLength) { |
379 |
metadataKeyCellText = [metadataKeyCellText substringToIndex:(maxMetadataViewableLength - 3)]; |
380 |
metadataKeyCellText = [metadataKeyCellText stringByAppendingString:@"..."]; |
381 |
} |
382 |
if ([metadataValueCellText length] > maxMetadataViewableLength) { |
383 |
metadataValueCellText = [metadataValueCellText substringToIndex:(maxMetadataViewableLength - 3)]; |
384 |
metadataValueCellText = [metadataValueCellText stringByAppendingString:@"..."]; |
385 |
} |
386 |
|
387 |
cell.textLabel.text = metadataKeyCellText; |
388 |
cell.detailTextLabel.text = metadataValueCellText; |
389 |
} |
390 |
} else if (indexPath.section == publicLinkSection) { |
391 |
if (indexPath.row == 0) { |
392 |
cell.textLabel.text = @"Public URL"; |
393 |
cell.detailTextLabel.text = @""; |
394 |
cell.accessoryView = objectIsPublicSwitch; |
395 |
cell.accessoryType = UITableViewCellAccessoryNone; |
396 |
cell.selectionStyle = UITableViewCellSelectionStyleNone; |
397 |
} |
398 |
} else if (indexPath.section == permissionsSection) { |
399 |
if (account.sharingAccount) { |
400 |
cell.accessoryType = UITableViewCellAccessoryNone; |
401 |
cell.selectionStyle = UITableViewCellSelectionStyleNone; |
402 |
cell.userInteractionEnabled = NO; |
403 |
} |
404 |
else { |
405 |
cell.selectionStyle = UITableViewCellSelectionStyleBlue; |
406 |
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; |
407 |
} |
408 |
cell.accessoryView = nil; |
409 |
|
410 |
if (indexPath.row == [permissions count]) { |
411 |
cell.textLabel.text = @"Add Permissions"; |
412 |
cell.detailTextLabel.text = @""; |
413 |
} |
414 |
else { |
415 |
NSString *user = [[permissions allKeys] objectAtIndex:indexPath.row]; |
416 |
cell.textLabel.text = user; |
417 |
cell.detailTextLabel.text = [permissions objectForKey:user]; |
418 |
} |
419 |
} else if (indexPath.section == cdnURLSection) { |
420 |
cell.detailTextLabel.textAlignment = UITextAlignmentLeft; |
421 |
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; |
422 |
cell.textLabel.text = @""; |
423 |
cell.detailTextLabel.text = [[NSString stringWithFormat:@"%@/%@", self.container.cdnURL, self.object.fullPath] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; |
424 |
} else if (indexPath.section == actionsSection) { |
425 |
if (fileDownloading) { |
426 |
if (actionSelectedIndexPath.row == indexPath.row) { |
427 |
cell.accessoryView = downloadProgressView; |
428 |
} else { |
429 |
cell.textLabel.textColor = [UIColor grayColor]; |
430 |
cell.selectionStyle = UITableViewCellSelectionStyleNone; |
431 |
} |
432 |
} else { |
433 |
cell.selectionStyle = UITableViewCellSelectionStyleBlue; |
434 |
cell.accessoryView = nil; |
435 |
} |
436 |
if (indexPath.row == 0) { |
437 |
cell.textLabel.text = @"Open File"; |
438 |
cell.accessoryType = UITableViewCellAccessoryNone; |
439 |
cell.detailTextLabel.text = @""; |
440 |
|
441 |
} else if (indexPath.row == 1) { |
442 |
cell.textLabel.text = @"Email File as Attachment"; |
443 |
cell.detailTextLabel.text = @""; |
444 |
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; |
445 |
} |
446 |
} else if (indexPath.section == deleteSection) { |
447 |
cell.selectionStyle = UITableViewCellSelectionStyleBlue; |
448 |
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; |
449 |
cell.textLabel.text = @"Delete Object"; |
450 |
cell.detailTextLabel.text = @""; |
451 |
|
452 |
} else if (indexPath.section == versionsSection) { |
453 |
cell.selectionStyle = UITableViewCellSelectionStyleBlue; |
454 |
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; |
455 |
cell.textLabel.text = @"Versions"; |
456 |
cell.detailTextLabel.text = @""; |
457 |
} |
458 |
|
459 |
return cell; |
460 |
} |
461 |
|
462 |
|
463 |
|
464 |
#pragma mark - |
465 |
#pragma mark Table view delegate |
466 |
|
467 |
- (void)reloadActionsTitleRow:(NSTimer *)timer { |
468 |
[[timer.userInfo objectForKey:@"tableView"] reloadRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:0 inSection:actionsSection]] withRowAnimation:UITableViewRowAnimationNone]; |
469 |
} |
470 |
|
471 |
- (void)tableView:(UITableView *)aTableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { |
472 |
if (indexPath.section == kMetadata) { |
473 |
EditMetadataViewController *vc = [[EditMetadataViewController alloc] initWithNibName:@"EditMetadataViewController" bundle:nil]; |
474 |
NSString *metadataKey; |
475 |
NSString *metadataValue; |
476 |
|
477 |
if (indexPath.row == [self.object.metadata count]) { |
478 |
metadataKey = @""; |
479 |
metadataValue = @""; |
480 |
vc.removeMetadataEnabled = FALSE; |
481 |
vc.navigationItem.title = @"Add Metadata"; |
482 |
} |
483 |
else { |
484 |
metadataKey = [[self.object.metadata allKeys] objectAtIndex:indexPath.row]; |
485 |
metadataValue = [self.object.metadata objectForKey:metadataKey]; |
486 |
vc.removeMetadataEnabled = YES; |
487 |
vc.navigationItem.title = @"Edit Metadata"; |
488 |
} |
489 |
|
490 |
vc.metadataKey = metadataKey; |
491 |
vc.metadataValue = metadataValue; |
492 |
vc.account = account; |
493 |
vc.container = container; |
494 |
vc.object = object; |
495 |
[self.navigationController pushViewController:vc animated:YES]; |
496 |
[vc release]; |
497 |
} else if (indexPath.section == permissionsSection) { |
498 |
EditPermissionsViewController *vc = [[EditPermissionsViewController alloc] initWithNibName:@"EditPermissionsViewController" bundle:nil]; |
499 |
NSString *user; |
500 |
|
501 |
if (indexPath.row == [permissions count]) { |
502 |
user = @""; |
503 |
vc.removePermissionsEnabled = NO; |
504 |
vc.navigationItem.title = @"Add Permissions"; |
505 |
} |
506 |
else { |
507 |
user = [[permissions allKeys] objectAtIndex:indexPath.row]; |
508 |
NSString *userPermissions = [permissions objectForKey:user]; |
509 |
if ([userPermissions rangeOfString:@"read"].location != NSNotFound) |
510 |
vc.readPermissionSelected = YES; |
511 |
else |
512 |
vc.readPermissionSelected = NO; |
513 |
|
514 |
if ([userPermissions rangeOfString:@"write"].location != NSNotFound) |
515 |
vc.writePermissionSelected = YES; |
516 |
else |
517 |
vc.writePermissionSelected = NO; |
518 |
|
519 |
vc.removePermissionsEnabled = YES; |
520 |
vc.navigationItem.title = @"Edit Permissions"; |
521 |
} |
522 |
|
523 |
vc.user = user; |
524 |
vc.permissions = permissions; |
525 |
vc.account = account; |
526 |
vc.container = container; |
527 |
vc.object = object; |
528 |
vc.folderViewController = folderViewController; |
529 |
[self.navigationController pushViewController:vc animated:YES]; |
530 |
[vc release]; |
531 |
} else if (indexPath.section == cdnURLSection) { |
532 |
[cdnURLActionSheet showInView:self.view]; |
533 |
} else if (indexPath.section == actionsSection) { |
534 |
if (!fileDownloaded) { |
535 |
if (!fileDownloading) { |
536 |
// download the file |
537 |
fileDownloading = YES; |
538 |
self.actionSelectedIndexPath = indexPath; |
539 |
[self.tableView reloadData]; |
540 |
NSMutableDictionary *requestUserInfo = [NSDictionary dictionaryWithObject:indexPath forKey:@"actionSelectedIndexPath"]; |
541 |
[[self.account.manager getObject:self.container object:self.object downloadProgressDelegate:self requestUserInfo:requestUserInfo version:versionID] |
542 |
success:^(OpenStackRequest *request) { |
543 |
fileDownloaded = YES; |
544 |
fileDownloading = NO; |
545 |
if ([self.navigationController.visibleViewController isEqual:self]) |
546 |
[self.tableView.delegate tableView:self.tableView didSelectRowAtIndexPath:indexPath]; |
547 |
[self.tableView reloadData]; |
548 |
[self.folderViewController.tableView reloadData]; |
549 |
} |
550 |
failure:^(OpenStackRequest *request) { |
551 |
fileDownloaded = NO; |
552 |
fileDownloading = NO; |
553 |
[self alert:@"File failed to download" request:request]; |
554 |
[self.tableView reloadData]; |
555 |
}]; |
556 |
[self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:indexPath.row inSection:actionsSection]] withRowAnimation:UITableViewRowAnimationNone]; |
557 |
} |
558 |
} else if (indexPath.row == 0) { |
559 |
if (fileDownloaded) { |
560 |
NSString *filePath = [appDelegate.cachedObjectsDictionary objectForKey:object.hash]; |
561 |
self.documentInteractionController = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:filePath]]; |
562 |
self.documentInteractionController.delegate = self; |
563 |
self.documentInteractionController.name = object.name; |
564 |
|
565 |
UITableViewCell *openFileCell = [self.tableView cellForRowAtIndexPath:indexPath]; |
566 |
if (![self.documentInteractionController presentOptionsMenuFromRect:openFileCell.frame inView:self.view animated:YES]) { |
567 |
if ([self.object isPlayableMedia]) { |
568 |
MediaViewController *vc = [[MediaViewController alloc] initWithNibName:@"MediaViewController" bundle:nil]; |
569 |
vc.container = self.container; |
570 |
vc.object = self.object; |
571 |
[self.navigationController pushViewController:vc animated:YES]; |
572 |
[vc release]; |
573 |
} else { |
574 |
[self alert:@"Error" message:@"This file could not be opened."]; |
575 |
[self.tableView deselectRowAtIndexPath:indexPath animated:YES]; |
576 |
} |
577 |
} |
578 |
|
579 |
[self.tableView deselectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:actionsSection] animated:YES]; |
580 |
|
581 |
} |
582 |
} else if (indexPath.row == 1) { |
583 |
|
584 |
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); |
585 |
NSString *documentsDirectory = [paths objectAtIndex:0]; |
586 |
NSString *shortPath = @""; |
587 |
|
588 |
if (self.container && [self.container respondsToSelector:@selector(name)] && self.object && [self.object respondsToSelector:@selector(fullPath)]) { |
589 |
shortPath = [NSString stringWithFormat:@"/%@/%@", self.container.name, self.object.fullPath]; |
590 |
} |
591 |
|
592 |
NSString *filePath = [documentsDirectory stringByAppendingString:shortPath]; |
593 |
NSData *data = [NSData dataWithContentsOfURL:[NSURL fileURLWithPath:filePath]]; |
594 |
|
595 |
|
596 |
if (![MFMailComposeViewController canSendMail]) { |
597 |
[self alert:@"Cannot send mail" message:@"Your device has not been configured for sending email"]; |
598 |
[self.tableView deselectRowAtIndexPath:indexPath animated:NO]; |
599 |
} |
600 |
else { |
601 |
MFMailComposeViewController *vc = [[MFMailComposeViewController alloc] init]; |
602 |
|
603 |
vc.mailComposeDelegate = self; |
604 |
[vc setSubject:self.object.name]; |
605 |
[vc addAttachmentData:data mimeType:self.object.contentType fileName:self.object.name]; |
606 |
[vc setMessageBody:@"" isHTML:NO]; |
607 |
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { |
608 |
vc.modalPresentationStyle = UIModalPresentationPageSheet; |
609 |
} |
610 |
[self presentModalViewController:vc animated:YES]; |
611 |
[vc release]; |
612 |
} |
613 |
} |
614 |
} else if (indexPath.section == deleteSection) { |
615 |
[deleteActionSheet showInView:self.view]; |
616 |
} else if (indexPath.section == versionsSection) { |
617 |
ObjectVersionsViewController *vc = [[ObjectVersionsViewController alloc] initWithNibName:@"ObjectVersionsViewController" bundle:nil]; |
618 |
vc.account = account; |
619 |
vc.container = container; |
620 |
vc.object = object; |
621 |
[self.navigationController pushViewController:vc animated:YES]; |
622 |
[vc release]; |
623 |
} |
624 |
} |
625 |
|
626 |
- (void)setProgress:(float)newProgress { |
627 |
[downloadProgressView setProgress:newProgress animated:YES]; |
628 |
if (newProgress >= 1.0) { |
629 |
fileDownloading = NO; |
630 |
fileDownloaded = YES; |
631 |
[self.tableView reloadData]; |
632 |
} |
633 |
} |
634 |
|
635 |
|
636 |
#pragma mark - |
637 |
#pragma mark Document Interation Controller Delegate |
638 |
|
639 |
- (UIViewController *)documentInteractionControllerViewControllerForPreview:(UIDocumentInteractionController *) controller { |
640 |
return self.navigationController; |
641 |
} |
642 |
|
643 |
- (void)documentInteractionControllerDidEndPreview:(UIDocumentInteractionController *)controllers { |
644 |
[self.tableView deselectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:actionsSection] animated:YES]; |
645 |
} |
646 |
|
647 |
#pragma mark - |
648 |
#pragma mark Action Sheet Delegate |
649 |
|
650 |
- (void)deleteObjectRow { |
651 |
[self.folderViewController.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:selectedIndexPath] withRowAnimation:UITableViewRowAnimationLeft]; |
652 |
} |
653 |
|
654 |
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex { |
655 |
if ([actionSheet isEqual:deleteActionSheet]) { |
656 |
if (buttonIndex == 0) { |
657 |
// delete the file and pop out |
658 |
|
659 |
NSString *activityMessage = @"Deleting file"; |
660 |
|
661 |
activityIndicatorView = [[ActivityIndicatorView alloc] initWithFrame:[ActivityIndicatorView frameForText:activityMessage] text:activityMessage]; |
662 |
[activityIndicatorView addToView:self.view]; |
663 |
|
664 |
|
665 |
[[self.account.manager deleteObject:self.container object:self.object] |
666 |
success:^(OpenStackRequest *request) { |
667 |
[activityIndicatorView removeFromSuperviewAndRelease]; |
668 |
performingAction = NO; |
669 |
[self.folder.objects removeObjectForKey:self.object.name]; |
670 |
|
671 |
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) { |
672 |
[self.navigationController popViewControllerAnimated:YES]; |
673 |
if (account.shared) |
674 |
self.folderViewController.needsRefreshing = YES; |
675 |
} else if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { |
676 |
if (!account.shared) |
677 |
[self.folderViewController setDetailViewController]; |
678 |
else |
679 |
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) |
680 |
[self.folderViewController refreshButtonPressed:nil]; |
681 |
} |
682 |
|
683 |
if ([self.folder.objects count] + [self.folder.folders count] == 0) { |
684 |
[self.folderViewController.tableView reloadData]; |
685 |
} else { |
686 |
[self.folderViewController.tableView selectRowAtIndexPath:selectedIndexPath animated:YES scrollPosition:UITableViewScrollPositionNone]; |
687 |
[NSTimer scheduledTimerWithTimeInterval:0.75 target:self selector:@selector(deleteObjectRow) userInfo:nil repeats:NO]; |
688 |
} |
689 |
} |
690 |
failure:^(OpenStackRequest *request) { |
691 |
[activityIndicatorView removeFromSuperviewAndRelease]; |
692 |
[self hideToolbarActivityMessage]; |
693 |
performingAction = NO; |
694 |
[self alert:@"There was a problem deleting this file." request:request]; |
695 |
}]; |
696 |
} |
697 |
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:deleteSection]; |
698 |
[self.tableView deselectRowAtIndexPath:indexPath animated:YES]; |
699 |
} else if ([actionSheet isEqual:cdnURLActionSheet]) { |
700 |
NSURL *url = [NSURL URLWithString:[[NSString stringWithFormat:@"%@/%@", self.container.cdnURL, self.object.fullPath] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]; |
701 |
|
702 |
if (buttonIndex == 0) { |
703 |
// copy to pasteboard |
704 |
UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]; |
705 |
[pasteboard setString:[url description]]; |
706 |
} else if (buttonIndex == 1) { |
707 |
// open in safari |
708 |
UIApplication *application = [UIApplication sharedApplication]; |
709 |
if ([application canOpenURL:url]) { |
710 |
[application openURL:url]; |
711 |
} else { |
712 |
[self alert:@"Error" message:[NSString stringWithFormat:@"This URL cannot be opened.\n%@", url]]; |
713 |
} |
714 |
} else if (buttonIndex == 2) { |
715 |
// email link to file |
716 |
MFMailComposeViewController *vc = [[MFMailComposeViewController alloc] init]; |
717 |
vc.mailComposeDelegate = self; |
718 |
[vc setSubject:self.object.name]; |
719 |
[vc setMessageBody:[url description] isHTML:NO]; |
720 |
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { |
721 |
vc.modalPresentationStyle = UIModalPresentationPageSheet; |
722 |
} |
723 |
[self presentModalViewController:vc animated:YES]; |
724 |
[vc release]; |
725 |
} else if (buttonIndex == 3) { |
726 |
// tweet link to file |
727 |
UIApplication *app = [UIApplication sharedApplication]; |
728 |
NSURL *twitterURL = [NSURL URLWithString:[NSString stringWithFormat:@"twitter://post?message=%@", [[url description] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]]; |
729 |
if ([app canOpenURL:twitterURL]) { |
730 |
[app openURL:twitterURL]; |
731 |
} |
732 |
} |
733 |
[self.tableView deselectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:cdnURLSection] animated:YES]; |
734 |
} |
735 |
} |
736 |
|
737 |
#pragma mark - |
738 |
#pragma mark Mail Composer Delegate |
739 |
|
740 |
// Dismisses the email composition interface when users tap Cancel or Send. |
741 |
- (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error { |
742 |
[self dismissModalViewControllerAnimated:YES]; |
743 |
[self.tableView deselectRowAtIndexPath:[NSIndexPath indexPathForRow:1 inSection:actionsSection] animated:YES]; |
744 |
} |
745 |
|
746 |
#pragma mark - |
747 |
#pragma mark Switches |
748 |
|
749 |
- (void)objectIsPublicSwitchChanged:(id)sender |
750 |
{ |
751 |
NSString *activityMessage = [NSString stringWithFormat:@"Enabling public link.."]; |
752 |
self.oldPubicURI = object.publicURI; |
753 |
|
754 |
if (objectIsPublic) { |
755 |
activityMessage = [NSString stringWithFormat:@"Disabling public link.."]; |
756 |
object.publicURI = @""; |
757 |
} |
758 |
else { |
759 |
object.publicURI = @"TRUE"; |
760 |
} |
761 |
|
762 |
activityIndicatorView = [[ActivityIndicatorView alloc] initWithFrame:[ActivityIndicatorView frameForText:activityMessage] text:activityMessage]; |
763 |
[activityIndicatorView addToView:self.view scrollOffset:self.tableView.contentOffset.y]; |
764 |
|
765 |
objectIsPublic = !objectIsPublic; |
766 |
[[self.account.manager writeObjectMetadata:container object:object] |
767 |
success:^(OpenStackRequest *request) { |
768 |
NSIndexPath *publicURICellIndexPath = [NSIndexPath indexPathForRow:1 inSection:publicLinkSection]; |
769 |
if (objectIsPublic) { |
770 |
[[self.account.manager getObjectInfo:container object:object version:versionID] |
771 |
success:^(OpenStackRequest *request) { |
772 |
[activityIndicatorView removeFromSuperviewAndRelease]; |
773 |
object.publicURI = [request.responseHeaders objectForKey:@"X-Object-Public"]; |
774 |
NSIndexPath *publicURICellIndexPath = [NSIndexPath indexPathForRow:1 inSection:publicLinkSection]; |
775 |
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:publicURICellIndexPath] |
776 |
withRowAnimation:UITableViewRowAnimationBottom]; |
777 |
} |
778 |
failure:^(OpenStackRequest *request) { |
779 |
[activityIndicatorView removeFromSuperviewAndRelease]; |
780 |
[self alert:@"There was a problem retrieving the public link from the server." request:request]; |
781 |
}]; |
782 |
} |
783 |
else { |
784 |
[activityIndicatorView removeFromSuperviewAndRelease]; |
785 |
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:publicURICellIndexPath] |
786 |
withRowAnimation:UITableViewRowAnimationTop]; |
787 |
} |
788 |
} |
789 |
failure:^(OpenStackRequest *request) { |
790 |
[activityIndicatorView removeFromSuperviewAndRelease]; |
791 |
objectIsPublic = !objectIsPublic; |
792 |
objectIsPublicSwitch.on = !objectIsPublicSwitch.on; |
793 |
object.publicURI = oldPubicURI; |
794 |
[self alert:@"There was a problem enabling the public link." request:request]; |
795 |
|
796 |
}]; |
797 |
} |
798 |
|
799 |
|
800 |
|
801 |
#pragma mark - |
802 |
#pragma mark Memory management |
803 |
|
804 |
- (void)dealloc { |
805 |
if (fileDownloading) { |
806 |
OpenStackRequest *request = [self.account.manager.objectDownloadRequests objectForKey:object.fullPath]; |
807 |
[request setDownloadProgressDelegate:nil]; |
808 |
} |
809 |
[account release]; |
810 |
[downloadProgressView release]; |
811 |
[deleteActionSheet release]; |
812 |
[cdnURLActionSheet release]; |
813 |
[tableView release]; |
814 |
[folderViewController release]; |
815 |
[objectIsPublicSwitch release]; |
816 |
[permissions release]; |
817 |
[documentInteractionController release]; |
818 |
[actionSelectedIndexPath release]; |
819 |
[versionID release]; |
820 |
|
821 |
[super dealloc]; |
822 |
} |
823 |
|
824 |
#pragma mark - |
825 |
#pragma mark Helper functions |
826 |
|
827 |
- (void)reloadMetadataSection { |
828 |
NSString *activityMessage = @"Loading metadata..."; |
829 |
activityIndicatorView = [[ActivityIndicatorView alloc] initWithFrame:[ActivityIndicatorView frameForText:activityMessage] text:activityMessage]; |
830 |
[activityIndicatorView addToView:self.view]; |
831 |
[[self.account.manager getObjectInfo:container object:object version:versionID] |
832 |
success:^(OpenStackRequest *request) { |
833 |
[activityIndicatorView removeFromSuperviewAndRelease]; |
834 |
object.metadata = [NSMutableDictionary dictionary]; |
835 |
for (NSString *header in request.responseHeaders) { |
836 |
NSString *metadataKey; |
837 |
NSString *metadataValue; |
838 |
if ([header rangeOfString:@"X-Object-Meta-"].location != NSNotFound) { |
839 |
metadataKey = [header substringFromIndex:14]; |
840 |
metadataValue = [request.responseHeaders objectForKey:header]; |
841 |
[object.metadata setObject:metadataValue forKey:metadataKey]; |
842 |
} |
843 |
} |
844 |
NSIndexSet *metadataSections = [NSIndexSet indexSetWithIndex:kMetadata]; |
845 |
[self.tableView reloadSections:metadataSections withRowAnimation:UITableViewRowAnimationFade]; |
846 |
} |
847 |
failure:^(OpenStackRequest *request) { |
848 |
[activityIndicatorView removeFromSuperviewAndRelease]; |
849 |
[self alert:@"There was a problem retrieving the object's metadata." request:request]; |
850 |
}]; |
851 |
} |
852 |
|
853 |
|
854 |
@end |
855 |
|