Handle new events notification

This commit is contained in:
giomfo 2014-10-30 18:23:02 +01:00
parent a8052f65b6
commit 3e6bbb2a25
9 changed files with 344 additions and 12 deletions

View file

@ -13,6 +13,7 @@
F024098219E7D177006E741B /* tab_recents@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = F024098119E7D177006E741B /* tab_recents@2x.png */; };
F02D707319F1CE4A007B47D3 /* CustomTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = F02D707219F1CE4A007B47D3 /* CustomTableViewCell.m */; };
F02D707619F1DC9E007B47D3 /* RoomMemberTableCell.m in Sources */ = {isa = PBXBuildFile; fileRef = F02D707519F1DC9E007B47D3 /* RoomMemberTableCell.m */; };
F03C47111A02952800E445AB /* CustomAlert.m in Sources */ = {isa = PBXBuildFile; fileRef = F03C47101A02952800E445AB /* CustomAlert.m */; };
F03EF5F619F171EB00A0EE52 /* HomeViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = F03EF5EB19F171EB00A0EE52 /* HomeViewController.m */; };
F03EF5F719F171EB00A0EE52 /* LoginViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = F03EF5ED19F171EB00A0EE52 /* LoginViewController.m */; };
F03EF5F819F171EB00A0EE52 /* MasterTabBarController.m in Sources */ = {isa = PBXBuildFile; fileRef = F03EF5EF19F171EB00A0EE52 /* MasterTabBarController.m */; };
@ -56,6 +57,8 @@
F02D707219F1CE4A007B47D3 /* CustomTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CustomTableViewCell.m; sourceTree = "<group>"; };
F02D707419F1DC9E007B47D3 /* RoomMemberTableCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RoomMemberTableCell.h; sourceTree = "<group>"; };
F02D707519F1DC9E007B47D3 /* RoomMemberTableCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RoomMemberTableCell.m; sourceTree = "<group>"; };
F03C470F1A02952800E445AB /* CustomAlert.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CustomAlert.h; sourceTree = "<group>"; };
F03C47101A02952800E445AB /* CustomAlert.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CustomAlert.m; sourceTree = "<group>"; };
F03EF5EA19F171EB00A0EE52 /* HomeViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HomeViewController.h; sourceTree = "<group>"; };
F03EF5EB19F171EB00A0EE52 /* HomeViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HomeViewController.m; sourceTree = "<group>"; };
F03EF5EC19F171EB00A0EE52 /* LoginViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LoginViewController.h; sourceTree = "<group>"; };
@ -206,6 +209,8 @@
F07A80DA19DD9DE700B621A1 /* AppDelegate.m */,
F0D3C30A1A011EF10000D49E /* AppSettings.h */,
F0D3C30B1A011EF10000D49E /* AppSettings.m */,
F03C470F1A02952800E445AB /* CustomAlert.h */,
F03C47101A02952800E445AB /* CustomAlert.m */,
F05B955D19DEED8A008761B0 /* MatrixHandler.h */,
F05B955E19DEED8A008761B0 /* MatrixHandler.m */,
F03EF60019F19E7C00A0EE52 /* MediaManager.h */,
@ -397,6 +402,7 @@
F03EF5F619F171EB00A0EE52 /* HomeViewController.m in Sources */,
F03EF60219F19E7C00A0EE52 /* MediaManager.m in Sources */,
F03EF5F919F171EB00A0EE52 /* RecentsViewController.m in Sources */,
F03C47111A02952800E445AB /* CustomAlert.m in Sources */,
F02D707619F1DC9E007B47D3 /* RoomMemberTableCell.m in Sources */,
F0D3C30C1A011EF10000D49E /* AppSettings.m in Sources */,
F03EF5F719F171EB00A0EE52 /* LoginViewController.m in Sources */,

View file

@ -54,6 +54,7 @@ static AppSettings *sharedSettings = nil;
}
- (void)setEnableNotifications:(BOOL)notifications {
[[MatrixHandler sharedHandler] enableEventsNotifications:notifications];
[[NSUserDefaults standardUserDefaults] setBool:notifications forKey:@"enableNotifications"];
}

View file

