photo-ios/OpenPhoto/PhotoViewController.m
2011-11-04 07:30:05 +01:00

549 lines
21 KiB
Objective-C

//
// PhotoViewController.m
// OpenPhoto
//
// Created by Patrick Santana on 29/07/11.
// Copyright 2011 OpenPhoto. All rights reserved.
//
#import "PhotoViewController.h"
@interface PhotoViewController()
// all details
-(void) uploadPictureOnDetachTread:(NSDictionary*) values;
-(void) uploadPicture:(NSDictionary*) values;
@end
@implementation PhotoViewController
@synthesize detailsPictureTable;
@synthesize statusBar;
@synthesize imageOriginal,imageFiltered;
@synthesize titleTextField, descriptionTextField, permissionPicture, highResolutionPicture, gpsPosition;
@synthesize tagController, sourceType;
@synthesize location, service;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil photo:(UIImage *) imageFromPicker source:(UIImagePickerControllerSourceType) pickerSourceType
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
self.imageOriginal = imageFromPicker;
self.sourceType = pickerSourceType;
// initialization of tag controller
self.tagController = [[[TagViewController alloc] init]autorelease];
[self.tagController setReadOnly];
// to send the request via the web service class
self.service = [[WebService alloc]init];
[self.service setDelegate:self];
}
return self;
}
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{ statusBar.hidden = YES;
[[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationFade];
[self.navigationController setNavigationBarHidden:NO animated:YES];
// if user wants to cancel the upload
UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc] initWithTitle:@"Cancel" style:UIBarButtonItemStylePlain target:self action:@selector(cancelUploadButton)];
self.navigationItem.rightBarButtonItem = cancelButton;
[cancelButton release];
coreLocationController = [[CoreLocationController alloc] init];
coreLocationController.delegate = self;
[super viewDidLoad];
}
- (void) cancelUploadButton
{
[self dismissModalViewControllerAnimated:YES];
}
- (void)viewDidUnload
{
[imageTitle release];
imageTitle = nil;
[imageDescription release];
imageDescription = nil;
[statusBar release];
statusBar = nil;
[self setStatusBar:nil];
[self setDetailsPictureTable:nil];
[super viewDidUnload];
[coreLocationController release];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (IBAction)upload:(id)sender {
statusBar.hidden = NO;
[statusBar startAnimating];
// title
NSString *title = (titleTextField.text.length > 0 ? titleTextField.text : @"");
// description
NSString *description = (descriptionTextField.text.length > 0 ? descriptionTextField.text : @"");
// default permission for the pictures is PUBLIC
NSString *defaultPermission = @"1";
if ([permissionPicture isOn]){
defaultPermission = @"0";
}
NSString *latitude =@"";
NSString *longitude=@"";
if (self.location != nil){
latitude = [NSString stringWithFormat:@"%f", location.coordinate.latitude];
longitude = [NSString stringWithFormat:@"%f", location.coordinate.longitude];
}
// check the size of the image
if (![highResolutionPicture isOn]){
CGSize sz = CGSizeMake(imageOriginal.size.width/2,imageOriginal.size.height/2);
self.imageOriginal = [ImageManipulation imageWithImage:imageOriginal scaledToSize:sz];
if (self.imageFiltered != nil){
CGSize sz = CGSizeMake(imageFiltered.size.width/2,imageFiltered.size.height/2);
self.imageFiltered = [ImageManipulation imageWithImage:imageFiltered scaledToSize:sz];
}
}
// parameters to upload
NSArray *keys = [NSArray arrayWithObjects:@"image", @"title", @"description", @"permission",@"exifCameraMake",@"exifCameraModel",@"tags",@"latitude",@"longitude",nil];
NSArray *objects;
// set the correct image to upload depends if there is a filtered or not.
if (self.imageFiltered != nil){
objects = [NSArray arrayWithObjects:self.imageFiltered, title, description, defaultPermission, @"Apple",[[UIDevice currentDevice] model],[tagController getSelectedTagsInJsonFormat],latitude,longitude, nil];
} else{
objects = [NSArray arrayWithObjects:self.imageOriginal, title, description, defaultPermission, @"Apple",[[UIDevice currentDevice] model],[tagController getSelectedTagsInJsonFormat],latitude,longitude, nil];
}
NSDictionary *values = [NSDictionary dictionaryWithObjects:objects forKeys:keys];
// just save if it cames from the camera.
if (self.sourceType == UIImagePickerControllerSourceTypeCamera){
// save picture local
if ( [[NSUserDefaults standardUserDefaults] boolForKey:@"photos_save_camera_roll_or_snapshot"] == YES){
NSLog(@"Saving picture in the photo album");
UIImageWriteToSavedPhotosAlbum([self.imageOriginal retain], self, @selector(image:didFinishSavingWithError:contextInfo:), nil);
}
// save filtered picture local
if ( [[NSUserDefaults standardUserDefaults] boolForKey:@"photos_save_camera_roll_or_snapshot"] == YES && self.imageFiltered != nil){
UIImageWriteToSavedPhotosAlbum([self.imageFiltered retain], self, @selector(image:didFinishSavingWithError:contextInfo:), nil);
}
}
// to send the request we add a thread.
[NSThread detachNewThreadSelector:@selector(uploadPictureOnDetachTread:)
toTarget:self
withObject:values];
// stop gps position
[coreLocationController.locMgr stopUpdatingLocation];
}
-(void) uploadPictureOnDetachTread:(NSDictionary*) values
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[self uploadPicture:values];
#ifdef TEST_FLIGHT_ENABLED
[TestFlight passCheckpoint:@"Picture uploaded"];
#endif
[pool release];
}
- (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo{
[image release];
if (error.localizedDescription != nil){
NSLog(@"Image could not be saved = %@", error.localizedDescription);
}else{
NSLog(@"Image saved");
}
}
- (void) notifyUserNoInternet{
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
// problem with internet, show message to user
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Internet error" message:@"Couldn't reach the server. Please, check your internet connection" delegate:self cancelButtonTitle:@"Ok" otherButtonTitles:nil];
[alert show];
[alert release];
}
#pragma mark - Table
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section{
return kNumbersRow;
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell;
NSUInteger row = [indexPath row];
switch (row) {
case 0:
// title
cell=[tableView dequeueReusableCellWithIdentifier:kCellIdentifierTitle];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kCellIdentifierTitle] autorelease];
titleTextField = [[UITextField alloc] initWithFrame:CGRectMake(17 , 13, 260, 21)];
titleTextField.adjustsFontSizeToFitWidth = YES;
titleTextField.textColor = [UIColor grayColor];
titleTextField.placeholder = @"title";
titleTextField.keyboardType = UIKeyboardTypeDefault;
titleTextField.returnKeyType = UIReturnKeyDone;
titleTextField.delegate = self;
titleTextField.backgroundColor = [UIColor whiteColor];
[cell addSubview:titleTextField];
}
break;
case 1:
// description
cell=[tableView dequeueReusableCellWithIdentifier:kCellIdentifierDescription];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kCellIdentifierDescription] autorelease];
descriptionTextField = [[UITextField alloc] initWithFrame:CGRectMake(17 , 13, 260, 21)];
descriptionTextField.adjustsFontSizeToFitWidth = YES;
descriptionTextField.textColor = [UIColor grayColor];
descriptionTextField.placeholder = @"description";
descriptionTextField.keyboardType = UIKeyboardTypeDefault;
descriptionTextField.returnKeyType = UIReturnKeyDone;
descriptionTextField.delegate = self;
descriptionTextField.backgroundColor = [UIColor whiteColor];
[cell addSubview:descriptionTextField];
}
break;
case 2:
// tags
cell=[tableView dequeueReusableCellWithIdentifier:kCellIdentifierTags];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kCellIdentifierTags] autorelease];
// Do anything that should be the same on EACH cell here. Fonts, colors, etc.
}
cell.textLabel.text=@"Tags";
cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
break;
case 3:
// filter: disclosure button
cell=[tableView dequeueReusableCellWithIdentifier:kCellIdentifierFilter];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kCellIdentifierFilter] autorelease];
// Do anything that should be the same on EACH cell here. Fonts, colors, etc.
}
cell.textLabel.text=@"Crop & effects";
cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
break;
case 4:
// high resolution picture
cell=[tableView dequeueReusableCellWithIdentifier:kCellIdentifierHighResolutionPicture];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kCellIdentifierHighResolutionPicture] autorelease];
// Do anything that should be the same on EACH cell here. Fonts, colors, etc.
}
cell.textLabel.text=@"High resolution";
highResolutionPicture = [[[UISwitch alloc] initWithFrame:CGRectZero] autorelease];
cell.accessoryView = highResolutionPicture;
// get from user if picture will be uploaded in high resolution or not
[(UISwitch *)cell.accessoryView setOn:[[NSUserDefaults standardUserDefaults] boolForKey:@"photos_high_resolution"]];
break;
case 5:
// private flag
cell=[tableView dequeueReusableCellWithIdentifier:kCellIdentifierPrivate];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kCellIdentifierPrivate] autorelease];
// Do anything that should be the same on EACH cell here. Fonts, colors, etc.
}
cell.textLabel.text=@"Private";
permissionPicture = [[[UISwitch alloc] initWithFrame:CGRectZero] autorelease];
cell.accessoryView = permissionPicture;
// get from user configuration if pictures should be private or not
[(UISwitch *)cell.accessoryView setOn:[[NSUserDefaults standardUserDefaults] boolForKey:@"photos_are_private"]];
break;
case 6:
// gps position
// private flag
cell=[tableView dequeueReusableCellWithIdentifier:kCellIdentifierGpsPosition];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kCellIdentifierGpsPosition] autorelease];
}
cell.textLabel.text=@"GPS Position";
self.gpsPosition = [[[UISwitch alloc] initWithFrame:CGRectZero] autorelease];
[self.gpsPosition addTarget:self action:@selector(switchedGpsPosition) forControlEvents:UIControlEventValueChanged];
cell.accessoryView = self.gpsPosition;
// get from user configuration if pictures should be private or not
[(UISwitch *)cell.accessoryView setOn:NO];
break;
default:
break;
}
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
return cell;
}
- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath {
NSUInteger row = [indexPath row];
if ( row == 3){
// filter
[tableView selectRowAtIndexPath:indexPath animated:NO scrollPosition:0];
AFFeatherController *controller = [[AFFeatherController alloc]
initWithImage:self.imageOriginal];
controller.delegate = self;
[self presentModalViewController:controller animated:YES];
[controller release];
}else if (row == 2){
// tags
[tableView selectRowAtIndexPath:indexPath animated:NO scrollPosition:0];
[self.navigationController pushViewController:self.tagController animated:YES];
}
}
-(void) switchedGpsPosition{
// get gps position
if ([self.gpsPosition isOn]){
[coreLocationController.locMgr startUpdatingLocation];
NSLog(@"Start Updating Location");
}else{
// stop gps position
[coreLocationController.locMgr stopUpdatingLocation];
}
}
- (void)feather:(AFFeatherController *)featherController finishedWithImage:(UIImage *)image{
NSLog(@"Image changed");
self.imageFiltered = image;
}
- (void)featherCanceled:(AFFeatherController *)featherController{
NSLog(@"Widget canceled");
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
[textField resignFirstResponder];
return YES;
}
- (void)locationUpdate:(CLLocation *)position{
self.location = position;
}
- (void)locationError:(NSError *)error {
NSLog(@"Location %@", [error description]);
}
// For upload
-(void) uploadPicture:(NSDictionary*) values{
if (service.internetActive == YES && service.hostActive == YES){
// send message to the site. it is pickedImage
NSData *imageData = UIImageJPEGRepresentation([values objectForKey:@"image"] ,0.7);
//Custom implementations, no built in base64 or HTTP escaping for iPhone
NSString *imageB64 = [QSStrings encodeBase64WithData:imageData];
NSString* imageEscaped = [Base64Utilities fullEscape:imageB64];
// set all details to send
NSString *uploadCall = [NSString stringWithFormat:@"photo=%@&title=%@&description=%@&permission=%@&exifCameraMake=%@&exifCameraModel=%@&tags=%@&latitude=%@&longitude=%@",imageEscaped,[values objectForKey:@"title"],[values objectForKey:@"description"],[values objectForKey:@"permission"],[values objectForKey:@"exifCameraMake"],[values objectForKey:@"exifCameraModel"], [values objectForKey:@"tags"],[values objectForKey:@"latitude"],[values objectForKey:@"longitude"]];
NSMutableString *urlString = [NSMutableString stringWithFormat: @"%@/photo/upload.json",
[[NSUserDefaults standardUserDefaults] stringForKey:kOpenPhotoServer]];
#ifdef DEVELOPMENT_ENABLED
NSLog(@"Request to be sent = [%@]",urlString);
#endif
// transform in URL for the request
NSURL *url = [NSURL URLWithString:urlString];
NSUserDefaults *standardUserDefaults = [NSUserDefaults standardUserDefaults];
// token to send. We get the details from the user defaults
OAToken *token = [[OAToken alloc] initWithKey:[standardUserDefaults valueForKey:kAuthenticationOAuthToken]
secret:[standardUserDefaults valueForKey:kAuthenticationOAuthSecret]];
//consumer to send. We get the details from the user defaults
OAConsumer *consumer = [[OAConsumer alloc] initWithKey:[standardUserDefaults valueForKey:kAuthenticationConsumerKey]
secret:[standardUserDefaults valueForKey:kAuthenticationConsumerSecret] ];
OAMutableURLRequest *oaUrlRequest = [[OAMutableURLRequest alloc] initWithURL:url
consumer:consumer
token:token
realm:nil
signatureProvider:nil];
[oaUrlRequest setHTTPMethod:@"POST"];
[oaUrlRequest setValue:[NSString stringWithFormat:@"%d",[uploadCall length]] forHTTPHeaderField:@"Content-length"];
// prepare the Authentication Header
[oaUrlRequest prepare];
[oaUrlRequest setHTTPBody:[uploadCall dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:NO]];
responseData = [[NSMutableData data] retain];
[[NSURLConnection alloc] initWithRequest:oaUrlRequest delegate:self startImmediately:YES];
HUD = [[MBProgressHUD showHUDAddedTo:self.navigationController.view animated:YES] retain];
[token release];
[consumer release];
[oaUrlRequest release];
}
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
NSLog(@"didReceiveResponse");
expectedLength = [response expectedContentLength];
currentLength = 0;
HUD.mode = MBProgressHUDModeDeterminate;
[responseData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
NSLog(@"didReceiveData");
currentLength += [data length];
HUD.progress = currentLength / (float)expectedLength;
[responseData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSLog(@"connectionDidFinishLoading");
// progress bar
HUD.customView = [[[UIImageView alloc] initWithImage:[UIImage imageNamed:@"19-check.png"]] autorelease];
HUD.mode = MBProgressHUDModeCustomView;
[HUD hide:YES afterDelay:2];
// finish details
[connection release];
NSString *jsonString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
// it can be released
[responseData release];
#ifdef DEVELOPMENT_ENABLED
NSLog(@"Succeed = %@",jsonString);
#endif
// Create a dictionary from JSON string
// When there are newline characters in the JSON string,
// the error "Unescaped control character '0x9'" will be thrown. This removes those characters.
jsonString = [jsonString stringByTrimmingCharactersInSet:[NSCharacterSet newlineCharacterSet]];
NSDictionary *response = [jsonString JSONValue];
[statusBar stopAnimating];
statusBar.hidden = YES;
// check if message is valid
if (![WebService isMessageValid:response]){
NSString* message = [WebService getResponseMessage:response];
NSLog(@"Invalid response = %@",message);
// show alert to user
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Response Error" message:message delegate:self cancelButtonTitle:@"Ok" otherButtonTitles:nil];
[alert show];
[alert release];
}
// open gallery
[self dismissModalViewControllerAnimated:YES];
[[NSNotificationCenter defaultCenter] postNotificationName:kNotificationOpenGallery object:nil ];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
NSLog(@"Connection failed: %@", [error description]);
[HUD hide:YES];
}
#pragma mark -
#pragma mark MBProgressHUDDelegate methods
- (void)hudWasHidden:(MBProgressHUD *)hud {
// Remove HUD from screen when the HUD was hidded
[HUD removeFromSuperview];
[HUD release];
HUD = nil;
}
-(void) receivedResponse:(NSDictionary *)response{
NSLog(@"receivedResponse");
}
- (void)dealloc {
[imageTitle release];
[imageDescription release];
[statusBar release];
[imageOriginal release];
[imageFiltered release];
[statusBar release];
[detailsPictureTable release];
[titleTextField release];
[descriptionTextField release];
[permissionPicture release];
[highResolutionPicture release];
[gpsPosition release];
[self.service release];
[coreLocationController release];
[location release];
[super dealloc];
}
@end