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 "NSObject+Conveniences.h"
10 #import "ContainersViewController.h"
11 #import "OpenStackAccount.h"
13 #import "AddContainerViewController.h"
14 #import "UIViewController+Conveniences.h"
15 #import "FolderViewController.h"
16 #import "ContainerDetailViewController.h"
17 #import "AccountManager.h"
18 #import "OpenStackAppDelegate.h"
19 #import "RootViewController.h"
20 #import "APICallback.h"
22 #import "AccountHomeViewController.h"
25 @implementation ContainersViewController
27 @synthesize tableView, account, accountUsageInfo, accountHomeViewController, containerDetailViewController;
29 - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
30 return (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) || (toInterfaceOrientation == UIInterfaceOrientationPortrait);
34 #pragma mark View lifecycle
38 self.navigationItem.title = @"Containers";
42 if (!account.shared && !account.sharingAccount && containersLoaded) {
43 if (![self.account.containers objectForKey:@"pithos"])
44 [self createContainerWithName:@"pithos"];
45 if (![self.account.containers objectForKey:@"trash"])
46 [self createContainerWithName:@"trash"];
51 - (void)viewWillAppear:(BOOL)animated {
52 [super viewWillAppear:animated];
54 if ([self.account.containers count] == 0) {
55 self.tableView.allowsSelection = NO;
56 self.tableView.scrollEnabled = NO;
57 [self.tableView reloadData];
59 if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
60 if ([self.account.containers count] == 0 ) {
61 NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
62 [self.tableView selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
63 [self tableView:self.tableView didSelectRowAtIndexPath:indexPath];
64 } else if ([self.tableView indexPathForSelectedRow].row == 0 && [self.tableView indexPathForSelectedRow].section == 0) {
65 ContainerDetailViewController *vc = [[ContainerDetailViewController alloc] initWithNibName:@"ContainerDetailViewController" bundle:nil];
66 [self presentPrimaryViewController:vc];
71 if (!containersLoaded && [self.account.containers count] == 0) {
72 [self refreshButtonPressed:nil];
76 - (void)viewDidDisappear:(BOOL)animated {
77 [super viewDidDisappear:animated];
81 #pragma mark Button Handlers
83 - (void)addButtonPressed:(id)sender {
84 AddContainerViewController *vc = [[AddContainerViewController alloc] initWithNibName:@"AddContainerViewController" bundle:nil];
85 vc.containersViewController = self;
87 if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
88 vc.modalPresentationStyle = UIModalPresentationFormSheet;
89 OpenStackAppDelegate *app = [[UIApplication sharedApplication] delegate];
90 if (app.rootViewController.popoverController != nil) {
91 [app.rootViewController.popoverController dismissPopoverAnimated:YES];
94 [self presentModalViewControllerWithNavigation:vc];
98 - (IBAction)homeButtonPressed:(id)sender {
99 [self.navigationController popToViewController:accountHomeViewController animated:YES];
103 - (void)enableRefreshButton {
104 refreshButton.enabled = YES;
105 [self hideToolbarActivityMessage];
106 if (!account.sharingAccount)
107 [self showToolbarInfoMessage:accountUsageInfo];
110 - (void)refreshButtonPressed:(id)sender {
111 refreshButton.enabled = NO;
112 //BOOL hadZeroContainers = [self.account.containers count] == 0;
113 if (!account.sharingAccount)
114 [self hideToolbarInfoMessage];
115 [self showToolbarActivityMessage:@"Refreshing containers..."];
117 [[self.account.manager getContainers] success:^(OpenStackRequest *request) {
118 self.account.containers = [request containers];
119 self.account.containerCount = [self.account.containers count];
120 self.account.totalBytesUsed = [[request.responseHeaders objectForKey:@"X-Account-Bytes-Used"] longLongValue];
121 self.account.quota = [[request.responseHeaders objectForKey:@"X-Account-Policy-Quota"] longLongValue];
122 self.accountUsageInfo = [NSString stringWithFormat:@"%@ used, %@ available",
123 [NSObject osxStyleHumanizedBytes:self.account.totalBytesUsed],
124 [NSObject osxStyleHumanizedBytes:self.account.quota]];
126 [self.account persist];
127 containersLoaded = YES;
128 [self enableRefreshButton];
129 [self.tableView reloadData];
130 //GetCDNContainersRequest *cdnRequest = [GetCDNContainersRequest request:self.account];
131 //[cdnRequest startAsynchronous];
133 } failure:^(OpenStackRequest *request) {
134 containersLoaded = NO;
135 [self enableRefreshButton];
136 if (request.responseStatusCode != 0) {
137 [self alert:@"There was a problem loading your containers." request:request];
143 #pragma mark Table view data source
145 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
149 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
150 if ([self.account.containers count] == 0) {
151 self.tableView.allowsSelection = NO;
152 self.tableView.scrollEnabled = NO;
154 self.tableView.allowsSelection = YES;
155 self.tableView.scrollEnabled = YES;
157 if (!containersLoaded && [self.account.containers count] == 0) {
160 return MAX(1, [account.containers count]);
164 - (CGFloat)tableView:(UITableView *)aTableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
165 if ([account.containers count] == 0) {
166 return aTableView.frame.size.height;
168 return aTableView.rowHeight;
171 - (UITableViewCell *)tableView:(UITableView *)aTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
172 if (containersLoaded && [self.account.containers count] == 0) {
173 NSString *noContainersTitle = self.account.shared ? @"No shared containers" : @"No containers";
174 NSString *noContainersSubtitle = self.account.shared ? @"" : @"Tap the + button to create a new container";
175 self.navigationItem.rightBarButtonItem.enabled = !self.account.shared;
177 return [self tableView:tableView emptyCellWithImage:
178 [UIImage imageNamed:@"empty-containers.png"]
179 title:noContainersTitle
180 subtitle:noContainersSubtitle];
182 static NSString *CellIdentifier = @"Cell";
184 UITableViewCell *cell = [aTableView dequeueReusableCellWithIdentifier:CellIdentifier];
186 cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
187 if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
188 cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
190 cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
193 Container *container = [self.account.pithosSortedContainers objectAtIndex:indexPath.row];
194 cell.textLabel.text = container.name;
195 if ([container.name isEqualToString:@"pithos"])
196 cell.imageView.image = [UIImage imageNamed:@"PithosContainerIcon.png"];
197 else if ([container.name isEqualToString:@"trash"])
198 cell.imageView.image = [UIImage imageNamed:@"TrashIcon.png"];
200 cell.imageView.image = [UIImage imageNamed:@"ContainerIcon.png"];
202 if (!self.account.sharingAccount)
203 cell.detailTextLabel.text = [container osxStyleHumanizedSize];
210 #pragma mark Table view delegate
212 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
213 Container *container = nil;
214 if ([account.containers count] > 0) {
215 container = [self.account.pithosSortedContainers objectAtIndex:indexPath.row];
217 FolderViewController *vc = [[FolderViewController alloc] initWithNibName:@"FolderViewController" bundle:nil];
218 vc.account = self.account;
219 vc.container = container;
220 vc.folder = container.rootFolder;
221 vc.containersViewController = self;
222 vc.selectedContainerIndexPath = indexPath;
223 [self.navigationController pushViewController:vc animated:YES];
225 [self.tableView deselectRowAtIndexPath:indexPath animated:YES];
228 if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
229 ContainerDetailViewController *vc = [[ContainerDetailViewController alloc] initWithNibName:@"ContainerDetailViewController" bundle:nil];
230 vc.account = self.account;
231 vc.container = container;
232 vc.containersViewController = self;
233 vc.selectedContainerIndexPath = indexPath;
234 [self presentPrimaryViewController:vc];
235 self.containerDetailViewController = vc;
240 - (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath {
241 Container *container = nil;
242 if ([account.containers count] > 0) {
243 container = [self.account.pithosSortedContainers objectAtIndex:indexPath.row];
245 ContainerDetailViewController *vc = [[ContainerDetailViewController alloc] initWithNibName:@"ContainerDetailViewController" bundle:nil];
246 vc.account = self.account;
247 vc.container = container;
248 vc.containersViewController = self;
249 vc.selectedContainerIndexPath = indexPath;
250 [self.navigationController pushViewController:vc animated:YES];
255 #pragma mark Helper methods
257 - (NSString *)humanReadableSize:(unsigned long long)bytes {
258 NSString *sizeUnit = @"bytes";
260 double sizeInBytes = bytes;
261 if (bytes > 1023 && bytes < 1048576) {
262 sizeInBytes = bytes / 1024.0;
265 else if (bytes > 1048575 && bytes < 1073741824) {
266 sizeInBytes = bytes / 1048576.0;
269 else if (bytes > 1073741823) {
270 sizeInBytes = bytes / 1073741824.0;
274 NSString *humanReadableString = [NSString stringWithFormat:@"%.1f %@", sizeInBytes, sizeUnit];
275 humanReadableString = [humanReadableString stringByReplacingOccurrencesOfString:@".0" withString:@""];
277 return humanReadableString;
280 - (void)createContainerWithName:(NSString *)containerName {
281 [self hideToolbarInfoMessage];
282 [self showToolbarActivityMessage:@"Creating container..."];
283 Container *container = [[Container alloc] init];
284 container.name = containerName;
285 [[self.account.manager createContainer:container]
286 success:^(OpenStackRequest *request) {
287 [self hideToolbarActivityMessage];
288 if (!account.sharingAccount)
289 [self showToolbarInfoMessage:accountUsageInfo];
290 [self.tableView reloadData];
292 failure:^(OpenStackRequest *request) {
293 [self hideToolbarActivityMessage];
294 if (!account.sharingAccount)
295 [self showToolbarInfoMessage:accountUsageInfo];
296 [self alert:@"There was a problem creating your container." request:request];
303 #pragma mark Memory management
306 [accountUsageInfo release];
309 [containerDetailViewController release];