root / Classes / StorageObjectViewController.m @ 29cc4957
History | View | Annotate | Download (38.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 2 |
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 |
actionsSection = 1; |
161 |
publicLinkSection = 3; |
162 |
permissionsSection = 4; |
163 |
if (self.container.cdnEnabled) { |
164 |
cdnURLSection = 5; |
165 |
deleteSection = 6; |
166 |
versionsSection = 7; |
167 |
} else { |
168 |
cdnURLSection = -1; |
169 |
deleteSection = 5; |
170 |
versionsSection = 6; |
171 |
} |
172 |
|
173 |
if (versionID) { |
174 |
publicLinkSection = -1; |
175 |
permissionsSection = -1; |
176 |
versionsSection = -1; |
177 |
deleteSection = -1; |
178 |
objectIsReadOnly = YES; |
179 |
} |
180 |
if (account.sharingAccount || account.shared) { |
181 |
versionsSection = -1; |
182 |
deleteSection = -1; |
183 |
} |
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 |
if (indexPath.section == publicLinkSection) { |
301 |
if (indexPath.row == 1) { |
302 |
TextViewCell *cell = [aTableView dequeueReusableCellWithIdentifier:TextViewCellIdentifier]; |
303 |
if (cell == nil) { |
304 |
cell = [[[TextViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:TextViewCellIdentifier] autorelease]; |
305 |
cell.textView.frame = cell.contentView.frame; |
306 |
|
307 |
} |
308 |
cell.selectionStyle = UITableViewCellSelectionStyleNone; |
309 |
cell.textView.backgroundColor = [UIColor clearColor]; |
310 |
cell.textView.font = [UIFont systemFontOfSize:15.0]; |
311 |
cell.textView.dataDetectorTypes = UIDataDetectorTypeLink; |
312 |
cell.textView.text = [NSString stringWithFormat:@"%@%@", |
313 |
account.pithosPublicLinkURLPrefix, |
314 |
[NSString encodeToPercentEscape:self.object.publicURI charactersToEncode:@"!*'();:@&=+$,?%#[]"]]; |
315 |
|
316 |
cell.selectionStyle = UITableViewCellSelectionStyleNone; |
317 |
cell.accessoryView = UITableViewCellAccessoryNone; |
318 |
return cell; |
319 |
} |
320 |
} |
321 |
|
322 |
UITableViewCell *cell = [aTableView dequeueReusableCellWithIdentifier:CellIdentifier]; |
323 |
if (cell == nil) { |
324 |
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease]; |
325 |
cell.textLabel.backgroundColor = [UIColor clearColor]; |
326 |
cell.detailTextLabel.backgroundColor = [UIColor clearColor]; |
327 |
cell.detailTextLabel.lineBreakMode = UILineBreakModeWordWrap; |
328 |
} |
329 |
cell.textLabel.textColor = [UIColor blackColor]; |
330 |
cell.detailTextLabel.numberOfLines = 0; |
331 |
|
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 = @"Share"; |
412 |
cell.detailTextLabel.text = @""; |
413 |
} else { |
414 |
NSString *user = [[permissions allKeys] objectAtIndex:indexPath.row]; |
415 |
cell.textLabel.text = user; |
416 |
NSString *accessType; |
417 |
if ([[permissions objectForKey:user] isEqualToString:@"write"]) |
418 |
accessType = @"Read/Write"; |
419 |
else |
420 |
accessType = @"Read Only"; |
421 |
cell.detailTextLabel.numberOfLines = 1; |
422 |
cell.detailTextLabel.lineBreakMode = UILineBreakModeTailTruncation; |
423 |
cell.detailTextLabel.text = accessType; |
424 |
} |
425 |
} else if (indexPath.section == cdnURLSection) { |
426 |
cell.detailTextLabel.textAlignment = UITextAlignmentLeft; |
427 |
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; |
428 |
cell.textLabel.text = @""; |
429 |
cell.detailTextLabel.text = [[NSString stringWithFormat:@"%@/%@", self.container.cdnURL, self.object.fullPath] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; |
430 |
} else if (indexPath.section == actionsSection) { |
431 |
if (fileDownloading) { |
432 |
if (actionSelectedIndexPath.row == indexPath.row) { |
433 |
cell.accessoryView = downloadProgressView; |
434 |
} else { |
435 |
cell.textLabel.textColor = [UIColor grayColor]; |
436 |
cell.selectionStyle = UITableViewCellSelectionStyleNone; |
437 |
} |
438 |
} else { |
439 |
cell.selectionStyle = UITableViewCellSelectionStyleBlue; |
440 |
cell.accessoryView = nil; |
441 |
} |
442 |
if (indexPath.row == 0) { |
443 |
cell.textLabel.text = @"Open File"; |
444 |
cell.accessoryType = UITableViewCellAccessoryNone; |
445 |
cell.detailTextLabel.text = @""; |
446 |
|
447 |
} else if (indexPath.row == 1) { |
448 |
cell.textLabel.text = @"Email File as Attachment"; |
449 |
cell.detailTextLabel.text = @""; |
450 |
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; |
451 |
} |
452 |
} else if (indexPath.section == deleteSection) { |
453 |
cell.selectionStyle = UITableViewCellSelectionStyleBlue; |
454 |
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; |
455 |
cell.textLabel.text = @"Delete Object"; |
456 |
cell.detailTextLabel.text = @""; |
457 |
|
458 |
} else if (indexPath.section == versionsSection) { |
459 |
cell.selectionStyle = UITableViewCellSelectionStyleBlue; |
460 |
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; |
461 |
cell.textLabel.text = @"Versions"; |
462 |
cell.detailTextLabel.text = @""; |
463 |
} |
464 |
|
465 |
return cell; |
466 |
} |
467 |
|
468 |
|
469 |
|
470 |
#pragma mark - |
471 |
#pragma mark Table view delegate |
472 |
|
473 |
- (void)reloadActionsTitleRow:(NSTimer *)timer { |
474 |
[[timer.userInfo objectForKey:@"tableView"] reloadRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:0 inSection:actionsSection]] withRowAnimation:UITableViewRowAnimationNone]; |
475 |
} |
476 |
|
477 |
- (void)tableView:(UITableView *)aTableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { |
478 |
if (indexPath.section == kMetadata) { |
479 |
EditMetadataViewController *vc = [[EditMetadataViewController alloc] initWithNibName:@"EditMetadataViewController" bundle:nil]; |
480 |
NSString *metadataKey; |
481 |
NSString *metadataValue; |
482 |
|
483 |
if (indexPath.row == [self.object.metadata count]) { |
484 |
metadataKey = @""; |
485 |
metadataValue = @""; |
486 |
vc.removeMetadataEnabled = FALSE; |
487 |
vc.navigationItem.title = @"Add Metadata"; |
488 |
} |
489 |
else { |
490 |
metadataKey = [[self.object.metadata allKeys] objectAtIndex:indexPath.row]; |
491 |
metadataValue = [self.object.metadata objectForKey:metadataKey]; |
492 |
vc.removeMetadataEnabled = YES; |
493 |
vc.navigationItem.title = @"Edit Metadata"; |
494 |
} |
495 |
|
496 |
vc.metadataKey = metadataKey; |
497 |
vc.metadataValue = metadataValue; |
498 |
vc.account = account; |
499 |
vc.container = container; |
500 |
vc.object = object; |
501 |
[self.navigationController pushViewController:vc animated:YES]; |
502 |
[vc release]; |
503 |
} else if (indexPath.section == permissionsSection) { |
504 |
EditPermissionsViewController *vc = [[EditPermissionsViewController alloc] initWithNibName:@"EditPermissionsViewController" bundle:nil]; |
505 |
NSString *user; |
506 |
|
507 |
if (indexPath.row == [permissions count]) { |
508 |
user = @""; |
509 |
vc.removePermissionsEnabled = NO; |
510 |
vc.navigationItem.title = @"Share"; |
511 |
} |
512 |
else { |
513 |
user = [[permissions allKeys] objectAtIndex:indexPath.row]; |
514 |
NSString *userPermissions = [permissions objectForKey:user]; |
515 |
if ([userPermissions rangeOfString:@"read"].location != NSNotFound) |
516 |
vc.readPermissionSelected = YES; |
517 |
else |
518 |
vc.readPermissionSelected = NO; |
519 |
|
520 |
if ([userPermissions rangeOfString:@"write"].location != NSNotFound) |
521 |
vc.writePermissionSelected = YES; |
522 |
else |
523 |
vc.writePermissionSelected = NO; |
524 |
|
525 |
vc.removePermissionsEnabled = YES; |
526 |
vc.navigationItem.title = @"Edit Sharing"; |
527 |
} |
528 |
|
529 |
vc.user = user; |
530 |
vc.permissions = permissions; |
531 |
vc.account = account; |
532 |
vc.container = container; |
533 |
vc.object = object; |
534 |
vc.folderViewController = folderViewController; |
535 |
[self.navigationController pushViewController:vc animated:YES]; |
536 |
[vc release]; |
537 |
} else if (indexPath.section == cdnURLSection) { |
538 |
[cdnURLActionSheet showInView:self.view]; |
539 |
} else if (indexPath.section == actionsSection) { |
540 |
if (!fileDownloaded) { |
541 |
if (!fileDownloading) { |
542 |
// download the file |
543 |
fileDownloading = YES; |
544 |
self.actionSelectedIndexPath = indexPath; |
545 |
[self.tableView reloadData]; |
546 |
NSMutableDictionary *requestUserInfo = [NSDictionary dictionaryWithObject:indexPath forKey:@"actionSelectedIndexPath"]; |
547 |
[[self.account.manager getObject:self.container object:self.object downloadProgressDelegate:self requestUserInfo:requestUserInfo version:versionID] |
548 |
success:^(OpenStackRequest *request) { |
549 |
fileDownloaded = YES; |
550 |
fileDownloading = NO; |
551 |
if ([self.navigationController.visibleViewController isEqual:self]) |
552 |
[self.tableView.delegate tableView:self.tableView didSelectRowAtIndexPath:indexPath]; |
553 |
[self.tableView reloadData]; |
554 |
[self.folderViewController.tableView reloadData]; |
555 |
} |
556 |
failure:^(OpenStackRequest *request) { |
557 |
fileDownloaded = NO; |
558 |
fileDownloading = NO; |
559 |
[self alert:@"File failed to download" request:request]; |
560 |
[self.tableView reloadData]; |
561 |
}]; |
562 |
[self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:indexPath.row inSection:actionsSection]] withRowAnimation:UITableViewRowAnimationNone]; |
563 |
} |
564 |
} else if (indexPath.row == 0) { |
565 |
if (fileDownloaded) { |
566 |
NSString *filePath = [appDelegate.cachedObjectsDictionary objectForKey:object.hash]; |
567 |
self.documentInteractionController = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:filePath]]; |
568 |
self.documentInteractionController.delegate = self; |
569 |
self.documentInteractionController.name = object.name; |
570 |
|
571 |
UITableViewCell *openFileCell = [self.tableView cellForRowAtIndexPath:indexPath]; |
572 |
CGRect frameToPresentMenuFrom = CGRectMake(openFileCell.frame.origin.x, |
573 |
openFileCell.frame.origin.y - self.tableView.contentOffset.y, |
574 |
openFileCell.frame.size.width, |
575 |
openFileCell.frame.size.height); |
576 |
if (![self.documentInteractionController presentOptionsMenuFromRect:frameToPresentMenuFrom inView:self.view animated:YES]) { |
577 |
if ([self.object isPlayableMedia]) { |
578 |
MediaViewController *vc = [[MediaViewController alloc] initWithNibName:@"MediaViewController" bundle:nil]; |
579 |
vc.container = self.container; |
580 |
vc.object = self.object; |
581 |
[self.navigationController pushViewController:vc animated:YES]; |
582 |
[vc release]; |
583 |
} else { |
584 |
[self alert:@"Error" message:@"This file could not be opened."]; |
585 |
[self.tableView deselectRowAtIndexPath:indexPath animated:YES]; |
586 |
} |
587 |
} |
588 |
|
589 |
[self.tableView deselectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:actionsSection] animated:YES]; |
590 |
|
591 |
} |
592 |
} else if (indexPath.row == 1) { |
593 |
|
594 |
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); |
595 |
NSString *documentsDirectory = [paths objectAtIndex:0]; |
596 |
NSString *shortPath = @""; |
597 |
|
598 |
if (self.container && [self.container respondsToSelector:@selector(name)] && self.object && [self.object respondsToSelector:@selector(fullPath)]) { |
599 |
shortPath = [NSString stringWithFormat:@"/%@/%@", self.container.name, self.object.fullPath]; |
600 |
} |
601 |
|
602 |
NSString *filePath = [documentsDirectory stringByAppendingString:shortPath]; |
603 |
NSData *data = [NSData dataWithContentsOfURL:[NSURL fileURLWithPath:filePath]]; |
604 |
|
605 |
|
606 |
if (![MFMailComposeViewController canSendMail]) { |
607 |
[self alert:@"Cannot send mail" message:@"Your device has not been configured for sending email"]; |
608 |
[self.tableView deselectRowAtIndexPath:indexPath animated:NO]; |
609 |
} |
610 |
else { |
611 |
MFMailComposeViewController *vc = [[MFMailComposeViewController alloc] init]; |
612 |
|
613 |
vc.mailComposeDelegate = self; |
614 |
[vc setSubject:self.object.name]; |
615 |
[vc addAttachmentData:data mimeType:self.object.contentType fileName:self.object.name]; |
616 |
[vc setMessageBody:@"" isHTML:NO]; |
617 |
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { |
618 |
vc.modalPresentationStyle = UIModalPresentationPageSheet; |
619 |
} |
620 |
[self presentModalViewController:vc animated:YES]; |
621 |
[vc release]; |
622 |
} |
623 |
} |
624 |
} else if (indexPath.section == deleteSection) { |
625 |
[deleteActionSheet showInView:self.view]; |
626 |
} else if (indexPath.section == versionsSection) { |
627 |
ObjectVersionsViewController *vc = [[ObjectVersionsViewController alloc] initWithNibName:@"ObjectVersionsViewController" bundle:nil]; |
628 |
vc.account = account; |
629 |
vc.container = container; |
630 |
vc.object = object; |
631 |
[self.navigationController pushViewController:vc animated:YES]; |
632 |
[vc release]; |
633 |
} |
634 |
} |
635 |
|
636 |
- (void)setProgress:(float)newProgress { |
637 |
[downloadProgressView setProgress:newProgress animated:YES]; |
638 |
if (newProgress >= 1.0) { |
639 |
fileDownloading = NO; |
640 |
fileDownloaded = YES; |
641 |
[self.tableView reloadData]; |
642 |
} |
643 |
} |
644 |
|
645 |
|
646 |
#pragma mark - |
647 |
#pragma mark Document Interation Controller Delegate |
648 |
|
649 |
- (UIViewController *)documentInteractionControllerViewControllerForPreview:(UIDocumentInteractionController *) controller { |
650 |
return self.navigationController; |
651 |
} |
652 |
|
653 |
- (void)documentInteractionControllerDidEndPreview:(UIDocumentInteractionController *)controllers { |
654 |
[self.tableView deselectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:actionsSection] animated:YES]; |
655 |
} |
656 |
|
657 |
#pragma mark - |
658 |
#pragma mark Action Sheet Delegate |
659 |
|
660 |
- (void)deleteObjectRow { |
661 |
[self.folder.objects removeObjectForKey:self.object.name]; |
662 |
[self.folderViewController.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:selectedIndexPath] withRowAnimation:UITableViewRowAnimationLeft]; |
663 |
self.folderViewController.refreshButton.enabled = YES; |
664 |
} |
665 |
|
666 |
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex { |
667 |
if ([actionSheet isEqual:deleteActionSheet]) { |
668 |
if (buttonIndex == 0) { |
669 |
// delete the file and pop out |
670 |
|
671 |
NSString *activityMessage = @"Deleting file"; |
672 |
[activityIndicatorView release]; |
673 |
activityIndicatorView = [[ActivityIndicatorView alloc] initWithFrame:[ActivityIndicatorView frameForText:activityMessage] text:activityMessage]; |
674 |
[activityIndicatorView addToView:self.view]; |
675 |
|
676 |
self.folderViewController.refreshButton.enabled = NO; |
677 |
[[self.account.manager deleteObject:self.container object:self.object] |
678 |
success:^(OpenStackRequest *request) { |
679 |
[activityIndicatorView removeFromSuperview]; |
680 |
performingAction = NO; |
681 |
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) { |
682 |
[self.navigationController popViewControllerAnimated:YES]; |
683 |
if (account.shared) |
684 |
self.folderViewController.needsRefreshing = YES; |
685 |
} else if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { |
686 |
self.folderViewController.selectedObjectViewController = nil; |
687 |
if (!account.shared) |
688 |
[self.folderViewController setDetailViewController]; |
689 |
else |
690 |
[self.folderViewController refreshButtonPressed:nil]; |
691 |
} |
692 |
if (self.folder.objects.count == 1) |
693 |
[self.folder.objects removeObjectForKey:self.object.name]; |
694 |
|
695 |
if ([self.folder.objects count] + [self.folder.folders count] == 0) { |
696 |
[self.folderViewController.tableView reloadData]; |
697 |
} else { |
698 |
[self.folderViewController.tableView selectRowAtIndexPath:selectedIndexPath animated:YES scrollPosition:UITableViewScrollPositionNone]; |
699 |
[NSTimer scheduledTimerWithTimeInterval:0.75 target:self selector:@selector(deleteObjectRow) userInfo:nil repeats:NO]; |
700 |
} |
701 |
} |
702 |
failure:^(OpenStackRequest *request) { |
703 |
[activityIndicatorView removeFromSuperview]; |
704 |
[self hideToolbarActivityMessage]; |
705 |
performingAction = NO; |
706 |
[self alert:@"There was a problem deleting this file." request:request]; |
707 |
}]; |
708 |
} |
709 |
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:deleteSection]; |
710 |
[self.tableView deselectRowAtIndexPath:indexPath animated:YES]; |
711 |
} else if ([actionSheet isEqual:cdnURLActionSheet]) { |
712 |
NSURL *url = [NSURL URLWithString:[[NSString stringWithFormat:@"%@/%@", self.container.cdnURL, self.object.fullPath] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]; |
713 |
|
714 |
if (buttonIndex == 0) { |
715 |
// copy to pasteboard |
716 |
UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]; |
717 |
[pasteboard setString:[url description]]; |
718 |
} else if (buttonIndex == 1) { |
719 |
// open in safari |
720 |
UIApplication *application = [UIApplication sharedApplication]; |
721 |
if ([application canOpenURL:url]) { |
722 |
[application openURL:url]; |
723 |
} else { |
724 |
[self alert:@"Error" message:[NSString stringWithFormat:@"This URL cannot be opened.\n%@", url]]; |
725 |
} |
726 |
} else if (buttonIndex == 2) { |
727 |
// email link to file |
728 |
MFMailComposeViewController *vc = [[MFMailComposeViewController alloc] init]; |
729 |
vc.mailComposeDelegate = self; |
730 |
[vc setSubject:self.object.name]; |
731 |
[vc setMessageBody:[url description] isHTML:NO]; |
732 |
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { |
733 |
vc.modalPresentationStyle = UIModalPresentationPageSheet; |
734 |
} |
735 |
[self presentModalViewController:vc animated:YES]; |
736 |
[vc release]; |
737 |
} else if (buttonIndex == 3) { |
738 |
// tweet link to file |
739 |
UIApplication *app = [UIApplication sharedApplication]; |
740 |
NSURL *twitterURL = [NSURL URLWithString:[NSString stringWithFormat:@"twitter://post?message=%@", [[url description] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]]; |
741 |
if ([app canOpenURL:twitterURL]) { |
742 |
[app openURL:twitterURL]; |
743 |
} |
744 |
} |
745 |
[self.tableView deselectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:cdnURLSection] animated:YES]; |
746 |
} |
747 |
} |
748 |
|
749 |
#pragma mark - |
750 |
#pragma mark Mail Composer Delegate |
751 |
|
752 |
// Dismisses the email composition interface when users tap Cancel or Send. |
753 |
- (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error { |
754 |
[self dismissModalViewControllerAnimated:YES]; |
755 |
[self.tableView deselectRowAtIndexPath:[NSIndexPath indexPathForRow:1 inSection:actionsSection] animated:YES]; |
756 |
} |
757 |
|
758 |
#pragma mark - |
759 |
#pragma mark Switches |
760 |
|
761 |
- (void)objectIsPublicSwitchChanged:(id)sender |
762 |
{ |
763 |
NSString *activityMessage = [NSString stringWithFormat:@"Enabling public link.."]; |
764 |
self.oldPubicURI = object.publicURI; |
765 |
|
766 |
if (objectIsPublic) { |
767 |
activityMessage = [NSString stringWithFormat:@"Disabling public link.."]; |
768 |
object.publicURI = @""; |
769 |
} |
770 |
else { |
771 |
object.publicURI = @"TRUE"; |
772 |
} |
773 |
[activityIndicatorView release]; |
774 |
activityIndicatorView = [[ActivityIndicatorView alloc] initWithFrame:[ActivityIndicatorView frameForText:activityMessage] text:activityMessage]; |
775 |
[activityIndicatorView addToView:self.view scrollOffset:self.tableView.contentOffset.y]; |
776 |
|
777 |
objectIsPublic = !objectIsPublic; |
778 |
[[self.account.manager writeObjectMetadata:container object:object] |
779 |
success:^(OpenStackRequest *request) { |
780 |
NSIndexPath *publicURICellIndexPath = [NSIndexPath indexPathForRow:1 inSection:publicLinkSection]; |
781 |
if (objectIsPublic) { |
782 |
[[self.account.manager getObjectInfo:container object:object version:versionID] |
783 |
success:^(OpenStackRequest *request) { |
784 |
[activityIndicatorView removeFromSuperview]; |
785 |
object.publicURI = [request.responseHeaders objectForKey:@"X-Object-Public"]; |
786 |
NSIndexPath *publicURICellIndexPath = [NSIndexPath indexPathForRow:1 inSection:publicLinkSection]; |
787 |
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:publicURICellIndexPath] |
788 |
withRowAnimation:UITableViewRowAnimationBottom]; |
789 |
} |
790 |
failure:^(OpenStackRequest *request) { |
791 |
[activityIndicatorView removeFromSuperview]; |
792 |
[self alert:@"There was a problem retrieving the public link from the server." request:request]; |
793 |
}]; |
794 |
} |
795 |
else { |
796 |
[activityIndicatorView removeFromSuperview]; |
797 |
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:publicURICellIndexPath] |
798 |
withRowAnimation:UITableViewRowAnimationTop]; |
799 |
} |
800 |
} |
801 |
failure:^(OpenStackRequest *request) { |
802 |
[activityIndicatorView removeFromSuperview]; |
803 |
objectIsPublic = !objectIsPublic; |
804 |
objectIsPublicSwitch.on = !objectIsPublicSwitch.on; |
805 |
object.publicURI = oldPubicURI; |
806 |
[self alert:@"There was a problem enabling the public link." request:request]; |
807 |
|
808 |
}]; |
809 |
} |
810 |
|
811 |
|
812 |
|
813 |
#pragma mark - |
814 |
#pragma mark Memory management |
815 |
|
816 |
- (void)dealloc { |
817 |
if (fileDownloading) { |
818 |
OpenStackRequest *request = [self.account.manager.objectDownloadRequests objectForKey:object.fullPath]; |
819 |
[request setDownloadProgressDelegate:nil]; |
820 |
} |
821 |
[account release]; |
822 |
[downloadProgressView release]; |
823 |
[deleteActionSheet release]; |
824 |
[cdnURLActionSheet release]; |
825 |
[tableView release]; |
826 |
[folderViewController release]; |
827 |
[objectIsPublicSwitch release]; |
828 |
[permissions release]; |
829 |
[documentInteractionController release]; |
830 |
[actionSelectedIndexPath release]; |
831 |
[versionID release]; |
832 |
[activityIndicatorView release]; |
833 |
[super dealloc]; |
834 |
} |
835 |
|
836 |
#pragma mark - |
837 |
#pragma mark Helper functions |
838 |
|
839 |
- (void)reloadMetadataSection { |
840 |
NSString *activityMessage = @"Loading metadata..."; |
841 |
[activityIndicatorView release]; |
842 |
activityIndicatorView = [[ActivityIndicatorView alloc] initWithFrame:[ActivityIndicatorView frameForText:activityMessage] text:activityMessage]; |
843 |
[activityIndicatorView addToView:self.view]; |
844 |
[[self.account.manager getObjectInfo:container object:object version:versionID] |
845 |
success:^(OpenStackRequest *request) { |
846 |
[activityIndicatorView removeFromSuperview]; |
847 |
object.metadata = [NSMutableDictionary dictionary]; |
848 |
for (NSString *header in request.responseHeaders) { |
849 |
NSString *metadataKey; |
850 |
NSString *metadataValue; |
851 |
if ([header rangeOfString:@"X-Object-Meta-"].location != NSNotFound) { |
852 |
metadataKey = [NSString decodeFromPercentEscape:[header substringFromIndex:14]]; |
853 |
metadataValue = [NSString decodeFromPercentEscape:[request.responseHeaders objectForKey:header]]; |
854 |
[object.metadata setObject:metadataValue forKey:metadataKey]; |
855 |
} |
856 |
} |
857 |
NSIndexSet *metadataSections = [NSIndexSet indexSetWithIndex:kMetadata]; |
858 |
[self.tableView reloadSections:metadataSections withRowAnimation:UITableViewRowAnimationFade]; |
859 |
} |
860 |
failure:^(OpenStackRequest *request) { |
861 |
[activityIndicatorView removeFromSuperview]; |
862 |
[self alert:@"There was a problem retrieving the object's metadata." request:request]; |
863 |
}]; |
864 |
} |
865 |
|
866 |
|
867 |
@end |
868 |
|