@ -0,0 +1,52 @@
/*
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 <UIKit/UIKit.h>
// Note: UIAlertView is deprecated in iOS 8. To create and manage alerts in iOS 8 and later, instead use UIAlertController
// with a preferredStyle of UIAlertControllerStyleAlert.
typedef enum : NSUInteger {
CustomAlertActionStyleDefault = 0,
CustomAlertActionStyleCancel,
CustomAlertActionStyleDestructive
} CustomAlertActionStyle;
typedef enum : NSUInteger {
CustomAlertStyleActionSheet = 0,
CustomAlertStyleAlert
} CustomAlertStyle;
@interface CustomAlert : NSObject <UIActionSheetDelegate> {
}
typedef void (^blockCustomAlert_onClick)(CustomAlert *alert);
typedef void (^blockCustomAlert_textFieldHandler)(UITextField *textField);
@property(nonatomic) NSInteger cancelButtonIndex; // required to dismiss cusmtomAlert on iOS < 8 (default is -1).
- (id)initWithTitle:(NSString *)title message:(NSString *)message style:(CustomAlertStyle)style;
// adds a button with the title. returns the index (0 based) of where it was added.
- (NSInteger)addActionWithTitle:(NSString *)title style:(CustomAlertActionStyle)style handler:(blockCustomAlert_onClick)handler;
// Adds a text field to an alert (Note: You can add a text field only if the style property is set to CustomAlertStyleAlert).
- (void)addTextFieldWithConfigurationHandler:(blockCustomAlert_textFieldHandler)configurationHandler;
- (void)showInViewController:(UIViewController*)viewController;
- (void)dismiss:(BOOL)animated;
- (UITextField *)textFieldAtIndex:(NSInteger)textFieldIndex;
@end

View file

@ -0,0 +1,192 @@
/*
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 "CustomAlert.h"
#import <objc/runtime.h>
@interface CustomAlert()
{
// alert is kind of UIAlertController for IOS 8 and later, in other cases it's kind of UIAlertView or UIActionSheet.
id alert;
UIViewController* parentViewController;
NSMutableArray *actions; // use only for iOS < 8
}
@end
@implementation CustomAlert
- (void)dealloc {
alert = nil;
parentViewController = nil;
actions = nil;
}
- (id)initWithTitle:(NSString *)title message:(NSString *)message style:(CustomAlertStyle)style {
if (self = [super init]) {
// Check iOS version
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8) {
alert = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:(UIAlertControllerStyle)style];
} else {
// Use legacy objects
if (style == CustomAlertStyleActionSheet) {
alert = [[UIActionSheet alloc] initWithTitle:title delegate:self cancelButtonTitle:nil destructiveButtonTitle:nil otherButtonTitles:nil];
} else {
alert = [[UIAlertView alloc] initWithTitle:title message:message delegate:self cancelButtonTitle:nil otherButtonTitles:nil];
}
self.cancelButtonIndex = -1;
}
}
return self;
}
- (NSInteger)addActionWithTitle:(NSString *)title style:(CustomAlertActionStyle)style handler:(blockCustomAlert_onClick)handler {
NSInteger index = 0;
if ([alert isKindOfClass:[UIAlertController class]]) {
index = [(UIAlertController *)alert actions].count;
UIAlertAction* action = [UIAlertAction actionWithTitle:title
style:(UIAlertActionStyle)style
handler:^(UIAlertAction * action) {
handler(self);
}];
[(UIAlertController *)alert addAction:action];
} else if ([alert isKindOfClass:[UIActionSheet class]]) {
if (actions == nil) {
actions = [NSMutableArray array];
}
index = [(UIActionSheet *)alert addButtonWithTitle:title];
if (handler) {
[actions addObject:handler];
} else {
[actions addObject:[NSNull null]];
}
} else if ([alert isKindOfClass:[UIAlertView class]]) {
if (actions == nil) {
actions = [NSMutableArray array];
}
index = [(UIAlertView *)alert addButtonWithTitle:title];
if (handler) {
[actions addObject:handler];
} else {
[actions addObject:[NSNull null]];
}
}
return index;
}
- (void)addTextFieldWithConfigurationHandler:(blockCustomAlert_textFieldHandler)configurationHandler {
if ([alert isKindOfClass:[UIAlertController class]]) {
[(UIAlertController *)alert addTextFieldWithConfigurationHandler:configurationHandler];
} else if ([alert isKindOfClass:[UIAlertView class]]) {
UIAlertView *alertView = (UIAlertView *)alert;
// Check the current style
if (alertView.alertViewStyle == UIAlertViewStyleDefault) {
// Add the first text fields
alertView.alertViewStyle = UIAlertViewStylePlainTextInput;
// Store the callback
UITextField *textField = [alertView textFieldAtIndex:0];
objc_setAssociatedObject(textField, "configurationHandler", [configurationHandler copy], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
} else if (alertView.alertViewStyle != UIAlertViewStyleLoginAndPasswordInput) {
// Add a second text field
alertView.alertViewStyle = UIAlertViewStyleLoginAndPasswordInput;
// Store the callback
UITextField *textField = [alertView textFieldAtIndex:1];
objc_setAssociatedObject(textField, "configurationHandler", [configurationHandler copy], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
// CAUTION 1: only 2 text fields are supported fro iOS < 8
// CAUTION 2: alert style "UIAlertViewStyleSecureTextInput" is not supported, use the configurationHandler to handle secure text field
}
}
- (void)showInViewController:(UIViewController*)viewController {
if ([alert isKindOfClass:[UIAlertController class]]) {
if (viewController) {
parentViewController = viewController;
[viewController presentViewController:(UIAlertController *)alert animated:YES completion:nil];
}
} else if ([alert isKindOfClass:[UIActionSheet class]]) {
[(UIActionSheet *)alert showInView:[[UIApplication sharedApplication] keyWindow]];
} else if ([alert isKindOfClass:[UIAlertView class]]) {
UIAlertView *alertView = (UIAlertView *)alert;
if (alertView.alertViewStyle != UIAlertViewStyleDefault) {
// Call here textField handlers
UITextField *textField = [alertView textFieldAtIndex:0];
blockCustomAlert_textFieldHandler configurationHandler = objc_getAssociatedObject(self, "configurationHandler");
if (configurationHandler) {
configurationHandler (textField);
}
if (alertView.alertViewStyle == UIAlertViewStyleLoginAndPasswordInput) {
textField = [alertView textFieldAtIndex:1];
blockCustomAlert_textFieldHandler configurationHandler = objc_getAssociatedObject(self, "configurationHandler");
if (configurationHandler) {
configurationHandler (textField);
}
}
}
[alertView show];
}
}
- (void)dismiss:(BOOL)animated {
if ([alert isKindOfClass:[UIAlertController class]]) {
[parentViewController dismissViewControllerAnimated:animated completion:nil];
} else if ([alert isKindOfClass:[UIActionSheet class]]) {
[((UIActionSheet *)alert) dismissWithClickedButtonIndex:self.cancelButtonIndex animated:animated];
} else if ([alert isKindOfClass:[UIAlertView class]]) {
[((UIAlertView *)alert) dismissWithClickedButtonIndex:self.cancelButtonIndex animated:animated];
}
}
- (UITextField *)textFieldAtIndex:(NSInteger)textFieldIndex{
if ([alert isKindOfClass:[UIAlertController class]]) {
return [((UIAlertController*)alert).textFields objectAtIndex:textFieldIndex];
} else if ([alert isKindOfClass:[UIAlertView class]]) {
return [((UIAlertView*)alert) textFieldAtIndex:textFieldIndex];
}
return nil;
}
#pragma mark - UIAlertViewDelegate (iOS < 8)
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
// Retrieve the callback
blockCustomAlert_onClick block = [actions objectAtIndex:buttonIndex];
if ([block isEqual:[NSNull null]] == NO) {
// And call it
block(self);
}
}
#pragma mark - UIActionSheetDelegate (iOS < 8)
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
// Retrieve the callback
blockCustomAlert_onClick block = [actions objectAtIndex:buttonIndex];
if ([block isEqual:[NSNull null]] == NO) {
// And call it
block(self);
}
}
@end

View file

@ -29,7 +29,6 @@ extern NSString *const kMatrixHandlerUnsupportedMessagePrefix;
@property (strong, nonatomic) MXSession *mxSession;
@property (strong, nonatomic) MXData *mxData;
@property (strong, nonatomic) NSString *homeServerURL;
@property (strong, nonatomic) NSString *homeServer;
@property (strong, nonatomic) NSString *userLogin;
@ -50,6 +49,8 @@ extern NSString *const kMatrixHandlerUnsupportedMessagePrefix;
// Flush and restore Matrix data
- (void)forceInitialSync;
- (void)enableEventsNotifications:(BOOL)isEnabled;
- (BOOL)isAttachment:(MXEvent*)message;
- (BOOL)isNotification:(MXEvent*)message;
- (NSString*)displayTextFor:(MXEvent*)message inSubtitleMode:(BOOL)isSubtitle;

View file

@ -17,6 +17,7 @@
#import "MatrixHandler.h"
#import "AppDelegate.h"
#import "AppSettings.h"
#import "CustomAlert.h"
NSString *const kMatrixHandlerUnsupportedMessagePrefix = @"UNSUPPORTED MSG: ";
@ -28,11 +29,12 @@ static MatrixHandler *sharedHandler = nil;
// Handle user's settings change
id roomMembersListener;
// Handle new events notification
// Handle events notification
id eventsListener;
}
@property (nonatomic,readwrite) BOOL isInitialSyncDone;
@property (strong, nonatomic) CustomAlert *mxNotification;
@end
@ -70,6 +72,8 @@ static MatrixHandler *sharedHandler = nil;
if (self.userDisplayName == nil) {
self.userDisplayName = @"";
}
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onAppDidEnterBackground) name:UIApplicationDidEnterBackgroundNotification object:nil];
}
return self;
}
@ -129,15 +133,9 @@ static MatrixHandler *sharedHandler = nil;
}
}];
// Check here whether the app user wants notifications on new events
// Check whether the app user wants notifications on new events
if ([[AppSettings sharedSettings] enableNotifications]) {
// Register events listener
eventsListener = [self.mxData registerEventListenerForTypes:self.mxData.eventsFilterForMessages block:^(MXData *matrixData, MXEvent *event, BOOL isLive) {
// Consider only live event
if (isLive) {
// TODO
}
}];
[self enableEventsNotifications:YES];
}
} failure:^(NSError *error) {
NSLog(@"Initial Sync failed: %@", error);
@ -173,8 +171,23 @@ static MatrixHandler *sharedHandler = nil;
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
[self closeSession];
self.mxHomeServer = nil;
if (self.mxNotification) {
[self.mxNotification dismiss:NO];
self.mxNotification = nil;
}
}
- (void)onAppDidEnterBackground {
// Hide potential notification
if (self.mxNotification) {
[self.mxNotification dismiss:NO];
self.mxNotification = nil;
}
}
#pragma mark -
@ -198,6 +211,61 @@ static MatrixHandler *sharedHandler = nil;
[self openSession];
}
- (void)enableEventsNotifications:(BOOL)isEnabled {
if (isEnabled) {
// Register events listener
eventsListener = [self.mxData registerEventListenerForTypes:self.mxData.eventsFilterForMessages block:^(MXData *matrixData, MXEvent *event, BOOL isLive) {
// Consider only live event
if (isLive) {
// If we are running on background, show a local notif
if (UIApplicationStateBackground == [UIApplication sharedApplication].applicationState)
{
UILocalNotification *localNotification = [[UILocalNotification alloc] init];
localNotification.fireDate = [NSDate dateWithTimeIntervalSinceNow:0];
localNotification.hasAction = YES;
[localNotification setAlertBody:[self displayTextFor:event inSubtitleMode:YES]];
[[UIApplication sharedApplication] scheduleLocalNotification:localNotification];
} else if ([[AppDelegate theDelegate].masterTabBarController.visibleRoomId isEqualToString:event.room_id] == NO) {
// The concerned room is not presently visible, we display a notification by removing existing one (if any)
if (self.mxNotification) {
[self.mxNotification dismiss:NO];
self.mxNotification = nil;
}
self.mxNotification = [[CustomAlert alloc] initWithTitle:[self.mxData getRoomData:event.room_id].displayname
message:[self displayTextFor:event inSubtitleMode:YES]
style:CustomAlertStyleAlert];
self.mxNotification.cancelButtonIndex = [self.mxNotification addActionWithTitle:@"OK"
style:CustomAlertActionStyleDefault
handler:^(CustomAlert *alert) {
[MatrixHandler sharedHandler].mxNotification = nil;
}];
[self.mxNotification addActionWithTitle:@"View"
style:CustomAlertActionStyleDefault
handler:^(CustomAlert *alert) {
[MatrixHandler sharedHandler].mxNotification = nil;
// Show the room
[[AppDelegate theDelegate].masterTabBarController showRoom:event.room_id];
}];
[self.mxNotification showInViewController:[[AppDelegate theDelegate].masterTabBarController selectedViewController]];
}
}
}];
} else {
if (eventsListener) {
[self.mxData unregisterListener:eventsListener];
eventsListener = nil;
}
if (self.mxNotification) {
[self.mxNotification dismiss:NO];
self.mxNotification = nil;
}
}
}
#pragma mark - Properties
- (NSString *)homeServerURL {
return [[NSUserDefaults standardUserDefaults] objectForKey:@"homeserverurl"];
}

View file

@ -27,5 +27,7 @@
- (void)showRoomCreationForm;
- (void)showRoom:(NSString*)roomId;
@property (strong, nonatomic) NSString *visibleRoomId; // nil if no room is presently visible
@end

View file

@ -28,6 +28,8 @@
@implementation MasterTabBarController
@synthesize visibleRoomId;
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
@ -91,8 +93,10 @@
// Switch on Recents Tab
[self setSelectedIndex:TABBAR_RECENTS_INDEX];
// Select room to display its details
// Select room to display its details (dispatch this action in order to let TabBarController end its refresh)
dispatch_async(dispatch_get_main_queue(), ^{
recentsViewController.preSelectedRoomId = roomId;
});
}
@end

View file

@ -118,6 +118,9 @@ NSString *const kFailedEventId = @"failedEventId";
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onKeyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onTextFieldChange:) name:UITextFieldTextDidChangeNotification object:nil];
// Set visible room id
[AppDelegate theDelegate].masterTabBarController.visibleRoomId = self.roomId;
}
- (void)viewWillDisappear:(BOOL)animated {
@ -134,6 +137,9 @@ NSString *const kFailedEventId = @"failedEventId";
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UITextFieldTextDidChangeNotification object:nil];
// Reset visible room id
[AppDelegate theDelegate].masterTabBarController.visibleRoomId = nil;
}
- (void)viewDidAppear:(BOOL)animated {