Revision 64929bae
b/Classes/AccountManager.h | ||
---|---|---|
16 | 16 |
@interface AccountManager : NSObject { |
17 | 17 |
OpenStackAccount *account; |
18 | 18 |
ASINetworkQueue *queue; |
19 |
NSMutableDictionary *objectDownloadRequests; |
|
19 | 20 |
} |
20 | 21 |
|
21 | 22 |
@property (nonatomic, retain) ASINetworkQueue *queue; |
22 | 23 |
|
23 | 24 |
@property (nonatomic, assign) OpenStackAccount *account; |
25 |
@property (nonatomic, retain) NSMutableDictionary *objectDownloadRequests; |
|
24 | 26 |
|
25 | 27 |
- (NSString *)notificationName:(NSString *)key identifier:(NSString *)identifier; |
26 | 28 |
- (void)notify:(NSString *)name request:(OpenStackRequest *)request; |
... | ... | |
61 | 63 |
- (void)getObjects:(Container *)container; |
62 | 64 |
- (void)getObjects:(Container *)container afterMarker:(NSString *)marker objectsBuffer:(NSMutableDictionary *)objectsBuffer; |
63 | 65 |
- (APICallback *)getObjectInfo:(Container *)container object:(StorageObject *)object; |
66 |
- (APICallback *)getObjectInfo:(Container *)container object:(StorageObject *)object version:(NSString *)version; |
|
67 |
- (APICallback *)getObjectVersionsList:(Container *)container object:(StorageObject *)object; |
|
64 | 68 |
- (APICallback *)getObject:(Container *)container object:(StorageObject *)object downloadProgressDelegate:(id)downloadProgressDelegate; |
69 |
|
|
70 |
- (APICallback *)getObject:(Container *)container |
|
71 |
object:(StorageObject *)object |
|
72 |
downloadProgressDelegate:(id)downloadProgressDelegate |
|
73 |
requestUserInfo:(NSDictionary *)requestUserInfo; |
|
74 |
|
|
75 |
- (APICallback *)getObject:(Container *)container |
|
76 |
object:(StorageObject *)object |
|
77 |
downloadProgressDelegate:(id)downloadProgressDelegate |
|
78 |
requestUserInfo:(NSDictionary *)requestUserInfo |
|
79 |
version:(NSString *)version; |
|
80 |
|
|
81 |
|
|
65 | 82 |
- (APICallback *)writeObject:(Container *)container object:(StorageObject *)object downloadProgressDelegate:(id)downloadProgressDelegate; |
66 | 83 |
- (APICallback *)writeObjectMetadata:(Container *)container object:(StorageObject *)object; |
67 | 84 |
- (APICallback *)deleteObject:(Container *)container object:(StorageObject *)object; |
b/Classes/AccountManager.m | ||
---|---|---|
27 | 27 |
#import "APICallback.h" |
28 | 28 |
#import "Analytics.h" |
29 | 29 |
#import "JSON.h" |
30 |
#import "OpenStackAppDelegate.h" |
|
30 | 31 |
|
31 | 32 |
|
32 | 33 |
|
33 | 34 |
|
34 | 35 |
@implementation AccountManager |
35 | 36 |
|
36 |
@synthesize account, queue; |
|
37 |
@synthesize account, queue, objectDownloadRequests;
|
|
37 | 38 |
|
38 | 39 |
#pragma mark - Callbacks |
39 | 40 |
|
... | ... | |
494 | 495 |
return [self callbackWithRequest:request]; |
495 | 496 |
} |
496 | 497 |
|
498 |
- (APICallback *)getObjectInfo:(Container *)container object:(StorageObject *)object version:(NSString *)version { |
|
499 |
if (!version) |
|
500 |
return [self getObjectInfo:container object:object]; |
|
501 |
|
|
502 |
__block OpenStackRequest *request = [OpenStackRequest getObjectInfoRequest:self.account container:container object:object version:version]; |
|
503 |
return [self callbackWithRequest:request]; |
|
504 |
} |
|
505 |
|
|
506 |
- (APICallback *)getObjectVersionsList:(Container *)container object:(StorageObject *)object { |
|
507 |
__block OpenStackRequest *request = [OpenStackRequest getObjectVersionsRequest:account container:container object:object]; |
|
508 |
return [self callbackWithRequest:request]; |
|
509 |
} |
|
510 |
|
|
497 | 511 |
- (APICallback *)getObject:(Container *)container object:(StorageObject *)object downloadProgressDelegate:(id)downloadProgressDelegate { |
498 |
__block OpenStackRequest *request = [OpenStackRequest getObjectRequest:self.account container:container object:object]; |
|
512 |
return [self getObject:container object:object downloadProgressDelegate:downloadProgressDelegate requestUserInfo:nil]; |
|
513 |
} |
|
514 |
|
|
515 |
- (APICallback *)getObject:(Container *)container |
|
516 |
object:(StorageObject *)object |
|
517 |
downloadProgressDelegate:(id)downloadProgressDelegate |
|
518 |
requestUserInfo:(NSDictionary *)requestUserInfo { |
|
519 |
|
|
520 |
return [self getObject:container object:object downloadProgressDelegate:downloadProgressDelegate requestUserInfo:requestUserInfo version:nil]; |
|
521 |
} |
|
522 |
|
|
523 |
|
|
524 |
- (APICallback *)getObject:(Container *)container |
|
525 |
object:(StorageObject *)object |
|
526 |
downloadProgressDelegate:(id)downloadProgressDelegate |
|
527 |
requestUserInfo:(NSDictionary *)requestUserInfo |
|
528 |
version:(NSString *)version{ |
|
529 |
__block OpenStackRequest *request = [OpenStackRequest getObjectRequest:self.account container:container object:object version:version]; |
|
499 | 530 |
request.delegate = self; |
500 | 531 |
request.downloadProgressDelegate = downloadProgressDelegate; |
501 |
request.showAccurateProgress = YES; |
|
532 |
request.showAccurateProgress = YES; |
|
533 |
if (requestUserInfo) { |
|
534 |
request.userInfo = requestUserInfo; |
|
535 |
} |
|
536 |
if (!objectDownloadRequests) |
|
537 |
self.objectDownloadRequests = [NSMutableDictionary dictionary]; |
|
538 |
[objectDownloadRequests setObject:request forKey:object.fullPath]; |
|
502 | 539 |
return [self callbackWithRequest:request success:^(OpenStackRequest *request) { |
503 | 540 |
|
504 |
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); |
|
505 |
NSString *documentsDirectory = [paths objectAtIndex:0]; |
|
506 |
NSString *shortPath = [NSString stringWithFormat:@"/%@/%@", container.name, object.fullPath]; |
|
507 |
NSString *filePath = [documentsDirectory stringByAppendingString:shortPath]; |
|
508 |
NSString *directoryPath = [filePath stringByReplacingOccurrencesOfString:[NSString stringWithFormat:@"/%@", object.name] withString:@""]; |
|
509 |
|
|
510 |
NSFileManager *fileManager = [NSFileManager defaultManager]; |
|
511 |
if ([fileManager createDirectoryAtPath:directoryPath withIntermediateDirectories:YES attributes:nil error:nil]) { |
|
512 |
|
|
513 |
[[request responseData] writeToFile:filePath atomically:YES]; |
|
514 |
|
|
541 |
OpenStackAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate]; |
|
542 |
NSString *filePath = [appDelegate.cacheDirectoryPath stringByAppendingFormat:@"/%@.%@",object.hash, object.name.pathExtension]; |
|
543 |
[[request responseData] writeToFile:filePath atomically:YES]; |
|
544 |
@synchronized(appDelegate.cachedObjectsDictionary) { |
|
545 |
[appDelegate.cachedObjectsDictionary setObject:filePath forKey:object.hash]; |
|
546 |
[appDelegate saveCacheDictionary]; |
|
515 | 547 |
} |
516 |
|
|
548 |
[objectDownloadRequests removeObjectForKey:object.fullPath]; |
|
549 |
} |
|
550 |
failure:^(OpenStackRequest *request) { |
|
551 |
[objectDownloadRequests removeObjectForKey:object.fullPath]; |
|
517 | 552 |
}]; |
518 | 553 |
} |
519 | 554 |
|
... | ... | |
740 | 775 |
#pragma mark Memory Management |
741 | 776 |
|
742 | 777 |
- (void)dealloc { |
778 |
[objectDownloadRequests release]; |
|
743 | 779 |
[super dealloc]; |
744 | 780 |
} |
745 | 781 |
|
b/Classes/FolderViewController.m | ||
---|---|---|
26 | 26 |
#import "OpenStackRequest.h" |
27 | 27 |
#import "JSON.h" |
28 | 28 |
#import "APICallback.h" |
29 |
#import "OpenStackAppDelegate.h" |
|
29 | 30 |
|
30 | 31 |
|
31 | 32 |
@implementation FolderViewController |
... | ... | |
236 | 237 |
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; |
237 | 238 |
|
238 | 239 |
StorageObject *object = item; |
239 |
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); |
|
240 |
NSString *documentsDirectory = [paths objectAtIndex:0]; |
|
241 |
NSString *shortPath = [NSString stringWithFormat:@"/%@/%@", self.container.name, object.fullPath]; |
|
242 |
NSString *filePath = [documentsDirectory stringByAppendingString:shortPath]; |
|
243 |
|
|
240 |
OpenStackAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate]; |
|
241 |
NSString *filePath = [appDelegate.cachedObjectsDictionary objectForKey:object.hash]; |
|
244 | 242 |
if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) { |
245 | 243 |
UIDocumentInteractionController *udic = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:filePath]]; |
246 | 244 |
if ([udic.icons count] > 0) { |
b/Classes/ObjectVersionsViewController.h | ||
---|---|---|
1 |
// |
|
2 |
// ObjectVersionsViewController.h |
|
3 |
// pithos-ios |
|
4 |
// |
|
5 |
// Copyright 2011 GRNET S.A. All rights reserved. |
|
6 |
// |
|
7 |
// Redistribution and use in source and binary forms, with or |
|
8 |
// without modification, are permitted provided that the following |
|
9 |
// conditions are met: |
|
10 |
// |
|
11 |
// 1. Redistributions of source code must retain the above |
|
12 |
// copyright notice, this list of conditions and the following |
|
13 |
// disclaimer. |
|
14 |
// |
|
15 |
// 2. Redistributions in binary form must reproduce the above |
|
16 |
// copyright notice, this list of conditions and the following |
|
17 |
// disclaimer in the documentation and/or other materials |
|
18 |
// provided with the distribution. |
|
19 |
// |
|
20 |
// THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS |
|
21 |
// OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
|
22 |
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
|
23 |
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR |
|
24 |
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
25 |
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|
26 |
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
|
27 |
// USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
|
28 |
// AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
|
29 |
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
|
30 |
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
|
31 |
// POSSIBILITY OF SUCH DAMAGE. |
|
32 |
// |
|
33 |
// The views and conclusions contained in the software and |
|
34 |
// documentation are those of the authors and should not be |
|
35 |
// interpreted as representing official policies, either expressed |
|
36 |
// or implied, of GRNET S.A. |
|
37 |
|
|
38 |
#import <UIKit/UIKit.h> |
|
39 |
#import "OpenStackViewController.h" |
|
40 |
|
|
41 |
@class OpenStackAccount, Container, StorageObject; |
|
42 |
|
|
43 |
@interface ObjectVersionsViewController : OpenStackViewController <UITableViewDelegate, UITableViewDataSource> { |
|
44 |
|
|
45 |
IBOutlet UITableView *tableView; |
|
46 |
NSMutableArray *versions; |
|
47 |
OpenStackAccount *account; |
|
48 |
Container *container; |
|
49 |
StorageObject *object; |
|
50 |
BOOL versionsLoaded; |
|
51 |
|
|
52 |
} |
|
53 |
|
|
54 |
@property (nonatomic, retain) IBOutlet UITableView *tableView; |
|
55 |
@property (nonatomic, retain) NSMutableArray *versions; |
|
56 |
@property (nonatomic, retain) OpenStackAccount *account; |
|
57 |
@property (nonatomic, retain) Container *container; |
|
58 |
@property (nonatomic, retain) StorageObject *object; |
|
59 |
|
|
60 |
@end |
b/Classes/ObjectVersionsViewController.m | ||
---|---|---|
1 |
// |
|
2 |
// ObjectVersionsViewController.m |
|
3 |
// pithos-ios |
|
4 |
// |
|
5 |
// Copyright 2011 GRNET S.A. All rights reserved. |
|
6 |
// |
|
7 |
// Redistribution and use in source and binary forms, with or |
|
8 |
// without modification, are permitted provided that the following |
|
9 |
// conditions are met: |
|
10 |
// |
|
11 |
// 1. Redistributions of source code must retain the above |
|
12 |
// copyright notice, this list of conditions and the following |
|
13 |
// disclaimer. |
|
14 |
// |
|
15 |
// 2. Redistributions in binary form must reproduce the above |
|
16 |
// copyright notice, this list of conditions and the following |
|
17 |
// disclaimer in the documentation and/or other materials |
|
18 |
// provided with the distribution. |
|
19 |
// |
|
20 |
// THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS |
|
21 |
// OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
|
22 |
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
|
23 |
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR |
|
24 |
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
25 |
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|
26 |
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
|
27 |
// USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
|
28 |
// AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
|
29 |
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
|
30 |
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
|
31 |
// POSSIBILITY OF SUCH DAMAGE. |
|
32 |
// |
|
33 |
// The views and conclusions contained in the software and |
|
34 |
// documentation are those of the authors and should not be |
|
35 |
// interpreted as representing official policies, either expressed |
|
36 |
// or implied, of GRNET S.A. |
|
37 |
|
|
38 |
#import "ObjectVersionsViewController.h" |
|
39 |
#import "StorageObjectViewController.h" |
|
40 |
#import "OpenStackAccount.h" |
|
41 |
#import "OpenStackRequest.h" |
|
42 |
#import "AccountManager.h" |
|
43 |
#import "APICallback.h" |
|
44 |
#import "JSON.h" |
|
45 |
#import "ActivityIndicatorView.h" |
|
46 |
#import "UIViewController+Conveniences.h" |
|
47 |
#import "StorageObject.h" |
|
48 |
|
|
49 |
|
|
50 |
@implementation ObjectVersionsViewController |
|
51 |
|
|
52 |
@synthesize tableView, versions, account, container, object; |
|
53 |
|
|
54 |
#pragma mark - View lifecycle |
|
55 |
|
|
56 |
- (void)viewDidLoad { |
|
57 |
[super viewDidLoad]; |
|
58 |
self.navigationItem.title = @"Versions"; |
|
59 |
self.versions = [NSMutableArray array]; |
|
60 |
versionsLoaded = NO; |
|
61 |
NSString *activityMessage = @"Loading.."; |
|
62 |
ActivityIndicatorView *activityIndicatorView = [[ActivityIndicatorView alloc] initWithFrame:[ActivityIndicatorView frameForText:activityMessage] text:activityMessage]; |
|
63 |
[activityIndicatorView addToView:self.view]; |
|
64 |
|
|
65 |
[[self.account.manager getObjectVersionsList:container object:object] |
|
66 |
success:^(OpenStackRequest *request) { |
|
67 |
SBJSON *parser = [[SBJSON alloc] init]; |
|
68 |
NSArray *versionsInJson = [[parser objectWithString:[request responseString]] objectForKey:@"versions"]; |
|
69 |
for (NSArray *versionInfo in versionsInJson) { |
|
70 |
[versions addObject:[NSDictionary dictionaryWithObjectsAndKeys:[versionInfo objectAtIndex:0], @"versionID", |
|
71 |
[NSDate dateWithTimeIntervalSince1970:[[versionInfo objectAtIndex:1] doubleValue]], @"versionDate", |
|
72 |
nil]]; |
|
73 |
} |
|
74 |
[activityIndicatorView removeFromSuperviewAndRelease]; |
|
75 |
versionsLoaded = YES; |
|
76 |
[self.tableView reloadData]; |
|
77 |
} |
|
78 |
failure:^(OpenStackRequest *request) { |
|
79 |
[activityIndicatorView removeFromSuperviewAndRelease]; |
|
80 |
[self alert:@"Couldn't get versions from server" request:request]; |
|
81 |
}]; |
|
82 |
} |
|
83 |
|
|
84 |
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation { |
|
85 |
return (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) || (toInterfaceOrientation == UIInterfaceOrientationPortrait); |
|
86 |
} |
|
87 |
|
|
88 |
#pragma mark - memory management |
|
89 |
|
|
90 |
- (void)dealloc { |
|
91 |
[account release]; |
|
92 |
[container release]; |
|
93 |
[object release]; |
|
94 |
[versions release]; |
|
95 |
[super dealloc]; |
|
96 |
} |
|
97 |
|
|
98 |
|
|
99 |
#pragma mark - Table view data source |
|
100 |
|
|
101 |
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { |
|
102 |
return 1; |
|
103 |
} |
|
104 |
|
|
105 |
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { |
|
106 |
if (!versionsLoaded) |
|
107 |
return 0; |
|
108 |
else |
|
109 |
return MAX(1, versions.count); |
|
110 |
} |
|
111 |
|
|
112 |
- (UITableViewCell *)tableView:(UITableView *)aTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { |
|
113 |
static NSString *CellIdentifier = @"Cell"; |
|
114 |
|
|
115 |
UITableViewCell *cell = [aTableView dequeueReusableCellWithIdentifier:CellIdentifier]; |
|
116 |
if (cell == nil) { |
|
117 |
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease]; |
|
118 |
} |
|
119 |
cell.userInteractionEnabled = YES; |
|
120 |
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; |
|
121 |
cell.selectionStyle = UITableViewCellSelectionStyleBlue; |
|
122 |
if (versions.count == 0 || !versions) { |
|
123 |
cell.textLabel.text = @"No previous versions available"; |
|
124 |
cell.userInteractionEnabled = NO; |
|
125 |
cell.accessoryType = UITableViewCellAccessoryNone; |
|
126 |
cell.selectionStyle = UITableViewCellSelectionStyleNone; |
|
127 |
} else { |
|
128 |
NSDictionary *versionDetails = [versions objectAtIndex:indexPath.row]; |
|
129 |
cell.textLabel.text = [[versionDetails objectForKey:@"versionID"] description]; |
|
130 |
NSString *dateString = [NSDateFormatter localizedStringFromDate:[versionDetails objectForKey:@"versionDate"] |
|
131 |
dateStyle:NSDateFormatterMediumStyle |
|
132 |
timeStyle:NSDateFormatterMediumStyle]; |
|
133 |
cell.detailTextLabel.text = dateString; |
|
134 |
} |
|
135 |
|
|
136 |
return cell; |
|
137 |
} |
|
138 |
|
|
139 |
#pragma mark - Table view delegate |
|
140 |
|
|
141 |
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { |
|
142 |
NSString *activityMessage = @"Loading.."; |
|
143 |
ActivityIndicatorView *activityIndicatorView = [[ActivityIndicatorView alloc] initWithFrame:[ActivityIndicatorView frameForText:activityMessage] text:activityMessage]; |
|
144 |
[activityIndicatorView addToView:self.view]; |
|
145 |
|
|
146 |
NSDictionary *versionDetails = [versions objectAtIndex:indexPath.row]; |
|
147 |
NSString *versionID = [[versionDetails objectForKey:@"versionID"] description]; |
|
148 |
|
|
149 |
[[self.account.manager getObjectInfo:container object:object version:versionID] |
|
150 |
success:^(OpenStackRequest *request) { |
|
151 |
[activityIndicatorView removeFromSuperviewAndRelease]; |
|
152 |
StorageObject *versionedObject = [[[StorageObject alloc] init] autorelease]; |
|
153 |
versionedObject.name = object.name; |
|
154 |
versionedObject.fullPath = object.fullPath; |
|
155 |
[versionedObject setPropertiesfromResponseHeaders:request.responseHeaders]; |
|
156 |
StorageObjectViewController *vc = [[StorageObjectViewController alloc] initWithNibName:@"StorageObjectViewController" bundle:nil]; |
|
157 |
vc.objectIsReadOnly = YES; |
|
158 |
vc.account = account; |
|
159 |
vc.container = container; |
|
160 |
vc.object = versionedObject; |
|
161 |
vc.versionID = versionID; |
|
162 |
[self.navigationController pushViewController:vc animated:YES]; |
|
163 |
[vc release]; |
|
164 |
[self.tableView deselectRowAtIndexPath:indexPath animated:YES]; |
|
165 |
} |
|
166 |
failure:^(OpenStackRequest *request) { |
|
167 |
[activityIndicatorView removeFromSuperviewAndRelease]; |
|
168 |
[self alert:[NSString stringWithFormat:@"Failed to get file info for version: %@", versionID] request:request]; |
|
169 |
}]; |
|
170 |
} |
|
171 |
|
|
172 |
@end |
b/Classes/ObjectVersionsViewController.xib | ||
---|---|---|
1 |
<?xml version="1.0" encoding="UTF-8"?> |
|
2 |
<archive type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="8.00"> |
|
3 |
<data> |
|
4 |
<int key="IBDocument.SystemTarget">1280</int> |
|
5 |
<string key="IBDocument.SystemVersion">11C74</string> |
|
6 |
<string key="IBDocument.InterfaceBuilderVersion">1938</string> |
|
7 |
<string key="IBDocument.AppKitVersion">1138.23</string> |
|
8 |
<string key="IBDocument.HIToolboxVersion">567.00</string> |
|
9 |
<object class="NSMutableDictionary" key="IBDocument.PluginVersions"> |
|
10 |
<string key="NS.key.0">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string> |
|
11 |
<string key="NS.object.0">933</string> |
|
12 |
</object> |
|
13 |
<array key="IBDocument.IntegratedClassDependencies"> |
|
14 |
<string>IBProxyObject</string> |
|
15 |
<string>IBUIView</string> |
|
16 |
<string>IBUITableView</string> |
|
17 |
</array> |
|
18 |
<array key="IBDocument.PluginDependencies"> |
|
19 |
<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string> |
|
20 |
</array> |
|
21 |
<object class="NSMutableDictionary" key="IBDocument.Metadata"> |
|
22 |
<string key="NS.key.0">PluginDependencyRecalculationVersion</string> |
|
23 |
<integer value="1" key="NS.object.0"/> |
|
24 |
</object> |
|
25 |
<array class="NSMutableArray" key="IBDocument.RootObjects" id="1000"> |
|
26 |
<object class="IBProxyObject" id="372490531"> |
|
27 |
<string key="IBProxiedObjectIdentifier">IBFilesOwner</string> |
|
28 |
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string> |
|
29 |
</object> |
|
30 |
<object class="IBProxyObject" id="975951072"> |
|
31 |
<string key="IBProxiedObjectIdentifier">IBFirstResponder</string> |
|
32 |
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string> |
|
33 |
</object> |
|
34 |
<object class="IBUIView" id="191373211"> |
|
35 |
<reference key="NSNextResponder"/> |
|
36 |
<int key="NSvFlags">274</int> |
|
37 |
<array class="NSMutableArray" key="NSSubviews"> |
|
38 |
<object class="IBUITableView" id="360754307"> |
|
39 |
<reference key="NSNextResponder" ref="191373211"/> |
|
40 |
<int key="NSvFlags">274</int> |
|
41 |
<string key="NSFrameSize">{320, 460}</string> |
|
42 |
<reference key="NSSuperview" ref="191373211"/> |
|
43 |
<string key="NSReuseIdentifierKey">_NS:418</string> |
|
44 |
<object class="NSColor" key="IBUIBackgroundColor"> |
|
45 |
<int key="NSColorSpace">3</int> |
|
46 |
<bytes key="NSWhite">MQA</bytes> |
|
47 |
</object> |
|
48 |
<bool key="IBUIClipsSubviews">YES</bool> |
|
49 |
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string> |
|
50 |
<bool key="IBUIAlwaysBounceVertical">YES</bool> |
|
51 |
<int key="IBUISeparatorStyle">1</int> |
|
52 |
<int key="IBUISectionIndexMinimumDisplayRowCount">0</int> |
|
53 |
<bool key="IBUIShowsSelectionImmediatelyOnTouchBegin">YES</bool> |
|
54 |
<float key="IBUIRowHeight">44</float> |
|
55 |
<float key="IBUISectionHeaderHeight">22</float> |
|
56 |
<float key="IBUISectionFooterHeight">22</float> |
|
57 |
</object> |
|
58 |
</array> |
|
59 |
<string key="NSFrame">{{0, 20}, {320, 460}}</string> |
|
60 |
<reference key="NSSuperview"/> |
|
61 |
<reference key="NSNextKeyView"/> |
|
62 |
<object class="NSColor" key="IBUIBackgroundColor"> |
|
63 |
<int key="NSColorSpace">3</int> |
|
64 |
<bytes key="NSWhite">MQA</bytes> |
|
65 |
<object class="NSColorSpace" key="NSCustomColorSpace"> |
|
66 |
<int key="NSID">2</int> |
|
67 |
</object> |
|
68 |
</object> |
|
69 |
<object class="IBUISimulatedStatusBarMetrics" key="IBUISimulatedStatusBarMetrics"/> |
|
70 |
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string> |
|
71 |
</object> |
|
72 |
</array> |
|
73 |
<object class="IBObjectContainer" key="IBDocument.Objects"> |
|
74 |
<array class="NSMutableArray" key="connectionRecords"> |
|
75 |
<object class="IBConnectionRecord"> |
|
76 |
<object class="IBCocoaTouchOutletConnection" key="connection"> |
|
77 |
<string key="label">view</string> |
|
78 |
<reference key="source" ref="372490531"/> |
|
79 |
<reference key="destination" ref="191373211"/> |
|
80 |
</object> |
|
81 |
<int key="connectionID">3</int> |
|
82 |
</object> |
|
83 |
<object class="IBConnectionRecord"> |
|
84 |
<object class="IBCocoaTouchOutletConnection" key="connection"> |
|
85 |
<string key="label">tableView</string> |
|
86 |
<reference key="source" ref="372490531"/> |
|
87 |
<reference key="destination" ref="360754307"/> |
|
88 |
</object> |
|
89 |
<int key="connectionID">5</int> |
|
90 |
</object> |
|
91 |
<object class="IBConnectionRecord"> |
|
92 |
<object class="IBCocoaTouchOutletConnection" key="connection"> |
|
93 |
<string key="label">dataSource</string> |
|
94 |
<reference key="source" ref="360754307"/> |
|
95 |
<reference key="destination" ref="372490531"/> |
|
96 |
</object> |
|
97 |
<int key="connectionID">6</int> |
|
98 |
</object> |
|
99 |
<object class="IBConnectionRecord"> |
|
100 |
<object class="IBCocoaTouchOutletConnection" key="connection"> |
|
101 |
<string key="label">delegate</string> |
|
102 |
<reference key="source" ref="360754307"/> |
|
103 |
<reference key="destination" ref="372490531"/> |
|
104 |
</object> |
|
105 |
<int key="connectionID">7</int> |
|
106 |
</object> |
|
107 |
</array> |
|
108 |
<object class="IBMutableOrderedSet" key="objectRecords"> |
|
109 |
<array key="orderedObjects"> |
|
110 |
<object class="IBObjectRecord"> |
|
111 |
<int key="objectID">0</int> |
|
112 |
<array key="object" id="0"/> |
|
113 |
<reference key="children" ref="1000"/> |
|
114 |
<nil key="parent"/> |
|
115 |
</object> |
|
116 |
<object class="IBObjectRecord"> |
|
117 |
<int key="objectID">1</int> |
|
118 |
<reference key="object" ref="191373211"/> |
|
119 |
<array class="NSMutableArray" key="children"> |
|
120 |
<reference ref="360754307"/> |
|
121 |
</array> |
|
122 |
<reference key="parent" ref="0"/> |
|
123 |
</object> |
|
124 |
<object class="IBObjectRecord"> |
|
125 |
<int key="objectID">-1</int> |
|
126 |
<reference key="object" ref="372490531"/> |
|
127 |
<reference key="parent" ref="0"/> |
|
128 |
<string key="objectName">File's Owner</string> |
|
129 |
</object> |
|
130 |
<object class="IBObjectRecord"> |
|
131 |
<int key="objectID">-2</int> |
|
132 |
<reference key="object" ref="975951072"/> |
|
133 |
<reference key="parent" ref="0"/> |
|
134 |
</object> |
|
135 |
<object class="IBObjectRecord"> |
|
136 |
<int key="objectID">4</int> |
|
137 |
<reference key="object" ref="360754307"/> |
|
138 |
<reference key="parent" ref="191373211"/> |
|
139 |
</object> |
|
140 |
</array> |
|
141 |
</object> |
|
142 |
<dictionary class="NSMutableDictionary" key="flattenedProperties"> |
|
143 |
<string key="-1.CustomClassName">ObjectVersionsViewController</string> |
|
144 |
<string key="-1.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string> |
|
145 |
<string key="-2.CustomClassName">UIResponder</string> |
|
146 |
<string key="-2.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string> |
|
147 |
<string key="1.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string> |
|
148 |
<string key="4.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string> |
|
149 |
</dictionary> |
|
150 |
<dictionary class="NSMutableDictionary" key="unlocalizedProperties"/> |
|
151 |
<nil key="activeLocalization"/> |
|
152 |
<dictionary class="NSMutableDictionary" key="localizations"/> |
|
153 |
<nil key="sourceID"/> |
|
154 |
<int key="maxID">7</int> |
|
155 |
</object> |
|
156 |
<object class="IBClassDescriber" key="IBDocument.Classes"/> |
|
157 |
<int key="IBDocument.localizationMode">0</int> |
|
158 |
<string key="IBDocument.TargetRuntimeIdentifier">IBCocoaTouchFramework</string> |
|
159 |
<bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool> |
|
160 |
<int key="IBDocument.defaultPropertyAccessControl">3</int> |
|
161 |
<string key="IBCocoaTouchPluginVersion">933</string> |
|
162 |
</data> |
|
163 |
</archive> |
b/Classes/OpenStackAppDelegate.h | ||
---|---|---|
10 | 10 |
|
11 | 11 |
@class RootViewController; |
12 | 12 |
|
13 |
#define CACHED_OBJECTS_ARCHIVE_KEY @"cachedObjectsDictionary" |
|
14 |
#define CACHE_DICT_ARCHIVE_NAME @"cache.dict" |
|
15 |
|
|
13 | 16 |
@interface OpenStackAppDelegate : NSObject <UIApplicationDelegate> { |
14 | 17 |
UIWindow *window; |
15 | 18 |
UINavigationController *navigationController; |
... | ... | |
18 | 21 |
UIBarButtonItem *barButtonItem; |
19 | 22 |
RootViewController *rootViewController; |
20 | 23 |
id serviceUnavailableObserver; |
24 |
NSMutableDictionary *cachedObjectsDictionary; |
|
25 |
NSString *cacheDictionaryFilePath; |
|
26 |
NSString *cacheDirectoryPath; |
|
21 | 27 |
|
28 |
NSUserDefaults *userDefaults; |
|
22 | 29 |
} |
23 | 30 |
|
24 | 31 |
@property (nonatomic, retain) IBOutlet UIWindow *window; |
... | ... | |
27 | 34 |
@property (nonatomic, retain) UINavigationController *masterNavigationController; |
28 | 35 |
@property (nonatomic, retain) UIBarButtonItem *barButtonItem; |
29 | 36 |
@property (nonatomic, retain) RootViewController *rootViewController; |
37 |
@property (nonatomic, retain) NSMutableDictionary *cachedObjectsDictionary; |
|
38 |
@property (nonatomic, copy) NSString *cacheDictionaryFilePath; |
|
39 |
@property (nonatomic, copy) NSString *cacheDirectoryPath; |
|
30 | 40 |
|
31 | 41 |
//- (void) setupDependencies; |
42 |
- (void)saveCacheDictionary; |
|
32 | 43 |
|
33 | 44 |
@end |
34 | 45 |
|
b/Classes/OpenStackAppDelegate.m | ||
---|---|---|
39 | 39 |
@synthesize masterNavigationController; |
40 | 40 |
@synthesize barButtonItem; |
41 | 41 |
@synthesize rootViewController; |
42 |
@synthesize cachedObjectsDictionary; |
|
43 |
@synthesize cacheDictionaryFilePath; |
|
44 |
@synthesize cacheDirectoryPath; |
|
42 | 45 |
|
43 | 46 |
- (void)loadSettingsDefaults { |
44 | 47 |
|
... | ... | |
57 | 60 |
[Keychain setString:@"NO" forKey:@"passcode_lock_erase_data_on"]; |
58 | 61 |
} |
59 | 62 |
|
60 |
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
|
63 |
userDefaults = [[NSUserDefaults standardUserDefaults] retain];
|
|
61 | 64 |
|
62 |
if (![defaults stringForKey:@"api_logging_level"]) {
|
|
63 |
[defaults setValue:@"all" forKey:@"api_logging_level"];
|
|
65 |
if (![userDefaults stringForKey:@"api_logging_level"]) {
|
|
66 |
[userDefaults setValue:@"all" forKey:@"api_logging_level"];
|
|
64 | 67 |
} |
65 | 68 |
|
66 |
if (![defaults stringForKey:@"aboutURL"]) { |
|
67 |
[defaults setValue:@"https://plus.pithos.grnet.gr" forKey:@"aboutURL"]; |
|
68 |
} |
|
69 |
if (![userDefaults stringForKey:@"aboutURL"]) { |
|
70 |
[userDefaults setValue:@"https://plus.pithos.grnet.gr" forKey:@"aboutURL"]; |
|
71 |
} |
|
72 |
|
|
73 |
self.cachedObjectsDictionary = [userDefaults objectForKey:@"cachedObjectsDictionary"]; |
|
74 |
if (!cachedObjectsDictionary) { |
|
75 |
self.cachedObjectsDictionary = [NSMutableDictionary dictionary]; |
|
76 |
[userDefaults setValue:cachedObjectsDictionary forKey:@"cachedObjectsDictionary"]; |
|
77 |
} |
|
69 | 78 |
|
70 |
[defaults synchronize];
|
|
79 |
[userDefaults synchronize];
|
|
71 | 80 |
|
72 | 81 |
} |
73 | 82 |
|
... | ... | |
148 | 157 |
[alert release]; |
149 | 158 |
[[NSNotificationCenter defaultCenter] removeObserver:serviceUnavailableObserver]; |
150 | 159 |
}]; |
151 |
|
|
160 |
|
|
161 |
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); |
|
162 |
self.cacheDirectoryPath = [[paths objectAtIndex:0] stringByAppendingPathComponent:@"DownloadedFiles"]; |
|
163 |
NSFileManager *fileManager = [NSFileManager defaultManager]; |
|
164 |
NSError *error = nil; |
|
165 |
[fileManager createDirectoryAtPath:cacheDirectoryPath withIntermediateDirectories:YES attributes:nil error:&error]; |
|
166 |
if (error) { |
|
167 |
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error" |
|
168 |
message:[NSString stringWithFormat:@"Error in creating cache directory\n%@",error.localizedDescription] |
|
169 |
delegate:nil |
|
170 |
cancelButtonTitle:@"OK" otherButtonTitles:nil]; |
|
171 |
[alert show]; |
|
172 |
[alert release]; |
|
173 |
} |
|
174 |
|
|
152 | 175 |
return YES; |
153 | 176 |
} |
154 | 177 |
|
... | ... | |
202 | 225 |
|
203 | 226 |
|
204 | 227 |
- (void)applicationDidBecomeActive:(UIApplication *)application { |
205 |
/* |
|
206 |
Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
|
|
207 |
*/
|
|
208 |
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
|
209 |
[defaults setBool:NO forKey:@"already_failed_on_connection"];
|
|
210 |
[defaults synchronize];
|
|
228 |
|
|
229 |
/*
|
|
230 |
Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
|
|
231 |
*/
|
|
232 |
[userDefaults setBool:NO forKey:@"already_failed_on_connection"];
|
|
233 |
[userDefaults synchronize];
|
|
211 | 234 |
|
212 | 235 |
[self showPasscodeLock]; |
213 | 236 |
//DispatchAnalytics(); |
... | ... | |
291 | 314 |
return YES; |
292 | 315 |
} |
293 | 316 |
|
317 |
#pragma mark - persistence |
|
318 |
|
|
319 |
- (void)saveCacheDictionary { |
|
320 |
[userDefaults setObject:cachedObjectsDictionary forKey:@"cachedObjectsDictionary"]; |
|
321 |
[userDefaults synchronize]; |
|
322 |
} |
|
323 |
|
|
294 | 324 |
|
295 | 325 |
#pragma mark - |
296 | 326 |
#pragma mark Memory management |
... | ... | |
309 | 339 |
[barButtonItem release]; |
310 | 340 |
[rootViewController release]; |
311 | 341 |
[window release]; |
342 |
[cachedObjectsDictionary release]; |
|
343 |
[userDefaults release]; |
|
312 | 344 |
[super dealloc]; |
313 | 345 |
} |
314 | 346 |
|
b/Classes/OpenStackRequest.h | ||
---|---|---|
121 | 121 |
- (NSMutableDictionary *)objects; |
122 | 122 |
|
123 | 123 |
+ (OpenStackRequest *)getObjectInfoRequest:(OpenStackAccount *)account container:(Container *)container object:(StorageObject *)object; |
124 |
+ (OpenStackRequest *)getObjectInfoRequest:(OpenStackAccount *)account |
|
125 |
container:(Container *)container |
|
126 |
object:(StorageObject *)object |
|
127 |
version:(NSString *)version; |
|
128 |
+ (OpenStackRequest *)getObjectVersionsRequest:(OpenStackAccount *)account container:(Container *)container object:(StorageObject *)object; |
|
124 | 129 |
+ (OpenStackRequest *)getObjectRequest:(OpenStackAccount *)account container:(Container *)container object:(StorageObject *)object; |
130 |
+ (OpenStackRequest *)getObjectRequest:(OpenStackAccount *)account |
|
131 |
container:(Container *)container |
|
132 |
object:(StorageObject *)object |
|
133 |
version:(NSString *)version; |
|
125 | 134 |
+ (OpenStackRequest *)writeObjectRequest:(OpenStackAccount *)account container:(Container *)container object:(StorageObject *)object; |
126 | 135 |
+ (OpenStackRequest *)writeObjectMetadataRequest:(OpenStackAccount *)account container:(Container *)container object:(StorageObject *)object; |
127 | 136 |
+ (OpenStackRequest *)deleteObjectRequest:(OpenStackAccount *)account container:(Container *)container object:(StorageObject *)object; |
b/Classes/OpenStackRequest.m | ||
---|---|---|
661 | 661 |
return [OpenStackRequest filesRequest:account method:@"HEAD" path:[NSString stringWithFormat:@"/%@/%@",[NSString encodeToPercentEscape:container.name], [NSString encodeToPercentEscape:object.fullPath charactersToEncode:@"!*'();:@&=+$,?%#[]"]]]; |
662 | 662 |
} |
663 | 663 |
|
664 |
+ (OpenStackRequest *)getObjectInfoRequest:(OpenStackAccount *)account |
|
665 |
container:(Container *)container |
|
666 |
object:(StorageObject *)object |
|
667 |
version:(NSString *)version { |
|
668 |
OpenStackRequest *request = [OpenStackRequest getObjectInfoRequest:account container:container object:object]; |
|
669 |
request.url = [NSURL URLWithString:[NSString stringWithFormat:@"%@&version=%@",request.url.description, version]]; |
|
670 |
return request; |
|
671 |
} |
|
672 |
|
|
673 |
+ (OpenStackRequest *)getObjectVersionsRequest:(OpenStackAccount *)account container:(Container *)container object:(StorageObject *)object { |
|
674 |
OpenStackRequest *request = [OpenStackRequest filesRequest:account method:@"GET" path:[NSString stringWithFormat:@"/%@/%@",[NSString encodeToPercentEscape:container.name], [NSString encodeToPercentEscape:object.fullPath charactersToEncode:@"!*'();:@&=+$,?%#[]"]]]; |
|
675 |
|
|
676 |
request.url = [NSURL URLWithString:[NSString stringWithFormat:@"%@&version=list",request.url.description]]; |
|
677 |
return request; |
|
678 |
} |
|
679 |
|
|
664 | 680 |
+ (OpenStackRequest *)getObjectRequest:(OpenStackAccount *)account container:(Container *)container object:(StorageObject *)object { |
665 | 681 |
return [OpenStackRequest filesRequest:account method:@"GET" path:[NSString stringWithFormat:@"/%@/%@",[NSString encodeToPercentEscape:container.name], [NSString encodeToPercentEscape:object.fullPath charactersToEncode:@"!*'();:@&=+$,?%#[]"]]]; |
666 | 682 |
} |
667 | 683 |
|
684 |
+ (OpenStackRequest *)getObjectRequest:(OpenStackAccount *)account |
|
685 |
container:(Container *)container |
|
686 |
object:(StorageObject *)object |
|
687 |
version:(NSString *)version { |
|
688 |
OpenStackRequest *request = [OpenStackRequest getObjectRequest:account container:container object:object]; |
|
689 |
if (version) { |
|
690 |
request.url = [NSURL URLWithString:[NSString stringWithFormat:@"%@&version=%@",request.url.description, version]]; |
|
691 |
} |
|
692 |
return request; |
|
693 |
} |
|
694 |
|
|
668 | 695 |
+ (OpenStackRequest *)writeObjectRequest:(OpenStackAccount *)account container:(Container *)container object:(StorageObject *)object { |
669 | 696 |
NSString *fullPath = object.fullPath; |
670 | 697 |
if ([fullPath characterAtIndex:0] == '/') { |
b/Classes/PithosUtilities.h | ||
---|---|---|
40 | 40 |
@interface PithosUtilities : NSObject |
41 | 41 |
|
42 | 42 |
+ (BOOL)isContentTypeDirectory:(NSString *)contentType; |
43 |
+ (unsigned long long)sizeOfDirectory:(NSString *)directoryPath; |
|
44 |
+ (NSString *)humanReadableSize:(unsigned long long)bytes; |
|
43 | 45 |
|
44 | 46 |
@end |
b/Classes/PithosUtilities.m | ||
---|---|---|
47 | 47 |
[contentType hasPrefix:@"application/folder;"]); |
48 | 48 |
} |
49 | 49 |
|
50 |
+ (unsigned long long)sizeOfDirectory:(NSString *)directoryPath { |
|
51 |
NSFileManager *fileManager = [NSFileManager defaultManager]; |
|
52 |
NSDirectoryEnumerator *directoryEnumerator = [fileManager enumeratorAtPath:directoryPath]; |
|
53 |
unsigned long long directorySize = 0; |
|
54 |
NSString *file; |
|
55 |
while (file = [directoryEnumerator nextObject]) { |
|
56 |
NSDictionary *fileAttributes = [fileManager attributesOfItemAtPath:[NSString stringWithFormat:@"%@/%@",directoryPath,file] error:nil]; |
|
57 |
directorySize += [fileAttributes fileSize]; |
|
58 |
} |
|
59 |
return directorySize; |
|
60 |
} |
|
61 |
|
|
62 |
+ (NSString *)humanReadableSize:(unsigned long long)bytes { |
|
63 |
if (bytes <= 999) { |
|
64 |
return [NSString stringWithFormat:@"%d B", (int)bytes]; |
|
65 |
} else if (bytes <= 999000) { |
|
66 |
return [NSString stringWithFormat:@"%d KB", (int)ceil(bytes / 1000)]; |
|
67 |
} else if (bytes <= 999900000) { |
|
68 |
double megabytes = floor(bytes / 1000000); |
|
69 |
double hundredkilobytes = ceil((bytes - megabytes * 1000000) / 100000); |
|
70 |
if (hundredkilobytes == 10) { |
|
71 |
megabytes++; |
|
72 |
hundredkilobytes = 0; |
|
73 |
} |
|
74 |
if (hundredkilobytes == 0) { |
|
75 |
return [NSString stringWithFormat:@"%d MB", (int)megabytes]; |
|
76 |
} else { |
|
77 |
return [NSString stringWithFormat:@"%d.%d MB", (int)megabytes, (int)hundredkilobytes]; |
|
78 |
} |
|
79 |
} else { |
|
80 |
double gigabytes = floor(bytes / 1000000000); |
|
81 |
double hundredmegabytes = ceil((bytes - gigabytes * 1000000000) / 100000000); |
|
82 |
if (hundredmegabytes == 10) { |
|
83 |
gigabytes++; |
|
84 |
hundredmegabytes = 0; |
|
85 |
} |
|
86 |
if (hundredmegabytes == 0) { |
|
87 |
return [NSString stringWithFormat:@"%d GB", (int)gigabytes]; |
|
88 |
} else { |
|
89 |
return [NSString stringWithFormat:@"%d.%d GB", (int)gigabytes, (int)hundredmegabytes]; |
|
90 |
} |
|
91 |
} |
|
92 |
} |
|
93 |
|
|
50 | 94 |
@end |
b/Classes/SettingsViewController.h | ||
---|---|---|
9 | 9 |
#import <UIKit/UIKit.h> |
10 | 10 |
|
11 | 11 |
@interface SettingsViewController : UITableViewController { |
12 |
NSInteger cacheSection; |
|
12 | 13 |
NSInteger aboutSection; |
13 | 14 |
} |
14 | 15 |
|
b/Classes/SettingsViewController.m | ||
---|---|---|
14 | 14 |
#import "SettingsPluginHandler.h" |
15 | 15 |
#import "SettingsPlugin.h" |
16 | 16 |
#import "AboutViewController.h" |
17 |
#import "OpenStackAppDelegate.h" |
|
18 |
#import "PithosUtilities.h" |
|
17 | 19 |
|
18 | 20 |
#define kPasscodeLock 0 |
19 | 21 |
|
... | ... | |
37 | 39 |
self.navigationItem.title = @"Settings"; |
38 | 40 |
|
39 | 41 |
//aboutSection = 1 + [[SettingsPluginHandler plugins] count]; |
40 |
aboutSection = 1; |
|
42 |
cacheSection = 1; |
|
43 |
aboutSection = 2; |
|
41 | 44 |
UIBarButtonItem *doneButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(doneButtonPressed:)]; |
42 | 45 |
self.navigationItem.rightBarButtonItem = doneButton; |
43 | 46 |
[doneButton release]; |
... | ... | |
47 | 50 |
#pragma mark Table view data source |
48 | 51 |
|
49 | 52 |
- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section { |
50 |
if (section > kPasscodeLock && section < aboutSection) {
|
|
53 |
if (section > kPasscodeLock && section < cacheSection) {
|
|
51 | 54 |
id <SettingsPlugin> plugin = [[SettingsPluginHandler plugins] objectAtIndex:section - 1]; |
52 | 55 |
return [plugin tableView:tableView titleForFooterInSection:section]; |
53 | 56 |
} else { |
... | ... | |
57 | 60 |
|
58 | 61 |
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { |
59 | 62 |
//return 2 + [[SettingsPluginHandler plugins] count]; |
60 |
return 2;
|
|
63 |
return 3;
|
|
61 | 64 |
} |
62 | 65 |
|
63 | 66 |
|
... | ... | |
86 | 89 |
if (cell == nil) { |
87 | 90 |
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease]; |
88 | 91 |
} |
92 |
cell.userInteractionEnabled = YES; |
|
93 |
cell.textLabel.textColor = [UIColor blackColor]; |
|
89 | 94 |
|
90 | 95 |
// Configure the cell... |
91 | 96 |
if (indexPath.section == kPasscodeLock) { |
... | ... | |
110 | 115 |
} |
111 | 116 |
|
112 | 117 |
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; |
118 |
} else if (indexPath.section == cacheSection) { |
|
119 |
OpenStackAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate]; |
|
120 |
NSString *cacheSize = [PithosUtilities humanReadableSize:[PithosUtilities sizeOfDirectory:appDelegate.cacheDirectoryPath]]; |
|
121 |
if ([cacheSize hasPrefix:@"0"]) { |
|
122 |
cell.textLabel.textColor = [UIColor grayColor]; |
|
123 |
cell.userInteractionEnabled = NO; |
|
124 |
} |
|
125 |
cell.textLabel.text = [NSString stringWithFormat:@"Clear Cache (%@)", cacheSize]; |
|
126 |
cell.detailTextLabel.text = @""; |
|
127 |
cell.accessoryType = UITableViewCellAccessoryNone; |
|
113 | 128 |
} else if (indexPath.section == aboutSection) { |
114 | 129 |
cell.textLabel.text = @"About This App"; |
115 | 130 |
cell.detailTextLabel.text = @""; |
... | ... | |
138 | 153 |
vc.settingsViewController = self; |
139 | 154 |
[self.navigationController pushViewController:vc animated:YES]; |
140 | 155 |
[vc release]; |
156 |
} else if (indexPath.section == cacheSection) { |
|
157 |
OpenStackAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate]; |
|
158 |
NSFileManager *fileManager = [NSFileManager defaultManager]; |
|
159 |
NSError *error = nil; |
|
160 |
NSString *file; |
|
161 |
NSDirectoryEnumerator *directoryEnumerator = [fileManager enumeratorAtPath:appDelegate.cacheDirectoryPath]; |
|
162 |
@synchronized(appDelegate.cachedObjectsDictionary) { |
|
163 |
while (file = [directoryEnumerator nextObject]) { |
|
164 |
[fileManager removeItemAtPath:[NSString stringWithFormat:@"%@/%@",appDelegate.cacheDirectoryPath,file] error:&error]; |
|
165 |
if (error) { |
|
166 |
[self alert:@"Error" message:[NSString stringWithFormat:@"Error in removing cached file, %@", error.localizedDescription]]; |
|
167 |
} else { |
|
168 |
for (NSString *key in [appDelegate.cachedObjectsDictionary allKeys]) |
|
169 |
if ([[appDelegate.cachedObjectsDictionary objectForKey:key] isEqualToString:file]) |
|
170 |
[appDelegate.cachedObjectsDictionary removeObjectForKey:key]; |
|
171 |
} |
|
172 |
} |
|
173 |
} |
|
174 |
[self.tableView deselectRowAtIndexPath:indexPath animated:YES]; |
|
175 |
[self.tableView reloadData]; |
|
141 | 176 |
} else if (indexPath.section == aboutSection) { |
142 | 177 |
//This currently is a link to the pithos docs page. It might change in the future to use the AboutViewController; |
143 | 178 |
NSString *aboutURLString = [[NSUserDefaults standardUserDefaults] objectForKey:@"aboutURL"]; |
... | ... | |
146 | 181 |
/*AboutViewController *vc = [[AboutViewController alloc] initWithNibName:@"AboutViewController" bundle:nil]; |
147 | 182 |
[self.navigationController pushViewController:vc animated:YES]; |
148 | 183 |
[vc release];*/ |
149 |
} else { |
|
184 |
} else {
|
|
150 | 185 |
id <SettingsPlugin> plugin = [[SettingsPluginHandler plugins] objectAtIndex:indexPath.section - 1]; |
151 | 186 |
return [plugin tableView:tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath]; |
152 | 187 |
} |
b/Classes/SharingAccountsViewController.m | ||
---|---|---|
190 | 190 |
[self.navigationController pushViewController:vc animated:YES]; |
191 | 191 |
[vc refreshButtonPressed:nil]; |
192 | 192 |
[vc release]; |
193 |
[self.tableView deselectRowAtIndexPath:indexPath animated:NO];
|
|
193 |
[self.tableView deselectRowAtIndexPath:indexPath animated:YES];
|
|
194 | 194 |
} |
195 | 195 |
|
196 | 196 |
|
b/Classes/StorageObject.h | ||
---|---|---|
35 | 35 |
|
36 | 36 |
- (NSString *)humanizedBytes; |
37 | 37 |
+ (StorageObject *)fromJSON:(NSDictionary *)dict; |
38 |
- (void)setPropertiesfromResponseHeaders:(NSDictionary *)headers; |
|
38 | 39 |
|
39 | 40 |
- (BOOL)isPlayableMedia; |
40 | 41 |
|
b/Classes/StorageObject.m | ||
---|---|---|
58 | 58 |
|
59 | 59 |
object.name = [dict objectForKey:@"name"]; // this may be shortened by folder parsing later |
60 | 60 |
object.fullPath = [dict objectForKey:@"name"]; |
61 |
object.hash = [dict objectForKey:@"hash"]; |
|
61 |
object.hash = [dict objectForKey:@"x_object_hash"];
|
|
62 | 62 |
object.bytes = [[dict objectForKey:@"bytes"] intValue]; |
63 | 63 |
object.contentType = [dict objectForKey:@"content_type"]; |
64 | 64 |
object.lastModified = [ComputeModel dateFromString:[dict objectForKey:@"last_modified"]]; |
... | ... | |
77 | 77 |
return object; |
78 | 78 |
} |
79 | 79 |
|
80 |
- (void)setPropertiesfromResponseHeaders:(NSDictionary *)headers { |
|
81 |
self.hash = [headers objectForKey:@"X-Object-Hash"]; |
|
82 |
self.bytes = [[headers objectForKey:@"Content-Length"] intValue]; |
|
83 |
self.contentType = [headers objectForKey:@"Content-Type"]; |
|
84 |
self.lastModified = [headers objectForKey:@"Last-Modified"]; |
|
85 |
self.publicURI = [headers objectForKey:@"X-Object-Public"]; |
|
86 |
self.sharing = [headers objectForKey:@"X-Object-Sharing"]; |
|
87 |
|
|
88 |
self.metadata = [NSMutableDictionary dictionary]; |
|
89 |
for (NSString *key in headers) { |
|
90 |
if ([key hasPrefix:@"X-Object-Meta-"]) { |
|
91 |
NSString *metadataValue = [headers objectForKey:key]; |
|
92 |
NSString *metadataKey = [key substringFromIndex:14]; |
|
93 |
[self.metadata setObject:metadataValue forKey:metadataKey]; |
|
94 |
} |
|
95 |
} |
|
96 |
} |
|
97 |
|
|
80 | 98 |
#pragma mark - |
81 | 99 |
#pragma mark Presentation |
82 | 100 |
|
b/Classes/StorageObjectViewController.h | ||
---|---|---|
13 | 13 |
#import <MessageUI/MessageUI.h> |
14 | 14 |
#import <MessageUI/MFMailComposeViewController.h> |
15 | 15 |
#import "ActivityIndicatorView.h" |
16 |
#import "OpenStackAppDelegate.h" |
|
16 | 17 |
|
17 | 18 |
@class OpenStackAccount, Container, Folder, StorageObject, AnimatedProgressView, FolderViewController; |
18 | 19 |
|
... | ... | |
41 | 42 |
NSInteger cdnURLSection; |
42 | 43 |
NSInteger actionsSection; |
43 | 44 |
NSInteger deleteSection; |
45 |
NSInteger versionsSection; |
|
46 |
NSInteger publicLinkSection; |
|
47 |
NSInteger permissionsSection; |
|
44 | 48 |
|
45 | 49 |
NSString *oldObjectSharingString; |
46 | 50 |
NSString *oldPublicURI; |
47 | 51 |
NSMutableDictionary *permissions; |
52 |
NSIndexPath *actionSelectedIndexPath; |
|
53 |
NSString *versionID; |
|
54 |
OpenStackAppDelegate *appDelegate; |
|
48 | 55 |
} |
49 | 56 |
|
50 | 57 |
@property (nonatomic, retain) OpenStackAccount *account; |
... | ... | |
55 | 62 |
@property (nonatomic, retain) FolderViewController *folderViewController; |
56 | 63 |
@property (nonatomic, retain) NSString *oldPubicURI; |
57 | 64 |
@property (nonatomic, retain) UIDocumentInteractionController *documentInteractionController; |
65 |
@property (nonatomic, retain) NSIndexPath *actionSelectedIndexPath; |
|
66 |
@property (nonatomic, assign) BOOL objectIsReadOnly; |
|
67 |
@property (nonatomic, retain) NSString *versionID; |
|
58 | 68 |
|
59 | 69 |
- (void)setProgress:(float)newProgress; |
60 | 70 |
- (IBAction)homeButtonPressed:(id)sender; |
b/Classes/StorageObjectViewController.m | ||
---|---|---|
25 | 25 |
#import "TextViewCell.h" |
26 | 26 |
#import "NSString+Conveniences.h" |
27 | 27 |
#import "APICallback.h" |
28 |
#import "ObjectVersionsViewController.h" |
|
28 | 29 |
|
29 | 30 |
#define kDetails 0 |
30 | 31 |
#define kMetadata 1 |
31 |
#define kPublic 2 |
|
32 |
#define kPermissions 3 |
|
33 | 32 |
|
34 | 33 |
#define maxMetadataViewableLength 12 |
35 | 34 |
|
... | ... | |
59 | 58 |
@implementation StorageObjectViewController |
60 | 59 |
|
61 | 60 |
@synthesize account, container, folder, object, tableView, folderViewController; |
62 |
@synthesize oldPubicURI, documentInteractionController; |
|
61 |
@synthesize oldPubicURI, documentInteractionController, actionSelectedIndexPath, objectIsReadOnly, versionID;
|
|
63 | 62 |
|
64 | 63 |
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation { |
65 | 64 |
return (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) || (toInterfaceOrientation == UIInterfaceOrientationPortrait); |
... | ... | |
120 | 119 |
} |
121 | 120 |
objectIsPublicSwitch.enabled = NO; |
122 | 121 |
} |
122 |
|
|
123 |
|
|
124 |
downloadProgressView = [[AnimatedProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleDefault]; |
|
125 |
fileDownloading = ([self.account.manager.objectDownloadRequests objectForKey:object.fullPath] != nil) ? YES : NO; |
|
126 |
if (fileDownloading) { |
|
127 |
OpenStackRequest *request = [self.account.manager.objectDownloadRequests objectForKey:object.fullPath]; |
|
128 |
self.actionSelectedIndexPath = [request.userInfo objectForKey:@"actionSelectedIndexPath"]; |
|
129 |
[request setDownloadProgressDelegate:self]; |
|
130 |
} |
|
131 |
appDelegate = [[UIApplication sharedApplication] delegate]; |
|
123 | 132 |
} |
124 | 133 |
|
125 | 134 |
- (void)viewWillAppear:(BOOL)animated { |
... | ... | |
129 | 138 |
NSIndexPath *selection = [self.tableView indexPathForSelectedRow]; |
130 | 139 |
if (selection) |
131 | 140 |
[self.tableView deselectRowAtIndexPath:selection animated:YES]; |
132 |
|
|
133 |
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); |
|
134 |
NSString *documentsDirectory = [paths objectAtIndex:0]; |
|
135 |
NSString *shortPath = [NSString stringWithFormat:@"/%@/%@", self.container.name, self.object.fullPath]; |
|
136 |
NSString *filePath = [documentsDirectory stringByAppendingString:shortPath]; |
|
137 |
|
|
138 |
NSFileManager *fileManager = [NSFileManager defaultManager]; |
|
139 |
fileDownloaded = [fileManager fileExistsAtPath:filePath]; |
|
140 |
|
|
141 |
downloadProgressView = [[AnimatedProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleDefault]; |
|
141 |
if ([appDelegate.cachedObjectsDictionary objectForKey:object.hash] != nil) { |
|
142 |
if ([[NSFileManager defaultManager] fileExistsAtPath:[appDelegate.cachedObjectsDictionary objectForKey:object.hash]]) |
|
143 |
fileDownloaded = YES; |
|
144 |
else { |
|
145 |
fileDownloaded = NO; |
|
146 |
[appDelegate.cachedObjectsDictionary removeObjectForKey:object.hash]; |
|
147 |
[appDelegate saveCacheDictionary]; |
|
148 |
} |
|
149 |
} else { |
|
150 |
fileDownloaded = NO; |
|
151 |
} |
|
142 | 152 |
|
143 | 153 |
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { |
144 | 154 |
CGRect rect = downloadProgressView.frame; |
... | ... | |
147 | 157 |
} |
148 | 158 |
|
149 | 159 |
//[self setBackgroundView]; |
160 |
publicLinkSection = 2; |
|
161 |
permissionsSection = 3; |
|
150 | 162 |
if (self.container.cdnEnabled) { |
151 | 163 |
cdnURLSection = 4; |
152 | 164 |
actionsSection = 5; |
153 | 165 |
deleteSection = 6; |
166 |
versionsSection = 7; |
|
154 | 167 |
} else { |
155 | 168 |
cdnURLSection = -1; |
156 | 169 |
actionsSection = 4; |
157 | 170 |
deleteSection = 5; |
171 |
versionsSection = 6; |
|
158 | 172 |
} |
159 | 173 |
|
160 |
if (account.sharingAccount || account.shared) { |
|
174 |
if (versionID) { |
|
175 |
publicLinkSection = -1; |
|
176 |
permissionsSection = -1; |
|
177 |
versionsSection = -1; |
|
161 | 178 |
deleteSection = -1; |
179 |
actionsSection = 2; |
|
180 |
objectIsReadOnly = YES; |
|
162 | 181 |
} |
182 |
if (account.sharingAccount || account.shared) |
|
183 |
deleteSection = -1; |
|
184 |
|
|
163 | 185 |
|
164 | 186 |
// let's see if we can tweet |
165 | 187 |
UIApplication *app = [UIApplication sharedApplication]; |
... | ... | |
179 | 201 |
#pragma mark Table view data source |
180 | 202 |
|
181 | 203 |
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { |
182 |
if (account.sharingAccount || account.shared) |
|
183 |
return self.container.cdnEnabled ? 6 : 5; |
|
184 |
else |
|
185 |
return self.container.cdnEnabled ? 7 : 6; |
|
204 |
int numberOfSections = 8; |
|
205 |
if (!self.container.cdnEnabled) |
|
206 |
numberOfSections--; |
|
207 |
if (deleteSection < 0) |
|
208 |
numberOfSections--; |
|
209 |
if (versionsSection < 0) |
|
210 |
numberOfSections--; |
|
211 |
if (publicLinkSection < 0) |
|
212 |
numberOfSections--; |
|
213 |
if (permissionsSection < 0) |
|
214 |
numberOfSections--; |
|
215 |
|
|
216 |
return numberOfSections; |
|
186 | 217 |
} |
187 | 218 |
|
188 | 219 |
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { |
189 | 220 |
if (section == kDetails) { |
190 | 221 |
return 4; |
191 | 222 |
} else if (section == kMetadata) { |
192 |
if (objectIsReadOnly) |
|
223 |
if (objectIsReadOnly) {
|
|
193 | 224 |
return [object.metadata count]; |
194 |
else
|
|
225 |
} else {
|
|
195 | 226 |
return 1 + [object.metadata count]; |
227 |
} |
|
196 | 228 |
} else if (section == cdnURLSection) { |
197 | 229 |
return 1; |
198 | 230 |
} else if (section == actionsSection) { |
199 |
return fileDownloaded ? 2 : 1;
|
|
200 |
} else if (section == kPublic) {
|
|
231 |
return 2;
|
|
232 |
} else if (section == publicLinkSection) {
|
|
201 | 233 |
return objectIsPublic ? 2 : 1; |
202 |
} else if (section == kPermissions) {
|
|
203 |
if (account.sharingAccount) |
|
234 |
} else if (section == permissionsSection) {
|
|
235 |
if (account.sharingAccount || objectIsReadOnly)
|
|
204 | 236 |
return [permissions count]; |
205 | 237 |
else |
206 | 238 |
return 1 + [permissions count]; |
... | ... | |
244 | 276 |
} |
245 | 277 |
CGSize stringSize = [object.name sizeWithFont:[UIFont systemFontOfSize:18.0] constrainedToSize:textLabelSize lineBreakMode:UILineBreakModeWordWrap]; |
246 | 278 |
return 22.0 + stringSize.height; |
247 |
} else if (indexPath.section == kPublic && indexPath.row == 1) {
|
|
279 |
} else if (indexPath.section == publicLinkSection && indexPath.row == 1) {
|
|
248 | 280 |
NSString *publicLinkUrl = [NSString stringWithFormat:@"%@%@", |
249 | 281 |
account.pithosPublicLinkURLPrefix, |
250 | 282 |
self.object.publicURI]; |
... | ... | |
259 | 291 |
static NSString *CellIdentifier = @"Cell"; |
260 | 292 |
static NSString *TextViewCellIdentifier = @"TextViewCell"; |
261 | 293 |
|
262 |
if (indexPath.section == kPublic) {
|
|
294 |
if (indexPath.section == publicLinkSection) {
|
|
263 | 295 |
if (indexPath.row == 1) { |
264 | 296 |
TextViewCell *cell = [aTableView dequeueReusableCellWithIdentifier:TextViewCellIdentifier]; |
265 | 297 |
if (cell == nil) { |
... | ... | |
289 | 321 |
cell.detailTextLabel.numberOfLines = 0; |
290 | 322 |
cell.detailTextLabel.lineBreakMode = UILineBreakModeWordWrap; |
291 | 323 |
} |
292 |
|
|
324 |
cell.textLabel.textColor = [UIColor blackColor]; |
|
293 | 325 |
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { |
294 | 326 |
cell.backgroundColor = [UIColor colorWithRed:1 green:1 blue:1 alpha:0.8]; |
295 | 327 |
} |
... | ... | |
348 | 380 |
cell.textLabel.text = metadataKeyCellText; |
349 | 381 |
cell.detailTextLabel.text = metadataValueCellText; |
350 | 382 |
} |
351 |
} else if (indexPath.section == kPublic) {
|
|
383 |
} else if (indexPath.section == publicLinkSection) {
|
|
352 | 384 |
if (indexPath.row == 0) { |
353 | 385 |
cell.textLabel.text = @"Public URL"; |
354 | 386 |
cell.detailTextLabel.text = @""; |
... | ... | |
356 | 388 |
cell.accessoryType = UITableViewCellAccessoryNone; |
357 | 389 |
cell.selectionStyle = UITableViewCellSelectionStyleNone; |
358 | 390 |
} |
359 |
} else if (indexPath.section == kPermissions) {
|
|
391 |
} else if (indexPath.section == permissionsSection) {
|
|
360 | 392 |
if (account.sharingAccount) { |
361 | 393 |
cell.accessoryType = UITableViewCellAccessoryNone; |
362 | 394 |
cell.selectionStyle = UITableViewCellSelectionStyleNone; |
... | ... | |
383 | 415 |
cell.textLabel.text = @""; |
384 | 416 |
cell.detailTextLabel.text = [[NSString stringWithFormat:@"%@/%@", self.container.cdnURL, self.object.fullPath] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; |
385 | 417 |
} else if (indexPath.section == actionsSection) { |
386 |
cell.accessoryView = nil; |
|
387 |
if (performingAction) { |
|
388 |
cell.textLabel.textColor = [UIColor grayColor]; |
|
389 |
cell.selectionStyle = UITableViewCellSelectionStyleNone; |
|
390 |
cell.accessoryType = UITableViewCellAccessoryNone; |
|
418 |
if (fileDownloading) { |
|
419 |
if (actionSelectedIndexPath.row == indexPath.row) { |
|
420 |
cell.accessoryView = downloadProgressView; |
|
421 |
} else { |
|
422 |
cell.textLabel.textColor = [UIColor grayColor]; |
|
423 |
cell.selectionStyle = UITableViewCellSelectionStyleNone; |
|
424 |
} |
|
391 | 425 |
} else { |
392 |
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
|
|
393 |
cell.selectionStyle = UITableViewCellSelectionStyleNone;
|
|
426 |
cell.selectionStyle = UITableViewCellSelectionStyleBlue;
|
|
427 |
cell.accessoryView = nil;
|
|
394 | 428 |
} |
395 |
|
|
396 | 429 |
if (indexPath.row == 0) { |
397 |
if (fileDownloaded) { |
|
398 |
cell.textLabel.text = @"Open File"; |
|
399 |
cell.accessoryType = UITableViewCellAccessoryNone; |
|
400 |
cell.selectionStyle = UITableViewCellSelectionStyleBlue; |
|
401 |
} else { |
|
402 |
if (fileDownloading) { |
|
403 |
cell.accessoryView = downloadProgressView; |
|
404 |
// TODO: if you leave this view while downloading, there's EXC_BAD_ACCESS |
|
405 |
cell.textLabel.text = @"Downloading"; |
|
406 |
} else { |
|
407 |
cell.textLabel.text = @"Download File"; |
|
408 |
} |
|
409 |
} |
|
430 |
cell.textLabel.text = @"Open File"; |
|
431 |
cell.accessoryType = UITableViewCellAccessoryNone; |
|
410 | 432 |
cell.detailTextLabel.text = @""; |
411 | 433 |
|
412 | 434 |
} else if (indexPath.row == 1) { |
413 | 435 |
cell.textLabel.text = @"Email File as Attachment"; |
414 | 436 |
cell.detailTextLabel.text = @""; |
415 |
cell.selectionStyle = UITableViewCellSelectionStyleBlue;
|
|
416 |
} |
|
437 |
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
|
|
438 |
}
|
|
417 | 439 |
} else if (indexPath.section == deleteSection) { |
418 | 440 |
cell.selectionStyle = UITableViewCellSelectionStyleBlue; |
419 | 441 |
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; |
420 | 442 |
cell.textLabel.text = @"Delete Object"; |
421 | 443 |
cell.detailTextLabel.text = @""; |
422 | 444 |
|
445 |
} else if (indexPath.section == versionsSection) { |
|
446 |
cell.selectionStyle = UITableViewCellSelectionStyleBlue; |
|
447 |
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; |
|
448 |
cell.textLabel.text = @"Versions"; |
|
449 |
cell.detailTextLabel.text = @""; |
|
423 | 450 |
} |
424 | 451 |
|
425 | 452 |
return cell; |
... | ... | |
460 | 487 |
vc.object = object; |
461 | 488 |
[self.navigationController pushViewController:vc animated:YES]; |
462 | 489 |
[vc release]; |
463 |
} else if (indexPath.section == kPermissions) {
|
|
490 |
} else if (indexPath.section == permissionsSection) {
|
|
464 | 491 |
EditPermissionsViewController *vc = [[EditPermissionsViewController alloc] initWithNibName:@"EditPermissionsViewController" bundle:nil]; |
465 | 492 |
NSString *user; |
466 | 493 |
|
... | ... | |
497 | 524 |
} else if (indexPath.section == cdnURLSection) { |
498 | 525 |
[cdnURLActionSheet showInView:self.view]; |
499 | 526 |
} else if (indexPath.section == actionsSection) { |
500 |
if (indexPath.row == 0) { |
|
527 |
if (!fileDownloaded) { |
|
528 |
if (!fileDownloading) { |
|
529 |
// download the file |
|
530 |
fileDownloading = YES; |
|
531 |
self.actionSelectedIndexPath = indexPath; |
|
532 |
[self.tableView reloadData]; |
|
533 |
NSMutableDictionary *requestUserInfo = [NSDictionary dictionaryWithObject:indexPath forKey:@"actionSelectedIndexPath"]; |
|
534 |
[[self.account.manager getObject:self.container object:self.object downloadProgressDelegate:self requestUserInfo:requestUserInfo version:versionID] |
|
535 |
success:^(OpenStackRequest *request) { |
|
536 |
fileDownloaded = YES; |
|
537 |
fileDownloading = NO; |
|
538 |
if ([self.navigationController.visibleViewController isEqual:self]) |
|
539 |
[self.tableView.delegate tableView:self.tableView didSelectRowAtIndexPath:indexPath]; |
|
540 |
[self.tableView reloadData]; |
|
541 |
[self.folderViewController.tableView reloadData]; |
|
542 |
} |
|
543 |
failure:^(OpenStackRequest *request) { |
|
544 |
fileDownloaded = NO; |
|
545 |
fileDownloading = NO; |
|
546 |
[self alert:@"File failed to download" request:request]; |
|
547 |
[self.tableView reloadData]; |
|
548 |
}]; |
|
549 |
[self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:indexPath.row inSection:actionsSection]] withRowAnimation:UITableViewRowAnimationNone]; |
|
550 |
} |
|
551 |
} else if (indexPath.row == 0) { |
|
501 | 552 |
if (fileDownloaded) { |
502 |
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); |
|
503 |
NSString *documentsDirectory = [paths objectAtIndex:0]; |
|
504 |
NSString *shortPath = [NSString stringWithFormat:@"/%@/%@", self.container.name, self.object.fullPath]; |
|
505 |
NSString *filePath = [documentsDirectory stringByAppendingString:shortPath]; |
|
506 |
|
|
553 |
NSString *filePath = [appDelegate.cachedObjectsDictionary objectForKey:object.hash]; |
|
507 | 554 |
self.documentInteractionController = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:filePath]]; |
508 | 555 |
self.documentInteractionController.delegate = self; |
556 |
self.documentInteractionController.name = object.name; |
|
509 | 557 |
|
510 | 558 |
UITableViewCell *openFileCell = [self.tableView cellForRowAtIndexPath:indexPath]; |
511 | 559 |
if (![self.documentInteractionController presentOptionsMenuFromRect:openFileCell.frame inView:self.view animated:YES]) { |
... | ... | |
523 | 571 |
|
524 | 572 |
[self.tableView deselectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:actionsSection] animated:YES]; |
525 | 573 |
|
526 |
} else { |
|
527 |
if (!fileDownloading) { |
|
528 |
// download the file |
|
529 |
fileDownloading = YES; |
|
530 |
[self.account.manager getObject:self.container object:self.object downloadProgressDelegate:self]; |
|
531 |
[self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:0 inSection:actionsSection]] withRowAnimation:UITableViewRowAnimationNone]; |
|
532 |
} |
|
533 |
|
|
534 |
} |
|
574 |
} |
|
535 | 575 |
} else if (indexPath.row == 1) { |
536 | 576 |
|
537 | 577 |
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); |
... | ... | |
566 | 606 |
} |
567 | 607 |
} else if (indexPath.section == deleteSection) { |
568 | 608 |
[deleteActionSheet showInView:self.view]; |
609 |
} else if (indexPath.section == versionsSection) { |
|
610 |
ObjectVersionsViewController *vc = [[ObjectVersionsViewController alloc] initWithNibName:@"ObjectVersionsViewController" bundle:nil]; |
|
611 |
vc.account = account; |
|
612 |
vc.container = container; |
|
613 |
vc.object = object; |
|
614 |
[self.navigationController pushViewController:vc animated:YES]; |
|
615 |
[vc release]; |
|
569 | 616 |
} |
570 | 617 |
} |
571 | 618 |
|
... | ... | |
574 | 621 |
if (newProgress >= 1.0) { |
575 | 622 |
fileDownloading = NO; |
576 | 623 |
fileDownloaded = YES; |
577 |
|
|
578 |
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:1 inSection:actionsSection]] withRowAnimation:UITableViewRowAnimationBottom]; |
|
579 |
[self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:0 inSection:actionsSection]] withRowAnimation:UITableViewRowAnimationNone]; |
|
624 |
[self.tableView reloadData]; |
|
580 | 625 |
} |
581 | 626 |
} |
582 | 627 |
|
... | ... | |
713 | 758 |
objectIsPublic = !objectIsPublic; |
714 | 759 |
[[self.account.manager writeObjectMetadata:container object:object] |
715 | 760 |
success:^(OpenStackRequest *request) { |
716 |
NSIndexPath *publicURICellIndexPath = [NSIndexPath indexPathForRow:1 inSection:kPublic];
|
|
761 |
NSIndexPath *publicURICellIndexPath = [NSIndexPath indexPathForRow:1 inSection:publicLinkSection];
|
|
717 | 762 |
if (objectIsPublic) { |
718 |
[[self.account.manager getObjectInfo:container object:object] |
|
763 |
[[self.account.manager getObjectInfo:container object:object version:versionID]
|
|
719 | 764 |
success:^(OpenStackRequest *request) { |
720 | 765 |
[activityIndicatorView removeFromSuperviewAndRelease]; |
721 | 766 |
object.publicURI = [request.responseHeaders objectForKey:@"X-Object-Public"]; |
722 |
NSIndexPath *publicURICellIndexPath = [NSIndexPath indexPathForRow:1 inSection:kPublic];
|
|
767 |
NSIndexPath *publicURICellIndexPath = [NSIndexPath indexPathForRow:1 inSection:publicLinkSection];
|
|
723 | 768 |
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:publicURICellIndexPath] |
724 | 769 |
withRowAnimation:UITableViewRowAnimationBottom]; |
725 | 770 |
} |
... | ... | |
750 | 795 |
#pragma mark Memory management |
751 | 796 |
|
752 | 797 |
- (void)dealloc { |
798 |
if (fileDownloading) { |
|
799 |
OpenStackRequest *request = [self.account.manager.objectDownloadRequests objectForKey:object.fullPath]; |
|
800 |
[request setDownloadProgressDelegate:nil]; |
|
801 |
} |
|
753 | 802 |
[account release]; |
754 | 803 |
[downloadProgressView release]; |
755 | 804 |
[deleteActionSheet release]; |
... | ... | |
759 | 808 |
[objectIsPublicSwitch release]; |
760 | 809 |
[permissions release]; |
761 | 810 |
[documentInteractionController release]; |
811 |
[actionSelectedIndexPath release]; |
|
812 |
[versionID release]; |
|
762 | 813 |
|
763 | 814 |
[super dealloc]; |
764 | 815 |
} |
b/OpenStack.xcodeproj/project.pbxproj | ||
---|---|---|
28 | 28 |
248547AC144C4B8200E48921 /* AccountGroupsViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 248547AA144C4B8200E48921 /* AccountGroupsViewController.xib */; }; |
29 | 29 |
248547BB144C614D00E48921 /* EditAccountGroupsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 248547B9144C613700E48921 /* EditAccountGroupsViewController.m */; }; |
30 | 30 |
248547BC144C614D00E48921 /* EditAccountGroupsViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 248547BA144C613A00E48921 /* EditAccountGroupsViewController.xib */; }; |
31 |
249F004C14BC836A000AB729 /* ObjectVersionsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 249F004A14BC8369000AB729 /* ObjectVersionsViewController.m */; }; |
|
32 |
249F004D14BC836A000AB729 /* ObjectVersionsViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 249F004B14BC8369000AB729 /* ObjectVersionsViewController.xib */; }; |
|
31 | 33 |
24A18E22143DB870003232F1 /* EditMetadataViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 24A18E20143DB870003232F1 /* EditMetadataViewController.m */; }; |
32 | 34 |
24A18E23143DB870003232F1 /* EditMetadataViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 24A18E21143DB870003232F1 /* EditMetadataViewController.xib */; }; |
33 | 35 |
24A18E56143F0429003232F1 /* FolderDetailViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 24A18E54143F0428003232F1 /* FolderDetailViewController.m */; }; |
... | ... | |
1116 | 1118 |
248547B8144C613400E48921 /* EditAccountGroupsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EditAccountGroupsViewController.h; sourceTree = "<group>"; }; |
1117 | 1119 |
248547B9144C613700E48921 /* EditAccountGroupsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EditAccountGroupsViewController.m; sourceTree = "<group>"; }; |
1118 | 1120 |
248547BA144C613A00E48921 /* EditAccountGroupsViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = EditAccountGroupsViewController.xib; sourceTree = "<group>"; }; |
1121 |
249F004914BC8369000AB729 /* ObjectVersionsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ObjectVersionsViewController.h; sourceTree = "<group>"; }; |
|
1122 |
249F004A14BC8369000AB729 /* ObjectVersionsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ObjectVersionsViewController.m; sourceTree = "<group>"; }; |
|
1123 |
249F004B14BC8369000AB729 /* ObjectVersionsViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ObjectVersionsViewController.xib; sourceTree = "<group>"; }; |
|
1119 | 1124 |
24A18E1F143DB86F003232F1 /* EditMetadataViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EditMetadataViewController.h; sourceTree = "<group>"; }; |
1120 | 1125 |
24A18E20143DB870003232F1 /* EditMetadataViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EditMetadataViewController.m; sourceTree = "<group>"; }; |
1121 | 1126 |
24A18E21143DB870003232F1 /* EditMetadataViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = EditMetadataViewController.xib; sourceTree = "<group>"; }; |
... | ... | |
3199 | 3204 |
278906DB12BEDAB5007112B6 /* StorageObjectViewController.h */, |
3200 | 3205 |
278907A112BEF72C007112B6 /* StorageObjectViewController.m */, |
3201 | 3206 |
278906DD12BEDAB5007112B6 /* StorageObjectViewController.xib */, |
Also available in: Unified diff