Change UI labels. Fix UI bugs. Update version.
[pithos-ios] / Classes / FolderDetailViewController.m
1 //
2 //  FolderDetailViewController.m
3 //  pithos-ios
4 //
5 // Copyright 2011 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 "FolderDetailViewController.h"
39 #import "EditMetadataViewController.h"
40 #import "EditPermissionsViewController.h"
41 #import "StorageObject.h"
42 #import "APICallback.h"
43 #import "AccountManager.h"
44 #import "UIViewController+Conveniences.h"
45 #import "NSString+Conveniences.h"
46
47 #define kOverview 0
48 #define kMetadata 1
49 #define kPermissions 2
50
51 #define maxMetadataViewableLength 12
52
53
54 @implementation FolderDetailViewController
55
56 @synthesize account, container, folder, folderViewController;
57
58 #pragma mark - 
59 #pragma mark Memory management
60
61 - (void)dealloc
62 {
63     [object release];
64     [account release];
65     [container release];
66     [folderViewController release];
67     [folder release];
68     [permissions release];
69     [super dealloc];
70 }
71
72 - (void)didReceiveMemoryWarning
73 {
74     // Releases the view if it doesn't have a superview.
75     [super didReceiveMemoryWarning];
76     
77     // Release any cached data, images, etc that aren't in use.
78 }
79
80 #pragma mark - View lifecycle
81
82 - (void)viewDidLoad
83 {
84     [super viewDidLoad];
85     permissions = [[NSMutableDictionary alloc] init];
86     if (folder.sharing.length > 0) {
87         NSArray *sharingArray = [folder.sharing componentsSeparatedByString:@";"];
88         for (NSString *typeSpecificPermissions in sharingArray) { 
89             NSArray *array=[typeSpecificPermissions componentsSeparatedByString:@"="];
90             NSString *permissionsType = [array objectAtIndex:0];
91             if ([permissionsType hasPrefix:@" "])
92                 permissionsType = [permissionsType substringFromIndex:1];
93             
94             NSArray *users = [[array objectAtIndex:1] componentsSeparatedByString:@","];
95             for (NSString *user in users) {
96                 [permissions setObject:permissionsType forKey:user];
97             }
98         }
99     }
100     
101     folderIsReadOnly = NO;
102     if (account.sharingAccount) { 
103         if ([permissions count] > 0) {
104             folderIsReadOnly = [[permissions objectForKey:[account username]] isEqualToString:@"read"];
105         }
106     }
107     
108     object = [[StorageObject alloc] init];
109     object.name = folder.name;
110     object.metadata = folder.metadata;
111     object.fullPath = [folder fullPath];
112     object.sharing = folder.sharing;
113     object.contentType = folder.contentType;
114 }
115
116 - (void)viewDidUnload
117 {
118     [super viewDidUnload];
119 }
120
121 - (void)viewWillAppear:(BOOL)animated
122 {
123     [super viewWillAppear:animated];
124     [self.tableView reloadData];
125 }
126
127 - (void)viewDidAppear:(BOOL)animated
128 {
129     [super viewDidAppear:animated];
130     if (folder.metadata == nil) {
131         [self reloadMetadataSection];
132     }
133 }
134
135 - (void)viewWillDisappear:(BOOL)animated
136 {
137     [super viewWillDisappear:animated];
138     folder.sharing = object.sharing;
139 }
140
141 - (void)viewDidDisappear:(BOOL)animated
142 {
143     [super viewDidDisappear:animated];
144 }
145
146 - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
147     return (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) || (toInterfaceOrientation == UIInterfaceOrientationPortrait);
148 }
149
150 #pragma mark - Table view data source
151
152 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
153 {
154     return 3;
155 }
156
157 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
158 {
159     if (section == kOverview)
160         return 2;
161     else if (section == kPermissions) {
162         if (account.sharingAccount)
163             return [permissions count];
164         else
165             return 1 + [permissions count];
166     }
167     else if (section == kMetadata)
168         if (folderIsReadOnly)
169             return [folder.metadata count];
170         else
171             return 1 + [folder.metadata count];     
172         return 0;
173 }
174
175 - (CGFloat)findLabelHeight:(NSString*)text font:(UIFont *)font {
176     CGSize textLabelSize;    
177     if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
178         textLabelSize = CGSizeMake(537.0, 9000.0f);
179     } else {
180         textLabelSize = CGSizeMake(221.0, 9000.0f);
181     }
182
183     CGSize stringSize = [text sizeWithFont:font constrainedToSize:textLabelSize lineBreakMode:UILineBreakModeCharacterWrap];
184     return stringSize.height;
185 }
186
187 - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
188     CGFloat result;
189     
190     if (indexPath.section == kOverview) {
191         if (indexPath.row == 0) {
192             result = 22 + [self findLabelHeight:folder.name font:[UIFont systemFontOfSize:18.0]];
193             
194             return MAX(tableView.rowHeight, result);
195         } else if (indexPath.row == 1) {
196             NSString *folderFullPathToShow = folder.fullPath;
197             if ([folderFullPathToShow hasPrefix:@"/"]) {
198                 folderFullPathToShow = [folderFullPathToShow substringFromIndex:1];
199             }
200             result = 22 + [self findLabelHeight:folderFullPathToShow font:[UIFont systemFontOfSize:18.0]];
201         
202             return MAX(tableView.rowHeight, result);
203         }
204     }
205     
206     return tableView.rowHeight;
207 }
208
209
210 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
211 {
212     static NSString *CellIdentifier = @"Cell";
213     
214     UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
215     if (cell == nil) {
216         cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease];
217
218         cell.textLabel.backgroundColor = [UIColor clearColor];
219         cell.detailTextLabel.backgroundColor = [UIColor clearColor];
220         cell.detailTextLabel.numberOfLines = 0;
221         cell.detailTextLabel.lineBreakMode = UILineBreakModeWordWrap;
222         cell.detailTextLabel.textAlignment = UITextAlignmentRight;
223     }
224     
225     if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
226         cell.backgroundColor = [UIColor colorWithRed:1 green:1 blue:1 alpha:0.8];
227     }
228     
229     if (indexPath.section == kOverview) {
230         cell.accessoryType = UITableViewCellAccessoryNone;
231         cell.selectionStyle = UITableViewCellSelectionStyleNone;
232         cell.accessoryView = nil;
233         if (indexPath.row == 0) {
234             cell.textLabel.text = @"Name";
235             cell.detailTextLabel.text = folder.name;
236         } else if (indexPath.row == 1) {
237             cell.textLabel.text = @"Full Path";
238             NSString *folderFullPathToShow = folder.fullPath;
239             if ([folderFullPathToShow hasPrefix:@"/"]) {
240                 folderFullPathToShow = [folderFullPathToShow substringFromIndex:1];
241             }
242             cell.detailTextLabel.text = folderFullPathToShow;
243         }
244     } else if (indexPath.section == kMetadata) {
245         if (folderIsReadOnly) {
246             cell.accessoryType = UITableViewCellAccessoryNone;
247             cell.selectionStyle = UITableViewCellSelectionStyleNone;
248             cell.userInteractionEnabled = NO;
249         }
250         else {
251             cell.selectionStyle = UITableViewCellSelectionStyleBlue;
252             cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
253         }
254         cell.accessoryView = nil;
255         if (indexPath.row == [folder.metadata count]) {
256             cell.textLabel.text = @"Add Metadata";
257             cell.detailTextLabel.text = @"";
258         } else {
259             NSString *key = [[folder.metadata allKeys] objectAtIndex:indexPath.row];
260             NSString *value = [folder.metadata objectForKey:key];
261             NSString *metadataKeyCellText = key;
262             NSString *metadataValueCellText = value;
263             if ([metadataKeyCellText length] > maxMetadataViewableLength) {
264                 metadataKeyCellText = [metadataKeyCellText substringToIndex:(maxMetadataViewableLength - 3)];
265                 metadataKeyCellText = [metadataKeyCellText stringByAppendingString:@"..."];
266             }
267             if ([metadataValueCellText length] > maxMetadataViewableLength) {
268                 metadataValueCellText = [metadataValueCellText substringToIndex:(maxMetadataViewableLength - 3)];
269                 metadataValueCellText = [metadataValueCellText stringByAppendingString:@"..."];
270             }
271
272             cell.textLabel.text = metadataKeyCellText;
273             cell.detailTextLabel.text = metadataValueCellText;
274         }
275     } else if (indexPath.section == kPermissions) {
276         if (account.sharingAccount) {
277             cell.accessoryType = UITableViewCellAccessoryNone;
278             cell.selectionStyle = UITableViewCellSelectionStyleNone;
279             cell.userInteractionEnabled = NO;
280         }
281         else {
282             cell.selectionStyle = UITableViewCellSelectionStyleBlue;
283             cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
284         }
285         cell.accessoryView = nil;
286         
287         if (indexPath.row == [permissions count]) {
288             cell.textLabel.text = @"Share";
289             cell.detailTextLabel.text = @""; 
290         }
291         else {
292             NSString *user = [[permissions allKeys] objectAtIndex:indexPath.row];
293             cell.textLabel.text = user;
294             cell.detailTextLabel.text = [permissions objectForKey:user];
295         }
296     }
297
298     return cell;
299 }
300
301
302 #pragma mark - Table view delegate
303
304 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
305 {
306     if (indexPath.section == kMetadata) {
307         EditMetadataViewController *vc = [[EditMetadataViewController alloc] initWithNibName:@"EditMetadataViewController" bundle:nil];
308         NSString *metadataKey;
309         NSString *metadataValue;
310         
311         if (indexPath.row == [self.folder.metadata count]) {
312             metadataKey = @"";
313             metadataValue = @"";
314             vc.removeMetadataEnabled = FALSE;
315             vc.navigationItem.title = @"Add Metadata";
316         }
317         else {
318             metadataKey = [[self.folder.metadata allKeys] objectAtIndex:indexPath.row];
319             metadataValue = [self.folder.metadata objectForKey:metadataKey];
320             vc.removeMetadataEnabled = TRUE;
321             vc.navigationItem.title = @"Edit Metadata";
322         }
323                 
324         vc.metadataKey = metadataKey;
325         vc.metadataValue = metadataValue;
326         vc.account = account;
327         vc.container = container;
328         vc.object = object;
329         vc.objectIsFolder = YES;
330         vc.folderViewController = folderViewController;
331
332         [self.navigationController pushViewController:vc animated:YES];
333         [vc release];
334     } else if (indexPath.section == kPermissions) {
335         EditPermissionsViewController *vc = [[EditPermissionsViewController alloc] initWithNibName:@"EditPermissionsViewController" bundle:nil];
336         NSString *user;
337         
338         if (indexPath.row == [permissions count]) {
339             user = @"";
340             vc.removePermissionsEnabled = NO;
341             vc.navigationItem.title = @"Share";
342         }
343         else {
344             user = [[permissions allKeys] objectAtIndex:indexPath.row];
345             NSString *userPermissions = [permissions objectForKey:user];
346             if ([userPermissions rangeOfString:@"read"].location != NSNotFound)
347                 vc.readPermissionSelected = YES;
348             else
349                 vc.readPermissionSelected = NO;
350             
351             if ([userPermissions rangeOfString:@"write"].location != NSNotFound)
352                 vc.writePermissionSelected = YES;
353             else
354                 vc.writePermissionSelected = NO;
355             
356             vc.removePermissionsEnabled = YES;
357             vc.navigationItem.title = @"Edit Sharing";
358         }
359         
360         vc.user = user;
361         vc.permissions = permissions;
362         vc.account = account;
363         vc.container = container;
364         vc.object = object;
365         vc.objectIsFolder = YES;
366         vc.folderViewController = folderViewController;
367         [self.navigationController pushViewController:vc animated:YES];
368         [vc release];
369     } 
370 }
371
372 #pragma mark - 
373 #pragma mark Helper functions
374
375 - (void)reloadMetadataSection {
376     NSString *activityMessage = @"Loading metadata...";
377     ActivityIndicatorView *activityIndicatorView = [[ActivityIndicatorView alloc] initWithFrame:[ActivityIndicatorView frameForText:activityMessage] text:activityMessage];
378     [activityIndicatorView addToView:self.view];         
379     [[self.account.manager getObjectInfo:container object:object version:nil] 
380      success:^(OpenStackRequest *request) {
381          [activityIndicatorView removeFromSuperviewAndRelease];
382          folder.metadata = [NSMutableDictionary dictionary];
383          for (NSString *header in request.responseHeaders) {
384              NSString *metadataKey;
385              NSString *metadataValue;
386              if ([header rangeOfString:@"X-Object-Meta-"].location != NSNotFound) {
387                  metadataKey = [NSString decodeFromPercentEscape:[header substringFromIndex:14]];
388                  metadataValue = [NSString decodeFromPercentEscape:[request.responseHeaders objectForKey:header]];
389                  [folder.metadata setObject:metadataValue forKey:metadataKey];
390              }
391          }   
392          object.metadata = folder.metadata;
393          NSIndexSet *metadataSections = [NSIndexSet indexSetWithIndex:kMetadata];
394          [self.tableView reloadSections:metadataSections withRowAnimation:UITableViewRowAnimationFade];
395      }
396      failure:^(OpenStackRequest *request) {
397          [activityIndicatorView removeFromSuperviewAndRelease];
398          [self alert:@"There was a problem retrieving the object's metadata." request:request]; 
399      }];
400 }
401
402 @end