Statistics
| Branch: | Tag: | Revision:

root / Classes / AddPhotoViewController.m @ 3a8071d4

History | View | Annotate | Download (17.9 kB)

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
#import "APICallback.h"
22

    
23
#define kName 0
24

    
25
// give me the option to add a description of the file and the URL - date/time stamped
26

    
27
@implementation AddPhotoViewController
28

    
29
@synthesize image, account, container, folder, folderViewController, isFromCamera;
30

    
31
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
32
    return (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) || (toInterfaceOrientation == UIInterfaceOrientationPortrait);
33
}
34

    
35
#pragma mark -
36
#pragma mark View lifecycle
37

    
38
- (void)viewDidLoad {
39
    [super viewDidLoad];
40
    self.navigationItem.title = @"Add Photo";
41
    [self addSaveButton];
42
    format = @".jpg";
43
    
44
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
45
        nameTextField = [[UITextField alloc] initWithFrame:CGRectMake(98.0, 13.0, 400.0, 24.0)];
46
    } else {
47
        nameTextField = [[UITextField alloc] initWithFrame:CGRectMake(79.0, 13.0, 222.0, 24.0)];
48
    }    
49
    nameTextField.delegate = self;
50
    nameTextField.font = [UIFont systemFontOfSize:17.0];
51
    nameTextField.textColor = [UIColor value1DetailTextLabelColor];
52
    nameTextField.backgroundColor = [UIColor clearColor];
53
    nameTextField.textAlignment = UITextAlignmentRight;
54
    nameTextField.returnKeyType = UIReturnKeyDone;
55
    nameTextField.autocorrectionType = UITextAutocorrectionTypeNo;
56
    nameTextField.autocapitalizationType = UITextAutocapitalizationTypeNone;    
57
    nameTextField.placeholder = [NSString stringWithFormat:@"ios_upload_%.0f", [[NSDate date] timeIntervalSince1970]];    
58
    
59
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
60
        formatLabel = [[UILabel alloc] initWithFrame:CGRectMake(41.0, 15.5, 458.0, 18.0)];
61
    } else {
62
        formatLabel = [[UILabel alloc] initWithFrame:CGRectMake(21.0, 15.5, 280.0, 18.0)];
63
    }    
64
    formatLabel.font = [UIFont systemFontOfSize:17.0];
65
    formatLabel.textColor = [UIColor value1DetailTextLabelColor];
66
    formatLabel.backgroundColor = [UIColor clearColor];
67
    formatLabel.textAlignment = UITextAlignmentRight;
68
    formatLabel.text = format;
69
    
70
    slider = [[UISlider alloc] init];
71
    slider.value = 0.65;
72
    
73
    // move the text field to make room for the numbers label
74
    CGSize size = [formatLabel.text sizeWithFont:formatLabel.font constrainedToSize:CGSizeMake(280.0, 900.0f)];
75
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
76
        nameTextField.frame = CGRectMake(98.0, 13.0, 400.0 - size.width, 24.0);
77
    } else {
78
        nameTextField.frame = CGRectMake(79.0, 13.0, 222.0 - size.width, 24.0);
79
    }    
80
    
81
}
82

    
83
- (void)viewWillAppear:(BOOL)animated {
84
    [super viewWillAppear:animated];
85
//    data = UIImageJPEGRepresentation(image, slider.value);
86
//    [data retain];
87
    
88
    // when saving a camera image as a PNG, it ends up rotated.  i have no idea why and have
89
    // not been able to successfully rotate the image, so we're only allowing JPEG from the
90
    // camera for now.  not a big deal, since the iPhone 4 camera is making 8 MB PNG files
91
    if (isFromCamera) {
92
        formatSection = -1;
93
        qualitySection = 1;
94
    } else {
95
        formatSection = 1;
96
        qualitySection = 2;
97
    }
98
}
99

    
100
- (void)viewDidAppear:(BOOL)animated {
101
    [super viewDidAppear:animated];
102
    [qualityActivityIndicatorView release];
103
    qualityActivityIndicatorView = [[ActivityIndicatorView alloc] initWithFrame:[ActivityIndicatorView frameForText:@"Calculating size..."] text:@"Calculating size..."];
104
    [qualityActivityIndicatorView addToView:self.view];    
105
    [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(calculateSize) userInfo:nil repeats:NO];
106
}
107

    
108
#pragma mark -
109
#pragma mark Table view data source
110

    
111
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
112
    if ([format isEqualToString:@".jpg"]) {
113
        if (transitioning) {
114
            return isFromCamera ? 1 : 2;
115
        } else {
116
            return isFromCamera ? 2 : 3;
117
        }
118
    } else {
119
        return transitioning ? 3 : 2;
120
    }
