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