2 // ContainersViewController.m
5 // Created by Mike Mayo on 12/7/10.
6 // The OpenStack project is provided under the Apache 2.0 license.
9 #import "ContainersViewController.h"
10 #import "OpenStackAccount.h"
12 #import "AddContainerViewController.h"
13 #import "UIViewController+Conveniences.h"
14 #import "FolderViewController.h"
15 #import "ContainerDetailViewController.h"
16 #import "AccountManager.h"
17 #import "OpenStackAppDelegate.h"
18 #import "RootViewController.h"
19 #import "APICallback.h"
20 #import "GetCDNContainersRequest.h"
23 @implementation ContainersViewController
25 @synthesize tableView, account;
27 - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
28 return (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) || (toInterfaceOrientation == UIInterfaceOrientationPortrait);
32 #pragma mark View lifecycle
36 self.navigationItem.title = @"Containers";
40 - (void)viewWillAppear:(BOOL)animated {
41 [super viewWillAppear:animated];
43 successObserver = [[NSNotificationCenter defaultCenter] addObserverForName:@"createContainerSucceeded" object:self.account
44 queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notification)
46 [self hideToolbarActivityMessage];
47 [self.tableView reloadData];
50 failureObserver = [[NSNotificationCenter defaultCenter] addObserverForName:@"createContainerFailed" object:self.account
51 queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notification)
53 [self hideToolbarActivityMessage];
54 [self alert:@"There was a problem creating your container." request:[notification.userInfo objectForKey:@"request"]];
57 if ([self.account.containers count] == 0) {
58 self.tableView.allowsSelection = NO;
59 self.tableView.scrollEnabled = NO;
60 [self.tableView reloadData];
63 if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad && [self.account.containers count] == 0) {
64 NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
65 [self.tableView selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
66 [self tableView:self.tableView didSelectRowAtIndexPath:indexPath];
69 if (!containersLoaded && [self.account.containers count] == 0) {
70 [self refreshButtonPressed:nil];
75 - (void)viewDidDisappear:(BOOL)animated {
76 [super viewDidDisappear:animated];
77 [[NSNotificationCenter defaultCenter] removeObserver:successObserver];
78 [[NSNotificationCenter defaultCenter] removeObserver:failureObserver];
82 #pragma mark Button Handlers
84 - (void)addButtonPressed:(id)sender {
85 AddContainerViewController *vc = [[AddContainerViewController alloc] initWithNibName:@"AddContainerViewController" bundle:nil];
86 vc.containersViewController = self;
88 if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
89 vc.modalPresentationStyle = UIModalPresentationFormSheet;
90 OpenStackAppDelegate *app = [[UIApplication sharedApplication] delegate];
91 if (app.rootViewController.popoverController != nil) {
92 [app.rootViewController.popoverController dismissPopoverAnimated:YES];
95 [self presentModalViewControllerWithNavigation:vc];
99 - (void)enableRefreshButton {
100 containersLoaded = YES;
101 refreshButton.enabled = YES;
102 [self hideToolbarActivityMessage];
103 [self showToolbarInfoMessage:accountUsageInfo];
106 - (void)refreshButtonPressed:(id)sender {
108 refreshButton.enabled = NO;
110 //BOOL hadZeroContainers = [self.account.containers count] == 0;
112 [self hideToolbarInfoMessage];
113 [self showToolbarActivityMessage:@"Refreshing containers..."];
115 [[self.account.manager getContainersWithCallback] success:^(OpenStackRequest *request) {
116 self.account.containers = [request containers];
117 self.account.containerCount = [self.account.containers count];
118 self.account.totalBytesUsed = [[request.responseHeaders objectForKey:@"X-Account-Bytes-Used"] longLongValue];
119 self.account.quota = [[request.responseHeaders objectForKey:@"X-Account-Policy-Quota"] longLongValue];
120 accountUsageInfo = [NSString stringWithFormat:@"%@ used, %@ available",
121 [self humanReadableSize:self.account.totalBytesUsed], [self humanReadableSize:self.account.quota]];
123 [self.account persist];
124 [self enableRefreshButton];
125 [self.tableView reloadData];
127 //GetCDNContainersRequest *cdnRequest = [GetCDNContainersRequest request:self.account];
128 //[cdnRequest startAsynchronous];
130 } failure:^(OpenStackRequest *request) {
131 [self enableRefreshButton];
132 if (request.responseStatusCode != 0) {
133 [self alert:@"There was a problem loading your containers." request:request];
139 #pragma mark Table view data source
141 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
145 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
146 if ([self.account.containers count] == 0) {
147 self.tableView.allowsSelection = NO;
148 self.tableView.scrollEnabled = NO;
150 self.tableView.allowsSelection = YES;
151 self.tableView.scrollEnabled = YES;
153 if (!containersLoaded && [self.account.containers count] == 0) {
156 return MAX(1, [account.containers count]);
160 - (CGFloat)tableView:(UITableView *)aTableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
161 if ([account.containers count] == 0) {
162 return aTableView.frame.size.height;
164 return aTableView.rowHeight;
167 - (UITableViewCell *)tableView:(UITableView *)aTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
168 if (containersLoaded && [self.account.containers count] == 0) {
169 return [self tableView:tableView emptyCellWithImage:[UIImage imageNamed:@"empty-containers.png"] title:@"No Containers" subtitle:@"Tap the + button to create a new container"];
171 static NSString *CellIdentifier = @"Cell";
173 UITableViewCell *cell = [aTableView dequeueReusableCellWithIdentifier:CellIdentifier];
175 cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
176 if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
177 cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
179 cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
181 cell.imageView.image = [UIImage imageNamed:@"folder-icon.png"];
184 Container *container = [self.account.sortedContainers objectAtIndex:indexPath.row];
185 cell.textLabel.text = container.name;
186 cell.detailTextLabel.text = [container humanizedSize];
193 #pragma mark Table view delegate
195 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
196 Container *container = nil;
197 if ([account.containers count] > 0) {
198 container = [self.account.sortedContainers objectAtIndex:indexPath.row];
200 FolderViewController *vc = [[FolderViewController alloc] initWithNibName:@"FolderViewController" bundle:nil];
201 vc.account = self.account;
202 vc.container = container;
203 vc.folder = container.rootFolder;
204 vc.containersViewController = self;
205 vc.selectedContainerIndexPath = indexPath;
206 [self.navigationController pushViewController:vc animated:YES];
208 [self.tableView deselectRowAtIndexPath:indexPath animated:YES];
211 if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
212 ContainerDetailViewController *vc = [[ContainerDetailViewController alloc] initWithNibName:@"ContainerDetailViewController" bundle:nil];
213 vc.account = self.account;
214 vc.container = container;
215 vc.containersViewController = self;
216 vc.selectedContainerIndexPath = indexPath;
217 [self presentPrimaryViewController:vc];
222 - (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath {
223 Container *container = nil;
224 if ([account.containers count] > 0) {
225 container = [self.account.sortedContainers objectAtIndex:indexPath.row];
227 ContainerDetailViewController *vc = [[ContainerDetailViewController alloc] initWithNibName:@"ContainerDetailViewController" bundle:nil];
228 vc.account = self.account;
229 vc.container = container;
230 vc.containersViewController = self;
231 vc.selectedContainerIndexPath = indexPath;
232 [self.navigationController pushViewController:vc animated:YES];
237 #pragma mark Helper methods
239 - (NSString *)humanReadableSize:(unsigned long long)bytes {
240 NSString *sizeUnit = @"bytes";
242 double sizeInBytes = bytes;
243 if (bytes > 1023 && bytes < 1048576) {
244 sizeInBytes = bytes / 1024.0;
247 else if (bytes > 1048575 && bytes < 1073741824) {
248 sizeInBytes = bytes / 1048576.0;
251 else if (bytes > 1073741823) {
252 sizeInBytes = bytes / 1073741824.0;
256 NSString *humanReadableString = [NSString stringWithFormat:@"%.1f %@", sizeInBytes, sizeUnit];
257 humanReadableString = [humanReadableString stringByReplacingOccurrencesOfString:@".0" withString:@""];
259 return humanReadableString;
264 #pragma mark Memory management