http://www.mediawiki.org/wiki/Special:Code/MediaWiki/84892
Revision: 84892 Author: hartman Date: 2011-03-27 23:15:34 +0000 (Sun, 27 Mar 2011) Log Message: ----------- Add support for uploading with GPS and EXIF Modified Paths: -------------- trunk/tools/WikiSnaps/Classes/CommonsUpload.h trunk/tools/WikiSnaps/Classes/CommonsUpload.m trunk/tools/WikiSnaps/Classes/Configuration.h trunk/tools/WikiSnaps/Classes/ImageDetailsViewController.m trunk/tools/WikiSnaps/Classes/ImageUploadViewController.m trunk/tools/WikiSnaps/Classes/LicensePickerViewController.m trunk/tools/WikiSnaps/Classes/PhotoPickerAppDelegate.h trunk/tools/WikiSnaps/Classes/PhotoPickerAppDelegate.m trunk/tools/WikiSnaps/Classes/SettingsViewController.m trunk/tools/WikiSnaps/Classes/SourcePickerViewController.h trunk/tools/WikiSnaps/Classes/SourcePickerViewController.m trunk/tools/WikiSnaps/WikiSnaps.xcodeproj/project.pbxproj Modified: trunk/tools/WikiSnaps/Classes/CommonsUpload.h =================================================================== --- trunk/tools/WikiSnaps/Classes/CommonsUpload.h 2011-03-27 22:45:32 UTC (rev 84891) +++ trunk/tools/WikiSnaps/Classes/CommonsUpload.h 2011-03-27 23:15:34 UTC (rev 84892) @@ -20,8 +20,9 @@ @interface CommonsUpload : NSObject { - NSData *imageData; - NSString *title; + UIImage *originalImage; + NSURL *imageURL; + NSString *imageTitle; NSString *description; NSString *token; NSString *editToken; @@ -29,8 +30,9 @@ id <CommonsUploadDelegate> delegate; } -@property (nonatomic, retain) NSData *imageData; -@property (nonatomic, retain) NSString *title; +@property (nonatomic, retain) UIImage *originalImage; +@property (nonatomic, retain) NSURL *imageURL; +@property (nonatomic, retain) NSString *imageTitle; @property (nonatomic, retain) NSString *description; @property (nonatomic, assign) id <CommonsUploadDelegate> delegate; Modified: trunk/tools/WikiSnaps/Classes/CommonsUpload.m =================================================================== --- trunk/tools/WikiSnaps/Classes/CommonsUpload.m 2011-03-27 22:45:32 UTC (rev 84891) +++ trunk/tools/WikiSnaps/Classes/CommonsUpload.m 2011-03-27 23:15:34 UTC (rev 84892) @@ -8,6 +8,8 @@ // Dual-licensed MIT and BSD #import "CommonsUpload.h" +#import <AssetsLibrary/AssetsLibrary.h> + #import "Configuration.h" #import "ASIFormDataRequest.h" #import "XMLReader.h" @@ -23,8 +25,22 @@ @implementation CommonsUpload -@synthesize imageData, title, description, delegate; +@synthesize originalImage; +@synthesize imageURL; +@synthesize imageTitle; +@synthesize description; +@synthesize delegate; +- (void)dealloc { + self.originalImage = nil; + self.imageURL = nil; + self.imageTitle = nil; + self.description = nil; + self.delegate = nil; + + [super dealloc]; +} + - (NSString *)getUploadText { return @""; } @@ -60,14 +76,15 @@ NSLog(@"%@", dateString); - return [NSString stringWithFormat: @"{{Information\n|Description={{en|1=%@}}\n|Author=[[User:%@]]\n|Source={{own}}\n|Date=%@\n|Permission=\n|other_versions=\n}}\n\n== {{int:license}} ==\n%@\n\n[[Category:%@]]", - description, - [[NSUserDefaults standardUserDefaults] valueForKey: COMMONS_USERNAME_KEY], - dateString, - [self getLicenseString], - APPLICATION_CATEGORY, - nil + NSString *result = [NSString stringWithFormat: @"{{Information\n|Description={{en|1=%@}}\n|Author=[[User:%@]]\n|Source={{own}}\n|Date=%@\n|Permission=\n|other_versions=\n}}\n\n== {{int:license}} ==\n%@\n\n[[Category:%@]]", + self.description, + [[NSUserDefaults standardUserDefaults] stringForKey: COMMONS_USERNAME_KEY], + dateString, + [self getLicenseString], + APPLICATION_CATEGORY ]; + NSLog( @"%@", result ); + return result; } - (void)uploadImage { @@ -196,7 +213,7 @@ [newRequest addPostValue:@"query" forKey:@"action"]; [newRequest addPostValue:@"xml" forKey: @"format"]; [newRequest addPostValue:@"edit" forKey:@"intoken"]; - [newRequest addPostValue:title forKey:@"titles"]; + [newRequest addPostValue:self.imageTitle forKey:@"titles"]; [newRequest addPostValue:@"info" forKey:@"prop"]; [newRequest setDelegate:self]; @@ -242,7 +259,7 @@ return; } - editToken = [query objectForKey:@"edittoken"]; + editToken = [query objectForKey:@"edittoken"]; if( !editToken ) { [delegate uploadFailed: [NSString stringWithFormat:@"could not find edittoken"]]; return; @@ -250,18 +267,43 @@ //New request NSURL *url = [NSURL URLWithString:COMMONS_API_URL]; + NSString *uploadDescription = [self getUploadDescription]; ASIFormDataRequest *newRequest = [ASIFormDataRequest requestWithURL:url]; [newRequest setPostFormat:ASIMultipartFormDataPostFormat]; [newRequest addPostValue:@"upload" forKey:@"action"]; [newRequest addPostValue:@"xml" forKey: @"format"]; [newRequest addPostValue:editToken forKey:@"token"]; - [newRequest addPostValue:title forKey:@"filename"]; - [newRequest addPostValue:[self getUploadDescription] forKey:@"comment"]; - [newRequest addPostValue:[self getUploadDescription] forKey:@"text"]; - [newRequest addData:imageData forKey:@"file"]; + [newRequest addPostValue:self.imageTitle forKey:@"filename"]; + [newRequest addPostValue:uploadDescription forKey:@"comment"]; + [newRequest addPostValue:uploadDescription forKey:@"text"]; + if( self.imageURL == nil && self.originalImage != nil ) { + [newRequest addData:UIImageJPEGRepresentation(self.originalImage, 0.85f) forKey:@"file"]; + } else if ( self.imageURL ) { + ALAssetsLibrary *assetLib = [[[ALAssetsLibrary alloc] init] autorelease]; + ALAssetsLibraryAssetForURLResultBlock resultBlock = + ^(ALAsset *asset) { + ALAssetRepresentation *representation = [asset defaultRepresentation]; + Byte *buf = malloc([representation size]); + NSError *err = nil; + NSUInteger bytes = [representation getBytes:buf fromOffset:0LL length:[representation size] error:&err]; + if (err || bytes == 0) { + NSLog( @"Could not read asset: %@", err ); + } else { + NSData *cumbersomeWayToGetNSData = [NSData dataWithBytesNoCopy:buf length:[representation size] freeWhenDone:YES]; + [newRequest addData:cumbersomeWayToGetNSData forKey:@"file"]; + } + }; + + [assetLib assetForURL:self.imageURL resultBlock:resultBlock failureBlock:^(NSError *error) { + NSLog( @"Error finding asset: %@", error); + }]; + /* + NSData *tempData = [NSData dataWithContentsOfURL:self.imageURL]; + [newRequest addData:tempData forKey:@"file"]; + */ + } - [newRequest setDelegate:self]; [newRequest setDidFinishSelector:@selector(requestUploadFinished:)]; [newRequest setDidFailSelector:@selector(requestUploadFailed:)]; Modified: trunk/tools/WikiSnaps/Classes/Configuration.h =================================================================== --- trunk/tools/WikiSnaps/Classes/Configuration.h 2011-03-27 22:45:32 UTC (rev 84891) +++ trunk/tools/WikiSnaps/Classes/Configuration.h 2011-03-27 23:15:34 UTC (rev 84892) @@ -13,6 +13,7 @@ #define COMMONS_USERNAME_KEY @"CommonsUsernameKey" #define COMMONS_LICENSE_KEY @"CommonsLicenseKey" #define COMMONS_KEYCHAIN_KEY @"CommonsKey" +#define GEOTAGGING_KEY @"GeoTaggingKey" // Constants #define COMMONS_DESTINATION_URL @"http://commons.wikimedia.org/wiki/File:%@" Modified: trunk/tools/WikiSnaps/Classes/ImageDetailsViewController.m =================================================================== --- trunk/tools/WikiSnaps/Classes/ImageDetailsViewController.m 2011-03-27 22:45:32 UTC (rev 84891) +++ trunk/tools/WikiSnaps/Classes/ImageDetailsViewController.m 2011-03-27 23:15:34 UTC (rev 84892) @@ -63,9 +63,9 @@ - (void)dealloc { - [titleField release]; - [descriptionText release]; - [upload release]; + self.titleField = nil; + self.descriptionText = nil; + self.upload = nil; [super dealloc]; } @@ -76,11 +76,11 @@ -(void)textFieldDidEndEditing:(id)sender { if(sender == titleField ) { /* Verify name */ - if( ![upload verifyTitle: titleField.text] ) { - titleField.textColor = [UIColor redColor]; + if( ![self.upload verifyTitle: self.titleField.text] ) { + self.titleField.textColor = [UIColor redColor]; } else { - titleField.textColor = [UIColor blackColor]; - [descriptionText becomeFirstResponder]; + self.titleField.textColor = [UIColor blackColor]; + [self.descriptionText becomeFirstResponder]; } return; } @@ -94,12 +94,12 @@ } - (void)doUpload:(id)sender { - upload.title = [NSString stringWithFormat: @"%@.jpg", titleField.text]; - upload.description = descriptionText.text; - [descriptionText resignFirstResponder]; + self.upload.imageTitle = [NSString stringWithFormat: @"%@.jpg", self.titleField.text]; + self.upload.description = self.descriptionText.text; + [self.descriptionText resignFirstResponder]; ImageUploadViewController *uploadViewController = [[ImageUploadViewController alloc] init]; - uploadViewController.upload = upload; + uploadViewController.upload = self.upload; [self.navigationController pushViewController:uploadViewController animated:YES]; [uploadViewController release]; } Modified: trunk/tools/WikiSnaps/Classes/ImageUploadViewController.m =================================================================== --- trunk/tools/WikiSnaps/Classes/ImageUploadViewController.m 2011-03-27 22:45:32 UTC (rev 84891) +++ trunk/tools/WikiSnaps/Classes/ImageUploadViewController.m 2011-03-27 23:15:34 UTC (rev 84892) @@ -33,16 +33,16 @@ - (void)viewDidLoad { [super viewDidLoad]; - uploadOverlayImage.image = [UIImage imageWithData:upload.imageData]; + uploadOverlayImage.image = self.upload.originalImage; uploadProgressMessage.text = NSLocalizedString( @"uploading", @"Upload progress message" ); uploadProgress.progress = 0.0f; // view.frame = CGRectMake(0, 20, 320, 460); - // [[UIApplication sharedApplication].keyWindow addSubview:uploadPhotoOverlay]; + // [[UIApplication sharedApplication].keyWindow addSubview:PhotoOverlay]; // Start the actual upload - upload.delegate = self; - [upload uploadImage]; + [self.upload setDelegate: self]; + [self.upload uploadImage]; } - (void) viewWillAppear:(BOOL)animated{ @@ -77,7 +77,7 @@ - (void)dealloc { - [upload release]; + self.upload = nil; [super dealloc]; } @@ -92,8 +92,8 @@ [[UIAlertView alloc] initWithTitle: NSLocalizedString( @"Upload succeeded", @"Title for upload succeeded alert" ) message: nil delegate: self - cancelButtonTitle: NSLocalizedString( @"Show upload", @"Title for Show upload button in alert view after upload succeeded" ) - otherButtonTitles: nil]; + cancelButtonTitle: NSLocalizedString( @"Cancel", @"" ) + otherButtonTitles: NSLocalizedString( @"Show upload", @"Title for Show upload button in alert view after upload succeeded" ),nil]; [alert show]; [alert release]; } @@ -104,8 +104,12 @@ } - (void) alertView: (UIAlertView *) alertView clickedButtonAtIndex: (NSInteger) buttonIndex { - [[UIApplication sharedApplication] openURL:[NSURL URLWithString: [NSString stringWithFormat: COMMONS_DESTINATION_URL, [upload.title stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]]]; - //[self.navigationController popToRootViewControllerAnimated:YES]; + if( buttonIndex == 0 ) { + NSLog( @"Cancel" ); + } else if ( buttonIndex == 1 ) { + [[UIApplication sharedApplication] openURL:[NSURL URLWithString: [NSString stringWithFormat: COMMONS_DESTINATION_URL, [self.upload.imageTitle stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]]]; + } + [self.navigationController popToRootViewControllerAnimated:YES]; } // clickedButtonAtIndex Modified: trunk/tools/WikiSnaps/Classes/LicensePickerViewController.m =================================================================== --- trunk/tools/WikiSnaps/Classes/LicensePickerViewController.m 2011-03-27 22:45:32 UTC (rev 84891) +++ trunk/tools/WikiSnaps/Classes/LicensePickerViewController.m 2011-03-27 23:15:34 UTC (rev 84892) @@ -34,9 +34,9 @@ dismissButton.action = @selector( dismissLicensePicker: ); [pickerControl selectRow:selectedLicense inComponent:0 animated: NO]; - NSDictionary *aLicense = [licenses objectAtIndex:selectedLicense]; - pickerLabel.text = [aLicense objectForKey:@"name"]; - [descriptionText loadHTMLString: [aLicense objectForKey:@"description"] baseURL: nil]; + NSDictionary *aLicense = [self.licenses objectAtIndex:selectedLicense]; + self.pickerLabel.text = [aLicense objectForKey:@"name"]; + [self.descriptionText loadHTMLString: [aLicense objectForKey:@"description"] baseURL: nil]; } @@ -63,13 +63,18 @@ - (void)dealloc { + self.descriptionText = nil; + self.pickerLabel = nil; + self.licenses = nil; + self.delegate = nil; + [super dealloc]; } #pragma mark Actions - (IBAction) dismissLicensePicker: (id) sender { - [delegate licensePickerDidFinish: [pickerControl selectedRowInComponent:0]]; + [self.delegate licensePickerDidFinish: [pickerControl selectedRowInComponent:0]]; } #pragma mark UIPickerViewDelegate @@ -78,7 +83,7 @@ titleForRow: (NSInteger)row forComponent: (NSInteger)component { - NSDictionary *dict = [licenses objectAtIndex:row]; + NSDictionary *dict = [self.licenses objectAtIndex:row]; if( dict != nil ) { return [dict objectForKey:@"short"]; } @@ -89,10 +94,10 @@ didSelectRow:(NSInteger)row inComponent:(NSInteger)component { - NSDictionary *dict = [licenses objectAtIndex:row]; + NSDictionary *dict = [self.licenses objectAtIndex:row]; if( dict != nil ) { - pickerLabel.text = [dict objectForKey:@"name"]; - [descriptionText loadHTMLString: [dict objectForKey:@"description"] baseURL: nil]; + self.pickerLabel.text = [dict objectForKey:@"name"]; + [self.descriptionText loadHTMLString: [dict objectForKey:@"description"] baseURL: nil]; } } @@ -106,7 +111,7 @@ - (NSInteger)pickerView: (UIPickerView *)aPickerView numberOfRowsInComponent: (NSInteger)component { - NSInteger numberOfRows = [licenses count]; + NSInteger numberOfRows = [self.licenses count]; return numberOfRows; } Modified: trunk/tools/WikiSnaps/Classes/PhotoPickerAppDelegate.h =================================================================== --- trunk/tools/WikiSnaps/Classes/PhotoPickerAppDelegate.h 2011-03-27 22:45:32 UTC (rev 84891) +++ trunk/tools/WikiSnaps/Classes/PhotoPickerAppDelegate.h 2011-03-27 23:15:34 UTC (rev 84892) @@ -8,6 +8,7 @@ // Based on Photopicker (MIT) #import <UIKit/UIKit.h> +#import <CoreLocation/CoreLocation.h> #import "Configuration.h" @@ -15,27 +16,37 @@ @class PhotoPickerViewController; -@interface PhotoPickerAppDelegate : NSObject <UIApplicationDelegate> { +@interface PhotoPickerAppDelegate : NSObject <UIApplicationDelegate, + CLLocationManagerDelegate> { int defaultImageSource; BOOL justInstalled; + NSString *postContext; UIWindow *window; PhotoPickerViewController *viewController; UINavigationController *navController; + NSArray *licenses; + + CLLocationManager *locationManager; + CLLocation *lastLocation; } -@property (nonatomic, assign) int defaultImageSource; +@property int defaultImageSource; // Checking the justInstalled property could be useful if you want to point the somewhere special // the first time they run the app. -@property (nonatomic, assign) BOOL justInstalled; +@property BOOL justInstalled; @property (nonatomic, retain) NSString *postContext; @property (nonatomic, retain) IBOutlet PhotoPickerViewController *viewController; @property (nonatomic, retain) IBOutlet UINavigationController *navController; @property (nonatomic, retain) IBOutlet UIWindow *window; + @property (nonatomic, retain) NSArray *licenses; +@property (nonatomic, assign) CLLocationManager *locationManager; +@property (nonatomic, retain) CLLocation *lastLocation; + @end Modified: trunk/tools/WikiSnaps/Classes/PhotoPickerAppDelegate.m =================================================================== --- trunk/tools/WikiSnaps/Classes/PhotoPickerAppDelegate.m 2011-03-27 22:45:32 UTC (rev 84891) +++ trunk/tools/WikiSnaps/Classes/PhotoPickerAppDelegate.m 2011-03-27 23:15:34 UTC (rev 84892) @@ -12,6 +12,8 @@ @interface PhotoPickerAppDelegate () - (void)checkIfJustInstalled; + - (void)startLocationUpdates; + - (void)stopLocationUpdates; @end @@ -22,10 +24,11 @@ @synthesize postContext; @synthesize viewController; @synthesize navController; -@synthesize window; @synthesize licenses; +@synthesize locationManager, lastLocation; + - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { @@ -34,28 +37,100 @@ self.defaultImageSource = -1; NSString *path = [[NSBundle mainBundle] pathForResource:@"Licenses" ofType:@"plist"]; - licenses = [[NSMutableArray alloc] initWithContentsOfFile:path]; - if( licenses == nil ) { + self.licenses = [[NSMutableArray alloc] initWithContentsOfFile:path]; + if( self.licenses == nil ) { NSLog( @"Could not load the licenses information" ); } [window addSubview:navController.view]; [window makeKeyAndVisible]; - + + [self startLocationUpdates]; return YES; } +- (void)applicationWillTerminate:(UIApplication *)application { + [self stopLocationUpdates]; +} +- (void)applicationWillEnterForeground:(UIApplication *)application { + [self startLocationUpdates]; +} + + +- (void)applicationDidEnterBackground:(UIApplication *)application { + [self stopLocationUpdates]; +} + + - (void)dealloc { self.viewController = nil; self.navController = nil; self.window = nil; - [licenses release]; + self.licenses = nil; + self.lastLocation = nil; [super dealloc]; } +#pragma mark Location services +- (void)startLocationUpdates { + // Create the location manager if this object does not + // already have one. + if( [CLLocationManager locationServicesEnabled] && + //[[NSUserDefaults standardUserDefaults] boolForKey: GEOTAGGING_KEY] ) + TRUE ) + { + if (nil == self.locationManager) + self.locationManager = [[CLLocationManager alloc] init]; + + self.locationManager.delegate = self; + self.locationManager.desiredAccuracy = kCLLocationAccuracyKilometer; + + // Set a movement threshold for new events. + self.locationManager.distanceFilter = 500; + + [self.locationManager startUpdatingLocation]; + + if( [self.locationManager headingAvailable] ) { + [self.locationManager startUpdatingHeading]; + } + } +} +- (void)stopLocationUpdates { + if( self.locationManager != nil ) { + [self.locationManager stopUpdatingHeading]; + [self.locationManager stopUpdatingLocation]; + [self.locationManager release]; + self.locationManager = nil; + } +} + +#pragma mark LocationManager Delegate + +// Delegate method from the CLLocationManagerDelegate protocol. +- (void)locationManager:(CLLocationManager *)manager + didUpdateToLocation:(CLLocation *)newLocation + fromLocation:(CLLocation *)oldLocation +{ + // If it's a relatively recent event, turn off updates to save power + NSDate* eventDate = newLocation.timestamp; + NSTimeInterval howRecent = [eventDate timeIntervalSinceNow]; + if (abs(howRecent) < 15.0) + { + NSLog(@"latitude %+.6f, longitude %+.6f\n", + newLocation.coordinate.latitude, + newLocation.coordinate.longitude); + } + self.lastLocation = newLocation; +} + +- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error +{ + NSLog(@"%@", error ); +} + #pragma mark Private @@ -66,6 +141,7 @@ if (!testForInstallKey) { self.justInstalled = YES; [defaults setBool:YES forKey:@"installed"]; + [defaults setBool:NO forKey:GEOTAGGING_KEY]; } } Modified: trunk/tools/WikiSnaps/Classes/SettingsViewController.m =================================================================== --- trunk/tools/WikiSnaps/Classes/SettingsViewController.m 2011-03-27 22:45:32 UTC (rev 84891) +++ trunk/tools/WikiSnaps/Classes/SettingsViewController.m 2011-03-27 23:15:34 UTC (rev 84892) @@ -43,8 +43,8 @@ PhotoPickerAppDelegate *appDelegate = (PhotoPickerAppDelegate *) [UIApplication sharedApplication].delegate; - licenses = appDelegate.licenses; - selectedLicense = 0; + self.licenses = appDelegate.licenses; + self.selectedLicense = 0; [self loadData]; @@ -97,33 +97,36 @@ - (void)dealloc { - [username release]; - [password release]; - [license release]; - [save release]; + self.username = nil; + self.password = nil; + self.license = nil; + self.save = nil; + + self.licenses = nil; + [super dealloc]; } #pragma mark Data loading and saving - (void)loadData { - username.text = [[NSUserDefaults standardUserDefaults] valueForKey: COMMONS_USERNAME_KEY]; + self.username.text = [[NSUserDefaults standardUserDefaults] valueForKey: COMMONS_USERNAME_KEY]; NSString *licenseDefault = [[NSUserDefaults standardUserDefaults] stringForKey: COMMONS_LICENSE_KEY]; - NSEnumerator *enumerator = [licenses objectEnumerator]; + NSEnumerator *enumerator = [self.licenses objectEnumerator]; NSDictionary *aLicense; while( licenseDefault != nil && (aLicense = [enumerator nextObject]) ) { if( [licenseDefault compare: [aLicense objectForKey:@"short"]] == NSOrderedSame ) { - license.text = [aLicense objectForKey:@"name"]; + self.license.text = [aLicense objectForKey:@"name"]; break; } - selectedLicense++; + self.selectedLicense++; } - if( selectedLicense == [licenses count] ) - selectedLicense = 0; + if( self.selectedLicense == [self.licenses count] ) + self.selectedLicense = 0; NSError *error = nil; - password.text = [SFHFKeychainUtils getPasswordForUsername:username.text andServiceName:COMMONS_KEYCHAIN_KEY error: &error]; + self.password.text = [SFHFKeychainUtils getPasswordForUsername:username.text andServiceName:COMMONS_KEYCHAIN_KEY error: &error]; if( error ) { NSLog( @"pasword storage problem: %@", [error localizedDescription] ); } @@ -132,7 +135,7 @@ - (void)saveData { NSError *error = nil; NSString *oldUsername = [[NSUserDefaults standardUserDefaults] valueForKey: COMMONS_USERNAME_KEY]; - if( [username.text compare:oldUsername] != NSOrderedSame ) { + if( [self.username.text compare:oldUsername] != NSOrderedSame ) { /* Delete password for previous username */ [SFHFKeychainUtils deleteItemForUsername:oldUsername andServiceName:COMMONS_KEYCHAIN_KEY error:&error]; if( error ) { @@ -142,13 +145,13 @@ } /* Save the data */ - [[NSUserDefaults standardUserDefaults] setObject:username.text forKey:COMMONS_USERNAME_KEY]; + [[NSUserDefaults standardUserDefaults] setObject:self.username.text forKey:COMMONS_USERNAME_KEY]; - NSDictionary *aLicense = [licenses objectAtIndex:selectedLicense]; + NSDictionary *aLicense = [self.licenses objectAtIndex:self.selectedLicense]; [[NSUserDefaults standardUserDefaults] setObject:[aLicense objectForKey:@"short"] forKey:COMMONS_LICENSE_KEY]; /* Store the password in the keychain */ - [SFHFKeychainUtils storeUsername: username.text andPassword: password.text forServiceName:COMMONS_KEYCHAIN_KEY updateExisting: YES error: &error]; + [SFHFKeychainUtils storeUsername: self.username.text andPassword: self.password.text forServiceName:COMMONS_KEYCHAIN_KEY updateExisting: YES error: &error]; if( error ) { NSLog( @"pasword storage problem: %@", [error localizedDescription] ); @@ -169,7 +172,7 @@ - (IBAction)textFieldDidEnd:(id)sender { if(sender == username ) { - [password becomeFirstResponder]; + [self.password becomeFirstResponder]; return; } [sender resignFirstResponder]; @@ -186,8 +189,8 @@ - (IBAction) pickLicensePicker:(id)sender{ LicensePickerViewController *picker = [[LicensePickerViewController alloc] initWithNibName:@"LicensePickerViewController" bundle:nil]; picker.delegate = self; - picker.licenses = licenses; - picker.selectedLicense = selectedLicense; + picker.licenses = self.licenses; + picker.selectedLicense = self.selectedLicense; [self presentModalViewController:picker animated:YES]; [picker release]; } @@ -196,8 +199,8 @@ -(void)licensePickerDidFinish:(int)theSelectedLicense { NSDictionary *licenseDict = [licenses objectAtIndex:theSelectedLicense]; - license.text = [licenseDict objectForKey:@"name"]; - selectedLicense = theSelectedLicense; + self.license.text = [licenseDict objectForKey:@"name"]; + self.selectedLicense = theSelectedLicense; [self dismissModalViewControllerAnimated:YES]; } Modified: trunk/tools/WikiSnaps/Classes/SourcePickerViewController.h =================================================================== --- trunk/tools/WikiSnaps/Classes/SourcePickerViewController.h 2011-03-27 22:45:32 UTC (rev 84891) +++ trunk/tools/WikiSnaps/Classes/SourcePickerViewController.h 2011-03-27 23:15:34 UTC (rev 84892) @@ -13,13 +13,17 @@ #import "Configuration.h" @interface SourcePickerViewController : UITableViewController <UINavigationControllerDelegate, - UIImagePickerControllerDelegate> { + UIImagePickerControllerDelegate> +{ + UIImagePickerController *imagePicker; BOOL cameraAvailable; BOOL fakeCameraAvailable; - NSData *imageData; + UIImage *image; NSArray *licenses; } +@property (nonatomic, retain) UIImage *image; +@property (nonatomic, retain) UIImagePickerController *imagePicker; - (IBAction)settingsPressed:(id)sender; - (IBAction)infoPressed:(id)sender; Modified: trunk/tools/WikiSnaps/Classes/SourcePickerViewController.m =================================================================== --- trunk/tools/WikiSnaps/Classes/SourcePickerViewController.m 2011-03-27 22:45:32 UTC (rev 84891) +++ trunk/tools/WikiSnaps/Classes/SourcePickerViewController.m 2011-03-27 23:15:34 UTC (rev 84892) @@ -9,6 +9,8 @@ // Based on Photopicker (MIT) #import "PhotoPickerAppDelegate.h" +#import <AssetsLibrary/AssetsLibrary.h> +#import <ImageIO/ImageIO.h> #import "SourcePickerViewController.h" #import "SettingsViewController.h" @@ -24,13 +26,14 @@ /* Private */ @interface SourcePickerViewController () - @property (nonatomic, retain) NSData *imageData; - (void)pickPhoto:(UIImagePickerControllerSourceType)sourceType; + - (void)detailsForImageWithURL:(NSURL *)assetURL; @end @implementation SourcePickerViewController -@synthesize imageData; +@synthesize image; +@synthesize imagePicker; #pragma mark - #pragma mark Actions @@ -63,8 +66,8 @@ /* Open a photopicker */ - (void)pickPhoto:(UIImagePickerControllerSourceType)sourceType { - UIImagePickerController *imagePickerController = [[UIImagePickerController alloc] init]; - imagePickerController.delegate = self; + self.imagePicker = [[[UIImagePickerController alloc] init] autorelease]; + self.imagePicker.delegate = self; // If the camera is force enabled, show the library instead. #ifdef FORCE_ENABLE_CAMERA @@ -73,13 +76,68 @@ } #endif - imagePickerController.sourceType = sourceType; + self.imagePicker.sourceType = sourceType; // imagePickerController.allowsImageEditing = YES; - - [self presentModalViewController:imagePickerController animated:YES]; - [imagePickerController release]; + + [self presentModalViewController:self.imagePicker animated:YES]; } +- (NSMutableDictionary*)currentLocation { + NSMutableDictionary *locDict = [[NSMutableDictionary alloc] init]; + PhotoPickerAppDelegate *appDelegate = + (PhotoPickerAppDelegate *) [UIApplication sharedApplication].delegate; + CLLocation *lastLocation = appDelegate.lastLocation; + + if (lastLocation != nil) { + CLLocationDegrees exifLatitude = lastLocation.coordinate.latitude; + CLLocationDegrees exifLongitude = lastLocation.coordinate.longitude; + CLLocationDistance exifAltitude = lastLocation.altitude; + + [locDict setObject:@"2.2.0.0" forKey:(NSString *)kCGImagePropertyGPSVersion]; + [locDict setObject:lastLocation.timestamp forKey:(NSString*)kCGImagePropertyGPSTimeStamp]; + + if (exifLatitude < 0.0) { + exifLatitude = exifLatitude*(-1); + [locDict setObject:@"S" forKey:(NSString*)kCGImagePropertyGPSLatitudeRef]; + } else { + [locDict setObject:@"N" forKey:(NSString*)kCGImagePropertyGPSLatitudeRef]; + } + [locDict setObject:[NSNumber numberWithFloat:exifLatitude] forKey:(NSString*)kCGImagePropertyGPSLatitude]; + + if (exifLongitude < 0.0) { + exifLongitude=exifLongitude*(-1); + [locDict setObject:@"W" forKey:(NSString*)kCGImagePropertyGPSLongitudeRef]; + } else { + [locDict setObject:@"E" forKey:(NSString*)kCGImagePropertyGPSLongitudeRef]; + } + [locDict setObject:[NSNumber numberWithFloat:exifLongitude] forKey:(NSString*) kCGImagePropertyGPSLongitude]; + + if (!isnan(exifAltitude)){ + if (exifAltitude < 0) { + exifAltitude = -exifAltitude; + [locDict setObject:@"1" forKey:(NSString *)kCGImagePropertyGPSAltitudeRef]; + } else { + [locDict setObject:@"0" forKey:(NSString *)kCGImagePropertyGPSAltitudeRef]; + } + [locDict setObject:[NSNumber numberWithFloat:exifAltitude] forKey:(NSString *)kCGImagePropertyGPSAltitude]; + } + + // Speed, must be converted from m/s to km/h + if (lastLocation.speed >= 0){ + [locDict setObject:@"K" forKey:(NSString *)kCGImagePropertyGPSSpeedRef]; + [locDict setObject:[NSNumber numberWithFloat:lastLocation.speed*3.6] forKey:(NSString *)kCGImagePropertyGPSSpeed]; + } + + // Heading + if (lastLocation.course >= 0){ + [locDict setObject:@"T" forKey:(NSString *)kCGImagePropertyGPSTrackRef]; + [locDict setObject:[NSNumber numberWithFloat:lastLocation.course] forKey:(NSString *)kCGImagePropertyGPSTrack]; + } + } + + return [locDict autorelease]; +} + #pragma mark - #pragma mark View lifecycle @@ -214,18 +272,42 @@ didFinishPickingMediaWithInfo:(NSDictionary *)info { NSLog(@"Image info: %@",info); - UIImage *image = [info valueForKey:UIImagePickerControllerOriginalImage]; + self.image = [info valueForKey:UIImagePickerControllerOriginalImage]; + NSURL *imageURL = [info valueForKey:UIImagePickerControllerMediaURL]; + NSMutableDictionary *metaData = [NSMutableDictionary dictionaryWithDictionary:[info valueForKey:UIImagePickerControllerMediaMetadata]]; - image = [image correctOrientation:image]; + [metaData setObject:[self currentLocation] forKey: (NSString *)kCGImagePropertyGPSDictionary]; // Store the image on the Camera Roll if( picker.sourceType == UIImagePickerControllerSourceTypeCamera ) { - UIImageWriteToSavedPhotosAlbum( image, nil, nil, nil ); + Class assestsLibClass = (NSClassFromString(@"ALAssetsLibrary")); + if( assestsLibClass != nil ) { + ALAssetsLibrary *library = [[[ALAssetsLibrary alloc] init] autorelease]; + + ALAssetsLibraryWriteImageCompletionBlock completionBlock = ^(NSURL *newURL, NSError *error) { + if (error) { + NSLog( @"Could not write image to photoalbum: %@", error ); + } else { + [self detailsForImageWithURL: newURL]; + } + }; + + [library writeImageToSavedPhotosAlbum:[self.image CGImage] metadata:metaData completionBlock:completionBlock]; + return; + } else { + self.image = [self.image correctOrientation:self.image]; + UIImageWriteToSavedPhotosAlbum( self.image, nil, nil, nil ); + } } + [self detailsForImageWithURL: imageURL]; +} + +- (void)detailsForImageWithURL:(NSURL *)assetURL { // Prepare upload CommonsUpload *ourUpload = [[CommonsUpload alloc] init]; - ourUpload.imageData = UIImageJPEGRepresentation(image, 0.85f); + ourUpload.originalImage = self.image; + ourUpload.imageURL = assetURL; ImageDetailsViewController *detailsController = [[ImageDetailsViewController alloc] init]; @@ -235,8 +317,8 @@ //to push the UIView. [self.navigationController pushViewController:detailsController animated:YES]; [detailsController release]; - - [picker dismissModalViewControllerAnimated:YES]; + + [self dismissModalViewControllerAnimated:YES]; } @@ -252,7 +334,7 @@ if (shouldCancelApp) { //[self cancelApp]; } else { - [picker dismissModalViewControllerAnimated:YES]; + [self dismissModalViewControllerAnimated:YES]; //[self showPhotoSourceMenuOrPhotoSourceDirectly]; } @@ -275,6 +357,8 @@ - (void)dealloc { + self.image = nil; + self.imagePicker = nil; [super dealloc]; } Modified: trunk/tools/WikiSnaps/WikiSnaps.xcodeproj/project.pbxproj =================================================================== --- trunk/tools/WikiSnaps/WikiSnaps.xcodeproj/project.pbxproj 2011-03-27 22:45:32 UTC (rev 84891) +++ trunk/tools/WikiSnaps/WikiSnaps.xcodeproj/project.pbxproj 2011-03-27 23:15:34 UTC (rev 84892) @@ -25,6 +25,9 @@ 4971EC87133E77FD0043DD67 /* Licenses.plist in Resources */ = {isa = PBXBuildFile; fileRef = 4971EC86133E77FD0043DD67 /* Licenses.plist */; }; 4971ED31133E9DD90043DD67 /* LicensePickerViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4971ED2F133E9DD90043DD67 /* LicensePickerViewController.m */; }; 4971ED32133E9DD90043DD67 /* LicensePickerViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4971ED30133E9DD90043DD67 /* LicensePickerViewController.xib */; }; + 49E03406133F6C1300BFE247 /* CoreLocation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 49E03405133F6C1300BFE247 /* CoreLocation.framework */; }; + 49E0340A133F72A100BFE247 /* AssetsLibrary.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 49E03409133F72A100BFE247 /* AssetsLibrary.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; + 49E03463133F814D00BFE247 /* ImageIO.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 49E03462133F814D00BFE247 /* ImageIO.framework */; }; A127DA4012E0DF9700149FC9 /* SettingsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = A127DA3E12E0DF9700149FC9 /* SettingsViewController.m */; }; A127DA4112E0DF9700149FC9 /* SettingsViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = A127DA3F12E0DF9700149FC9 /* SettingsViewController.xib */; }; A1338B8612E0F01700662B28 /* ASIAuthenticationDialog.m in Sources */ = {isa = PBXBuildFile; fileRef = A1338B7312E0F01700662B28 /* ASIAuthenticationDialog.m */; }; @@ -80,6 +83,9 @@ 4971ED2E133E9DD90043DD67 /* LicensePickerViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LicensePickerViewController.h; sourceTree = "<group>"; }; 4971ED2F133E9DD90043DD67 /* LicensePickerViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LicensePickerViewController.m; sourceTree = "<group>"; }; 4971ED30133E9DD90043DD67 /* LicensePickerViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = LicensePickerViewController.xib; path = Classes/LicensePickerViewController.xib; sourceTree = "<group>"; }; + 49E03405133F6C1300BFE247 /* CoreLocation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreLocation.framework; path = System/Library/Frameworks/CoreLocation.framework; sourceTree = SDKROOT; }; + 49E03409133F72A100BFE247 /* AssetsLibrary.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AssetsLibrary.framework; path = System/Library/Frameworks/AssetsLibrary.framework; sourceTree = SDKROOT; }; + 49E03462133F814D00BFE247 /* ImageIO.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ImageIO.framework; path = System/Library/Frameworks/ImageIO.framework; sourceTree = SDKROOT; }; 8D1107310486CEB800E47090 /* WikiSnaps-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "WikiSnaps-Info.plist"; plistStructureDefinitionIdentifier = "com.apple.xcode.plist.structure-definition.iphone.info-plist"; sourceTree = "<group>"; }; A127DA3D12E0DF9700149FC9 /* SettingsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SettingsViewController.h; sourceTree = "<group>"; }; A127DA3E12E0DF9700149FC9 /* SettingsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SettingsViewController.m; sourceTree = "<group>"; }; @@ -142,6 +148,9 @@ A159144712E0F69C0003BBE2 /* MobileCoreServices.framework in Frameworks */, A159144B12E0F6BE0003BBE2 /* SystemConfiguration.framework in Frameworks */, 49354963130096A000A7A44E /* Security.framework in Frameworks */, + 49E03406133F6C1300BFE247 /* CoreLocation.framework in Frameworks */, + 49E0340A133F72A100BFE247 /* AssetsLibrary.framework in Frameworks */, + 49E03463133F814D00BFE247 /* ImageIO.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -231,6 +240,9 @@ A159144612E0F69C0003BBE2 /* MobileCoreServices.framework */, A159144A12E0F6BE0003BBE2 /* SystemConfiguration.framework */, 49354962130096A000A7A44E /* Security.framework */, + 49E03405133F6C1300BFE247 /* CoreLocation.framework */, + 49E03409133F72A100BFE247 /* AssetsLibrary.framework */, + 49E03462133F814D00BFE247 /* ImageIO.framework */, ); name = Frameworks; sourceTree = "<group>"; _______________________________________________ MediaWiki-CVS mailing list MediaWiki-CVS@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-cvs