Skip to content
This repository has been archived by the owner on Dec 12, 2022. It is now read-only.

Commit

Permalink
BF: When the last message is redacted, [MXKRecentCellData update] mak…
Browse files Browse the repository at this point in the history
…es paginations loops element-hq/element-ios#520

Use the new MXEventsEnumerator from MatrixSDK to find the right last message to display.
  • Loading branch information
manuroe committed Aug 24, 2016
1 parent 3ac3db3 commit e24b46a
Show file tree
Hide file tree
Showing 3 changed files with 206 additions and 122 deletions.
20 changes: 15 additions & 5 deletions MatrixKit/Models/Room/MXKRoomDataSource.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,11 +119,6 @@ extern NSString *const kMXKRoomDataSourceSyncStatusChanged;
*/
@property (nonatomic, readonly) BOOL isPeeking;

/**
The last event in the room that matches the `eventsFilterForMessages` property.
*/
@property (nonatomic, readonly) MXEvent *lastMessage;

/**
The list of the attachments with thumbnail in the current available bubbles (MXKAttachment instances).
*/
Expand Down Expand Up @@ -475,4 +470,19 @@ extern NSString *const kMXKRoomDataSourceSyncStatusChanged;
*/
- (void)handleUnsentMessages;

/**
The last event in the room.
This event must match several criteria:
- its type must be in `eventsFilterForMessages`
- it must follow the mxSession.ignoreProfileChangesDuringLastMessageProcessing
setting
- it must be displayable, ie the passed eventFormatter must return a non empty
string for it
@param eventFormatter the event formatter in order to check the displayability of events.
@param onComplete a block call when the operation completes. The provided lastMessage can be nil.
*/
- (void)lastMessageWithEventFormatter:(MXKEventFormatter*)eventFormatter onComplete:(void(^)(MXEvent *lastMessage))onComplete;

@end
187 changes: 138 additions & 49 deletions MatrixKit/Models/Room/MXKRoomDataSource.m
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,11 @@ Current pagination request (if any)
*/
MXPeekingRoom *peekingRoom;

/**
The cache for the last message returned by [self lastMessageWithEventFormatter:]
*/
MXEvent *lastMessage;

/**
Observe UIApplicationSignificantTimeChangeNotification to trigger cell change on time formatting change.
*/
Expand Down Expand Up @@ -378,6 +383,7 @@ - (void)reset

[bubbles removeAllObjects];
[eventIdToBubbleMap removeAllObjects];
lastMessage = nil;

_room = nil;
}
Expand Down Expand Up @@ -447,6 +453,7 @@ - (void)destroy

eventsToProcess = nil;
bubbles = nil;
lastMessage = nil;
eventIdToBubbleMap = nil;

[_timeline destroy];
Expand Down Expand Up @@ -583,50 +590,6 @@ - (void)didMXSessionStateChange
}
}

- (MXEvent *)lastMessage
{
MXEvent *lastMessage;

// Look for the most recent message (ignore events without timestamp).
id<MXKRoomBubbleCellDataStoring> bubbleData;
@synchronized(bubbles)
{
NSInteger index = bubbles.count;
while (index--)
{
bubbleData = bubbles[index];
if (bubbleData.date)
{
break;
}
}
}

if (bubbleData)
{
NSInteger index = bubbleData.events.count;
while (index--)
{
lastMessage = bubbleData.events[index];
if (lastMessage.originServerTs != kMXUndefinedTimestamp)
{
break;
}
lastMessage = nil;
}
}

if (!lastMessage)
{
// Use here the stored data for this room
lastMessage = [_room lastMessageWithTypeIn:_eventsFilterForMessages];

// Check if this event is a bing event
[self checkBing:lastMessage];
}
return lastMessage;
}