121
}
122

    
123
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
124
    if (section == kName) {
125
        return 2;
126
    } else if (section == formatSection) {
127
        return 2;
128
    } else if (section == qualitySection) {
129
        return 1;
130
    } else {
131
        return 0;
132
    }
133
}
134

    
135
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
136
    if (indexPath.section == qualitySection) {
137
        return tableView.rowHeight + slider.frame.size.height + 3.0;
138
    } else {
139
        return tableView.rowHeight;
140
    }
141
}
142
- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section {
143
    if (section == formatSection) {
144
        return @"JPEG is a lossy format designed for digital photography. PNG is a lossless format that supports transparency.";
145
    } else if (section == qualitySection) {
146
        return @"A high quality will produce a better image. A low quality will use less space.";
147
    } else {
148
        return @"";
149
    }
150
}
151

    
152
- (UITableViewCell *)tableView:(UITableView *)tableView nameCellForRowAtIndexPath:(NSIndexPath *)indexPath {
153
    static NSString *CellIdentifier = @"NameCell";    
154
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
155
    if (cell == nil) {
156
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease];
157
        cell.selectionStyle = UITableViewCellSelectionStyleNone;
158
        cell.textLabel.text = @"Name";
159
        [cell addSubview:nameTextField];
160
        [cell addSubview:formatLabel];
161
    }    
162
    return cell;
163
}
164

    
165
- (UITableViewCell *)tableView:(UITableView *)tableView qualityCellForRowAtIndexPath:(NSIndexPath *)indexPath {
166
    static NSString *CellIdentifier = @"QualityCell";
167
    
168
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
169
    if (cell == nil) {
170
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease];
171
        cell.selectionStyle = UITableViewCellSelectionStyleNone;
172
        
173
        UILabel *textLabel = [[UILabel alloc] initWithFrame:CGRectMake(20.0, 13.0, 280.0, 20.0)];
174
        if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
175
            textLabel.frame = CGRectMake(41.0, 13.0, 458.0, 20.0);
176
        }
177
        textLabel.font = [UIFont boldSystemFontOfSize:17.0];
178
        textLabel.text = @"Quality";
179
        textLabel.textColor = [UIColor blackColor];
180
        textLabel.backgroundColor = [UIColor clearColor];
181
        [cell addSubview:textLabel];
182
        [textLabel release];
183
        
184
        if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
185
            slider.frame = CGRectMake(41.0, 38.0, 458.0, slider.frame.size.height);
186
        } else {
187
            slider.frame = CGRectMake(20.0, 38.0, 280.0, slider.frame.size.height);
188
        }
189
        
190
        [slider addTarget:self action:@selector(sliderMoved:) forControlEvents:UIControlEventValueChanged];
191
        [slider addTarget:self action:@selector(sliderFinished:) forControlEvents:UIControlEventTouchUpInside];
192
        
193
        [cell addSubview:slider];
194
        qualityLabel = [[UILabel alloc] initWithFrame:CGRectMake(20.0, 14.0, 280.0, 18.0)];
195
        if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
196
            qualityLabel.frame = CGRectMake(41.0, 14.0, 458.0, 18.0);
197
        }        
198
        qualityLabel.font = [UIFont systemFontOfSize:17.0];
199
        qualityLabel.textColor = [UIColor value1DetailTextLabelColor];
200
        qualityLabel.backgroundColor = [UIColor clearColor];
201
        qualityLabel.textAlignment = UITextAlignmentRight;
202
        [cell addSubview:qualityLabel];
203
    }
204
    
205
    qualityLabel.text = [NSString stringWithFormat:@"%.0f%%", slider.value * 100];
206
    
207
    return cell;
208
}
209

    
210
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
211

    
212
    if (indexPath.section == kName && indexPath.row == 0) {
213
        return [self tableView:tableView nameCellForRowAtIndexPath:indexPath];
214
    } else if (indexPath.section == qualitySection) {
215
        return [self tableView:tableView qualityCellForRowAtIndexPath:indexPath];
216
    } else {
217
        static NSString *CellIdentifier = @"Cell";
218
        
219
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
220
        if (cell == nil) {
221
            cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease];
222
        }
223
        
