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

Reply via email to