Statistics
| Branch: | Tag: | Revision:

root / Classes / OpenStackAppDelegate.m @ 54fd5c36

History | View | Annotate | Download (14.4 kB)

1
//
2
//  OpenStackAppDelegate.m
3
//  OpenStack
4
//
5
//  Created by Mike Mayo on 9/30/10.
6
//  The OpenStack project is provided under the Apache 2.0 license.
7
//
8

    
9
#import "OpenStackAppDelegate.h"
10
#import "RootViewController.h"
11
#import "OpenStackAccount.h"
12
#import "Keychain.h"
13

    
14
#import "JSON.h"
15
#import "Server.h"
16
#import "Archiver.h"
17
#import "Provider.h"
18
#import "Image.h"
19

    
20
#import "SettingsPluginHandler.h"
21
#import "AddServerPluginHandler.h"
22
#import "OpenStackAccount.h"
23

    
24
#import "RSSFeedViewController.h"
25
#import "PithosImageViewController.h"
26

    
27
#import "RootViewController.h"
28
#import "PasscodeViewController.h"
29
#import "UIViewController+Conveniences.h"
30
#import "HTNotifier.h"
31
#import "Analytics.h"
32
#import "ProvidersViewController.h"
33

    
34
@implementation OpenStackAppDelegate
35

    
36
@synthesize window;
37
@synthesize navigationController;
38
@synthesize splitViewController;
39
@synthesize masterNavigationController;
40
@synthesize barButtonItem;
41
@synthesize rootViewController;
42
@synthesize cachedObjectsDictionary;
43
@synthesize cacheDictionaryFilePath;
44
@synthesize cacheDirectoryPath;
45

    
46
- (void)loadSettingsDefaults {
47
    
48
    // if settings haven't been set up yet, let's go ahead and set some sensible defaults
49
    
50
    // passcode settings are ALL sensitive, so they will all go in the keychain
51
    if (![Keychain getStringForKey:@"passcode_lock_passcode_on"]) {
52
        [Keychain setString:@"NO" forKey:@"passcode_lock_passcode_on"];
53
    }
54
    
55
    if (![Keychain getStringForKey:@"passcode_lock_simple_passcode_on"]) {
56
        [Keychain setString:@"YES" forKey:@"passcode_lock_simple_passcode_on"];
57
    }
58
    
59
    if (![Keychain getStringForKey:@"passcode_lock_erase_data_on"]) {
60
        [Keychain setString:@"NO" forKey:@"passcode_lock_erase_data_on"];
61
    }
62
    
63
    userDefaults = [[NSUserDefaults standardUserDefaults] retain];
64
    
65
    if (![userDefaults stringForKey:@"api_logging_level"]) {
66
        [userDefaults setValue:@"all" forKey:@"api_logging_level"];
67
    }
68
    
69
    self.cachedObjectsDictionary = [userDefaults objectForKey:@"cachedObjectsDictionary"];
70
    if (!cachedObjectsDictionary) {
71
        self.cachedObjectsDictionary = [NSMutableDictionary dictionary];
72
        [userDefaults setValue:cachedObjectsDictionary forKey:@"cachedObjectsDictionary"];
73
    }
74
    
75
    [userDefaults synchronize];
76
    
77
}
78

    
79
- (void)presentAndRelease:(NSTimer *)timer {
80
    UIViewController *vc = [timer.userInfo objectForKey:@"vc"];
81
    [[self.navigationController topViewController] presentModalViewControllerWithNavigation:vc animated:NO];
82
    [vc release];
83
}
84

    
85
- (void)showPasscodeLock {
86
    if ([[Keychain getStringForKey:@"passcode_lock_passcode_on"] isEqualToString:@"YES"]) {
87
        PasscodeViewController *vc = [[PasscodeViewController alloc] initWithNibName:@"PasscodeViewController" bundle:nil];
88
        vc.mode = kModeEnterPasscode;
89
        //vc.rootViewController = self;
90
        if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
91
            vc.modalPresentationStyle = UIModalPresentationFullScreen;
92
        }                
93
        
94
        if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
95
            OpenStackAppDelegate *app = [[UIApplication sharedApplication] delegate];
96
            for (UIViewController *svc in app.splitViewController.viewControllers) {
97
                svc.view.alpha = 0.0;
98
            }
99
            
100
            // for some reason, this needs to be delayed
101
            [NSTimer scheduledTimerWithTimeInterval:0.3 target:self selector:@selector(presentAndRelease:) userInfo:[NSDictionary dictionaryWithObject:vc forKey:@"vc"] repeats:NO];
102
            
103
        } else {
104
            [[self.navigationController topViewController] presentModalViewControllerWithNavigation:vc animated:NO];
105
            [vc release];
106
        }
107
    }
108
}
109

    
110
#pragma mark -
111
#pragma mark Application lifecycle
112

    
113
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    
114
    // Override point for customization after application launch.
115
//    [self setupDependencies];
116
        
117
    [self loadSettingsDefaults];
118
        
119
    rootViewController = [navigationController.viewControllers objectAtIndex:0];
120
    OpenStackAppDelegate <UINavigationControllerDelegate> *delegate = (OpenStackAppDelegate <UINavigationControllerDelegate> *)self;
121
    navigationController.delegate = delegate;
122
        
123
    // Add the navigation controller's view to the window and display.
124
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
125
        
126
        /*RSSFeedViewController *vc = [[RSSFeedViewController alloc] initWithNibName:@"RSSFeedViewController" bundle:nil];
127
        vc.feed = [NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:@"Cloud Servers Status", @"feed://status.rackspacecloud.com/cloudservers/rss.xml", kCloudServersIcon, nil] forKeys:[NSArray arrayWithObjects:@"name", @"url", @"logo", nil]];*/
128
        
129
        PithosImageViewController *vc = [[PithosImageViewController alloc] initWithNibName:@"PithosImageViewController" bundle:nil];
130
        self.masterNavigationController = [[[UINavigationController alloc] initWithRootViewController:vc] autorelease];
131
        self.masterNavigationController.navigationBar.tintColor = self.navigationController.navigationBar.tintColor;
132
        self.masterNavigationController.navigationBar.translucent = self.navigationController.navigationBar.translucent;
133
        self.masterNavigationController.navigationBar.opaque = self.navigationController.navigationBar.opaque;
134
        self.masterNavigationController.navigationBar.barStyle = self.navigationController.navigationBar.barStyle;
135
        
136
        self.splitViewController.delegate = [navigationController.viewControllers objectAtIndex:0];
137
        self.splitViewController.viewControllers = [NSArray arrayWithObjects:self.navigationController, self.masterNavigationController, nil];
138
        
139
        [window addSubview:splitViewController.view];
140
        [window makeKeyAndVisible];
141
        [vc release];
142
    } else {
143
        
144
        [window addSubview:navigationController.view];
145
        [window makeKeyAndVisible];
146
    }
147

    
148
    serviceUnavailableObserver = [[NSNotificationCenter defaultCenter] addObserverForName:@"serviceUnavailable" object:nil
149
                                                                           queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification* notification) 
150
    {
151
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Service Unavailable" message:@"The API is currently unavailable.  Please try again later." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
152
        [alert show];
153
        [alert release];
154
        [[NSNotificationCenter defaultCenter] removeObserver:serviceUnavailableObserver];
155
    }];
156
    
157
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
158
    self.cacheDirectoryPath = [[paths objectAtIndex:0] stringByAppendingPathComponent:@"DownloadedFiles"];
159
    NSFileManager *fileManager = [NSFileManager defaultManager];
160
    NSError *error = nil;
161
    [fileManager createDirectoryAtPath:cacheDirectoryPath withIntermediateDirectories:YES attributes:nil error:&error];
162
    if (error) {
163
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error"
164
                                                        message:[NSString stringWithFormat:@"Error in creating cache directory\n%@",error.localizedDescription]
165
                                                       delegate:nil 
166
                                              cancelButtonTitle:@"OK" otherButtonTitles:nil];
167
        [alert show];
168
        [alert release];
169
    }
170

    
171
    return YES;
172
}
173

    
174
//- (void) setupDependencies {
175
//#if TARGET_OS_EMBEDDED
176
//    
177
//    NSString *path = [[NSBundle bundleForClass:[self class]] pathForResource:@"Constants" ofType:@"plist"];
178
//    
179
//    if ([[NSFileManager defaultManager] fileExistsAtPath:path]){
180
//        
181
//        NSDictionary *constants = [NSDictionary dictionaryWithContentsOfFile:path];
182
//        
183
//        [HTNotifier startNotifierWithAPIKey:[constants objectForKey:@"HOPTOAD_ACCOUNT_KEY"]
184
//                            environmentName:HTNotifierAppStoreEnvironment];
185
//        [[GANTracker sharedTracker] startTrackerWithAccountID:[constants objectForKey:@"ANALYTICS_ACCOUNT_KEY"] dispatchPeriod:10 delegate:nil];
186
//        
187
//        // track the app version
188
//        NSString *version = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"];
189
//        [[GANTracker sharedTracker] setCustomVariableAtIndex:1 name:@"app_version" value:version withError:nil];
190
//        
191
//        DispatchAnalytics();
192
//
193
//    } else {
194
//        [HTNotifier startNotifierWithAPIKey:@"HOPTOAD_ACCOUNT_KEY" environmentName:HTNotifierAppStoreEnvironment];
195
//        [[GANTracker sharedTracker] startTrackerWithAccountID:@"ANALYTICS_ACCOUNT_KEY" dispatchPeriod:10 delegate:nil];
196
//    }
197
//    
198
//#endif
199
//}
200

    
201

    
202
- (void)applicationWillResignActive:(UIApplication *)application {
203
    
204
//    DispatchAnalytics();
205
}
206

    
207

    
208
- (void)applicationDidEnterBackground:(UIApplication *)application {
209
    /*
210
     Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 
211
     If your application supports background execution, called instead of applicationWillTerminate: when the user quits.
212
     */
213
}
214

    
215

    
216
- (void)applicationWillEnterForeground:(UIApplication *)application {
217
    /*
218
     Called as part of  transition from the background to the inactive state: here you can undo many of the changes made on entering the background.
219
     */
220
}
221

    
222

    
223
- (void)applicationDidBecomeActive:(UIApplication *)application {
224
    
225
    /* 
226
	 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.
227
	*/
228
    [userDefaults setBool:NO forKey:@"already_failed_on_connection"];
229
    [userDefaults synchronize];
230
    
231
    [self showPasscodeLock];
232
    //DispatchAnalytics();
233
}
234

    
235

    
236
- (void)applicationWillTerminate:(UIApplication *)application {    
237
    /*
238
     Called when the application is about to terminate.
239
     See also applicationDidEnterBackground:.
240
     */
241
    // TODO: perhaps this is a good place to release all the stuff allocated in
242
    // +(void)initialize methods all over the place
243
//    [[SettingsPluginHandler plugins] release];
244
//    [[AddServerPluginHandler plugins] release];
245
//    [[OpenStackAccount accounts] release];
246
}
247

    
248
- (void) navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated{
249
    
250
    TrackViewController(viewController);
251
}
252

    
253
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url {
254
    if (!url)
255
        return NO;
256

    
257
    NSString *host = [url host];
258
	NSString *query = [url query];
259

    
260
    if ([host hasPrefix:@"login"] && query) {
261
        // user=
262
        NSString *authUser;
263
        NSRange userRange = [query rangeOfString:@"user=" options:NSCaseInsensitiveSearch];
264
        if (userRange.length == 0)
265
            // XXX maybe show an error message?
266
            return NO;
267
        NSUInteger authUserStartLocation = userRange.location + userRange.length;
268
        NSRange userEndRange = [query rangeOfString:@"-" options:NSCaseInsensitiveSearch 
269
                                              range:NSMakeRange(authUserStartLocation, [query length] - authUserStartLocation)];
270
        if (userEndRange.length) {
271
            authUser = [[query substringWithRange:NSMakeRange(authUserStartLocation, userEndRange.location - authUserStartLocation)]
272
                        stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
273
        } else {
274
            authUser = [[query substringFromIndex:authUserStartLocation]
275
                        stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
276
        }
277
        // token=
278
        NSString *authToken;
279
        NSRange tokenRange = [query rangeOfString:@"token=" options:NSCaseInsensitiveSearch];
280
        if (tokenRange.length == 0)
281
            // XXX maybe show an error message?
282
            return NO;
283
        NSUInteger authTokenStartLocation = tokenRange.location + tokenRange.length;
284
        NSRange tokenEndRange = [query rangeOfString:@"&" options:NSCaseInsensitiveSearch 
285
                                               range:NSMakeRange(authTokenStartLocation, [query length] - authTokenStartLocation)];
286
        if (tokenEndRange.length) {
287
            authToken = [[query substringWithRange:NSMakeRange(authTokenStartLocation, tokenEndRange.location - authTokenStartLocation)]
288
                         stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
289
        } else {
290
            authToken = [[query substringFromIndex:authTokenStartLocation]
291
                         stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
292
        }
293
        
294
        if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
295
            if (authToken)
296
                [masterNavigationController.visibleViewController setValue:authToken forKey:@"apiKey"];
297
            if (authUser)
298
                [masterNavigationController.visibleViewController setValue:authUser forKey:@"userName"];
299
            [((UITableViewController *)masterNavigationController.visibleViewController).tableView reloadData];        
300
        } else {
301
            if (authToken)
302
                [navigationController.visibleViewController setValue:authToken forKey:@"apiKey"];
303
            if (authUser)
304
                [navigationController.visibleViewController setValue:authUser forKey:@"userName"];
305
            [((UITableViewController *)navigationController.visibleViewController).tableView reloadData];        
306
        }
307
    }
308
    // XXX else maybe show an error message?
309
    
310
    return YES;
311
}
312

    
313
#pragma mark - persistence
314

    
315
- (void)saveCacheDictionary {
316
    [userDefaults setObject:cachedObjectsDictionary forKey:@"cachedObjectsDictionary"];
317
    [userDefaults synchronize];
318
}
319

    
320

    
321
#pragma mark -
322
#pragma mark Memory management
323

    
324
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
325
    /*
326
     Free up as much memory as possible by purging cached data objects that can be recreated (or reloaded from disk) later.
327
     */
328
}
329

    
330

    
331
- (void)dealloc {
332
	[navigationController release];
333
    [splitViewController release];
334
    [masterNavigationController release];
335
    [barButtonItem release];
336
    [rootViewController release];
337
	[window release];
338
    [cachedObjectsDictionary release];
339
    [userDefaults release];
340
	[super dealloc];
341
}
342

    
343

    
344
@end
345