Console: Improve offline mode:

- remove loading wheel when network is unreachable.
- color in red the navigation bar when the app is offline.

Buf Fix SYIOS- 66 - Console: last outgoing message is stuck as local echo whereas the message has been delivered.
This commit is contained in:
giomfo 2015-02-12 11:16:28 +01:00
parent 75e1a606ac
commit 4b76c6b24d
13 changed files with 352 additions and 162 deletions

View file

@ -22,7 +22,9 @@ typedef enum : NSUInteger {
MatrixSDKHandlerStatusLoggedOut = 0,
MatrixSDKHandlerStatusLogged,
MatrixSDKHandlerStatusStoreDataReady,
MatrixSDKHandlerStatusServerSyncDone
MatrixSDKHandlerStatusServerSyncInProgress,
MatrixSDKHandlerStatusServerSyncDone,
MatrixSDKHandlerStatusPaused
} MatrixSDKHandlerStatus;
@interface MatrixSDKHandler : NSObject
@ -47,7 +49,7 @@ typedef enum : NSUInteger {
@property (nonatomic) MXPresence userPresence;
@property (nonatomic,readonly) MatrixSDKHandlerStatus status;
@property (nonatomic,readonly) BOOL isResumeDone;
@property (nonatomic,readonly) BOOL isActivityInProgress;
// return the MX cache size in bytes
@property (nonatomic,readonly) NSUInteger MXCacheSize;
// return the sum of the caches (MX cache + media cache ...) in bytes
@ -66,7 +68,7 @@ typedef enum : NSUInteger {
- (void)logout;
// Flush and restore Matrix data
- (void)forceInitialSync:(BOOL)clearCache;
- (void)reload:(BOOL)clearCache;
- (void)enableInAppNotifications:(BOOL)isEnabled;

View file

@ -24,6 +24,8 @@
#import "MediaManager.h"
#import "AFNetworkReachabilityManager.h"
NSString *const kMatrixSDKHandlerUnsupportedEventDescriptionPrefix = @"Unsupported event: ";
static MatrixSDKHandler *sharedHandler = nil;
@ -31,16 +33,19 @@ static MatrixSDKHandler *sharedHandler = nil;
@interface MatrixSDKHandler () {
// We will notify user only once on session failure
BOOL notifyOpenSessionFailure;
NSTimer* initialServerSyncTimer;
// Handle user's settings change
id userUpdateListener;
// Handle events notification
id eventsListener;
// Reachability observer
id reachabilityObserver;
}
@property (strong, nonatomic) MXFileStore *mxFileStore;
@property (nonatomic,readwrite) MatrixSDKHandlerStatus status;
@property (nonatomic,readwrite) BOOL isResumeDone;
@property (nonatomic,readwrite) BOOL isActivityInProgress;
@property (strong, nonatomic) MXCAlert *mxNotification;
@property (nonatomic) UIBackgroundTaskIdentifier bgTask;
@ -66,8 +71,7 @@ static MatrixSDKHandler *sharedHandler = nil;
-(MatrixSDKHandler *)init {
if (self = [super init]) {
_status = (self.accessToken != nil) ? MatrixSDKHandlerStatusLogged : MatrixSDKHandlerStatusLoggedOut;
_isResumeDone = NO;
self.status = (self.accessToken != nil) ? MatrixSDKHandlerStatusLogged : MatrixSDKHandlerStatusLoggedOut;
_userPresence = MXPresenceUnknown;
notifyOpenSessionFailure = YES;
@ -87,12 +91,29 @@ static MatrixSDKHandler *sharedHandler = nil;
}
_unnotifiedRooms = [[NSMutableArray alloc] init];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onAppDidEnterBackground) name:UIApplicationDidEnterBackgroundNotification object:nil];
}
return self;
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
[[NSNotificationCenter defaultCenter] removeObserver:reachabilityObserver];
reachabilityObserver = nil;
[initialServerSyncTimer invalidate];
initialServerSyncTimer = nil;
_processingQueue = nil;
[self closeSession];
self.mxSession = nil;
if (self.mxNotification) {
[self.mxNotification dismiss:NO];
self.mxNotification = nil;
}
}
- (void)openSession {
MXCredentials *credentials = [[MXCredentials alloc] initWithHomeServer:self.homeServerURL
userId:self.userId
@ -138,64 +159,101 @@ static MatrixSDKHandler *sharedHandler = nil;
kMXEventTypeStringRoomMessage
];
}
// Launch mxSession
[self.mxSession start:^{
typeof(self) self = weakSelf;
self->_isResumeDone = YES;
self.status = MatrixSDKHandlerStatusServerSyncDone;
[self setUserPresence:MXPresenceOnline andStatusMessage:nil completion:nil];
// Register listener to update user's information
self->userUpdateListener = [self.mxSession.myUser listenToUserUpdate:^(MXEvent *event) {
// Consider only events related to user's presence
if (event.eventType == MXEventTypePresence) {
MXPresence presence = [MXTools presence:event.content[@"presence"]];
if (self.userPresence != presence) {
// Handle user presence on multiple devices (keep the more pertinent)
if (self.userPresence == MXPresenceOnline) {
if (presence == MXPresenceUnavailable || presence == MXPresenceOffline) {
// Force the local presence to overwrite the user presence on server side
[self setUserPresence:self->_userPresence andStatusMessage:nil completion:nil];
return;
}
} else if (self.userPresence == MXPresenceUnavailable) {
if (presence == MXPresenceOffline) {
// Force the local presence to overwrite the user presence on server side
[self setUserPresence:self->_userPresence andStatusMessage:nil completion:nil];
return;
}
}
self.userPresence = presence;
}
}
}];
// Check whether the app user wants notifications on new events
if ([[AppSettings sharedSettings] enableInAppNotifications]) {
[self enableInAppNotifications:YES];
}
} failure:^(NSError *error) {
typeof(self) self = weakSelf;
NSLog(@"Initial Sync failed: %@", error);
if (self->notifyOpenSessionFailure) {
//Alert user only once
self->notifyOpenSessionFailure = NO;
[[AppDelegate theDelegate] showErrorAsAlert:error];
}
// Postpone a new attempt in 10 sec
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self openSession];
});
}];
// Complete session registration by launching live stream
[self launchInitialServerSync];
} failure:^(NSError *error) {
// This cannot happen. Loading of MXFileStore cannot fail.
typeof(self) self = weakSelf;
self.mxSession = nil;
}];
}
}
- (void)launchInitialServerSync {
// Complete the session registration when store data is ready.
// Cancel potential reachability observer and pending action
[[NSNotificationCenter defaultCenter] removeObserver:reachabilityObserver];
reachabilityObserver = nil;
[initialServerSyncTimer invalidate];
initialServerSyncTimer = nil;
// Sanity check
if (self.status != MatrixSDKHandlerStatusStoreDataReady) {
NSLog(@"Initial server sync is applicable only when store data is ready to complete session initialisation");
return;
}
// Launch mxSession
self.status = MatrixSDKHandlerStatusServerSyncInProgress;
[self.mxSession start:^{
self.status = MatrixSDKHandlerStatusServerSyncDone;
[self setUserPresence:MXPresenceOnline andStatusMessage:nil completion:nil];
// Register listener to update user's information
userUpdateListener = [self.mxSession.myUser listenToUserUpdate:^(MXEvent *event) {
// Consider only events related to user's presence
if (event.eventType == MXEventTypePresence) {
MXPresence presence = [MXTools presence:event.content[@"presence"]];
if (self.userPresence != presence) {
// Handle user presence on multiple devices (keep the more pertinent)
if (self.userPresence == MXPresenceOnline) {
if (presence == MXPresenceUnavailable || presence == MXPresenceOffline) {
// Force the local presence to overwrite the user presence on server side
[self setUserPresence:_userPresence andStatusMessage:nil completion:nil];
return;
}
} else if (self.userPresence == MXPresenceUnavailable) {
if (presence == MXPresenceOffline) {
// Force the local presence to overwrite the user presence on server side
[self setUserPresence:_userPresence andStatusMessage:nil completion:nil];
return;
}
}
self.userPresence = presence;
}
}
}];
// Check whether the app user wants notifications on new events
if ([[AppSettings sharedSettings] enableInAppNotifications]) {
[self enableInAppNotifications:YES];
}
} failure:^(NSError *error) {
NSLog(@"Initial Sync failed: %@", error);
if (notifyOpenSessionFailure) {
//Alert user only once
notifyOpenSessionFailure = NO;
[[AppDelegate theDelegate] showErrorAsAlert:error];
}
// Return in previous state
self.status = MatrixSDKHandlerStatusStoreDataReady;
// Check network reachability
if ([error.domain isEqualToString:NSURLErrorDomain] && error.code == NSURLErrorNotConnectedToInternet) {
// Add observer to launch a new attempt according to reachability.
reachabilityObserver = [[NSNotificationCenter defaultCenter] addObserverForName:AFNetworkingReachabilityDidChangeNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
NSNumber *staturItem = note.userInfo[AFNetworkingReachabilityNotificationStatusItem];
if (staturItem) {
AFNetworkReachabilityStatus reachabilityStatus = staturItem.integerValue;
if (reachabilityStatus == AFNetworkReachabilityStatusReachableViaWiFi || reachabilityStatus == AFNetworkReachabilityStatusReachableViaWWAN) {
// New attempt
[self launchInitialServerSync];
}
}
}];
} else {
// Postpone a new attempt in 10 sec
initialServerSyncTimer = [NSTimer scheduledTimerWithTimeInterval:10 target:self selector:@selector(launchInitialServerSync) userInfo:self repeats:NO];
}
}];
}
- (void)closeSession {
self.status = (self.accessToken != nil) ? MatrixSDKHandlerStatusLogged : MatrixSDKHandlerStatusLoggedOut;
if (eventsListener) {
[self.mxSession removeListener:eventsListener];
eventsListener = nil;
@ -204,10 +262,12 @@ static MatrixSDKHandler *sharedHandler = nil;
[self.mxSession.myUser removeListener:userUpdateListener];
userUpdateListener = nil;
}
[self.mxSession close];
self.mxSession = nil;
[self.mxRestClient close];
if (self.homeServerURL) {
self.mxRestClient = [[MXRestClient alloc] initWithHomeServer:self.homeServerURL];
if (self.identityServerURL) {
@ -217,25 +277,12 @@ static MatrixSDKHandler *sharedHandler = nil;
self.mxRestClient = nil;
}
_isResumeDone = NO;
notifyOpenSessionFailure = YES;
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
_processingQueue = nil;
[self closeSession];
self.mxSession = nil;
if (self.mxNotification) {
[self.mxNotification dismiss:NO];
self.mxNotification = nil;
}
}
#pragma mark -
- (void)onAppDidEnterBackground {
- (void)pauseInBackgroundTask {
// Hide potential notification
if (self.mxNotification) {
[self.mxNotification dismiss:NO];
@ -243,11 +290,7 @@ static MatrixSDKHandler *sharedHandler = nil;
}
_unnotifiedRooms = [[NSMutableArray alloc] init];
}
#pragma mark -
- (void)pauseInBackgroundTask {
if (self.mxSession && self.status == MatrixSDKHandlerStatusServerSyncDone) {
_bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
[[UIApplication sharedApplication] endBackgroundTask:_bgTask];
@ -259,7 +302,7 @@ static MatrixSDKHandler *sharedHandler = nil;
NSLog(@"pauseInBackgroundTask : %08lX starts", (unsigned long)_bgTask);
// Pause SDK
[self.mxSession pause];
self.isResumeDone = NO;
self.status = MatrixSDKHandlerStatusPaused;
// Update user presence
__weak typeof(self) weakSelf = self;
[self setUserPresence:MXPresenceUnavailable andStatusMessage:nil completion:^{
@ -268,17 +311,26 @@ static MatrixSDKHandler *sharedHandler = nil;
weakSelf.bgTask = UIBackgroundTaskInvalid;
NSLog(@">>>>> background pause task finished");
}];
} else {
// Cancel pending actions
[[NSNotificationCenter defaultCenter] removeObserver:reachabilityObserver];
reachabilityObserver = nil;
[initialServerSyncTimer invalidate];
initialServerSyncTimer = nil;
}
}
- (void)resume {
if (self.mxSession && self.status == MatrixSDKHandlerStatusServerSyncDone) {
if (!self.isResumeDone) {
if (self.mxSession) {
if (self.status == MatrixSDKHandlerStatusPaused) {
// Resume SDK and update user presence
[self.mxSession resume:^{
[self setUserPresence:MXPresenceOnline andStatusMessage:nil completion:nil];
self.isResumeDone = YES;
self.status = MatrixSDKHandlerStatusServerSyncDone;
}];
} else if (self.status == MatrixSDKHandlerStatusStoreDataReady) {
// The session initialisation was uncompleted, we try to complete it here.
[self launchInitialServerSync];
}
if (_bgTask) {
@ -302,9 +354,8 @@ static MatrixSDKHandler *sharedHandler = nil;
// Keep userLogin, homeServerUrl
}
- (void)forceInitialSync:(BOOL)clearCache {
if (self.status == MatrixSDKHandlerStatusServerSyncDone || self.status == MatrixSDKHandlerStatusStoreDataReady) {
self.status = MatrixSDKHandlerStatusLogged;
- (void)reload:(BOOL)clearCache {
if (self.mxSession) {
[self closeSession];
notifyOpenSessionFailure = NO;
@ -391,6 +442,47 @@ static MatrixSDKHandler *sharedHandler = nil;
#pragma mark - Properties
- (void)setStatus:(MatrixSDKHandlerStatus)status {
// Remove potential reachability observer
if (reachabilityObserver) {
[[NSNotificationCenter defaultCenter] removeObserver:reachabilityObserver];
reachabilityObserver = nil;
}
// Update activity flag
switch (status) {
case MatrixSDKHandlerStatusLoggedOut:
case MatrixSDKHandlerStatusStoreDataReady:
case MatrixSDKHandlerStatusServerSyncDone: {
self.isActivityInProgress = NO;
break;
}
case MatrixSDKHandlerStatusLogged:
case MatrixSDKHandlerStatusServerSyncInProgress: {
self.isActivityInProgress = YES;
break;
}
case MatrixSDKHandlerStatusPaused: {
// Here the app is resuming, the activity is in progress except if the network is unreachable
AFNetworkReachabilityStatus reachabilityStatus = [AFNetworkReachabilityManager sharedManager].networkReachabilityStatus;
self.isActivityInProgress = (reachabilityStatus == AFNetworkReachabilityStatusReachableViaWiFi || reachabilityStatus ==AFNetworkReachabilityStatusReachableViaWWAN);
// Add observer to update handler activity according to reachability.
reachabilityObserver = [[NSNotificationCenter defaultCenter] addObserverForName:AFNetworkingReachabilityDidChangeNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
NSNumber *staturItem = note.userInfo[AFNetworkingReachabilityNotificationStatusItem];
if (staturItem) {
AFNetworkReachabilityStatus reachabilityStatus = staturItem.integerValue;
self.isActivityInProgress = (reachabilityStatus == AFNetworkReachabilityStatusReachableViaWiFi || reachabilityStatus ==AFNetworkReachabilityStatusReachableViaWWAN);
}
}];
break;
}
}
// Report status
_status = status;
}
- (NSString *)homeServerURL {
return [[NSUserDefaults standardUserDefaults] objectForKey:@"homeserverurl"];
}
@ -478,7 +570,6 @@ static MatrixSDKHandler *sharedHandler = nil;
[self openSession];
} else {
[[NSUserDefaults standardUserDefaults] removeObjectForKey:@"accesstoken"];
self.status = MatrixSDKHandlerStatusLoggedOut;
[self closeSession];
}
[[NSUserDefaults standardUserDefaults] synchronize];
@ -565,8 +656,7 @@ static MatrixSDKHandler *sharedHandler = nil;
NSMutableArray* matrixIDs = [[NSMutableArray alloc] init];
MatrixSDKHandler *mxHandler = [MatrixSDKHandler sharedHandler];
if ((mxHandler.status == MatrixSDKHandlerStatusStoreDataReady) || (mxHandler.status == MatrixSDKHandlerStatusServerSyncDone)) {
if (mxHandler.mxSession) {
NSArray *recentEvents = [NSMutableArray arrayWithArray:[mxHandler.mxSession recentsWithTypeIn:mxHandler.eventsFilterForMessages]];
for (MXEvent *mxEvent in recentEvents) {

View file

@ -23,6 +23,8 @@
#import "SettingsViewController.h"
#import "ContactManager.h"
#import "AFNetworkReachabilityManager.h"
#define MAKE_STRING(x) #x
#define MAKE_NS_STRING(x) @MAKE_STRING(x)
@ -70,7 +72,7 @@
return _build;
}
#pragma mark -
#pragma mark - UIApplicationDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
@ -141,6 +143,9 @@
// 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.
// Stop reachability monitoring
[[AFNetworkReachabilityManager sharedManager] stopMonitoring];
// check if some media msut be released to reduce the cache size
[MediaManager reduceCacheSizeToInsert:0];
// Suspend Matrix handler
@ -162,6 +167,10 @@
- (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.
// Start monitoring reachability
[[AFNetworkReachabilityManager sharedManager] startMonitoring];
// Resume Matrix handler
[[MatrixSDKHandler sharedHandler] resume];

View file

@ -98,7 +98,7 @@ static AppSettings *sharedSettings = nil;
- (void)setDisplayAllEvents:(BOOL)displayAllEvents {
[[NSUserDefaults standardUserDefaults] setBool:displayAllEvents forKey:@"displayAllEvents"];
// Flush and restore Matrix data
[[MatrixSDKHandler sharedHandler] forceInitialSync:NO];
[[MatrixSDKHandler sharedHandler] reload:NO];
}
- (BOOL)hideRedactedInformation {

View file

@ -20,8 +20,6 @@
#import "AppDelegate.h"
#import "MXCAlert.h"
#import "AFNetworkReachabilityManager.h"
@interface AuthenticationViewController () {
// Current request in progress
NSOperation *mxAuthFlowRequest;
@ -231,8 +229,7 @@
- (void)refreshSupportedAuthFlow {
MatrixSDKHandler *mxHandler = [MatrixSDKHandler sharedHandler];
// Stop reachability monitoring
[[AFNetworkReachabilityManager sharedManager] stopMonitoring];
// Remove reachability observer
[[NSNotificationCenter defaultCenter] removeObserver:self name:AFNetworkingReachabilityDidChangeNotification object:nil];
// Cancel protential request in progress
@ -289,13 +286,13 @@
}
- (void)onFailureDuringFlowRefresh:(NSError*)error {
[_activityIndicator stopAnimating];
if ([error.domain isEqualToString:NSURLErrorDomain] && error.code == kCFURLErrorCancelled) {
// Ignore this error
return;
}
[_activityIndicator stopAnimating];
NSLog(@"GET auth flows failed: %@", error);
// Alert user
NSString *title = [error.userInfo valueForKey:NSLocalizedFailureReasonErrorKey];
@ -321,9 +318,8 @@
if ([error.domain isEqualToString:NSURLErrorDomain]) {
// Check network reachability
if (error.code == NSURLErrorNotConnectedToInternet) {
// Start monitoring in order to launch a new request when network will be available
// Add reachability observer in order to launch a new request when network will be available
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onReachabilityStatusChange:) name:AFNetworkingReachabilityDidChangeNotification object:nil];
[[AFNetworkReachabilityManager sharedManager] startMonitoring];
} else if (error.code == kCFURLErrorTimedOut) {
// Send a new request in 2 sec
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

View file

@ -245,10 +245,9 @@ NSString *const kInvitationMessage = @"I'd like to chat with you with matrix. Pl
}
- (void)updateSectionedMatrixContacts {
// check if the user is already known
// Check whether mxSession is available in matrix handler
MatrixSDKHandler *mxHandler = [MatrixSDKHandler sharedHandler];
if ((mxHandler.status != MatrixSDKHandlerStatusServerSyncDone) && (mxHandler.status != MatrixSDKHandlerStatusStoreDataReady)) {
if (!mxHandler.mxSession) {
[self startActivityIndicator];
sectionedMatrixContacts = nil;
} else {
@ -428,8 +427,8 @@ NSString *const kInvitationMessage = @"I'd like to chat with you with matrix. Pl
MatrixSDKHandler* mxHandler = [MatrixSDKHandler sharedHandler];
// display only if the matrix SDk is ready
if ((mxHandler.status == MatrixSDKHandlerStatusServerSyncDone) || (mxHandler.status == MatrixSDKHandlerStatusStoreDataReady)) {
// display only if the mxSession is available in matrix SDK handler
if (mxHandler.mxSession) {
// only 1 matrix ID
if (matrixIDs.count == 1) {
NSString* matrixID = [matrixIDs objectAtIndex:0];

View file

@ -16,6 +16,8 @@
#import <UIKit/UIKit.h>
#import "AFNetworkReachabilityManager.h"
@interface RageShakableTableViewController : UITableViewController
@end

View file

@ -17,18 +17,71 @@
#import "RageShakableUIResponder.h"
@interface RageShakableTableViewController () {
id reachabilityObserver;
}
@end
@implementation RageShakableTableViewController
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[RageShakableUIResponder cancel:self];
if (self.navigationController) {
// The navigation bar tintColor depends on reachability status - Register reachability observer
reachabilityObserver = [[NSNotificationCenter defaultCenter] addObserverForName:AFNetworkingReachabilityDidChangeNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notification) {
[self onReachabilityStatusChange];
}];
// Force update
[self onReachabilityStatusChange];
}
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[[NSNotificationCenter defaultCenter] removeObserver:reachabilityObserver];
[RageShakableUIResponder cancel:self];
}
#pragma mark - Reachability monitoring
- (void)onReachabilityStatusChange {
// Retrieve the current reachability status
AFNetworkReachabilityManager *reachabilityManager = [AFNetworkReachabilityManager sharedManager];
AFNetworkReachabilityStatus status = reachabilityManager.networkReachabilityStatus;
// Retrieve the main navigation controller if the current view controller is embedded inside a split view controller.
UINavigationController *mainNavigationController = nil;
if (self.splitViewController) {
mainNavigationController = self.navigationController;
UIViewController *parentViewController = self.parentViewController;
while (parentViewController) {
if (parentViewController.navigationController) {
mainNavigationController = parentViewController.navigationController;
parentViewController = parentViewController.parentViewController;
} else {
break;
}
}
}
// Update navigationBar tintColor
if (status == AFNetworkReachabilityStatusNotReachable) {
self.navigationController.navigationBar.barTintColor = [UIColor redColor];
if (mainNavigationController) {
mainNavigationController.navigationBar.barTintColor = [UIColor redColor];
}
} else if (status == AFNetworkReachabilityStatusReachableViaWiFi || status == AFNetworkReachabilityStatusReachableViaWWAN) {
self.navigationController.navigationBar.barTintColor = nil;
if (mainNavigationController) {
mainNavigationController.navigationBar.barTintColor = nil;
}
}
}
#pragma mark - rageshake : screenshot
- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event {
if (motion == UIEventSubtypeMotionShake) {

View file

@ -16,6 +16,8 @@
#import <UIKit/UIKit.h>
#import "AFNetworkReachabilityManager.h"
@interface RageShakableViewController : UIViewController
@end

View file

@ -17,18 +17,71 @@
#import "RageShakableUIResponder.h"
@interface RageShakableViewController () {
id reachabilityObserver;
}
@end
@implementation RageShakableViewController
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[RageShakableUIResponder cancel:self];
if (self.navigationController) {
// The navigation bar tintColor depends on reachability status - Register reachability observer
reachabilityObserver = [[NSNotificationCenter defaultCenter] addObserverForName:AFNetworkingReachabilityDidChangeNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notification) {
[self onReachabilityStatusChange];
}];
// Force update
[self onReachabilityStatusChange];
}
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[[NSNotificationCenter defaultCenter] removeObserver:reachabilityObserver];
[RageShakableUIResponder cancel:self];
}
#pragma mark - Reachability monitoring
- (void)onReachabilityStatusChange {
// Retrieve the current reachability status
AFNetworkReachabilityManager *reachabilityManager = [AFNetworkReachabilityManager sharedManager];
AFNetworkReachabilityStatus status = reachabilityManager.networkReachabilityStatus;
// Retrieve the main navigation controller if the current view controller is embedded inside a split view controller.
UINavigationController *mainNavigationController = nil;
if (self.splitViewController) {
mainNavigationController = self.navigationController;
UIViewController *parentViewController = self.parentViewController;
while (parentViewController) {
if (parentViewController.navigationController) {
mainNavigationController = parentViewController.navigationController;
parentViewController = parentViewController.parentViewController;
} else {
break;
}
}
}
// Update navigationBar tintColor
if (status == AFNetworkReachabilityStatusNotReachable) {
self.navigationController.navigationBar.barTintColor = [UIColor redColor];
if (mainNavigationController) {
mainNavigationController.navigationBar.barTintColor = [UIColor redColor];
}
} else if (status == AFNetworkReachabilityStatusReachableViaWiFi || status == AFNetworkReachabilityStatusReachableViaWWAN) {
self.navigationController.navigationBar.barTintColor = nil;
if (mainNavigationController) {
mainNavigationController.navigationBar.barTintColor = nil;
}
}
}
#pragma mark - rageshake : screenshot
- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event {
if (motion == UIEventSubtypeMotionShake) {

View file

@ -40,7 +40,7 @@
NSDateFormatter *dateFormatter;
RoomViewController *currentRoomViewController;
BOOL isVisible;
BOOL shouldHideActivityIndicator;
}
@property (strong, nonatomic) IBOutlet UIActivityIndicatorView *activityIndicator;
@ -116,14 +116,22 @@
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
MatrixSDKHandler *mxHandler = [MatrixSDKHandler sharedHandler];
[mxHandler addObserver:self forKeyPath:@"isActivityInProgress" options:0 context:nil];
// Refresh display
shouldHideActivityIndicator = NO;
if (mxHandler.isActivityInProgress) {
[self startActivityIndicator];
}
[self configureView];
[[MatrixSDKHandler sharedHandler] addObserver:self forKeyPath:@"isResumeDone" options:0 context:nil];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[[MatrixSDKHandler sharedHandler] removeObserver:self forKeyPath:@"isActivityInProgress"];
// Leave potential editing mode
[self setEditing:NO];
// Leave potential search session
@ -132,16 +140,14 @@
}
// Hide activity indicator
[self stopActivityIndicator];
shouldHideActivityIndicator = YES;
_preSelectedRoomId = nil;
[[MatrixSDKHandler sharedHandler] removeObserver:self forKeyPath:@"isResumeDone"];
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
isVisible = YES;
// Release potential Room ViewController if none is visible (Note: check on room visibility is required to handle correctly splitViewController)
if ([AppDelegate theDelegate].masterTabBarController.visibleRoomId == nil && currentRoomViewController) {
currentRoomViewController.roomId = nil;
@ -149,12 +155,6 @@
}
}
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
isVisible = NO;
}
#pragma mark -
- (void)setPreSelectedRoomId:(NSString *)roomId {
@ -216,12 +216,11 @@
- (void)configureView {
MatrixSDKHandler *mxHandler = [MatrixSDKHandler sharedHandler];
[self startActivityIndicator];
[[NSNotificationCenter defaultCenter] removeObserver:self name:kRecentRoomUpdatedByBackPagination object:nil];
if (mxHandler.mxSession) {
// Check matrix handler status
if (mxHandler.status == MatrixSDKHandlerStatusStoreDataReady) {
if (mxHandler.status == MatrixSDKHandlerStatusStoreDataReady || mxHandler.status == MatrixSDKHandlerStatusServerSyncInProgress) {
// Server sync is not complete yet
if (!recents) {
// Retrieve recents from local storage (some data may not be up-to-date)
@ -339,15 +338,13 @@
}];
}
// else nothing to do
} else {
} else if (mxHandler.status != MatrixSDKHandlerStatusPaused) {
// Here status is MatrixSDKHandlerStatusLoggedOut or MatrixSDKHandlerStatusLogged - Reset recents
recents = nil;
}
// Reload table
[self.tableView reloadData];
if ([mxHandler isResumeDone]) {
[self stopActivityIndicator];
}
// Check whether a room is preselected
if (_preSelectedRoomId) {
@ -355,7 +352,6 @@
}
} else {
if (mxHandler.status == MatrixSDKHandlerStatusLoggedOut) {
[self stopActivityIndicator];
// Update title
unreadCount = 0;
[self updateTitleView];
@ -462,16 +458,12 @@
if ([@"status" isEqualToString:keyPath]) {
dispatch_async(dispatch_get_main_queue(), ^{
[self configureView];
// Hide the activity indicator when Recents is not visible
if (!isVisible) {
[self stopActivityIndicator];
}
});
} else if ([@"isResumeDone" isEqualToString:keyPath]) {
if ([[MatrixSDKHandler sharedHandler] isResumeDone]) {
[self stopActivityIndicator];
} else {
} else if ([@"isActivityInProgress" isEqualToString:keyPath]) {
if (!shouldHideActivityIndicator && [MatrixSDKHandler sharedHandler].isActivityInProgress) {
[self startActivityIndicator];
} else {
[self stopActivityIndicator];
}
}
}

View file

@ -230,8 +230,7 @@ NSString *const kCmdResetUserPowerLevel = @"/deop";
_redactionListener = nil;
[[AppSettings sharedSettings] removeObserver:self forKeyPath:@"hideRedactedInformation"];
[[AppSettings sharedSettings] removeObserver:self forKeyPath:@"hideUnsupportedEvents"];
[[MatrixSDKHandler sharedHandler] removeObserver:self forKeyPath:@"status"];
[[MatrixSDKHandler sharedHandler] removeObserver:self forKeyPath:@"isResumeDone"];
[[MatrixSDKHandler sharedHandler] removeObserver:self forKeyPath:@"isActivityInProgress"];
}
self.mxRoom = nil;
@ -606,8 +605,7 @@ NSString *const kCmdResetUserPowerLevel = @"/deop";
_redactionListener = nil;
[[AppSettings sharedSettings] removeObserver:self forKeyPath:@"hideRedactedInformation"];
[[AppSettings sharedSettings] removeObserver:self forKeyPath:@"hideUnsupportedEvents"];
[[MatrixSDKHandler sharedHandler] removeObserver:self forKeyPath:@"status"];
[[MatrixSDKHandler sharedHandler] removeObserver:self forKeyPath:@"isResumeDone"];
[[MatrixSDKHandler sharedHandler] removeObserver:self forKeyPath:@"isActivityInProgress"];
}
currentTypingUsers = nil;
if (typingNotifListener) {
@ -658,8 +656,7 @@ NSString *const kCmdResetUserPowerLevel = @"/deop";
[[AppSettings sharedSettings] addObserver:self forKeyPath:@"hideRedactedInformation" options:0 context:nil];
[[AppSettings sharedSettings] addObserver:self forKeyPath:@"hideUnsupportedEvents" options:0 context:nil];
[mxHandler addObserver:self forKeyPath:@"status" options:0 context:nil];
[mxHandler addObserver:self forKeyPath:@"isResumeDone" options:0 context:nil];
[mxHandler addObserver:self forKeyPath:@"isActivityInProgress" options:0 context:nil];
// Register a listener to handle messages
_messagesListener = [self.mxRoom listenToEventsOfTypes:mxHandler.eventsFilterForMessages onEvent:^(MXEvent *event, MXEventDirection direction, MXRoomState *roomState) {
// Handle first live events
@ -906,7 +903,7 @@ NSString *const kCmdResetUserPowerLevel = @"/deop";
- (void)stopActivityIndicator {
// Check whether all conditions are satisfied before stopping loading wheel
MatrixSDKHandler *mxHandler = [MatrixSDKHandler sharedHandler];
if (mxHandler.status == MatrixSDKHandlerStatusServerSyncDone && mxHandler.isResumeDone && !isBackPaginationInProgress && !isJoinRequestInProgress) {
if (!mxHandler.isActivityInProgress && !isBackPaginationInProgress && !isJoinRequestInProgress) {
[_activityIndicator stopAnimating];
}
}
@ -925,17 +922,11 @@ NSString *const kCmdResetUserPowerLevel = @"/deop";
#pragma mark - KVO
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if ([@"status" isEqualToString:keyPath]) {
if ([MatrixSDKHandler sharedHandler].status == MatrixSDKHandlerStatusServerSyncDone) {
[self stopActivityIndicator];
} else {
if ([@"isActivityInProgress" isEqualToString:keyPath]) {
if ([MatrixSDKHandler sharedHandler].isActivityInProgress) {
[self startActivityIndicator];
}
} else if ([@"isResumeDone" isEqualToString:keyPath]) {
if ([[MatrixSDKHandler sharedHandler] isResumeDone]) {
[self stopActivityIndicator];
} else {
[self startActivityIndicator];
[self stopActivityIndicator];
}
} else if ((object == inputAccessoryView.superview) && ([@"frame" isEqualToString:keyPath] || [@"center" isEqualToString:keyPath])) {

View file

@ -172,15 +172,22 @@ NSString* const kCommandsDescriptionText = @"The following commands are availabl
selectedCountryCode = countryCode = [[AppSettings sharedSettings] countryCode];
MatrixSDKHandler *mxHandler = [MatrixSDKHandler sharedHandler];
[mxHandler addObserver:self forKeyPath:@"isActivityInProgress" options:0 context:nil];
// Refresh display
[self startActivityIndicator];
if (mxHandler.isActivityInProgress) {
[self startActivityIndicator];
}
[self configureView];
[[MatrixSDKHandler sharedHandler] addObserver:self forKeyPath:@"isResumeDone" options:0 context:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onAPNSHandlerHasBeenUpdated) name:kAPNSHandlerHasBeenUpdated object:nil];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[[MatrixSDKHandler sharedHandler] removeObserver:self forKeyPath:@"isActivityInProgress"];
[self stopActivityIndicator];
// if country has been updated
// update the contact phonenumbers
@ -195,7 +202,6 @@ NSString* const kCommandsDescriptionText = @"The following commands are availabl
}
countryCode = [[AppSettings sharedSettings] countryCode];
[[MatrixSDKHandler sharedHandler] removeObserver:self forKeyPath:@"isResumeDone"];
[[NSNotificationCenter defaultCenter] removeObserver:self name:kAPNSHandlerHasBeenUpdated object:nil];
}
@ -328,8 +334,6 @@ NSString* const kCommandsDescriptionText = @"The following commands are availabl
currentDisplayName = mxHandler.mxSession.myUser.displayname;
self.userDisplayName.text = currentDisplayName;
[self stopActivityIndicator];
// Register listener to update user's information
userUpdateListener = [mxHandler.mxSession.myUser listenToUserUpdate:^(MXEvent *event) {
// Update displayName
@ -346,7 +350,7 @@ NSString* const kCommandsDescriptionText = @"The following commands are availabl
// TODO display user's presence
}];
}
} else if (mxHandler.status == MatrixSDKHandlerStatusStoreDataReady) {
} else if (mxHandler.status == MatrixSDKHandlerStatusStoreDataReady || mxHandler.status == MatrixSDKHandlerStatusServerSyncInProgress) {
// Set local user's information (the data may not be up-to-date)
[self updateUserPicture:mxHandler.mxSession.myUser.avatarUrl force:NO];
currentDisplayName = mxHandler.mxSession.myUser.displayname;
@ -355,9 +359,6 @@ NSString* const kCommandsDescriptionText = @"The following commands are availabl
[self reset];
}
if ([mxHandler isResumeDone]) {
[self stopActivityIndicator];
}
// Restore user's interactions
_userPictureButton.enabled = YES;
_userDisplayName.enabled = YES;
@ -438,8 +439,8 @@ NSString* const kCommandsDescriptionText = @"The following commands are availabl
// Backup is complete
isSavingInProgress = NO;
// Stop animation (except if the app is resuming)
if ([[MatrixSDKHandler sharedHandler] isResumeDone]) {
// Stop activity indicator except if matrix sdk handler is working
if (!mxHandler.isActivityInProgress) {
[self stopActivityIndicator];
}
}
@ -627,11 +628,11 @@ NSString* const kCommandsDescriptionText = @"The following commands are availabl
dispatch_async(dispatch_get_main_queue(), ^{
[self configureView];
});
} else if ([@"isResumeDone" isEqualToString:keyPath]) {
if ([[MatrixSDKHandler sharedHandler] isResumeDone] && !isSavingInProgress) {
[self stopActivityIndicator];
} else {
} else if ([@"isActivityInProgress" isEqualToString:keyPath]) {
if ([MatrixSDKHandler sharedHandler].isActivityInProgress || isSavingInProgress) {
[self startActivityIndicator];
} else {
[self stopActivityIndicator];
}
}
}
@ -1112,7 +1113,7 @@ NSString* const kCommandsDescriptionText = @"The following commands are availabl
// tap on clear application cache
if ((indexPath.section == SETTINGS_SECTION_ROOMS_INDEX) && (indexPath.row == SETTINGS_SECTION_ROOMS_CLEAR_CACHE_INDEX)) {
// clear caches
[[MatrixSDKHandler sharedHandler] forceInitialSync:YES];
[[MatrixSDKHandler sharedHandler] reload:YES];
}
else if (indexPath.section == SETTINGS_SECTION_CONTACTS_INDEX) {