224
        if (indexPath.section == kName) {
225
            cell.textLabel.text = @"Size";
226
            cell.detailTextLabel.text = [Container humanizedBytes:[data length]];
227
            cell.selectionStyle = UITableViewCellSelectionStyleNone;
228
            cell.accessoryType = UITableViewCellAccessoryNone;
229
        } else if (indexPath.section == formatSection) {
230
            cell.selectionStyle = UITableViewCellSelectionStyleBlue;
231
            if (indexPath.row == 0) {
232
                cell.textLabel.text = @"JPEG";
233
                cell.detailTextLabel.text = @"";
234
                if ([format isEqualToString:@".jpg"]) {
235
                    cell.accessoryType = UITableViewCellAccessoryCheckmark;
236
                } else {
237
                    cell.accessoryType = UITableViewCellAccessoryNone;
238
                }
239
            } else if (indexPath.row == 1) {
240
                cell.textLabel.text = @"PNG";
241
                cell.detailTextLabel.text = @"";
242
                if ([format isEqualToString:@".png"]) {
243
                    cell.accessoryType = UITableViewCellAccessoryCheckmark;
244
                } else {
245
                    cell.accessoryType = UITableViewCellAccessoryNone;
246
                }
247
            }
248
        } else {
249
            cell.textLabel.text = @"Quality";
250
            cell.detailTextLabel.text = @"65%";
251
            cell.selectionStyle = UITableViewCellSelectionStyleNone;
252
        }
253
        
254
        return cell;
255
    }
256
}
257

    
258
#pragma mark -
259
#pragma mark Table view delegate
260

    
261
- (void)updateFormat {
262
    
263
    transitioning = YES;
264
    
265
    NSArray *indexPaths = [NSArray arrayWithObjects:[NSIndexPath indexPathForRow:0 inSection:formatSection], [NSIndexPath indexPathForRow:1 inSection:formatSection], nil];
266
    [self.tableView reloadRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationNone];
267
    
268
    transitioning = NO;
269
    
270
    if ([format isEqualToString:@".jpg"]) {
271
        [self.tableView insertSections:[NSIndexSet indexSetWithIndex:qualitySection] withRowAnimation:UITableViewRowAnimationBottom];
272
    } else {
273
        [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:qualitySection] withRowAnimation:UITableViewRowAnimationTop];
274
    }
275
    
276
    formatLabel.text = format;
277
    // move the text field to make room for the numbers label
278
    CGSize size = [formatLabel.text sizeWithFont:formatLabel.font constrainedToSize:CGSizeMake(280.0, 900.0f)];
279
    nameTextField.frame = CGRectMake(79.0, 13.0, 222.0 - size.width, 24.0);
280
    [qualityActivityIndicatorView release];
281
    qualityActivityIndicatorView = [[ActivityIndicatorView alloc] initWithFrame:[ActivityIndicatorView frameForText:@"Calculating size..."] text:@"Calculating size..."];
282
    [qualityActivityIndicatorView addToView:self.view];    
283
    [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(calculateSize) userInfo:nil repeats:NO];
284
    
285
}
286

    
287
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
288
    if (indexPath.section == formatSection) {
289
        if (indexPath.row == 0) {
290
            format = @".jpg";
291
        } else { //if (indexPath.row == 1) {
292
            format = @".png";
293
        }
294
//        [self.tableView deselectRowAtIndexPath:indexPath animated:YES];
295
        [NSTimer scheduledTimerWithTimeInterval:0.35 target:self selector:@selector(updateFormat) userInfo:nil repeats:NO];
296
    }
297
}
298

    
299
#pragma mark -
300
#pragma mark Text Field Delegate
301

    
302
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
303
    [textField resignFirstResponder];
304
    return NO;
305
}
306

    
307
#pragma mark -
308
#pragma mark Slider
309

    
310
- (void)calculateSize {
311
    if ([format isEqualToString:@".jpg"]) {
312
        [data release];
313
        data = UIImageJPEGRepresentation(image, slider.value);
314
        [data retain];
315
    } else {
316
        [data release];
317
        
318
        if (isFromCamera) {
319
            // PNG files from the camera need to be rotated
320
            UIImage *rotatedImage = [[UIImage alloc] initWithCGImage:(CGImageRef)image scale:1.0 orientation:UIImageOrientationLeft];
321
            data = UIImagePNGRepresentation(rotatedImage);
322
            [rotatedImage release];
323
        } else {
324
            data = UIImagePNGRepresentation(image);
325
        }
326
        [data retain];
327
    }
328
    
329
    [self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:1 inSection:kName]] withRowAnimation:UITableViewRowAnimationNone];    
330
    [qualityActivityIndicatorView removeFromSuperview];
