Merge lp:~urbanape/ubuntuone-ios-files/auto-uploads-view into lp:ubuntuone-ios-files

Proposed by Zachery Bir
Status: Merged
Merge reported by: Zachery Bir
Merged at revision: not available
Proposed branch: lp:~urbanape/ubuntuone-ios-files/auto-uploads-view
Merge into: lp:ubuntuone-ios-files
Diff against target: 7414 lines (+5251/-436)
67 files modified
.bzrignore (+1/-0)
Dependencies/RIButtonItem.h (+23/-0)
Dependencies/RIButtonItem.m (+28/-0)
Dependencies/Reachability/Reachability.h (+88/-0)
Dependencies/Reachability/Reachability.m (+274/-0)
Dependencies/TestFlightSDK/README.txt (+167/-0)
Dependencies/TestFlightSDK/TestFlight.h (+44/-0)
Dependencies/TestFlightSDK/release_notes.txt (+41/-0)
Dependencies/UIActionSheet+Blocks.h (+16/-0)
Dependencies/UIActionSheet+Blocks.m (+71/-0)
Dependencies/UIAlertView+Blocks.h (+16/-0)
Dependencies/UIAlertView+Blocks.m (+61/-0)
Dependencies/oauthconsumer/Crypto/sha1.c (+2/-0)
Dependencies/oauthconsumer/OAMutableURLRequest.m (+2/-2)
Dependencies/oauthconsumer/OAToken.m (+1/-1)
Dependencies/oauthconsumer/OATokenManager.m (+3/-1)
Files.xcodeproj/project.pbxproj (+210/-9)
Files/Entitlements.plist (+14/-0)
Files/Files-Info.plist (+22/-6)
Files/Files-Prefix.pch (+6/-2)
Files/FilesAppDelegate.h (+5/-2)
Files/FilesAppDelegate.m (+147/-68)
Files/Generated/_U1Asset.h (+111/-0)
Files/Generated/_U1Asset.m (+98/-0)
Files/Generated/_U1FileNode.h (+13/-0)
Files/Generated/_U1FileNode.m (+4/-0)
Files/Generated/_U1Volume.h (+16/-1)
Files/Generated/_U1Volume.m (+7/-0)
Files/NSDictionary+U1Additions.h (+23/-0)
Files/NSDictionary+U1Additions.m (+29/-0)
Files/U1Asset.h (+5/-0)
Files/U1Asset.m (+7/-0)
Files/U1AssetUploadOperation.h (+32/-0)
Files/U1AssetUploadOperation.m (+103/-0)
Files/U1ByteSizeValueTransformer.m (+1/-1)
Files/U1DataRepository.h (+5/-1)
Files/U1DataRepository.m (+23/-0)
Files/U1FileNode.m (+3/-5)
Files/U1FilePreviewViewController.h (+2/-1)
Files/U1FilePreviewViewController.m (+78/-2)
Files/U1FilePreviewViewController.xib (+120/-35)
Files/U1Files.xcdatamodeld/.xccurrentversion (+1/-1)
Files/U1FilesClient.h (+11/-3)
Files/U1FilesClient.m (+207/-45)
Files/U1FilesService.h (+8/-3)
Files/U1FilesService.m (+86/-7)
Files/U1FolderNode.m (+1/-1)
Files/U1FolderViewController.m (+44/-16)
Files/U1LocalAssetsManager.h (+33/-0)
Files/U1LocalAssetsManager.m (+354/-0)
Files/U1LocalAssetsViewController.h (+43/-0)
Files/U1LocalAssetsViewController.m (+420/-0)
Files/U1LocalAssetsViewController.xib (+391/-0)
Files/U1Node.m (+10/-10)
Files/U1SettingsViewController.h (+38/-0)
Files/U1SettingsViewController.m (+264/-0)
Files/U1SettingsViewController.xib (+632/-0)
Files/U1UTIMapper.h (+22/-0)
Files/U1UTIMapper.m (+63/-0)
Files/U1Volume.h (+19/-1)
Files/U1Volume.m (+58/-1)
Files/U1VolumesViewController.h (+5/-3)
Files/U1VolumesViewController.m (+186/-41)
Files/U1VolumesViewController.xib (+45/-33)
Files/default-settings.plist (+14/-0)
Files/iPhone/en.lproj/MainWindow_iPhone.xib (+340/-134)
Files/uti-mappings.plist (+34/-0)
To merge this branch: bzr merge lp:~urbanape/ubuntuone-ios-files/auto-uploads-view
Reviewer Review Type Date Requested Status
Jason Foreman (community) Approve
Review via email: mp+80647@code.launchpad.net

Description of the change

Big branch that magically got bigger.

This branch handles auto-uploading of the iOS camera roll.

It also splits out the management view for this auto-upload behavior from the main folder browsing view, and incorporates a Settings view (TBD).

The default (and configurable) settings we *want* are:

  - Auto Upload [ Off ( On ) ]

    - Wifi Only [ Off ( On ) ]

    - Include Video [ ( Off ) On ]

Which we don't actually have yet.

To post a comment you must log in.
94. By Zachery Bir

Stupid Xcode

95. By Zachery Bir

Added so our apps can share Keychain access

96. By Zachery Bir

Up the build to 15, and fix the Bundle name

97. By Zachery Bir

Fix some crasher, redo how we handle the tab bar view controllers.

98. By Zachery Bir

Change "fetchNodeWithResourcePath" to "fetchFolderWithResourcePath" and add "fetchFileWithResourcePath" since the web returns a 403 (!?) for GETs on files with "?include_children=True" in the query string.

99. By Zachery Bir

Fix a crasher.

100. By Zachery Bir

Remove the class method that returns a UINavigationController, and use the new filesClient method

101. By Zachery Bir

Remove the class method that returns a UINavigationController

102. By Zachery Bir

Remove the class method that returns a UINavigationController, and use the new filesClient method

103. By Zachery Bir

Xcode kookiness.

104. By Zachery Bir

Handle uploads in batches of 50 assets at a time, and ditch all the debugging logging.

105. By Zachery Bir

Get rid of the commented out code.

When uploading a file, first try to fetch it. If there's something there at the same path, let's just skip it now. We can try to compare byte length later.

Properly handle the rest of the upload inside the ALAssetsLibrary assetForURL resultBlock.

106. By Zachery Bir

Added some dependency code for action sheets with blocks.

107. By Zachery Bir

Default preferences:

  asked_auto_upload_on_first_launch - whether we should display the alert view asking whether we should upload camera roll contents automatically (defaults to NO, obviously)

  auto_upload - whether we should upload camera roll contents automatically (defaults to NO)

  wifi_only - whether we should upload camera roll contents over 3G (defaults to YES)

  include_video - whether video files should be uploaded as well (defaults to NO)

108. By Zachery Bir

Interface layout for the settings view.

109. By Zachery Bir

Modified the Settings view to be owned by a nav controller

110. By Zachery Bir

Wire up the Settings view, and ask the user if she wants to enable automatically uploading camera roll contents.

111. By Zachery Bir

Use user preferences to determine whether we should upload the camera contents and whether we should include video

112. By Zachery Bir

Wire up the settings and make them clever enough that the wifi_only and include_video settings are disabled if auto_upload is disabled in the first place.

113. By Zachery Bir

New files.

114. By Zachery Bir

Write out preferences when we aren't the foreground app.

115. By Zachery Bir

Subscribe to user defaults changing. If we turn off auto_upload, suspend the queue. If it is turned on subsequently, resume the queue, and re-walk the library.

Also, avoid re-adding an operation to the queue, if the resource path is already in teh queue.

116. By Zachery Bir

Release mah bits.

117. By Zachery Bir

Merged Jason's touchup branch

118. By Zachery Bir

Merged Jason's account settings branch

119. By Zachery Bir

Merged Jason's preview additions branch

120. By Zachery Bir

Merged Jason's reachability branch

Revision history for this message
Jason Foreman (threeve) wrote :

+1, let's do this!

review: Approve
121. By Zachery Bir

Upped the build number to 16

122. By Zachery Bir