- (NSArray *)attachmentsWithThumbnail
{
NSMutableArray *attachments = [NSMutableArray array];
Expand Down Expand Up @@ -730,13 +693,13 @@ - (void)setEventsFilterForMessages:(NSArray *)eventsFilterForMessages
{
BOOL shouldRemoveBubbleData = NO;
BOOL hasChanged = NO;

MXEvent *redactedEvent = nil;

@synchronized (bubbleData)
{
// Retrieve the original event to redact it
NSArray *events = bubbleData.events;
MXEvent *redactedEvent = nil;


for (MXEvent *event in events)
{
if ([event.eventId isEqualToString:redactionEvent.redacts])
Expand Down Expand Up @@ -774,7 +737,13 @@ - (void)setEventsFilterForMessages:(NSArray *)eventsFilterForMessages
{
// Update the delegate on main thread
dispatch_async(dispatch_get_main_queue(), ^{


// Reset lastMessage if it has been redacted
if ([lastMessage.eventId isEqualToString:redactedEvent.eventId])
{
lastMessage = nil;
}

if (self.delegate)
{
[self.delegate dataSource:self didCellChange:nil];
Expand Down Expand Up @@ -1813,6 +1782,12 @@ - (void)removeEventWithEventId:(NSString *)eventId

// Remove the event from the outgoing messages storage
[_room removeOutgoingMessage:eventId];

// Reset lastMessage if it has been removed
if ([lastMessage.eventId isEqualToString:eventId])
{
lastMessage = nil;
}

// Update the delegate
if (self.delegate)
Expand Down Expand Up @@ -1877,6 +1852,98 @@ - (void)handleUnsentMessages
}
}

- (void)lastMessageWithEventFormatter:(MXKEventFormatter*)eventFormatter onComplete:(void(^)(MXEvent *))onComplete
{
// The last message can

// Firstly, check if it has been cached
if (lastMessage)
{
NSLog(@"lastMessage: case #1 for %@", self.roomId);
onComplete(lastMessage);
return;
}

MXEvent *lastDisplayableEvent;
MXEvent *event;
MXKEventFormatterError *error;

// Secondly, search for a matching event in the outgoing messages
id<MXEventsEnumerator> enumerator = [[MXEventsByTypesEnumeratorOnArray alloc] initWithMessages:_room.outgoingMessages
andTypesIn:self.eventsFilterForMessages
ignoreMemberProfileChanges:self.mxSession.ignoreProfileChangesDuringLastMessageProcessing];
while ((event = enumerator.nextEvent))
{
// Check that the event formatter can display the event
NSString *eventTextMessage = [eventFormatter stringFromEvent:event withRoomState:_room.state error:&error];
if (eventTextMessage.length)
{
lastDisplayableEvent = event;
NSLog(@"lastMessage: case #2 for %@", self.roomId);
break;
}
}

if (!lastDisplayableEvent)
{
// Thirdly, search for a matching event in the messages already in the store
// for this room
enumerator = [self.room enumeratorForStoredMessagesWithTypeIn:self.eventsFilterForMessages
ignoreMemberProfileChanges:self.mxSession.ignoreProfileChangesDuringLastMessageProcessing];

while ((event = enumerator.nextEvent))
{
// Check that the event formatter can display the event
NSString *eventTextMessage = [eventFormatter stringFromEvent:event withRoomState:_room.state error:&error];
if (eventTextMessage.length)
{
lastDisplayableEvent = event;
NSLog(@"lastMessage: case #3 for %@", self.roomId);
break;
}
}
}

if (lastDisplayableEvent)
{
// Cache it for future reuse
lastMessage = lastDisplayableEvent;
onComplete(lastDisplayableEvent);
}
else
{
if ([_timeline canPaginate: MXTimelineDirectionBackwards])
{
// Finally, as there is no matching events locally, get more messages from
// the homeserver
NSLog(@"lastMessage: case #4 for %@", self.roomId);

// Trigger asynchronously this back pagination to not block the UI thread.
dispatch_async(dispatch_get_main_queue(), ^{

// Make the data source load more messages than available in the store to
// force it to get them from the homeserver
[self paginate:(self.room.storedMessagesCount + 30) direction:MXTimelineDirectionBackwards onlyFromStore:NO success:^(NSUInteger addedCellNumber) {

[self lastMessageWithEventFormatter:eventFormatter onComplete:onComplete];

} failure:^(NSError *error) {

onComplete(nil);

}];
});
}
else
{
// All the room history has been loaded locally but no message matches the
// criteria
NSLog(@"lastMessage: case #5 for %@", self.roomId);
onComplete(nil);
}
}
}

#pragma mark - Private methods
- (MXEvent*)addLocalEchoForMessageContent:(NSDictionary*)msgContent
{
Expand Down Expand Up @@ -1965,6 +2032,15 @@ - (void)replaceLocalEcho:(MXEvent*)localEcho withEvent:(MXEvent*)event
{
[self removeCellData:bubbleData];
}

// Update lastMessage if it has been replaced
if ([lastMessage.eventId isEqualToString:localEcho.eventId])
{
// The new event should have the same characteristics as localEcho: it should
// match [self lastMessageWithEventFormatter:] criteria and can replace it as
// as the last message
lastMessage = event;
}

// Update the delegate
if (self.delegate)
Expand Down Expand Up @@ -2188,6 +2264,7 @@ - (void)processQueuedEvents:(void (^)(NSUInteger addedHistoryCellNb, NSUInteger
NSUInteger serverSyncEventCount = 0;
NSUInteger addedHistoryCellCount = 0;
NSUInteger addedLiveCellCount = 0;
BOOL lastMessageHasChanged = NO;

// Lock on `eventsToProcessSnapshot` to suspend reload or destroy during the process.
@synchronized(eventsToProcessSnapshot)
Expand Down Expand Up @@ -2371,6 +2448,12 @@ - (void)processQueuedEvents:(void (^)(NSUInteger addedHistoryCellNb, NSUInteger
eventIdToBubbleMap[queuedEvent.event.eventId] = bubbleData;
}
}

if (queuedEvent.direction == MXTimelineDirectionForwards)
{
// There is a new last message
lastMessageHasChanged = YES;
}
}
}
eventsToProcessSnapshot = nil;
Expand All @@ -2382,7 +2465,13 @@ - (void)processQueuedEvents:(void (^)(NSUInteger addedHistoryCellNb, NSUInteger
// Updated data can be displayed now
// Block MXKRoomDataSource.processingQueue while the processing is finalised on the main thread
dispatch_sync(dispatch_get_main_queue(), ^{


// Reset the last message cache if new live events have been received
if (lastMessageHasChanged)
{
lastMessage = nil;
}

// Check whether self has not been reloaded or destroyed
if (self.state == MXKDataSourceStateReady && bubblesSnapshot)
{
Expand Down
Loading

0 comments on commit e24b46a

Please sign in to comment.