331
}
332

    
333
- (void)sliderFinished:(id)sender {
334
    [qualityActivityIndicatorView release];
335
    qualityActivityIndicatorView = [[ActivityIndicatorView alloc] initWithFrame:[ActivityIndicatorView frameForText:@"Calculating size..."] text:@"Calculating size..."];
336
    [qualityActivityIndicatorView addToView:self.view];    
337
    [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(calculateSize) userInfo:nil repeats:NO];
338
}
339

    
340
- (void)sliderMoved:(id)sender {
341
    qualityLabel.text = [NSString stringWithFormat:@"%.0f%%", slider.value * 100];
342
}
343

    
344
#pragma mark -
345
#pragma mark Save Button
346

    
347
- (void)saveButtonPressed:(id)sender {
348
    [nameTextField resignFirstResponder];
349
    NSString *objectName;
350
    if (nameTextField.text && ![nameTextField.text isEqualToString:@""]) {
351
        objectName = [NSString stringWithFormat:@"%@%@", nameTextField.text, format];
352
    } else {
353
        objectName = [NSString stringWithFormat:@"%@%@", nameTextField.placeholder, format];
354
    }
355
    
356
    BOOL objectNameHasTrailingSlash = [objectName hasSuffix:@"/"];
357
    NSUInteger indexOfFirstSlash = [objectName rangeOfString:@"/"].location;
358
    
359
    if ((!objectNameHasTrailingSlash && indexOfFirstSlash != NSNotFound) || 
360
        (objectNameHasTrailingSlash && indexOfFirstSlash < objectName.length - 1)) {
361
        [self alert:@"Invalid file name" message:@"'/' characters are only allowed at the end of file names"];
362
        return;
363
    }
364
    
365
    if ([folderViewController.folder.objects objectForKey:objectName] && !allowOverwrite) {
366
        NSString *alertMessage = [NSString stringWithFormat:@"An object with path '%@' in the container '%@' already exists, do you want to replace it?",objectName, folderViewController.container.name];
367
        NSString *alertTitle = @"Apply changes";
368
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:alertTitle
369
                                                        message:alertMessage
370
                                                       delegate:self
371
                                              cancelButtonTitle:@"Cancel"
372
                                              otherButtonTitles:@"OK", nil];
373
        [alert show];
374
        [alert release];
375
        return;
376
    }
377
    [activityIndicatorView release];
378
    activityIndicatorView = [[ActivityIndicatorView alloc] initWithFrame:[ActivityIndicatorView frameForText:@"Uploading..." withProgress:YES] text:@"Uploading..." withProgress:YES];
379
    [activityIndicatorView addToView:self.view];
380

    
381
    StorageObject *object = [[StorageObject alloc] init];
382
    object.name = objectName;
383
    object.fullPath = [NSString stringWithFormat:@"%@/%@", [folder fullPath], object.name];
384
    object.fullPath = [object.fullPath substringFromIndex:1];
385
    
386
    if ([format isEqualToString:@".jpg"]) {
387
        object.contentType = @"image/jpeg";
388
    } else {
389
        object.contentType = @"image/png";
390
    }
391

    
392
    object.data = data;
393
    object.bytes = [data length];
394
    
395
    [[self.account.manager writeObject:self.container object:object downloadProgressDelegate:activityIndicatorView.progressView]
396
     success:^(OpenStackRequest *request) {
397
         [activityIndicatorView removeFromSuperview];
398
         object.data = nil;
399
         object.sharing = folder.sharing;
400
         BOOL currentFolderIsRoot = NO;
401
         if ([folderViewController.folder isEqual:container.rootFolder]) {
402
             currentFolderIsRoot = YES;
403
         }
404
         [folder.objects setObject:object forKey:object.name];
405
         [folderViewController.tableView reloadData];
406
         if (currentFolderIsRoot) {
407
             container.count += 1;
408
             container.rootFolder = folder;
409
             [self.account.containers setObject:container forKey:container.name];
410
         }
411
         if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
412
             [folderViewController setDetailViewController];
413
         allowOverwrite = NO;
414
         [self dismissModalViewControllerAnimated:YES];
415
     }
416
     failure:^(OpenStackRequest *request) {
417
         [activityIndicatorView removeFromSuperview];
418
         allowOverwrite = NO;
419
         [self alert:@"There was a problem uploading this file." request:request];            
420
     }];
421
}
422

    
423
#pragma mark - Alertview delegate
424

    
425
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
426
{
427
    if (buttonIndex == 1) {
428
        allowOverwrite = YES;
429
        [self saveButtonPressed:nil];
430
    } 
431
}
432

    
433
#pragma mark -
434
#pragma mark Memory management
435

    
436
- (void)dealloc {
437
    [image release];
438
    [account release];
439
    [container release];
440
    [folder release];
441
    [folderViewController release];
442
    [nameTextField release];
443
    [formatLabel release];
444
    [slider release];
445
    [qualityActivityIndicatorView release];
446
    [activityIndicatorView release];
447
    [super dealloc];
448
}
449

    
450

    
451
@end
452