Updated the copyright headers

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file '.bzrignore'
2--- .bzrignore 2011-07-18 16:25:02 +0000
3+++ .bzrignore 2011-11-01 14:25:30 +0000
4@@ -5,3 +5,4 @@
5 Files.xcodeproj/*.mode1v3
6 Files.xcodeproj/xcuserdata
7 Files.xcodeproj/project.xcworkspace/
8+U1TestFlightTeamToken.txt
9
10=== added file 'Assets/218-trash2.png'
11Binary files Assets/218-trash2.png 1970-01-01 00:00:00 +0000 and Assets/218-trash2.png 2011-11-01 14:25:30 +0000 differ
12=== added file 'Assets/218-trash2@2x.png'
13Binary files Assets/218-trash2@2x.png 1970-01-01 00:00:00 +0000 and Assets/218-trash2@2x.png 2011-11-01 14:25:30 +0000 differ
14=== added file 'Assets/progress_view_background.png'
15Binary files Assets/progress_view_background.png 1970-01-01 00:00:00 +0000 and Assets/progress_view_background.png 2011-11-01 14:25:30 +0000 differ
16=== added file 'Assets/progress_view_background@2x.png'
17Binary files Assets/progress_view_background@2x.png 1970-01-01 00:00:00 +0000 and Assets/progress_view_background@2x.png 2011-11-01 14:25:30 +0000 differ
18=== added file 'Assets/settings.png'
19Binary files Assets/settings.png 1970-01-01 00:00:00 +0000 and Assets/settings.png 2011-11-01 14:25:30 +0000 differ
20=== added file 'Assets/settings@2x.png'
21Binary files Assets/settings@2x.png 1970-01-01 00:00:00 +0000 and Assets/settings@2x.png 2011-11-01 14:25:30 +0000 differ
22=== added file 'Dependencies/RIButtonItem.h'
23--- Dependencies/RIButtonItem.h 1970-01-01 00:00:00 +0000
24+++ Dependencies/RIButtonItem.h 2011-11-01 14:25:30 +0000
25@@ -0,0 +1,23 @@
26+//
27+// RIButtonItem.h
28+// Shibui
29+//
30+// Created by Jiva DeVoe on 1/12/11.
31+// Copyright 2011 Random Ideas, LLC. All rights reserved.
32+//
33+
34+#import <Foundation/Foundation.h>
35+
36+typedef void (^RISimpleAction)();
37+
38+@interface RIButtonItem : NSObject
39+{
40+ NSString *label;
41+ RISimpleAction action;
42+}
43+@property (retain, nonatomic) NSString *label;
44+@property (copy, nonatomic) RISimpleAction action;
45++(id)item;
46++(id)itemWithLabel:(NSString *)inLabel;
47+@end
48+
49
50=== added file 'Dependencies/RIButtonItem.m'
51--- Dependencies/RIButtonItem.m 1970-01-01 00:00:00 +0000
52+++ Dependencies/RIButtonItem.m 2011-11-01 14:25:30 +0000
53@@ -0,0 +1,28 @@
54+//
55+// RIButtonItem.m
56+// Shibui
57+//
58+// Created by Jiva DeVoe on 1/12/11.
59+// Copyright 2011 Random Ideas, LLC. All rights reserved.
60+//
61+
62+#import "RIButtonItem.h"
63+
64+@implementation RIButtonItem
65+@synthesize label;
66+@synthesize action;
67+
68++(id)item
69+{
70+ return [[self new] autorelease];
71+}
72+
73++(id)itemWithLabel:(NSString *)inLabel
74+{
75+ id newItem = [self item];
76+ [newItem setLabel:inLabel];
77+ return newItem;
78+}
79+
80+@end
81+
82
83=== added directory 'Dependencies/Reachability'
84=== added file 'Dependencies/Reachability/Reachability.h'
85--- Dependencies/Reachability/Reachability.h 1970-01-01 00:00:00 +0000
86+++ Dependencies/Reachability/Reachability.h 2011-11-01 14:25:30 +0000
87@@ -0,0 +1,88 @@
88+/*
89+
90+ File: Reachability.h
91+ Abstract: Basic demonstration of how to use the SystemConfiguration Reachablity APIs.
92+
93+ Version: 2.0
94+
95+ Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc.
96+ ("Apple") in consideration of your agreement to the following terms, and your
97+ use, installation, modification or redistribution of this Apple software
98+ constitutes acceptance of these terms. If you do not agree with these terms,
99+ please do not use, install, modify or redistribute this Apple software.
100+
101+ In consideration of your agreement to abide by the following terms, and subject
102+ to these terms, Apple grants you a personal, non-exclusive license, under
103+ Apple's copyrights in this original Apple software (the "Apple Software"), to
104+ use, reproduce, modify and redistribute the Apple Software, with or without
105+ modifications, in source and/or binary forms; provided that if you redistribute
106+ the Apple Software in its entirety and without modifications, you must retain
107+ this notice and the following text and disclaimers in all such redistributions
108+ of the Apple Software.
109+ Neither the name, trademarks, service marks or logos of Apple Inc. may be used
110+ to endorse or promote products derived from the Apple Software without specific
111+ prior written permission from Apple. Except as expressly stated in this notice,
112+ no other rights or licenses, express or implied, are granted by Apple herein,
113+ including but not limited to any patent rights that may be infringed by your
114+ derivative works or by other works in which the Apple Software may be
115+ incorporated.
116+
117+ The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
118+ WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
119+ WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
120+ PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
121+ COMBINATION WITH YOUR PRODUCTS.
122+
123+ IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
124+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
125+ GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
126+ ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR
127+ DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF
128+ CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
129+ APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
130+
131+ Copyright (C) 2009 Apple Inc. All Rights Reserved.
132+
133+*/
134+
135+
136+#import <Foundation/Foundation.h>
137+#import <SystemConfiguration/SystemConfiguration.h>
138+
139+typedef enum {
140+ NotReachable = 0,
141+ ReachableViaWiFi,
142+ ReachableViaWWAN
143+} NetworkStatus;
144+#define kReachabilityChangedNotification @"kNetworkReachabilityChangedNotification"
145+
146+@interface Reachability: NSObject
147+{
148+ BOOL localWiFiRef;
149+ SCNetworkReachabilityRef reachabilityRef;
150+}
151+
152+//reachabilityWithHostName- Use to check the reachability of a particular host name.
153++ (Reachability*) reachabilityWithHostName: (NSString*) hostName;
154+
155+//reachabilityWithAddress- Use to check the reachability of a particular IP address.
156+//+ (Reachability*) reachabilityWithAddress: (const struct sockaddr_in*) hostAddress;
157+
158+//reachabilityForInternetConnection- checks whether the default route is available.
159+// Should be used by applications that do not connect to a particular host
160++ (Reachability*) reachabilityForInternetConnection;
161+
162+//reachabilityForLocalWiFi- checks whether a local wifi connection is available.
163++ (Reachability*) reachabilityForLocalWiFi;
164+
165+//Start listening for reachability notifications on the current run loop
166+- (BOOL) startNotifer;
167+- (void) stopNotifer;
168+
169+- (NetworkStatus) currentReachabilityStatus;
170+//WWAN may be available, but not active until a connection has been established.
171+//WiFi may require a connection for VPN on Demand.
172+- (BOOL) connectionRequired;
173+@end
174+
175+
176
177=== added file 'Dependencies/Reachability/Reachability.m'
178--- Dependencies/Reachability/Reachability.m 1970-01-01 00:00:00 +0000
179+++ Dependencies/Reachability/Reachability.m 2011-11-01 14:25:30 +0000
180@@ -0,0 +1,274 @@
181+/*
182+
183+ File: Reachability.m
184+ Abstract: Basic demonstration of how to use the SystemConfiguration Reachablity APIs.
185+
186+ Version: 2.0
187+
188+ Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc.
189+ ("Apple") in consideration of your agreement to the following terms, and your
190+ use, installation, modification or redistribution of this Apple software
191+ constitutes acceptance of these terms. If you do not agree with these terms,
192+ please do not use, install, modify or redistribute this Apple software.
193+
194+ In consideration of your agreement to abide by the following terms, and subject
195+ to these terms, Apple grants you a personal, non-exclusive license, under
196+ Apple's copyrights in this original Apple software (the "Apple Software"), to
197+ use, reproduce, modify and redistribute the Apple Software, with or without
198+ modifications, in source and/or binary forms; provided that if you redistribute
199+ the Apple Software in its entirety and without modifications, you must retain
200+ this notice and the following text and disclaimers in all such redistributions
201+ of the Apple Software.
202+ Neither the name, trademarks, service marks or logos of Apple Inc. may be used
203+ to endorse or promote products derived from the Apple Software without specific
204+ prior written permission from Apple. Except as expressly stated in this notice,
205+ no other rights or licenses, express or implied, are granted by Apple herein,
206+ including but not limited to any patent rights that may be infringed by your
207+ derivative works or by other works in which the Apple Software may be
208+ incorporated.
209+
210+ The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
211+ WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
212+ WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
213+ PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
214+ COMBINATION WITH YOUR PRODUCTS.
215+
216+ IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
217+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
218+ GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
219+ ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR
220+ DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF
221+ CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
222+ APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
223+
224+ Copyright (C) 2009 Apple Inc. All Rights Reserved.
225+
226+*/
227+
228+#import <sys/socket.h>
229+#import <netinet/in.h>
230+#import <netinet6/in6.h>
231+#import <arpa/inet.h>
232+#import <ifaddrs.h>
233+#import <netdb.h>
234+
235+#import <CoreFoundation/CoreFoundation.h>
236+
237+#import "Reachability.h"
238+
239+#define kShouldPrintReachabilityFlags 0
240+
241+static void PrintReachabilityFlags(SCNetworkReachabilityFlags flags, const char* comment)
242+{
243+#if kShouldPrintReachabilityFlags
244+
245+ NSLog(@"Reachability Flag Status: %c%c %c%c%c%c%c%c%c %s\n",
246+ (flags & kSCNetworkReachabilityFlagsIsWWAN) ? 'W' : '-',
247+ (flags & kSCNetworkReachabilityFlagsReachable) ? 'R' : '-',
248+
249+ (flags & kSCNetworkReachabilityFlagsTransientConnection) ? 't' : '-',
250+ (flags & kSCNetworkReachabilityFlagsConnectionRequired) ? 'c' : '-',
251+ (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) ? 'C' : '-',
252+ (flags & kSCNetworkReachabilityFlagsInterventionRequired) ? 'i' : '-',
253+ (flags & kSCNetworkReachabilityFlagsConnectionOnDemand) ? 'D' : '-',
254+ (flags & kSCNetworkReachabilityFlagsIsLocalAddress) ? 'l' : '-',
255+ (flags & kSCNetworkReachabilityFlagsIsDirect) ? 'd' : '-',
256+ comment
257+ );
258+#endif
259+}
260+
261+
262+@implementation Reachability
263+static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void* info)
264+{
265+ #pragma unused (target, flags)
266+ NSCAssert(info != NULL, @"info was NULL in ReachabilityCallback");
267+ NSCAssert([(NSObject*) info isKindOfClass: [Reachability class]], @"info was wrong class in ReachabilityCallback");
268+
269+ //We're on the main RunLoop, so an NSAutoreleasePool is not necessary, but is added defensively
270+ // in case someon uses the Reachablity object in a different thread.
271+ NSAutoreleasePool* myPool = [[NSAutoreleasePool alloc] init];
272+
273+ Reachability* noteObject = (Reachability*) info;
274+ // Post a notification to notify the client that the network reachability changed.
275+ [[NSNotificationCenter defaultCenter] postNotificationName: kReachabilityChangedNotification object: noteObject];
276+
277+ [myPool release];
278+}
279+
280+- (BOOL) startNotifer
281+{
282+ BOOL retVal = NO;
283+ SCNetworkReachabilityContext context = {0, self, NULL, NULL, NULL};
284+ if(SCNetworkReachabilitySetCallback(reachabilityRef, ReachabilityCallback, &context))
285+ {
286+ if(SCNetworkReachabilityScheduleWithRunLoop(reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode))
287+ {
288+ retVal = YES;
289+ }
290+ }
291+ return retVal;
292+}
293+
294+- (void) stopNotifer
295+{
296+ if(reachabilityRef!= NULL)
297+ {
298+ SCNetworkReachabilityUnscheduleFromRunLoop(reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
299+ }
300+}
301+
302+- (void) dealloc
303+{
304+ [self stopNotifer];
305+ if(reachabilityRef!= NULL)
306+ {
307+ CFRelease(reachabilityRef);
308+ }
309+ [super dealloc];
310+}
311+
312++ (Reachability*) reachabilityWithHostName: (NSString*) hostName;
313+{
314+ Reachability* retVal = NULL;
315+ SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(NULL, [hostName UTF8String]);
316+ if(reachability!= NULL)
317+ {
318+ retVal= [[[self alloc] init] autorelease];
319+ if(retVal!= NULL)
320+ {
321+ retVal->reachabilityRef = reachability;
322+ retVal->localWiFiRef = NO;
323+ }
324+ }
325+ return retVal;
326+}
327+
328++ (Reachability*) reachabilityWithAddress: (const struct sockaddr_in*) hostAddress;
329+{
330+ SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr*)hostAddress);
331+ Reachability* retVal = NULL;
332+ if(reachability!= NULL)
333+ {
334+ retVal= [[[self alloc] init] autorelease];
335+ if(retVal!= NULL)
336+ {
337+ retVal->reachabilityRef = reachability;
338+ retVal->localWiFiRef = NO;
339+ }
340+ }
341+ return retVal;
342+}
343+
344++ (Reachability*) reachabilityForInternetConnection;
345+{
346+ struct sockaddr_in zeroAddress;
347+ bzero(&zeroAddress, sizeof(zeroAddress));
348+ zeroAddress.sin_len = sizeof(zeroAddress);
349+ zeroAddress.sin_family = AF_INET;
350+ return [self reachabilityWithAddress: &zeroAddress];
351+}
352+
353++ (Reachability*) reachabilityForLocalWiFi;
354+{
355+ //[super init];
356+ struct sockaddr_in localWifiAddress;
357+ bzero(&localWifiAddress, sizeof(localWifiAddress));
358+ localWifiAddress.sin_len = sizeof(localWifiAddress);
359+ localWifiAddress.sin_family = AF_INET;
360+ // IN_LINKLOCALNETNUM is defined in <netinet/in.h> as 169.254.0.0
361+ localWifiAddress.sin_addr.s_addr = htonl(IN_LINKLOCALNETNUM);
362+ Reachability* retVal = [self reachabilityWithAddress: &localWifiAddress];
363+ if(retVal!= NULL)
364+ {
365+ retVal->localWiFiRef = YES;
366+ }
367+ return retVal;
368+}
369+
370+#pragma mark Network Flag Handling
371+
372+- (NetworkStatus) localWiFiStatusForFlags: (SCNetworkReachabilityFlags) flags
373+{
374+ PrintReachabilityFlags(flags, "localWiFiStatusForFlags");
375+
376+ BOOL retVal = NotReachable;
377+ if((flags & kSCNetworkReachabilityFlagsReachable) && (flags & kSCNetworkReachabilityFlagsIsDirect))
378+ {
379+ retVal = ReachableViaWiFi;
380+ }
381+ return retVal;
382+}
383+
384+- (NetworkStatus) networkStatusForFlags: (SCNetworkReachabilityFlags) flags
385+{
386+ PrintReachabilityFlags(flags, "networkStatusForFlags");
387+ if ((flags & kSCNetworkReachabilityFlagsReachable) == 0)
388+ {
389+ // if target host is not reachable
390+ return NotReachable;
391+ }
392+
393+ BOOL retVal = NotReachable;
394+
395+ if ((flags & kSCNetworkReachabilityFlagsConnectionRequired) == 0)
396+ {
397+ // if target host is reachable and no connection is required
398+ // then we'll assume (for now) that your on Wi-Fi
399+ retVal = ReachableViaWiFi;
400+ }
401+
402+
403+ if ((((flags & kSCNetworkReachabilityFlagsConnectionOnDemand ) != 0) ||
404+ (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0))
405+ {
406+ // ... and the connection is on-demand (or on-traffic) if the
407+ // calling application is using the CFSocketStream or higher APIs
408+
409+ if ((flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0)
410+ {
411+ // ... and no [user] intervention is needed
412+ retVal = ReachableViaWiFi;
413+ }
414+ }
415+
416+ if ((flags & kSCNetworkReachabilityFlagsIsWWAN) == kSCNetworkReachabilityFlagsIsWWAN)
417+ {
418+ // ... but WWAN connections are OK if the calling application
419+ // is using the CFNetwork (CFSocketStream?) APIs.
420+ retVal = ReachableViaWWAN;
421+ }
422+ return retVal;
423+}
424+
425+- (BOOL) connectionRequired;
426+{
427+ NSAssert(reachabilityRef != NULL, @"connectionRequired called with NULL reachabilityRef");
428+ SCNetworkReachabilityFlags flags;
429+ if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags))
430+ {
431+ return (flags & kSCNetworkReachabilityFlagsConnectionRequired);
432+ }
433+ return NO;
434+}
435+
436+- (NetworkStatus) currentReachabilityStatus
437+{
438+ NSAssert(reachabilityRef != NULL, @"currentNetworkStatus called with NULL reachabilityRef");
439+ NetworkStatus retVal = NotReachable;
440+ SCNetworkReachabilityFlags flags;
441+ if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags))
442+ {
443+ if(localWiFiRef)
444+ {
445+ retVal = [self localWiFiStatusForFlags: flags];
446+ }
447+ else
448+ {
449+ retVal = [self networkStatusForFlags: flags];
450+ }
451+ }
452+ return retVal;
453+}
454+@end
455
456=== added directory 'Dependencies/TestFlightSDK'
457=== added file 'Dependencies/TestFlightSDK/README.txt'
458--- Dependencies/TestFlightSDK/README.txt 1970-01-01 00:00:00 +0000
459+++ Dependencies/TestFlightSDK/README.txt 2011-11-01 14:25:30 +0000
460@@ -0,0 +1,167 @@
461+Thanks for downloading the TestFlight SDK 0.7!
462+
463+This document is also available on the web at https://www.testflightapp.com/sdk/doc
464+
465+1. Why use the TestFlight SDK?
466+2. Considerations
467+3. How do I integrate the SDK into my project?
468+4. Using the Checkpoint API
469+5. Using the Feedback API
470+6. Upload your build
471+7. Questions API
472+8. View your results
473+9. Advanced Exception Handling
474+
475+START
476+
477+
478+1. Why use the TestFlight SDK?
479+
480+The TestFlight SDK allows you to track how beta testers are testing your application. Out of the box we track simple usage information, such as which tester is using your application, their device model/OS, how long they used the application, logs of their test session, and automatic recording of any crashes they encounter.
481+
482+To get the most out of the SDK we have provided the Checkpoint API.
483+
484+The Checkpoint API is used to help you track exactly how your testers are using your application. Curious about which users passed level 5 in your game, or posted their high score to Twitter, or found that obscure feature? With a single line of code you can finally gather all this information. Wondering how many times your app has crashed? Wondering who your power testers are? We've got you covered. See more information on the Checkpoint API in section 4.
485+
486+Alongside the Checkpoint API is the Questions interface. The Questions interface is managed on a per build basis on the TestFlight website. Find out more about the Questions Interface in section 6.
487+
488+2. Considerations
489+
490+
491+Information gathered by the SDK is sent to the website in real time. When an application is put into the background (iOS 4.x) or terminated (iOS 3.x) we try to send the finalizing information for the session during the time allowed for finalizing the application. Should all of the data not get sent the remaining data will be sent the next time the application is launched. As such, to get the most out of the SDK we recommend your application support iOS 4.0 and higher.
492+
493+This SDK can be run from both the iPhone Simulator and Device and has been tested using Xcode 4.0.
494+
495+3. How do I integrate the SDK into my project?
496+
497+
498+1. Add the files to your project: Project -> Add to Project -> TestFlightSDK
499+
500+ 1. Copy items into destination folder (if needed): Checked
501+ 2. Reference Type: Default
502+ 3. Recursively create groups for added folders
503+
504+2. Verify that libTestFlight.a has been added to the Link Binary With Libraries Build Phase for the targets you want to use the SDK with
505+
506+ 1. Select your Project in the Project Navigator
507+ 2. Select the target you want to enable the SDK for
508+ 3. Select the Build Phases tab
509+ 4. Open the Link Binary With Libraries Phase
510+ 5. If libTestFlight.a is not listed, drag and drop the library from your Project Navigator to the Link Binary With Libraries area
511+ 6. Repeat Steps 2 - 5 until all targets you want to use the SDK with have the SDK linked
512+
513+3. In your Application Delegate:
514+
515+ 1. Import TestFlight: `#import "TestFlight.h"`
516+ NOTE: If you do not want to import TestFlight.h in every file you may add the above line into you pre-compiled header (`<projectname>_Prefix.pch`) file inside of the
517+
518+ #ifdef __OBJC__ section.
519+ This will give you access to the SDK across all files.
520+
521+ 2. Get your Team Token which you can find at [http://testflightapp.com/dashboard/team/](http://testflightapp.com/dashboard/team/) select the team you are using from the team selection drop down list on the top of the page and then select edit.
522+
523+
524+ 3. Launch TestFlight with your Team Token
525+
526+ -(BOOL)application:(UIApplication *)application
527+ didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
528+ // start of your application:didFinishLaunchingWithOptions
529+ // ...
530+ [TestFlight takeOff:@"Insert your Team Token here"];
531+ // The rest of your application:didFinishLaunchingWithOptions method
532+ // ...
533+ }
534+
535+ 4. To report crashes to you we install our own uncaught exception handler. If you are not currently using an exception handler of your own then all you need to do is go to the next step. If you currently use an Exception Handler, or you use another framework that does please go to the section on advanced exception handling.
536+
537+4. To enable the best crash reporting possible we recommend setting the following project build settings in Xcode to NO for all targets that you want to have live crash reporting for You can find build settings by opening the Project Navigator (default command+1 or command+shift+j) then clicking on the project you are configuring (usually the first selection in the list). From there you can choose to either change the global project settings or settings on an individual project basis. All settings below are in the Deployment Section.
538+
539+ 1. Deployment Post Processing
540+ 2. Strip Debug Symbols During Copy
541+ 3. Strip Linked Product
542+
543+4. Use the Checkpoint API to create important checkpoints throughout your application.
544+
545+When a tester passes a level, or adds a new todo item, you can pass a checkpoint. The checkpoint progress is used to provide insight into how your testers are testing your apps. The passed checkpoints are also attached to crashes, which can help when creating steps to replicate.
546+
547+`[TestFlight passCheckpoint:@"CHECKPOINT_NAME"];`
548+Use `passCheckpoint:` to track when a user performs certain tasks in your application. This can be useful for making sure testers are hitting all parts of your application, as well as tracking which testers are being thorough.
549+
550+5. Using the Feedback API
551+
552+To launch unguided feedback call the `openFeedbackView` method. We recommend that you call this from a GUI element.
553+
554+ -(IBAction)launchFeedback {
555+ [TestFlight openFeedbackView];
556+ }
557+
558+Once users have submitted feedback from inside of the application you can view it in the feedback area of your build page.
559+
560+6. Upload your build.
561+
562+After you have integrated the SDK into your application you need to upload your build to TestFlight. You can upload from your dashboard or or using the Upload API, full documentation at <https://testflightapp.com/api/doc/>
563+
564+7. Add Questions to Checkpoints
565+
566+In order to ask a question, you'll need to associate it with a checkpoint. Make sure your checkpoints are initialized by running your app and hitting them all yourself before you start adding questions.
567+
568+There are three question types available: Yes/No, Multiple Choice, and Long Answer.
569+
570+To create questions, visit your builds Questions page and click on 'Add Question'. If you choose Multiple Choice, you'll need to enter a list of possible answers for your testers to choose from &mdash; otherwise, you'll only need to enter your question's, well, question. If your build has no questions, you can also choose to migrate questions from another build (because seriously &mdash; who wants to do all that typing again)?
571+
572+After restarting your application on an approved device, when you pass the checkpoint associated with your questions a Test Flight modal question form will appear on the screen asking the beta tester to answer your question.
573+
574+After you upload a new build to TestFlight you will need to associate questions once again. However if your checkpoints and questions have remained the same you can choose "copy questions from an older build" and choose which build to copy the questions from.
575+
576+8. View your results.
577+
578+As testers install your build and start to test it you will see their session data on the web on the build report page for the build you've uploaded.
579+
580+9. Advanced Exception Handling
581+
582+An uncaught exception means that your application is in an unknown state and there is not much that you can do but try and exit gracefully. Our SDK does its best to get the data we collect in this situation to you while it is crashing, but it is designed in such a way that the important act of saving the data occurs in as safe way a way as possible before trying to send anything. If you do use uncaught exception or signal handlers install your handlers before calling `takeOff`. Our SDK will then call your handler while ours is running. For example:
583+
584+ /*
585+ My Apps Custom uncaught exception catcher, we do special stuff here, and TestFlight takes care of the rest
586+ **/
587+ void HandleExceptions(NSException *exception) {
588+ NSLog(@"This is where we save the application data during a exception");
589+ // Save application data on crash
590+ }
591+ /*
592+ My Apps Custom signal catcher, we do special stuff here, and TestFlight takes care of the rest
593+ **/
594+ void SignalHandler(int sig) {
595+ NSLog(@"This is where we save the application data during a signal");
596+ // Save application data on crash
597+ }
598+
599+ -(BOOL)application:(UIApplication *)application
600+ didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
601+ // installs HandleExceptions as the Uncaught Exception Handler
602+ NSSetUncaughtExceptionHandler(&HandleExceptions);
603+ // create the signal action structure
604+ struct sigaction newSignalAction;
605+ // initialize the signal action structure
606+ memset(&newSignalAction, 0, sizeof(newSignalAction));
607+ // set SignalHandler as the handler in the signal action structure
608+ newSignalAction.sa_handler = &SignalHandler;
609+ // set SignalHandler as the handlers for SIGABRT, SIGILL and SIGBUS
610+ sigaction(SIGABRT, &newSignalAction, NULL);
611+ sigaction(SIGILL, &newSignalAction, NULL);
612+ sigaction(SIGBUS, &newSignalAction, NULL);
613+ // Call takeOff after install your own unhandled exception and signal handlers
614+ [TestFlight takeOff:@"Insert your Team Token here"];
615+ // continue with your application initialization
616+ }
617+
618+You do not need to add the above code if your application does not use exception handling already.
619+
620+END
621+
622+Please contact us if you have any questions.
623+
624+The TestFlight Team
625+
626+w. http://www.testflightapp.com
627+e. beta@testflightapp.com
628
629=== added file 'Dependencies/TestFlightSDK/TestFlight.h'
630--- Dependencies/TestFlightSDK/TestFlight.h 1970-01-01 00:00:00 +0000
631+++ Dependencies/TestFlightSDK/TestFlight.h 2011-11-01 14:25:30 +0000
632@@ -0,0 +1,44 @@
633+//
634+// TestFlight.h
635+// libTestFlight
636+//
637+// Created by Jonathan Janzen on 06/11/11.
638+// Copyright 2011 TestFlight. All rights reserved.
639+
640+#import <Foundation/Foundation.h>
641+#define TESTFLIGHT_SDK_VERSION @"0.7.2"
642+
643+@interface TestFlight : NSObject {
644+
645+}
646+
647+/**
648+ Add custom environment information
649+ If you want to track a user name from your application you can add it here
650+ */
651++ (void)addCustomEnvironmentInformation:(NSString *)information forKey:(NSString*)key;
652+
653+/**
654+ Starts a TestFlight session
655+ */
656++ (void)takeOff:(NSString *)teamToken;
657+
658+/**
659+ Sets custom options
660+ Option Accepted Values Description
661+ reinstallCrashHandlers [NSNumber numberWithBool:YES] Reinstalls crash handlers, to be used if a third party
662+ library installs crash handlers overtop of the TestFlight Crash Handlers
663+ */
664++ (void)setOptions:(NSDictionary*)options;
665+
666+/**
667+ Track when a user has passed a checkpoint after the flight has taken off. Eg. passed level 1, posted high score
668+ */
669++ (void)passCheckpoint:(NSString *)checkpointName;
670+
671+/**
672+ Opens a feeback window that is not attached to a checkpoint
673+ */
674++ (void)openFeedbackView;
675+
676+@end
677
678=== added file 'Dependencies/TestFlightSDK/release_notes.txt'
679--- Dependencies/TestFlightSDK/release_notes.txt 1970-01-01 00:00:00 +0000
680+++ Dependencies/TestFlightSDK/release_notes.txt 2011-11-01 14:25:30 +0000
681@@ -0,0 +1,41 @@
682+0.7.2 - September 29, 2011
683+Changed TESTFLIGHT_SDK_VERSION string to be an NSString
684+Fixed an issue where exiting an application while the SDK is active caused modal views to be dismissed
685+0.7.1 - September 22, 2011
686+Internal release
687+Refactoring
688+0.7 - September 21, 2011
689+Moved TestFlight images and data to the Library/Caches folder
690+Resolved an issue where sometimes the rootViewController could not be found and feedback, questions and upgrade views would not be displayed
691+In application upgrade changed to allow skipping until the next version is installed and allows upgrades to be forced
692+Fixed a memory leak when launching questions
693+0.6 - September 2, 2011
694+Renamed base64_encode to testflight_base64_encode to remove a conflict with other third party libraries
695+Added ability to reinstall crash handlers when they are overwritten using the setOptions API
696+Fixed an issue where crash reports might not get sent under certain circumstances
697+Fixed a deadlock when the application is put in the background and then resumed before all information can be sent
698+Fixed an issue when attempting to un-install all signal handlers during a signal
699+Added support for landscape mode on the iPad to the Questions and Feedback views
700+Crash reporting now works in versions of Xcode earlier than 4.2
701+Fixed a memory leak during handshake
702+0.5 - August 19, 2011
703+Feedback that is not attached to a checkpoint [TestFlight openFeedbackView]
704+Usability changes to question views
705+Removed pause and resume sessions, replaced with sessions being stopped and started
706+Added text auto correction to the Long Answer question type
707+Crash reports now send on crash instead of next launch
708+0.4 - August 15, 2011
709+In Application Feedback with Questions
710+In application updates
711+Custom Environment Information added
712+Networking stack reimplementation
713+Exception handling fixes
714+0.3 - June 15, 2011
715+Removed all mention of JSONKit from the README
716+Added support for using both the Bundle Version and the Bundle Short Version string
717+0.2 - June 14, 2011
718+Removed all categories this allows users to use the SDK without having to set -ObjC and -load_all
719+Prefixed JSONKit for use in TestFlight to remove reported issues where some users were already using JSONKit
720+Added support for armv6 again
721+0.1 - June 11, 2011
722+Initial Version
723\ No newline at end of file
724
725=== added file 'Dependencies/UIActionSheet+Blocks.h'
726--- Dependencies/UIActionSheet+Blocks.h 1970-01-01 00:00:00 +0000
727+++ Dependencies/UIActionSheet+Blocks.h 2011-11-01 14:25:30 +0000
728@@ -0,0 +1,16 @@
729+//
730+// UIActionSheet+Blocks.h
731+// Shibui
732+//
733+// Created by Jiva DeVoe on 1/5/11.
734+// Copyright 2011 Random Ideas, LLC. All rights reserved.
735+//
736+
737+#import <Foundation/Foundation.h>
738+#import "RIButtonItem.h"
739+
740+@interface UIActionSheet (Blocks) <UIActionSheetDelegate>
741+
742+-(id)initWithTitle:(NSString *)inTitle cancelButtonItem:(RIButtonItem *)inCancelButtonItem destructiveButtonItem:(RIButtonItem *)inDestructiveItem otherButtonItems:(RIButtonItem *)inOtherButtonItems, ... NS_REQUIRES_NIL_TERMINATION;
743+
744+@end
745
746=== added file 'Dependencies/UIActionSheet+Blocks.m'
747--- Dependencies/UIActionSheet+Blocks.m 1970-01-01 00:00:00 +0000
748+++ Dependencies/UIActionSheet+Blocks.m 2011-11-01 14:25:30 +0000
749@@ -0,0 +1,71 @@
750+//
751+// UIActionSheet+Blocks.m
752+// Shibui
753+//
754+// Created by Jiva DeVoe on 1/5/11.
755+// Copyright 2011 Random Ideas, LLC. All rights reserved.
756+//
757+
758+#import "UIActionSheet+Blocks.h"
759+#import <objc/runtime.h>
760+
761+static NSString *RI_BUTTON_ASS_KEY = @"com.random-ideas.BUTTONS";
762+
763+@implementation UIActionSheet (Blocks)
764+
765+-(id)initWithTitle:(NSString *)inTitle cancelButtonItem:(RIButtonItem *)inCancelButtonItem destructiveButtonItem:(RIButtonItem *)inDestructiveItem otherButtonItems:(RIButtonItem *)inOtherButtonItems, ...
766+{
767+ if((self = [self initWithTitle:inTitle delegate:self cancelButtonTitle:nil destructiveButtonTitle:nil otherButtonTitles:nil]))
768+ {
769+ NSMutableArray *buttonsArray = [NSMutableArray array];
770+
771+ RIButtonItem *eachItem;
772+ va_list argumentList;
773+ if (inOtherButtonItems)
774+ {
775+ [buttonsArray addObject: inOtherButtonItems];
776+ va_start(argumentList, inOtherButtonItems);
777+ while((eachItem = va_arg(argumentList, RIButtonItem *)))
778+ {
779+ [buttonsArray addObject: eachItem];
780+ }
781+ va_end(argumentList);
782+ }
783+
784+ for(RIButtonItem *item in buttonsArray)
785+ {
786+ [self addButtonWithTitle:item.label];
787+ }
788+
789+ if(inDestructiveItem)
790+ {
791+ [buttonsArray addObject:inDestructiveItem];
792+ NSInteger destIndex = [self addButtonWithTitle:inDestructiveItem.label];
793+ [self setDestructiveButtonIndex:destIndex];
794+ }
795+ if(inCancelButtonItem)
796+ {
797+ [buttonsArray addObject:inCancelButtonItem];
798+ NSInteger cancelIndex = [self addButtonWithTitle:inCancelButtonItem.label];
799+ [self setCancelButtonIndex:cancelIndex];
800+ }
801+
802+ objc_setAssociatedObject(self, RI_BUTTON_ASS_KEY, buttonsArray, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
803+
804+ [self retain]; // keep yourself around!
805+ }
806+ return self;
807+}
808+
809+- (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex
810+{
811+ NSArray *buttonsArray = objc_getAssociatedObject(self, RI_BUTTON_ASS_KEY);
812+ RIButtonItem *item = [buttonsArray objectAtIndex:buttonIndex];
813+ if(item.action)
814+ item.action();
815+ objc_setAssociatedObject(self, RI_BUTTON_ASS_KEY, nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
816+ [self release]; // and release yourself!
817+}
818+
819+
820+@end
821
822=== added file 'Dependencies/UIAlertView+Blocks.h'
823--- Dependencies/UIAlertView+Blocks.h 1970-01-01 00:00:00 +0000
824+++ Dependencies/UIAlertView+Blocks.h 2011-11-01 14:25:30 +0000
825@@ -0,0 +1,16 @@
826+//
827+// UIAlertView+Blocks.h
828+// Shibui
829+//
830+// Created by Jiva DeVoe on 12/28/10.
831+// Copyright 2010 Random Ideas, LLC. All rights reserved.
832+//
833+
834+#import <Foundation/Foundation.h>
835+#import "RIButtonItem.h"
836+
837+@interface UIAlertView (Blocks)
838+
839+-(id)initWithTitle:(NSString *)inTitle message:(NSString *)inMessage cancelButtonItem:(RIButtonItem *)inCancelButtonItem otherButtonItems:(RIButtonItem *)inOtherButtonItems, ... NS_REQUIRES_NIL_TERMINATION;
840+
841+@end
842
843=== added file 'Dependencies/UIAlertView+Blocks.m'
844--- Dependencies/UIAlertView+Blocks.m 1970-01-01 00:00:00 +0000
845+++ Dependencies/UIAlertView+Blocks.m 2011-11-01 14:25:30 +0000
846@@ -0,0 +1,61 @@
847+//
848+// UIAlertView+Blocks.m
849+// Shibui
850+//
851+// Created by Jiva DeVoe on 12/28/10.
852+// Copyright 2010 Random Ideas, LLC. All rights reserved.
853+//
854+
855+#import "UIAlertView+Blocks.h"
856+#import <objc/runtime.h>
857+
858+static NSString *RI_BUTTON_ASS_KEY = @"com.random-ideas.BUTTONS";
859+
860+@implementation UIAlertView (Blocks)
861+
862+-(id)initWithTitle:(NSString *)inTitle message:(NSString *)inMessage cancelButtonItem:(RIButtonItem *)inCancelButtonItem otherButtonItems:(RIButtonItem *)inOtherButtonItems, ...
863+{
864+ if((self = [self initWithTitle:inTitle message:inMessage delegate:self cancelButtonTitle:inCancelButtonItem.label otherButtonTitles:nil]))
865+ {
866+ NSMutableArray *buttonsArray = [NSMutableArray array];
867+
868+ RIButtonItem *eachItem;
869+ va_list argumentList;
870+ if (inOtherButtonItems)
871+ {
872+ [buttonsArray addObject: inOtherButtonItems];
873+ va_start(argumentList, inOtherButtonItems);
874+ while((eachItem = va_arg(argumentList, RIButtonItem *)))
875+ {
876+ [buttonsArray addObject: eachItem];
877+ }
878+ va_end(argumentList);
879+ }
880+
881+ for(RIButtonItem *item in buttonsArray)
882+ {
883+ [self addButtonWithTitle:item.label];
884+ }
885+
886+ if(inCancelButtonItem)
887+ [buttonsArray insertObject:inCancelButtonItem atIndex:0];
888+
889+ objc_setAssociatedObject(self, RI_BUTTON_ASS_KEY, buttonsArray, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
890+
891+ [self setDelegate:self];
892+ [self retain]; // keep yourself around!
893+ }
894+ return self;
895+}
896+
897+- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
898+{
899+ NSArray *buttonsArray = objc_getAssociatedObject(self, RI_BUTTON_ASS_KEY);
900+ RIButtonItem *item = [buttonsArray objectAtIndex:buttonIndex];
901+ if(item.action)
902+ item.action();
903+ objc_setAssociatedObject(self, RI_BUTTON_ASS_KEY, nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
904+ [self release]; // and release yourself!
905+}
906+
907+@end
908
909=== modified file 'Dependencies/oauthconsumer/Crypto/sha1.c'
910--- Dependencies/oauthconsumer/Crypto/sha1.c 2011-08-31 14:56:30 +0000
911+++ Dependencies/oauthconsumer/Crypto/sha1.c 2011-11-01 14:25:30 +0000
912@@ -98,6 +98,7 @@
913 state[4] += e;
914 /* Wipe variables */
915 a = b = c = d = e = 0;
916+ (void)a; // shut up the static analyzer
917 }
918
919
920@@ -159,6 +160,7 @@
921 }
922 /* Wipe variables */
923 i = j = 0;
924+ (void)i; // shut up the static analyzer
925 memset(context->buffer, 0, 64);
926 memset(context->state, 0, 20);
927 memset(context->count, 0, 8);
928
929=== modified file 'Dependencies/oauthconsumer/OAMutableURLRequest.m'
930--- Dependencies/oauthconsumer/OAMutableURLRequest.m 2011-08-31 14:56:30 +0000
931+++ Dependencies/oauthconsumer/OAMutableURLRequest.m 2011-11-01 14:25:30 +0000
932@@ -85,7 +85,7 @@
933 signatureProvider:(id<OASignatureProviding>)aProvider
934 nonce:(NSString *)aNonce
935 timestamp:(NSString *)aTimestamp {
936- [self initWithURL:aUrl
937+ self = [self initWithURL:aUrl
938 consumer:aConsumer
939 token:aToken
940 realm:aRealm
941@@ -135,7 +135,7 @@
942 - (void)_generateNonce {
943 CFUUIDRef theUUID = CFUUIDCreate(NULL);
944 CFStringRef string = CFUUIDCreateString(NULL, theUUID);
945- NSMakeCollectable(theUUID);
946+ [NSMakeCollectable(theUUID) autorelease];
947 if (nonce) {
948 CFRelease(nonce);
949 }
950
951=== modified file 'Dependencies/oauthconsumer/OAToken.m'
952--- Dependencies/oauthconsumer/OAToken.m 2011-08-31 14:56:30 +0000
953+++ Dependencies/oauthconsumer/OAToken.m 2011-11-01 14:25:30 +0000
954@@ -117,7 +117,7 @@
955 }
956
957 - (id)initWithUserDefaultsUsingServiceProviderName:(const NSString *)provider prefix:(const NSString *)prefix {
958- [super init];
959+ self = [super init];
960 self.key = [OAToken loadSetting:@"key" provider:provider prefix:prefix];
961 self.secret = [OAToken loadSetting:@"secret" provider:provider prefix:prefix];
962 self.session = [OAToken loadSetting:@"session" provider:provider prefix:prefix];
963
964=== modified file 'Dependencies/oauthconsumer/OATokenManager.m'
965--- Dependencies/oauthconsumer/OATokenManager.m 2011-08-31 14:56:30 +0000
966+++ Dependencies/oauthconsumer/OATokenManager.m 2011-11-01 14:25:30 +0000
967@@ -93,7 +93,7 @@
968 [self exchangeToken];
969 } else {
970 [authorizedTokenKey release];
971- authorizedTokenKey = [aKey retain];
972+ authorizedTokenKey = (NSString*)[aKey retain];
973 }
974 }
975
976@@ -284,6 +284,7 @@
977 {
978 OAToken *token = [[OAToken alloc] initWithHTTPResponseBody:body];
979 [self setAccessToken:token];
980+ [token release];
981 }
982
983 - (void)renewToken {
984@@ -371,6 +372,7 @@
985 [delegates setObject:aDelegate forKey:[NSString stringWithFormat:@"%p", call]];
986 }
987 [self dispatch];
988+ [call release];
989 }
990
991 - (void)fetchData:(NSString *)aURL method:(NSString *)aMethod parameters:(NSArray *)theParameters
992
993=== modified file 'Files.xcodeproj/project.pbxproj'
994--- Files.xcodeproj/project.pbxproj 2011-09-27 14:36:00 +0000
995+++ Files.xcodeproj/project.pbxproj 2011-11-01 14:25:30 +0000
996@@ -7,6 +7,28 @@
997 objects = {
998
999 /* Begin PBXBuildFile section */
1000+ 913A54AF1451EFE70081FD67 /* progress_view_background.png in Resources */ = {isa = PBXBuildFile; fileRef = 913A54AD1451EFE70081FD67 /* progress_view_background.png */; };
1001+ 913A54B01451EFE70081FD67 /* progress_view_background@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 913A54AE1451EFE70081FD67 /* progress_view_background@2x.png */; };
1002+ 916BF7611459EF9C00D4FE06 /* U1UTIMapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 916BF7601459EF9C00D4FE06 /* U1UTIMapper.m */; };
1003+ 916BF7641459F66A00D4FE06 /* uti-mappings.plist in Resources */ = {isa = PBXBuildFile; fileRef = 916BF7631459F66A00D4FE06 /* uti-mappings.plist */; };
1004+ 916BF76B145A464E00D4FE06 /* settings.png in Resources */ = {isa = PBXBuildFile; fileRef = 916BF769145A464E00D4FE06 /* settings.png */; };
1005+ 916BF76C145A464E00D4FE06 /* settings@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 916BF76A145A464E00D4FE06 /* settings@2x.png */; };
1006+ 916BF77A145AF6B900D4FE06 /* Entitlements.plist in Resources */ = {isa = PBXBuildFile; fileRef = 916BF779145AF6B900D4FE06 /* Entitlements.plist */; };
1007+ 916E0082143C9A3A0037F6D3 /* U1LocalAssetsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 916E0081143C9A390037F6D3 /* U1LocalAssetsViewController.m */; };
1008+ 917ADEC71458954E00980FD4 /* Icon.png in Resources */ = {isa = PBXBuildFile; fileRef = 917ADEC51458954E00980FD4 /* Icon.png */; };
1009+ 917ADEC81458954E00980FD4 /* Icon@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 917ADEC61458954E00980FD4 /* Icon@2x.png */; };
1010+ 9190AAF41444CA0A0063614A /* U1LocalAssetsViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 9190AAF31444CA0A0063614A /* U1LocalAssetsViewController.xib */; };
1011+ 91A5E2DC142A70DF00EAAC2B /* U1LocalAssetsManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 91A5E2DB142A70DF00EAAC2B /* U1LocalAssetsManager.m */; };
1012+ 91A5E2DF142B727600EAAC2B /* U1AssetUploadOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 91A5E2DE142B727500EAAC2B /* U1AssetUploadOperation.m */; };
1013+ 91B3F2D5141E87F900939B3C /* AssetsLibrary.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 91B3F2D4141E87F900939B3C /* AssetsLibrary.framework */; };
1014+ 91B3F2DC141FDFAB00939B3C /* _U1Asset.m in Sources */ = {isa = PBXBuildFile; fileRef = 91B3F2DB141FDFAB00939B3C /* _U1Asset.m */; };
1015+ 91B3F2DF141FDFBE00939B3C /* U1Asset.m in Sources */ = {isa = PBXBuildFile; fileRef = 91B3F2DE141FDFBE00939B3C /* U1Asset.m */; };
1016+ 91EC184E145B8E3B00DF31F4 /* U1SettingsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 91EC184C145B8E3A00DF31F4 /* U1SettingsViewController.m */; };
1017+ 91EC184F145B8E3B00DF31F4 /* U1SettingsViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 91EC184D145B8E3B00DF31F4 /* U1SettingsViewController.xib */; };
1018+ 91EC1851145F0A8F00DF31F4 /* default-settings.plist in Resources */ = {isa = PBXBuildFile; fileRef = 91EC1850145F0A8F00DF31F4 /* default-settings.plist */; };
1019+ 91EC1858145F0C1600DF31F4 /* RIButtonItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 91EC1857145F0C1600DF31F4 /* RIButtonItem.m */; };
1020+ 91EC185D145F0C3000DF31F4 /* UIActionSheet+Blocks.m in Sources */ = {isa = PBXBuildFile; fileRef = 91EC185A145F0C3000DF31F4 /* UIActionSheet+Blocks.m */; };
1021+ 91EC185E145F0C3000DF31F4 /* UIAlertView+Blocks.m in Sources */ = {isa = PBXBuildFile; fileRef = 91EC185C145F0C3000DF31F4 /* UIAlertView+Blocks.m */; };
1022 960D46131409E0E100B73177 /* PullRefreshTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 960D46001409E09F00B73177 /* PullRefreshTableViewController.m */; };
1023 960D46141409E0F000B73177 /* arrow.png in Resources */ = {isa = PBXBuildFile; fileRef = 960D45FB1409E09F00B73177 /* arrow.png */; };
1024 960D46161409E10200B73177 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 960D46151409E10200B73177 /* QuartzCore.framework */; };
1025@@ -21,6 +43,7 @@
1026 960D462E140DD22800B73177 /* U1FileNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 960D462D140DD22600B73177 /* U1FileNode.m */; };
1027 960D4631140DD23600B73177 /* U1FolderNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 960D4630140DD23400B73177 /* U1FolderNode.m */; };
1028 960D4635140DDBE400B73177 /* U1NodeChildrenResultSet.m in Sources */ = {isa = PBXBuildFile; fileRef = 960D4634140DDBE400B73177 /* U1NodeChildrenResultSet.m */; };
1029+ 963C16D0144346CC007A51D0 /* libTestFlight.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 963C16CB144346A6007A51D0 /* libTestFlight.a */; };
1030 965D7EA814293B6700E4754F /* ic_act_publish_file.png in Resources */ = {isa = PBXBuildFile; fileRef = 965D7EA214293B6700E4754F /* ic_act_publish_file.png */; };
1031 965D7EA914293B6700E4754F /* ic_act_publish_file@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 965D7EA314293B6700E4754F /* ic_act_publish_file@2x.png */; };
1032 965D7EAA14293B6700E4754F /* ic_act_unpublish_file.png in Resources */ = {isa = PBXBuildFile; fileRef = 965D7EA414293B6700E4754F /* ic_act_unpublish_file.png */; };
1033@@ -52,6 +75,11 @@
1034 96A169A01430C9C900E4C990 /* 265-download.png in Resources */ = {isa = PBXBuildFile; fileRef = 96A1699E1430C9C900E4C990 /* 265-download.png */; };
1035 96A169A11430C9C900E4C990 /* 265-download@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 96A1699F1430C9C900E4C990 /* 265-download@2x.png */; };
1036 96A169A41430D53700E4C990 /* U1LocalFileInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 96A169A31430D53600E4C990 /* U1LocalFileInfo.m */; };
1037+ 96B20E6D145F6AAE00D8ED69 /* 218-trash2.png in Resources */ = {isa = PBXBuildFile; fileRef = 96B20E6B145F6AAE00D8ED69 /* 218-trash2.png */; };
1038+ 96B20E6E145F6AAE00D8ED69 /* 218-trash2@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 96B20E6C145F6AAE00D8ED69 /* 218-trash2@2x.png */; };
1039+ 96B20E78145F815500D8ED69 /* Reachability.m in Sources */ = {isa = PBXBuildFile; fileRef = 96B20E77145F815500D8ED69 /* Reachability.m */; };
1040+ 96B20E7A145F819300D8ED69 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 96B20E79145F819200D8ED69 /* SystemConfiguration.framework */; };
1041+ 96CAD3C71457823B007A496C /* NSDictionary+U1Additions.m in Sources */ = {isa = PBXBuildFile; fileRef = 96CAD3C61457823B007A496C /* NSDictionary+U1Additions.m */; };
1042 96CC17C81417E5E400EFC1BA /* U1Files.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 96CC17C61417E5E400EFC1BA /* U1Files.xcdatamodeld */; };
1043 96CC17D31417EA0700EFC1BA /* _U1FileNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 96CC17CC1417EA0700EFC1BA /* _U1FileNode.m */; };
1044 96CC17D41417EA0700EFC1BA /* _U1FolderNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 96CC17CE1417EA0700EFC1BA /* _U1FolderNode.m */; };
1045@@ -116,6 +144,39 @@
1046 /* End PBXContainerItemProxy section */
1047
1048 /* Begin PBXFileReference section */
1049+ 913A54AD1451EFE70081FD67 /* progress_view_background.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = progress_view_background.png; path = Assets/progress_view_background.png; sourceTree = "<group>"; };
1050+ 913A54AE1451EFE70081FD67 /* progress_view_background@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "progress_view_background@2x.png"; path = "Assets/progress_view_background@2x.png"; sourceTree = "<group>"; };
1051+ 916BF75F1459EF9C00D4FE06 /* U1UTIMapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = U1UTIMapper.h; sourceTree = "<group>"; };
1052+ 916BF7601459EF9C00D4FE06 /* U1UTIMapper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = U1UTIMapper.m; sourceTree = "<group>"; };
1053+ 916BF7631459F66A00D4FE06 /* uti-mappings.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "uti-mappings.plist"; sourceTree = "<group>"; };
1054+ 916BF769145A464E00D4FE06 /* settings.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = settings.png; path = Assets/settings.png; sourceTree = "<group>"; };
1055+ 916BF76A145A464E00D4FE06 /* settings@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "settings@2x.png"; path = "Assets/settings@2x.png"; sourceTree = "<group>"; };
1056+ 916BF779145AF6B900D4FE06 /* Entitlements.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Entitlements.plist; sourceTree = "<group>"; };
1057+ 916E0080143C9A390037F6D3 /* U1LocalAssetsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = U1LocalAssetsViewController.h; sourceTree = "<group>"; };
1058+ 916E0081143C9A390037F6D3 /* U1LocalAssetsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = U1LocalAssetsViewController.m; sourceTree = "<group>"; };
1059+ 917ADEC014585DC800980FD4 /* U1Files 1.0-9.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "U1Files 1.0-9.xcdatamodel"; sourceTree = "<group>"; };
1060+ 917ADEC51458954E00980FD4 /* Icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Icon.png; sourceTree = "<group>"; };
1061+ 917ADEC61458954E00980FD4 /* Icon@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon@2x.png"; sourceTree = "<group>"; };
1062+ 9190AAF31444CA0A0063614A /* U1LocalAssetsViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = U1LocalAssetsViewController.xib; sourceTree = "<group>"; };
1063+ 91A5E2DB142A70DF00EAAC2B /* U1LocalAssetsManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = U1LocalAssetsManager.m; sourceTree = "<group>"; };
1064+ 91A5E2DD142B727500EAAC2B /* U1AssetUploadOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = U1AssetUploadOperation.h; sourceTree = "<group>"; };
1065+ 91A5E2DE142B727500EAAC2B /* U1AssetUploadOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = U1AssetUploadOperation.m; sourceTree = "<group>"; };
1066+ 91B3F2D4141E87F900939B3C /* AssetsLibrary.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AssetsLibrary.framework; path = System/Library/Frameworks/AssetsLibrary.framework; sourceTree = SDKROOT; };
1067+ 91B3F2D7141FC9BE00939B3C /* U1LocalAssetsManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = U1LocalAssetsManager.h; sourceTree = "<group>"; };
1068+ 91B3F2DA141FDFAB00939B3C /* _U1Asset.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _U1Asset.h; sourceTree = "<group>"; };
1069+ 91B3F2DB141FDFAB00939B3C /* _U1Asset.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = _U1Asset.m; sourceTree = "<group>"; };
1070+ 91B3F2DD141FDFBE00939B3C /* U1Asset.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = U1Asset.h; sourceTree = "<group>"; };
1071+ 91B3F2DE141FDFBE00939B3C /* U1Asset.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = U1Asset.m; sourceTree = "<group>"; };
1072+ 91EC184B145B8E3A00DF31F4 /* U1SettingsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = U1SettingsViewController.h; sourceTree = "<group>"; };
1073+ 91EC184C145B8E3A00DF31F4 /* U1SettingsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = U1SettingsViewController.m; sourceTree = "<group>"; };
1074+ 91EC184D145B8E3B00DF31F4 /* U1SettingsViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = U1SettingsViewController.xib; sourceTree = "<group>"; };
1075+ 91EC1850145F0A8F00DF31F4 /* default-settings.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "default-settings.plist"; sourceTree = "<group>"; };
1076+ 91EC1856145F0C1600DF31F4 /* RIButtonItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RIButtonItem.h; sourceTree = "<group>"; };
1077+ 91EC1857145F0C1600DF31F4 /* RIButtonItem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RIButtonItem.m; sourceTree = "<group>"; };
1078+ 91EC1859145F0C3000DF31F4 /* UIActionSheet+Blocks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIActionSheet+Blocks.h"; sourceTree = "<group>"; };
1079+ 91EC185A145F0C3000DF31F4 /* UIActionSheet+Blocks.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIActionSheet+Blocks.m"; sourceTree = "<group>"; };
1080+ 91EC185B145F0C3000DF31F4 /* UIAlertView+Blocks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIAlertView+Blocks.h"; sourceTree = "<group>"; };
1081+ 91EC185C145F0C3000DF31F4 /* UIAlertView+Blocks.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIAlertView+Blocks.m"; sourceTree = "<group>"; };
1082 960D45FA1409E09F00B73177 /* .gitignore */ = {isa = PBXFileReference; lastKnownFileType = text; path = .gitignore; sourceTree = "<group>"; };
1083 960D45FB1409E09F00B73177 /* arrow.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = arrow.png; sourceTree = "<group>"; };
1084 960D45FD1409E09F00B73177 /* DemoTableViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DemoTableViewController.h; sourceTree = "<group>"; };
1085@@ -149,6 +210,10 @@
1086 960D4630140DD23400B73177 /* U1FolderNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = U1FolderNode.m; sourceTree = "<group>"; };
1087 960D4633140DDBE400B73177 /* U1NodeChildrenResultSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = U1NodeChildrenResultSet.h; sourceTree = "<group>"; };
1088 960D4634140DDBE400B73177 /* U1NodeChildrenResultSet.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = U1NodeChildrenResultSet.m; sourceTree = "<group>"; };
1089+ 963C16CB144346A6007A51D0 /* libTestFlight.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libTestFlight.a; sourceTree = "<group>"; };
1090+ 963C16CC144346A6007A51D0 /* README.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = README.txt; sourceTree = "<group>"; };
1091+ 963C16CD144346A6007A51D0 /* release_notes.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = release_notes.txt; sourceTree = "<group>"; };
1092+ 963C16CE144346A6007A51D0 /* TestFlight.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TestFlight.h; sourceTree = "<group>"; };
1093 965D7EA214293B6700E4754F /* ic_act_publish_file.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = ic_act_publish_file.png; path = Assets/ic_act_publish_file.png; sourceTree = "<group>"; };
1094 965D7EA314293B6700E4754F /* ic_act_publish_file@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "ic_act_publish_file@2x.png"; path = "Assets/ic_act_publish_file@2x.png"; sourceTree = "<group>"; };
1095 965D7EA414293B6700E4754F /* ic_act_unpublish_file.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = ic_act_unpublish_file.png; path = Assets/ic_act_unpublish_file.png; sourceTree = "<group>"; };
1096@@ -194,6 +259,14 @@
1097 96A1699F1430C9C900E4C990 /* 265-download@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "265-download@2x.png"; path = "Assets/265-download@2x.png"; sourceTree = "<group>"; };
1098 96A169A21430D53600E4C990 /* U1LocalFileInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = U1LocalFileInfo.h; sourceTree = "<group>"; };
1099 96A169A31430D53600E4C990 /* U1LocalFileInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = U1LocalFileInfo.m; sourceTree = "<group>"; };
1100+ 96A56430143265B4007A1A93 /* U1Files 1.0-3.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "U1Files 1.0-3.xcdatamodel"; sourceTree = "<group>"; };
1101+ 96B20E6B145F6AAE00D8ED69 /* 218-trash2.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "218-trash2.png"; path = "Assets/218-trash2.png"; sourceTree = "<group>"; };
1102+ 96B20E6C145F6AAE00D8ED69 /* 218-trash2@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "218-trash2@2x.png"; path = "Assets/218-trash2@2x.png"; sourceTree = "<group>"; };
1103+ 96B20E76145F815500D8ED69 /* Reachability.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Reachability.h; sourceTree = "<group>"; };
1104+ 96B20E77145F815500D8ED69 /* Reachability.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Reachability.m; sourceTree = "<group>"; };
1105+ 96B20E79145F819200D8ED69 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; };
1106+ 96CAD3C51457823B007A496C /* NSDictionary+U1Additions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDictionary+U1Additions.h"; sourceTree = "<group>"; };
1107+ 96CAD3C61457823B007A496C /* NSDictionary+U1Additions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSDictionary+U1Additions.m"; sourceTree = "<group>"; };
1108 96CC17C71417E5E400EFC1BA /* U1Files.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = U1Files.xcdatamodel; sourceTree = "<group>"; };
1109 96CC17CB1417EA0700EFC1BA /* _U1FileNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _U1FileNode.h; sourceTree = "<group>"; };
1110 96CC17CC1417EA0700EFC1BA /* _U1FileNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = _U1FileNode.m; sourceTree = "<group>"; };
1111@@ -292,6 +365,8 @@
1112 isa = PBXFrameworksBuildPhase;
1113 buildActionMask = 2147483647;
1114 files = (
1115+ 96B20E7A145F819300D8ED69 /* SystemConfiguration.framework in Frameworks */,
1116+ 91B3F2D5141E87F900939B3C /* AssetsLibrary.framework in Frameworks */,
1117 96CC17D81417EA2B00EFC1BA /* CoreData.framework in Frameworks */,
1118 96733B12140DFD6D0074D545 /* Security.framework in Frameworks */,
1119 960D46161409E10200B73177 /* QuartzCore.framework in Frameworks */,
1120@@ -299,6 +374,7 @@
1121 96E860B613F7251D0026783D /* UIKit.framework in Frameworks */,
1122 96E860B813F7251D0026783D /* Foundation.framework in Frameworks */,
1123 96E860BA13F7251D0026783D /* CoreGraphics.framework in Frameworks */,
1124+ 963C16D0144346CC007A51D0 /* libTestFlight.a in Frameworks */,
1125 );
1126 runOnlyForDeploymentPostprocessing = 0;
1127 };
1128@@ -350,6 +426,8 @@
1129 96CC17CA1417E9E500EFC1BA /* Generated */,
1130 96CC17DF1418091100EFC1BA /* Parsers */,
1131 96CC17C61417E5E400EFC1BA /* U1Files.xcdatamodeld */,
1132+ 91B3F2DD141FDFBE00939B3C /* U1Asset.h */,
1133+ 91B3F2DE141FDFBE00939B3C /* U1Asset.m */,
1134 96CC17D91417EBF500EFC1BA /* U1Volume.h */,
1135 96CC17DA1417EBF500EFC1BA /* U1Volume.m */,
1136 960D4629140D99DB00B73177 /* U1Node.h */,
1137@@ -366,6 +444,17 @@
1138 name = Model;
1139 sourceTree = "<group>";
1140 };
1141+ 963C16CA144346A6007A51D0 /* TestFlightSDK */ = {
1142+ isa = PBXGroup;
1143+ children = (
1144+ 963C16CB144346A6007A51D0 /* libTestFlight.a */,
1145+ 963C16CC144346A6007A51D0 /* README.txt */,
1146+ 963C16CD144346A6007A51D0 /* release_notes.txt */,
1147+ 963C16CE144346A6007A51D0 /* TestFlight.h */,
1148+ );
1149+ path = TestFlightSDK;
1150+ sourceTree = "<group>";
1151+ };
1152 96733AEC140DFABB0074D545 /* SSO */ = {
1153 isa = PBXGroup;
1154 children = (
1155@@ -383,14 +472,12 @@
1156 96783E6513F8ABC70092C6A1 /* Assets */ = {
1157 isa = PBXGroup;
1158 children = (
1159+ 96A1699A1430C95E00E4C990 /* 04-eye.png */,
1160+ 96A1699B1430C95E00E4C990 /* 04-eye@2x.png */,
1161+ 96B20E6B145F6AAE00D8ED69 /* 218-trash2.png */,
1162+ 96B20E6C145F6AAE00D8ED69 /* 218-trash2@2x.png */,
1163 96A1699E1430C9C900E4C990 /* 265-download.png */,
1164 96A1699F1430C9C900E4C990 /* 265-download@2x.png */,
1165- 96A1699A1430C95E00E4C990 /* 04-eye.png */,
1166- 96A1699B1430C95E00E4C990 /* 04-eye@2x.png */,
1167- 965D7EAF1429663A00E4754F /* logo_4_white.png */,
1168- 965D7EB01429663A00E4754F /* logo_4_white@2x.png */,
1169- 965D7EB11429663A00E4754F /* white_tile.png */,
1170- 965D7EB21429663A00E4754F /* white_tile@2x.png */,
1171 965D7EA214293B6700E4754F /* ic_act_publish_file.png */,
1172 965D7EA314293B6700E4754F /* ic_act_publish_file@2x.png */,
1173 965D7EA414293B6700E4754F /* ic_act_unpublish_file.png */,
1174@@ -399,14 +486,35 @@
1175 965D7EA714293B6700E4754F /* ic_act_upload_photo@2x.png */,
1176 960D461F1409ECC500B73177 /* ic_folder.png */,
1177 960D46201409ECC500B73177 /* ic_folder@2x.png */,
1178+ 917ADEC51458954E00980FD4 /* Icon.png */,
1179+ 917ADEC61458954E00980FD4 /* Icon@2x.png */,
1180+ 965D7EAF1429663A00E4754F /* logo_4_white.png */,
1181+ 965D7EB01429663A00E4754F /* logo_4_white@2x.png */,
1182+ 913A54AD1451EFE70081FD67 /* progress_view_background.png */,
1183+ 913A54AE1451EFE70081FD67 /* progress_view_background@2x.png */,
1184+ 916BF769145A464E00D4FE06 /* settings.png */,
1185+ 916BF76A145A464E00D4FE06 /* settings@2x.png */,
1186+ 965D7EB11429663A00E4754F /* white_tile.png */,
1187+ 965D7EB21429663A00E4754F /* white_tile@2x.png */,
1188 );
1189 name = Assets;
1190 path = ..;
1191 sourceTree = "<group>";
1192 };
1193+ 96B20E75145F815500D8ED69 /* Reachability */ = {
1194+ isa = PBXGroup;
1195+ children = (
1196+ 96B20E76145F815500D8ED69 /* Reachability.h */,
1197+ 96B20E77145F815500D8ED69 /* Reachability.m */,
1198+ );
1199+ path = Reachability;
1200+ sourceTree = "<group>";
1201+ };
1202 96CC17CA1417E9E500EFC1BA /* Generated */ = {
1203 isa = PBXGroup;
1204 children = (
1205+ 91B3F2DA141FDFAB00939B3C /* _U1Asset.h */,
1206+ 91B3F2DB141FDFAB00939B3C /* _U1Asset.m */,
1207 96CC17CB1417EA0700EFC1BA /* _U1FileNode.h */,
1208 96CC17CC1417EA0700EFC1BA /* _U1FileNode.m */,
1209 96CC17CD1417EA0700EFC1BA /* _U1FolderNode.h */,
1210@@ -451,6 +559,8 @@
1211 96E860B413F7251D0026783D /* Frameworks */ = {
1212 isa = PBXGroup;
1213 children = (
1214+ 96B20E79145F819200D8ED69 /* SystemConfiguration.framework */,
1215+ 91B3F2D4141E87F900939B3C /* AssetsLibrary.framework */,
1216 96CC17D71417EA2B00EFC1BA /* CoreData.framework */,
1217 96733B11140DFD6D0074D545 /* Security.framework */,
1218 960D46151409E10200B73177 /* QuartzCore.framework */,
1219@@ -486,6 +596,8 @@
1220 96E8614213F728380026783D /* U1FilesService.m */,
1221 96CC17E314180C5F00EFC1BA /* U1FilesClient.h */,
1222 96CC17E414180C5F00EFC1BA /* U1FilesClient.m */,
1223+ 91B3F2D7141FC9BE00939B3C /* U1LocalAssetsManager.h */,
1224+ 91A5E2DB142A70DF00EAAC2B /* U1LocalAssetsManager.m */,
1225 969EF22613F8C10C00CEF6CB /* U1VolumesViewController.h */,
1226 969EF22713F8C10C00CEF6CB /* U1VolumesViewController.m */,
1227 969EF22813F8C10C00CEF6CB /* U1VolumesViewController.xib */,
1228@@ -498,10 +610,20 @@
1229 960D4624140D8AF200B73177 /* U1ByteSizeValueTransformer.m */,
1230 960D4626140D8B4400B73177 /* U1FriendlyDateValueTransformer.h */,
1231 960D4627140D8B4400B73177 /* U1FriendlyDateValueTransformer.m */,
1232+ 91A5E2DD142B727500EAAC2B /* U1AssetUploadOperation.h */,
1233+ 91A5E2DE142B727500EAAC2B /* U1AssetUploadOperation.m */,
1234 965D7EB71429690C00E4754F /* U1NavigationBar.h */,
1235 965D7EB81429690C00E4754F /* U1NavigationBar.m */,
1236 96A169A21430D53600E4C990 /* U1LocalFileInfo.h */,
1237 96A169A31430D53600E4C990 /* U1LocalFileInfo.m */,
1238+ 916E0080143C9A390037F6D3 /* U1LocalAssetsViewController.h */,
1239+ 916E0081143C9A390037F6D3 /* U1LocalAssetsViewController.m */,
1240+ 9190AAF31444CA0A0063614A /* U1LocalAssetsViewController.xib */,
1241+ 916BF75F1459EF9C00D4FE06 /* U1UTIMapper.h */,
1242+ 916BF7601459EF9C00D4FE06 /* U1UTIMapper.m */,
1243+ 91EC184B145B8E3A00DF31F4 /* U1SettingsViewController.h */,
1244+ 91EC184C145B8E3A00DF31F4 /* U1SettingsViewController.m */,
1245+ 91EC184D145B8E3B00DF31F4 /* U1SettingsViewController.xib */,
1246 );
1247 path = Files;
1248 sourceTree = "<group>";
1249@@ -509,6 +631,7 @@
1250 96E860BC13F7251D0026783D /* Supporting Files */ = {
1251 isa = PBXGroup;
1252 children = (
1253+ 916BF779145AF6B900D4FE06 /* Entitlements.plist */,
1254 96733B0E140DFD510074D545 /* SFHFKeychainUtils.h */,
1255 96733B0F140DFD510074D545 /* SFHFKeychainUtils.m */,
1256 96733B08140DFBB60074D545 /* URLQueryStringParser.h */,
1257@@ -529,6 +652,10 @@
1258 96E860C313F7251D0026783D /* Files-Prefix.pch */,
1259 96733B13140E04940074D545 /* UIActionSheet+U1Additions.h */,
1260 96733B14140E04940074D545 /* UIActionSheet+U1Additions.m */,
1261+ 96CAD3C51457823B007A496C /* NSDictionary+U1Additions.h */,
1262+ 96CAD3C61457823B007A496C /* NSDictionary+U1Additions.m */,
1263+ 916BF7631459F66A00D4FE06 /* uti-mappings.plist */,
1264+ 91EC1850145F0A8F00DF31F4 /* default-settings.plist */,
1265 );
1266 name = "Supporting Files";
1267 sourceTree = "<group>";
1268@@ -555,6 +682,14 @@
1269 96E860F413F726250026783D /* Dependencies */ = {
1270 isa = PBXGroup;
1271 children = (
1272+ 96B20E75145F815500D8ED69 /* Reachability */,
1273+ 91EC1859145F0C3000DF31F4 /* UIActionSheet+Blocks.h */,
1274+ 91EC185A145F0C3000DF31F4 /* UIActionSheet+Blocks.m */,
1275+ 91EC185B145F0C3000DF31F4 /* UIAlertView+Blocks.h */,
1276+ 91EC185C145F0C3000DF31F4 /* UIAlertView+Blocks.m */,
1277+ 91EC1856145F0C1600DF31F4 /* RIButtonItem.h */,
1278+ 91EC1857145F0C1600DF31F4 /* RIButtonItem.m */,
1279+ 963C16CA144346A6007A51D0 /* TestFlightSDK */,
1280 96E8614713F740E20026783D /* JSONKit */,
1281 96E860F513F7265B0026783D /* oauthconsumer */,
1282 960D45F91409E09F00B73177 /* PullToRefresh */,
1283@@ -645,6 +780,7 @@
1284 buildPhases = (
1285 96E860AD13F7251D0026783D /* Sources */,
1286 96E860AE13F7251D0026783D /* Frameworks */,
1287+ 963C16D614437CF4007A51D0 /* ShellScript */,
1288 96E860AF13F7251D0026783D /* Resources */,
1289 );
1290 buildRules = (
1291@@ -728,6 +864,19 @@
1292 96A1699D1430C95E00E4C990 /* 04-eye@2x.png in Resources */,
1293 96A169A01430C9C900E4C990 /* 265-download.png in Resources */,
1294 96A169A11430C9C900E4C990 /* 265-download@2x.png in Resources */,
1295+ 9190AAF41444CA0A0063614A /* U1LocalAssetsViewController.xib in Resources */,
1296+ 913A54AF1451EFE70081FD67 /* progress_view_background.png in Resources */,
1297+ 913A54B01451EFE70081FD67 /* progress_view_background@2x.png in Resources */,
1298+ 917ADEC71458954E00980FD4 /* Icon.png in Resources */,
1299+ 917ADEC81458954E00980FD4 /* Icon@2x.png in Resources */,
1300+ 916BF7641459F66A00D4FE06 /* uti-mappings.plist in Resources */,
1301+ 916BF76B145A464E00D4FE06 /* settings.png in Resources */,
1302+ 916BF76C145A464E00D4FE06 /* settings@2x.png in Resources */,
1303+ 916BF77A145AF6B900D4FE06 /* Entitlements.plist in Resources */,
1304+ 91EC184F145B8E3B00DF31F4 /* U1SettingsViewController.xib in Resources */,
1305+ 91EC1851145F0A8F00DF31F4 /* default-settings.plist in Resources */,
1306+ 96B20E6D145F6AAE00D8ED69 /* 218-trash2.png in Resources */,
1307+ 96B20E6E145F6AAE00D8ED69 /* 218-trash2@2x.png in Resources */,
1308 );
1309 runOnlyForDeploymentPostprocessing = 0;
1310 };
1311@@ -743,6 +892,20 @@
1312 /* End PBXResourcesBuildPhase section */
1313
1314 /* Begin PBXShellScriptBuildPhase section */
1315+ 963C16D614437CF4007A51D0 /* ShellScript */ = {
1316+ isa = PBXShellScriptBuildPhase;
1317+ buildActionMask = 2147483647;
1318+ files = (
1319+ );
1320+ inputPaths = (
1321+ );
1322+ outputPaths = (
1323+ );
1324+ runOnlyForDeploymentPostprocessing = 0;
1325+ shellPath = /bin/bash;
1326+ shellScript = "\nif [ -f ${SRCROOT}/U1TestFlightTeamToken.txt ]\nthen\n\ncp ${SRCROOT}/U1TestFlightTeamToken.txt ${CODESIGNING_FOLDER_PATH}\n\nelse \n\necho \"warning: ${SRCROOT}/U1TestFlightTeamToken.txt does not exist. Create this file and paste the Ubuntu One TestFlight team token into it to enable TestFlight SDK analytics.\"\n\nfi\n\n\n#echo \"foo\" > ${CODESIGNING_FOLDER_PATH}/foo.plist\n";
1327+ showEnvVarsInLog = 0;
1328+ };
1329 96E860D813F7251D0026783D /* ShellScript */ = {
1330 isa = PBXShellScriptBuildPhase;
1331 buildActionMask = 2147483647;
1332@@ -818,8 +981,20 @@
1333 96CC17DE1417EF7200EFC1BA /* U1DataRepository.m in Sources */,
1334 96CC17E21418094800EFC1BA /* U1NodeJSONParser.m in Sources */,
1335 96CC17E514180C6000EFC1BA /* U1FilesClient.m in Sources */,
1336+ 91B3F2DC141FDFAB00939B3C /* _U1Asset.m in Sources */,
1337+ 91B3F2DF141FDFBE00939B3C /* U1Asset.m in Sources */,
1338+ 91A5E2DC142A70DF00EAAC2B /* U1LocalAssetsManager.m in Sources */,
1339+ 91A5E2DF142B727600EAAC2B /* U1AssetUploadOperation.m in Sources */,
1340 965D7EB91429690C00E4754F /* U1NavigationBar.m in Sources */,
1341 96A169A41430D53700E4C990 /* U1LocalFileInfo.m in Sources */,
1342+ 916E0082143C9A3A0037F6D3 /* U1LocalAssetsViewController.m in Sources */,
1343+ 96CAD3C71457823B007A496C /* NSDictionary+U1Additions.m in Sources */,
1344+ 916BF7611459EF9C00D4FE06 /* U1UTIMapper.m in Sources */,
1345+ 91EC184E145B8E3B00DF31F4 /* U1SettingsViewController.m in Sources */,
1346+ 91EC1858145F0C1600DF31F4 /* RIButtonItem.m in Sources */,
1347+ 91EC185D145F0C3000DF31F4 /* UIActionSheet+Blocks.m in Sources */,
1348+ 91EC185E145F0C3000DF31F4 /* UIAlertView+Blocks.m in Sources */,
1349+ 96B20E78145F815500D8ED69 /* Reachability.m in Sources */,
1350 );
1351 runOnlyForDeploymentPostprocessing = 0;
1352 };
1353@@ -925,13 +1100,26 @@
1354 96E860EF13F7251D0026783D /* Debug */ = {
1355 isa = XCBuildConfiguration;
1356 buildSettings = {
1357+ ARCHS = (
1358+ armv6,
1359+ armv7,
1360+ );
1361+ CODE_SIGN_IDENTITY = "iPhone Developer: Zachery Bir (P7WDPDEFHU)";
1362+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer: Zachery Bir (P7WDPDEFHU)";
1363 GCC_PRECOMPILE_PREFIX_HEADER = YES;
1364 GCC_PREFIX_HEADER = "Files/Files-Prefix.pch";
1365 GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
1366 INFOPLIST_FILE = "Files/Files-Info.plist";
1367 IPHONEOS_DEPLOYMENT_TARGET = 4.0;
1368+ LIBRARY_SEARCH_PATHS = (
1369+ "$(inherited)",
1370+ "\"$(SRCROOT)/Dependencies/TestFlightSDK\"",
1371+ );
1372 PRODUCT_NAME = "$(TARGET_NAME)";
1373+ PROVISIONING_PROFILE = "9D31E6D0-194D-4310-9E89-CB404D06C116";
1374+ "PROVISIONING_PROFILE[sdk=iphoneos*]" = "3D867106-3B81-4625-A9C8-1E9BD85B7E75";
1375 TARGETED_DEVICE_FAMILY = 1;
1376+ VALID_ARCHS = "arm6 armv7";
1377 WRAPPER_EXTENSION = app;
1378 };
1379 name = Debug;
1380@@ -939,15 +1127,26 @@
1381 96E860F013F7251D0026783D /* Release */ = {
1382 isa = XCBuildConfiguration;
1383 buildSettings = {
1384- "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
1385+ ARCHS = (
1386+ armv6,
1387+ armv7,
1388+ );
1389+ CODE_SIGN_IDENTITY = "iPhone Distribution: Canonical Group Limited";
1390+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution: Canonical Group Limited";
1391 GCC_PRECOMPILE_PREFIX_HEADER = YES;
1392 GCC_PREFIX_HEADER = "Files/Files-Prefix.pch";
1393 GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
1394 INFOPLIST_FILE = "Files/Files-Info.plist";
1395 IPHONEOS_DEPLOYMENT_TARGET = 4.0;
1396+ LIBRARY_SEARCH_PATHS = (
1397+ "$(inherited)",
1398+ "\"$(SRCROOT)/Dependencies/TestFlightSDK\"",
1399+ );
1400 PRODUCT_NAME = "$(TARGET_NAME)";
1401- "PROVISIONING_PROFILE[sdk=iphoneos*]" = "";
1402+ PROVISIONING_PROFILE = "B93E008E-7980-4B68-961E-44E81643E70F";
1403+ "PROVISIONING_PROFILE[sdk=iphoneos*]" = "B93E008E-7980-4B68-961E-44E81643E70F";
1404 TARGETED_DEVICE_FAMILY = 1;
1405+ VALID_ARCHS = "arm6 armv7";
1406 WRAPPER_EXTENSION = app;
1407 };
1408 name = Release;
1409@@ -1022,9 +1221,11 @@
1410 96CC17C61417E5E400EFC1BA /* U1Files.xcdatamodeld */ = {
1411 isa = XCVersionGroup;
1412 children = (
1413+ 917ADEC014585DC800980FD4 /* U1Files 1.0-9.xcdatamodel */,
1414+ 96A56430143265B4007A1A93 /* U1Files 1.0-3.xcdatamodel */,
1415 96CC17C71417E5E400EFC1BA /* U1Files.xcdatamodel */,
1416 );
1417- currentVersion = 96CC17C71417E5E400EFC1BA /* U1Files.xcdatamodel */;
1418+ currentVersion = 917ADEC014585DC800980FD4 /* U1Files 1.0-9.xcdatamodel */;
1419 path = U1Files.xcdatamodeld;
1420 sourceTree = "<group>";
1421 versionGroupType = wrapper.xcdatamodel;
1422
1423=== added file 'Files/Entitlements.plist'
1424--- Files/Entitlements.plist 1970-01-01 00:00:00 +0000
1425+++ Files/Entitlements.plist 2011-11-01 14:25:30 +0000
1426@@ -0,0 +1,14 @@
1427+<?xml version="1.0" encoding="UTF-8"?>
1428+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
1429+<plist version="1.0">
1430+<dict>
1431+ <key>application-identifier</key>
1432+ <string>UD653J2ZMP.com.ubuntu.one.files</string>
1433+ <key>get-task-allow</key>
1434+ <false/>
1435+ <key>keychain-access-groups</key>
1436+ <array>
1437+ <string>UD653J2ZMP.com.ubuntu.one</string>
1438+ </array>
1439+</dict>
1440+</plist>
1441
1442=== modified file 'Files/Files-Info.plist'
1443--- Files/Files-Info.plist 2011-09-27 14:42:09 +0000
1444+++ Files/Files-Info.plist 2011-11-01 14:25:30 +0000
1445@@ -9,13 +9,31 @@
1446 <key>CFBundleExecutable</key>
1447 <string>${EXECUTABLE_NAME}</string>
1448 <key>CFBundleIconFile</key>
1449- <string></string>
1450+ <string>Icon.png</string>
1451+ <key>CFBundleIconFiles</key>
1452+ <array>
1453+ <string>Icon.png</string>
1454+ <string>Icon@2x.png</string>
1455+ </array>
1456+ <key>CFBundleIcons</key>
1457+ <dict>
1458+ <key>CFBundlePrimaryIcon</key>
1459+ <dict>
1460+ <key>CFBundleIconFiles</key>
1461+ <array>
1462+ <string>Icon.png</string>
1463+ <string>Icon@2x.png</string>
1464+ </array>
1465+ <key>UIPrerenderedIcon</key>
1466+ <true/>
1467+ </dict>
1468+ </dict>
1469 <key>CFBundleIdentifier</key>
1470- <string>com.ubuntu.one.${PRODUCT_NAME:rfc1034identifier}</string>
1471+ <string>com.ubuntu.one.files</string>
1472 <key>CFBundleInfoDictionaryVersion</key>
1473 <string>6.0</string>
1474 <key>CFBundleName</key>
1475- <string>${PRODUCT_NAME}</string>
1476+ <string>com.ubuntu.one.${PRODUCT_NAME:rfc1034identifier}</string>
1477 <key>CFBundlePackageType</key>
1478 <string>APPL</string>
1479 <key>CFBundleShortVersionString</key>
1480@@ -23,13 +41,11 @@
1481 <key>CFBundleSignature</key>
1482 <string>????</string>
1483 <key>CFBundleVersion</key>
1484- <string>2</string>
1485+ <string>16</string>
1486 <key>LSRequiresIPhoneOS</key>
1487 <true/>
1488 <key>NSMainNibFile</key>
1489 <string>MainWindow_iPhone</string>
1490- <key>NSMainNibFile~ipad</key>
1491- <string>MainWindow_iPad</string>
1492 <key>UISupportedInterfaceOrientations</key>
1493 <array>
1494 <string>UIInterfaceOrientationPortrait</string>
1495
1496=== modified file 'Files/Files-Prefix.pch'
1497--- Files/Files-Prefix.pch 2011-08-31 14:56:30 +0000
1498+++ Files/Files-Prefix.pch 2011-11-01 14:25:30 +0000
1499@@ -20,6 +20,10 @@
1500 #endif
1501
1502 #ifdef __OBJC__
1503- #import <UIKit/UIKit.h>
1504- #import <Foundation/Foundation.h>
1505+
1506+#import <UIKit/UIKit.h>
1507+#import <Foundation/Foundation.h>
1508+#import "TestFlight.h"
1509+#import "NSDictionary+U1Additions.h"
1510+
1511 #endif
1512
1513=== modified file 'Files/FilesAppDelegate.h'
1514--- Files/FilesAppDelegate.h 2011-09-27 14:36:00 +0000
1515+++ Files/FilesAppDelegate.h 2011-11-01 14:25:30 +0000
1516@@ -18,7 +18,10 @@
1517
1518 @interface FilesAppDelegate : NSObject <UIApplicationDelegate>
1519
1520-@property (nonatomic, retain, readonly) IBOutlet UIWindow *window;
1521-@property (nonatomic, retain) IBOutlet UINavigationController *navController;
1522+@property (nonatomic, retain) IBOutlet UIWindow *window;
1523+@property (nonatomic, retain) IBOutlet UITabBarController *tabBarController;
1524+@property (nonatomic, retain) IBOutlet UINavigationController *volumesNavController;
1525+@property (nonatomic, retain) IBOutlet UINavigationController *cameraNavController;
1526+@property (nonatomic, retain) IBOutlet UINavigationController *settingsNavController;
1527
1528 @end
1529
1530=== modified file 'Files/FilesAppDelegate.m'
1531--- Files/FilesAppDelegate.m 2011-09-27 14:36:00 +0000
1532+++ Files/FilesAppDelegate.m 2011-11-01 14:25:30 +0000
1533@@ -13,6 +13,10 @@
1534 // You should have received a copy of the GNU Affero General Public License
1535 // along with this program. If not, see <http://www.gnu.org/licenses/>.
1536
1537+#import <AssetsLibrary/ALAssetsLibrary.h>
1538+#import <AssetsLibrary/ALAssetsGroup.h>
1539+#import <AssetsLibrary/ALAsset.h>
1540+
1541 #import "FilesAppDelegate.h"
1542
1543 #import "U1AccountManager.h"
1544@@ -20,36 +24,47 @@
1545 #import "U1FileNode.h"
1546 #import "U1FilePreviewViewController.h"
1547 #import "U1FilesClient.h"
1548-#import "U1FilesService.h"
1549+#import "U1LocalAssetsManager.h"
1550+#import "U1LocalAssetsViewController.h"
1551 #import "U1FolderNode.h"
1552 #import "U1FolderViewController.h"
1553 #import "U1LoginController.h"
1554 #import "U1Node.h"
1555+#import "U1SettingsViewController.h"
1556 #import "U1VolumesViewController.h"
1557-
1558-
1559-@interface FilesAppDelegate () <U1FolderViewControllerDelegate, U1VolumesViewControllerDelegate, U1LoginControllerDelegate>
1560-@property (retain) U1FilesService *filesService;
1561+#import "U1Volume.h"
1562+#import "UIAlertView+Blocks.h"
1563+#import "RIButtonItem.h"
1564+
1565+
1566+@interface FilesAppDelegate () <U1LoginControllerDelegate>
1567 @property (retain) U1FilesClient *filesClient;
1568+@property (retain) U1LocalAssetsManager *localAssetsManager;
1569 @property (retain) U1LoginController *loginController;
1570 @property (retain) U1DataRepository *dataRepository;
1571-- (NSURL*)dataStoreURL;
1572 - (void)showVolumes;
1573 - (void)showLoginController;
1574+- (void)ensureUploadFolder;
1575+- (NSString*)remoteUploadFolderPath;
1576+- (NSString*)localUploadQueuePath;
1577+- (void)prepareTestFlight;
1578 @end
1579
1580
1581 @implementation FilesAppDelegate
1582
1583-@synthesize window;
1584-@synthesize filesService, filesClient, navController, loginController, dataRepository;
1585+@synthesize window, volumesNavController, cameraNavController;
1586+@synthesize filesClient, localAssetsManager, tabBarController, settingsNavController, loginController, dataRepository;
1587
1588 - (void)dealloc
1589 {
1590 [window release];
1591- [filesService release];
1592+ [volumesNavController release];
1593+ [cameraNavController release];
1594+ [settingsNavController release];
1595 [filesClient release];
1596- [navController release];
1597+ [localAssetsManager release];
1598+ [tabBarController release];
1599 [loginController release];
1600 [dataRepository release];
1601 [super dealloc];
1602@@ -57,8 +72,17 @@
1603
1604 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
1605 {
1606+ [self prepareTestFlight];
1607+
1608+ [[NSUserDefaults standardUserDefaults] registerDefaults:[NSDictionary dictionaryWithContentsOfFile:
1609+ [[NSBundle mainBundle] pathForResource:@"default-settings" ofType:@"plist"]]];
1610+
1611+ self.localAssetsManager = [U1LocalAssetsManager sharedLocalAssetsManager];
1612+ self.filesClient = [U1FilesClient sharedFilesClient];
1613+
1614+ [window addSubview:[tabBarController view]];
1615 [self.window makeKeyAndVisible];
1616-
1617+
1618 if (![[U1AccountManager sharedAccountManager] hasCredentials])
1619 {
1620 [self showLoginController];
1621@@ -71,87 +95,142 @@
1622 return YES;
1623 }
1624
1625+- (void)applicationDidBecomeActive:(UIApplication *)application;
1626+{
1627+ if ([[U1AccountManager sharedAccountManager] hasCredentials])
1628+ {
1629+ [self ensureUploadFolder];
1630+ }
1631+}
1632+
1633+- (void)ensureUploadFolder;
1634+{
1635+
1636+ NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
1637+
1638+ if (![defaults boolForKey:@"asked_auto_upload_on_first_launch"])
1639+ {
1640+ RIButtonItem *cancelButton = [RIButtonItem item];
1641+ cancelButton.label = NSLocalizedString(@"No", @"");
1642+ cancelButton.action = ^
1643+ {
1644+ [defaults setBool:YES forKey:@"asked_auto_upload_on_first_launch"];
1645+ };
1646+
1647+ RIButtonItem *dismissButton = [RIButtonItem item];
1648+ dismissButton.label = NSLocalizedString(@"Yes", @"");
1649+ dismissButton.action = ^
1650+ {
1651+ [defaults setBool:YES forKey:@"auto_uploads"];
1652+ [defaults setBool:YES forKey:@"asked_auto_upload_on_first_launch"];
1653+ };
1654+
1655+ UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Auto-Upload", @"")
1656+ message:NSLocalizedString(@"Shall I automatically upload all items in your camera roll?", @"")
1657+ cancelButtonItem:cancelButton otherButtonItems:dismissButton, nil];
1658+ [alertView show];
1659+ [alertView release];
1660+ }
1661+
1662+ [self.filesClient volumesWithCompletionBlock:^(U1Volume *rootVolume, NSFetchedResultsController *cloudFoldersResultsController, NSError *error) {
1663+ dispatch_async(dispatch_get_main_queue(), ^(void) {
1664+ // iterate over volumeInfos. If there isn't one there called "Pictures - <device name>", create it.
1665+ BOOL found = NO;
1666+ for (U1Volume *volume in [cloudFoldersResultsController fetchedObjects]) {
1667+ if ([volume.nodePath isEqualToString:[self remoteUploadFolderPath]])
1668+ {
1669+ found = YES;
1670+ self.localAssetsManager.remoteUploadFolder = [volume rootFolder];
1671+ break;
1672+ }
1673+ }
1674+ if (!found)
1675+ {
1676+ [self.filesClient createVolumeAtPath:[self remoteUploadFolderPath]
1677+ completionBlock:^(U1Volume *volume, NSError *error) {
1678+ self.localAssetsManager.remoteUploadFolder = [volume rootFolder];
1679+ [self.localAssetsManager checkForNewAssets];
1680+ if (error)
1681+ {
1682+ NSLog(@"Error: %@", error);
1683+ }
1684+ }];
1685+ } else
1686+ {
1687+ [self.localAssetsManager checkForNewAssets];
1688+ }
1689+ });
1690+ }];
1691+}
1692+
1693+- (NSString *)remoteUploadFolderPath;
1694+{
1695+ return [NSString stringWithFormat:@"/~/Pictures - %@", [[UIDevice currentDevice] name]];
1696+}
1697+
1698+- (NSString*)localUploadQueuePath;
1699+{
1700+ NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
1701+ return [[paths objectAtIndex:0] stringByAppendingPathComponent:@"localAssetsToUpload.array"];
1702+}
1703+
1704 - (void)applicationWillResignActive:(UIApplication *)application;
1705 {
1706 [self.dataRepository save:NULL];
1707+ [[NSUserDefaults standardUserDefaults] synchronize];
1708 }
1709
1710 - (void)applicationWillTerminate:(UIApplication *)application;
1711 {
1712 // TODO: check error
1713 [self.dataRepository save:NULL];
1714-}
1715-
1716-- (NSURL*)dataStoreURL;
1717-{
1718- NSURL *cachesDirectory = [[[NSFileManager defaultManager] URLsForDirectory:NSCachesDirectory inDomains:NSUserDomainMask] lastObject];
1719- NSURL *storeURL = [NSURL URLWithString:@"U1Files.sqlite" relativeToURL:cachesDirectory];
1720- return storeURL;
1721+ [[NSUserDefaults standardUserDefaults] synchronize];
1722 }
1723
1724 - (void)showVolumes;
1725 {
1726- filesService = [U1FilesService new];
1727-
1728- NSURL *storeURL = [self dataStoreURL];
1729- self.dataRepository = [[U1DataRepository alloc] initWithStoreURL:storeURL];
1730- [dataRepository release];
1731-
1732- filesClient = [[U1FilesClient alloc] init];
1733- [self.filesClient setFilesService:filesService];
1734- [self.filesClient setDataRepository:self.dataRepository];
1735-
1736- U1VolumesViewController *rootController = [U1VolumesViewController new];
1737- rootController.delegate = self;
1738- rootController.filesService = self.filesService;
1739-
1740- [self.navController setViewControllers:[NSArray arrayWithObject:rootController] animated:NO];
1741+ U1VolumesViewController *volumesViewController = [[[U1VolumesViewController alloc] init] autorelease];
1742+ [self.volumesNavController setViewControllers:[NSArray arrayWithObject:volumesViewController]];
1743+ U1LocalAssetsViewController *assetsViewController = [[[U1LocalAssetsViewController alloc] initWithNodeResourcePath:[self remoteUploadFolderPath]] autorelease];
1744+ [self.cameraNavController setViewControllers:[NSArray arrayWithObject:assetsViewController]];
1745+ U1SettingsViewController *settingsViewController = [[U1SettingsViewController alloc] initWithNibName:@"U1SettingsViewController" bundle:nil];
1746+ [self.settingsNavController setViewControllers:[NSArray arrayWithObject:settingsViewController]];
1747 }
1748
1749 - (void)showLoginController;
1750 {
1751 self.loginController = [[[U1LoginController alloc] init] autorelease];
1752 self.loginController.delegate = self;
1753- [self.navController presentModalViewController:self.loginController.loginViewController animated:YES];
1754+ [self.tabBarController presentModalViewController:self.loginController.loginViewController animated:YES];
1755 }
1756
1757 - (void)loginControllerDidLogin;
1758 {
1759- [self.navController dismissModalViewControllerAnimated:YES];
1760+ [self.tabBarController dismissModalViewControllerAnimated:YES];
1761 self.loginController = nil;
1762 [self showVolumes];
1763-}
1764-
1765-
1766-#pragma mark U1FolderViewControllerDelegate Methods
1767-
1768-- (void)folderController:(U1FolderViewController*)folderController didSelectNode:(U1Node*)node;
1769-{
1770- if ([node isFolder])
1771- {
1772- U1FolderViewController *nextFolderController = [[U1FolderViewController alloc] initWithNodeResourcePath:node.resourcePath];
1773- nextFolderController.filesClient = self.filesClient;
1774- nextFolderController.delegate = self;
1775- [self.navController pushViewController:nextFolderController animated:YES];
1776- }
1777- else if ([node isFile])
1778- {
1779- U1FilePreviewViewController *fileController = [[U1FilePreviewViewController alloc] initWithNode:(id)node];
1780- fileController.filesClient = self.filesClient;
1781- [self.navController pushViewController:fileController animated:YES];
1782- }
1783-}
1784-
1785-
1786-#pragma mark U1VolumesControllerDelegate Methods
1787-
1788-- (void)volumesController:(U1VolumesViewController *)volumesController didSelectVolume:(NSDictionary *)volume;
1789-{
1790- NSString *nodePath = [volume objectForKey:@"node_path"];
1791- U1FolderViewController *folderController = [[U1FolderViewController alloc] initWithNodeResourcePath:nodePath];
1792- folderController.filesClient = self.filesClient;
1793- folderController.delegate = self;
1794- [self.navController pushViewController:folderController animated:YES];
1795-}
1796+ [self ensureUploadFolder];
1797+}
1798+
1799+- (void)prepareTestFlight;
1800+{
1801+ NSString *tokenFilePath = [[NSBundle mainBundle] pathForResource:@"U1TestFlightTeamToken" ofType:@"txt"];
1802+ if (!tokenFilePath)
1803+ return;
1804+
1805+ NSError *error = nil;
1806+ NSString *teamToken = [NSString stringWithContentsOfFile:tokenFilePath usedEncoding:NULL error:&error];
1807+
1808+ if (teamToken)
1809+ {
1810+ teamToken = [teamToken stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
1811+ [TestFlight takeOff:teamToken];
1812+ }
1813+ else
1814+ {
1815+ NSLog(@"error loading TestFlight team token: %@", error);
1816+ }
1817+}
1818+
1819
1820 @end
1821
1822=== added file 'Files/Generated/_U1Asset.h'
1823--- Files/Generated/_U1Asset.h 1970-01-01 00:00:00 +0000
1824+++ Files/Generated/_U1Asset.h 2011-11-01 14:25:30 +0000
1825@@ -0,0 +1,111 @@
1826+// DO NOT EDIT. This file is machine-generated and constantly overwritten.
1827+// Make changes to U1Asset.h instead.
1828+
1829+#import <CoreData/CoreData.h>
1830+
1831+
1832+@class U1FileNode;
1833+
1834+
1835+
1836+
1837+
1838+
1839+@interface U1AssetID : NSManagedObjectID {}
1840+@end
1841+
1842+@interface _U1Asset : NSManagedObject {}
1843++ (id)insertInManagedObjectContext:(NSManagedObjectContext*)moc_;
1844++ (NSString*)entityName;
1845++ (NSEntityDescription*)entityInManagedObjectContext:(NSManagedObjectContext*)moc_;
1846+- (U1AssetID*)objectID;
1847+
1848+
1849+
1850+
1851+@property (nonatomic, retain) NSString *filename;
1852+
1853+
1854+//- (BOOL)validateFilename:(id*)value_ error:(NSError**)error_;
1855+
1856+
1857+
1858+
1859+@property (nonatomic, retain) NSNumber *generation;
1860+
1861+
1862+@property int generationValue;
1863+- (int)generationValue;
1864+- (void)setGenerationValue:(int)value_;
1865+
1866+//- (BOOL)validateGeneration:(id*)value_ error:(NSError**)error_;
1867+
1868+
1869+
1870+
1871+@property (nonatomic, retain) NSString *groupId;
1872+
1873+
1874+//- (BOOL)validateGroupId:(id*)value_ error:(NSError**)error_;
1875+
1876+
1877+
1878+
1879+@property (nonatomic, retain) NSString *url;
1880+
1881+
1882+//- (BOOL)validateUrl:(id*)value_ error:(NSError**)error_;
1883+
1884+
1885+
1886+
1887+
1888+@property (nonatomic, retain) U1FileNode* fileNode;
1889+
1890+//- (BOOL)validateFileNode:(id*)value_ error:(NSError**)error_;
1891+
1892+
1893+
1894+
1895+@end
1896+
1897+@interface _U1Asset (CoreDataGeneratedAccessors)
1898+
1899+@end
1900+
1901+@interface _U1Asset (CoreDataGeneratedPrimitiveAccessors)
1902+
1903+
1904+- (NSString*)primitiveFilename;
1905+- (void)setPrimitiveFilename:(NSString*)value;
1906+
1907+
1908+
1909+
1910+- (NSNumber*)primitiveGeneration;
1911+- (void)setPrimitiveGeneration:(NSNumber*)value;
1912+
1913+- (int)primitiveGenerationValue;
1914+- (void)setPrimitiveGenerationValue:(int)value_;
1915+
1916+
1917+
1918+
1919+- (NSString*)primitiveGroupId;
1920+- (void)setPrimitiveGroupId:(NSString*)value;
1921+
1922+
1923+
1924+
1925+- (NSString*)primitiveUrl;
1926+- (void)setPrimitiveUrl:(NSString*)value;
1927+
1928+
1929+
1930+
1931+
1932+- (U1FileNode*)primitiveFileNode;
1933+- (void)setPrimitiveFileNode:(U1FileNode*)value;
1934+
1935+
1936+@end
1937
1938=== added file 'Files/Generated/_U1Asset.m'
1939--- Files/Generated/_U1Asset.m 1970-01-01 00:00:00 +0000
1940+++ Files/Generated/_U1Asset.m 2011-11-01 14:25:30 +0000
1941@@ -0,0 +1,98 @@
1942+// DO NOT EDIT. This file is machine-generated and constantly overwritten.
1943+// Make changes to U1Asset.m instead.
1944+
1945+#import "_U1Asset.h"
1946+
1947+@implementation U1AssetID
1948+@end
1949+
1950+@implementation _U1Asset
1951+
1952++ (id)insertInManagedObjectContext:(NSManagedObjectContext*)moc_ {
1953+ NSParameterAssert(moc_);
1954+ return [NSEntityDescription insertNewObjectForEntityForName:@"Asset" inManagedObjectContext:moc_];
1955+}
1956+
1957++ (NSString*)entityName {
1958+ return @"Asset";
1959+}
1960+
1961++ (NSEntityDescription*)entityInManagedObjectContext:(NSManagedObjectContext*)moc_ {
1962+ NSParameterAssert(moc_);
1963+ return [NSEntityDescription entityForName:@"Asset" inManagedObjectContext:moc_];
1964+}
1965+
1966+- (U1AssetID*)objectID {
1967+ return (U1AssetID*)[super objectID];
1968+}
1969+
1970++ (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key {
1971+ NSSet *keyPaths = [super keyPathsForValuesAffectingValueForKey:key];
1972+
1973+ if ([key isEqualToString:@"generationValue"]) {
1974+ NSSet *affectingKey = [NSSet setWithObject:@"generation"];
1975+ keyPaths = [keyPaths setByAddingObjectsFromSet:affectingKey];
1976+ }
1977+
1978+ return keyPaths;
1979+}
1980+
1981+
1982+
1983+
1984+@dynamic filename;
1985+
1986+
1987+
1988+
1989+
1990+
1991+@dynamic generation;
1992+
1993+
1994+
1995+- (int)generationValue {
1996+ NSNumber *result = [self generation];
1997+ return [result intValue];
1998+}
1999+
2000+- (void)setGenerationValue:(int)value_ {
2001+ [self setGeneration:[NSNumber numberWithInt:value_]];
2002+}
2003+
2004+- (int)primitiveGenerationValue {
2005+ NSNumber *result = [self primitiveGeneration];
2006+ return [result intValue];
2007+}
2008+
2009+- (void)setPrimitiveGenerationValue:(int)value_ {
2010+ [self setPrimitiveGeneration:[NSNumber numberWithInt:value_]];
2011+}
2012+
2013+
2014+
2015+
2016+
2017+@dynamic groupId;
2018+
2019+
2020+
2021+
2022+
2023+
2024+@dynamic url;
2025+
2026+
2027+
2028+
2029+
2030+
2031+@dynamic fileNode;
2032+
2033+
2034+
2035+
2036+
2037+
2038+
2039+@end
2040
2041=== modified file 'Files/Generated/_U1FileNode.h'
2042--- Files/Generated/_U1FileNode.h 2011-09-08 16:59:34 +0000
2043+++ Files/Generated/_U1FileNode.h 2011-11-01 14:25:30 +0000
2044@@ -4,6 +4,7 @@
2045 #import <CoreData/CoreData.h>
2046 #import "U1Node.h"
2047
2048+@class U1Asset;
2049
2050
2051
2052@@ -54,6 +55,13 @@
2053
2054
2055
2056+@property (nonatomic, retain) U1Asset* asset;
2057+
2058+//- (BOOL)validateAsset:(id*)value_ error:(NSError**)error_;
2059+
2060+
2061+
2062+
2063 @end
2064
2065 @interface _U1FileNode (CoreDataGeneratedAccessors)
2066@@ -87,4 +95,9 @@
2067
2068
2069
2070+
2071+- (U1Asset*)primitiveAsset;
2072+- (void)setPrimitiveAsset:(U1Asset*)value;
2073+
2074+
2075 @end
2076
2077=== modified file 'Files/Generated/_U1FileNode.m'
2078--- Files/Generated/_U1FileNode.m 2011-09-08 16:59:34 +0000
2079+++ Files/Generated/_U1FileNode.m 2011-11-01 14:25:30 +0000
2080@@ -103,6 +103,10 @@
2081
2082
2083
2084+@dynamic asset;
2085+
2086+
2087+
2088
2089
2090
2091
2092=== modified file 'Files/Generated/_U1Volume.h'
2093--- Files/Generated/_U1Volume.h 2011-09-08 16:59:34 +0000
2094+++ Files/Generated/_U1Volume.h 2011-11-01 14:25:30 +0000
2095@@ -2,6 +2,7 @@
2096 // Make changes to U1Volume.h instead.
2097
2098 #import <CoreData/CoreData.h>
2099+#import "U1Node.h"
2100
2101
2102
2103@@ -9,7 +10,7 @@
2104 @interface U1VolumeID : NSManagedObjectID {}
2105 @end
2106
2107-@interface _U1Volume : NSManagedObject {}
2108+@interface _U1Volume : U1Node {}
2109 + (id)insertInManagedObjectContext:(NSManagedObjectContext*)moc_;
2110 + (NSString*)entityName;
2111 + (NSEntityDescription*)entityInManagedObjectContext:(NSManagedObjectContext*)moc_;
2112@@ -18,6 +19,14 @@
2113
2114
2115
2116+@property (nonatomic, retain) NSString *nodePath;
2117+
2118+
2119+//- (BOOL)validateNodePath:(id*)value_ error:(NSError**)error_;
2120+
2121+
2122+
2123+
2124
2125 @end
2126
2127@@ -28,4 +37,10 @@
2128 @interface _U1Volume (CoreDataGeneratedPrimitiveAccessors)
2129
2130
2131+- (NSString*)primitiveNodePath;
2132+- (void)setPrimitiveNodePath:(NSString*)value;
2133+
2134+
2135+
2136+
2137 @end
2138
2139=== modified file 'Files/Generated/_U1Volume.m'
2140--- Files/Generated/_U1Volume.m 2011-09-08 16:59:34 +0000
2141+++ Files/Generated/_U1Volume.m 2011-11-01 14:25:30 +0000
2142@@ -36,6 +36,13 @@
2143
2144
2145
2146+@dynamic nodePath;
2147+
2148+
2149+
2150+
2151+
2152+
2153
2154
2155
2156
2157=== added file 'Files/NSDictionary+U1Additions.h'
2158--- Files/NSDictionary+U1Additions.h 1970-01-01 00:00:00 +0000
2159+++ Files/NSDictionary+U1Additions.h 2011-11-01 14:25:30 +0000
2160@@ -0,0 +1,23 @@
2161+//
2162+// Copyright 2011 Canonical Ltd.
2163+//
2164+// This program is free software: you can redistribute it and/or modify it
2165+// under the terms of the GNU Affero General Public License version 3,
2166+// as published by the Free Software Foundation.
2167+//
2168+// This program is distributed in the hope that it will be useful, but
2169+// WITHOUT ANY WARRANTY; without even the implied warranties of
2170+// MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
2171+// PURPOSE. See the GNU Affero General Public License for more details.
2172+//
2173+// You should have received a copy of the GNU Affero General Public License
2174+// along with this program. If not, see <http://www.gnu.org/licenses/>.
2175+
2176+#import <Foundation/Foundation.h>
2177+
2178+
2179+@interface NSDictionary (U1Additions)
2180+
2181+- (id)nonNullValueForKey:(NSString*)key;
2182+
2183+@end
2184
2185=== added file 'Files/NSDictionary+U1Additions.m'
2186--- Files/NSDictionary+U1Additions.m 1970-01-01 00:00:00 +0000
2187+++ Files/NSDictionary+U1Additions.m 2011-11-01 14:25:30 +0000
2188@@ -0,0 +1,29 @@
2189+//
2190+// Copyright 2011 Canonical Ltd.
2191+//
2192+// This program is free software: you can redistribute it and/or modify it
2193+// under the terms of the GNU Affero General Public License version 3,
2194+// as published by the Free Software Foundation.
2195+//
2196+// This program is distributed in the hope that it will be useful, but
2197+// WITHOUT ANY WARRANTY; without even the implied warranties of
2198+// MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
2199+// PURPOSE. See the GNU Affero General Public License for more details.
2200+//
2201+// You should have received a copy of the GNU Affero General Public License
2202+// along with this program. If not, see <http://www.gnu.org/licenses/>.
2203+
2204+#import "NSDictionary+U1Additions.h"
2205+
2206+
2207+@implementation NSDictionary (U1Additions)
2208+
2209+- (id)nonNullValueForKey:(NSString*)key;
2210+{
2211+ id value = [self valueForKey:key];
2212+ if (value == [NSNull null])
2213+ return nil;
2214+ return value;
2215+}
2216+
2217+@end
2218
2219=== added file 'Files/U1Asset.h'
2220--- Files/U1Asset.h 1970-01-01 00:00:00 +0000
2221+++ Files/U1Asset.h 2011-11-01 14:25:30 +0000
2222@@ -0,0 +1,5 @@
2223+#import "_U1Asset.h"
2224+
2225+@interface U1Asset : _U1Asset {}
2226+// Custom logic goes here.
2227+@end
2228
2229=== added file 'Files/U1Asset.m'
2230--- Files/U1Asset.m 1970-01-01 00:00:00 +0000
2231+++ Files/U1Asset.m 2011-11-01 14:25:30 +0000
2232@@ -0,0 +1,7 @@
2233+#import "U1Asset.h"
2234+
2235+@implementation U1Asset
2236+
2237+// Custom logic goes here.
2238+
2239+@end
2240
2241=== added file 'Files/U1AssetUploadOperation.h'
2242--- Files/U1AssetUploadOperation.h 1970-01-01 00:00:00 +0000
2243+++ Files/U1AssetUploadOperation.h 2011-11-01 14:25:30 +0000
2244@@ -0,0 +1,32 @@
2245+//
2246+// Copyright 2011 Canonical Ltd.
2247+//
2248+// This program is free software: you can redistribute it and/or modify it
2249+// under the terms of the GNU Affero General Public License version 3,
2250+// as published by the Free Software Foundation.
2251+//
2252+// This program is distributed in the hope that it will be useful, but
2253+// WITHOUT ANY WARRANTY; without even the implied warranties of
2254+// MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
2255+// PURPOSE. See the GNU Affero General Public License for more details.
2256+//
2257+// You should have received a copy of the GNU Affero General Public License
2258+// along with this program. If not, see <http://www.gnu.org/licenses/>.
2259+
2260+#import <Foundation/Foundation.h>
2261+#import <AssetsLibrary/AssetsLibrary.h>
2262+
2263+@class U1Asset;
2264+@class U1FolderNode;
2265+
2266+@interface U1AssetUploadOperation : NSOperation {
2267+@private
2268+
2269+}
2270+@property (retain) ALAssetRepresentation *representation;
2271+@property (retain) U1Asset *asset;
2272+@property (retain) U1FolderNode *folder;
2273+@property (retain) NSString *filename;
2274+@property (retain) NSString *mimetype;
2275+@property (retain) NSError *error;
2276+@end
2277
2278=== added file 'Files/U1AssetUploadOperation.m'
2279--- Files/U1AssetUploadOperation.m 1970-01-01 00:00:00 +0000
2280+++ Files/U1AssetUploadOperation.m 2011-11-01 14:25:30 +0000
2281@@ -0,0 +1,103 @@
2282+//
2283+// Copyright 2011 Canonical Ltd.
2284+//
2285+// This program is free software: you can redistribute it and/or modify it
2286+// under the terms of the GNU Affero General Public License version 3,
2287+// as published by the Free Software Foundation.
2288+//
2289+// This program is distributed in the hope that it will be useful, but
2290+// WITHOUT ANY WARRANTY; without even the implied warranties of
2291+// MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
2292+// PURPOSE. See the GNU Affero General Public License for more details.
2293+//
2294+// You should have received a copy of the GNU Affero General Public License
2295+// along with this program. If not, see <http://www.gnu.org/licenses/>.
2296+
2297+#import "U1AssetUploadOperation.h"
2298+#import "U1Asset.h"
2299+#import "U1FilesClient.h"
2300+#import "U1FileNode.h"
2301+#import "U1FolderNode.h"
2302+
2303+@interface U1AssetUploadOperation ()
2304+@property (getter=isExecuting) BOOL executing;
2305+@property (getter=isFinished) BOOL finished;
2306+- (void)finishExecuting;
2307+@end
2308+
2309+@implementation U1AssetUploadOperation
2310+
2311+@synthesize executing, finished, asset, representation, folder, filename, mimetype, error;
2312+
2313+- (id)init
2314+{
2315+ self = [super init];
2316+ if (self) {
2317+ // Initialization code here.
2318+ }
2319+
2320+ return self;
2321+}
2322+
2323+- (BOOL)isConcurrent;
2324+{
2325+ return YES;
2326+}
2327+
2328+- (void)finishExecuting;
2329+{
2330+ [self willChangeValueForKey:@"isExecuting"];
2331+ [self willChangeValueForKey:@"isFinished"];
2332+ self.finished = YES;
2333+ self.executing = NO;
2334+ [self didChangeValueForKey:@"isFinished"];
2335+ [self didChangeValueForKey:@"isExecuting"];
2336+// [UONetworkStatusCoordinator removeNetworkActivity];
2337+}
2338+
2339+- (void)start;
2340+{
2341+ [self willChangeValueForKey:@"isExecuting"];
2342+ self.executing = YES;
2343+ [self didChangeValueForKey:@"isExecuting"];
2344+
2345+ U1FilesClient *filesClient = [U1FilesClient sharedFilesClient];
2346+
2347+ // if the file already exists at that resourcePath, skip it. In the future, we should do stuff like test that the remote resource's size is the same as our size, and do the right thing accordingly, but I'm not sure what that is right now.
2348+
2349+ dispatch_async(dispatch_get_main_queue(), ^(void) {
2350+ [filesClient fetchFileWithResourcePath:[[self.folder resourcePath] stringByAppendingPathComponent:self.filename] completionBlock:^(U1Node *node, NSError *error) {
2351+ if (node.generation == nil)
2352+ {
2353+ Byte *buffer = (Byte*)malloc(self.representation.size);
2354+ NSUInteger length = [self.representation getBytes:buffer fromOffset:0 length:self.representation.size error:nil];
2355+ NSData *assetData = [NSData dataWithBytesNoCopy:buffer length:length freeWhenDone:YES];
2356+
2357+ dispatch_async(dispatch_get_main_queue(), ^(void) {
2358+ [filesClient uploadContentData:assetData
2359+ toFolder:self.folder
2360+ withResourceName:self.filename
2361+ withContentType:self.mimetype
2362+ progressBlock:^(long long bytesUploaded, long long totalBytes) {
2363+ // dispatch_async(dispatch_get_main_queue(), ^(void){
2364+ // NSLog(@"Uploaded %lld of %lld for %@", bytesUploaded, totalBytes, self.filename);
2365+ // });
2366+ } completionBlock:^(U1FileNode *updatedNode, NSError *uploadError) {
2367+ self.error = uploadError;
2368+ [self finishExecuting];
2369+ }];
2370+ });
2371+ }
2372+ else {
2373+ [self finishExecuting];
2374+ }
2375+ }];
2376+ });
2377+}
2378+
2379+- (void)dealloc
2380+{
2381+ [super dealloc];
2382+}
2383+
2384+@end
2385
2386=== modified file 'Files/U1ByteSizeValueTransformer.m'
2387--- Files/U1ByteSizeValueTransformer.m 2011-08-31 14:56:30 +0000
2388+++ Files/U1ByteSizeValueTransformer.m 2011-11-01 14:25:30 +0000
2389@@ -29,7 +29,7 @@
2390 if (![value isKindOfClass:[NSNumber class]])
2391 return nil;
2392
2393- CGFloat size = (CGFloat)[value unsignedIntValue];
2394+ double size = [value doubleValue];
2395 NSUInteger suffixIndex = 0;
2396 while (size > 1024.f && ++suffixIndex < sizeof(suffixes))
2397 {
2398
2399=== modified file 'Files/U1DataRepository.h'
2400--- Files/U1DataRepository.h 2011-09-08 16:59:34 +0000
2401+++ Files/U1DataRepository.h 2011-11-01 14:25:30 +0000
2402@@ -20,12 +20,16 @@
2403
2404
2405 @interface U1DataRepository : NSObject
2406-
2407++ (U1DataRepository*)sharedDataRepository;
2408 - (id)initWithStoreURL:(NSURL*)storeURL;
2409 - (BOOL)save:(NSError**)error;
2410
2411 - (U1Node*)nodeWithResourcePath:(NSString*)resourcePath;
2412
2413+//- (void)fetchResultsForEntityClass:(Class)entityClass matchingPredicate:(NSPredicate*)predicate withSortDescriptors:(NSArray*)sortDescriptors completionBlock:(void(^)(NSArray *results, NSError *error))completionBlock;
2414+
2415+- (NSArray*)resultsForEntityClass:(Class)entityClass matchingPredicate:(NSPredicate*)predicate withSortDescriptors:(NSArray*)sortDescriptors error:(NSError**)error;
2416+
2417 - (void)dispatchBlockWithManagedObjectContext:(void(^)(NSManagedObjectContext *context))block;
2418
2419 - (void)dispatchAsyncBlockWithManagedObjectContext:(void(^)(NSManagedObjectContext *context))block;
2420
2421=== modified file 'Files/U1DataRepository.m'
2422--- Files/U1DataRepository.m 2011-09-08 16:59:34 +0000
2423+++ Files/U1DataRepository.m 2011-11-01 14:25:30 +0000
2424@@ -19,6 +19,7 @@
2425
2426 #import "U1Node.h"
2427
2428+static U1DataRepository *sharedDataRepository = nil;
2429
2430 @interface U1DataRepository ()
2431
2432@@ -35,6 +36,18 @@
2433
2434 @synthesize model, mainContext, storeCoordinator;
2435
2436++ (U1DataRepository*)sharedDataRepository;
2437+{
2438+ if (sharedDataRepository == nil)
2439+ {
2440+ NSURL *cachesDirectory = [[[NSFileManager defaultManager] URLsForDirectory:NSCachesDirectory
2441+ inDomains:NSUserDomainMask] lastObject];
2442+ NSURL *storeURL = [NSURL URLWithString:@"U1Files.sqlite" relativeToURL:cachesDirectory];
2443+ sharedDataRepository = [[self alloc] initWithStoreURL:storeURL];
2444+ }
2445+ return sharedDataRepository;
2446+}
2447+
2448 - (id)initWithStoreURL:(NSURL*)storeURL;
2449 {
2450 if (!(self = [super init]))
2451@@ -93,6 +106,16 @@
2452 return node;
2453 }
2454
2455+//- (void)fetchResultsForEntityClass:(Class)entityClass matchingPredicate:(NSPredicate*)predicate withSortDescriptors:(NSArray*)sortDescriptors completionBlock:(void(^)(NSArray *results, NSError *error))completionBlock;
2456+//{
2457+//
2458+//}
2459+
2460+- (NSArray*)resultsForEntityClass:(Class)entityClass matchingPredicate:(NSPredicate*)predicate withSortDescriptors:(NSArray*)sortDescriptors error:(NSError**)error;
2461+{
2462+ return [self fetchEntitiesForClass:entityClass inContext:self.mainContext withPredicate:predicate sortDescriptors:sortDescriptors error:error];
2463+}
2464+
2465 - (NSArray*)fetchEntitiesForClass:(Class)class inContext:(NSManagedObjectContext*)context withPredicate:(NSPredicate*)predicate sortDescriptors:(NSArray*)sortDescriptors error:(NSError**)error;
2466 {
2467 NSParameterAssert(class != nil);
2468
2469=== modified file 'Files/U1FileNode.m'
2470--- Files/U1FileNode.m 2011-09-08 16:59:34 +0000
2471+++ Files/U1FileNode.m 2011-11-01 14:25:30 +0000
2472@@ -21,11 +21,9 @@
2473 - (void)updatePropertiesFromJSONDictionary:(NSDictionary*)jsonDictionary;
2474 {
2475 [super updatePropertiesFromJSONDictionary:jsonDictionary];
2476- self.size = [[jsonDictionary objectForKey:@"size"] copy];
2477- self.isPublic = [[jsonDictionary objectForKey:@"is_public"] copy];
2478- NSString *url = [jsonDictionary objectForKey:@"public_url"];
2479- if (url != (id)[NSNull null])
2480- self.publicURLString = [url copy];
2481+ self.size = [jsonDictionary nonNullValueForKey:@"size"];
2482+ self.isPublic = [jsonDictionary nonNullValueForKey:@"is_public"];
2483+ self.publicURLString = [jsonDictionary nonNullValueForKey:@"public_url"];
2484 }
2485
2486 - (BOOL)isFile;
2487
2488=== modified file 'Files/U1FilePreviewViewController.h'
2489--- Files/U1FilePreviewViewController.h 2011-09-27 14:36:00 +0000
2490+++ Files/U1FilePreviewViewController.h 2011-11-01 14:25:30 +0000
2491@@ -18,7 +18,7 @@
2492 @class U1FilesClient, U1FileNode;
2493
2494
2495-@interface U1FilePreviewViewController : UIViewController
2496+@interface U1FilePreviewViewController : UIViewController <UITextFieldDelegate>
2497
2498 @property (nonatomic, retain, readonly) IBOutlet UIView *loadingContainerView;
2499 @property (nonatomic, retain, readonly) IBOutlet UIImageView *iconImageView;
2500@@ -29,6 +29,7 @@
2501 @property (nonatomic, retain, readonly) IBOutlet UILabel *modifiedLabel;
2502 @property (nonatomic, retain, readonly) IBOutlet UIToolbar *toolbar;
2503 @property (nonatomic, retain, readonly) IBOutlet UITextView *publicURLLabel;
2504+@property (nonatomic, retain, readonly) IBOutlet UITextField *renameTextField;
2505
2506 @property (readonly, retain) U1FileNode *node;
2507 @property (retain) U1FilesClient *filesClient;
2508
2509=== modified file 'Files/U1FilePreviewViewController.m'
2510--- Files/U1FilePreviewViewController.m 2011-09-27 14:36:00 +0000
2511+++ Files/U1FilePreviewViewController.m 2011-11-01 14:25:30 +0000
2512@@ -31,6 +31,8 @@
2513 @property (nonatomic, retain) U1LocalFileInfo *fileInfo;
2514
2515 @property (retain) UIBarButtonItem *publishItem;
2516+@property (retain) UIBarButtonItem *renameItem;
2517+@property (retain) UIBarButtonItem *deleteItem;
2518 @property (retain) UIBarButtonItem *downloadItem;
2519 @property (retain) UIBarButtonItem *previewItem;
2520 @property (retain) UIBarButtonItem *openInItem;
2521@@ -48,8 +50,8 @@
2522
2523 @implementation U1FilePreviewViewController
2524
2525-@synthesize loadingContainerView, iconImageView, nameLabel, loadingActivityView, sizeLabel, createdLabel, modifiedLabel, toolbar, publicURLLabel;
2526-@synthesize node, docController, filesClient, contentURL, fileInfo, publishItem, downloadItem, previewItem, openInItem, downloadProgressItem, downloadProgressView;
2527+@synthesize loadingContainerView, iconImageView, nameLabel, loadingActivityView, sizeLabel, createdLabel, modifiedLabel, toolbar, publicURLLabel, renameTextField;
2528+@synthesize node, docController, filesClient, contentURL, fileInfo, publishItem, renameItem, deleteItem, downloadItem, previewItem, openInItem, downloadProgressItem, downloadProgressView;
2529
2530 NSDateFormatter *modificationDateFormatter(void)
2531 {
2532@@ -78,6 +80,7 @@
2533 self = [super initWithNibName:@"U1FilePreviewViewController" bundle:nil];
2534 if (self == nil)
2535 return nil;
2536+ filesClient = [U1FilesClient sharedFilesClient];
2537 self.node = theNode;
2538 self.title = [node.path lastPathComponent];
2539
2540@@ -95,6 +98,8 @@
2541 [titleLabel release];
2542
2543 publishItem = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ic_act_publish_file"] style:UIBarButtonItemStylePlain target:self action:@selector(publishItem:)];
2544+ renameItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemOrganize target:self action:@selector(renameItem:)];
2545+ deleteItem = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"218-trash2"] style:UIBarButtonItemStylePlain target:self action:@selector(deleteItem:)];
2546 downloadItem = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"265-download"] style:UIBarButtonItemStylePlain target:self action:@selector(downloadItem:)];
2547 previewItem = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"04-eye"] style:UIBarButtonItemStylePlain target:self action:@selector(showPreview:)];
2548 openInItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAction target:self action:@selector(openIn:)];
2549@@ -121,7 +126,10 @@
2550 [filesClient release];
2551 [toolbar release];
2552 [publicURLLabel release];
2553+ [renameTextField release];
2554 [publishItem release];
2555+ [renameItem release];
2556+ [deleteItem release];
2557 [downloadItem release];
2558 [previewItem release];
2559 [openInItem release];
2560@@ -170,6 +178,10 @@
2561 [self flexibleSpaceItem],
2562 self.publishItem,
2563 [self fixedSpaceItemWithWidth:32.f],
2564+ self.renameItem,
2565+ [self fixedSpaceItemWithWidth:32.f],
2566+ self.deleteItem,
2567+ [self fixedSpaceItemWithWidth:32.f],
2568 self.previewItem,
2569 [self fixedSpaceItemWithWidth:32.f],
2570 self.openInItem,
2571@@ -182,6 +194,10 @@
2572 [self flexibleSpaceItem],
2573 self.publishItem,
2574 [self fixedSpaceItemWithWidth:32.f],
2575+ self.renameItem,
2576+ [self fixedSpaceItemWithWidth:32.f],
2577+ self.deleteItem,
2578+ [self fixedSpaceItemWithWidth:32.f],
2579 self.downloadItem,
2580 [self flexibleSpaceItem],
2581 nil];
2582@@ -200,9 +216,27 @@
2583 [modifiedLabel release], modifiedLabel = nil;
2584 [toolbar release], toolbar = nil;
2585 [publicURLLabel release], publicURLLabel = nil;
2586+ [renameTextField release], renameTextField = nil;
2587 [super viewDidUnload];
2588 }
2589
2590+- (void)setEditing:(BOOL)editing animated:(BOOL)animated;
2591+{
2592+ [super setEditing:editing animated:animated];
2593+ if (editing)
2594+ {
2595+ [self.renameTextField setText:self.title];
2596+ [self.renameTextField setHidden:NO];
2597+ [self.nameLabel setHidden:YES];
2598+ [self.renameTextField becomeFirstResponder];
2599+ }
2600+ else
2601+ {
2602+ [self.renameTextField setHidden:YES];
2603+ [self.nameLabel setHidden:NO];
2604+ }
2605+}
2606+
2607 - (IBAction)publishItem:(UIBarButtonItem*)sender;
2608 {
2609 if ([self.node isPublicValue])
2610@@ -225,6 +259,19 @@
2611 }
2612 }
2613
2614+- (IBAction)renameItem:(UIBarButtonItem*)sender;
2615+{
2616+ [self setEditing:YES animated:YES];
2617+}
2618+
2619+- (IBAction)deleteItem:(UIBarButtonItem*)sender;
2620+{
2621+ [self.filesClient deleteNode:self.node completionBlock:^(NSError *error) {
2622+
2623+ }];
2624+ [self.navigationController popViewControllerAnimated:YES];
2625+}
2626+
2627 - (IBAction)downloadItem:(UIBarButtonItem*)sender;
2628 {
2629 self.fileInfo = [self.filesClient downloadFileForNode:self.node completionBlock:^(NSError *error) {
2630@@ -337,4 +384,33 @@
2631 return [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:NULL] autorelease];
2632 }
2633
2634+- (BOOL)textFieldShouldReturn:(UITextField *)textField;
2635+{
2636+ [textField endEditing:NO];
2637+// [textField resignFirstResponder];
2638+ return YES;
2639+}
2640+
2641+- (void)textFieldDidEndEditing:(UITextField *)textField;
2642+{
2643+ NSString *newName = [self.renameTextField text];
2644+
2645+ [self setEditing:NO animated:YES];
2646+
2647+ if (!newName)
2648+ return;
2649+
2650+ [[U1FilesClient sharedFilesClient] renameNode:self.node toName:newName completionBlock:^(U1Node *newNode, NSError *error) {
2651+
2652+ if (!error)
2653+ {
2654+ self.title = [node.path lastPathComponent];
2655+ UILabel *titleLabel = (UILabel*)[self.navigationItem titleView];
2656+ [titleLabel setText:self.title];
2657+ [titleLabel sizeToFit];
2658+ [self.nameLabel setText:self.title];
2659+ }
2660+ }];
2661+}
2662+
2663 @end
2664
2665=== modified file 'Files/U1FilePreviewViewController.xib'
2666--- Files/U1FilePreviewViewController.xib 2011-09-27 14:36:00 +0000
2667+++ Files/U1FilePreviewViewController.xib 2011-11-01 14:25:30 +0000
2668@@ -1,34 +1,32 @@
2669 <?xml version="1.0" encoding="UTF-8"?>
2670 <archive type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="7.10">
2671 <data>
2672- <int key="IBDocument.SystemTarget">1056</int>
2673+ <int key="IBDocument.SystemTarget">1280</int>
2674 <string key="IBDocument.SystemVersion">10K549</string>
2675- <string key="IBDocument.InterfaceBuilderVersion">1306</string>
2676+ <string key="IBDocument.InterfaceBuilderVersion">1938</string>
2677 <string key="IBDocument.AppKitVersion">1038.36</string>
2678 <string key="IBDocument.HIToolboxVersion">461.00</string>
2679 <object class="NSMutableDictionary" key="IBDocument.PluginVersions">
2680 <string key="NS.key.0">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
2681- <string key="NS.object.0">301</string>
2682+ <string key="NS.object.0">933</string>
2683 </object>
2684 <object class="NSArray" key="IBDocument.IntegratedClassDependencies">
2685 <bool key="EncodedWithXMLCoder">YES</bool>
2686+ <string>IBProxyObject</string>
2687+ <string>IBUIImageView</string>
2688+ <string>IBUILabel</string>
2689+ <string>IBUIToolbar</string>
2690+ <string>IBUITextField</string>
2691 <string>IBUITextView</string>
2692- <string>IBUIToolbar</string>
2693- <string>IBUIImageView</string>
2694 <string>IBUIView</string>
2695- <string>IBUILabel</string>
2696- <string>IBProxyObject</string>
2697 </object>
2698 <object class="NSArray" key="IBDocument.PluginDependencies">
2699 <bool key="EncodedWithXMLCoder">YES</bool>
2700 <string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
2701 </object>
2702 <object class="NSMutableDictionary" key="IBDocument.Metadata">
2703- <bool key="EncodedWithXMLCoder">YES</bool>
2704- <object class="NSArray" key="dict.sortedKeys" id="0">
2705- <bool key="EncodedWithXMLCoder">YES</bool>
2706- </object>
2707- <reference key="dict.values" ref="0"/>
2708+ <string key="NS.key.0">PluginDependencyRecalculationVersion</string>
2709+ <integer value="1" key="NS.object.0"/>
2710 </object>
2711 <object class="NSMutableArray" key="IBDocument.RootObjects" id="1000">
2712 <bool key="EncodedWithXMLCoder">YES</bool>
2713@@ -83,18 +81,13 @@
2714 <string key="NSFrame">{{118, 20}, {182, 78}}</string>
2715 <reference key="NSSuperview" ref="959604046"/>
2716 <reference key="NSWindow"/>
2717- <reference key="NSNextKeyView" ref="526184231"/>
2718+ <reference key="NSNextKeyView" ref="1038751454"/>
2719 <bool key="IBUIOpaque">NO</bool>
2720 <bool key="IBUIClipsSubviews">YES</bool>
2721 <int key="IBUIContentMode">7</int>
2722 <bool key="IBUIUserInteractionEnabled">NO</bool>
2723 <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
2724 <string key="IBUIText"/>
2725- <object class="NSFont" key="IBUIFont">
2726- <string key="NSName">HelveticaNeue-Bold</string>
2727- <double key="NSSize">17</double>
2728- <int key="NSfFlags">16</int>
2729- </object>
2730 <object class="NSColor" key="IBUITextColor" id="995516164">
2731 <int key="NSColorSpace">1</int>
2732 <bytes key="NSRGB">MCAwIDAAA</bytes>
2733@@ -104,6 +97,17 @@
2734 <bool key="IBUIAdjustsFontSizeToFit">NO</bool>
2735 <float key="IBUIMinimumFontSize">10</float>
2736 <int key="IBUINumberOfLines">2</int>
2737+ <object class="IBUIFontDescription" key="IBUIFontDescription">
2738+ <string key="name">HelveticaNeue-Bold</string>
2739+ <string key="family">Helvetica Neue</string>
2740+ <int key="traits">2</int>
2741+ <double key="pointSize">17</double>
2742+ </object>
2743+ <object class="NSFont" key="IBUIFont">
2744+ <string key="NSName">HelveticaNeue-Bold</string>
2745+ <double key="NSSize">17</double>
2746+ <int key="NSfFlags">16</int>
2747+ </object>
2748 </object>
2749 <object class="IBUILabel" id="526184231">
2750 <reference key="NSNextResponder" ref="959604046"/>
2751@@ -118,11 +122,6 @@
2752 <bool key="IBUIUserInteractionEnabled">NO</bool>
2753 <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
2754 <string key="IBUIText">size</string>
2755- <object class="NSFont" key="IBUIFont" id="1064584347">
2756- <string key="NSName">HelveticaNeue</string>
2757- <double key="NSSize">14</double>
2758- <int key="NSfFlags">16</int>
2759- </object>
2760 <object class="NSColor" key="IBUITextColor" id="994737462">
2761 <int key="NSColorSpace">3</int>
2762 <bytes key="NSWhite">MC4zMzMzMzMzMzMzAA</bytes>
2763@@ -131,6 +130,17 @@
2764 <int key="IBUIBaselineAdjustment">1</int>
2765 <float key="IBUIMinimumFontSize">10</float>
2766 <int key="IBUITextAlignment">2</int>
2767+ <object class="IBUIFontDescription" key="IBUIFontDescription" id="823461873">
2768+ <string key="name">HelveticaNeue</string>
2769+ <string key="family">Helvetica Neue</string>
2770+ <int key="traits">0</int>
2771+ <double key="pointSize">14</double>
2772+ </object>
2773+ <object class="NSFont" key="IBUIFont" id="754417662">
2774+ <string key="NSName">HelveticaNeue-Medium</string>
2775+ <double key="NSSize">14</double>
2776+ <int key="NSfFlags">16</int>
2777+ </object>
2778 </object>
2779 <object class="IBUILabel" id="383512508">
2780 <reference key="NSNextResponder" ref="959604046"/>
2781@@ -145,12 +155,13 @@
2782 <bool key="IBUIUserInteractionEnabled">NO</bool>
2783 <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
2784 <string key="IBUIText">created</string>
2785- <reference key="IBUIFont" ref="1064584347"/>
2786 <reference key="IBUITextColor" ref="994737462"/>
2787 <nil key="IBUIHighlightedColor"/>
2788 <int key="IBUIBaselineAdjustment">1</int>
2789 <float key="IBUIMinimumFontSize">10</float>
2790 <int key="IBUITextAlignment">2</int>
2791+ <reference key="IBUIFontDescription" ref="823461873"/>
2792+ <reference key="IBUIFont" ref="754417662"/>
2793 </object>
2794 <object class="IBUILabel" id="426088224">
2795 <reference key="NSNextResponder" ref="959604046"/>
2796@@ -165,12 +176,13 @@
2797 <bool key="IBUIUserInteractionEnabled">NO</bool>
2798 <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
2799 <string key="IBUIText"/>
2800- <reference key="IBUIFont" ref="1064584347"/>
2801 <reference key="IBUITextColor" ref="995516164"/>
2802 <nil key="IBUIHighlightedColor"/>
2803 <int key="IBUIBaselineAdjustment">1</int>
2804 <bool key="IBUIAdjustsFontSizeToFit">NO</bool>
2805 <float key="IBUIMinimumFontSize">10</float>
2806+ <reference key="IBUIFontDescription" ref="823461873"/>
2807+ <reference key="IBUIFont" ref="754417662"/>
2808 </object>
2809 <object class="IBUILabel" id="546780773">
2810 <reference key="NSNextResponder" ref="959604046"/>
2811@@ -185,12 +197,13 @@
2812 <bool key="IBUIUserInteractionEnabled">NO</bool>
2813 <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
2814 <string key="IBUIText"/>
2815- <reference key="IBUIFont" ref="1064584347"/>
2816 <reference key="IBUITextColor" ref="995516164"/>
2817 <nil key="IBUIHighlightedColor"/>
2818 <int key="IBUIBaselineAdjustment">1</int>
2819 <bool key="IBUIAdjustsFontSizeToFit">NO</bool>
2820 <float key="IBUIMinimumFontSize">10</float>
2821+ <reference key="IBUIFontDescription" ref="823461873"/>
2822+ <reference key="IBUIFont" ref="754417662"/>
2823 </object>
2824 <object class="IBUILabel" id="256323477">
2825 <reference key="NSNextResponder" ref="959604046"/>
2826@@ -205,12 +218,13 @@
2827 <bool key="IBUIUserInteractionEnabled">NO</bool>
2828 <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
2829 <string key="IBUIText">modified</string>
2830- <reference key="IBUIFont" ref="1064584347"/>
2831 <reference key="IBUITextColor" ref="994737462"/>
2832 <nil key="IBUIHighlightedColor"/>
2833 <int key="IBUIBaselineAdjustment">1</int>
2834 <float key="IBUIMinimumFontSize">10</float>
2835 <int key="IBUITextAlignment">2</int>
2836+ <reference key="IBUIFontDescription" ref="823461873"/>
2837+ <reference key="IBUIFont" ref="754417662"/>
2838 </object>
2839 <object class="IBUILabel" id="968704124">
2840 <reference key="NSNextResponder" ref="959604046"/>
2841@@ -225,12 +239,13 @@
2842 <bool key="IBUIUserInteractionEnabled">NO</bool>
2843 <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
2844 <string key="IBUIText"/>
2845- <reference key="IBUIFont" ref="1064584347"/>
2846 <reference key="IBUITextColor" ref="995516164"/>
2847 <nil key="IBUIHighlightedColor"/>
2848 <int key="IBUIBaselineAdjustment">1</int>
2849 <bool key="IBUIAdjustsFontSizeToFit">NO</bool>
2850 <float key="IBUIMinimumFontSize">10</float>
2851+ <reference key="IBUIFontDescription" ref="823461873"/>
2852+ <reference key="IBUIFont" ref="754417662"/>
2853 </object>
2854 <object class="IBUILabel" id="221780367">
2855 <reference key="NSNextResponder" ref="959604046"/>
2856@@ -245,12 +260,13 @@
2857 <bool key="IBUIUserInteractionEnabled">NO</bool>
2858 <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
2859 <string key="IBUIText">public URL</string>
2860- <reference key="IBUIFont" ref="1064584347"/>
2861 <reference key="IBUITextColor" ref="994737462"/>
2862 <nil key="IBUIHighlightedColor"/>
2863 <int key="IBUIBaselineAdjustment">1</int>
2864 <float key="IBUIMinimumFontSize">10</float>
2865 <int key="IBUITextAlignment">2</int>
2866+ <reference key="IBUIFontDescription" ref="823461873"/>
2867+ <reference key="IBUIFont" ref="754417662"/>
2868 </object>
2869 <object class="IBUITextView" id="395268767">
2870 <reference key="NSNextResponder" ref="959604046"/>
2871@@ -272,12 +288,46 @@
2872 <bool key="IBUIShowsVerticalScrollIndicator">NO</bool>
2873 <bool key="IBUIEditable">NO</bool>
2874 <string key="IBUIText"/>
2875- <reference key="IBUIFont" ref="1064584347"/>
2876 <object class="IBUITextInputTraits" key="IBUITextInputTraits">
2877 <int key="IBUIAutocapitalizationType">2</int>
2878 <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
2879 </object>
2880 <int key="IBUIDataDetectorTypes">2</int>
2881+ <reference key="IBUIFontDescription" ref="823461873"/>
2882+ <reference key="IBUIFont" ref="754417662"/>
2883+ </object>
2884+ <object class="IBUITextField" id="1038751454">
2885+ <reference key="NSNextResponder" ref="959604046"/>
2886+ <int key="NSvFlags">-2147483356</int>
2887+ <string key="NSFrame">{{118, 20}, {182, 78}}</string>
2888+ <reference key="NSSuperview" ref="959604046"/>
2889+ <reference key="NSWindow"/>
2890+ <reference key="NSNextKeyView" ref="526184231"/>
2891+ <bool key="IBUIOpaque">NO</bool>
2892+ <bool key="IBUIClipsSubviews">YES</bool>
2893+ <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
2894+ <int key="IBUIContentVerticalAlignment">0</int>
2895+ <string key="IBUIText"/>
2896+ <object class="NSColor" key="IBUITextColor">
2897+ <int key="NSColorSpace">3</int>
2898+ <bytes key="NSWhite">MAA</bytes>
2899+ <reference key="NSCustomColorSpace" ref="838192903"/>
2900+ </object>
2901+ <bool key="IBUIAdjustsFontSizeToFit">YES</bool>
2902+ <float key="IBUIMinimumFontSize">17</float>
2903+ <object class="IBUITextInputTraits" key="IBUITextInputTraits">
2904+ <int key="IBUIReturnKeyType">9</int>
2905+ <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
2906+ </object>
2907+ <object class="IBUIFontDescription" key="IBUIFontDescription">
2908+ <int key="type">2</int>
2909+ <double key="pointSize">17</double>
2910+ </object>
2911+ <object class="NSFont" key="IBUIFont">
2912+ <string key="NSName">Helvetica-Bold</string>
2913+ <double key="NSSize">17</double>
2914+ <int key="NSfFlags">16</int>
2915+ </object>
2916 </object>
2917 </object>
2918 <string key="NSFrameSize">{320, 372}</string>
2919@@ -401,13 +451,31 @@
2920 </object>
2921 <int key="connectionID">46</int>
2922 </object>
2923+ <object class="IBConnectionRecord">
2924+ <object class="IBCocoaTouchOutletConnection" key="connection">
2925+ <string key="label">renameTextField</string>
2926+ <reference key="source" ref="372490531"/>
2927+ <reference key="destination" ref="1038751454"/>
2928+ </object>
2929+ <int key="connectionID">48</int>
2930+ </object>
2931+ <object class="IBConnectionRecord">
2932+ <object class="IBCocoaTouchOutletConnection" key="connection">
2933+ <string key="label">delegate</string>
2934+ <reference key="source" ref="1038751454"/>
2935+ <reference key="destination" ref="372490531"/>
2936+ </object>
2937+ <int key="connectionID">49</int>
2938+ </object>
2939 </object>
2940 <object class="IBMutableOrderedSet" key="objectRecords">
2941 <object class="NSArray" key="orderedObjects">
2942 <bool key="EncodedWithXMLCoder">YES</bool>
2943 <object class="IBObjectRecord">
2944 <int key="objectID">0</int>
2945- <reference key="object" ref="0"/>
2946+ <object class="NSArray" key="object" id="0">
2947+ <bool key="EncodedWithXMLCoder">YES</bool>
2948+ </object>
2949 <reference key="children" ref="1000"/>
2950 <nil key="parent"/>
2951 </object>
2952@@ -448,6 +516,7 @@
2953 <reference ref="221780367"/>
2954 <reference ref="749932571"/>
2955 <reference ref="395268767"/>
2956+ <reference ref="1038751454"/>
2957 </object>
2958 <reference key="parent" ref="191373211"/>
2959 <string key="objectName">Info View</string>
2960@@ -524,6 +593,11 @@
2961 <reference key="object" ref="395268767"/>
2962 <reference key="parent" ref="959604046"/>
2963 </object>
2964+ <object class="IBObjectRecord">
2965+ <int key="objectID">47</int>
2966+ <reference key="object" ref="1038751454"/>
2967+ <reference key="parent" ref="959604046"/>
2968+ </object>
2969 </object>
2970 </object>
2971 <object class="NSMutableDictionary" key="flattenedProperties">
2972@@ -531,8 +605,9 @@
2973 <object class="NSArray" key="dict.sortedKeys">
2974 <bool key="EncodedWithXMLCoder">YES</bool>
2975 <string>-1.CustomClassName</string>
2976+ <string>-1.IBPluginDependency</string>
2977 <string>-2.CustomClassName</string>
2978- <string>1.IBEditorWindowLastContentRect</string>
2979+ <string>-2.IBPluginDependency</string>
2980 <string>1.IBPluginDependency</string>
2981 <string>17.IBPluginDependency</string>
2982 <string>21.IBPluginDependency</string>
2983@@ -546,13 +621,16 @@
2984 <string>40.IBPluginDependency</string>
2985 <string>41.IBPluginDependency</string>
2986 <string>45.IBPluginDependency</string>
2987+ <string>47.IBPluginDependency</string>
2988 <string>5.IBPluginDependency</string>
2989 </object>
2990 <object class="NSMutableArray" key="dict.values">
2991 <bool key="EncodedWithXMLCoder">YES</bool>
2992 <string>U1FilePreviewViewController</string>
2993+ <string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
2994 <string>UIResponder</string>
2995- <string>{{556, 412}, {320, 480}}</string>
2996+ <string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
2997+ <string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
2998 <string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
2999 <string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
3000 <string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
3001@@ -581,7 +659,7 @@
3002 <reference key="dict.values" ref="0"/>
3003 </object>
3004 <nil key="sourceID"/>
3005- <int key="maxID">46</int>
3006+ <int key="maxID">49</int>
3007 </object>
3008 <object class="IBClassDescriber" key="IBDocument.Classes">
3009 <object class="NSMutableArray" key="referencedPartialClassDescriptions">
3010@@ -600,6 +678,7 @@
3011 <string>modifiedLabel</string>
3012 <string>nameLabel</string>
3013 <string>publicURLLabel</string>
3014+ <string>renameTextField</string>
3015 <string>sizeLabel</string>
3016 <string>toolbar</string>
3017 </object>
3018@@ -612,6 +691,7 @@
3019 <string>UILabel</string>
3020 <string>UILabel</string>
3021 <string>UITextView</string>
3022+ <string>UITextField</string>
3023 <string>UILabel</string>
3024 <string>UIToolbar</string>
3025 </object>
3026@@ -627,6 +707,7 @@
3027 <string>modifiedLabel</string>
3028 <string>nameLabel</string>
3029 <string>publicURLLabel</string>
3030+ <string>renameTextField</string>
3031 <string>sizeLabel</string>
3032 <string>toolbar</string>
3033 </object>
3034@@ -661,6 +742,10 @@
3035 <string key="candidateClassName">UITextView</string>
3036 </object>
3037 <object class="IBToOneOutletInfo">
3038+ <string key="name">renameTextField</string>
3039+ <string key="candidateClassName">UITextField</string>
3040+ </object>
3041+ <object class="IBToOneOutletInfo">
3042 <string key="name">sizeLabel</string>
3043 <string key="candidateClassName">UILabel</string>
3044 </object>
3045@@ -685,6 +770,6 @@
3046 </object>
3047 <bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
3048 <int key="IBDocument.defaultPropertyAccessControl">3</int>
3049- <string key="IBCocoaTouchPluginVersion">301</string>
3050+ <string key="IBCocoaTouchPluginVersion">933</string>
3051 </data>
3052 </archive>
3053
3054=== modified file 'Files/U1Files.xcdatamodeld/.xccurrentversion'
3055--- Files/U1Files.xcdatamodeld/.xccurrentversion 2011-09-08 16:59:34 +0000
3056+++ Files/U1Files.xcdatamodeld/.xccurrentversion 2011-11-01 14:25:30 +0000
3057@@ -3,6 +3,6 @@
3058 <plist version="1.0">
3059 <dict>
3060 <key>_XCCurrentVersionName</key>
3061- <string>U1Files.xcdatamodel</string>
3062+ <string>U1Files 1.0-9.xcdatamodel</string>
3063 </dict>
3064 </plist>
3065
3066=== added directory 'Files/U1Files.xcdatamodeld/U1Files 1.0-3.xcdatamodel'
3067=== added file 'Files/U1Files.xcdatamodeld/U1Files 1.0-3.xcdatamodel/elements'
3068Binary files Files/U1Files.xcdatamodeld/U1Files 1.0-3.xcdatamodel/elements 1970-01-01 00:00:00 +0000 and Files/U1Files.xcdatamodeld/U1Files 1.0-3.xcdatamodel/elements 2011-11-01 14:25:30 +0000 differ
3069=== added file 'Files/U1Files.xcdatamodeld/U1Files 1.0-3.xcdatamodel/layout'
3070Binary files Files/U1Files.xcdatamodeld/U1Files 1.0-3.xcdatamodel/layout 1970-01-01 00:00:00 +0000 and Files/U1Files.xcdatamodeld/U1Files 1.0-3.xcdatamodel/layout 2011-11-01 14:25:30 +0000 differ
3071=== added directory 'Files/U1Files.xcdatamodeld/U1Files 1.0-9.xcdatamodel'
3072=== added file 'Files/U1Files.xcdatamodeld/U1Files 1.0-9.xcdatamodel/elements'
3073Binary files Files/U1Files.xcdatamodeld/U1Files 1.0-9.xcdatamodel/elements 1970-01-01 00:00:00 +0000 and Files/U1Files.xcdatamodeld/U1Files 1.0-9.xcdatamodel/elements 2011-11-01 14:25:30 +0000 differ
3074=== added file 'Files/U1Files.xcdatamodeld/U1Files 1.0-9.xcdatamodel/layout'
3075Binary files Files/U1Files.xcdatamodeld/U1Files 1.0-9.xcdatamodel/layout 1970-01-01 00:00:00 +0000 and Files/U1Files.xcdatamodeld/U1Files 1.0-9.xcdatamodel/layout 2011-11-01 14:25:30 +0000 differ
3076=== modified file 'Files/U1Files.xcdatamodeld/U1Files.xcdatamodel/elements'
3077Binary files Files/U1Files.xcdatamodeld/U1Files.xcdatamodel/elements 2011-09-08 16:59:34 +0000 and Files/U1Files.xcdatamodeld/U1Files.xcdatamodel/elements 2011-11-01 14:25:30 +0000 differ
3078=== modified file 'Files/U1Files.xcdatamodeld/U1Files.xcdatamodel/layout'
3079Binary files Files/U1Files.xcdatamodeld/U1Files.xcdatamodel/layout 2011-09-08 16:59:34 +0000 and Files/U1Files.xcdatamodeld/U1Files.xcdatamodel/layout 2011-11-01 14:25:30 +0000 differ
3080=== modified file 'Files/U1FilesClient.h'
3081--- Files/U1FilesClient.h 2011-09-27 14:36:00 +0000
3082+++ Files/U1FilesClient.h 2011-11-01 14:25:30 +0000
3083@@ -16,7 +16,7 @@
3084 #import <Foundation/Foundation.h>
3085
3086 @class NSFetchedResultsController;
3087-@class U1Node, U1FileNode, U1FolderNode, U1NodeChildrenResultSet, U1LocalFileInfo;
3088+@class U1Node, U1FileNode, U1FolderNode, U1NodeChildrenResultSet, U1Volume, U1LocalFileInfo;
3089 @class U1DataRepository, U1FilesService;
3090
3091
3092@@ -25,11 +25,19 @@
3093 @property (retain) U1DataRepository *dataRepository;
3094 @property (retain) U1FilesService *filesService;
3095
3096-- (id)fetchNodeWithResourcePath:(NSString*)nodePath completionBlock:(void(^)(U1Node *node, NSFetchedResultsController *childrenResultsController, NSError *error))completionBlock;
3097++ (U1FilesClient *)sharedFilesClient;
3098+
3099+- (id)accountInfoWithCompletionBlock:(void(^)(NSDictionary *accountInfo, NSError *error))completionBlock;
3100+- (id)volumesWithCompletionBlock:(void(^)(U1Volume *rootVolume, NSFetchedResultsController *cloudFoldersResultsController, NSError *error))completionBlock;
3101+- (id)fetchFolderWithResourcePath:(NSString*)nodePath completionBlock:(void(^)(U1Node *node, NSFetchedResultsController *childrenResultsController, NSError *error))completionBlock;
3102+- (id)fetchFileWithResourcePath:(NSString*)nodePath completionBlock:(void(^)(U1Node *node, NSError *error))completionBlock;
3103+- (id)renameNode:(U1Node*)node toName:(NSString*)newName completionBlock:(void(^)(U1Node *node, NSError *error))completionBlock;
3104 - (id)deleteNode:(U1Node*)node completionBlock:(void(^)(NSError *error))completionBlock;
3105-- (id)uploadContentData:(NSData*)contentData toFolder:(U1FolderNode*)folderNode withResourceName:(NSString*)resourceName progressBlock:(void(^)(long long bytesUploaded, long long totalBytes))progressBlock completionBlock:(void(^)(U1FileNode *updatedNode, NSError *error))completionBlock;
3106+- (id)uploadContentData:(NSData*)contentData toFolder:(U1FolderNode*)folderNode withResourceName:(NSString*)resourceName withContentType:(NSString*)contentType progressBlock:(void(^)(long long bytesUploaded, long long totalBytes))progressBlock completionBlock:(void(^)(U1FileNode *updatedNode, NSError *error))completionBlock;
3107 - (id)publishNode:(U1FileNode*)node completionBlock:(void(^)(U1FileNode *node, NSError *error))completionBlock;
3108 - (id)unpublishNode:(U1FileNode*)node completionBlock:(void(^)(U1FileNode *node, NSError *error))completionBlock;
3109+- (id)createFolderNamed:(NSString*)name inFolder:(U1FolderNode*)folderNode completionBlock:(void(^)(U1FolderNode *newFolderNode, NSError *error))completionBlock;
3110+- (id)createVolumeAtPath:(NSString*)folderPath completionBlock:(void(^)(U1Volume *volume, NSError *error))completionBlock;
3111 - (BOOL)isNodeSavedLocally:(U1FileNode*)node;
3112 - (U1LocalFileInfo*)localInfoForNode:(U1FileNode*)node;
3113
3114
3115=== modified file 'Files/U1FilesClient.m'
3116--- Files/U1FilesClient.m 2011-09-27 14:36:00 +0000
3117+++ Files/U1FilesClient.m 2011-11-01 14:25:30 +0000
3118@@ -23,66 +23,136 @@
3119 #import "U1FolderNode.h"
3120 #import "U1LocalFileInfo.h"
3121 #import "U1Node.h"
3122+#import "U1Volume.h"
3123
3124
3125 @interface U1FilesClient ()
3126 - (NSURL*)fileURLForNode:(U1FileNode*)node;
3127 @end
3128
3129+static U1FilesClient *sharedFilesClient = nil;
3130
3131 @implementation U1FilesClient
3132
3133 @synthesize dataRepository, filesService;
3134
3135-- (void)dealloc;
3136-{
3137- [dataRepository release];
3138- [filesService release];
3139- [super dealloc];
3140-}
3141-
3142-- (id)fetchNodeWithResourcePath:(NSString*)nodePath completionBlock:(void(^)(U1Node *node, NSFetchedResultsController *childrenResultsController, NSError *error))completionBlock;
3143-{
3144-
3145- U1FolderNode *node = (id)[self.dataRepository nodeWithResourcePath:nodePath];
3146-
3147- // TODO: temporary, create node if doesn't exist
3148++ (U1FilesClient*)sharedFilesClient;
3149+{
3150+ if (sharedFilesClient == nil)
3151+ {
3152+ sharedFilesClient = [[self alloc] init];
3153+ }
3154+ return sharedFilesClient;
3155+}
3156+
3157+- (id)init;
3158+{
3159+ self = [super init];
3160+ if (self == nil)
3161+ return nil;
3162+ dataRepository = [U1DataRepository sharedDataRepository];
3163+ filesService = [U1FilesService sharedFilesService];
3164+ return self;
3165+}
3166+
3167+- (id)accountInfoWithCompletionBlock:(void(^)(NSDictionary *accountInfo, NSError *error))completionBlock;
3168+{
3169+ return [self.filesService accountInfoWithCompletionBlock:completionBlock];
3170+}
3171+
3172+- (id)volumesWithCompletionBlock:(void(^)(U1Volume *rootVolume, NSFetchedResultsController *cloudFoldersResultsController, NSError *error))completionBlock;
3173+{
3174+ NSParameterAssert(completionBlock != NULL);
3175+
3176+ [self.filesService volumeInfoWithCompletionBlock:^(NSArray *volumeInfos, NSError *error) {
3177+
3178+ __block U1Volume *rootVolume = nil;
3179+ [self.dataRepository dispatchBlockWithManagedObjectContext:^(NSManagedObjectContext *context) {
3180+ for (NSDictionary *volumeInfo in volumeInfos)
3181+ {
3182+ NSString *path = [volumeInfo objectForKey:@"path"];
3183+ NSPredicate *p = [NSPredicate predicateWithFormat:@"path = %@", path];
3184+ U1Volume *volume = [[self.dataRepository resultsForEntityClass:[U1Volume class] matchingPredicate:p withSortDescriptors:nil error:NULL] lastObject];
3185+ if (!volume)
3186+ {
3187+ volume = [U1Volume insertInManagedObjectContext:context];
3188+ }
3189+ [volume updatePropertiesFromJSONDictionary:volumeInfo];
3190+ if ([volume.kind isEqualToString:@"root"])
3191+ {
3192+ rootVolume = [volume retain];
3193+ }
3194+ }
3195+ [context save:NULL];
3196+ }];
3197+
3198+ [self.dataRepository dispatchBlockWithManagedObjectContext:^(NSManagedObjectContext *context) {
3199+
3200+ NSFetchRequest *request = [[NSFetchRequest alloc] init];
3201+ [request setEntity:[U1Volume entityInManagedObjectContext:context]];
3202+ NSPredicate *p = [NSPredicate predicateWithFormat:@"kind = 'udf'"];
3203+ [request setPredicate:p];
3204+ NSArray *sortDescriptors = [NSArray arrayWithObjects:
3205+ [NSSortDescriptor sortDescriptorWithKey:@"resourcePath" ascending:YES selector:@selector(localizedStandardCompare:)],
3206+ nil];
3207+ [request setSortDescriptors:sortDescriptors];
3208+ NSFetchedResultsController *cloudFoldersResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:request managedObjectContext:context sectionNameKeyPath:nil cacheName:nil];
3209+ [request release];
3210+
3211+ dispatch_async(dispatch_get_main_queue(), ^(void) {
3212+ NSError *error = nil;
3213+ [cloudFoldersResultsController performFetch:&error];
3214+ completionBlock(rootVolume, cloudFoldersResultsController, error);
3215+ [cloudFoldersResultsController release];
3216+ [rootVolume release];
3217+ });
3218+ }];
3219+ }];
3220+ return nil;
3221+}
3222+
3223+- (id)fetchFolderWithResourcePath:(NSString*)nodePath completionBlock:(void(^)(U1Node *node, NSFetchedResultsController *childrenResultsController, NSError *error))completionBlock;
3224+{
3225+
3226+ __block U1FolderNode *node = [(id)[self.dataRepository nodeWithResourcePath:nodePath] retain];
3227+
3228 if (!node)
3229 {
3230 [self.dataRepository dispatchBlockWithManagedObjectContext:^(NSManagedObjectContext *context) {
3231- U1Node *newNode = [U1FolderNode insertInManagedObjectContext:context];
3232- newNode.resourcePath = nodePath;
3233+ node = [[U1FolderNode insertInManagedObjectContext:context] retain];
3234+ node.resourcePath = nodePath;
3235 [context save:NULL];
3236 }];
3237 }
3238-
3239- node = (id)[self.dataRepository nodeWithResourcePath:nodePath];
3240
3241 [self.filesService infoForNodeAtResourcePath:node.resourcePath includeChildren:YES completionBlock:^(NSDictionary *nodeInfo, NSError *error) {
3242-
3243- [node updatePropertiesFromJSONDictionary:nodeInfo];
3244-
3245- NSArray *childInfos = [nodeInfo objectForKey:@"children"];
3246- [self.dataRepository dispatchBlockWithManagedObjectContext:^(NSManagedObjectContext *context) {
3247
3248- for (NSDictionary *childInfo in childInfos)
3249- {
3250- NSString *childResourcePath = [childInfo objectForKey:@"resource_path"];
3251- NSString *kind = [childInfo objectForKey:@"kind"];
3252- U1Node *childNode = [self.dataRepository nodeWithResourcePath:childResourcePath];
3253- if (!childNode)
3254- {
3255- if ([@"file" isEqualToString:kind])
3256- childNode = [U1FileNode insertInManagedObjectContext:context];
3257- else
3258- childNode = [U1FolderNode insertInManagedObjectContext:context];
3259- }
3260+ if (error == nil)
3261+ {
3262+ [node updatePropertiesFromJSONDictionary:nodeInfo];
3263+
3264+ NSArray *childInfos = [nodeInfo objectForKey:@"children"];
3265+ [self.dataRepository dispatchBlockWithManagedObjectContext:^(NSManagedObjectContext *context) {
3266
3267- [childNode updatePropertiesFromJSONDictionary:childInfo];
3268- childNode.parent = node;
3269- }
3270- [context save:NULL];
3271- }];
3272+ for (NSDictionary *childInfo in childInfos)
3273+ {
3274+ NSString *childResourcePath = [childInfo objectForKey:@"resource_path"];
3275+ NSString *kind = [childInfo objectForKey:@"kind"];
3276+ U1Node *childNode = [self.dataRepository nodeWithResourcePath:childResourcePath];
3277+ if (!childNode)
3278+ {
3279+ if ([@"file" isEqualToString:kind])
3280+ childNode = [U1FileNode insertInManagedObjectContext:context];
3281+ else
3282+ childNode = [U1FolderNode insertInManagedObjectContext:context];
3283+ }
3284+
3285+ [childNode updatePropertiesFromJSONDictionary:childInfo];
3286+ childNode.parent = node;
3287+ }
3288+ [context save:NULL];
3289+ }];
3290+ }
3291
3292 __block NSFetchedResultsController *resultsController = nil;
3293 [self.dataRepository dispatchBlockWithManagedObjectContext:^(NSManagedObjectContext *context) {
3294@@ -93,7 +163,7 @@
3295 [request setPredicate:p];
3296 NSArray *sortDescriptors = [NSArray arrayWithObjects:
3297 [NSSortDescriptor sortDescriptorWithKey:@"kind" ascending:YES],
3298- [NSSortDescriptor sortDescriptorWithKey:@"resourcePath" ascending:YES selector:@selector(caseInsensitiveCompare:)],
3299+ [NSSortDescriptor sortDescriptorWithKey:@"resourcePath" ascending:YES selector:@selector(localizedStandardCompare:)],
3300 nil];
3301 [request setSortDescriptors:sortDescriptors];
3302 resultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:request managedObjectContext:context sectionNameKeyPath:nil cacheName:nil];
3303@@ -106,12 +176,59 @@
3304 [resultsController performFetch:&error];
3305 completionBlock(node, resultsController, error);
3306 [resultsController release];
3307+ [node release];
3308 });
3309
3310 }];
3311 return nil;
3312 }
3313
3314+- (id)fetchFileWithResourcePath:(NSString *)nodePath completionBlock:(void (^)(U1Node *, NSError *))completionBlock;
3315+{
3316+ __block U1FileNode *node = [(id)[self.dataRepository nodeWithResourcePath:nodePath] retain];
3317+
3318+ if (!node)
3319+ {
3320+ [self.dataRepository dispatchBlockWithManagedObjectContext:^(NSManagedObjectContext *context) {
3321+ node = [[U1FileNode insertInManagedObjectContext:context] retain];
3322+ node.resourcePath = nodePath;
3323+ [context save:NULL];
3324+ }];
3325+ }
3326+
3327+
3328+ [self.filesService infoForNodeAtResourcePath:node.resourcePath includeChildren:NO completionBlock:^(NSDictionary *nodeInfo, NSError *error) {
3329+ if (error == nil)
3330+ {
3331+ [node updatePropertiesFromJSONDictionary:nodeInfo];
3332+ }
3333+ }];
3334+
3335+ dispatch_async(dispatch_get_main_queue(), ^(void) {
3336+ NSError *error = nil;
3337+ completionBlock(node, error);
3338+ [node release];
3339+ });
3340+
3341+ return nil;
3342+}
3343+
3344+- (id)renameNode:(U1Node*)node toName:(NSString*)newName completionBlock:(void(^)(U1Node *node, NSError *error))completionBlock;
3345+{
3346+ NSParameterAssert(node != nil);
3347+ NSParameterAssert(newName != nil);
3348+ NSParameterAssert(completionBlock != NULL);
3349+
3350+ NSString *newPath = [[node.path stringByDeletingLastPathComponent] stringByAppendingPathComponent:newName];
3351+ return [self.filesService moveNodeAtResourcePath:node.resourcePath toPath:newPath withCompletionBlock:^(NSDictionary *nodeInfo, NSError *error) {
3352+ if (!error)
3353+ {
3354+ [node updatePropertiesFromJSONDictionary:nodeInfo];
3355+ }
3356+ completionBlock(node, error);
3357+ }];
3358+}
3359+
3360 - (id)deleteNode:(U1Node*)node completionBlock:(void(^)(NSError *error))completionBlock;
3361 {
3362 return [self.filesService deleteNodeAtResourcePath:node.resourcePath completionBlock:^(NSError *error) {
3363@@ -126,7 +243,7 @@
3364 }];
3365 }
3366
3367-- (id)uploadContentData:(NSData*)contentData toFolder:(U1FolderNode*)folderNode withResourceName:(NSString*)resourceName progressBlock:(void(^)(long long bytesUploaded, long long totalBytes))progressBlock completionBlock:(void(^)(U1FileNode *updatedNode, NSError *error))completionBlock;
3368+- (id)uploadContentData:(NSData*)contentData toFolder:(U1FolderNode*)folderNode withResourceName:(NSString*)resourceName withContentType:(NSString*)contentType progressBlock:(void(^)(long long bytesUploaded, long long totalBytes))progressBlock completionBlock:(void(^)(U1FileNode *updatedNode, NSError *error))completionBlock;
3369 {
3370 NSString *resourcePath = [folderNode.resourcePath stringByAppendingPathComponent:resourceName];
3371 U1FileNode *node = (id)[self.dataRepository nodeWithResourcePath:resourcePath];
3372@@ -143,10 +260,19 @@
3373 node = (id)[self.dataRepository nodeWithResourcePath:resourcePath];
3374 }
3375
3376- return [self.filesService uploadContentData:contentData forNode:node progressBlock:progressBlock completionBlock:^(NSDictionary *updatedNodeInfo, NSError *error) {
3377-
3378- [node updatePropertiesFromJSONDictionary:updatedNodeInfo];
3379- completionBlock(node, error);
3380+ return [self.filesService uploadContentData:contentData forNode:node withContentType:contentType progressBlock:progressBlock completionBlock:^(NSDictionary *updatedNodeInfo, NSError *error) {
3381+ if (error != nil)
3382+ {
3383+ [self.dataRepository dispatchBlockWithManagedObjectContext:^(NSManagedObjectContext *context) {
3384+ [context deleteObject:node];
3385+ }];
3386+ completionBlock(nil, error);
3387+ }
3388+ else
3389+ {
3390+ [node updatePropertiesFromJSONDictionary:updatedNodeInfo];
3391+ completionBlock(node, error);
3392+ }
3393 }];
3394 }
3395
3396@@ -160,6 +286,42 @@
3397 return [self.filesService unpublishNode:node completionBlock:completionBlock];
3398 }
3399
3400+- (id)createFolderNamed:(NSString*)name inFolder:(U1FolderNode*)folderNode completionBlock:(void(^)(U1FolderNode *newFolderNode, NSError *error))completionBlock;
3401+{
3402+ NSString *resourcePath = folderNode.resourcePath;
3403+ resourcePath = [resourcePath stringByAppendingPathComponent:name];
3404+
3405+ U1FolderNode *node = (id)[self.dataRepository nodeWithResourcePath:resourcePath];
3406+ if (!node)
3407+ {
3408+ [self.dataRepository dispatchBlockWithManagedObjectContext:^(NSManagedObjectContext *context) {
3409+ U1FolderNode *newNode = [U1FolderNode insertInManagedObjectContext:context];
3410+ newNode.resourcePath = resourcePath;
3411+ newNode.kind = @"directory";
3412+ newNode.contentPath = [folderNode.contentPath stringByAppendingPathComponent:name];
3413+ newNode.parent = folderNode;
3414+ [context save:NULL];
3415+ }];
3416+ node = (id)[self.dataRepository nodeWithResourcePath:resourcePath];
3417+ }
3418+
3419+ return [self.filesService createFolderAtPath:resourcePath completionBlock:^(NSDictionary *nodeInfo, NSError *error) {
3420+ [node updatePropertiesFromJSONDictionary:nodeInfo];
3421+ completionBlock(node, error);
3422+ }];
3423+}
3424+
3425+- (id)createVolumeAtPath:(NSString*)folderPath completionBlock:(void(^)(U1Volume *volume, NSError *error))completionBlock;
3426+{
3427+ return [self.filesService createVolumeAtPath:folderPath completionBlock:^(NSDictionary *volumeInfo, NSError *error) {
3428+ [self.dataRepository dispatchBlockWithManagedObjectContext:^(NSManagedObjectContext *context) {
3429+ U1Volume *volume = [U1Volume insertInManagedObjectContext:context];
3430+ [volume updatePropertiesFromJSONDictionary:volumeInfo];
3431+ completionBlock(volume, error);
3432+ }];
3433+ }];
3434+}
3435+
3436 - (BOOL)isNodeSavedLocally:(U1FileNode*)node;
3437 {
3438 NSString *contentPath = node.contentPath;
3439
3440=== modified file 'Files/U1FilesService.h'
3441--- Files/U1FilesService.h 2011-09-08 16:59:34 +0000
3442+++ Files/U1FilesService.h 2011-11-01 14:25:30 +0000
3443@@ -15,20 +15,25 @@
3444
3445 #import <Foundation/Foundation.h>
3446
3447-@class U1Node, U1FileNode;
3448+@class U1Node, U1FileNode, U1FolderNode;
3449
3450
3451 @interface U1FilesService : NSObject
3452
3453-- (id)volumeInfoWithCompletionBlock:(void(^)(NSArray *volumeInfo, NSError *error))completionBlock;
3454++ (U1FilesService *)sharedFilesService;
3455
3456+- (id)accountInfoWithCompletionBlock:(void(^)(NSDictionary *accountInfo, NSError *error))completionBlock;
3457+- (id)volumeInfoWithCompletionBlock:(void(^)(NSArray *volumeInfos, NSError *error))completionBlock;
3458 - (id)infoForNodeAtResourcePath:(NSString*)resourcePath includeChildren:(BOOL)includeChildren completionBlock:(void(^)(NSDictionary *node, NSError *error))completionBlock;
3459 - (id)infoForNode:(U1Node*)node includeChildren:(BOOL)includeChildren completionBlock:(void(^)(NSDictionary *node, NSError *error))completionBlock;
3460 - (id)contentForNode:(U1FileNode*)node progressBlock:(void(^)(long long bytesReceived, long long bytesExpected))progressBlock completionBlock:(void(^)(NSURL *contentURL))completionBlock;
3461 - (id)uploadContentAtURL:(NSURL*)contentURL forNode:(U1FileNode*)node progressBlock:(void(^)(long long bytesUploaded, long long totalBytes))progressBlock completionBlock:(void(^)(U1FileNode *updatedNode, NSError *error))completionBlock;
3462-- (id)uploadContentData:(NSData*)contentData forNode:(U1FileNode*)node progressBlock:(void(^)(long long bytesUploaded, long long totalBytes))progressBlock completionBlock:(void(^)(NSDictionary *updatedNodeInfo, NSError *error))completionBlock;
3463+- (id)uploadContentData:(NSData*)contentData forNode:(U1FileNode*)node withContentType:(NSString*)contentType progressBlock:(void(^)(long long bytesUploaded, long long totalBytes))progressBlock completionBlock:(void(^)(NSDictionary *updatedNodeInfo, NSError *error))completionBlock;
3464+- (id)moveNodeAtResourcePath:(NSString*)resourcePath toPath:(NSString*)newPath withCompletionBlock:(void(^)(NSDictionary *nodeInfo, NSError *error))completionBlock;
3465 - (id)deleteNodeAtResourcePath:(NSString*)resourcePath completionBlock:(void(^)(NSError *error))completionBlock;
3466 - (id)publishNode:(U1FileNode*)node completionBlock:(void(^)(U1FileNode *node, NSError *error))completionBlock;
3467 - (id)unpublishNode:(U1FileNode*)node completionBlock:(void(^)(U1FileNode *node, NSError *error))completionBlock;
3468+- (id)createFolderAtPath:(NSString*)folderPath completionBlock:(void(^)(NSDictionary *nodeInfo, NSError *error))completionBlock;
3469+- (id)createVolumeAtPath:(NSString*)folderPath completionBlock:(void(^)(NSDictionary *volumeInfo, NSError *error))completionBlock;
3470
3471 @end
3472
3473=== modified file 'Files/U1FilesService.m'
3474--- Files/U1FilesService.m 2011-09-27 14:36:00 +0000
3475+++ Files/U1FilesService.m 2011-11-01 14:25:30 +0000
3476@@ -17,17 +17,21 @@
3477
3478 #import "JSONKit.h"
3479 #import "OAuthConsumer.h"
3480+#import "Reachability.h"
3481
3482 #import "U1AccountManager.h"
3483 #import "U1HTTPRequestOperation.h"
3484 #import "U1Node.h"
3485 #import "U1FileNode.h"
3486
3487+static U1FilesService *sharedFilesService = nil;
3488
3489 @interface U1FilesService ()
3490
3491 @property (retain) NSOperationQueue *networkQueue;
3492+@property (retain) Reachability *reachability;
3493
3494+- (NSURL*)URLForVolumeWithPath:(NSString*)volumePath;
3495 - (NSURL*)URLForNode:(NSString*)nodePath includeChildren:(BOOL)includeChildren;
3496 - (id)execute:(NSString*)method toURL:(NSURL*)url withParameters:(NSDictionary*)parameters requestBody:(NSString*)body parseResponseBody:(BOOL)parseResponseBody completionBlock:(void(^)(id results, NSError *error))completionBlock;
3497 - (id)execute:(NSString*)method toURL:(NSURL*)url withParameters:(NSDictionary*)parameters requestData:(NSData*)bodyData contentType:(NSString*)contentType parseResponseBody:(BOOL)parseResponseBody completionBlock:(void(^)(id results, NSError *error))completionBlock;
3498@@ -42,7 +46,16 @@
3499 static NSString *const U1FilesServiceAPIVersion1 = @"/v1";
3500 static NSString *const U1FilesServiceAPIContentRoot = @"https://files.one.ubuntu.com";
3501
3502-@synthesize networkQueue;
3503+@synthesize networkQueue, reachability;
3504+
3505++ (U1FilesService*)sharedFilesService;
3506+{
3507+ if (sharedFilesService == nil)
3508+ {
3509+ sharedFilesService = [[self alloc] init];
3510+ }
3511+ return sharedFilesService;
3512+}
3513
3514 - (id)init;
3515 {
3516@@ -50,16 +63,31 @@
3517 if (self == nil)
3518 return nil;
3519 networkQueue = [[NSOperationQueue alloc] init];
3520+ reachability = [[Reachability reachabilityWithHostName:U1FilesServiceAPIContentRoot] retain];
3521+ [reachability startNotifer];
3522 return self;
3523 }
3524
3525 - (void)dealloc;
3526 {
3527 [networkQueue release];
3528+ [reachability stopNotifer];
3529+ [reachability release];
3530 [super dealloc];
3531 }
3532
3533-- (id)volumeInfoWithCompletionBlock:(void(^)(NSArray *volumeInfo, NSError *error))completionBlock;
3534+- (id)accountInfoWithCompletionBlock:(void(^)(NSDictionary *accountInfo, NSError *error))completionBlock;
3535+{
3536+ NSMutableString *urlString = [NSMutableString stringWithString:U1FilesServiceAPIBase];
3537+ [urlString appendString:U1FilesServiceAPIPath];
3538+ [urlString appendString:U1FilesServiceAPIVersion1];
3539+ NSURL *rootURL = [NSURL URLWithString:urlString];
3540+ return [self execute:@"GET" toURL:rootURL withParameters:nil requestBody:nil parseResponseBody:YES completionBlock:^(id results, NSError *error) {
3541+ completionBlock(results, error);
3542+ }];
3543+}
3544+
3545+- (id)volumeInfoWithCompletionBlock:(void(^)(NSArray *volumeInfos, NSError *error))completionBlock;
3546 {
3547 NSURL *volumesURL = [self URLForNode:@"/volumes" includeChildren:NO];
3548 return [self execute:@"GET" toURL:volumesURL withParameters:nil requestBody:nil parseResponseBody:YES completionBlock:^(id results, NSError *error) {
3549@@ -129,7 +157,9 @@
3550 if (completionBlock)
3551 completionBlock(fileURL);
3552 }];
3553+ [request release];
3554 [self.networkQueue addOperation:httpOperation];
3555+ [httpOperation release];
3556 return nil;
3557 }
3558
3559@@ -144,10 +174,11 @@
3560 [signatureProvider release];
3561
3562 [request setHTTPMethod:@"PUT"];
3563- [request setValue:@"application/octet-stream" forHTTPHeaderField:@"Content-Type"];
3564+ [request setValue:@"image/jpeg" forHTTPHeaderField:@"Content-Type"];
3565 [request prepare];
3566 NSInputStream *contentStream = [[NSInputStream alloc] initWithURL:contentURL];
3567 [request setHTTPBodyStream:contentStream];
3568+ [contentStream release];
3569
3570 U1HTTPRequestOperationInMemoryDataCollector *collector = [U1HTTPRequestOperationInMemoryDataCollector new];
3571 U1HTTPRequestOperation *httpOperation = [[U1HTTPRequestOperation alloc] initWithRequest:request dataCollector:collector];
3572@@ -158,16 +189,16 @@
3573 // completionBlock(fileURL);
3574 }];
3575 [self.networkQueue addOperation:httpOperation];
3576-
3577+ [httpOperation release];
3578 return nil;
3579 }
3580
3581-- (id)uploadContentData:(NSData*)contentData forNode:(U1FileNode*)node progressBlock:(void(^)(long long bytesUploaded, long long totalBytes))progressBlock completionBlock:(void(^)(NSDictionary *updatedNodeInfo, NSError *error))completionBlock;
3582+- (id)uploadContentData:(NSData*)contentData forNode:(U1FileNode*)node withContentType:(NSString*)contentType progressBlock:(void(^)(long long bytesUploaded, long long totalBytes))progressBlock completionBlock:(void(^)(NSDictionary *updatedNodeInfo, NSError *error))completionBlock;
3583 {
3584 NSString *contentPath = node.contentPath;
3585 NSURL *requestURL = [NSURL URLWithString:[[U1FilesServiceAPIContentRoot stringByAppendingPathComponent:contentPath] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
3586
3587- [self execute:@"PUT" toURL:requestURL withParameters:nil requestData:contentData contentType:@"application/octet-stream" parseResponseBody:YES completionBlock:^(id results, NSError *error) {
3588+ [self execute:@"PUT" toURL:requestURL withParameters:nil requestData:contentData contentType:contentType parseResponseBody:YES completionBlock:^(id results, NSError *error) {
3589
3590 completionBlock(results, error);
3591 }];
3592@@ -175,6 +206,19 @@
3593 return nil;
3594 }
3595
3596+- (id)moveNodeAtResourcePath:(NSString*)resourcePath toPath:(NSString*)newPath withCompletionBlock:(void(^)(NSDictionary *nodeInfo, NSError *error))completionBlock;
3597+{
3598+ NSParameterAssert(resourcePath != nil);
3599+ NSParameterAssert(newPath != nil);
3600+ NSParameterAssert(completionBlock != NULL);
3601+
3602+ NSURL *nodeURL = [self URLForNode:resourcePath includeChildren:NO];
3603+ NSString *body = [NSString stringWithFormat:@"{\"path\": \"%@\"}", newPath];
3604+ return [self execute:@"PUT" toURL:nodeURL withParameters:nil requestBody:body parseResponseBody:YES completionBlock:^(id results, NSError *error) {
3605+ completionBlock(results, error);
3606+ }];
3607+}
3608+
3609 - (id)deleteNodeAtResourcePath:(NSString*)resourcePath completionBlock:(void(^)(NSError *error))completionBlock;
3610 {
3611 NSURL *nodeURL = [self URLForNode:resourcePath includeChildren:NO];
3612@@ -205,9 +249,44 @@
3613 }];
3614 }
3615
3616+- (id)createFolderAtPath:(NSString*)folderPath completionBlock:(void(^)(NSDictionary *nodeInfo, NSError *error))completionBlock;
3617+{
3618+ NSParameterAssert(folderPath != nil);
3619+ NSParameterAssert(completionBlock != NULL);
3620+
3621+ NSURL *nodeURL = [self URLForNode:folderPath includeChildren:NO];
3622+ return [self execute:@"PUT" toURL:nodeURL withParameters:nil requestBody:@"{\"kind\": \"directory\"}" parseResponseBody:YES completionBlock:^(id results, NSError *error) {
3623+ completionBlock(results, error);
3624+ }];
3625+}
3626+
3627+- (id)createVolumeAtPath:(NSString*)volumePath completionBlock:(void(^)(NSDictionary *volumeInfo, NSError *error))completionBlock;
3628+{
3629+ NSParameterAssert(volumePath != nil);
3630+ NSParameterAssert(completionBlock != NULL);
3631+
3632+ NSURL *volumeURL = [self URLForVolumeWithPath:volumePath];
3633+ return [self execute:@"PUT" toURL:volumeURL withParameters:nil requestBody:@"" parseResponseBody:YES completionBlock:^(id results, NSError *error) {
3634+ completionBlock(results, error);
3635+ }];
3636+}
3637+
3638
3639 #pragma mark Private Methods
3640
3641+- (NSURL*)URLForVolumeWithPath:(NSString*)volumePath;
3642+{
3643+ NSParameterAssert(volumePath != nil);
3644+ NSParameterAssert([volumePath hasPrefix:@"/"]);
3645+
3646+ NSMutableString *urlString = [NSMutableString stringWithString:U1FilesServiceAPIBase];
3647+ [urlString appendString:U1FilesServiceAPIPath];
3648+ [urlString appendString:U1FilesServiceAPIVersion1];
3649+ [urlString appendString:@"/volumes"];
3650+ [urlString appendString:volumePath];
3651+ return [NSURL URLWithString:[urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
3652+}
3653+
3654 - (NSURL*)URLForNode:(NSString*)nodePath includeChildren:(BOOL)includeChildren;
3655 {
3656 NSMutableString *urlString = [NSMutableString stringWithString:U1FilesServiceAPIBase];
3657@@ -255,7 +334,7 @@
3658 ![[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(200, 100)] containsIndex:[response statusCode]])
3659 {
3660 // TODO: semantic error messages
3661- error = [NSError errorWithDomain:@"U1FilesServiceErrorDomain" code:0 userInfo:nil];
3662+ error = [NSError errorWithDomain:@"U1FilesServiceErrorDomain" code:[response statusCode] userInfo:nil];
3663 }
3664 if (!error && parseResponseBody)
3665 {
3666
3667=== modified file 'Files/U1FolderNode.m'
3668--- Files/U1FolderNode.m 2011-09-08 16:59:34 +0000
3669+++ Files/U1FolderNode.m 2011-11-01 14:25:30 +0000
3670@@ -21,7 +21,7 @@
3671 - (void)updatePropertiesFromJSONDictionary:(NSDictionary*)jsonDictionary;
3672 {
3673 [super updatePropertiesFromJSONDictionary:jsonDictionary];
3674- self.hasChildren = [jsonDictionary objectForKey:@"has_children"];
3675+ self.hasChildren = [jsonDictionary nonNullValueForKey:@"has_children"];
3676 }
3677
3678 - (BOOL)isFolder;
3679
3680=== modified file 'Files/U1FolderViewController.m'
3681--- Files/U1FolderViewController.m 2011-09-27 14:36:00 +0000
3682+++ Files/U1FolderViewController.m 2011-11-01 14:25:30 +0000
3683@@ -15,12 +15,14 @@
3684
3685 #import "U1FolderViewController.h"
3686
3687+#import <AssetsLibrary/AssetsLibrary.h>
3688 #import "U1ByteSizeValueTransformer.h"
3689 #import "U1FileNode.h"
3690 #import "U1FilesClient.h"
3691 #import "U1FolderItemCell.h"
3692 #import "U1FolderNode.h"
3693 #import "U1Node.h"
3694+#import "U1UTIMapper.h"
3695 #import "UIActionSheet+U1Additions.h"
3696
3697
3698@@ -48,8 +50,9 @@
3699 if (!self)
3700 return nil;
3701 self.title = [theResourcePath lastPathComponent];
3702- self.resourcePath = [theResourcePath copy];
3703+ self.resourcePath = theResourcePath;
3704 self.byteSizeTransformer = [[U1ByteSizeValueTransformer new] autorelease];
3705+ filesClient = [U1FilesClient sharedFilesClient];
3706
3707 UIBarButtonItem *uploadItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(uploadImage:)];
3708 [self.navigationItem setRightBarButtonItem:uploadItem];
3709@@ -74,7 +77,6 @@
3710 - (void)dealloc;
3711 {
3712 [loadingCell release];
3713- [filesClient release];
3714 [resourcePath release];
3715 [node release];
3716 [byteSizeTransformer release];
3717@@ -119,7 +121,7 @@
3718
3719 [actionSheet setTitle:[[childNode path] lastPathComponent]];
3720 [actionSheet setDestructiveButtonIndex:[actionSheet addButtonWithTitle:@"Delete"]];
3721- // TODO: rename
3722+ NSInteger renameButtonIndex = [actionSheet addButtonWithTitle:@"Rename"];
3723 NSInteger publishButtonIndex = -1;
3724 NSInteger copyURLButtonIndex = -1;
3725 if ([childNode isFile])
3726@@ -143,6 +145,10 @@
3727 {
3728 [self deleteNodeAtIndexPath:self.pendingIndexPath];
3729 }
3730+ else if (buttonIndex == renameButtonIndex)
3731+ {
3732+ NSLog(@"rename!"); // TODO:
3733+ }
3734 else if (buttonIndex == publishButtonIndex)
3735 {
3736 U1FileNode *fileNode = (id)childNode;
3737@@ -182,20 +188,42 @@
3738
3739 [picker dismissModalViewControllerAnimated:YES];
3740
3741-// NSURL *imageURL = [info objectForKey:UIImagePickerControllerReferenceURL];
3742- UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage];
3743+ NSURL *imageURL = [info objectForKey:UIImagePickerControllerReferenceURL];
3744+ ALAssetsLibrary *assetsLibrary = [[[ALAssetsLibrary alloc] init] autorelease];
3745+ U1UTIMapper *utiMapper = [U1UTIMapper sharedU1UTIMapper];
3746
3747- // TODO: pull date from ALAsset metadata
3748- NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
3749- [dateFormatter setDateStyle:NSDateFormatterMediumStyle];
3750- [dateFormatter setTimeStyle:NSDateFormatterMediumStyle];
3751- NSString *filename = [NSString stringWithFormat:@"Photo %@.png", [dateFormatter stringFromDate:[NSDate date]]];
3752+ [assetsLibrary assetForURL:imageURL
3753+ resultBlock:^(ALAsset *asset) {
3754+ ALAssetRepresentation *representation = [asset defaultRepresentation];
3755+ NSString *mimetype = [utiMapper MIMETypeForUTI:[representation UTI]];
3756+ NSString *assetType = [asset valueForProperty:ALAssetPropertyType];
3757+ NSDate *assetDate = [asset valueForProperty:ALAssetPropertyDate];
3758
3759- [self.filesClient uploadContentData:UIImagePNGRepresentation(image) toFolder:self.node withResourceName:filename progressBlock:^(long long bytesUploaded, long long totalBytes) {
3760-
3761- } completionBlock:^(U1FileNode *updatedNode, NSError *error) {
3762-
3763- }];
3764+ NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
3765+ [dateFormatter setDateStyle:NSDateFormatterMediumStyle];
3766+ [dateFormatter setTimeStyle:NSDateFormatterMediumStyle];
3767+
3768+ NSString *ext = [utiMapper extensionForUTI:[representation UTI]];
3769+ NSString *filename = [NSString stringWithFormat:@"%@ %@.%@", assetType, [dateFormatter stringFromDate:assetDate], ext];
3770+ [dateFormatter release];
3771+
3772+ Byte *buffer = (Byte*)malloc(representation.size);
3773+ NSUInteger length = [representation getBytes:buffer fromOffset:0 length:representation.size error:nil];
3774+ NSData *assetData = [NSData dataWithBytesNoCopy:buffer length:length freeWhenDone:YES];
3775+
3776+ dispatch_async(dispatch_get_main_queue(), ^(void) {
3777+ [self.filesClient uploadContentData:assetData
3778+ toFolder:self.node
3779+ withResourceName:filename
3780+ withContentType:mimetype
3781+ progressBlock:^(long long bytesUploaded, long long totalBytes) {}
3782+ completionBlock:^(U1FileNode *updatedNode, NSError *uploadError) {}
3783+ ];
3784+ });
3785+ } failureBlock:^(NSError *error) {
3786+ NSLog(@"Error: %@", error);
3787+ }];
3788+
3789 }
3790
3791
3792@@ -286,7 +314,7 @@
3793 {
3794 NSParameterAssert(self.resourcePath != nil);
3795
3796- [self.filesClient fetchNodeWithResourcePath:self.resourcePath completionBlock:^(U1Node *theNode, NSFetchedResultsController *childrenResultsController, NSError *error) {
3797+ [self.filesClient fetchFolderWithResourcePath:self.resourcePath completionBlock:^(U1Node *theNode, NSFetchedResultsController *childrenResultsController, NSError *error) {
3798
3799 self.node = (id)theNode;
3800 self.resultsController = childrenResultsController;
3801
3802=== added file 'Files/U1LocalAssetsManager.h'
3803--- Files/U1LocalAssetsManager.h 1970-01-01 00:00:00 +0000
3804+++ Files/U1LocalAssetsManager.h 2011-11-01 14:25:30 +0000
3805@@ -0,0 +1,33 @@
3806+//
3807+// Copyright 2011 Canonical Ltd.
3808+//
3809+// This program is free software: you can redistribute it and/or modify it
3810+// under the terms of the GNU Affero General Public License version 3,
3811+// as published by the Free Software Foundation.
3812+//
3813+// This program is distributed in the hope that it will be useful, but
3814+// WITHOUT ANY WARRANTY; without even the implied warranties of
3815+// MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
3816+// PURPOSE. See the GNU Affero General Public License for more details.
3817+//
3818+// You should have received a copy of the GNU Affero General Public License
3819+// along with this program. If not, see <http://www.gnu.org/licenses/>.
3820+
3821+#import <Foundation/Foundation.h>
3822+
3823+@class U1DataRepository;
3824+@class U1Volume;
3825+@class U1FileNode;
3826+
3827+
3828+@interface U1LocalAssetsManager : NSObject
3829+@property (retain) U1DataRepository *dataRepository;
3830+@property (retain) NSMutableSet *localAssetsToUpload;
3831+@property (retain) U1FolderNode *remoteUploadFolder;
3832++ (U1LocalAssetsManager *)sharedLocalAssetsManager;
3833+- (int)numberOfAssets;
3834+- (int)numberOfAssetsUploaded;
3835+- (void)checkForNewAssets;
3836+- (BOOL)isResourceUploading:(NSString *)resourcePath;
3837+- (void)thumbnailForNode:(U1FileNode *)fileNode completionBlock:(void(^)(CGImageRef thumbnail))completionBlock;
3838+@end
3839
3840=== added file 'Files/U1LocalAssetsManager.m'
3841--- Files/U1LocalAssetsManager.m 1970-01-01 00:00:00 +0000
3842+++ Files/U1LocalAssetsManager.m 2011-11-01 14:25:30 +0000
3843@@ -0,0 +1,354 @@
3844+//
3845+// Copyright 2011 Canonical Ltd.
3846+//
3847+// This program is free software: you can redistribute it and/or modify it
3848+// under the terms of the GNU Affero General Public License version 3,
3849+// as published by the Free Software Foundation.
3850+//
3851+// This program is distributed in the hope that it will be useful, but
3852+// WITHOUT ANY WARRANTY; without even the implied warranties of
3853+// MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
3854+// PURPOSE. See the GNU Affero General Public License for more details.
3855+//
3856+// You should have received a copy of the GNU Affero General Public License
3857+// along with this program. If not, see <http://www.gnu.org/licenses/>.
3858+
3859+#import <AssetsLibrary/AssetsLibrary.h>
3860+
3861+#import "Reachability.h"
3862+
3863+#import "U1Asset.h"
3864+#import "U1DataRepository.h"
3865+#import "U1LocalAssetsManager.h"
3866+#import "U1AssetUploadOperation.h"
3867+#import "U1FileNode.h"
3868+#import "U1FilesClient.h"
3869+#import "U1Volume.h"
3870+#import "U1UTIMapper.h"
3871+
3872+
3873+@interface U1LocalAssetsManager ()
3874+@property (retain) ALAssetsLibrary *assetsLibrary;
3875+@property (retain) NSOperationQueue *uploadQueue;
3876+- (void)walkAssetsInLibrary;
3877+- (void)uploadRepresentation:(ALAssetRepresentation*)rep forAsset:(U1Asset*)asset withPriority:(NSOperationQueuePriority)priority;
3878+- (NSString *)generateFilenameForAsset:(ALAsset *)asset;
3879+- (U1FileNode *)createPendingFileNodeForResourcePath:(NSString *)resourcePath asset:(U1Asset *)asset;
3880+- (void)processAssetBatch:(NSArray*)batch inGroup:(ALAssetsGroup *)group;
3881+- (void)autoUploadSettingsChanged:(NSNotification*)notification;
3882+@end
3883+
3884+static U1LocalAssetsManager *sharedLocalAssetsManager = nil;
3885+
3886+@implementation U1LocalAssetsManager
3887+
3888+@synthesize dataRepository, uploadQueue, localAssetsToUpload, remoteUploadFolder;
3889+@synthesize assetsLibrary;
3890+
3891++ (U1LocalAssetsManager *)sharedLocalAssetsManager;
3892+{
3893+ if (sharedLocalAssetsManager == nil)
3894+ {
3895+ sharedLocalAssetsManager = [[self alloc] init];
3896+ }
3897+ return sharedLocalAssetsManager;
3898+}
3899+
3900+- (id)init
3901+{
3902+ if (!(self = [super init]))
3903+ return nil;
3904+
3905+ NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
3906+
3907+ assetsLibrary = [[ALAssetsLibrary alloc] init];
3908+ [defaultCenter addObserver:self selector:@selector(libraryChanged:) name:ALAssetsLibraryChangedNotification object:assetsLibrary];
3909+ [defaultCenter addObserver:self selector:@selector(autoUploadSettingsChanged:) name:NSUserDefaultsDidChangeNotification object:[NSUserDefaults standardUserDefaults]];
3910+ dataRepository = [U1DataRepository sharedDataRepository];
3911+ uploadQueue = [[NSOperationQueue alloc] init];
3912+ [uploadQueue setMaxConcurrentOperationCount:4];
3913+ self.localAssetsToUpload = [NSMutableSet set];
3914+ [defaultCenter addObserver:self selector:@selector(reachabilityChanged:) name:kReachabilityChangedNotification object:nil];
3915+ return self;
3916+
3917+}
3918+
3919+- (void)dealloc
3920+{
3921+ [[NSNotificationCenter defaultCenter] removeObserver:self];
3922+ [assetsLibrary release];
3923+ [super dealloc];
3924+}
3925+
3926+- (void)checkForNewAssets;
3927+{
3928+ [self walkAssetsInLibrary];
3929+}
3930+
3931+- (void)libraryChanged:(NSNotification*)notification;
3932+{
3933+ [self walkAssetsInLibrary];
3934+}
3935+
3936+- (void)autoUploadSettingsChanged:(NSNotification *)notification;
3937+{
3938+ NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
3939+
3940+ if ([defaults boolForKey:@"auto_upload"])
3941+ {
3942+ // Turned it on, start your engines
3943+ [self.uploadQueue setSuspended:NO];
3944+ [self walkAssetsInLibrary];
3945+ }
3946+ else
3947+ {
3948+ // Turned it off, cancel all operations
3949+ [self.uploadQueue setSuspended:YES];
3950+ }
3951+}
3952+
3953+- (void)reachabilityChanged:(NSNotification*)notification;
3954+{
3955+ Reachability *reachability = [notification object];
3956+ NetworkStatus status = [reachability currentReachabilityStatus];
3957+ switch (status)
3958+ {
3959+ case ReachableViaWiFi:
3960+ [self.uploadQueue setSuspended:NO];
3961+ break;
3962+ case ReachableViaWWAN:
3963+ {
3964+ BOOL shouldSuspend = [[NSUserDefaults standardUserDefaults] boolForKey:@"wifi_only"];
3965+ [self.uploadQueue setSuspended:shouldSuspend];
3966+ break;
3967+ }
3968+ case NotReachable:
3969+ [self.uploadQueue setSuspended:YES];
3970+ break;
3971+ }
3972+}
3973+
3974+- (void)walkAssetsInLibrary;
3975+{
3976+ NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
3977+ if ([defaults boolForKey:@"auto_upload"]) {
3978+ [self.assetsLibrary enumerateGroupsWithTypes:ALAssetsGroupSavedPhotos
3979+ usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
3980+ __block NSMutableArray *batch = [[NSMutableArray alloc] initWithCapacity:50];
3981+ [group enumerateAssetsUsingBlock:^(ALAsset *asset, NSUInteger index, BOOL *stop) {
3982+ if (asset == nil)
3983+ {
3984+ return;
3985+ }
3986+
3987+ [batch addObject:asset];
3988+
3989+ if ([batch count] >= 50)
3990+ {
3991+ NSSortDescriptor *sortBy = [NSSortDescriptor sortDescriptorWithKey:@"defaultRepresentation.url.absoluteString" ascending:YES];
3992+ [batch sortUsingDescriptors:[NSArray arrayWithObject:sortBy]];
3993+ [self processAssetBatch:batch inGroup:group];
3994+ [batch release];
3995+ batch = [[NSMutableArray alloc] initWithCapacity:50];
3996+ }
3997+ }];
3998+ if ([batch count] > 0) // Deal with last partial batch
3999+ {
4000+ NSSortDescriptor *sortBy = [NSSortDescriptor sortDescriptorWithKey:@"defaultRepresentation.url.absoluteString" ascending:YES];
4001+ [batch sortUsingDescriptors:[NSArray arrayWithObject:sortBy]];
4002+ [self processAssetBatch:batch inGroup:group];
4003+ }
4004+ [batch release];
4005+ batch = nil;
4006+ }
4007+ failureBlock:^(NSError *error) {
4008+ NSLog(@"Some error happened: %@", error);
4009+ }];
4010+ }
4011+}
4012+
4013+- (void)processAssetBatch:(NSArray*)batch inGroup:(ALAssetsGroup *)group;
4014+{
4015+ NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
4016+
4017+ // instead of dealing with a single asset, loop over our batch
4018+ NSMutableArray *URLs = [batch valueForKeyPath:@"defaultRepresentation.url.absoluteString"];
4019+
4020+ dispatch_async(dispatch_get_main_queue(), ^(void) {
4021+
4022+ NSPredicate *p = [NSPredicate predicateWithFormat:@"url in %@", URLs];
4023+ NSError *error = nil;
4024+ NSSortDescriptor *sortBy = [NSSortDescriptor sortDescriptorWithKey:@"url" ascending:YES];
4025+ NSArray *existingU1Assets = [self.dataRepository resultsForEntityClass:[U1Asset class] matchingPredicate:p withSortDescriptors:[NSArray arrayWithObject:sortBy] error:&error];
4026+
4027+ // If batch's asset isn't in existingU1Assets or existingU1Asset's generation is nil, we upload it.
4028+
4029+ // walk batch, looking for
4030+ NSEnumerator *assetEnumerator = [existingU1Assets objectEnumerator];
4031+ __block U1Asset *nextU1Asset = [assetEnumerator nextObject];
4032+ [batch enumerateObjectsUsingBlock:^(ALAsset *asset, NSUInteger idx, BOOL *stop) {
4033+ BOOL shouldUpload = NO;
4034+ U1Asset *assetToUpload = nil;
4035+
4036+ NSString *url = [[[asset defaultRepresentation] url] absoluteString];
4037+ while (nextU1Asset && [nextU1Asset.url compare:url] == NSOrderedAscending)
4038+ nextU1Asset = [assetEnumerator nextObject];
4039+
4040+ if ([nextU1Asset.url isEqualToString:url])
4041+ {
4042+ // matched... if the generation is nil, still need to upload it, but don't need to create it
4043+ if (nextU1Asset.generation == nil)
4044+ {
4045+ shouldUpload = YES;
4046+ assetToUpload = nextU1Asset;
4047+ }
4048+ }
4049+ else
4050+ {
4051+ // no U1asset, need to create/upload
4052+ NSString *assetType = [asset valueForProperty:ALAssetPropertyType];
4053+ BOOL canUpload = NO;
4054+ if ([defaults boolForKey:@"include_video"])
4055+ {
4056+ canUpload = ([assetType isEqualToString:ALAssetTypePhoto] ||
4057+ [assetType isEqualToString:ALAssetTypeVideo]);
4058+ }
4059+ else
4060+ {
4061+ canUpload = [assetType isEqualToString:ALAssetTypePhoto];
4062+ }
4063+
4064+ if (canUpload) {
4065+ __block U1Asset *newAsset = nil;
4066+ [self.dataRepository dispatchBlockWithManagedObjectContext:^(NSManagedObjectContext *context) {
4067+
4068+ newAsset = [U1Asset insertInManagedObjectContext:context];
4069+ newAsset.groupId = [group valueForProperty: ALAssetsGroupPropertyPersistentID];
4070+ newAsset.url = url;
4071+ newAsset.filename = [self generateFilenameForAsset:asset];
4072+ NSString *resourcePath = [self.remoteUploadFolder.resourcePath stringByAppendingPathComponent:newAsset.filename];
4073+ [self createPendingFileNodeForResourcePath:resourcePath asset:newAsset];
4074+ }];
4075+
4076+ shouldUpload = YES;
4077+ assetToUpload = newAsset;
4078+ }
4079+ }
4080+ // Check shouldUpload flag
4081+ if (shouldUpload && ![self.localAssetsToUpload member:assetToUpload])
4082+ {
4083+ [self uploadRepresentation:[asset defaultRepresentation] forAsset:assetToUpload withPriority:NSOperationQueuePriorityNormal];
4084+ }
4085+ }];
4086+ });
4087+
4088+ dispatch_async(dispatch_get_main_queue(), ^(void) {
4089+ [self.dataRepository save:NULL];
4090+ });
4091+}
4092+
4093+- (NSString *)generateFilenameForAsset:(ALAsset *)asset;
4094+{
4095+ // get the type of the asset
4096+ U1UTIMapper *utiMapper = [U1UTIMapper sharedU1UTIMapper];
4097+
4098+ NSString *ext = [utiMapper extensionForUTI:[asset.defaultRepresentation UTI]];
4099+
4100+ int idx = (int)[self numberOfAssets];
4101+
4102+ return [NSString stringWithFormat:@"IMG_%d.%@", idx, ext];
4103+}
4104+
4105+- (void)uploadRepresentation:(ALAssetRepresentation *)rep forAsset:(U1Asset *)asset withPriority:(NSOperationQueuePriority)priority;
4106+{
4107+ NSString *resourcePath = [self.remoteUploadFolder.resourcePath stringByAppendingPathComponent:asset.filename];
4108+
4109+ if (![self isResourceUploading:resourcePath])
4110+ {
4111+ [self.localAssetsToUpload addObject:asset];
4112+
4113+ U1AssetUploadOperation *operation = [[U1AssetUploadOperation alloc] init];
4114+ operation.asset = asset;
4115+ operation.folder = self.remoteUploadFolder;
4116+ operation.filename = asset.filename;
4117+ operation.mimetype = [[U1UTIMapper sharedU1UTIMapper] MIMETypeForUTI:[rep UTI]];
4118+ operation.representation = rep;
4119+ [operation setCompletionBlock:^{
4120+ dispatch_async(dispatch_get_main_queue(), ^(void) {
4121+ if (operation.error == nil) // or the error is somehow unrecoverable (e.g., over quota)
4122+ {
4123+ asset.generation = asset.fileNode.generation;
4124+ [self.dataRepository save:NULL];
4125+ [self.localAssetsToUpload removeObject:asset];
4126+ [[NSNotificationCenter defaultCenter] postNotificationName:@"imageUploaded" object:nil];
4127+ // Fire a notification that our U1LocalAssetsViewController can subscribe to
4128+ }
4129+ else
4130+ {
4131+ NSLog(@"Error trying to upload %@: %@", operation.filename, operation.error);
4132+ // Try it again (this is brittle if the error isn't recoverable (e.g. over quota)
4133+ [self uploadRepresentation:rep forAsset:asset withPriority:NSOperationQueuePriorityHigh];
4134+ }
4135+ });
4136+ }];
4137+ [self.uploadQueue addOperation:operation];
4138+ }
4139+}
4140+
4141+- (U1FileNode *)createPendingFileNodeForResourcePath:(NSString *)resourcePath asset:(U1Asset *)asset;
4142+{
4143+ __block U1FileNode *node = nil;
4144+
4145+ // TODO: temporary, create node if doesn't exist
4146+ [self.dataRepository dispatchBlockWithManagedObjectContext:^(NSManagedObjectContext *context) {
4147+ node = [U1FileNode insertInManagedObjectContext:context];
4148+ node.resourcePath = resourcePath;
4149+ node.kind = @"file";
4150+ node.parent = self.remoteUploadFolder;
4151+ node.contentPath = [self.remoteUploadFolder.contentPath stringByAppendingPathComponent:[resourcePath lastPathComponent]];
4152+ node.asset = asset;
4153+ }];
4154+
4155+ return node;
4156+}
4157+
4158+- (int)numberOfAssets;
4159+{
4160+ NSError *error = nil;
4161+ return [[self.dataRepository resultsForEntityClass:[U1Asset class]
4162+ matchingPredicate:nil
4163+ withSortDescriptors:nil
4164+ error:&error] count];
4165+}
4166+
4167+- (int)numberOfAssetsUploaded;
4168+{
4169+ return [self numberOfAssets] - [self.localAssetsToUpload count];
4170+}
4171+
4172+- (BOOL)isResourceUploading:(NSString *)resourcePath;
4173+{
4174+ __block BOOL isUploading = NO;
4175+
4176+ [[self.uploadQueue operations] enumerateObjectsUsingBlock:^(U1AssetUploadOperation *operation, NSUInteger idx, BOOL *stop) {
4177+ if ([operation.filename isEqualToString:[resourcePath lastPathComponent]] && [operation isExecuting])
4178+ {
4179+ isUploading = YES;
4180+ *stop = YES;
4181+ }
4182+ }];
4183+
4184+ return isUploading;
4185+}
4186+
4187+- (void)thumbnailForNode:(U1FileNode *)fileNode completionBlock:(void(^)(CGImageRef thumbnail))completionBlock;
4188+{
4189+ [self.assetsLibrary assetForURL:[NSURL URLWithString:fileNode.asset.url]
4190+ resultBlock:^(ALAsset *asset) {
4191+ completionBlock(asset.thumbnail);
4192+ } failureBlock:^(NSError *error) {
4193+ NSLog(@"Couldn't find the asset to get a thumbnail: %@", error);
4194+ }];
4195+}
4196+
4197+@end
4198
4199=== added file 'Files/U1LocalAssetsViewController.h'
4200--- Files/U1LocalAssetsViewController.h 1970-01-01 00:00:00 +0000
4201+++ Files/U1LocalAssetsViewController.h 2011-11-01 14:25:30 +0000
4202@@ -0,0 +1,43 @@
4203+//
4204+// Copyright 2011 Canonical Ltd.
4205+//
4206+// This program is free software: you can redistribute it and/or modify it
4207+// under the terms of the GNU Affero General Public License version 3,
4208+// as published by the Free Software Foundation.
4209+//
4210+// This program is distributed in the hope that it will be useful, but
4211+// WITHOUT ANY WARRANTY; without even the implied warranties of
4212+// MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
4213+// PURPOSE. See the GNU Affero General Public License for more details.
4214+//
4215+// You should have received a copy of the GNU Affero General Public License
4216+// along with this program. If not, see <http://www.gnu.org/licenses/>.
4217+
4218+#import <UIKit/UIKit.h>
4219+
4220+#import "PullRefreshTableViewController.h"
4221+
4222+@class U1FilesClient, U1Node;
4223+
4224+@protocol U1LocalAssetsViewControllerDelegate;
4225+
4226+
4227+@interface U1LocalAssetsViewController : PullRefreshTableViewController
4228+
4229+@property (nonatomic, retain, readonly) IBOutlet UITableViewCell *loadingCell;
4230+@property (nonatomic, retain) IBOutlet UIView *progressView;
4231+@property (nonatomic, retain) IBOutlet UIProgressView *progressBar;
4232+@property (nonatomic, retain) IBOutlet UILabel *progressLabel;
4233+
4234+@property (assign) id<U1LocalAssetsViewControllerDelegate> delegate;
4235+@property (retain) U1FilesClient *filesClient;
4236+
4237+- (id)initWithNodeResourcePath:(NSString*)resourcePath;
4238+
4239+@end
4240+
4241+
4242+@protocol U1LocalAssetsViewControllerDelegate <NSObject>
4243+@required
4244+- (void)localAssetsController:(U1LocalAssetsViewController*)localAssetsController didSelectNode:(U1Node*)node;
4245+@end
4246
4247=== added file 'Files/U1LocalAssetsViewController.m'
4248--- Files/U1LocalAssetsViewController.m 1970-01-01 00:00:00 +0000
4249+++ Files/U1LocalAssetsViewController.m 2011-11-01 14:25:30 +0000
4250@@ -0,0 +1,420 @@
4251+//
4252+// Copyright 2011 Canonical Ltd.
4253+//
4254+// This program is free software: you can redistribute it and/or modify it
4255+// under the terms of the GNU Affero General Public License version 3,
4256+// as published by the Free Software Foundation.
4257+//
4258+// This program is distributed in the hope that it will be useful, but
4259+// WITHOUT ANY WARRANTY; without even the implied warranties of
4260+// MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
4261+// PURPOSE. See the GNU Affero General Public License for more details.
4262+//
4263+// You should have received a copy of the GNU Affero General Public License
4264+// along with this program. If not, see <http://www.gnu.org/licenses/>.
4265+
4266+#import "U1LocalAssetsViewController.h"
4267+
4268+#import "U1ByteSizeValueTransformer.h"
4269+#import "U1FileNode.h"
4270+#import "U1FilePreviewViewController.h"
4271+#import "U1FilesClient.h"
4272+#import "U1FolderItemCell.h"
4273+#import "U1FolderNode.h"
4274+#import "U1Node.h"
4275+#import "UIActionSheet+U1Additions.h"
4276+#import "U1LocalAssetsManager.h"
4277+#import "U1DataRepository.h"
4278+
4279+@interface U1LocalAssetsViewController () <U1LocalAssetsViewControllerDelegate, UINavigationControllerDelegate, UIImagePickerControllerDelegate, NSFetchedResultsControllerDelegate>
4280+@property (copy) NSString *resourcePath;
4281+@property (retain) U1ByteSizeValueTransformer *byteSizeTransformer;
4282+@property (retain) NSIndexPath *pendingIndexPath;
4283+@property (retain) U1FolderNode *node;
4284+@property (retain) NSMutableArray *nodes;
4285+@property (retain) NSFetchedResultsController *resultsController;
4286+@property (retain) U1LocalAssetsManager *localAssetsManager;
4287+- (void)updateFeedback:(id)sender;
4288+- (void)loadInfoForNode;
4289+@end
4290+
4291+
4292+@implementation U1LocalAssetsViewController
4293+
4294+@synthesize loadingCell, progressView, progressBar, progressLabel;
4295+@synthesize delegate, filesClient, node, resourcePath;
4296+@synthesize byteSizeTransformer, pendingIndexPath, nodes, resultsController, localAssetsManager;
4297+
4298+- (id)initWithNodeResourcePath:(NSString*)theResourcePath;
4299+{
4300+ self = [super initWithNibName:@"U1LocalAssetsViewController" bundle:nil];
4301+ if (!self)
4302+ return nil;
4303+ self.title = NSLocalizedString(@"Camera Roll", @"");
4304+ self.resourcePath = theResourcePath;
4305+ self.byteSizeTransformer = [[U1ByteSizeValueTransformer new] autorelease];
4306+ self.delegate = self; // ???
4307+ filesClient = [U1FilesClient sharedFilesClient];
4308+ localAssetsManager = [U1LocalAssetsManager sharedLocalAssetsManager];
4309+
4310+ // This button should use a camera icon and go to the image picker to take a new photo.
4311+ UIBarButtonItem *cameraButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCamera target:self action:@selector(takePicture:)];
4312+ [self.navigationItem setRightBarButtonItem:cameraButton];
4313+ [cameraButton release];
4314+
4315+ UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 100, 20)];
4316+ // TODO: Ubuntu font
4317+ [titleLabel setFont:[UIFont boldSystemFontOfSize:18.f]];
4318+ [titleLabel setTextColor:[UIColor blackColor]];
4319+ [titleLabel setShadowColor:[UIColor whiteColor]];
4320+ [titleLabel setShadowOffset:CGSizeMake(-1, -1)];
4321+ [titleLabel setText:self.title];
4322+ [titleLabel sizeToFit];
4323+ [titleLabel setOpaque:NO];
4324+ [titleLabel setBackgroundColor:[UIColor clearColor]];
4325+ [self.navigationItem setTitleView:titleLabel];
4326+ [titleLabel release];
4327+ // [uploadItem release];
4328+
4329+ return self;
4330+}
4331+
4332+- (void)dealloc;
4333+{
4334+ [loadingCell release];
4335+ [resourcePath release];
4336+ [node release];
4337+ [byteSizeTransformer release];
4338+ [pendingIndexPath release];
4339+ [nodes release];
4340+ [resultsController release];
4341+ [super dealloc];
4342+}
4343+
4344+- (void)viewDidLoad;
4345+{
4346+ [super viewDidLoad];
4347+ [self updateFeedback:nil];
4348+ [self refresh];
4349+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateFeedback:) name:@"imageUploaded" object:nil];
4350+ UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPress:)];
4351+ [longPress setMinimumPressDuration:1.f];
4352+ [self.tableView addGestureRecognizer:longPress];
4353+ [longPress release];
4354+}
4355+
4356+- (void)viewDidUnload;
4357+{
4358+ [loadingCell release], loadingCell = nil;
4359+ [[NSNotificationCenter defaultCenter] removeObserver:self];
4360+ [super viewDidUnload];
4361+}
4362+
4363+- (void)viewDidAppear:(BOOL)animated;
4364+{
4365+ [super viewDidAppear:animated];
4366+ [self.tableView deselectRowAtIndexPath:[self.tableView indexPathForSelectedRow] animated:YES];
4367+}
4368+
4369+- (void)longPress:(UILongPressGestureRecognizer*)longPress;
4370+{
4371+ if (longPress.state == UIGestureRecognizerStateBegan)
4372+ {
4373+ CGPoint p = [longPress locationInView:self.tableView];
4374+ NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:p];
4375+ U1Node *childNode = [self.nodes objectAtIndex:indexPath.row];
4376+
4377+ UIActionSheet *actionSheet = [UIActionSheet new];
4378+
4379+ [actionSheet setTitle:[[childNode path] lastPathComponent]];
4380+ // TODO: rename
4381+ NSInteger publishButtonIndex = -1;
4382+ NSInteger copyURLButtonIndex = -1;
4383+ if ([childNode isFile])
4384+ {
4385+ U1FileNode *fileNode = (id)childNode;
4386+ if ([[fileNode isPublic] boolValue])
4387+ {
4388+ publishButtonIndex = [actionSheet addButtonWithTitle:@"Unpublish"];
4389+ copyURLButtonIndex = [actionSheet addButtonWithTitle:@"Copy Public URL"];
4390+ }
4391+ else
4392+ {
4393+ publishButtonIndex = [actionSheet addButtonWithTitle:@"Publish"];
4394+ }
4395+ }
4396+ [actionSheet setCancelButtonIndex:[actionSheet addButtonWithTitle:@"Cancel"]];
4397+
4398+ self.pendingIndexPath = indexPath;
4399+ [actionSheet showInView:self.view withCompletionBlock:^(NSInteger buttonIndex) {
4400+ if (buttonIndex == publishButtonIndex)
4401+ {
4402+ U1FileNode *fileNode = (id)childNode;
4403+ if ([[fileNode isPublic] boolValue])
4404+ [self.filesClient unpublishNode:fileNode completionBlock:^(U1FileNode *updatedNode, NSError *error) {
4405+ }];
4406+ else
4407+ [self.filesClient publishNode:fileNode completionBlock:^(U1FileNode *updatedNode, NSError *error) {
4408+ }];
4409+ }
4410+ else if (buttonIndex == copyURLButtonIndex)
4411+ {
4412+ U1FileNode *fileNode = (id)childNode;
4413+ NSArray *types = UIPasteboardTypeListString;
4414+ [[UIPasteboard generalPasteboard] setValue:[fileNode publicURLString] forPasteboardType:[types lastObject]];
4415+ }
4416+ else if (buttonIndex == [actionSheet cancelButtonIndex])
4417+ {
4418+ // NSLog(@"cancel");
4419+ }
4420+ self.pendingIndexPath = nil;
4421+ }];
4422+ }
4423+}
4424+
4425+- (void)takePicture:(id)sender;
4426+{
4427+ UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
4428+ imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
4429+ imagePicker.delegate = self;
4430+ [self presentModalViewController:imagePicker animated:YES];
4431+}
4432+
4433+- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info;
4434+{
4435+ // TODO: check for jpg/png
4436+ // TODO: handle videos (stream)
4437+
4438+ [picker dismissModalViewControllerAnimated:YES];
4439+
4440+ // NSURL *imageURL = [info objectForKey:UIImagePickerControllerReferenceURL];
4441+ UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage];
4442+
4443+ UIImageWriteToSavedPhotosAlbum(image, self, nil, nil);
4444+}
4445+
4446+- (void)updateFeedback:(id)sender;
4447+{
4448+ // Update the label and the progress bar
4449+ // progressLabel = (numberOfAssets - assetsPendingUpload) / numberOfAssets
4450+ dispatch_async(dispatch_get_main_queue(), ^{
4451+ U1LocalAssetsManager *localAssets = [U1LocalAssetsManager sharedLocalAssetsManager];
4452+ int totalAssets = [localAssets numberOfAssets];
4453+ int assetsUploaded = [localAssets numberOfAssetsUploaded];
4454+ float percentDone = (float)assetsUploaded / (float)totalAssets;
4455+ self.progressLabel.text = [NSString stringWithFormat:@"%d of %d uploaded", assetsUploaded, totalAssets];
4456+ self.progressBar.progress = percentDone;
4457+ [self.tableView reloadData];
4458+ });
4459+}
4460+
4461+#pragma mark UITableViewDataSource Methods
4462+
4463+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;
4464+{
4465+ if (!self.resultsController)
4466+ return 1;
4467+
4468+ return [[[self.resultsController sections] objectAtIndex:section] numberOfObjects];
4469+}
4470+
4471+- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section;
4472+{
4473+ if (section == 0 && [self.localAssetsManager.localAssetsToUpload count] > 0)
4474+ {
4475+ return 66.0f;
4476+ }
4477+
4478+ return [tableView sectionHeaderHeight];
4479+}
4480+
4481+- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section;
4482+{
4483+ if (section == 0 && [self.localAssetsManager.localAssetsToUpload count] > 0)
4484+ {
4485+ return self.progressView;
4486+ }
4487+
4488+ return nil;
4489+}
4490+
4491+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
4492+{
4493+ if (!self.resultsController)
4494+ {
4495+ return self.loadingCell;
4496+ }
4497+
4498+ U1FolderItemCell *cell = [U1FolderItemCell cellForTableView:tableView];
4499+
4500+ U1Node *childNode = [self.resultsController objectAtIndexPath:indexPath];
4501+ cell.nameLabel.text = [childNode.resourcePath lastPathComponent];
4502+ NSString *detailString = @"Pending";
4503+// TODO: get this thumbnail loading happening inside an operation queue, tied to visible rows
4504+// [self.localAssetsManager thumbnailForNode:childNode completionBlock:^(CGImageRef thumbnail) {
4505+// cell.iconImageView.image = [UIImage imageWithCGImage:thumbnail];
4506+// }];
4507+
4508+ BOOL hasChildren = [[childNode hasChildren] boolValue];
4509+ [cell setAccessoryType:(hasChildren ? UITableViewCellAccessoryDisclosureIndicator : UITableViewCellAccessoryNone)];
4510+
4511+ if (childNode.generation == nil)
4512+ {
4513+ cell.nameLabel.textColor = [UIColor grayColor];
4514+ // query the local assets manager to see if this childNode's corresponding asset is actually in the upload operation queue
4515+ BOOL isUploading = [self.localAssetsManager isResourceUploading:childNode.resourcePath];
4516+ if (isUploading)
4517+ {
4518+ [cell.uploadIndicator setHidden:NO];
4519+ [cell.uploadIndicator startAnimating];
4520+ detailString = @"Uploading";
4521+ }
4522+ else {
4523+ [cell.uploadIndicator setHidden:YES];
4524+ [cell.uploadIndicator stopAnimating];
4525+ }
4526+ }
4527+ else
4528+ {
4529+ cell.nameLabel.textColor = [UIColor blackColor];
4530+ [cell.detailLabel setHidden:NO];
4531+ [cell.uploadIndicator setHidden:YES];
4532+ [cell.uploadIndicator stopAnimating];
4533+ }
4534+
4535+ [cell.imageView setImage:nil];
4536+ if ([childNode isFolder])
4537+ {
4538+ [cell.imageView setImage:[UIImage imageNamed:@"ic_folder"]];
4539+ detailString = [childNode.modificationDate description];
4540+ }
4541+ else
4542+ {
4543+ NSString *contentPath = childNode.contentPath;
4544+ NSURL *contentURL = [NSURL fileURLWithPath:contentPath];
4545+ UIDocumentInteractionController *docController = [UIDocumentInteractionController interactionControllerWithURL:contentURL];
4546+ [cell.imageView setImage:[docController.icons objectAtIndex:0]];
4547+ NSNumber *size = [childNode valueForKey:@"size"];
4548+ NSString *sizeString = [self.byteSizeTransformer transformedValue:size];
4549+ if (childNode.generation != nil)
4550+ {
4551+ detailString = [sizeString stringByAppendingFormat:@", modified %@", childNode.modificationDate];
4552+ }
4553+ }
4554+
4555+ [cell.detailLabel setText:detailString];
4556+ return cell;
4557+}
4558+
4559+
4560+#pragma mark UITableViewDelegate Methods
4561+
4562+- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;
4563+{
4564+ U1Node *childNode = [self.resultsController objectAtIndexPath:indexPath];
4565+ [self.delegate localAssetsController:self didSelectNode:childNode];
4566+}
4567+
4568+- (void)refresh;
4569+{
4570+ [self loadInfoForNode];
4571+}
4572+
4573+
4574+#pragma mark Private Methods
4575+
4576+- (void)loadInfoForNode;
4577+{
4578+ NSParameterAssert(self.resourcePath != nil);
4579+
4580+ [self.filesClient fetchFolderWithResourcePath:self.resourcePath completionBlock:^(U1Node *theNode, NSFetchedResultsController *childrenResultsController, NSError *error) {
4581+
4582+ self.node = (id)theNode;
4583+ self.resultsController = childrenResultsController;
4584+ [self.resultsController setDelegate:self];
4585+ [self stopLoading];
4586+ [self.tableView reloadData];
4587+ }];
4588+}
4589+
4590+#pragma mark NSFetchedResultsControllerDelegate Methods
4591+
4592+
4593+- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller;
4594+{
4595+ [self.tableView beginUpdates];
4596+}
4597+
4598+
4599+- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo
4600+ atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type;
4601+{
4602+ switch (type)
4603+ {
4604+ case NSFetchedResultsChangeInsert:
4605+ [self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex]
4606+ withRowAnimation:UITableViewRowAnimationFade];
4607+ break;
4608+
4609+ case NSFetchedResultsChangeDelete:
4610+ [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex]
4611+ withRowAnimation:UITableViewRowAnimationFade];
4612+ break;
4613+ }
4614+}
4615+
4616+- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject
4617+ atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type
4618+ newIndexPath:(NSIndexPath *)newIndexPath;
4619+{
4620+
4621+ UITableView *tableView = self.tableView;
4622+
4623+ switch (type)
4624+ {
4625+
4626+ case NSFetchedResultsChangeInsert:
4627+ [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
4628+ withRowAnimation:UITableViewRowAnimationFade];
4629+ break;
4630+
4631+ case NSFetchedResultsChangeDelete:
4632+ [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
4633+ withRowAnimation:UITableViewRowAnimationFade];
4634+ break;
4635+
4636+ case NSFetchedResultsChangeUpdate:
4637+ // TODO:
4638+ // [self configureCell:[tableView cellForRowAtIndexPath:indexPath]
4639+ // atIndexPath:indexPath];
4640+ [self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
4641+ withRowAnimation:UITableViewRowAnimationNone];
4642+ break;
4643+
4644+ case NSFetchedResultsChangeMove:
4645+ [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
4646+ withRowAnimation:UITableViewRowAnimationFade];
4647+ [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
4648+ withRowAnimation:UITableViewRowAnimationFade];
4649+ break;
4650+ }
4651+}
4652+
4653+- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller;
4654+{
4655+ [self.tableView endUpdates];
4656+}
4657+
4658+#pragma mark U1LocalAssetsViewControllerDelegate Methods
4659+
4660+- (void)localAssetsController:(U1LocalAssetsViewController *)localAssetsController didSelectNode:(U1Node *)aNode
4661+{
4662+ if ([aNode isFile])
4663+ {
4664+ U1FilePreviewViewController *fileController = [[U1FilePreviewViewController alloc] initWithNode:(id)node];
4665+ [self.navigationController pushViewController:fileController animated:YES];
4666+ [fileController release];
4667+ }
4668+}
4669+
4670+@end
4671
4672=== added file 'Files/U1LocalAssetsViewController.xib'
4673--- Files/U1LocalAssetsViewController.xib 1970-01-01 00:00:00 +0000
4674+++ Files/U1LocalAssetsViewController.xib 2011-11-01 14:25:30 +0000
4675@@ -0,0 +1,391 @@
4676+<?xml version="1.0" encoding="UTF-8"?>
4677+<archive type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="8.00">
4678+ <data>
4679+ <int key="IBDocument.SystemTarget">1280</int>
4680+ <string key="IBDocument.SystemVersion">10K549</string>
4681+ <string key="IBDocument.InterfaceBuilderVersion">1938</string>
4682+ <string key="IBDocument.AppKitVersion">1038.36</string>
4683+ <string key="IBDocument.HIToolboxVersion">461.00</string>
4684+ <object class="NSMutableDictionary" key="IBDocument.PluginVersions">
4685+ <string key="NS.key.0">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
4686+ <string key="NS.object.0">933</string>
4687+ </object>
4688+ <array key="IBDocument.IntegratedClassDependencies">
4689+ <string>IBProxyObject</string>
4690+ <string>IBUIProgressView</string>
4691+ <string>IBUILabel</string>
4692+ <string>IBUIImageView</string>
4693+ <string>IBUIActivityIndicatorView</string>
4694+ <string>IBUITableView</string>
4695+ <string>IBUITableViewCell</string>
4696+ <string>IBUIView</string>
4697+ </array>
4698+ <array key="IBDocument.PluginDependencies">
4699+ <string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
4700+ </array>
4701+ <object class="NSMutableDictionary" key="IBDocument.Metadata">
4702+ <string key="NS.key.0">PluginDependencyRecalculationVersion</string>
4703+ <integer value="1" key="NS.object.0"/>
4704+ </object>
4705+ <array class="NSMutableArray" key="IBDocument.RootObjects" id="1000">
4706+ <object class="IBProxyObject" id="372490531">
4707+ <string key="IBProxiedObjectIdentifier">IBFilesOwner</string>
4708+ <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
4709+ </object>
4710+ <object class="IBProxyObject" id="975951072">
4711+ <string key="IBProxiedObjectIdentifier">IBFirstResponder</string>
4712+ <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
4713+ </object>
4714+ <object class="IBUIView" id="824354941">
4715+ <reference key="NSNextResponder"/>
4716+ <int key="NSvFlags">292</int>
4717+ <array class="NSMutableArray" key="NSSubviews">
4718+ <object class="IBUIImageView" id="135648369">
4719+ <reference key="NSNextResponder" ref="824354941"/>
4720+ <int key="NSvFlags">292</int>
4721+ <string key="NSFrameSize">{320, 66}</string>
4722+ <reference key="NSSuperview" ref="824354941"/>
4723+ <reference key="NSWindow"/>
4724+ <reference key="NSNextKeyView" ref="129966493"/>
4725+ <bool key="IBUIUserInteractionEnabled">NO</bool>
4726+ <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
4727+ <object class="NSCustomResource" key="IBUIImage">
4728+ <string key="NSClassName">NSImage</string>
4729+ <string key="NSResourceName">progress_view_background.png</string>
4730+ </object>
4731+ </object>
4732+ <object class="IBUIProgressView" id="129966493">
4733+ <reference key="NSNextResponder" ref="824354941"/>
4734+ <int key="NSvFlags">292</int>
4735+ <string key="NSFrame">{{60, 20}, {200, 9}}</string>
4736+ <reference key="NSSuperview" ref="824354941"/>
4737+ <reference key="NSWindow"/>
4738+ <reference key="NSNextKeyView" ref="54616486"/>
4739+ <bool key="IBUIOpaque">NO</bool>
4740+ <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
4741+ <float key="IBUIProgress">0.5</float>
4742+ </object>
4743+ <object class="IBUILabel" id="54616486">
4744+ <reference key="NSNextResponder" ref="824354941"/>
4745+ <int key="NSvFlags">292</int>
4746+ <string key="NSFrame">{{60, 37}, {200, 16}}</string>
4747+ <reference key="NSSuperview" ref="824354941"/>
4748+ <reference key="NSWindow"/>
4749+ <bool key="IBUIOpaque">NO</bool>
4750+ <bool key="IBUIClipsSubviews">YES</bool>
4751+ <int key="IBUIContentMode">7</int>
4752+ <bool key="IBUIUserInteractionEnabled">NO</bool>
4753+ <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
4754+ <string key="IBUIText">Label</string>
4755+ <object class="NSColor" key="IBUITextColor" id="943202549">
4756+ <int key="NSColorSpace">1</int>
4757+ <bytes key="NSRGB">MCAwIDAAA</bytes>
4758+ </object>
4759+ <nil key="IBUIHighlightedColor"/>
4760+ <int key="IBUIBaselineAdjustment">1</int>
4761+ <float key="IBUIMinimumFontSize">10</float>
4762+ <int key="IBUITextAlignment">1</int>
4763+ <object class="IBUIFontDescription" key="IBUIFontDescription">
4764+ <int key="type">1</int>
4765+ <double key="pointSize">12</double>
4766+ </object>
4767+ <object class="NSFont" key="IBUIFont">
4768+ <string key="NSName">Helvetica</string>
4769+ <double key="NSSize">12</double>
4770+ <int key="NSfFlags">16</int>
4771+ </object>
4772+ </object>
4773+ </array>
4774+ <string key="NSFrameSize">{320, 66}</string>
4775+ <reference key="NSSuperview"/>
4776+ <reference key="NSWindow"/>
4777+ <reference key="NSNextKeyView" ref="135648369"/>
4778+ <object class="NSColor" key="IBUIBackgroundColor" id="590472223">
4779+ <int key="NSColorSpace">3</int>
4780+ <bytes key="NSWhite">MCAwAA</bytes>
4781+ </object>
4782+ <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
4783+ </object>
4784+ <object class="IBUITableView" id="95160719">
4785+ <reference key="NSNextResponder"/>
4786+ <int key="NSvFlags">274</int>
4787+ <string key="NSFrameSize">{320, 480}</string>
4788+ <reference key="NSSuperview"/>
4789+ <reference key="NSWindow"/>
4790+ <object class="NSColor" key="IBUIBackgroundColor">
4791+ <int key="NSColorSpace">3</int>
4792+ <bytes key="NSWhite">MQA</bytes>
4793+ </object>
4794+ <bool key="IBUIClipsSubviews">YES</bool>
4795+ <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
4796+ <bool key="IBUIAlwaysBounceVertical">YES</bool>
4797+ <int key="IBUISeparatorStyle">1</int>
4798+ <int key="IBUISectionIndexMinimumDisplayRowCount">0</int>
4799+ <bool key="IBUIShowsSelectionImmediatelyOnTouchBegin">YES</bool>
4800+ <float key="IBUIRowHeight">54</float>
4801+ <float key="IBUISectionHeaderHeight">22</float>
4802+ <float key="IBUISectionFooterHeight">22</float>
4803+ </object>
4804+ <object class="IBUITableViewCell" id="1003077660">
4805+ <reference key="NSNextResponder"/>
4806+ <int key="NSvFlags">292</int>
4807+ <array class="NSMutableArray" key="NSSubviews">
4808+ <object class="IBUIView" id="783165177">
4809+ <reference key="NSNextResponder" ref="1003077660"/>
4810+ <int key="NSvFlags">256</int>
4811+ <array class="NSMutableArray" key="NSSubviews">
4812+ <object class="IBUILabel" id="131881887">
4813+ <reference key="NSNextResponder" ref="783165177"/>
4814+ <int key="NSvFlags">292</int>
4815+ <string key="NSFrame">{{136, 17}, {75, 21}}</string>
4816+ <reference key="NSSuperview" ref="783165177"/>
4817+ <reference key="NSWindow"/>
4818+ <bool key="IBUIOpaque">NO</bool>
4819+ <bool key="IBUIClipsSubviews">YES</bool>
4820+ <int key="IBUIContentMode">7</int>
4821+ <bool key="IBUIUserInteractionEnabled">NO</bool>
4822+ <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
4823+ <string key="IBUIText">Loading...</string>
4824+ <reference key="IBUITextColor" ref="943202549"/>
4825+ <nil key="IBUIHighlightedColor"/>
4826+ <int key="IBUIBaselineAdjustment">1</int>
4827+ <float key="IBUIMinimumFontSize">10</float>
4828+ <object class="IBUIFontDescription" key="IBUIFontDescription">
4829+ <string key="name">Helvetica</string>
4830+ <string key="family">Helvetica</string>
4831+ <int key="traits">0</int>
4832+ <double key="pointSize">17</double>
4833+ </object>
4834+ <object class="NSFont" key="IBUIFont">
4835+ <string key="NSName">Helvetica</string>
4836+ <double key="NSSize">17</double>
4837+ <int key="NSfFlags">16</int>
4838+ </object>
4839+ </object>
4840+ <object class="IBUIActivityIndicatorView" id="1037320153">
4841+ <reference key="NSNextResponder" ref="783165177"/>
4842+ <int key="NSvFlags">292</int>
4843+ <string key="NSFrame">{{108, 18}, {20, 20}}</string>
4844+ <reference key="NSSuperview" ref="783165177"/>
4845+ <reference key="NSWindow"/>
4846+ <reference key="NSNextKeyView" ref="131881887"/>
4847+ <bool key="IBUIOpaque">NO</bool>
4848+ <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
4849+ <bool key="IBUIHidesWhenStopped">NO</bool>
4850+ <bool key="IBUIAnimating">YES</bool>
4851+ <int key="IBUIStyle">2</int>
4852+ </object>
4853+ </array>
4854+ <string key="NSFrameSize">{320, 53}</string>
4855+ <reference key="NSSuperview" ref="1003077660"/>
4856+ <reference key="NSWindow"/>
4857+ <reference key="NSNextKeyView" ref="1037320153"/>
4858+ <reference key="IBUIBackgroundColor" ref="590472223"/>
4859+ <bool key="IBUIOpaque">NO</bool>
4860+ <bool key="IBUIClipsSubviews">YES</bool>
4861+ <int key="IBUIContentMode">4</int>
4862+ <bool key="IBUIMultipleTouchEnabled">YES</bool>
4863+ <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
4864+ </object>
4865+ </array>
4866+ <string key="NSFrameSize">{320, 54}</string>
4867+ <reference key="NSSuperview"/>
4868+ <reference key="NSWindow"/>
4869+ <reference key="NSNextKeyView" ref="783165177"/>
4870+ <object class="NSColor" key="IBUIBackgroundColor">
4871+ <int key="NSColorSpace">1</int>
4872+ <bytes key="NSRGB">MSAxIDEAA</bytes>
4873+ </object>
4874+ <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
4875+ <reference key="IBUIContentView" ref="783165177"/>
4876+ </object>
4877+ </array>
4878+ <object class="IBObjectContainer" key="IBDocument.Objects">
4879+ <array class="NSMutableArray" key="connectionRecords">
4880+ <object class="IBConnectionRecord">
4881+ <object class="IBCocoaTouchOutletConnection" key="connection">
4882+ <string key="label">loadingCell</string>
4883+ <reference key="source" ref="372490531"/>
4884+ <reference key="destination" ref="1003077660"/>
4885+ </object>
4886+ <int key="connectionID">12</int>
4887+ </object>
4888+ <object class="IBConnectionRecord">
4889+ <object class="IBCocoaTouchOutletConnection" key="connection">
4890+ <string key="label">view</string>
4891+ <reference key="source" ref="372490531"/>
4892+ <reference key="destination" ref="95160719"/>
4893+ </object>
4894+ <int key="connectionID">13</int>
4895+ </object>
4896+ <object class="IBConnectionRecord">
4897+ <object class="IBCocoaTouchOutletConnection" key="connection">
4898+ <string key="label">progressLabel</string>
4899+ <reference key="source" ref="372490531"/>
4900+ <reference key="destination" ref="54616486"/>
4901+ </object>
4902+ <int key="connectionID">15</int>
4903+ </object>
4904+ <object class="IBConnectionRecord">
4905+ <object class="IBCocoaTouchOutletConnection" key="connection">
4906+ <string key="label">progressView</string>
4907+ <reference key="source" ref="372490531"/>
4908+ <reference key="destination" ref="824354941"/>
4909+ </object>
4910+ <int key="connectionID">17</int>
4911+ </object>
4912+ <object class="IBConnectionRecord">
4913+ <object class="IBCocoaTouchOutletConnection" key="connection">
4914+ <string key="label">progressBar</string>
4915+ <reference key="source" ref="372490531"/>
4916+ <reference key="destination" ref="129966493"/>
4917+ </object>
4918+ <int key="connectionID">18</int>
4919+ </object>
4920+ </array>
4921+ <object class="IBMutableOrderedSet" key="objectRecords">
4922+ <array key="orderedObjects">
4923+ <object class="IBObjectRecord">
4924+ <int key="objectID">0</int>
4925+ <array key="object" id="0"/>
4926+ <reference key="children" ref="1000"/>
4927+ <nil key="parent"/>
4928+ </object>
4929+ <object class="IBObjectRecord">
4930+ <int key="objectID">-1</int>
4931+ <reference key="object" ref="372490531"/>
4932+ <reference key="parent" ref="0"/>
4933+ <string key="objectName">File's Owner</string>
4934+ </object>
4935+ <object class="IBObjectRecord">
4936+ <int key="objectID">-2</int>
4937+ <reference key="object" ref="975951072"/>
4938+ <reference key="parent" ref="0"/>
4939+ </object>
4940+ <object class="IBObjectRecord">
4941+ <int key="objectID">4</int>
4942+ <reference key="object" ref="95160719"/>
4943+ <array class="NSMutableArray" key="children"/>
4944+ <reference key="parent" ref="0"/>
4945+ </object>
4946+ <object class="IBObjectRecord">
4947+ <int key="objectID">9</int>
4948+ <reference key="object" ref="1003077660"/>
4949+ <array class="NSMutableArray" key="children">
4950+ <reference ref="131881887"/>
4951+ <reference ref="1037320153"/>
4952+ </array>
4953+ <reference key="parent" ref="0"/>
4954+ </object>
4955+ <object class="IBObjectRecord">
4956+ <int key="objectID">10</int>
4957+ <reference key="object" ref="131881887"/>
4958+ <reference key="parent" ref="1003077660"/>
4959+ </object>
4960+ <object class="IBObjectRecord">
4961+ <int key="objectID">11</int>
4962+ <reference key="object" ref="1037320153"/>
4963+ <reference key="parent" ref="1003077660"/>
4964+ </object>
4965+ <object class="IBObjectRecord">
4966+ <int key="objectID">5</int>
4967+ <reference key="object" ref="824354941"/>
4968+ <array class="NSMutableArray" key="children">
4969+ <reference ref="54616486"/>
4970+ <reference ref="129966493"/>
4971+ <reference ref="135648369"/>
4972+ </array>
4973+ <reference key="parent" ref="0"/>
4974+ </object>
4975+ <object class="IBObjectRecord">
4976+ <int key="objectID">8</int>
4977+ <reference key="object" ref="54616486"/>
4978+ <reference key="parent" ref="824354941"/>
4979+ </object>
4980+ <object class="IBObjectRecord">
4981+ <int key="objectID">6</int>
4982+ <reference key="object" ref="129966493"/>
4983+ <reference key="parent" ref="824354941"/>
4984+ </object>
4985+ <object class="IBObjectRecord">
4986+ <int key="objectID">19</int>
4987+ <reference key="object" ref="135648369"/>
4988+ <reference key="parent" ref="824354941"/>
4989+ </object>
4990+ </array>
4991+ </object>
4992+ <dictionary class="NSMutableDictionary" key="flattenedProperties">
4993+ <string key="-1.CustomClassName">U1LocalAssetsViewController</string>
4994+ <string key="-1.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
4995+ <string key="-2.CustomClassName">UIResponder</string>
4996+ <string key="-2.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
4997+ <string key="10.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
4998+ <string key="11.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
4999+ <string key="19.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
5000+ <string key="4.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches