2014-10-02 15:02:47 +00:00
|
|
|
/*
|
|
|
|
Copyright 2014 OpenMarket Ltd
|
|
|
|
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
you may not use this file except in compliance with the License.
|
|
|
|
You may obtain a copy of the License at
|
|
|
|
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
See the License for the specific language governing permissions and
|
|
|
|
limitations under the License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#import "AppDelegate.h"
|
2014-12-12 09:49:15 +00:00
|
|
|
#import "APNSHandler.h"
|
2014-10-03 17:26:39 +00:00
|
|
|
#import "RoomViewController.h"
|
2015-01-05 15:53:41 +00:00
|
|
|
#import "SettingsViewController.h"
|
2015-01-20 12:33:01 +00:00
|
|
|
#import "ContactManager.h"
|
2015-04-14 08:55:18 +00:00
|
|
|
#import "RageShakeManager.h"
|
2014-10-02 15:02:47 +00:00
|
|
|
|
2015-02-12 10:16:28 +00:00
|
|
|
#import "AFNetworkReachabilityManager.h"
|
|
|
|
|
2015-04-30 14:19:12 +00:00
|
|
|
#import <AudioToolbox/AudioToolbox.h>
|
|
|
|
|
2015-02-04 23:16:11 +00:00
|
|
|
#define MAKE_STRING(x) #x
|
|
|
|
#define MAKE_NS_STRING(x) @MAKE_STRING(x)
|
2015-02-04 17:18:38 +00:00
|
|
|
|
2015-02-18 16:40:55 +00:00
|
|
|
@interface AppDelegate () <UISplitViewControllerDelegate> {
|
|
|
|
// Reachability observer
|
|
|
|
id reachabilityObserver;
|
2015-04-17 13:45:32 +00:00
|
|
|
|
|
|
|
// matrix session observer used to detect new opened sessions.
|
|
|
|
id matrixSessionStateObserver;
|
2015-04-30 14:19:12 +00:00
|
|
|
|
|
|
|
// matrix account observer used to detect new added accounts.
|
|
|
|
id matrixAccountsObserver;
|
2015-02-18 16:40:55 +00:00
|
|
|
}
|
2014-10-02 15:02:47 +00:00
|
|
|
|
2015-04-30 14:19:12 +00:00
|
|
|
@property (strong, nonatomic) MXKAlert *mxInAppNotification;
|
|
|
|
|
2014-10-02 15:02:47 +00:00
|
|
|
@end
|
|
|
|
|
|
|
|
@implementation AppDelegate
|
|
|
|
|
2014-10-08 12:14:12 +00:00
|
|
|
#pragma mark -
|
|
|
|
|
|
|
|
+ (AppDelegate*)theDelegate {
|
|
|
|
return (AppDelegate*)[[UIApplication sharedApplication] delegate];
|
|
|
|
}
|
2015-02-04 17:18:38 +00:00
|
|
|
|
|
|
|
#pragma mark -
|
|
|
|
|
|
|
|
- (NSString*)appVersion {
|
|
|
|
if (!_appVersion) {
|
|
|
|
_appVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"];
|
|
|
|
}
|
|
|
|
|
|
|
|
return _appVersion;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString*)build {
|
|
|
|
if (!_build) {
|
|
|
|
NSString *buildBranch = nil;
|
|
|
|
NSString *buildNumber = nil;
|
|
|
|
// Check whether GIT_BRANCH and BUILD_NUMBER were provided during compilation in command line argument.
|
2015-02-04 23:16:11 +00:00
|
|
|
#ifdef GIT_BRANCH
|
|
|
|
buildBranch = MAKE_NS_STRING(GIT_BRANCH);
|
2015-02-04 17:18:38 +00:00
|
|
|
#endif
|
2015-02-04 23:16:11 +00:00
|
|
|
#ifdef BUILD_NUMBER
|
|
|
|
buildNumber = [NSString stringWithFormat:@"#%d", BUILD_NUMBER];
|
2015-02-04 17:18:38 +00:00
|
|
|
#endif
|
|
|
|
if (buildBranch && buildNumber) {
|
|
|
|
_build = [NSString stringWithFormat:@"%@ %@", buildBranch, buildNumber];
|
|
|
|
} else if (buildNumber){
|
|
|
|
_build = buildNumber;
|
|
|
|
} else {
|
2015-02-04 23:16:11 +00:00
|
|
|
_build = buildBranch ? buildBranch : @"(no build info)";
|
2015-02-04 17:18:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return _build;
|
|
|
|
}
|
|
|
|
|
2015-02-18 16:40:55 +00:00
|
|
|
- (void)setIsOffline:(BOOL)isOffline {
|
|
|
|
if (isOffline) {
|
|
|
|
// Add observer to leave this state automatically.
|
|
|
|
reachabilityObserver = [[NSNotificationCenter defaultCenter] addObserverForName:AFNetworkingReachabilityDidChangeNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
|
|
|
|
NSNumber *statusItem = note.userInfo[AFNetworkingReachabilityNotificationStatusItem];
|
|
|
|
if (statusItem) {
|
|
|
|
AFNetworkReachabilityStatus reachabilityStatus = statusItem.integerValue;
|
|
|
|
if (reachabilityStatus == AFNetworkReachabilityStatusReachableViaWiFi || reachabilityStatus == AFNetworkReachabilityStatusReachableViaWWAN) {
|
|
|
|
self.isOffline = NO;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}];
|
|
|
|
} else {
|
|
|
|
// Release potential observer
|
|
|
|
if (reachabilityObserver) {
|
|
|
|
[[NSNotificationCenter defaultCenter] removeObserver:reachabilityObserver];
|
|
|
|
reachabilityObserver = nil;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
_isOffline = isOffline;
|
|
|
|
}
|
|
|
|
|
2015-02-12 10:16:28 +00:00
|
|
|
#pragma mark - UIApplicationDelegate
|
2014-10-02 15:02:47 +00:00
|
|
|
|
|
|
|
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
|
2015-04-30 14:19:12 +00:00
|
|
|
|
2014-10-02 15:02:47 +00:00
|
|
|
// Override point for customization after application launch.
|
2014-10-08 16:55:26 +00:00
|
|
|
if ([self.window.rootViewController isKindOfClass:[MasterTabBarController class]])
|
2014-10-03 17:26:39 +00:00
|
|
|
{
|
2014-10-08 16:55:26 +00:00
|
|
|
self.masterTabBarController = (MasterTabBarController*)self.window.rootViewController;
|
|
|
|
self.masterTabBarController.delegate = self;
|
2014-10-03 17:26:39 +00:00
|
|
|
|
2015-04-17 13:45:32 +00:00
|
|
|
// By default the "Home" tab is focused
|
2014-10-08 16:55:26 +00:00
|
|
|
[self.masterTabBarController setSelectedIndex:TABBAR_HOME_INDEX];
|
2014-10-03 17:26:39 +00:00
|
|
|
|
2014-10-08 16:55:26 +00:00
|
|
|
UIViewController* recents = [self.masterTabBarController.viewControllers objectAtIndex:TABBAR_RECENTS_INDEX];
|
2014-10-03 17:26:39 +00:00
|
|
|
if ([recents isKindOfClass:[UISplitViewController class]]) {
|
|
|
|
UISplitViewController *splitViewController = (UISplitViewController *)recents;
|
|
|
|
UINavigationController *navigationController = [splitViewController.viewControllers lastObject];
|
2014-12-16 17:30:49 +00:00
|
|
|
|
|
|
|
// IOS >= 8
|
|
|
|
if ([splitViewController respondsToSelector:@selector(displayModeButtonItem)]) {
|
|
|
|
navigationController.topViewController.navigationItem.leftBarButtonItem = splitViewController.displayModeButtonItem;
|
2015-01-12 08:17:04 +00:00
|
|
|
|
|
|
|
// on IOS 8 iPad devices, force to display the primary and the secondary viewcontroller
|
|
|
|
// to avoid empty room View Controller in portrait orientation
|
|
|
|
// else, the user cannot select a room
|
|
|
|
// shouldHideViewController delegate method is also implemented
|
|
|
|
if ([splitViewController respondsToSelector:@selector(preferredDisplayMode)] && [(NSString*)[UIDevice currentDevice].model hasPrefix:@"iPad"]) {
|
|
|
|
splitViewController.preferredDisplayMode = UISplitViewControllerDisplayModeAllVisible;
|
|
|
|
}
|
2014-12-16 17:30:49 +00:00
|
|
|
}
|
|
|
|
|
2014-10-03 17:26:39 +00:00
|
|
|
splitViewController.delegate = self;
|
2014-10-09 09:26:12 +00:00
|
|
|
} else {
|
|
|
|
// Patch missing image in tabBarItem for iOS < 8.0
|
|
|
|
recents.tabBarItem.image = [[UIImage imageNamed:@"tab_recents"] imageWithRenderingMode:UIImageRenderingModeAutomatic];
|
2014-10-03 17:26:39 +00:00
|
|
|
}
|
2014-12-12 09:49:15 +00:00
|
|
|
|
2015-02-02 15:43:47 +00:00
|
|
|
_isAppForeground = NO;
|
|
|
|
|
2014-12-16 21:54:26 +00:00
|
|
|
// Retrieve custom configuration
|
|
|
|
NSString* userDefaults = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UserDefaults"];
|
|
|
|
NSString *defaultsPathFromApp = [[NSBundle mainBundle] pathForResource:userDefaults ofType:@"plist"];
|
|
|
|
NSDictionary *defaults = [NSDictionary dictionaryWithContentsOfFile:defaultsPathFromApp];
|
|
|
|
[[NSUserDefaults standardUserDefaults] registerDefaults:defaults];
|
|
|
|
[[NSUserDefaults standardUserDefaults] synchronize];
|
|
|
|
|
2015-04-30 14:19:12 +00:00
|
|
|
// Add matrix observers and initialize matrix sessions.
|
|
|
|
[self initMatrixSessions];
|
2014-10-02 15:02:47 +00:00
|
|
|
}
|
2015-01-30 08:05:15 +00:00
|
|
|
|
|
|
|
// clear the notifications counter
|
|
|
|
[self clearNotifications];
|
|
|
|
|
2014-10-02 15:02:47 +00:00
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)applicationWillResignActive:(UIApplication *)application {
|
|
|
|
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
|
|
|
|
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
|
2014-10-31 17:54:32 +00:00
|
|
|
if (self.errorNotification) {
|
|
|
|
[self.errorNotification dismiss:NO];
|
|
|
|
self.errorNotification = nil;
|
|
|
|
}
|
2014-12-09 17:21:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)applicationDidEnterBackground:(UIApplication *)application {
|
|
|
|
// 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.
|
|
|
|
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
|
2015-01-12 13:19:23 +00:00
|
|
|
|
2015-02-12 10:16:28 +00:00
|
|
|
// Stop reachability monitoring
|
2015-02-18 16:40:55 +00:00
|
|
|
self.isOffline = NO;
|
2015-02-12 10:16:28 +00:00
|
|
|
[[AFNetworkReachabilityManager sharedManager] stopMonitoring];
|
|
|
|
|
2015-04-30 14:19:12 +00:00
|
|
|
// check if some media must be released to reduce the cache size
|
2015-04-02 11:50:11 +00:00
|
|
|
[MXKMediaManager reduceCacheSizeToInsert:0];
|
2015-04-30 14:19:12 +00:00
|
|
|
|
|
|
|
// Hide potential notification
|
|
|
|
if (self.mxInAppNotification) {
|
|
|
|
[self.mxInAppNotification dismiss:NO];
|
|
|
|
self.mxInAppNotification = nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Suspend all running matrix sessions
|
|
|
|
NSArray *mxAccounts = [MXKAccountManager sharedManager].accounts;
|
|
|
|
for (MXKAccount *account in mxAccounts) {
|
|
|
|
[account pauseInBackgroundTask];
|
|
|
|
}
|
2015-01-30 08:05:15 +00:00
|
|
|
|
|
|
|
// clear the notifications counter
|
|
|
|
[self clearNotifications];
|
2015-02-02 15:43:47 +00:00
|
|
|
|
|
|
|
_isAppForeground = NO;
|
2014-10-02 15:02:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)applicationWillEnterForeground:(UIApplication *)application {
|
|
|
|
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
|
2015-01-30 08:05:15 +00:00
|
|
|
// clear the notifications counter
|
|
|
|
[self clearNotifications];
|
2015-02-02 15:43:47 +00:00
|
|
|
|
|
|
|
_isAppForeground = YES;
|
2014-10-02 15:02:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)applicationDidBecomeActive:(UIApplication *)application {
|
|
|
|
// 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.
|
2015-02-12 10:16:28 +00:00
|
|
|
|
|
|
|
// Start monitoring reachability
|
|
|
|
[[AFNetworkReachabilityManager sharedManager] startMonitoring];
|
|
|
|
|
2015-04-30 14:19:12 +00:00
|
|
|
// Resume all existing matrix sessions
|
|
|
|
NSArray *mxAccounts = [MXKAccountManager sharedManager].accounts;
|
|
|
|
for (MXKAccount *account in mxAccounts) {
|
|
|
|
[account resume];
|
|
|
|
}
|
2015-01-20 12:33:01 +00:00
|
|
|
|
|
|
|
// refresh the contacts list
|
2015-01-26 10:05:53 +00:00
|
|
|
[[ContactManager sharedManager] fullRefresh];
|
2015-02-02 15:43:47 +00:00
|
|
|
|
|
|
|
_isAppForeground = YES;
|
2015-03-10 13:15:02 +00:00
|
|
|
|
|
|
|
// check if the app crashed last time
|
|
|
|
if ([MXLogger crashLog]) {
|
2015-04-14 08:55:18 +00:00
|
|
|
[[RageShakeManager sharedManager] promptCrashReportInViewController:self.masterTabBarController.selectedViewController];
|
2015-03-10 13:15:02 +00:00
|
|
|
}
|
2014-10-02 15:02:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)applicationWillTerminate:(UIApplication *)application {
|
|
|
|
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
|
|
|
|
}
|
|
|
|
|
2014-12-12 09:49:15 +00:00
|
|
|
#pragma mark - APNS methods
|
|
|
|
|
|
|
|
- (void)registerUserNotificationSettings {
|
2014-12-18 15:29:34 +00:00
|
|
|
if (!isAPNSRegistered) {
|
|
|
|
if ([[UIApplication sharedApplication] respondsToSelector:@selector(registerUserNotificationSettings:)]) {
|
|
|
|
// Registration on iOS 8 and later
|
|
|
|
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:(UIRemoteNotificationTypeBadge
|
|
|
|
|UIRemoteNotificationTypeSound
|
|
|
|
|UIRemoteNotificationTypeAlert) categories:nil];
|
|
|
|
[[UIApplication sharedApplication] registerUserNotificationSettings:settings];
|
|
|
|
} else {
|
|
|
|
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationType)(UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeBadge)];
|
|
|
|
}
|
|
|
|
}
|
2014-12-12 09:49:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings
|
|
|
|
{
|
|
|
|
[application registerForRemoteNotifications];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)application:(UIApplication*)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken {
|
2015-02-24 12:49:05 +00:00
|
|
|
NSLog(@"[AppDelegate] Got APNS token!");
|
2014-12-12 09:49:15 +00:00
|
|
|
|
|
|
|
APNSHandler* apnsHandler = [APNSHandler sharedHandler];
|
|
|
|
[apnsHandler setDeviceToken:deviceToken];
|
|
|
|
|
|
|
|
// force send the push token once per app start
|
|
|
|
if (!isAPNSRegistered) {
|
|
|
|
apnsHandler.isActive = YES;
|
|
|
|
}
|
|
|
|
isAPNSRegistered = YES;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)application:(UIApplication*)app didFailToRegisterForRemoteNotificationsWithError:(NSError*)error {
|
2015-02-24 12:49:05 +00:00
|
|
|
NSLog(@"[AppDelegate] Failed to register for APNS: %@", error);
|
2014-12-12 09:49:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)application:(UIApplication*)application didReceiveRemoteNotification:(NSDictionary*)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
|
|
|
|
#ifdef DEBUG
|
|
|
|
// log the full userInfo only in DEBUG
|
2015-02-24 12:49:05 +00:00
|
|
|
NSLog(@"[AppDelegate] APNS: %@", userInfo);
|
2014-12-12 09:49:15 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
completionHandler(UIBackgroundFetchResultNoData);
|
2015-02-13 15:16:27 +00:00
|
|
|
|
2015-02-19 17:23:24 +00:00
|
|
|
// Jump to the concerned room only if the app is transitioning from the background
|
|
|
|
if ([UIApplication sharedApplication].applicationState == UIApplicationStateInactive) {
|
|
|
|
// Look for the room id
|
|
|
|
NSString* roomId = [userInfo objectForKey:@"room_id"];
|
|
|
|
if (roomId.length) {
|
|
|
|
[self.masterTabBarController showRoom:roomId];
|
|
|
|
}
|
2015-02-13 15:16:27 +00:00
|
|
|
}
|
2014-12-12 09:49:15 +00:00
|
|
|
}
|
|
|
|
|
2015-04-30 14:19:12 +00:00
|
|
|
#pragma mark - Matrix sessions handling
|
|
|
|
|
|
|
|
- (void)initMatrixSessions {
|
|
|
|
|
|
|
|
// Register matrix session state observer in order to handle new opened session
|
|
|
|
matrixSessionStateObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMXSessionStateDidChangeNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {
|
|
|
|
|
|
|
|
MXSession *mxSession = (MXSession*)notif.object;
|
|
|
|
|
|
|
|
// Check whether the concerned session is a new one
|
|
|
|
if (mxSession.state == MXSessionStateInitialised) {
|
|
|
|
|
|
|
|
// Report this new session to contact manager
|
|
|
|
[[ContactManager sharedManager] setMxSession:mxSession];
|
|
|
|
|
|
|
|
// Update all view controllers thanks to tab bar controller
|
|
|
|
self.masterTabBarController.mxSession = mxSession;
|
|
|
|
|
|
|
|
// Check whether the app user wants notifications on new events
|
|
|
|
if ([[MXKAppSettings standardAppSettings] enableInAppNotifications]) {
|
|
|
|
[self enableInAppNotifications:YES];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}];
|
|
|
|
|
|
|
|
// Register an observer in order to handle new account
|
|
|
|
matrixAccountsObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMXKAccountManagerDidAddAccountNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {
|
|
|
|
|
|
|
|
NSString *userId = (NSString*)notif.object;
|
|
|
|
|
|
|
|
// TODO GFO: handle here multi sessions
|
|
|
|
|
|
|
|
// Launch matrix session for this new account
|
|
|
|
MXKAccount *account = [[MXKAccountManager sharedManager] accountForUserId:userId];
|
|
|
|
if (account) {
|
|
|
|
[self registerUserNotificationSettings];
|
|
|
|
|
|
|
|
// Use MXFileStore as MXStore to permanently store events.
|
|
|
|
MXFileStore *mxFileStore = [[MXFileStore alloc] init];
|
|
|
|
[account openSessionWithStore:mxFileStore];
|
|
|
|
}
|
|
|
|
}];
|
|
|
|
|
|
|
|
// Observe settings changes
|
|
|
|
[[MXKAppSettings standardAppSettings] addObserver:self forKeyPath:@"enableInAppNotifications" options:0 context:nil];
|
|
|
|
[[MXKAppSettings standardAppSettings] addObserver:self forKeyPath:@"showAllEventsInRoomHistory" options:0 context:nil];
|
|
|
|
|
|
|
|
// Check whether we're logged in
|
|
|
|
NSArray *mxAccounts = [MXKAccountManager sharedManager].accounts;
|
|
|
|
if (mxAccounts.count) {
|
|
|
|
|
|
|
|
[self registerUserNotificationSettings];
|
|
|
|
|
|
|
|
// When user is already logged, we launch the app on Recents
|
|
|
|
[self.masterTabBarController setSelectedIndex:TABBAR_RECENTS_INDEX];
|
|
|
|
|
|
|
|
// Launch a matrix session only for the first account (TODO launch a session for each account).
|
|
|
|
// Use MXFileStore as MXStore to permanently store events.
|
|
|
|
MXFileStore *mxFileStore = [[MXFileStore alloc] init];
|
|
|
|
[mxAccounts.firstObject openSessionWithStore:mxFileStore];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)reloadMatrixSessions:(BOOL)clearCache {
|
|
|
|
|
|
|
|
// Reload all running matrix sessions
|
|
|
|
NSArray *mxAccounts = [MXKAccountManager sharedManager].accounts;
|
|
|
|
for (MXKAccount *account in mxAccounts) {
|
|
|
|
|
|
|
|
if (account.mxSession) {
|
|
|
|
id<MXStore> store = account.mxSession.store;
|
|
|
|
|
2015-05-05 16:06:50 +00:00
|
|
|
[MXKRoomDataSourceManager removeSharedManagerForMatrixSession:account.mxSession];
|
2015-04-30 14:19:12 +00:00
|
|
|
|
|
|
|
if (clearCache) {
|
|
|
|
[store deleteAllData];
|
|
|
|
}
|
|
|
|
[account openSessionWithStore:store];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Force back to Recents list if room details is displayed (Room details are not available until the end of initial sync)
|
|
|
|
[self.masterTabBarController popRoomViewControllerAnimated:NO];
|
|
|
|
|
|
|
|
if (clearCache) {
|
|
|
|
// clear the media cache
|
|
|
|
[MXKMediaManager clearCache];
|
|
|
|
}
|
|
|
|
}
|
2014-10-08 16:55:26 +00:00
|
|
|
|
|
|
|
- (void)logout {
|
2015-04-17 13:45:32 +00:00
|
|
|
|
2014-12-12 09:49:15 +00:00
|
|
|
[[UIApplication sharedApplication] unregisterForRemoteNotifications];
|
|
|
|
[[APNSHandler sharedHandler] reset];
|
|
|
|
isAPNSRegistered = NO;
|
2015-04-17 13:45:32 +00:00
|
|
|
|
2014-10-17 23:04:05 +00:00
|
|
|
// Clear cache
|
2015-04-02 11:50:11 +00:00
|
|
|
[MXKMediaManager clearCache];
|
2015-04-17 13:45:32 +00:00
|
|
|
|
2015-05-05 16:06:50 +00:00
|
|
|
// Reset all stored room data
|
|
|
|
NSArray *mxAccounts = [MXKAccountManager sharedManager].accounts;
|
|
|
|
for (MXKAccount *account in mxAccounts) {
|
|
|
|
if (account.mxSession) {
|
|
|
|
[MXKRoomDataSourceManager removeSharedManagerForMatrixSession:account.mxSession];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-30 14:19:12 +00:00
|
|
|
// Logout all matrix account
|
|
|
|
[[MXKAccountManager sharedManager] logout];
|
2015-04-17 13:45:32 +00:00
|
|
|
|
|
|
|
// Reset mxSession information in all view controllers
|
|
|
|
self.masterTabBarController.mxSession = nil;
|
|
|
|
|
|
|
|
// Return to authentication screen
|
2015-02-05 10:43:06 +00:00
|
|
|
[self.masterTabBarController showAuthenticationScreen];
|
2015-04-17 13:45:32 +00:00
|
|
|
|
2014-11-28 14:06:53 +00:00
|
|
|
// Reset App settings
|
2015-04-15 12:46:54 +00:00
|
|
|
[[MXKAppSettings standardAppSettings] reset];
|
2015-04-17 13:45:32 +00:00
|
|
|
|
2015-04-17 12:24:08 +00:00
|
|
|
// Reset the contact manager
|
2015-01-27 14:43:57 +00:00
|
|
|
[[ContactManager sharedManager] reset];
|
2015-04-17 13:45:32 +00:00
|
|
|
|
2014-10-08 16:55:26 +00:00
|
|
|
// By default the "Home" tab is focussed
|
|
|
|
[self.masterTabBarController setSelectedIndex:TABBAR_HOME_INDEX];
|
|
|
|
}
|
2014-10-03 17:26:39 +00:00
|
|
|
|
2015-04-02 09:33:41 +00:00
|
|
|
- (MXKAlert*)showErrorAsAlert:(NSError*)error {
|
2015-02-18 16:40:55 +00:00
|
|
|
// Ignore network reachability error when the app is already offline
|
|
|
|
if (self.isOffline && [error.domain isEqualToString:NSURLErrorDomain] && error.code == NSURLErrorNotConnectedToInternet) {
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
2014-10-31 17:54:32 +00:00
|
|
|
if (self.errorNotification) {
|
|
|
|
[self.errorNotification dismiss:NO];
|
|
|
|
}
|
|
|
|
|
2014-10-08 12:14:12 +00:00
|
|
|
NSString *title = [error.userInfo valueForKey:NSLocalizedFailureReasonErrorKey];
|
|
|
|
if (!title)
|
|
|
|
{
|
|
|
|
title = @"Error";
|
2014-10-03 17:26:39 +00:00
|
|
|
}
|
2014-10-08 12:14:12 +00:00
|
|
|
NSString *msg = [error.userInfo valueForKey:NSLocalizedDescriptionKey];
|
|
|
|
|
2015-04-02 09:33:41 +00:00
|
|
|
self.errorNotification = [[MXKAlert alloc] initWithTitle:title message:msg style:MXKAlertStyleAlert];
|
|
|
|
self.errorNotification.cancelButtonIndex = [self.errorNotification addActionWithTitle:@"OK" style:MXKAlertActionStyleDefault handler:^(MXKAlert *alert) {
|
2014-11-04 16:26:33 +00:00
|
|
|
[AppDelegate theDelegate].errorNotification = nil;
|
|
|
|
}];
|
2014-10-31 17:54:32 +00:00
|
|
|
[self.errorNotification showInViewController:[self.masterTabBarController selectedViewController]];
|
2014-10-03 17:26:39 +00:00
|
|
|
|
2015-02-18 16:40:55 +00:00
|
|
|
// Switch in offline mode in case of network reachability error
|
|
|
|
if ([error.domain isEqualToString:NSURLErrorDomain] && error.code == NSURLErrorNotConnectedToInternet) {
|
|
|
|
self.isOffline = YES;
|
|
|
|
}
|
|
|
|
|
2014-10-31 17:54:32 +00:00
|
|
|
return self.errorNotification;
|
2014-10-03 17:26:39 +00:00
|
|
|
}
|
|
|
|
|
2015-01-30 08:05:15 +00:00
|
|
|
- (void)clearNotifications
|
|
|
|
{
|
|
|
|
// force to clear the notification center
|
|
|
|
// switching from 0 -> 1 -> 0 seems forcing the notifications center to refresh
|
|
|
|
// so resetting it does not clear the notifications center.
|
|
|
|
[UIApplication sharedApplication].applicationIconBadgeNumber = 1;
|
|
|
|
[UIApplication sharedApplication].applicationIconBadgeNumber = 0;
|
|
|
|
|
|
|
|
[[UIApplication sharedApplication] cancelAllLocalNotifications];
|
|
|
|
}
|
|
|
|
|
2015-04-30 14:19:12 +00:00
|
|
|
- (void)enableInAppNotifications:(BOOL)isEnabled {
|
|
|
|
|
|
|
|
// Update In-App notifications in all running matrix sessions
|
|
|
|
NSArray *mxAccounts = [MXKAccountManager sharedManager].accounts;
|
|
|
|
for (MXKAccount *account in mxAccounts) {
|
|
|
|
|
|
|
|
if (account.mxSession) {
|
|
|
|
if (isEnabled) {
|
|
|
|
// Build MXEvent -> NSString formatter
|
|
|
|
MXKEventFormatter *eventFormatter = [[MXKEventFormatter alloc] initWithMatrixSession:account.mxSession];
|
|
|
|
eventFormatter.isForSubtitle = YES;
|
|
|
|
|
|
|
|
[account listenToNotifications:^(MXEvent *event, MXRoomState *roomState, MXPushRule *rule) {
|
|
|
|
|
|
|
|
// Check conditions to display this notification (TODO GFO multi-session handling)
|
|
|
|
if (![self.masterTabBarController.visibleRoomId isEqualToString:event.roomId]
|
|
|
|
&& ![self.masterTabBarController isPresentingMediaPicker]) {
|
|
|
|
|
|
|
|
MXKEventFormatterError error;
|
|
|
|
NSString* messageText = [eventFormatter stringFromEvent:event withRoomState:roomState error:&error];
|
|
|
|
if (messageText.length && (error == MXKEventFormatterErrorNone)) {
|
|
|
|
|
|
|
|
// Removing existing notification (if any)
|
|
|
|
if (self.mxInAppNotification) {
|
|
|
|
[self.mxInAppNotification dismiss:NO];
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check whether tweak is required
|
|
|
|
for (MXPushRuleAction *ruleAction in rule.actions) {
|
|
|
|
if (ruleAction.actionType == MXPushRuleActionTypeSetTweak) {
|
|
|
|
if ([[ruleAction.parameters valueForKey:@"set_tweak"] isEqualToString:@"sound"]) {
|
|
|
|
// Play system sound (VoicemailReceived)
|
|
|
|
AudioServicesPlaySystemSound (1002);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
__weak typeof(self) weakSelf = self;
|
|
|
|
self.mxInAppNotification = [[MXKAlert alloc] initWithTitle:roomState.displayname
|
|
|
|
message:messageText
|
|
|
|
style:MXKAlertStyleAlert];
|
|
|
|
self.mxInAppNotification.cancelButtonIndex = [self.mxInAppNotification addActionWithTitle:@"Cancel"
|
|
|
|
style:MXKAlertActionStyleDefault
|
|
|
|
handler:^(MXKAlert *alert) {
|
|
|
|
weakSelf.mxInAppNotification = nil;
|
|
|
|
[account updateNotificationListenerForRoomId:event.roomId ignore:YES];
|
|
|
|
}];
|
|
|
|
[self.mxInAppNotification addActionWithTitle:@"View"
|
|
|
|
style:MXKAlertActionStyleDefault
|
|
|
|
handler:^(MXKAlert *alert) {
|
|
|
|
weakSelf.mxInAppNotification = nil;
|
|
|
|
// Show the room
|
|
|
|
[weakSelf.masterTabBarController showRoom:event.roomId];
|
|
|
|
}];
|
|
|
|
|
|
|
|
[self.mxInAppNotification showInViewController:[self.masterTabBarController selectedViewController]];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}];
|
|
|
|
} else {
|
|
|
|
[account removeNotificationListener];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (self.mxInAppNotification) {
|
|
|
|
[self.mxInAppNotification dismiss:NO];
|
|
|
|
self.mxInAppNotification = nil;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
|
|
|
|
if ([@"showAllEventsInRoomHistory" isEqualToString:keyPath]) {
|
|
|
|
// Flush and restore Matrix data
|
|
|
|
[self reloadMatrixSessions:NO];
|
|
|
|
}
|
|
|
|
else if ([@"enableInAppNotifications" isEqualToString:keyPath]) {
|
|
|
|
[self enableInAppNotifications:[[MXKAppSettings standardAppSettings] enableInAppNotifications]];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-04 12:49:30 +00:00
|
|
|
#pragma mark - Matrix Rooms handling
|
|
|
|
|
|
|
|
- (void)startPrivateOneToOneRoomWithUserId:(NSString*)userId {
|
|
|
|
|
|
|
|
// TODO GFO: handle here multi sessions
|
|
|
|
|
|
|
|
NSArray *mxAccounts = [MXKAccountManager sharedManager].accounts;
|
|
|
|
if (mxAccounts.count) {
|
|
|
|
MXKAccount *mxAccount = mxAccounts.firstObject;
|
|
|
|
MXSession *mxSession = mxAccount.mxSession;
|
|
|
|
|
|
|
|
if (mxSession) {
|
|
|
|
MXRoom* mxRoom = [mxSession privateOneToOneRoomWithUserId:userId];
|
|
|
|
|
|
|
|
// if the room exists
|
|
|
|
if (mxRoom) {
|
|
|
|
// open it
|
|
|
|
[self.masterTabBarController showRoom:mxRoom.state.roomId];
|
|
|
|
} else {
|
|
|
|
// create a new room
|
|
|
|
[mxSession createRoom:nil
|
|
|
|
visibility:kMXRoomVisibilityPrivate
|
|
|
|
roomAlias:nil
|
|
|
|
topic:nil
|
|
|
|
success:^(MXRoom *room) {
|
|
|
|
// invite the other user only if it is defined and not onself
|
|
|
|
if (userId && ![mxSession.myUser.userId isEqualToString:userId]) {
|
|
|
|
// add the user
|
|
|
|
[room inviteUser:userId success:^{
|
|
|
|
} failure:^(NSError *error) {
|
|
|
|
NSLog(@"[AppDelegate] %@ invitation failed (roomId: %@): %@", userId, room.state.roomId, error);
|
|
|
|
//Alert user
|
|
|
|
[self showErrorAsAlert:error];
|
|
|
|
}];
|
|
|
|
}
|
|
|
|
|
|
|
|
// Open created room
|
|
|
|
[self.masterTabBarController showRoom:room.state.roomId];
|
|
|
|
|
|
|
|
} failure:^(NSError *error) {
|
|
|
|
NSLog(@"[AppDelegate] Create room failed: %@", error);
|
|
|
|
//Alert user
|
|
|
|
[self showErrorAsAlert:error];
|
|
|
|
}];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-12 08:17:04 +00:00
|
|
|
#pragma mark - SplitViewController delegate
|
2014-10-02 15:02:47 +00:00
|
|
|
|
|
|
|
- (BOOL)splitViewController:(UISplitViewController *)splitViewController collapseSecondaryViewController:(UIViewController *)secondaryViewController ontoPrimaryViewController:(UIViewController *)primaryViewController {
|
2015-04-07 14:22:40 +00:00
|
|
|
if ([secondaryViewController isKindOfClass:[UINavigationController class]] && [[(UINavigationController *)secondaryViewController topViewController] isKindOfClass:[RoomViewController class]] && ([(RoomViewController *)[(UINavigationController *)secondaryViewController topViewController] roomDataSource] == nil)) {
|
2014-10-02 15:02:47 +00:00
|
|
|
// Return YES to indicate that we have handled the collapse by doing nothing; the secondary controller will be discarded.
|
|
|
|
return YES;
|
|
|
|
} else {
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-12 08:17:04 +00:00
|
|
|
- (BOOL)splitViewController:(UISplitViewController *)svc shouldHideViewController:(UIViewController *)vc inOrientation:(UIInterfaceOrientation)orientation {
|
|
|
|
// oniPad devices, force to display the primary and the secondary viewcontroller
|
|
|
|
// to avoid empty room View Controller in portrait orientation
|
|
|
|
// else, the user cannot select a room
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
|
|
|
|
#pragma mark - UITabBarControllerDelegate delegate
|
|
|
|
|
2015-01-05 15:53:41 +00:00
|
|
|
- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController {
|
|
|
|
BOOL res = YES;
|
|
|
|
|
2015-01-26 15:51:34 +00:00
|
|
|
if (tabBarController.selectedIndex == TABBAR_SETTINGS_INDEX) {
|
|
|
|
// Prompt user to save unsaved profile changes before switching to another tab
|
|
|
|
UIViewController* selectedViewController = [tabBarController selectedViewController];
|
|
|
|
if ([selectedViewController isKindOfClass:[UINavigationController class]]) {
|
|
|
|
UIViewController *topViewController = ((UINavigationController*)selectedViewController).topViewController;
|
|
|
|
if ([topViewController isKindOfClass:[SettingsViewController class]]) {
|
|
|
|
res = [((SettingsViewController *)topViewController) shouldLeave:^() {
|
|
|
|
// This block is called when tab change is delayed to prompt user about his profile changes
|
|
|
|
NSUInteger nextSelectedViewController = [tabBarController.viewControllers indexOfObject:viewController];
|
|
|
|
tabBarController.selectedIndex = nextSelectedViewController;
|
|
|
|
}];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-01-05 15:53:41 +00:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2014-10-02 15:02:47 +00:00
|
|
|
@end
|