2 // ContainerDetailViewController.m
5 // Created by Mike Mayo on 12/22/10.
6 // The OpenStack project is provided under the Apache 2.0 license.
9 #import "ContainerDetailViewController.h"
10 #import "OpenStackAccount.h"
12 #import "ActivityIndicatorView.h"
13 #import "AccountManager.h"
14 #import "UIViewController+Conveniences.h"
15 #import "UIColor+MoreColors.h"
16 #import "ReferrerACLViewController.h"
17 #import "UserAgentACLViewController.h"
18 #import "ContainersViewController.h"
19 #import "EditMetadataViewController.h"
20 #import "EditPolicyViewController.h"
22 #import "FolderViewController.h"
23 #import "OpenStackRequest.h"
24 #import "APICallback.h"
29 #define kCDNAttributes 4
30 #define kLogRetention 5
31 #define kReferrerACL 6
32 #define kUserAgentACL 7
34 #define maxMetadataViewableLength 12
41 Publish to CDN [On/Off]
42 @"Containers published to the CDN will be viewable to everyone. If you disable CDN access, container contents will not be purged from the CDN until the TTL expires."
47 Log Retention [On/Off]
48 @"When Log Retention is enabled, CDN access logs will be stored in the .CDN_ACCESS_LOGS container in your account."
51 @"The Referrer ACL is a Perl Compatible Regular Expression (PCRE) that must match the referrer in order for container contents to be served. This is a useful mechanism to prevent other content providers from hot-linking your CDN content."
54 @"The User Agent ACL is a PCRE that must match the user agent that your users are using to access the CDN content."
58 @implementation ContainerDetailViewController
60 @synthesize account, container, containersViewController, selectedContainerIndexPath, rootFolderViewController;
62 - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
63 return (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) || (toInterfaceOrientation == UIInterfaceOrientationPortrait);
66 - (void)setBackgroundView {
67 if (!self.container) {
68 UIView *viewContainer = [[UIView alloc] init];
69 viewContainer.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
70 viewContainer.backgroundColor = [UIColor iPadTableBackgroundColor];
72 UILabel *label = [[UILabel alloc] init];
73 label.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin;
74 label.backgroundColor = [UIColor clearColor];
75 label.textColor = [UIColor emptyCollectionGrayColor];
76 label.font = [UIFont boldSystemFontOfSize:18.0];
77 label.text = @"No container selected";
78 label.textAlignment = UITextAlignmentCenter;
79 [viewContainer addSubview:label];
82 self.tableView.backgroundView = viewContainer;
83 [viewContainer release];
88 #pragma mark View lifecycle
92 cdnEnabledSwitch = [[UISwitch alloc] init];
93 cdnEnabledSwitch.on = container.cdnEnabled;
94 [cdnEnabledSwitch addTarget:self action:@selector(cdnEnabledSwitchChanged:) forControlEvents:UIControlEventValueChanged];
96 logRetentionSwitch = [[UISwitch alloc] init];
97 logRetentionSwitch.on = container.logRetention;
98 [logRetentionSwitch addTarget:self action:@selector(logRetentionSwitchChanged:) forControlEvents:UIControlEventValueChanged];
100 ttlSlider = [[UISlider alloc] init];
101 cdnURLActionSheet = [[UIActionSheet alloc] initWithTitle:container.cdnURL delegate:self cancelButtonTitle:@"Cancel" destructiveButtonTitle:nil otherButtonTitles:@"Copy to Pasteboard", nil];
102 deleteActionSheet = [[UIActionSheet alloc] initWithTitle:@"Are you sure you want to delete this container? This operation cannot be undone." delegate:self cancelButtonTitle:@"Cancel" destructiveButtonTitle:@"Delete Container" otherButtonTitles:nil];
104 if (!account.sharingAccount) {
105 deleteSection = container.cdnEnabled ? 8 : 3;
106 policySection = container.cdnEnabled ? 7 : 2;
113 - (void)viewWillAppear:(BOOL)animated {
114 [super viewWillAppear:animated];
116 self.navigationItem.title = container.name;
118 originalTTL = container.ttl;
119 [self setBackgroundView];
120 [self.tableView reloadData];
123 - (void)viewWillDisappear:(BOOL)animated {
124 [super viewWillDisappear:animated];
130 - (float)ttlToPercentage {
131 return self.container.ttl / 259200.0;
134 - (NSInteger)ttlFromPercentage:(float)percentage {
135 return percentage * 259200;
138 - (NSString *)ttlToHours {
139 NSString *result = [NSString stringWithFormat:@"%.0f hours", self.container.ttl / 3600.0];
140 if ([result isEqualToString:@"1 hours"]) {
146 - (void)ttlSliderFinished:(id)sender {
147 NSString *activityMessage = @"Updating TTL...";
148 activityIndicatorView = [[ActivityIndicatorView alloc] initWithFrame:[ActivityIndicatorView frameForText:activityMessage] text:activityMessage];
149 [activityIndicatorView addToView:self.view scrollOffset:self.tableView.contentOffset.y];
151 [self.account.manager updateCDNContainer:self.container];
153 successObserver = [[NSNotificationCenter defaultCenter] addObserverForName:@"updateCDNContainerSucceeded" object:self.container
154 queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification* notification)
156 [activityIndicatorView removeFromSuperviewAndRelease];
157 [[NSNotificationCenter defaultCenter] removeObserver:successObserver];
160 failureObserver = [[NSNotificationCenter defaultCenter] addObserverForName:@"updateCDNContainerFailed" object:self.container
161 queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification* notification)
163 [activityIndicatorView removeFromSuperviewAndRelease];
164 container.ttl = originalTTL;
165 [self.tableView reloadData];
166 [self alert:@"There was a problem updating this container." request:[notification.userInfo objectForKey:@"request"]];
167 [[NSNotificationCenter defaultCenter] removeObserver:failureObserver];
171 - (void)ttlSliderMoved:(id)sender {
172 CGFloat newTTL = ttlSlider.value;
173 self.container.ttl = [self ttlFromPercentage:newTTL];
174 ttlLabel.text = [self ttlToHours];
179 #pragma mark Table view data source
181 - (CGFloat)findLabelHeight:(NSString*)text font:(UIFont *)font {
182 CGSize textLabelSize;
184 if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
185 textLabelSize = CGSizeMake(577.0, 9000.0f);
187 textLabelSize = CGSizeMake(260.0, 9000.0f);
189 // pad \n\n to fix layout bug
190 CGSize stringSize = [text sizeWithFont:font constrainedToSize:textLabelSize lineBreakMode:UILineBreakModeWordWrap];
191 return stringSize.height;
194 - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
195 if (indexPath.section == deleteSection) {
196 return tableView.rowHeight;
197 } else if (indexPath.section == kCDNAttributes) {
198 if (indexPath.row == 0) { // URL
199 return tableView.rowHeight;
200 //return 22.0 + [self findLabelHeight:container.cdnURL font:[UIFont systemFontOfSize:18.0]];
201 } else { // if (indexPath.row == 1) {
202 return tableView.rowHeight + ttlSlider.frame.size.height + 3.0;
205 return tableView.rowHeight;
209 - (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section {
210 if (section == deleteSection) {
211 return @"Only empty containers can be deleted.";
212 } else if (section == kCDNAccess) {
213 //return @"CDN allows you to access files in this container via the public internet. Transfer charges apply.";
214 return @"CDN allows you to access files via the public internet. Transfer charges apply.";
215 } else if (section == kLogRetention) {
216 return @"When enabled, access logs will be stored in the .CDN_ACCESS_LOGS container.";
217 } else if (section == kReferrerACL) {
218 return @"The Referrer ACL is a Perl Compatible Regular Expression that must match the referrer for all content requests.";
219 } else if (section == kUserAgentACL) {
220 return @"The User Agent ACL is a Perl Compatible Regular Expression that must match the user agent for all content requests.";
226 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
227 if (self.container) {
228 int numberOfSections;
230 numberOfSections = container.cdnEnabled ? 4 : 9;
232 numberOfSections = container.cdnEnabled ? 9 : 4;
234 if (account.sharingAccount)
235 return numberOfSections - 2;
237 return numberOfSections;
243 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
244 // Return the number of rows in the section.
245 if (section == kOverview) {
247 } else if (section == kMetadata) {
248 if (account.sharingAccount)
249 return [container.metadata count];
251 return 1 + [container.metadata count];
252 } else if (section == policySection) {
253 if (account.sharingAccount)
262 - (UITableViewCell *)tableView:(UITableView *)tableView ttlCellForRowAtIndexPath:(NSIndexPath *)indexPath {
263 static NSString *CellIdentifier = @"TTLCell";
265 UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
267 cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease];
268 cell.selectionStyle = UITableViewCellSelectionStyleNone;
270 UILabel *textLabel = [[UILabel alloc] initWithFrame:CGRectMake(20.0, 13.0, 280.0, 20.0)];
271 if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
272 textLabel.frame = CGRectMake(54.0, 13.0, 458.0, 20.0);
274 textLabel.font = [UIFont boldSystemFontOfSize:17.0];
275 textLabel.text = @"TTL";
276 textLabel.textColor = [UIColor blackColor];
277 textLabel.backgroundColor = [UIColor clearColor];
278 [cell addSubview:textLabel];
281 if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
282 ttlSlider.frame = CGRectMake(54.0, 38.0, 596.0, ttlSlider.frame.size.height);
284 ttlSlider.frame = CGRectMake(20.0, 38.0, 280.0, ttlSlider.frame.size.height);
286 [ttlSlider addTarget:self action:@selector(ttlSliderMoved:) forControlEvents:UIControlEventValueChanged];
287 [ttlSlider addTarget:self action:@selector(ttlSliderFinished:) forControlEvents:UIControlEventTouchUpInside];
289 [cell addSubview:ttlSlider];
290 ttlLabel = [[UILabel alloc] initWithFrame:CGRectMake(20.0, 14.0, 280.0, 18.0)];
291 if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
292 ttlLabel.frame = CGRectMake(54.0, 14.0, 596.0, 18.0);
294 ttlLabel.font = [UIFont systemFontOfSize:17.0];
295 ttlLabel.textColor = [UIColor value1DetailTextLabelColor];
296 ttlLabel.backgroundColor = [UIColor clearColor];
297 ttlLabel.textAlignment = UITextAlignmentRight;
298 [cell addSubview:ttlLabel];
301 ttlLabel.text = [self ttlToHours];
302 ttlSlider.value = [self ttlToPercentage];
307 - (UITableViewCell *)tableView:(UITableView *)tableView deleteCellForRowAtIndexPath:(NSIndexPath *)indexPath {
308 static NSString *CellIdentifier = @"DeleteCell";
310 UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
312 cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
313 cell.textLabel.textAlignment = UITextAlignmentCenter;
314 cell.textLabel.text = @"Delete Container";
317 if (self.container.rootFolder) {
318 if (self.container.count == 0 || ([self.container.rootFolder.folders count] + [self.container.rootFolder.objects count] == 0)) {
319 cell.textLabel.textColor = [UIColor blackColor];
320 cell.selectionStyle = UITableViewCellSelectionStyleBlue;
322 cell.textLabel.textColor = [UIColor grayColor];
323 cell.selectionStyle = UITableViewCellSelectionStyleNone;
324 cell.userInteractionEnabled = NO;
327 if (self.container.count == 0) {
328 cell.textLabel.textColor = [UIColor blackColor];
329 cell.selectionStyle = UITableViewCellSelectionStyleBlue;
331 cell.textLabel.textColor = [UIColor grayColor];
332 cell.selectionStyle = UITableViewCellSelectionStyleNone;
333 cell.userInteractionEnabled = NO;
340 // Customize the appearance of table view cells.
341 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
343 static NSString *CellIdentifier = @"Cell";
345 UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
347 cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease];
348 cell.selectionStyle = UITableViewCellSelectionStyleNone;
349 cell.textLabel.backgroundColor = [UIColor clearColor];
350 cell.detailTextLabel.backgroundColor = [UIColor clearColor];
351 cell.detailTextLabel.numberOfLines = 0;
352 cell.detailTextLabel.lineBreakMode = UILineBreakModeWordWrap;
353 cell.detailTextLabel.textAlignment = UITextAlignmentLeft;
356 cell.accessoryType = UITableViewCellAccessoryNone;
357 cell.selectionStyle = UITableViewCellSelectionStyleNone;
359 if (indexPath.section == kOverview) {
360 cell.accessoryView = nil;
361 if (indexPath.row == 0) {
362 cell.textLabel.text = @"Name";
363 cell.detailTextLabel.text = container.name;
364 } else if (indexPath.row == 1) {
365 cell.textLabel.text = @"Size";
366 cell.detailTextLabel.text = [container humanizedSize];
368 } else if (indexPath.section == kMetadata) {
369 if (account.sharingAccount) {
370 cell.accessoryType = UITableViewCellAccessoryNone;
371 cell.selectionStyle = UITableViewCellSelectionStyleNone;
372 cell.userInteractionEnabled = NO;
375 cell.selectionStyle = UITableViewCellSelectionStyleBlue;
376 cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
378 if (indexPath.row == [container.metadata count]) {
379 cell.textLabel.text = @"Add Metadata";
380 cell.detailTextLabel.text = @"";
382 NSString *key = [[container.metadata allKeys] objectAtIndex:indexPath.row];
383 NSString *value = [container.metadata objectForKey:key];
384 NSString *metadataKeyCellText = key;
385 NSString *metadataValueCellText = value;
386 if ([metadataKeyCellText length] > maxMetadataViewableLength) {
387 metadataKeyCellText = [metadataKeyCellText substringToIndex:(maxMetadataViewableLength - 3)];
388 metadataKeyCellText = [metadataKeyCellText stringByAppendingString:@"..."];
390 if ([metadataValueCellText length] > maxMetadataViewableLength) {
391 metadataValueCellText = [metadataValueCellText substringToIndex:(maxMetadataViewableLength - 3)];
392 metadataValueCellText = [metadataValueCellText stringByAppendingString:@"..."];
394 cell.textLabel.text = metadataKeyCellText;
395 cell.detailTextLabel.text = metadataValueCellText;
397 } else if (indexPath.section == policySection) {
398 cell.selectionStyle = UITableViewCellSelectionStyleBlue;
399 if (indexPath.row == 0) {
400 cell.textLabel.text = @"Versioning";
401 cell.detailTextLabel.text = container.versioning;
402 cell.accessoryType = UITableViewCellAccessoryNone;
403 cell.selectionStyle = UITableViewCellSelectionStyleNone;
405 else if (indexPath.row == 1) {
406 cell.textLabel.text = @"Quota";
407 cell.detailTextLabel.text = [NSString stringWithFormat:@"%u", container.quota];
408 cell.accessoryType = UITableViewCellAccessoryNone;
409 cell.selectionStyle = UITableViewCellSelectionStyleNone;
412 cell.textLabel.text = @"Edit policy";
413 cell.detailTextLabel.text = @"";
414 cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
416 } else if (indexPath.section == deleteSection) {
417 return [self tableView:tableView deleteCellForRowAtIndexPath:indexPath];
418 } else if (indexPath.section == kLogRetention) {
419 cell.textLabel.text = @"Log Retention";
420 cell.detailTextLabel.text = @"";
421 cell.accessoryView = logRetentionSwitch;
422 cell.accessoryType = UITableViewCellAccessoryNone;
423 cell.selectionStyle = UITableViewCellSelectionStyleNone;
424 } else if (indexPath.section == kReferrerACL) {
425 cell.textLabel.text = @"Referrer ACL";
426 cell.detailTextLabel.text = container.referrerACL;
427 cell.accessoryView = nil;
428 cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
429 cell.selectionStyle = UITableViewCellSelectionStyleBlue;
430 cell.detailTextLabel.numberOfLines = 1;
431 } else if (indexPath.section == kUserAgentACL) {
432 cell.textLabel.text = @"User Agent ACL";
433 cell.detailTextLabel.text = container.useragentACL;
434 cell.accessoryView = nil;
435 cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
436 cell.selectionStyle = UITableViewCellSelectionStyleBlue;
437 cell.detailTextLabel.numberOfLines = 1;
444 #pragma mark Table view delegate
446 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
448 if (indexPath.section == kMetadata) {
449 EditMetadataViewController *vc = [[EditMetadataViewController alloc] initWithNibName:@"EditMetadataViewController" bundle:nil];
450 NSString *metadataKey;
451 NSString *metadataValue;
453 if (indexPath.row == [self.container.metadata count]) {
456 vc.removeMetadataEnabled = FALSE;
457 vc.navigationItem.title = @"Add Metadata";
460 metadataKey = [[self.container.metadata allKeys] objectAtIndex:indexPath.row];
461 metadataValue = [self.container.metadata objectForKey:metadataKey];
462 vc.removeMetadataEnabled = TRUE;
463 vc.navigationItem.title = @"Edit Metadata";
466 StorageObject *object = [[[StorageObject alloc] init] autorelease];
467 object.name = container.name;
468 object.metadata = container.metadata;
469 object.fullPath = @"";
471 vc.metadataKey = metadataKey;
472 vc.metadataValue = metadataValue;
473 vc.account = account;
474 vc.container = container;
476 vc.objectIsContainer = YES;
478 [self.navigationController pushViewController:vc animated:YES];
480 } else if (indexPath.section == policySection) {
481 if (indexPath.row == 2) {
482 EditPolicyViewController *vc = [[EditPolicyViewController alloc] initWithNibName:@"EditPolicyViewController" bundle:nil];
484 vc.account = account;
485 vc.container = container;
486 vc.containerDetailViewController = self;
488 [self.navigationController pushViewController:vc animated:YES];
491 } else if (indexPath.section == deleteSection) {
492 if (self.container.count == 0 || ([self.container.rootFolder.folders count] + [self.container.rootFolder.objects count] == 0)) {
493 [deleteActionSheet showInView:self.view];
495 } else if (indexPath.section == kCDNAttributes && indexPath.row == 0) {
496 [cdnURLActionSheet showInView:self.view];
497 } else if (indexPath.section == kReferrerACL) {
498 ReferrerACLViewController *vc = [[ReferrerACLViewController alloc] initWithNibName:@"ReferrerACLViewController" bundle:nil];
499 vc.account = self.account;
500 vc.container = self.container;
501 vc.containerDetailViewController = self;
502 if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
503 vc.modalPresentationStyle = UIModalPresentationFormSheet;
504 [self presentModalViewControllerWithNavigation:vc animated:YES];
506 [self.navigationController pushViewController:vc animated:YES];
509 } else if (indexPath.section == kUserAgentACL) {
510 UserAgentACLViewController *vc = [[UserAgentACLViewController alloc] initWithNibName:@"UserAgentACLViewController" bundle:nil];
511 vc.account = self.account;
512 vc.container = self.container;
513 vc.containerDetailViewController = self;
514 if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
515 vc.modalPresentationStyle = UIModalPresentationFormSheet;
516 [self presentModalViewControllerWithNavigation:vc animated:YES];
518 [self.navigationController pushViewController:vc animated:YES];
525 #pragma mark Switches
527 - (void)cdnEnabledSwitchChanged:(id)sender {
529 NSString *activityMessage = @"Disabling CDN Access...";
530 if (!container.cdnEnabled) {
531 activityMessage = @"Enabling CDN Access...";
533 activityIndicatorView = [[ActivityIndicatorView alloc] initWithFrame:[ActivityIndicatorView frameForText:activityMessage] text:activityMessage];
534 [activityIndicatorView addToView:self.view scrollOffset:self.tableView.contentOffset.y];
535 container.cdnEnabled = !container.cdnEnabled;
536 [self.account.manager updateCDNContainer:container];
538 successObserver = [[NSNotificationCenter defaultCenter] addObserverForName:@"updateCDNContainerSucceeded" object:self.container
539 queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification* notification)
541 [activityIndicatorView removeFromSuperviewAndRelease];
543 NSIndexSet *sections = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(3, 4)];
544 NSInteger oldDeleteSection = deleteSection;
545 if (container.cdnEnabled) {
548 [self.tableView reloadSections:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(oldDeleteSection, 1)] withRowAnimation:UITableViewRowAnimationBottom];
550 [self.tableView insertSections:sections withRowAnimation:UITableViewRowAnimationBottom];
554 [self.tableView reloadSections:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(deleteSection, 1)] withRowAnimation:UITableViewRowAnimationTop];
556 [self.tableView deleteSections:sections withRowAnimation:UITableViewRowAnimationTop];
559 [[NSNotificationCenter defaultCenter] removeObserver:successObserver];
562 failureObserver = [[NSNotificationCenter defaultCenter] addObserverForName:@"updateCDNContainerFailed" object:self.container
563 queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification* notification)
565 [activityIndicatorView removeFromSuperviewAndRelease];
566 container.cdnEnabled = !container.cdnEnabled;
567 cdnEnabledSwitch.on = !cdnEnabledSwitch.on;
568 [self alert:@"There was a problem updating this container." request:[notification.userInfo objectForKey:@"request"]];
569 [[NSNotificationCenter defaultCenter] removeObserver:failureObserver];
573 - (void)logRetentionSwitchChanged:(id)sender {
575 NSString *activityMessage = @"Disabling Log Retention...";
576 if (!container.logRetention) {
577 activityMessage = @"Enabling Log Retention...";
579 activityIndicatorView = [[ActivityIndicatorView alloc] initWithFrame:[ActivityIndicatorView frameForText:activityMessage] text:activityMessage];
580 [activityIndicatorView addToView:self.view scrollOffset:self.tableView.contentOffset.y];
582 container.logRetention = !container.logRetention;
583 [self.account.manager updateCDNContainer:container];
585 successObserver = [[NSNotificationCenter defaultCenter] addObserverForName:@"updateCDNContainerSucceeded" object:self.container
586 queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification* notification)
588 [activityIndicatorView removeFromSuperviewAndRelease];
589 [[NSNotificationCenter defaultCenter] removeObserver:successObserver];
592 failureObserver = [[NSNotificationCenter defaultCenter] addObserverForName:@"updateCDNContainerFailed" object:self.container
593 queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification* notification)
595 [activityIndicatorView removeFromSuperviewAndRelease];
596 container.logRetention = !container.logRetention;
597 logRetentionSwitch.on = !logRetentionSwitch.on;
598 [self alert:@"There was a problem updating this container." request:[notification.userInfo objectForKey:@"request"]];
599 [[NSNotificationCenter defaultCenter] removeObserver:failureObserver];
604 #pragma mark Action Sheet
606 - (void)deleteContainerRow {
607 if ([self.account.containers count] == 0) {
608 [self.containersViewController.tableView reloadData];
610 [self.containersViewController.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:selectedContainerIndexPath] withRowAnimation:UITableViewRowAnimationLeft];
612 [self.rootFolderViewController.navigationController popViewControllerAnimated:YES];
615 - (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
616 if ([actionSheet isEqual:cdnURLActionSheet]) {
617 if (buttonIndex == 0) {
618 UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
619 [pasteboard setString:container.cdnURL];
621 [self.tableView deselectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:kCDNAttributes] animated:YES];
622 } else if ([actionSheet isEqual:deleteActionSheet]) {
623 if (buttonIndex == 0) {
625 NSString *activityMessage = @"Deleting container...";
626 activityIndicatorView = [[ActivityIndicatorView alloc] initWithFrame:[ActivityIndicatorView frameForText:activityMessage] text:activityMessage];
627 [activityIndicatorView addToView:self.view scrollOffset:self.tableView.contentOffset.y];
629 [[self.account.manager deleteContainer:self.container] success:^(OpenStackRequest *request) {
631 [activityIndicatorView removeFromSuperviewAndRelease];
632 [self.account.containers removeObjectForKey:self.container.name];
633 [self.account persist];
634 if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
635 [self.containersViewController.navigationController popViewControllerAnimated:YES];
637 [self.navigationController popViewControllerAnimated:YES];
639 [self deleteContainerRow];
642 } failure:^(OpenStackRequest *request) {
644 // 404 Not Found means it's not there, so we can show the user that it's deleted
645 if ([request responseStatusCode] == 404) {
646 [self.account.containers removeObjectForKey:container.name];
647 [self.account persist];
650 [activityIndicatorView removeFromSuperviewAndRelease];
651 [self alert:@"There was a problem deleting this container." request:request];
656 [self.tableView deselectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:deleteSection] animated:YES];
662 #pragma mark Memory management
667 [cdnEnabledSwitch release];
669 [cdnURLActionSheet release];
670 [deleteActionSheet release];
671 [containersViewController release];
672 [selectedContainerIndexPath release];
673 [rootFolderViewController release];