Expanded open file functionality to use available apps.
[pithos-ios] / Classes / AddPhotoViewController.m
1 //
2 //  AddPhotoViewController.m
3 //  OpenStack
4 //
5 //  Created by Mike Mayo on 1/5/11.
6 //  Copyright 2011 __MyCompanyName__. All rights reserved.
7 //
8
9 #import "AddPhotoViewController.h"
10 #import "UIViewController+Conveniences.h"
11 #import "UIColor+MoreColors.h"
12 #import "Container.h"
13 #import "ActivityIndicatorView.h"
14 #import "StorageObject.h"
15 #import "OpenStackAccount.h"
16 #import "AccountManager.h"
17 #import "Container.h"
18 #import "Folder.h"
19 #import "FolderViewController.h"
20 #import "NSObject+Conveniences.h"
21
22 #define kName 0
23
24 // give me the option to add a description of the file and the URL - date/time stamped
25
26 @implementation AddPhotoViewController
27
28 @synthesize image, account, container, folder, folderViewController, isFromCamera;
29
30 - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
31     return (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) || (toInterfaceOrientation == UIInterfaceOrientationPortrait);
32 }
33
34 #pragma mark -
35 #pragma mark View lifecycle
36
37 - (void)viewDidLoad {
38     [super viewDidLoad];
39     self.navigationItem.title = @"Add Photo";
40     [self addSaveButton];
41     format = @".jpg";
42     
43     if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
44         nameTextField = [[UITextField alloc] initWithFrame:CGRectMake(98.0, 13.0, 400.0, 24.0)];
45     } else {
46         nameTextField = [[UITextField alloc] initWithFrame:CGRectMake(79.0, 13.0, 222.0, 24.0)];
47     }    
48     nameTextField.delegate = self;
49     nameTextField.font = [UIFont systemFontOfSize:17.0];
50     nameTextField.textColor = [UIColor value1DetailTextLabelColor];
51     nameTextField.backgroundColor = [UIColor clearColor];
52     nameTextField.textAlignment = UITextAlignmentRight;
53     nameTextField.returnKeyType = UIReturnKeyDone;
54     nameTextField.autocorrectionType = UITextAutocorrectionTypeNo;
55     nameTextField.autocapitalizationType = UITextAutocapitalizationTypeNone;    
56     nameTextField.placeholder = [NSString stringWithFormat:@"ios_upload_%.0f", [[NSDate date] timeIntervalSince1970]];    
57     
58     if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
59         formatLabel = [[UILabel alloc] initWithFrame:CGRectMake(41.0, 15.5, 458.0, 18.0)];
60     } else {
61         formatLabel = [[UILabel alloc] initWithFrame:CGRectMake(21.0, 15.5, 280.0, 18.0)];
62     }    
63     formatLabel.font = [UIFont systemFontOfSize:17.0];
64     formatLabel.textColor = [UIColor value1DetailTextLabelColor];
65     formatLabel.backgroundColor = [UIColor clearColor];
66     formatLabel.textAlignment = UITextAlignmentRight;
67     formatLabel.text = format;
68     
69     slider = [[UISlider alloc] init];
70     slider.value = 0.65;
71     
72     // move the text field to make room for the numbers label
73     CGSize size = [formatLabel.text sizeWithFont:formatLabel.font constrainedToSize:CGSizeMake(280.0, 900.0f)];
74     if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
75         nameTextField.frame = CGRectMake(98.0, 13.0, 400.0 - size.width, 24.0);
76     } else {
77         nameTextField.frame = CGRectMake(79.0, 13.0, 222.0 - size.width, 24.0);
78     }    
79     
80 }
81
82 - (void)viewWillAppear:(BOOL)animated {
83     [super viewWillAppear:animated];
84 //    data = UIImageJPEGRepresentation(image, slider.value);
85 //    [data retain];
86     
87     // when saving a camera image as a PNG, it ends up rotated.  i have no idea why and have
88     // not been able to successfully rotate the image, so we're only allowing JPEG from the
89     // camera for now.  not a big deal, since the iPhone 4 camera is making 8 MB PNG files
90     if (isFromCamera) {
91         formatSection = -1;
92         qualitySection = 1;
93     } else {
94         formatSection = 1;
95         qualitySection = 2;
96     }
97 }
98
99 - (void)viewDidAppear:(BOOL)animated {
100     [super viewDidAppear:animated];
101     
102     qualityActivityIndicatorView = [[ActivityIndicatorView alloc] initWithFrame:[ActivityIndicatorView frameForText:@"Calculating size..."] text:@"Calculating size..."];
103     [qualityActivityIndicatorView addToView:self.view];    
104     [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(calculateSize) userInfo:nil repeats:NO];
105 }
106
107 #pragma mark -
108 #pragma mark Table view data source
109
110 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
111     if ([format isEqualToString:@".jpg"]) {
112         if (transitioning) {
113             return isFromCamera ? 1 : 2;
114         } else {
115             return isFromCamera ? 2 : 3;
116         }
117     } else {
118         return transitioning ? 3 : 2;
119     }
120 }
121
122 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
123     if (section == kName) {
124         return 2;
125     } else if (section == formatSection) {
126         return 2;
127     } else if (section == qualitySection) {
128         return 1;
129     } else {
130         return 0;
131     }
132 }
133
134 - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
135     if (indexPath.section == qualitySection) {
136         return tableView.rowHeight + slider.frame.size.height + 3.0;
137     } else {
138         return tableView.rowHeight;
139     }
140 }
141 - (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section {
142     if (section == formatSection) {
143         return @"JPEG is a lossy format designed for digital photography. PNG is a lossless format that supports transparency.";
144     } else if (section == qualitySection) {
145         return @"A high quality will produce a better image. A low quality will use less space.";
146     } else {
147         return @"";
148     }
149 }
150
151 - (UITableViewCell *)tableView:(UITableView *)tableView nameCellForRowAtIndexPath:(NSIndexPath *)indexPath {
152     static NSString *CellIdentifier = @"NameCell";    
153     UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
154     if (cell == nil) {
155         cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease];
156         cell.selectionStyle = UITableViewCellSelectionStyleNone;
157         cell.textLabel.text = @"Name";
158         [cell addSubview:nameTextField];
159         [cell addSubview:formatLabel];
160     }    
161     return cell;
162 }
163
164 - (UITableViewCell *)tableView:(UITableView *)tableView qualityCellForRowAtIndexPath:(NSIndexPath *)indexPath {
165     static NSString *CellIdentifier = @"QualityCell";
166     
167     UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
168     if (cell == nil) {
169         cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease];
170         cell.selectionStyle = UITableViewCellSelectionStyleNone;
171         
172         UILabel *textLabel = [[UILabel alloc] initWithFrame:CGRectMake(20.0, 13.0, 280.0, 20.0)];
173         if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
174             textLabel.frame = CGRectMake(41.0, 13.0, 458.0, 20.0);
175         }
176         textLabel.font = [UIFont boldSystemFontOfSize:17.0];
177         textLabel.text = @"Quality";
178         textLabel.textColor = [UIColor blackColor];
179         textLabel.backgroundColor = [UIColor clearColor];
180         [cell addSubview:textLabel];
181         [textLabel release];
182         
183         if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
184             slider.frame = CGRectMake(41.0, 38.0, 458.0, slider.frame.size.height);
185         } else {
186             slider.frame = CGRectMake(20.0, 38.0, 280.0, slider.frame.size.height);
187         }
188         
189         [slider addTarget:self action:@selector(sliderMoved:) forControlEvents:UIControlEventValueChanged];
190         [slider addTarget:self action:@selector(sliderFinished:) forControlEvents:UIControlEventTouchUpInside];
191         
192         [cell addSubview:slider];
193         qualityLabel = [[UILabel alloc] initWithFrame:CGRectMake(20.0, 14.0, 280.0, 18.0)];
194         if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
195             qualityLabel.frame = CGRectMake(41.0, 14.0, 458.0, 18.0);
196         }        
197         qualityLabel.font = [UIFont systemFontOfSize:17.0];
198         qualityLabel.textColor = [UIColor value1DetailTextLabelColor];
199         qualityLabel.backgroundColor = [UIColor clearColor];
200         qualityLabel.textAlignment = UITextAlignmentRight;
201         [cell addSubview:qualityLabel];
202     }
203     
204     qualityLabel.text = [NSString stringWithFormat:@"%.0f%%", slider.value * 100];
205     
206     return cell;
207 }
208
209 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
210
211     if (indexPath.section == kName && indexPath.row == 0) {
212         return [self tableView:tableView nameCellForRowAtIndexPath:indexPath];
213     } else if (indexPath.section == qualitySection) {
214         return [self tableView:tableView qualityCellForRowAtIndexPath:indexPath];
215     } else {
216         static NSString *CellIdentifier = @"Cell";
217         
218         UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
219         if (cell == nil) {
220             cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease];
221         }
222         
223         if (indexPath.section == kName) {
224             cell.textLabel.text = @"Size";
225             cell.detailTextLabel.text = [Container humanizedBytes:[data length]];
226             cell.selectionStyle = UITableViewCellSelectionStyleNone;
227             cell.accessoryType = UITableViewCellAccessoryNone;
228         } else if (indexPath.section == formatSection) {
229             cell.selectionStyle = UITableViewCellSelectionStyleBlue;
230             if (indexPath.row == 0) {
231                 cell.textLabel.text = @"JPEG";
232                 cell.detailTextLabel.text = @"";
233                 if ([format isEqualToString:@".jpg"]) {
234                     cell.accessoryType = UITableViewCellAccessoryCheckmark;
235                 } else {
236                     cell.accessoryType = UITableViewCellAccessoryNone;
237                 }
238             } else if (indexPath.row == 1) {
239                 cell.textLabel.text = @"PNG";
240                 cell.detailTextLabel.text = @"";
241                 if ([format isEqualToString:@".png"]) {
242                     cell.accessoryType = UITableViewCellAccessoryCheckmark;
243                 } else {
244                     cell.accessoryType = UITableViewCellAccessoryNone;
245                 }
246             }
247         } else {
248             cell.textLabel.text = @"Quality";
249             cell.detailTextLabel.text = @"65%";
250             cell.selectionStyle = UITableViewCellSelectionStyleNone;
251         }
252         
253         return cell;
254     }
255 }
256
257 #pragma mark -
258 #pragma mark Table view delegate
259
260 - (void)updateFormat {
261     
262     transitioning = YES;
263     
264     NSArray *indexPaths = [NSArray arrayWithObjects:[NSIndexPath indexPathForRow:0 inSection:formatSection], [NSIndexPath indexPathForRow:1 inSection:formatSection], nil];
265     [self.tableView reloadRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationNone];
266     
267     transitioning = NO;
268     
269     if ([format isEqualToString:@".jpg"]) {
270         [self.tableView insertSections:[NSIndexSet indexSetWithIndex:qualitySection] withRowAnimation:UITableViewRowAnimationBottom];
271     } else {
272         [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:qualitySection] withRowAnimation:UITableViewRowAnimationTop];
273     }
274     
275     formatLabel.text = format;
276     // move the text field to make room for the numbers label
277     CGSize size = [formatLabel.text sizeWithFont:formatLabel.font constrainedToSize:CGSizeMake(280.0, 900.0f)];
278     nameTextField.frame = CGRectMake(79.0, 13.0, 222.0 - size.width, 24.0);
279     
280     qualityActivityIndicatorView = [[ActivityIndicatorView alloc] initWithFrame:[ActivityIndicatorView frameForText:@"Calculating size..."] text:@"Calculating size..."];
281     [qualityActivityIndicatorView addToView:self.view];    
282     [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(calculateSize) userInfo:nil repeats:NO];
283     
284 }
285
286 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
287     if (indexPath.section == formatSection) {
288         if (indexPath.row == 0) {
289             format = @".jpg";
290         } else { //if (indexPath.row == 1) {
291             format = @".png";
292         }
293 //        [self.tableView deselectRowAtIndexPath:indexPath animated:YES];
294         [NSTimer scheduledTimerWithTimeInterval:0.35 target:self selector:@selector(updateFormat) userInfo:nil repeats:NO];
295     }
296 }
297
298 #pragma mark -
299 #pragma mark Text Field Delegate
300
301 - (BOOL)textFieldShouldReturn:(UITextField *)textField {
302     [textField resignFirstResponder];
303     return NO;
304 }
305
306 #pragma mark -
307 #pragma mark Slider
308
309 - (void)calculateSize {
310     if ([format isEqualToString:@".jpg"]) {
311         [data release];
312         data = UIImageJPEGRepresentation(image, slider.value);
313         [data retain];
314     } else {
315         [data release];
316         
317         if (isFromCamera) {
318             // PNG files from the camera need to be rotated
319             UIImage *rotatedImage = [[UIImage alloc] initWithCGImage:(CGImageRef)image scale:1.0 orientation:UIImageOrientationLeft];
320             data = UIImagePNGRepresentation(rotatedImage);
321             [rotatedImage release];
322         } else {
323             data = UIImagePNGRepresentation(image);
324         }
325         [data retain];
326     }
327     
328     [self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:1 inSection:kName]] withRowAnimation:UITableViewRowAnimationNone];    
329     [qualityActivityIndicatorView removeFromSuperviewAndRelease];
330 }
331
332 - (void)sliderFinished:(id)sender {
333     qualityActivityIndicatorView = [[ActivityIndicatorView alloc] initWithFrame:[ActivityIndicatorView frameForText:@"Calculating size..."] text:@"Calculating size..."];
334     [qualityActivityIndicatorView addToView:self.view];    
335     [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(calculateSize) userInfo:nil repeats:NO];
336 }
337
338 - (void)sliderMoved:(id)sender {
339     qualityLabel.text = [NSString stringWithFormat:@"%.0f%%", slider.value * 100];
340 }
341
342 #pragma mark -
343 #pragma mark Save Button
344
345 - (void)saveButtonPressed:(id)sender {
346     activityIndicatorView = [[ActivityIndicatorView alloc] initWithFrame:[ActivityIndicatorView frameForText:@"Uploading..." withProgress:YES] text:@"Uploading..." withProgress:YES];
347     [activityIndicatorView addToView:self.view];
348
349     StorageObject *object = [[StorageObject alloc] init];
350     
351     if (nameTextField.text && ![nameTextField.text isEqualToString:@""]) {
352         object.name = [NSString stringWithFormat:@"%@%@", nameTextField.text, format];
353     } else {
354         object.name = [NSString stringWithFormat:@"%@%@", nameTextField.placeholder, format];
355     }
356     object.fullPath = [NSString stringWithFormat:@"%@/%@", [folder fullPath], object.name];
357     object.fullPath = [object.fullPath substringFromIndex:1];
358     
359     if ([format isEqualToString:@".jpg"]) {
360         object.contentType = @"image/jpeg";
361     } else {
362         object.contentType = @"image/png";
363     }
364
365     object.data = data;
366     object.bytes = [data length];
367     
368     [self.account.manager writeObject:self.container object:object downloadProgressDelegate:activityIndicatorView.progressView];
369
370     successObserver = [[NSNotificationCenter defaultCenter] addObserverForName:@"writeObjectSucceeded" object:object queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification* notification) 
371         {
372             [activityIndicatorView removeFromSuperviewAndRelease];
373             object.data = nil;
374             [folder.objects setObject:object forKey:object.name];
375             [folderViewController.tableView reloadData];
376             [self dismissModalViewControllerAnimated:YES];
377             [[NSNotificationCenter defaultCenter] removeObserver:successObserver];
378         }];
379
380     failureObserver = [[NSNotificationCenter defaultCenter] addObserverForName:@"writeObjectFailed" object:object queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification* notification) 
381         {
382             [activityIndicatorView removeFromSuperviewAndRelease];
383             [self alert:@"There was a problem uploading this file." request:[notification.userInfo objectForKey:@"request"]];            
384             [[NSNotificationCenter defaultCenter] removeObserver:failureObserver];
385         }];
386 }
387
388 #pragma mark -
389 #pragma mark Memory management
390
391 - (void)dealloc {
392     [image release];
393     [account release];
394     [container release];
395     [folder release];
396     [folderViewController release];
397     [nameTextField release];
398     [formatLabel release];
399     [slider release];
400     [super dealloc];
401 }
402
403
404 @end
405