Recents: handle unread messages

This commit is contained in:
giomfo 2014-12-05 17:48:06 +01:00
parent a539220950
commit 6bed500694
5 changed files with 188 additions and 63 deletions

View file

@ -39,6 +39,7 @@
F0CEA5B119E6898800E47915 /* tab_home.ico in Resources */ = {isa = PBXBuildFile; fileRef = F0CEA5B019E6898800E47915 /* tab_home.ico */; };
F0D3C30C1A011EF10000D49E /* AppSettings.m in Sources */ = {isa = PBXBuildFile; fileRef = F0D3C30B1A011EF10000D49E /* AppSettings.m */; };
F0D3C30F1A01330F0000D49E /* SettingsTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = F0D3C30E1A01330F0000D49E /* SettingsTableViewCell.m */; };
F0D942F61A31F3A300826CC1 /* RecentRoom.m in Sources */ = {isa = PBXBuildFile; fileRef = F0D942F51A31F3A300826CC1 /* RecentRoom.m */; };
F0E84D401A1F9AEC005F2E42 /* RecentsTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = F0E84D3F1A1F9AEC005F2E42 /* RecentsTableViewCell.m */; };
/* End PBXBuildFile section */
@ -108,6 +109,8 @@
F0D3C30B1A011EF10000D49E /* AppSettings.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppSettings.m; sourceTree = "<group>"; };
F0D3C30D1A01330F0000D49E /* SettingsTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SettingsTableViewCell.h; sourceTree = "<group>"; };
F0D3C30E1A01330F0000D49E /* SettingsTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SettingsTableViewCell.m; sourceTree = "<group>"; };
F0D942F41A31F3A300826CC1 /* RecentRoom.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RecentRoom.h; sourceTree = "<group>"; };
F0D942F51A31F3A300826CC1 /* RecentRoom.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RecentRoom.m; sourceTree = "<group>"; };
F0E84D3E1A1F9AEC005F2E42 /* RecentsTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RecentsTableViewCell.h; sourceTree = "<group>"; };
F0E84D3F1A1F9AEC005F2E42 /* RecentsTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RecentsTableViewCell.m; sourceTree = "<group>"; };
/* End PBXFileReference section */
@ -204,6 +207,8 @@
F0465AF71A251F85003639F9 /* Model */ = {
isa = PBXGroup;
children = (
F0D942F41A31F3A300826CC1 /* RecentRoom.h */,
F0D942F51A31F3A300826CC1 /* RecentRoom.m */,
F0465AF81A251F85003639F9 /* RoomMessage.h */,
F0465AF91A251F85003639F9 /* RoomMessage.m */,
F01A0FF11A27314B009FAE2F /* RoomMessageComponent.h */,
@ -435,6 +440,7 @@
F03EF5FA19F171EB00A0EE52 /* RoomViewController.m in Sources */,
F03EF5F819F171EB00A0EE52 /* MasterTabBarController.m in Sources */,
F03EF5F619F171EB00A0EE52 /* HomeViewController.m in Sources */,
F0D942F61A31F3A300826CC1 /* RecentRoom.m in Sources */,
F03EF60219F19E7C00A0EE52 /* MediaManager.m in Sources */,
F03EF5F919F171EB00A0EE52 /* RecentsViewController.m in Sources */,
F0465AFA1A251F85003639F9 /* RoomMessage.m in Sources */,

View file

@ -111,7 +111,7 @@ static MatrixHandler *sharedHandler = nil;
self.mxSession = [[MXSession alloc] initWithMatrixRestClient:self.mxRestClient andStore:store];
// Check here whether the app user wants to display all the events
if ([[AppSettings sharedSettings] displayAllEvents]) {
// Use a filter to retrieve all the events
// Use a filter to retrieve all the events (except kMXEventTypeStringPresence which are not related to a specific room)
self.eventsFilterForMessages = @[
kMXEventTypeStringRoomName,
kMXEventTypeStringRoomTopic,
@ -121,8 +121,7 @@ static MatrixHandler *sharedHandler = nil;
kMXEventTypeStringRoomPowerLevels,
kMXEventTypeStringRoomAliases,
kMXEventTypeStringRoomMessage,
kMXEventTypeStringRoomMessageFeedback,
kMXEventTypeStringPresence
kMXEventTypeStringRoomMessageFeedback
];
}
else {
@ -257,8 +256,8 @@ static MatrixHandler *sharedHandler = nil;
if (isEnabled) {
// Register events listener
eventsListener = [self.mxSession listenToEventsOfTypes:self.eventsFilterForMessages onEvent:^(MXEvent *event, MXEventDirection direction, id customObject) {
// Consider only live event (Ignore presence event)
if (direction == MXEventDirectionForwards && (event.eventType != MXEventTypePresence)) {
// Consider only live event
if (direction == MXEventDirectionForwards) {
MXRoomState* roomState = (MXRoomState*)customObject;
// If we are running on background, show a local notif
if (UIApplicationStateBackground == [UIApplication sharedApplication].applicationState)
@ -268,8 +267,10 @@ static MatrixHandler *sharedHandler = nil;
localNotification.hasAction = YES;
[localNotification setAlertBody:[self displayTextForEvent:event withRoomState:roomState inSubtitleMode:YES]];
[[UIApplication sharedApplication] scheduleLocalNotification:localNotification];
} else if ([[AppDelegate theDelegate].masterTabBarController.visibleRoomId isEqualToString:event.roomId] == NO) {
// The concerned room is not presently visible, we display a notification by removing existing one (if any)
} else if (![event.userId isEqualToString:self.userId]
&& ![[AppDelegate theDelegate].masterTabBarController.visibleRoomId isEqualToString:event.roomId]) {
// The sender is not the user and the concerned room is not presently visible,
// we display a notification by removing existing one (if any)
if (self.mxNotification) {
[self.mxNotification dismiss:NO];
}

View file

@ -0,0 +1,28 @@
/*
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 <MatrixSDK/MatrixSDK.h>
@interface RecentRoom : NSObject
@property (nonatomic, readonly) NSString *roomId;
@property (nonatomic, readonly) MXEvent *lastEvent;
@property (nonatomic, readonly) NSUInteger unreadCount;
- (id)initWithLastEvent:(MXEvent*)event andMarkAsUnread:(BOOL)isUnread;
- (void)updateWithLastEvent:(MXEvent*)event andMarkAsUnread:(BOOL)isUnread;
- (void)resetUnreadCount;
@end

View file

@ -0,0 +1,50 @@
/*
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 "RecentRoom.h"
@implementation RecentRoom
- (id)initWithLastEvent:(MXEvent*)event andMarkAsUnread:(BOOL)isUnread {
if (self = [super init]) {
_lastEvent = event;
_unreadCount = isUnread ? 1 : 0;
}
return self;
}
- (void)updateWithLastEvent:(MXEvent*)event andMarkAsUnread:(BOOL)isUnread {
_lastEvent = event;
if (isUnread) {
_unreadCount ++;
}
}
- (void)resetUnreadCount {
_unreadCount = 0;
}
- (void)dealloc {
_lastEvent = nil;
}
#pragma mark -
- (NSString*)roomId {
return _lastEvent.roomId;
}
@end

View file

@ -17,12 +17,14 @@
#import "RecentsViewController.h"
#import "RoomViewController.h"
#import "RecentRoom.h"
#import "RecentsTableViewCell.h"
#import "AppDelegate.h"
#import "MatrixHandler.h"
@interface RecentsViewController () {
// Array of RecentRooms
NSMutableArray *recents;
id recentsListener;
@ -71,7 +73,7 @@
recents = nil;
filteredRecents = nil;
NSString *dateFormat = @"MMM dd HH:mm";
NSString *dateFormat = @"MMM dd HH:mm";
dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:[[[NSBundle mainBundle] preferredLocalizations] objectAtIndex:0]]];
[dateFormatter setFormatterBehavior:NSDateFormatterBehavior10_4];
@ -105,7 +107,7 @@
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
// Refresh recents table
// Refresh display
[self configureView];
[[MatrixHandler sharedHandler] addObserver:self forKeyPath:@"isInitialSyncDone" options:0 context:nil];
[[MatrixHandler sharedHandler] addObserver:self forKeyPath:@"isResumeDone" options:0 context:nil];
@ -123,11 +125,6 @@
// Hide activity indicator
[self stopActivityIndicator];
if (recentsListener) {
[[MatrixHandler sharedHandler].mxSession removeListener:recentsListener];
recentsListener = nil;
}
_preSelectedRoomId = nil;
[[MatrixHandler sharedHandler] removeObserver:self forKeyPath:@"isInitialSyncDone"];
[[MatrixHandler sharedHandler] removeObserver:self forKeyPath:@"isResumeDone"];
@ -149,8 +146,8 @@
// Look for the room index in recents list
NSIndexPath *indexPath = nil;
for (NSUInteger index = 0; index < recents.count; index++) {
MXEvent *mxEvent = [recents objectAtIndex:index];
if ([roomId isEqualToString:mxEvent.roomId]) {
RecentRoom *recentRoom = [recents objectAtIndex:index];
if ([roomId isEqualToString:recentRoom.roomId]) {
indexPath = [NSIndexPath indexPathForRow:index inSection:0];
break;
}
@ -176,35 +173,55 @@
- (void)configureView {
MatrixHandler *mxHandler = [MatrixHandler sharedHandler];
// Remove potential listener
if (recentsListener && mxHandler.mxSession) {
[mxHandler.mxSession removeListener:recentsListener];
recentsListener = nil;
}
[self startActivityIndicator];
if ([mxHandler isInitialSyncDone] || [mxHandler isLogged] == NO) {
// Update recents
// Create/Update recents
if (mxHandler.mxSession) {
recents = [NSMutableArray arrayWithArray:[mxHandler.mxSession recentsWithTypeIn:mxHandler.eventsFilterForMessages]];
// Register recent listener
recentsListener = [mxHandler.mxSession listenToEventsOfTypes:mxHandler.eventsFilterForMessages onEvent:^(MXEvent *event, MXEventDirection direction, id customObject) {
// consider only live event
if (direction == MXEventDirectionForwards) {
// Refresh the whole recents list
recents = [NSMutableArray arrayWithArray:[mxHandler.mxSession recentsWithTypeIn:mxHandler.eventsFilterForMessages]];
// Reload table
[self.tableView reloadData];
if ([mxHandler isResumeDone]) {
[self stopActivityIndicator];
}
// Check whether a room is preselected
if (_preSelectedRoomId) {
self.preSelectedRoomId = _preSelectedRoomId;
if (!recents) {
NSArray *recentEvents = [NSMutableArray arrayWithArray:[mxHandler.mxSession recentsWithTypeIn:mxHandler.eventsFilterForMessages]];
recents = [NSMutableArray arrayWithCapacity:recentEvents.count];
for (MXEvent *mxEvent in recentEvents) {
RecentRoom *recentRoom = [[RecentRoom alloc] initWithLastEvent:mxEvent andMarkAsUnread:NO];
if (recentRoom) {
[recents addObject:recentRoom];
}
}
}];
// Register recent listener
recentsListener = [mxHandler.mxSession listenToEventsOfTypes:mxHandler.eventsFilterForMessages onEvent:^(MXEvent *event, MXEventDirection direction, id customObject) {
// consider only live event
if (direction == MXEventDirectionForwards) {
// Consider this new event as unread only if the sender is not the user and if the room is not visible
BOOL isUnread = (![event.userId isEqualToString:mxHandler.userId]
&& ![[AppDelegate theDelegate].masterTabBarController.visibleRoomId isEqualToString:event.roomId]);
// Look for the room
BOOL isFound = NO;
for (NSUInteger index = 0; index < recents.count; index++) {
RecentRoom *recentRoom = [recents objectAtIndex:index];
if ([event.roomId isEqualToString:recentRoom.roomId]) {
isFound = YES;
[recentRoom updateWithLastEvent:event andMarkAsUnread:isUnread];
// Move this room at first position
[recents removeObjectAtIndex:index];
[recents insertObject:recentRoom atIndex:0];
break;
}
}
if (!isFound) {
// Insert in first position this new room
RecentRoom *recentRoom = [[RecentRoom alloc] initWithLastEvent:event andMarkAsUnread:isUnread];
if (recentRoom) {
[recents insertObject:recentRoom atIndex:0];
}
}
// Reload table
[self.tableView reloadData];
}
}];
}
// else nothing to do
} else {
recents = nil;
}
@ -223,6 +240,14 @@
recents = nil;
[self.tableView reloadData];
}
if (!recents) {
// Remove potential listener
if (recentsListener && mxHandler.mxSession) {
[mxHandler.mxSession removeListener:recentsListener];
recentsListener = nil;
}
}
}
- (void)createNewRoom:(id)sender {
@ -250,7 +275,7 @@
- (void)startActivityIndicator {
// Add the spinner on main screen in order to ignore potential table scrolling
_activityIndicator.center = CGPointMake( [UIScreen mainScreen].bounds.size.width/2,[UIScreen mainScreen].bounds.size.height/2 - 10);
_activityIndicator.center = CGPointMake(self.view.center.x, self.view.center.x);
[[AppDelegate theDelegate].window addSubview:_activityIndicator];
[_activityIndicator startAnimating];
}
@ -281,11 +306,11 @@
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:@"showDetail"]) {
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
MXEvent *mxEvent;
RecentRoom *recentRoom;
if (filteredRecents) {
mxEvent = filteredRecents[indexPath.row];
recentRoom = filteredRecents[indexPath.row];
} else {
mxEvent = recents[indexPath.row];
recentRoom = recents[indexPath.row];
}
UIViewController *controller;
@ -297,17 +322,24 @@
if ([controller isKindOfClass:[RoomViewController class]]) {
if (currentRoomViewController) {
if ((currentRoomViewController != controller) || (![currentRoomViewController.roomId isEqualToString:mxEvent.roomId])) {
if ((currentRoomViewController != controller) || (![currentRoomViewController.roomId isEqualToString:recentRoom.roomId])) {
// Release the current one
currentRoomViewController.roomId = nil;
}
}
currentRoomViewController = (RoomViewController *)controller;
currentRoomViewController.roomId = mxEvent.roomId;
currentRoomViewController.roomId = recentRoom.roomId;
}
controller.navigationItem.leftBarButtonItem = self.splitViewController.displayModeButtonItem;
controller.navigationItem.leftItemsSupplementBackButton = YES;
// Reset unread count for this room
[recentRoom resetUnreadCount];
if (self.splitViewController) {
// Refresh display (required in case of splitViewController)
[self.tableView reloadData];
controller.navigationItem.leftBarButtonItem = self.splitViewController.displayModeButtonItem;
controller.navigationItem.leftItemsSupplementBackButton = YES;
}
}
}
@ -342,18 +374,18 @@
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
RecentsTableViewCell *cell = (RecentsTableViewCell*)[tableView dequeueReusableCellWithIdentifier:@"RecentsCell" forIndexPath:indexPath];
MXEvent *mxEvent;
RecentRoom *recentRoom;
if (filteredRecents) {
mxEvent = filteredRecents[indexPath.row];
recentRoom = filteredRecents[indexPath.row];
} else {
mxEvent = recents[indexPath.row];
recentRoom = recents[indexPath.row];
}
MatrixHandler *mxHandler = [MatrixHandler sharedHandler];
MXRoom *mxRoom = [mxHandler.mxSession roomWithRoomId:mxEvent.roomId];
MXRoom *mxRoom = [mxHandler.mxSession roomWithRoomId:recentRoom.roomId];
cell.roomTitle.text = [mxRoom.state displayname];
cell.lastEventDescription.text = [mxHandler displayTextForEvent:mxEvent withRoomState:mxRoom.state inSubtitleMode:YES];
cell.lastEventDescription.text = [mxHandler displayTextForEvent:recentRoom.lastEvent withRoomState:mxRoom.state inSubtitleMode:YES];
// Set in bold public room name
if (mxRoom.state.isPublic) {
@ -362,12 +394,20 @@
cell.roomTitle.font = [UIFont systemFontOfSize:19];
}
if (mxEvent.originServerTs != kMXUndefinedTimestamp) {
NSDate *date = [NSDate dateWithTimeIntervalSince1970:mxEvent.originServerTs/1000];
if (recentRoom.lastEvent.originServerTs != kMXUndefinedTimestamp) {
NSDate *date = [NSDate dateWithTimeIntervalSince1970:recentRoom.lastEvent.originServerTs/1000];
cell.recentDate.text = [dateFormatter stringFromDate:date];
} else {
cell.recentDate.text = nil;
}
}
// set background color
if (recentRoom.unreadCount) {
cell.backgroundColor = [UIColor colorWithRed:1 green:0.9 blue:0.9 alpha:1.0];
cell.roomTitle.text = [NSString stringWithFormat:@"%@ (%d)", cell.roomTitle.text, recentRoom.unreadCount];
} else {
cell.backgroundColor = [UIColor clearColor];
}
return cell;
}
@ -379,13 +419,13 @@
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Leave the selected room
MXEvent *mxEvent;
RecentRoom *recentRoom;
if (filteredRecents) {
mxEvent = filteredRecents[indexPath.row];
recentRoom = filteredRecents[indexPath.row];
} else {
mxEvent = recents[indexPath.row];
recentRoom = recents[indexPath.row];
}
MXRoom *mxRoom = [[MatrixHandler sharedHandler].mxSession roomWithRoomId:mxEvent.roomId];
MXRoom *mxRoom = [[MatrixHandler sharedHandler].mxSession roomWithRoomId:recentRoom.roomId];
[mxRoom leave:^{
// Refresh table display
if (filteredRecents) {
@ -395,7 +435,7 @@
}
[tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
} failure:^(NSError *error) {
NSLog(@"Failed to leave room (%@) failed: %@", mxEvent.roomId, error);
NSLog(@"Failed to leave room (%@) failed: %@", recentRoom.roomId, error);
//Alert user
[[AppDelegate theDelegate] showErrorAsAlert:error];
}];
@ -417,10 +457,10 @@
filteredRecents = [NSMutableArray arrayWithCapacity:recents.count];
}
MatrixHandler *mxHandler = [MatrixHandler sharedHandler];
for (MXEvent *mxEvent in recents) {
MXRoom *mxRoom = [mxHandler.mxSession roomWithRoomId:mxEvent.roomId];
for (RecentRoom *recentRoom in recents) {
MXRoom *mxRoom = [mxHandler.mxSession roomWithRoomId:recentRoom.roomId];
if ([[mxRoom.state displayname] rangeOfString:searchText options:NSCaseInsensitiveSearch].location != NSNotFound) {
[filteredRecents addObject:mxEvent];
[filteredRecents addObject:recentRoom];
}
}
} else {