Merge lp:~threeve/ubuntuone-ios-files/background-processing into lp:ubuntuone-ios-files
- background-processing
- Merge into trunk
Proposed by
Jason Foreman
Status: | Merged |
---|---|
Merged at revision: | 37 |
Proposed branch: | lp:~threeve/ubuntuone-ios-files/background-processing |
Merge into: | lp:ubuntuone-ios-files |
Diff against target: |
1483 lines (+478/-287) 23 files modified
Files.xcodeproj/project.pbxproj (+11/-11) Files/Files-Prefix.pch (+4/-2) Files/U1AssetRepresenationDataProvider.h (+4/-3) Files/U1AssetRepresenationDataProvider.m (+47/-8) Files/U1AutoUploadOperation.h (+8/-3) Files/U1AutoUploadOperation.m (+21/-11) Files/U1AutoUploadsManager.h (+1/-1) Files/U1AutoUploadsManager.m (+195/-144) Files/U1DataRepository.h (+4/-2) Files/U1DataRepository.m (+27/-10) Files/U1FilesClient.h (+1/-3) Files/U1FilesClient.m (+32/-17) Files/U1FilesService.h (+6/-1) Files/U1FilesService.m (+43/-32) Files/U1FolderItemCell.m (+16/-1) Files/U1FolderItemCell.xib (+3/-1) Files/U1FolderViewController.m (+4/-3) Files/U1ReportingInputStream.h (+3/-2) Files/U1ReportingInputStream.m (+6/-8) Files/U1UploadOperation.m (+21/-4) Files/U1UploadsPoolViewController.m (+1/-1) Files/U1Volume.m (+1/-1) Files/iPhone/en.lproj/MainWindow_iPhone.xib (+19/-18) |
To merge this branch: | bzr merge lp:~threeve/ubuntuone-ios-files/background-processing |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Zachery Bir | Approve | ||
Review via email: mp+85186@code.launchpad.net |
Commit message
Description of the change
Do node loading and parsing in the background to avoid UI blocking.
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'Files.xcodeproj/project.pbxproj' |
2 | --- Files.xcodeproj/project.pbxproj 2011-12-07 14:26:35 +0000 |
3 | +++ Files.xcodeproj/project.pbxproj 2011-12-09 20:00:29 +0000 |
4 | @@ -640,6 +640,13 @@ |
5 | 96CC17E414180C5F00EFC1BA /* U1FilesClient.m */, |
6 | 91B3F2D7141FC9BE00939B3C /* U1AutoUploadsManager.h */, |
7 | 91A5E2DB142A70DF00EAAC2B /* U1AutoUploadsManager.m */, |
8 | + 910393E61475B118004DE69D /* U1AutoUploadOperation.h */, |
9 | + 910393E71475B118004DE69D /* U1AutoUploadOperation.m */, |
10 | + 91A007E8147559F200D0E5FF /* U1AssetRepresenationDataProvider.h */, |
11 | + 91A007E9147559F200D0E5FF /* U1AssetRepresenationDataProvider.m */, |
12 | + 916E0080143C9A390037F6D3 /* U1UploadsPoolViewController.h */, |
13 | + 916E0081143C9A390037F6D3 /* U1UploadsPoolViewController.m */, |
14 | + 9190AAF31444CA0A0063614A /* U1UploadsPoolViewController.xib */, |
15 | 969EF22613F8C10C00CEF6CB /* U1VolumesViewController.h */, |
16 | 969EF22713F8C10C00CEF6CB /* U1VolumesViewController.m */, |
17 | 969EF22813F8C10C00CEF6CB /* U1VolumesViewController.xib */, |
18 | @@ -654,20 +661,13 @@ |
19 | 960D4627140D8B4400B73177 /* U1FriendlyDateValueTransformer.m */, |
20 | 91A5E2DD142B727500EAAC2B /* U1UploadOperation.h */, |
21 | 91A5E2DE142B727500EAAC2B /* U1UploadOperation.m */, |
22 | - 910393E61475B118004DE69D /* U1AutoUploadOperation.h */, |
23 | - 910393E71475B118004DE69D /* U1AutoUploadOperation.m */, |
24 | 965D7EB71429690C00E4754F /* U1NavigationBar.h */, |
25 | 965D7EB81429690C00E4754F /* U1NavigationBar.m */, |
26 | 96A169A21430D53600E4C990 /* U1LocalFileInfo.h */, |
27 | 96A169A31430D53600E4C990 /* U1LocalFileInfo.m */, |
28 | - 916E0080143C9A390037F6D3 /* U1UploadsPoolViewController.h */, |
29 | - 916E0081143C9A390037F6D3 /* U1UploadsPoolViewController.m */, |
30 | - 9190AAF31444CA0A0063614A /* U1UploadsPoolViewController.xib */, |
31 | 91EC184B145B8E3A00DF31F4 /* U1SettingsViewController.h */, |
32 | 91EC184C145B8E3A00DF31F4 /* U1SettingsViewController.m */, |
33 | 91EC184D145B8E3B00DF31F4 /* U1SettingsViewController.xib */, |
34 | - 91A007E8147559F200D0E5FF /* U1AssetRepresenationDataProvider.h */, |
35 | - 91A007E9147559F200D0E5FF /* U1AssetRepresenationDataProvider.m */, |
36 | 9623AE6014868F7000ACDF1C /* U1ReportingInputStream.h */, |
37 | 9623AE6114868F7000ACDF1C /* U1ReportingInputStream.m */, |
38 | 9172C86E148FA4F600FC7737 /* U1TopPinningLabel.h */, |
39 | @@ -1198,8 +1198,8 @@ |
40 | armv6, |
41 | armv7, |
42 | ); |
43 | - CODE_SIGN_IDENTITY = "iPhone Distribution: Canonical Group Limited"; |
44 | - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution: Canonical Group Limited"; |
45 | + CODE_SIGN_IDENTITY = "iPhone Distribution"; |
46 | + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; |
47 | FRAMEWORK_SEARCH_PATHS = ( |
48 | "$(inherited)", |
49 | "\"$(SRCROOT)\"", |
50 | @@ -1214,8 +1214,8 @@ |
51 | "\"$(SRCROOT)/Dependencies/TestFlightSDK\"", |
52 | ); |
53 | PRODUCT_NAME = "$(TARGET_NAME)"; |
54 | - PROVISIONING_PROFILE = "AC4373DF-1FF8-4EA3-A098-888460CA563B"; |
55 | - "PROVISIONING_PROFILE[sdk=iphoneos*]" = "AC4373DF-1FF8-4EA3-A098-888460CA563B"; |
56 | + PROVISIONING_PROFILE = ""; |
57 | + "PROVISIONING_PROFILE[sdk=iphoneos*]" = ""; |
58 | TARGETED_DEVICE_FAMILY = 1; |
59 | VALID_ARCHS = "arm6 armv7"; |
60 | WRAPPER_EXTENSION = app; |
61 | |
62 | === modified file 'Files/Files-Prefix.pch' |
63 | --- Files/Files-Prefix.pch 2011-10-26 03:39:52 +0000 |
64 | +++ Files/Files-Prefix.pch 2011-12-09 20:00:29 +0000 |
65 | @@ -15,14 +15,16 @@ |
66 | |
67 | #import <Availability.h> |
68 | |
69 | -#ifndef __IPHONE_3_0 |
70 | -#warning "This project uses features only available in iPhone SDK 3.0 and later." |
71 | +#ifndef __IPHONE_4_0 |
72 | +#warning "This project uses features only available in iPhone SDK 4.0 and later." |
73 | #endif |
74 | |
75 | #ifdef __OBJC__ |
76 | |
77 | #import <UIKit/UIKit.h> |
78 | #import <Foundation/Foundation.h> |
79 | +#import <CoreData/CoreData.h> |
80 | + |
81 | #import "TestFlight.h" |
82 | #import "NSDictionary+U1Additions.h" |
83 | |
84 | |
85 | === modified file 'Files/U1AssetRepresenationDataProvider.h' |
86 | --- Files/U1AssetRepresenationDataProvider.h 2011-11-18 16:27:59 +0000 |
87 | +++ Files/U1AssetRepresenationDataProvider.h 2011-12-09 20:00:29 +0000 |
88 | @@ -14,9 +14,10 @@ |
89 | // along with this program. If not, see <http://www.gnu.org/licenses/>. |
90 | |
91 | #import <Foundation/Foundation.h> |
92 | -#import <AssetsLibrary/AssetsLibrary.h> |
93 | -#import "U1FilesClient.h" |
94 | + |
95 | +#import "U1FilesService.h" |
96 | + |
97 | |
98 | @interface U1AssetRepresenationDataProvider : NSObject <U1UploadDataProvider> |
99 | -@property (retain) ALAssetRepresentation *representation; |
100 | +@property (retain) NSURL *assetURL; |
101 | @end |
102 | |
103 | === modified file 'Files/U1AssetRepresenationDataProvider.m' |
104 | --- Files/U1AssetRepresenationDataProvider.m 2011-11-18 16:27:59 +0000 |
105 | +++ Files/U1AssetRepresenationDataProvider.m 2011-12-09 20:00:29 +0000 |
106 | @@ -15,22 +15,61 @@ |
107 | |
108 | #import "U1AssetRepresenationDataProvider.h" |
109 | |
110 | +#import <AssetsLibrary/AssetsLibrary.h> |
111 | +#import <MobileCoreServices/MobileCoreServices.h> |
112 | + |
113 | + |
114 | @implementation U1AssetRepresenationDataProvider |
115 | - |
116 | -@synthesize representation; |
117 | +{ |
118 | + ALAssetsLibrary *library; |
119 | +} |
120 | + |
121 | +@synthesize assetURL; |
122 | + |
123 | +- (id)init; |
124 | +{ |
125 | + self = [super init]; |
126 | + if (self == nil) |
127 | + return nil; |
128 | + library = [[ALAssetsLibrary alloc] init]; |
129 | + return self; |
130 | +} |
131 | |
132 | - (void)dealloc; |
133 | { |
134 | - [representation release]; |
135 | + [assetURL release]; |
136 | + [library release]; |
137 | [super dealloc]; |
138 | } |
139 | |
140 | -- (NSData *)serializeData; |
141 | +- (void)prepareDataStreamWithBlock:(void(^)(NSInputStream *dataStream, NSString *mimeType, NSUInteger length, NSError *error))block; |
142 | { |
143 | - Byte *buffer = (Byte*)malloc(self.representation.size); |
144 | - NSUInteger length = [self.representation getBytes:buffer fromOffset:0 length:self.representation.size error:nil]; |
145 | - NSData *assetData = [NSData dataWithBytesNoCopy:buffer length:length freeWhenDone:YES]; |
146 | - return assetData; |
147 | + [library assetForURL:self.assetURL resultBlock:^(ALAsset *asset) { |
148 | + |
149 | + if (asset == nil) |
150 | + { |
151 | + if (block) |
152 | + { |
153 | + NSError *error = [NSError errorWithDomain:@"nonexistentAsset" code:1 userInfo:nil]; |
154 | + block(nil, nil, nil, error); |
155 | + } |
156 | + } |
157 | + else |
158 | + { |
159 | + ALAssetRepresentation *representation = [asset defaultRepresentation]; |
160 | + uint8_t *buffer = (uint8_t*)malloc(representation.size); |
161 | + NSUInteger length = [representation getBytes:buffer fromOffset:0 length:representation.size error:nil]; |
162 | + NSData *imageData = [NSData dataWithBytesNoCopy:buffer length:length freeWhenDone:YES]; |
163 | + NSString *mimeType = (id)UTTypeCopyPreferredTagWithClass((CFStringRef)[representation UTI], kUTTagClassMIMEType); |
164 | + NSInputStream *dataStream = [NSInputStream inputStreamWithData:imageData]; |
165 | + if (block) |
166 | + block(dataStream, mimeType, length, nil); |
167 | + } |
168 | + |
169 | + } failureBlock:^(NSError *error) { |
170 | + if (block) |
171 | + block(nil, nil, 0, error); |
172 | + }]; |
173 | } |
174 | |
175 | @end |
176 | |
177 | === modified file 'Files/U1AutoUploadOperation.h' |
178 | --- Files/U1AutoUploadOperation.h 2011-11-18 16:28:43 +0000 |
179 | +++ Files/U1AutoUploadOperation.h 2011-12-09 20:00:29 +0000 |
180 | @@ -14,17 +14,22 @@ |
181 | // along with this program. If not, see <http://www.gnu.org/licenses/>. |
182 | |
183 | #import <Foundation/Foundation.h> |
184 | -#import "U1FilesClient.h" |
185 | +#import <CoreData/CoreData.h> |
186 | |
187 | +@protocol U1UploadDataProvider; |
188 | @class U1Asset; |
189 | @class U1FolderNode; |
190 | |
191 | + |
192 | @interface U1AutoUploadOperation : NSOperation |
193 | |
194 | @property (retain) id<U1UploadDataProvider> dataProvider; |
195 | -@property (retain) U1Asset *u1asset; |
196 | -@property (retain) U1FolderNode *folder; |
197 | + |
198 | +@property (retain) NSManagedObjectID *assetID; |
199 | +@property (retain) NSManagedObjectID *folderID; |
200 | + |
201 | @property (retain) NSString *filename; |
202 | @property (retain) NSString *contentType; |
203 | @property (atomic) NSOperationQueuePriority priority; |
204 | + |
205 | @end |
206 | |
207 | === modified file 'Files/U1AutoUploadOperation.m' |
208 | --- Files/U1AutoUploadOperation.m 2011-12-06 20:53:05 +0000 |
209 | +++ Files/U1AutoUploadOperation.m 2011-12-09 20:00:29 +0000 |
210 | @@ -13,11 +13,14 @@ |
211 | // You should have received a copy of the GNU Affero General Public License |
212 | // along with this program. If not, see <http://www.gnu.org/licenses/>. |
213 | |
214 | +#import "U1AutoUploadOperation.h" |
215 | + |
216 | #import "U1Asset.h" |
217 | -#import "U1AutoUploadOperation.h" |
218 | #import "U1DataRepository.h" |
219 | #import "U1FileNode.h" |
220 | #import "U1FilesClient.h" |
221 | +#import "U1FilesService.h" |
222 | + |
223 | |
224 | @interface U1AutoUploadOperation () |
225 | @property (getter=isExecuting) BOOL executing; |
226 | @@ -26,9 +29,10 @@ |
227 | - (void)beginUpload; |
228 | @end |
229 | |
230 | + |
231 | @implementation U1AutoUploadOperation |
232 | |
233 | -@synthesize executing, finished, dataProvider, u1asset, folder, filename, contentType, priority; |
234 | +@synthesize executing, finished, dataProvider, assetID, folderID, filename, contentType, priority; |
235 | |
236 | - (BOOL)isConcurrent; |
237 | { |
238 | @@ -64,32 +68,38 @@ |
239 | - (void)dealloc |
240 | { |
241 | [dataProvider release]; |
242 | - [u1asset release]; |
243 | - [folder release]; |
244 | [filename release]; |
245 | [contentType release]; |
246 | + [assetID release]; |
247 | + [folderID release]; |
248 | [super dealloc]; |
249 | } |
250 | |
251 | - (void)beginUpload; |
252 | { |
253 | - dispatch_async(dispatch_get_main_queue(), ^(void) { |
254 | - [[U1FilesClient sharedFilesClient] uploadContentDataProvider:dataProvider toFolder:self.folder withResourceName:self.filename withContentType:self.contentType withPriority:self.priority progressBlock:^(long long bytesUploaded, long long totalBytes) { |
255 | - |
256 | + U1DataRepository *dataRepository = [U1DataRepository sharedDataRepository]; |
257 | + [dataRepository dispatchBlockWithMainContext:^(NSManagedObjectContext *context) { |
258 | + |
259 | + U1Asset *asset = (id)[context objectWithID:self.assetID]; |
260 | + U1FolderNode *folder = (id)[context objectWithID:self.folderID]; |
261 | + |
262 | + [[U1FilesClient sharedFilesClient] uploadContentDataProvider:dataProvider toFolder:folder withResourceName:self.filename withContentType:self.contentType withPriority:self.priority progressBlock:^(long long bytesUploaded, long long totalBytes) { |
263 | + |
264 | } completionBlock:^(U1FileNode *fileNode, NSError *error) { |
265 | if (error) |
266 | { |
267 | NSLog(@"auto-upload failed: %@", error); |
268 | } |
269 | - |
270 | + |
271 | dispatch_async(dispatch_get_main_queue(), ^(void) { |
272 | |
273 | - self.u1asset.generation = self.u1asset.fileNode.generation; |
274 | - [[U1DataRepository sharedDataRepository] save:NULL]; |
275 | + asset.generation = asset.fileNode.generation; |
276 | + [dataRepository save:NULL]; |
277 | [self finishExecuting]; |
278 | }); |
279 | }]; |
280 | - }); |
281 | + |
282 | + }]; |
283 | } |
284 | |
285 | @end |
286 | |
287 | === modified file 'Files/U1AutoUploadsManager.h' |
288 | --- Files/U1AutoUploadsManager.h 2011-12-06 18:03:30 +0000 |
289 | +++ Files/U1AutoUploadsManager.h 2011-12-09 20:00:29 +0000 |
290 | @@ -29,8 +29,8 @@ |
291 | + (U1AutoUploadsManager *)sharedAutoUploadsManager; |
292 | - (int)numberOfAssets; |
293 | - (void)checkForNewAssets; |
294 | -- (U1Asset *)createU1AssetWithAsset:(ALAsset *)asset group:(ALAssetsGroup *)group URLString:(NSString *)urlString fileName:(NSString *)filename inFolder:(U1FolderNode *)folderNode; |
295 | - (void)thumbnailForNode:(U1FileNode *)fileNode completionBlock:(void(^)(CGImageRef thumbnail))completionBlock; |
296 | - (NSOperation*)queueAutoUploadForAsset:(U1Asset *)assetToUpload andRepresentation:(ALAssetRepresentation *)representation; |
297 | - (int)pendingCount; |
298 | +- (U1Asset *)createU1AssetWithAsset:(ALAsset *)asset group:(ALAssetsGroup *)group URLString:(NSString *)urlString fileName:(NSString *)filename inFolder:(U1FolderNode *)folderNode context:(NSManagedObjectContext*)context; |
299 | @end |
300 | |
301 | === modified file 'Files/U1AutoUploadsManager.m' |
302 | --- Files/U1AutoUploadsManager.m 2011-12-07 20:42:55 +0000 |
303 | +++ Files/U1AutoUploadsManager.m 2011-12-09 20:00:29 +0000 |
304 | @@ -29,9 +29,11 @@ |
305 | #import "U1FolderNode.h" |
306 | #import "U1Volume.h" |
307 | |
308 | + |
309 | @interface U1AutoUploadsManager () |
310 | @property (retain) U1FilesClient *filesClient; |
311 | @property (retain) NSOperationQueue *autoUploadPreparationQueue; |
312 | +@property (retain) NSManagedObjectID *autoUploadsFolderID; |
313 | - (void)walkAssetsInLibrary; |
314 | - (NSString *)generateFilenameForAsset:(ALAsset *)asset; |
315 | - (void)processAssetBatch:(NSArray*)batch inGroup:(ALAssetsGroup *)group toArray:(NSMutableArray*)ops; |
316 | @@ -43,16 +45,16 @@ |
317 | - (void)volumesFetched:(NSNotification *)notification; |
318 | @end |
319 | |
320 | -static U1AutoUploadsManager *sharedAutoUploadsManager = nil; |
321 | |
322 | @implementation U1AutoUploadsManager |
323 | |
324 | @synthesize filesClient, dataRepository, assetsLibrary; |
325 | -@synthesize autoUploadPreparationQueue; |
326 | +@synthesize autoUploadPreparationQueue, autoUploadsFolderID; |
327 | @synthesize remoteUploadFolder; |
328 | |
329 | + (U1AutoUploadsManager *)sharedAutoUploadsManager; |
330 | { |
331 | + static U1AutoUploadsManager *sharedAutoUploadsManager = nil; |
332 | if (sharedAutoUploadsManager == nil) |
333 | { |
334 | sharedAutoUploadsManager = [[U1AutoUploadsManager alloc] init]; |
335 | @@ -86,6 +88,7 @@ |
336 | [assetsLibrary release]; |
337 | [autoUploadPreparationQueue release]; |
338 | [remoteUploadFolder release]; |
339 | + [autoUploadsFolderID release]; |
340 | [super dealloc]; |
341 | } |
342 | |
343 | @@ -169,6 +172,7 @@ |
344 | if (error == nil) |
345 | { |
346 | self.remoteUploadFolder = volume.rootFolder; |
347 | + self.autoUploadsFolderID = [volume.rootFolder objectID]; |
348 | [self fetchRemoteUploadFolderContents]; |
349 | } |
350 | else |
351 | @@ -180,6 +184,7 @@ |
352 | else |
353 | { |
354 | self.remoteUploadFolder = volume.rootFolder; |
355 | + self.autoUploadsFolderID = [volume.rootFolder objectID]; |
356 | [self fetchRemoteUploadFolderContents]; |
357 | } |
358 | } |
359 | @@ -200,6 +205,7 @@ |
360 | if (resultsDataSourceType == U1DataSourceRemote) |
361 | { |
362 | [childrenResultsController performFetch:NULL]; |
363 | + // TODO: this |
364 | [self queuePreviousUploads]; |
365 | [self checkForNewAssets]; |
366 | } |
367 | @@ -218,49 +224,56 @@ |
368 | |
369 | NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; |
370 | |
371 | - if ([defaults boolForKey:@"auto_upload"]) { |
372 | - [self.assetsLibrary enumerateGroupsWithTypes:ALAssetsGroupSavedPhotos |
373 | - usingBlock:^(ALAssetsGroup *group, BOOL *stop) { |
374 | - NSMutableArray *ops = [NSMutableArray array]; |
375 | - __block NSMutableArray *batch = [[NSMutableArray alloc] initWithCapacity:50]; |
376 | - [group enumerateAssetsUsingBlock:^(ALAsset *asset, NSUInteger index, BOOL *stop) { |
377 | - if (asset == nil) |
378 | - { |
379 | - return; |
380 | - } |
381 | - |
382 | - [batch addObject:asset]; |
383 | + if ([defaults boolForKey:@"auto_upload"]) |
384 | + { |
385 | + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ |
386 | |
387 | - if ([batch count] >= 50) |
388 | - { |
389 | - NSSortDescriptor *sortBy = [NSSortDescriptor sortDescriptorWithKey:@"defaultRepresentation.url.absoluteString" ascending:YES]; |
390 | - [batch sortUsingDescriptors:[NSArray arrayWithObject:sortBy]]; |
391 | - [self processAssetBatch:batch inGroup:group toArray:ops]; |
392 | - [batch release]; |
393 | - batch = [[NSMutableArray alloc] initWithCapacity:50]; |
394 | - } |
395 | - }]; |
396 | - if ([batch count] > 0) // Deal with last partial batch |
397 | - { |
398 | - NSSortDescriptor *sortBy = [NSSortDescriptor sortDescriptorWithKey:@"defaultRepresentation.url.absoluteString" ascending:YES]; |
399 | - [batch sortUsingDescriptors:[NSArray arrayWithObject:sortBy]]; |
400 | - [self processAssetBatch:batch inGroup:group toArray:ops]; |
401 | - } |
402 | - [batch release]; |
403 | - batch = nil; |
404 | - NSArray *sortedOps = [ops sortedArrayUsingDescriptors:[NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"filename" ascending:YES]]]; |
405 | - [sortedOps enumerateObjectsUsingBlock:^(U1AutoUploadOperation *operation, NSUInteger idx, BOOL *stop) { |
406 | - [self.autoUploadPreparationQueue addOperation:operation]; |
407 | - [[NSNotificationCenter defaultCenter] postNotificationName:@"uploadQueued" object:nil]; |
408 | - }]; |
409 | - [ops removeAllObjects]; |
410 | - alreadyWalking = NO; |
411 | - } |
412 | - failureBlock:^(NSError *error) { |
413 | - NSLog(@"Some error happened: %@", error); |
414 | - }]; |
415 | + [self.assetsLibrary enumerateGroupsWithTypes:ALAssetsGroupSavedPhotos usingBlock:^(ALAssetsGroup *group, BOOL *stop) { |
416 | + |
417 | + NSMutableArray *ops = [NSMutableArray array]; |
418 | + __block NSMutableArray *batch = [[NSMutableArray alloc] initWithCapacity:50]; |
419 | + [group enumerateAssetsUsingBlock:^(ALAsset *asset, NSUInteger index, BOOL *stop) { |
420 | + |
421 | + if (asset == nil) |
422 | + { |
423 | + return; |
424 | + } |
425 | + |
426 | + [batch addObject:asset]; |
427 | + |
428 | + if ([batch count] >= 50) |
429 | + { |
430 | + NSSortDescriptor *sortBy = [NSSortDescriptor sortDescriptorWithKey:@"defaultRepresentation.url.absoluteString" ascending:YES]; |
431 | + [batch sortUsingDescriptors:[NSArray arrayWithObject:sortBy]]; |
432 | + [self processAssetBatch:batch inGroup:group toArray:ops]; |
433 | + [batch release]; |
434 | + batch = [[NSMutableArray alloc] initWithCapacity:50]; |
435 | + } |
436 | + }]; |
437 | + if ([batch count] > 0) // Deal with last partial batch |
438 | + { |
439 | + NSSortDescriptor *sortBy = [NSSortDescriptor sortDescriptorWithKey:@"defaultRepresentation.url.absoluteString" ascending:YES]; |
440 | + [batch sortUsingDescriptors:[NSArray arrayWithObject:sortBy]]; |
441 | + [self processAssetBatch:batch inGroup:group toArray:ops]; |
442 | + } |
443 | + [batch release]; |
444 | + batch = nil; |
445 | + |
446 | + NSArray *sortedOps = [ops sortedArrayUsingDescriptors:[NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"filename" ascending:YES]]]; |
447 | + [sortedOps enumerateObjectsUsingBlock:^(U1AutoUploadOperation *operation, NSUInteger idx, BOOL *stop) { |
448 | + [self.autoUploadPreparationQueue addOperation:operation]; |
449 | + [[NSNotificationCenter defaultCenter] postNotificationName:@"uploadQueued" object:nil]; |
450 | + }]; |
451 | + [ops removeAllObjects]; |
452 | + alreadyWalking = NO; |
453 | + } failureBlock:^(NSError *error) { |
454 | + NSLog(@"Some error happened: %@", error); |
455 | + }]; |
456 | + |
457 | + }); |
458 | |
459 | } |
460 | + |
461 | } |
462 | |
463 | - (void)processAssetBatch:(NSArray*)batch inGroup:(ALAssetsGroup *)group toArray:(NSMutableArray*)ops; |
464 | @@ -270,16 +283,19 @@ |
465 | // instead of dealing with a single asset, loop over our batch |
466 | NSMutableArray *URLs = [batch valueForKeyPath:@"defaultRepresentation.url.absoluteString"]; |
467 | |
468 | - |
469 | [self.dataRepository dispatchBlockWithManagedObjectContext:^(NSManagedObjectContext *context) { |
470 | - NSPredicate *p = [NSPredicate predicateWithFormat:@"url in %@ and (fileNode.parent = %@ OR fileNode = nil)", URLs, self.remoteUploadFolder]; |
471 | + |
472 | + U1FolderNode *autoUploadsFolder = (id)[context objectWithID:self.autoUploadsFolderID]; |
473 | + NSMutableSet *assetsToUpload = [NSMutableSet set]; |
474 | + |
475 | + NSPredicate *p = [NSPredicate predicateWithFormat:@"url in %@ and (fileNode.parent = %@ OR fileNode = nil)", URLs, autoUploadsFolder]; |
476 | NSError *error = nil; |
477 | NSSortDescriptor *sortBy = [NSSortDescriptor sortDescriptorWithKey:@"url" ascending:YES]; |
478 | - NSArray *existingU1Assets = [[self.dataRepository resultsForEntityClass:[U1Asset class] |
479 | - matchingPredicate:p |
480 | - withSortDescriptors:[NSArray arrayWithObject:sortBy] |
481 | - error:&error] retain]; |
482 | - |
483 | + NSArray *existingU1Assets = [self.dataRepository resultsForEntityClass:[U1Asset class] |
484 | + inContext:context |
485 | + withPredicate:p |
486 | + sortDescriptors:[NSArray arrayWithObject:sortBy] |
487 | + error:&error]; |
488 | |
489 | // If batch's asset isn't in existingU1Assets or existingU1Asset's generation is nil, we upload it. |
490 | |
491 | @@ -320,22 +336,25 @@ |
492 | |
493 | if (canUpload) { |
494 | shouldUpload = YES; |
495 | - assetToUpload = [self createU1AssetWithAsset:asset group:group URLString:url fileName:nil inFolder:self.remoteUploadFolder]; |
496 | + assetToUpload = [self createU1AssetWithAsset:asset group:group URLString:url fileName:nil inFolder:autoUploadsFolder context:context]; |
497 | } |
498 | } |
499 | - // Check shouldUpload flag |
500 | if (shouldUpload) |
501 | { |
502 | - NSOperation *op = [self queueAutoUploadForAsset:assetToUpload andRepresentation:[asset defaultRepresentation]]; |
503 | - if (op) |
504 | - [ops addObject:op]; |
505 | - |
506 | - } |
507 | - }]; |
508 | - |
509 | - [self.dataRepository save:NULL]; |
510 | - |
511 | - |
512 | + [assetsToUpload addObject:assetToUpload]; |
513 | + } |
514 | + }]; |
515 | + |
516 | + [context save:NULL]; |
517 | + |
518 | + [assetsToUpload enumerateObjectsUsingBlock:^(U1Asset *u1asset, BOOL *stop) { |
519 | + |
520 | + NSOperation *op = [self queueAutoUploadForAsset:u1asset andRepresentation:nil]; |
521 | + if (op) |
522 | + { |
523 | + [ops addObject:op]; |
524 | + } |
525 | + }]; |
526 | }]; |
527 | |
528 | |
529 | @@ -344,54 +363,91 @@ |
530 | - (void)queuePreviousUploads; |
531 | { |
532 | // We should poll our data repository for all U1Assets which have generation=nil. They *should* all have U1FileNodes associated with them. If the U1FileNode's parent equals our autoUploadsManager's remoteUploadFolder, then it's an auto-upload, and we let the LAM handle it. Otherwise, kick it off immediately to the FilesClient and get it back in the queue. |
533 | - NSPredicate *p = [NSPredicate predicateWithFormat:@"generation = %@", nil]; |
534 | - NSError *error = nil; |
535 | - NSSortDescriptor *sortBy = [NSSortDescriptor sortDescriptorWithKey:@"filename" ascending:YES]; |
536 | - NSArray *previouslyQueuedU1Assets = [self.dataRepository resultsForEntityClass:[U1Asset class] |
537 | - matchingPredicate:p |
538 | - withSortDescriptors:[NSArray arrayWithObject:sortBy] |
539 | - error:&error]; |
540 | - [previouslyQueuedU1Assets enumerateObjectsUsingBlock:^(U1Asset *u1asset, NSUInteger idx, BOOL *stop) { |
541 | - if (u1asset.fileNode.parent == self.remoteUploadFolder) |
542 | - { |
543 | - [self.assetsLibrary assetForURL:[NSURL URLWithString:u1asset.url] |
544 | - resultBlock:^(ALAsset *asset) { |
545 | + NSPredicate *p = [NSPredicate predicateWithFormat:@"generation = %@", nil]; |
546 | + NSError *error = nil; |
547 | + NSSortDescriptor *sortBy = [NSSortDescriptor sortDescriptorWithKey:@"filename" ascending:YES]; |
548 | + NSArray *previouslyQueuedU1Assets = [self.dataRepository resultsForEntityClass:[U1Asset class] |
549 | + matchingPredicate:p |
550 | + withSortDescriptors:[NSArray arrayWithObject:sortBy] |
551 | + error:&error]; |
552 | + __block NSMutableArray *assetsDeletedFromLibrary = [NSMutableArray array]; |
553 | + |
554 | + [previouslyQueuedU1Assets enumerateObjectsUsingBlock:^(U1Asset *u1asset, NSUInteger idx, BOOL *stop) { |
555 | + if (u1asset.fileNode.parent == self.remoteUploadFolder) |
556 | + { |
557 | + [self.assetsLibrary assetForURL:[NSURL URLWithString:u1asset.url] |
558 | + resultBlock:^(ALAsset *asset) { |
559 | + if (asset == nil) |
560 | + { |
561 | + NSLog(@"In the results block, but asset is nil!"); |
562 | + [assetsDeletedFromLibrary addObject:u1asset]; |
563 | + } |
564 | + else |
565 | + { |
566 | ALAssetRepresentation *rep = [asset defaultRepresentation]; |
567 | // Belongs to LAM, could punt and let it get picked up by checkForNewAssets |
568 | NSOperation *op = [self queueAutoUploadForAsset:u1asset andRepresentation:rep]; |
569 | if (op) |
570 | + { |
571 | [self.autoUploadPreparationQueue addOperation:op]; |
572 | - } failureBlock:^(NSError *error) { |
573 | - NSLog(@"Error: %@", error); |
574 | - // TODO: delete asset |
575 | - }]; |
576 | - } |
577 | - else |
578 | + } |
579 | + } |
580 | + } failureBlock:^(NSError *error) { |
581 | + NSLog(@"Error: %@", error); |
582 | + [assetsDeletedFromLibrary addObject:u1asset]; |
583 | + }]; |
584 | + } |
585 | + else |
586 | + { |
587 | + NSURL *imageURL = [NSURL URLWithString:u1asset.url]; |
588 | + |
589 | + [self.assetsLibrary assetForURL:imageURL |
590 | + resultBlock:^(ALAsset *asset) { |
591 | + if (asset == nil) |
592 | + { |
593 | + NSLog(@"In the results block, but asset is nil!"); |
594 | + [assetsDeletedFromLibrary addObject:u1asset]; |
595 | + } |
596 | + else |
597 | + { |
598 | + ALAssetRepresentation *representation = [asset defaultRepresentation]; |
599 | + NSString *mimetype = (id)UTTypeCopyPreferredTagWithClass((CFStringRef)[representation UTI], kUTTagClassMIMEType); |
600 | + |
601 | + U1AssetRepresenationDataProvider *provider = [[U1AssetRepresenationDataProvider alloc] init]; |
602 | + provider.assetURL = imageURL; |
603 | + |
604 | + [self.filesClient uploadContentDataProvider:provider |
605 | + toFolder:u1asset.fileNode.parent |
606 | + withResourceName:u1asset.filename |
607 | + withContentType:mimetype |
608 | + withPriority:NSOperationQueuePriorityVeryHigh |
609 | + progressBlock:^(long long bytesUploaded, long long totalBytes) {} |
610 | + completionBlock:^(U1FileNode *updatedNode, NSError *error) { |
611 | + u1asset.generation = updatedNode.generation; |
612 | + }]; |
613 | + } |
614 | + } failureBlock:^(NSError *error) { |
615 | + NSLog(@"Error: %@", error); |
616 | + [assetsDeletedFromLibrary addObject:u1asset]; |
617 | + }]; |
618 | + } |
619 | + }]; |
620 | + |
621 | + // Iterate over the assetsDeletedFromLibrary, and clean them up. |
622 | + [self.dataRepository dispatchAsyncBlockWithManagedObjectContext:^(NSManagedObjectContext *context) { |
623 | + for (int i = 0; i < [assetsDeletedFromLibrary count]; i++) |
624 | + { |
625 | + U1Asset *assetToBeDeleted = [assetsDeletedFromLibrary objectAtIndex:i]; |
626 | + U1FileNode *placeholderNode = assetToBeDeleted.fileNode; |
627 | + [context deleteObject:assetToBeDeleted]; |
628 | + if (placeholderNode.generation == nil) |
629 | { |
630 | - NSURL *imageURL = [NSURL URLWithString:u1asset.url]; |
631 | - |
632 | - [self.assetsLibrary assetForURL:imageURL |
633 | - resultBlock:^(ALAsset *asset) { |
634 | - ALAssetRepresentation *representation = [asset defaultRepresentation]; |
635 | - NSString *mimetype = (id)UTTypeCopyPreferredTagWithClass((CFStringRef)[representation UTI], kUTTagClassMIMEType); |
636 | - |
637 | - U1AssetRepresenationDataProvider *provider = [[U1AssetRepresenationDataProvider alloc] init]; |
638 | - provider.representation = representation; |
639 | - |
640 | - [self.filesClient uploadContentDataProvider:provider |
641 | - toFolder:u1asset.fileNode.parent |
642 | - withResourceName:u1asset.filename |
643 | - withContentType:mimetype |
644 | - withPriority:NSOperationQueuePriorityVeryHigh |
645 | - progressBlock:^(long long bytesUploaded, long long totalBytes) {} |
646 | - completionBlock:^(U1FileNode *updatedNode, NSError *error) { |
647 | - u1asset.generation = updatedNode.generation; |
648 | - }]; |
649 | - } failureBlock:^(NSError *error) { |
650 | - NSLog(@"Error: %@", error); |
651 | - }]; |
652 | + [context deleteObject:placeholderNode]; |
653 | } |
654 | - }]; |
655 | + [self.dataRepository save:NULL]; |
656 | + } |
657 | + [assetsDeletedFromLibrary release]; |
658 | + }]; |
659 | } |
660 | |
661 | - (NSString *)remoteUploadFolderPath; |
662 | @@ -421,47 +477,41 @@ |
663 | return filename; |
664 | } |
665 | |
666 | -- (U1Asset *)createU1AssetWithAsset:(ALAsset *)asset group:(ALAssetsGroup *)group URLString:(NSString *)urlString fileName:(NSString *)filename inFolder:(U1FolderNode *)folderNode; |
667 | +- (U1Asset *)createU1AssetWithAsset:(ALAsset *)asset group:(ALAssetsGroup *)group URLString:(NSString *)urlString fileName:(NSString *)filename inFolder:(U1FolderNode *)folderNode context:(NSManagedObjectContext*)context; |
668 | { |
669 | - __block U1Asset *newAsset = nil; |
670 | - __block NSString *newFilename = filename; |
671 | - |
672 | - // TODO: temporary, create node if doesn't exist |
673 | - [self.dataRepository dispatchBlockWithManagedObjectContext:^(NSManagedObjectContext *context) { |
674 | - newAsset = [U1Asset insertInManagedObjectContext:context]; |
675 | - newAsset.groupId = [group valueForProperty: ALAssetsGroupPropertyPersistentID]; |
676 | - newAsset.url = urlString; |
677 | - if (filename == nil) |
678 | - { |
679 | - newFilename = [self generateFilenameForAsset:asset]; |
680 | - } |
681 | - newAsset.filename = newFilename; |
682 | - NSString *resourcePath = [folderNode.resourcePath stringByAppendingPathComponent:newFilename]; |
683 | - NSString *contentPath = [folderNode.contentPath stringByAppendingPathComponent:newFilename]; |
684 | - |
685 | - __block BOOL found = NO; |
686 | - __block U1FileNode *node = nil; |
687 | - |
688 | - [folderNode.children enumerateObjectsUsingBlock:^(U1FileNode *childNode, BOOL *stop) { |
689 | - if ([childNode.name isEqualToString:newFilename]) { |
690 | - found = YES; |
691 | - newAsset.generation = childNode.generation; |
692 | - newAsset.fileNode = childNode; |
693 | - *stop = YES; |
694 | - } |
695 | - }]; |
696 | - // Now we have an asset. We need to check to see if a corresponding FileNode is in our remoteUploadFolderChildren, and use it if it is. |
697 | - if (!found) |
698 | - { |
699 | - node = [U1FileNode insertInManagedObjectContext:context]; |
700 | - node.resourcePath = resourcePath; |
701 | - node.kind = @"file"; |
702 | - node.parent = folderNode; |
703 | - node.contentPath = contentPath; |
704 | - node.asset = newAsset; |
705 | + U1Asset *newAsset = [U1Asset insertInManagedObjectContext:context]; |
706 | + newAsset.groupId = [group valueForProperty: ALAssetsGroupPropertyPersistentID]; |
707 | + newAsset.url = urlString; |
708 | + if (filename == nil) |
709 | + { |
710 | + filename = [self generateFilenameForAsset:asset]; |
711 | + } |
712 | + newAsset.filename = filename; |
713 | + NSString *resourcePath = [folderNode.resourcePath stringByAppendingPathComponent:filename]; |
714 | + NSString *contentPath = [folderNode.contentPath stringByAppendingPathComponent:filename]; |
715 | + |
716 | + __block BOOL found = NO; |
717 | + __block U1FileNode *node = nil; |
718 | + |
719 | + [folderNode.children enumerateObjectsUsingBlock:^(U1FileNode *childNode, BOOL *stop) { |
720 | + if ([childNode.name isEqualToString:filename]) { |
721 | + found = YES; |
722 | + newAsset.generation = childNode.generation; |
723 | + newAsset.fileNode = childNode; |
724 | + *stop = YES; |
725 | } |
726 | }]; |
727 | - |
728 | + // Now we have an asset. We need to check to see if a corresponding FileNode is in our remoteUploadFolderChildren, and use it if it is. |
729 | + if (!found) |
730 | + { |
731 | + node = [U1FileNode insertInManagedObjectContext:context]; |
732 | + node.resourcePath = resourcePath; |
733 | + node.kind = @"file"; |
734 | + node.parent = folderNode; |
735 | + node.contentPath = contentPath; |
736 | + node.asset = newAsset; |
737 | + } |
738 | + |
739 | return newAsset; |
740 | } |
741 | |
742 | @@ -477,15 +527,16 @@ |
743 | if ((![self isPending:assetToUpload.filename]) && (assetToUpload.generation == nil)) |
744 | { |
745 | U1AssetRepresenationDataProvider *provider = [[U1AssetRepresenationDataProvider alloc] init]; |
746 | - provider.representation = representation; |
747 | + provider.assetURL = [NSURL URLWithString:assetToUpload.url]; |
748 | |
749 | // Let's create an operation! |
750 | U1AutoUploadOperation *operation = [[U1AutoUploadOperation alloc] init]; |
751 | operation.dataProvider = provider; |
752 | - operation.u1asset = assetToUpload; |
753 | - operation.folder = self.remoteUploadFolder; |
754 | + operation.assetID = [assetToUpload objectID]; |
755 | + operation.folderID = [self.remoteUploadFolder objectID]; |
756 | operation.filename = assetToUpload.filename; |
757 | - operation.contentType = (id)UTTypeCopyPreferredTagWithClass((CFStringRef)[provider.representation UTI], kUTTagClassMIMEType); |
758 | + // TODO: |
759 | +// operation.contentType = (id)UTTypeCopyPreferredTagWithClass((CFStringRef)[provider.representation UTI], kUTTagClassMIMEType); |
760 | operation.priority = NSOperationQueuePriorityNormal; |
761 | return [operation autorelease]; |
762 | } |
763 | |
764 | === modified file 'Files/U1DataRepository.h' |
765 | --- Files/U1DataRepository.h 2011-09-23 18:35:34 +0000 |
766 | +++ Files/U1DataRepository.h 2011-12-09 20:00:29 +0000 |
767 | @@ -26,10 +26,12 @@ |
768 | |
769 | - (U1Node*)nodeWithResourcePath:(NSString*)resourcePath; |
770 | |
771 | -//- (void)fetchResultsForEntityClass:(Class)entityClass matchingPredicate:(NSPredicate*)predicate withSortDescriptors:(NSArray*)sortDescriptors completionBlock:(void(^)(NSArray *results, NSError *error))completionBlock; |
772 | - |
773 | - (NSArray*)resultsForEntityClass:(Class)entityClass matchingPredicate:(NSPredicate*)predicate withSortDescriptors:(NSArray*)sortDescriptors error:(NSError**)error; |
774 | |
775 | +- (NSArray*)resultsForEntityClass:(Class)class inContext:(NSManagedObjectContext*)context withPredicate:(NSPredicate*)predicate sortDescriptors:(NSArray*)sortDescriptors error:(NSError**)error; |
776 | + |
777 | +- (void)dispatchBlockWithMainContext:(void(^)(NSManagedObjectContext *context))block; |
778 | + |
779 | - (void)dispatchBlockWithManagedObjectContext:(void(^)(NSManagedObjectContext *context))block; |
780 | |
781 | - (void)dispatchAsyncBlockWithManagedObjectContext:(void(^)(NSManagedObjectContext *context))block; |
782 | |
783 | === modified file 'Files/U1DataRepository.m' |
784 | --- Files/U1DataRepository.m 2011-10-25 23:36:04 +0000 |
785 | +++ Files/U1DataRepository.m 2011-12-09 20:00:29 +0000 |
786 | @@ -27,7 +27,7 @@ |
787 | @property (nonatomic, retain) NSManagedObjectContext *mainContext; |
788 | @property (nonatomic, retain) NSPersistentStoreCoordinator *storeCoordinator; |
789 | |
790 | -- (NSArray*)fetchEntitiesForClass:(Class)class inContext:(NSManagedObjectContext*)context withPredicate:(NSPredicate*)predicate sortDescriptors:(NSArray*)sortDescriptors error:(NSError**)error; |
791 | +- (NSArray*)resultsForEntityClass:(Class)class inContext:(NSManagedObjectContext*)context withPredicate:(NSPredicate*)predicate sortDescriptors:(NSArray*)sortDescriptors error:(NSError**)error; |
792 | |
793 | @end |
794 | |
795 | @@ -101,22 +101,17 @@ |
796 | NSParameterAssert(resourcePath); |
797 | |
798 | NSPredicate *p = [NSPredicate predicateWithFormat:@"resourcePath = %@", resourcePath]; |
799 | - NSArray *nodes = [self fetchEntitiesForClass:[U1Node class] inContext:self.mainContext withPredicate:p sortDescriptors:nil error:NULL]; |
800 | + NSArray *nodes = [self resultsForEntityClass:[U1Node class] inContext:self.mainContext withPredicate:p sortDescriptors:nil error:NULL]; |
801 | U1Node *node = [nodes lastObject]; |
802 | return node; |
803 | } |
804 | |
805 | -//- (void)fetchResultsForEntityClass:(Class)entityClass matchingPredicate:(NSPredicate*)predicate withSortDescriptors:(NSArray*)sortDescriptors completionBlock:(void(^)(NSArray *results, NSError *error))completionBlock; |
806 | -//{ |
807 | -// |
808 | -//} |
809 | - |
810 | - (NSArray*)resultsForEntityClass:(Class)entityClass matchingPredicate:(NSPredicate*)predicate withSortDescriptors:(NSArray*)sortDescriptors error:(NSError**)error; |
811 | { |
812 | - return [self fetchEntitiesForClass:entityClass inContext:self.mainContext withPredicate:predicate sortDescriptors:sortDescriptors error:error]; |
813 | + return [self resultsForEntityClass:entityClass inContext:self.mainContext withPredicate:predicate sortDescriptors:sortDescriptors error:error]; |
814 | } |
815 | |
816 | -- (NSArray*)fetchEntitiesForClass:(Class)class inContext:(NSManagedObjectContext*)context withPredicate:(NSPredicate*)predicate sortDescriptors:(NSArray*)sortDescriptors error:(NSError**)error; |
817 | +- (NSArray*)resultsForEntityClass:(Class)class inContext:(NSManagedObjectContext*)context withPredicate:(NSPredicate*)predicate sortDescriptors:(NSArray*)sortDescriptors error:(NSError**)error; |
818 | { |
819 | NSParameterAssert(class != nil); |
820 | NSParameterAssert(context != nil); |
821 | @@ -129,7 +124,7 @@ |
822 | return results; |
823 | } |
824 | |
825 | -- (void)dispatchBlockWithManagedObjectContext:(void(^)(NSManagedObjectContext *context))block; |
826 | +- (void)dispatchBlockWithMainContext:(void(^)(NSManagedObjectContext *context))block; |
827 | { |
828 | NSParameterAssert(block != NULL); |
829 | if (![NSThread isMainThread]) |
830 | @@ -146,6 +141,22 @@ |
831 | } |
832 | } |
833 | |
834 | +- (void)dispatchBlockWithManagedObjectContext:(void(^)(NSManagedObjectContext *context))block; |
835 | +{ |
836 | + NSParameterAssert(block != NULL); |
837 | + |
838 | + NSManagedObjectContext *context = [[NSManagedObjectContext alloc] init]; |
839 | + id observation = [[[NSNotificationCenter defaultCenter] addObserverForName:NSManagedObjectContextDidSaveNotification object:context queue:nil usingBlock:^(NSNotification *note) { |
840 | + dispatch_async(dispatch_get_main_queue(), ^{ |
841 | + [self.mainContext mergeChangesFromContextDidSaveNotification:note]; |
842 | + }); |
843 | + }] retain]; |
844 | + [context setPersistentStoreCoordinator:self.storeCoordinator]; |
845 | + block(context); |
846 | + [context release]; |
847 | + [observation release]; |
848 | +} |
849 | + |
850 | - (void)dispatchAsyncBlockWithManagedObjectContext:(void(^)(NSManagedObjectContext *context))block; |
851 | { |
852 | NSParameterAssert(block != NULL); |
853 | @@ -153,10 +164,16 @@ |
854 | typeof(block) contextBlock = [block copy]; |
855 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) { |
856 | NSManagedObjectContext *context = [[NSManagedObjectContext alloc] init]; |
857 | + id observation = [[[NSNotificationCenter defaultCenter] addObserverForName:NSManagedObjectContextDidSaveNotification object:context queue:nil usingBlock:^(NSNotification *note) { |
858 | + dispatch_async(dispatch_get_main_queue(), ^{ |
859 | + [self.mainContext mergeChangesFromContextDidSaveNotification:note]; |
860 | + }); |
861 | + }] retain]; |
862 | [context setPersistentStoreCoordinator:self.storeCoordinator]; |
863 | contextBlock(context); |
864 | [contextBlock release]; |
865 | [context release]; |
866 | + [observation release]; |
867 | }); |
868 | } |
869 | |
870 | |
871 | === modified file 'Files/U1FilesClient.h' |
872 | --- Files/U1FilesClient.h 2011-12-01 17:37:53 +0000 |
873 | +++ Files/U1FilesClient.h 2011-12-09 20:00:29 +0000 |
874 | @@ -22,10 +22,8 @@ |
875 | |
876 | extern NSString * const U1FilesClientNodeStatusChangedNotification; |
877 | |
878 | +@protocol U1UploadDataProvider; |
879 | |
880 | -@protocol U1UploadDataProvider <NSObject> |
881 | -- (NSData *)serializeData; |
882 | -@end |
883 | |
884 | typedef enum U1DataSourceType { |
885 | U1DataSourceLocal, |
886 | |
887 | === modified file 'Files/U1FilesClient.m' |
888 | --- Files/U1FilesClient.m 2011-12-06 20:53:05 +0000 |
889 | +++ Files/U1FilesClient.m 2011-12-09 20:00:29 +0000 |
890 | @@ -117,7 +117,7 @@ |
891 | __block NSFetchedResultsController *cloudFoldersResultsController = nil; |
892 | __block U1Volume *rootVolume = nil; // vestigial |
893 | |
894 | - [self.dataRepository dispatchBlockWithManagedObjectContext:^(NSManagedObjectContext *context) { |
895 | + [self.dataRepository dispatchBlockWithMainContext:^(NSManagedObjectContext *context) { |
896 | |
897 | NSFetchRequest *request = [[NSFetchRequest alloc] init]; |
898 | [request setEntity:[U1Volume entityInManagedObjectContext:context]]; |
899 | @@ -142,7 +142,7 @@ |
900 | |
901 | [self.filesService volumeInfoWithCompletionBlock:^(NSArray *volumeInfos, NSError *error) { |
902 | |
903 | - [self.dataRepository dispatchBlockWithManagedObjectContext:^(NSManagedObjectContext *context) { |
904 | + [self.dataRepository dispatchBlockWithMainContext:^(NSManagedObjectContext *context) { |
905 | |
906 | NSMutableArray *fetchedVolumes = [NSMutableArray array]; |
907 | for (NSDictionary *volumeInfo in volumeInfos) |
908 | @@ -193,7 +193,7 @@ |
909 | __block U1FolderNode *node = [(id)[self.dataRepository nodeWithResourcePath:nodePath] retain]; |
910 | __block NSFetchedResultsController *resultsController = nil; |
911 | |
912 | - [self.dataRepository dispatchBlockWithManagedObjectContext:^(NSManagedObjectContext *context) { |
913 | + [self.dataRepository dispatchBlockWithMainContext:^(NSManagedObjectContext *context) { |
914 | |
915 | if (!node) |
916 | { |
917 | @@ -237,17 +237,24 @@ |
918 | |
919 | [node updatePropertiesFromJSONDictionary:nodeInfo]; |
920 | |
921 | + NSManagedObjectID *nodeID = [node objectID]; |
922 | + |
923 | NSArray *childInfos = [nodeInfo objectForKey:@"children"]; |
924 | - [self.dataRepository dispatchBlockWithManagedObjectContext:^(NSManagedObjectContext *context) { |
925 | + [self.dataRepository dispatchAsyncBlockWithManagedObjectContext:^(NSManagedObjectContext *context) { |
926 | |
927 | + U1FolderNode *folderNode = (id)[context objectWithID:nodeID]; |
928 | NSMutableSet *orphans = [NSMutableSet set]; |
929 | - [orphans unionSet:node.children]; |
930 | + [orphans unionSet:folderNode.children]; |
931 | |
932 | + NSUInteger batchCounter = 0; |
933 | for (NSDictionary *childInfo in childInfos) |
934 | { |
935 | NSString *childResourcePath = [childInfo objectForKey:@"resource_path"]; |
936 | NSString *kind = [childInfo objectForKey:@"kind"]; |
937 | - U1Node *childNode = [self.dataRepository nodeWithResourcePath:childResourcePath]; |
938 | + NSError *error = nil; |
939 | + NSPredicate *p = [NSPredicate predicateWithFormat:@"resourcePath = %@", childResourcePath]; |
940 | + NSArray *results = [self.dataRepository resultsForEntityClass:[U1Node class] inContext:context withPredicate:p sortDescriptors:nil error:&error]; |
941 | + U1Node *childNode = [results lastObject]; |
942 | if (!childNode) |
943 | { |
944 | if ([@"file" isEqualToString:kind]) |
945 | @@ -257,8 +264,14 @@ |
946 | } |
947 | |
948 | [childNode updatePropertiesFromJSONDictionary:childInfo]; |
949 | - childNode.parent = node; |
950 | + childNode.parent = folderNode; |
951 | [orphans removeObject:childNode]; |
952 | + |
953 | + if (++batchCounter > 100) |
954 | + { |
955 | + [context save:NULL]; |
956 | + batchCounter = 0; |
957 | + } |
958 | } |
959 | |
960 | for (U1Node *orphan in orphans) |
961 | @@ -270,13 +283,15 @@ |
962 | } |
963 | |
964 | [context save:NULL]; |
965 | + |
966 | + dispatch_async(dispatch_get_main_queue(), ^(void) { |
967 | + resultsBlock(node, resultsController, U1DataSourceRemote); |
968 | + [resultsController release]; |
969 | + [node release]; |
970 | + }); |
971 | + |
972 | }]; |
973 | |
974 | - dispatch_async(dispatch_get_main_queue(), ^(void) { |
975 | - resultsBlock(node, resultsController, U1DataSourceRemote); |
976 | - [resultsController release]; |
977 | - [node release]; |
978 | - }); |
979 | |
980 | }]; |
981 | return nil; |
982 | @@ -288,7 +303,7 @@ |
983 | |
984 | if (!node) |
985 | { |
986 | - [self.dataRepository dispatchBlockWithManagedObjectContext:^(NSManagedObjectContext *context) { |
987 | + [self.dataRepository dispatchBlockWithMainContext:^(NSManagedObjectContext *context) { |
988 | node = [[U1FileNode insertInManagedObjectContext:context] retain]; |
989 | node.resourcePath = nodePath; |
990 | [context save:NULL]; |
991 | @@ -333,7 +348,7 @@ |
992 | return [self.filesService deleteNodeAtResourcePath:node.resourcePath completionBlock:^(NSError *error) { |
993 | if (!error) |
994 | { |
995 | - [self.dataRepository dispatchBlockWithManagedObjectContext:^(NSManagedObjectContext *context) { |
996 | + [self.dataRepository dispatchBlockWithMainContext:^(NSManagedObjectContext *context) { |
997 | [context deleteObject:node]; |
998 | [context save:NULL]; |
999 | }]; |
1000 | @@ -348,7 +363,7 @@ |
1001 | U1FileNode *node = (id)[self.dataRepository nodeWithResourcePath:resourcePath]; |
1002 | if (!node) |
1003 | { |
1004 | - [self.dataRepository dispatchBlockWithManagedObjectContext:^(NSManagedObjectContext *context) { |
1005 | + [self.dataRepository dispatchBlockWithMainContext:^(NSManagedObjectContext *context) { |
1006 | U1FileNode *newNode = [U1FileNode insertInManagedObjectContext:context]; |
1007 | newNode.resourcePath = resourcePath; |
1008 | newNode.kind = @"file"; |
1009 | @@ -429,7 +444,7 @@ |
1010 | U1FolderNode *node = (id)[self.dataRepository nodeWithResourcePath:resourcePath]; |
1011 | if (!node) |
1012 | { |
1013 | - [self.dataRepository dispatchBlockWithManagedObjectContext:^(NSManagedObjectContext *context) { |
1014 | + [self.dataRepository dispatchBlockWithMainContext:^(NSManagedObjectContext *context) { |
1015 | U1FolderNode *newNode = [U1FolderNode insertInManagedObjectContext:context]; |
1016 | newNode.resourcePath = resourcePath; |
1017 | newNode.kind = @"directory"; |
1018 | @@ -452,7 +467,7 @@ |
1019 | - (id)createVolumeAtPath:(NSString*)folderPath completionBlock:(void(^)(U1Volume *volume, NSError *error))completionBlock; |
1020 | { |
1021 | return [self.filesService createVolumeAtPath:folderPath completionBlock:^(NSDictionary *volumeInfo, NSError *error) { |
1022 | - [self.dataRepository dispatchBlockWithManagedObjectContext:^(NSManagedObjectContext *context) { |
1023 | + [self.dataRepository dispatchBlockWithMainContext:^(NSManagedObjectContext *context) { |
1024 | U1Volume *volume = [U1Volume insertInManagedObjectContext:context]; |
1025 | if (!error) |
1026 | { |
1027 | |
1028 | === modified file 'Files/U1FilesService.h' |
1029 | --- Files/U1FilesService.h 2011-11-01 01:17:53 +0000 |
1030 | +++ Files/U1FilesService.h 2011-12-09 20:00:29 +0000 |
1031 | @@ -18,6 +18,11 @@ |
1032 | @class U1Node, U1FileNode, U1FolderNode; |
1033 | |
1034 | |
1035 | +@protocol U1UploadDataProvider <NSObject> |
1036 | +- (void)prepareDataStreamWithBlock:(void(^)(NSInputStream *dataStream, NSString *mimeType, NSUInteger length, NSError *error))block; |
1037 | +@end |
1038 | + |
1039 | + |
1040 | @interface U1FilesService : NSObject |
1041 | |
1042 | + (U1FilesService *)sharedFilesService; |
1043 | @@ -28,7 +33,7 @@ |
1044 | - (id)infoForNode:(U1Node*)node includeChildren:(BOOL)includeChildren completionBlock:(void(^)(NSDictionary *node, NSError *error))completionBlock; |
1045 | - (id)contentForNode:(U1FileNode*)node progressBlock:(void(^)(long long bytesReceived, long long bytesExpected))progressBlock completionBlock:(void(^)(NSURL *contentURL))completionBlock; |
1046 | - (id)uploadContentAtURL:(NSURL*)contentURL forNode:(U1FileNode*)node progressBlock:(void(^)(long long bytesUploaded, long long totalBytes))progressBlock completionBlock:(void(^)(U1FileNode *updatedNode, NSError *error))completionBlock; |
1047 | -- (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; |
1048 | +- (id)uploadContentData:(id<U1UploadDataProvider>)contentData forNode:(U1FileNode*)node withContentType:(NSString*)contentType progressBlock:(void(^)(long long bytesUploaded, long long totalBytes))progressBlock completionBlock:(void(^)(NSDictionary *updatedNodeInfo, NSError *error))completionBlock; |
1049 | - (id)moveNodeAtResourcePath:(NSString*)resourcePath toPath:(NSString*)newPath withCompletionBlock:(void(^)(NSDictionary *nodeInfo, NSError *error))completionBlock; |
1050 | - (id)deleteNodeAtResourcePath:(NSString*)resourcePath completionBlock:(void(^)(NSError *error))completionBlock; |
1051 | - (id)publishNode:(U1FileNode*)node completionBlock:(void(^)(U1FileNode *node, NSError *error))completionBlock; |
1052 | |
1053 | === modified file 'Files/U1FilesService.m' |
1054 | --- Files/U1FilesService.m 2011-12-06 18:38:47 +0000 |
1055 | +++ Files/U1FilesService.m 2011-12-09 20:00:29 +0000 |
1056 | @@ -196,20 +196,28 @@ |
1057 | return nil; |
1058 | } |
1059 | |
1060 | -- (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; |
1061 | +- (id)uploadContentData:(id<U1UploadDataProvider>)contentData forNode:(U1FileNode*)node withContentType:(NSString*)contentType progressBlock:(void(^)(long long bytesUploaded, long long totalBytes))progressBlock completionBlock:(void(^)(NSDictionary *updatedNodeInfo, NSError *error))completionBlock; |
1062 | { |
1063 | NSString *contentPath = node.contentPath; |
1064 | NSURL *requestURL = [NSURL URLWithString:[[U1FilesServiceAPIContentRoot stringByAppendingPathComponent:contentPath] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]; |
1065 | |
1066 | - |
1067 | - U1ReportingInputStream *stream = [[U1ReportingInputStream alloc] initWithData:contentData]; |
1068 | - stream.progressBlock = progressBlock; |
1069 | - |
1070 | - [self execute:@"PUT" toURL:requestURL withParameters:nil requestBody:stream contentType:contentType contentLength:[contentData length] parseResponseBody:YES completionBlock:^(id results, NSError *error) { |
1071 | - |
1072 | - completionBlock(results, error); |
1073 | + [contentData prepareDataStreamWithBlock:^(NSInputStream *dataStream, NSString *mimeType, NSUInteger length, NSError *error) { |
1074 | + |
1075 | + if (error) |
1076 | + { |
1077 | + completionBlock(nil, error); |
1078 | + return; |
1079 | + } |
1080 | + |
1081 | + U1ReportingInputStream *stream = [U1ReportingInputStream inputStreamWithSourceStream:dataStream]; |
1082 | + stream.progressBlock = progressBlock; |
1083 | + stream.dataLength = length; |
1084 | + [self execute:@"PUT" toURL:requestURL withParameters:nil requestBody:stream contentType:mimeType contentLength:length parseResponseBody:YES completionBlock:^(id results, NSError *error) { |
1085 | + |
1086 | + completionBlock(results, error); |
1087 | + }]; |
1088 | }]; |
1089 | - |
1090 | + |
1091 | return nil; |
1092 | } |
1093 | |
1094 | @@ -350,30 +358,33 @@ |
1095 | [request release]; |
1096 | |
1097 | [httpOperation setCompletionBlock:^(void) { |
1098 | + |
1099 | + id result = nil; |
1100 | + NSHTTPURLResponse *response = httpOperation.response; |
1101 | + NSError *error = httpOperation.error; |
1102 | + |
1103 | + if ([response statusCode] == 401) |
1104 | + { |
1105 | + dispatch_async(dispatch_get_main_queue(), ^(void) { |
1106 | + [[U1AccountManager sharedAccountManager] removeCredentials]; |
1107 | + }); |
1108 | + return; |
1109 | + } |
1110 | + |
1111 | + if (!error && |
1112 | + ![[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(200, 100)] containsIndex:[response statusCode]]) |
1113 | + { |
1114 | + // TODO: semantic error messages |
1115 | + error = [NSError errorWithDomain:@"U1FilesServiceErrorDomain" code:[response statusCode] userInfo:nil]; |
1116 | + } |
1117 | + if (!error && parseResponseBody) |
1118 | + { |
1119 | + NSData *data = [collector data]; |
1120 | + result = [data objectFromJSONDataWithParseOptions:JKParseOptionNone error:&error]; |
1121 | + } |
1122 | + |
1123 | dispatch_async(dispatch_get_main_queue(), ^(void) { |
1124 | - |
1125 | - id result = nil; |
1126 | - NSHTTPURLResponse *response = httpOperation.response; |
1127 | - NSError *error = httpOperation.error; |
1128 | - |
1129 | - if ([response statusCode] == 401) |
1130 | - { |
1131 | - [[U1AccountManager sharedAccountManager] removeCredentials]; |
1132 | - return; |
1133 | - } |
1134 | - |
1135 | - if (!error && |
1136 | - ![[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(200, 100)] containsIndex:[response statusCode]]) |
1137 | - { |
1138 | - // TODO: semantic error messages |
1139 | - error = [NSError errorWithDomain:@"U1FilesServiceErrorDomain" code:[response statusCode] userInfo:nil]; |
1140 | - } |
1141 | - if (!error && parseResponseBody) |
1142 | - { |
1143 | - NSData *data = [collector data]; |
1144 | - result = [data objectFromJSONDataWithParseOptions:JKParseOptionNone error:&error]; |
1145 | - } |
1146 | - |
1147 | + |
1148 | if (completionBlock) |
1149 | completionBlock(result, error); |
1150 | |
1151 | |
1152 | === modified file 'Files/U1FolderItemCell.m' |
1153 | --- Files/U1FolderItemCell.m 2011-12-01 17:37:53 +0000 |
1154 | +++ Files/U1FolderItemCell.m 2011-12-09 20:00:29 +0000 |
1155 | @@ -19,6 +19,11 @@ |
1156 | #import "U1ViewNibLoader.h" |
1157 | |
1158 | |
1159 | +@interface U1FolderItemCell () |
1160 | ++ (UINib*)cellNib; |
1161 | +@end |
1162 | + |
1163 | + |
1164 | @implementation U1FolderItemCell |
1165 | |
1166 | @synthesize iconImageView, nameLabel, detailLabel, uploadIndicator, uploadProgressView; |
1167 | @@ -29,11 +34,21 @@ |
1168 | U1FolderItemCell *cell = (id)[tableView dequeueReusableCellWithIdentifier:NSStringFromClass(self)]; |
1169 | if (!cell) |
1170 | { |
1171 | - cell = [U1ViewNibLoader viewFromNib:NSStringFromClass(self)]; |
1172 | + cell = [U1ViewNibLoader viewFromUINib:[U1FolderItemCell cellNib]]; |
1173 | } |
1174 | return cell; |
1175 | } |
1176 | |
1177 | ++ (UINib*)cellNib; |
1178 | +{ |
1179 | + static UINib *cellNib; |
1180 | + static dispatch_once_t onceToken; |
1181 | + dispatch_once(&onceToken, ^{ |
1182 | + cellNib = [[UINib nibWithNibName:NSStringFromClass(self) bundle:nil] retain]; |
1183 | + }); |
1184 | + return cellNib; |
1185 | +} |
1186 | + |
1187 | - (void)dealloc |
1188 | { |
1189 | [iconImageView release]; |
1190 | |
1191 | === modified file 'Files/U1FolderItemCell.xib' |
1192 | --- Files/U1FolderItemCell.xib 2011-12-01 17:37:53 +0000 |
1193 | +++ Files/U1FolderItemCell.xib 2011-12-09 20:00:29 +0000 |
1194 | @@ -101,7 +101,7 @@ |
1195 | <string key="NSFrame">{{52, 28}, {234, 17}}</string> |
1196 | <reference key="NSSuperview" ref="604950473"/> |
1197 | <reference key="NSWindow"/> |
1198 | - <reference key="NSNextKeyView"/> |
1199 | + <reference key="NSNextKeyView" ref="23474122"/> |
1200 | <bool key="IBUIOpaque">NO</bool> |
1201 | <bool key="IBUIClipsSubviews">YES</bool> |
1202 | <int key="IBUIContentMode">7</int> |
1203 | @@ -134,6 +134,7 @@ |
1204 | <string key="NSFrame">{{293, 17}, {20, 20}}</string> |
1205 | <reference key="NSSuperview" ref="604950473"/> |
1206 | <reference key="NSWindow"/> |
1207 | + <reference key="NSNextKeyView"/> |
1208 | <bool key="IBUIOpaque">NO</bool> |
1209 | <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string> |
1210 | <bool key="IBUIHidesWhenStopped">NO</bool> |
1211 | @@ -145,6 +146,7 @@ |
1212 | <string key="NSFrame">{{52, 32}, {234, 9}}</string> |
1213 | <reference key="NSSuperview" ref="604950473"/> |
1214 | <reference key="NSWindow"/> |
1215 | + <reference key="NSNextKeyView" ref="587955385"/> |
1216 | <bool key="IBUIOpaque">NO</bool> |
1217 | <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string> |
1218 | <object class="NSColor" key="IBUIProgressTintColor"> |
1219 | |
1220 | === modified file 'Files/U1FolderViewController.m' |
1221 | --- Files/U1FolderViewController.m 2011-12-07 18:23:32 +0000 |
1222 | +++ Files/U1FolderViewController.m 2011-12-09 20:00:29 +0000 |
1223 | @@ -253,12 +253,13 @@ |
1224 | NSString *filename = [NSString stringWithFormat:@"%@ %@.%@", assetType, [dateFormatter stringFromDate:assetDate], ext]; |
1225 | [dateFormatter release]; |
1226 | |
1227 | - U1Asset *u1asset = [autoUploadsManager createU1AssetWithAsset:asset group:nil URLString:[imageURL absoluteString] fileName:filename inFolder:self.node]; |
1228 | + // TODO: fix! |
1229 | + U1Asset *u1asset = [autoUploadsManager createU1AssetWithAsset:asset group:nil URLString:[imageURL absoluteString] fileName:filename inFolder:self.node context:nil]; |
1230 | |
1231 | if (u1asset.generation == nil) // Prevent duplicate uploading to the same folder |
1232 | { |
1233 | U1AssetRepresenationDataProvider *provider = [[U1AssetRepresenationDataProvider alloc] init]; |
1234 | - provider.representation = representation; |
1235 | + provider.assetURL = [NSURL URLWithString:[u1asset url]]; |
1236 | dispatch_async(dispatch_get_main_queue(), ^(void) { |
1237 | [self.filesClient uploadContentDataProvider:provider |
1238 | toFolder:self.node |
1239 | @@ -271,7 +272,7 @@ |
1240 | if (error) |
1241 | { |
1242 | // TODO: remove direct access to data repository |
1243 | - [[U1DataRepository sharedDataRepository] dispatchBlockWithManagedObjectContext:^(NSManagedObjectContext *context) { |
1244 | + [[U1DataRepository sharedDataRepository] dispatchBlockWithMainContext:^(NSManagedObjectContext *context) { |
1245 | [context deleteObject:u1asset.fileNode]; |
1246 | }]; |
1247 | } |
1248 | |
1249 | === modified file 'Files/U1ReportingInputStream.h' |
1250 | --- Files/U1ReportingInputStream.h 2011-11-30 21:42:52 +0000 |
1251 | +++ Files/U1ReportingInputStream.h 2011-12-09 20:00:29 +0000 |
1252 | @@ -19,8 +19,9 @@ |
1253 | @interface U1ReportingInputStream : NSProxy |
1254 | |
1255 | @property (copy) void (^progressBlock)(long long, long long); |
1256 | +@property long long dataLength; |
1257 | |
1258 | -+ (NSInputStream*)inputStreamWithData:(NSData*)data; |
1259 | -- (id)initWithData:(NSData*)data; |
1260 | ++ (U1ReportingInputStream*)inputStreamWithSourceStream:(NSInputStream*)sourceStream; |
1261 | +- (id)initWithSourceStream:(NSInputStream*)sourceStream; |
1262 | |
1263 | @end |
1264 | |
1265 | === modified file 'Files/U1ReportingInputStream.m' |
1266 | --- Files/U1ReportingInputStream.m 2011-11-30 21:42:52 +0000 |
1267 | +++ Files/U1ReportingInputStream.m 2011-12-09 20:00:29 +0000 |
1268 | @@ -23,22 +23,20 @@ |
1269 | |
1270 | @implementation U1ReportingInputStream |
1271 | { |
1272 | - NSUInteger contentLength; |
1273 | NSUInteger readSoFar; |
1274 | } |
1275 | |
1276 | -@synthesize progressBlock; |
1277 | +@synthesize progressBlock, dataLength; |
1278 | @synthesize targetStream; |
1279 | |
1280 | -+ (NSInputStream *)inputStreamWithData:(NSData *)data; |
1281 | ++ (U1ReportingInputStream *)inputStreamWithSourceStream:(NSInputStream*)sourceStream; |
1282 | { |
1283 | - return [[[self alloc] initWithData:data] autorelease]; |
1284 | + return [[[self alloc] initWithSourceStream:sourceStream] autorelease]; |
1285 | } |
1286 | |
1287 | -- (id)initWithData:(NSData *)theData; |
1288 | +- (id)initWithSourceStream:(NSInputStream*)sourceStream; |
1289 | { |
1290 | - targetStream = [[NSInputStream alloc] initWithData:theData]; |
1291 | - contentLength = [theData length]; |
1292 | + targetStream = [sourceStream retain]; |
1293 | return self; |
1294 | } |
1295 | |
1296 | @@ -54,7 +52,7 @@ |
1297 | NSInteger read = [self.targetStream read:buffer maxLength:len]; |
1298 | readSoFar += read; |
1299 | if (self.progressBlock) |
1300 | - self.progressBlock(readSoFar, contentLength); |
1301 | + self.progressBlock(readSoFar, self.dataLength); |
1302 | return read; |
1303 | } |
1304 | |
1305 | |
1306 | === modified file 'Files/U1UploadOperation.m' |
1307 | --- Files/U1UploadOperation.m 2011-12-06 20:53:05 +0000 |
1308 | +++ Files/U1UploadOperation.m 2011-12-09 20:00:29 +0000 |
1309 | @@ -85,9 +85,7 @@ |
1310 | |
1311 | U1FilesService *filesService = [U1FilesService sharedFilesService]; |
1312 | fileInfo.uploading = YES; |
1313 | - NSData *uploadData = [self.dataProvider serializeData]; |
1314 | - |
1315 | - [filesService uploadContentData:uploadData forNode:self.fileNode withContentType:self.mimetype progressBlock:^(long long uploaded, long long totalLength) { |
1316 | + [filesService uploadContentData:self.dataProvider forNode:self.fileNode withContentType:self.mimetype progressBlock:^(long long uploaded, long long totalLength) { |
1317 | |
1318 | dispatch_async(dispatch_get_main_queue(), ^{ |
1319 | [self.fileInfo setUploadPercentage:((double)uploaded / (double)totalLength)]; |
1320 | @@ -107,7 +105,26 @@ |
1321 | if (filesServiceError != nil) |
1322 | { |
1323 | self.error = filesServiceError; |
1324 | - [self beginUpload]; |
1325 | + if ([filesServiceError.domain isEqualToString:@"nonexistentAsset"]) |
1326 | + { |
1327 | + // Asset is gone, delete U1Asset and potentially the Node, and stop running |
1328 | + U1DataRepository *dataRepository = [U1DataRepository sharedDataRepository]; |
1329 | + [dataRepository dispatchAsyncBlockWithManagedObjectContext:^(NSManagedObjectContext *context) { |
1330 | + U1Asset *assetToBeDeleted = self.fileNode.asset; |
1331 | + [context deleteObject:assetToBeDeleted]; |
1332 | + if (self.fileNode.generation == nil) |
1333 | + { |
1334 | + [context deleteObject:self.fileNode]; |
1335 | + } |
1336 | + [dataRepository save:NULL]; |
1337 | + }]; |
1338 | + [self finishExecuting]; |
1339 | + } |
1340 | + else |
1341 | + { |
1342 | + // File upload timed out or something else, so reschedule |
1343 | + [self beginUpload]; |
1344 | + } |
1345 | } |
1346 | else |
1347 | { |
1348 | |
1349 | === modified file 'Files/U1UploadsPoolViewController.m' |
1350 | --- Files/U1UploadsPoolViewController.m 2011-12-06 18:36:40 +0000 |
1351 | +++ Files/U1UploadsPoolViewController.m 2011-12-09 20:00:29 +0000 |
1352 | @@ -275,7 +275,7 @@ |
1353 | |
1354 | - (void)loadCurrentUploads; |
1355 | { |
1356 | - [[U1DataRepository sharedDataRepository] dispatchBlockWithManagedObjectContext:^(NSManagedObjectContext *context) { |
1357 | + [[U1DataRepository sharedDataRepository] dispatchBlockWithMainContext:^(NSManagedObjectContext *context) { |
1358 | |
1359 | NSFetchRequest *request = [[NSFetchRequest alloc] init]; |
1360 | [request setEntity:[U1Asset entityInManagedObjectContext:context]]; |
1361 | |
1362 | === modified file 'Files/U1Volume.m' |
1363 | --- Files/U1Volume.m 2011-10-26 04:40:14 +0000 |
1364 | +++ Files/U1Volume.m 2011-12-09 20:00:29 +0000 |
1365 | @@ -41,7 +41,7 @@ |
1366 | if (rootFolder == nil) |
1367 | { |
1368 | // Upload |
1369 | - [dataRepository dispatchBlockWithManagedObjectContext:^(NSManagedObjectContext *context) { |
1370 | + [dataRepository dispatchBlockWithMainContext:^(NSManagedObjectContext *context) { |
1371 | |
1372 | U1FolderNode *rootFolder = [U1FolderNode insertInManagedObjectContext:context]; |
1373 | rootFolder.resourcePath = self.nodePath; |
1374 | |
1375 | === modified file 'Files/iPhone/en.lproj/MainWindow_iPhone.xib' |
1376 | --- Files/iPhone/en.lproj/MainWindow_iPhone.xib 2011-11-18 17:53:03 +0000 |
1377 | +++ Files/iPhone/en.lproj/MainWindow_iPhone.xib 2011-12-09 20:00:29 +0000 |
1378 | @@ -45,10 +45,11 @@ |
1379 | <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string> |
1380 | </object> |
1381 | <object class="IBUIWindow" id="380026005"> |
1382 | - <nil key="NSNextResponder"/> |
1383 | + <reference key="NSNextResponder"/> |
1384 | <int key="NSvFlags">1316</int> |
1385 | <object class="NSPSMatrix" key="NSFrameMatrix"/> |
1386 | <string key="NSFrameSize">{320, 480}</string> |
1387 | + <reference key="NSSuperview"/> |
1388 | <object class="NSColor" key="IBUIBackgroundColor"> |
1389 | <int key="NSColorSpace">1</int> |
1390 | <bytes key="NSRGB">MSAxIDEAA</bytes> |
1391 | @@ -68,12 +69,12 @@ |
1392 | </object> |
1393 | <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string> |
1394 | <bool key="IBUIHorizontal">NO</bool> |
1395 | - <object class="IBUINavigationController" key="IBUISelectedViewController" id="941272465"> |
1396 | - <object class="IBUITabBarItem" key="IBUITabBarItem" id="463875161"> |
1397 | - <string key="IBUITitle">Uploads</string> |
1398 | + <object class="IBUINavigationController" key="IBUISelectedViewController" id="175250829"> |
1399 | + <object class="IBUITabBarItem" key="IBUITabBarItem" id="1047769425"> |
1400 | + <string key="IBUITitle">Files</string> |
1401 | <object class="NSCustomResource" key="IBUIImage"> |
1402 | <string key="NSClassName">NSImage</string> |
1403 | - <string key="NSResourceName">upload.png</string> |
1404 | + <string key="NSResourceName">folder.png</string> |
1405 | </object> |
1406 | <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string> |
1407 | </object> |
1408 | @@ -85,7 +86,7 @@ |
1409 | </object> |
1410 | <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string> |
1411 | <bool key="IBUIHorizontal">NO</bool> |
1412 | - <object class="IBUINavigationBar" key="IBUINavigationBar" id="499706903"> |
1413 | + <object class="IBUINavigationBar" key="IBUINavigationBar" id="131246382"> |
1414 | <nil key="NSNextResponder"/> |
1415 | <int key="NSvFlags">256</int> |
1416 | <string key="NSFrameSize">{0, 0}</string> |
1417 | @@ -100,12 +101,12 @@ |
1418 | </object> |
1419 | <object class="NSMutableArray" key="IBUIViewControllers"> |
1420 | <bool key="EncodedWithXMLCoder">YES</bool> |
1421 | - <object class="IBUIViewController" id="743143347"> |
1422 | - <object class="IBUINavigationItem" key="IBUINavigationItem" id="374575231"> |
1423 | + <object class="IBUIViewController" id="852027692"> |
1424 | + <object class="IBUINavigationItem" key="IBUINavigationItem" id="570921376"> |
1425 | <string key="IBUITitle">Root View Controller</string> |
1426 | <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string> |
1427 | </object> |
1428 | - <reference key="IBUIParentViewController" ref="941272465"/> |
1429 | + <reference key="IBUIParentViewController" ref="175250829"/> |
1430 | <object class="IBUISimulatedOrientationMetrics" key="IBUISimulatedOrientationMetrics"> |
1431 | <int key="IBUIInterfaceOrientation">1</int> |
1432 | <int key="interfaceOrientation">1</int> |
1433 | @@ -117,12 +118,13 @@ |
1434 | </object> |
1435 | <object class="NSMutableArray" key="IBUIViewControllers"> |
1436 | <bool key="EncodedWithXMLCoder">YES</bool> |
1437 | - <object class="IBUINavigationController" id="175250829"> |
1438 | - <object class="IBUITabBarItem" key="IBUITabBarItem" id="1047769425"> |
1439 | - <string key="IBUITitle">Files</string> |
1440 | + <reference ref="175250829"/> |
1441 | + <object class="IBUINavigationController" id="941272465"> |
1442 | + <object class="IBUITabBarItem" key="IBUITabBarItem" id="463875161"> |
1443 | + <string key="IBUITitle">Uploads</string> |
1444 | <object class="NSCustomResource" key="IBUIImage"> |
1445 | <string key="NSClassName">NSImage</string> |
1446 | - <string key="NSResourceName">folder.png</string> |
1447 | + <string key="NSResourceName">upload.png</string> |
1448 | </object> |
1449 | <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string> |
1450 | </object> |
1451 | @@ -134,7 +136,7 @@ |
1452 | </object> |
1453 | <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string> |
1454 | <bool key="IBUIHorizontal">NO</bool> |
1455 | - <object class="IBUINavigationBar" key="IBUINavigationBar" id="131246382"> |
1456 | + <object class="IBUINavigationBar" key="IBUINavigationBar" id="499706903"> |
1457 | <nil key="NSNextResponder"/> |
1458 | <int key="NSvFlags">256</int> |
1459 | <string key="NSFrameSize">{0, 0}</string> |
1460 | @@ -149,12 +151,12 @@ |
1461 | </object> |
1462 | <object class="NSMutableArray" key="IBUIViewControllers"> |
1463 | <bool key="EncodedWithXMLCoder">YES</bool> |
1464 | - <object class="IBUIViewController" id="852027692"> |
1465 | - <object class="IBUINavigationItem" key="IBUINavigationItem" id="570921376"> |
1466 | + <object class="IBUIViewController" id="743143347"> |
1467 | + <object class="IBUINavigationItem" key="IBUINavigationItem" id="374575231"> |
1468 | <string key="IBUITitle">Root View Controller</string> |
1469 | <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string> |
1470 | </object> |
1471 | - <reference key="IBUIParentViewController" ref="175250829"/> |
1472 | + <reference key="IBUIParentViewController" ref="941272465"/> |
1473 | <object class="IBUISimulatedOrientationMetrics" key="IBUISimulatedOrientationMetrics"> |
1474 | <int key="IBUIInterfaceOrientation">1</int> |
1475 | <int key="interfaceOrientation">1</int> |
1476 | @@ -164,7 +166,6 @@ |
1477 | </object> |
1478 | </object> |
1479 | </object> |
1480 | - <reference ref="941272465"/> |
1481 | <object class="IBUINavigationController" id="631281359"> |
1482 | <object class="IBUITabBarItem" key="IBUITabBarItem" id="460599548"> |
1483 | <string key="IBUITitle">Settings</string> |
LAND, LAND