Update version
[pithos-ios] / Classes / AccountGroupsViewController.m
1 //
2 //  AccountGroupsViewController.m
3 //  pithos-ios
4 //
5 // Copyright 2011-2013 GRNET S.A. All rights reserved.
6 //
7 // Redistribution and use in source and binary forms, with or
8 // without modification, are permitted provided that the following
9 // conditions are met:
10 // 
11 //   1. Redistributions of source code must retain the above
12 //      copyright notice, this list of conditions and the following
13 //      disclaimer.
14 // 
15 //   2. Redistributions in binary form must reproduce the above
16 //      copyright notice, this list of conditions and the following
17 //      disclaimer in the documentation and/or other materials
18 //      provided with the distribution.
19 // 
20 // THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
21 // OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
24 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
27 // USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28 // AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 // POSSIBILITY OF SUCH DAMAGE.
32 // 
33 // The views and conclusions contained in the software and
34 // documentation are those of the authors and should not be
35 // interpreted as representing official policies, either expressed
36 // or implied, of GRNET S.A.
37
38 #import "AccountGroupsViewController.h"
39 #import "OpenStackAccount.h"
40 #import "ActivityIndicatorView.h"
41 #import "AccountManager.h"
42 #import "OpenStackRequest.h"
43 #import "EditAccountGroupsViewController.h"
44 #import "UIViewController+Conveniences.h"
45 #import "NSString+Conveniences.h"
46 #import "APICallback.h"
47
48 @implementation AccountGroupsViewController
49
50 @synthesize account, groups, metadata;
51
52 #pragma mark - View lifecycle
53
54 - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
55     return ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) || (toInterfaceOrientation == UIInterfaceOrientationPortrait);
56 }
57
58 - (void)viewWillAppear:(BOOL)animated {
59     [super viewWillAppear:animated];
60     self.navigationItem.title = @"Groups";
61 }
62
63 - (void)viewDidAppear:(BOOL)animated {
64     [super viewDidAppear:animated];
65     __block ActivityIndicatorView *activityIndicatorView = [ActivityIndicatorView activityIndicatorViewWithText:@"Loading groups..."
66                                                                                                    andAddToView:self.view];
67     [[self.account.manager getStorageAccountInfo]
68      success:^(OpenStackRequest *request) {
69          self.groups = [NSMutableDictionary dictionary];
70          self.metadata = [NSMutableDictionary dictionary];
71      
72          for (NSString *headerName in request.responseHeaders) {
73              if ([headerName hasPrefix:@"X-Account-Group-"]) {
74                  [groups setObject:[[NSString decodeFromPercentEscape:[request.responseHeaders objectForKey:headerName]] componentsSeparatedByString:@","]
75                             forKey:[NSString decodeFromPercentEscape:[headerName substringFromIndex:16]]];
76               } else if ([headerName hasPrefix:@"X-Account-Meta-"]) {
77                  [metadata setObject:[NSString decodeFromPercentEscape:[request.responseHeaders objectForKey:headerName]]
78                               forKey:[NSString decodeFromPercentEscape:[headerName substringFromIndex:15]]];
79              }
80          }
81          
82          NSMutableArray *UUIDs = [NSMutableArray array];
83          for (NSString *groupName in groups) {
84              [UUIDs addObjectsFromArray:[groups objectForKey:groupName]];
85          }
86          if (UUIDs.count) {
87              [[self.account.manager userCatalogForDisplaynames:nil UUIDs:UUIDs]
88               success:^(OpenStackRequest *request) {
89                   [activityIndicatorView stopAnimatingAndRemoveFromSuperview];
90                   [self.tableView reloadData];
91               }
92               failure:^(OpenStackRequest *request) {
93                   [activityIndicatorView stopAnimatingAndRemoveFromSuperview];
94                   [self.tableView reloadData];
95                   if (request.responseStatusCode != 404) {
96                       // Don't show alert on 404, since it can be a pre-UUID server.
97                       [self alert:@"Failed to translate group UUIDs." request:request];
98                   }
99               }];
100          } else {
101              [activityIndicatorView stopAnimatingAndRemoveFromSuperview];
102              [self.tableView reloadData];
103          }
104      }
105      failure:^(OpenStackRequest *request) {
106          [activityIndicatorView stopAnimatingAndRemoveFromSuperview];
107          [self alert:@"Failed to get account information." request:request];
108      }];
109 }
110
111 #pragma mark - Internal
112
113 - (NSMutableArray *)groupUsersForGroupName:(NSString *)groupName {
114     NSArray *groupUUIDs = [groups objectForKey:groupName];
115     NSMutableArray *groupUsers = [NSMutableArray arrayWithCapacity:groupUUIDs.count];
116     for (NSString *UUID in groupUUIDs) {
117         [groupUsers addObject:[self.account displaynameForUUID:UUID safe:YES]];
118     }
119     return groupUsers;
120 }
121
122 - (NSMutableString *)groupUsersStringForGroupName:(NSString *)groupName {
123     NSMutableArray *groupUsers = [self groupUsersForGroupName:groupName];
124     NSMutableString *groupUsersString = [NSMutableString string];
125     for (NSUInteger index = 0; index < groupUsers.count; index++) {
126         if (index) {
127             [groupUsersString appendString:@","];
128         }
129         [groupUsersString appendString:[groupUsers objectAtIndex:index]];
130     }
131     return groupUsersString;
132 }
133
134 #pragma mark - Memory management
135
136 - (void)dealloc {
137     [account release];
138     [groups release];
139     [metadata release];
140     [super dealloc];
141 }
142
143 #pragma mark - UITableViewDataSource
144
145 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
146     return (groups.count + 1);
147 }
148
149 - (CGFloat)tableView:(UITableView *)aTableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
150     CGFloat result;
151     if (indexPath.row < groups.count) {
152         NSString *groupName = [[[groups allKeys] sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)] objectAtIndex:indexPath.row];
153         result = 22.0 + [[self groupUsersStringForGroupName:groupName] sizeWithFont:[UIFont systemFontOfSize:18.0]
154                                                                   constrainedToSize:(([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) ?
155                                                                                      CGSizeMake(596.0, 9000.0) :
156                                                                                      CGSizeMake(280.0, 9000.0))
157                                                                       lineBreakMode:UILineBreakModeCharacterWrap].height;
158         return MAX(aTableView.rowHeight, result);
159     }
160     return aTableView.rowHeight;
161 }
162
163
164 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
165     static NSString *CellIdentifier = @"Cell";
166     UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
167     if (cell == nil) {
168         cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease];
169     }
170     
171     cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
172     if (indexPath.row < groups.count) {
173         NSString *groupName = [[[groups allKeys] sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)] objectAtIndex:indexPath.row];
174         cell.textLabel.text = groupName;
175         cell.detailTextLabel.text = [self groupUsersStringForGroupName:groupName];
176         cell.detailTextLabel.numberOfLines = 0;
177         cell.detailTextLabel.lineBreakMode = UILineBreakModeCharacterWrap;
178     } else {
179         cell.textLabel.text = @"Add Group";
180         cell.detailTextLabel.text = @"";
181     }
182     
183     return cell;
184 }
185
186
187 #pragma mark - UITableViewDelegate
188
189 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
190     EditAccountGroupsViewController *vc = [[EditAccountGroupsViewController alloc] initWithNibName:@"EditAccountGroupsViewController" bundle:nil];
191     vc.account = self.account;
192     vc.metadata = metadata;
193     vc.groups = groups;
194     if (indexPath.row < groups.count) {
195         NSString *groupName = [[[groups allKeys] sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)] objectAtIndex:indexPath.row];
196         vc.removeGroupEnabled = YES;
197         vc.groupName = groupName;
198         vc.navigationItem.title = @"Edit Group";
199     } else {
200         vc.removeGroupEnabled = NO;
201         vc.groupName = @"";
202         vc.navigationItem.title = @"Add Group";
203     }
204     
205     [self.navigationController pushViewController:vc animated:YES];
206     [vc release];
207 }
208
209 @end