mirror of
https://github.com/vector-im/element-ios.git
synced 2024-09-28 23:32:41 +00:00
RoomVC: BF: Read receipts processing dramatically slows down UI
#1899 Build, cache and update read receipts on the processing queue.
This commit is contained in:
parent
429ebe3ce0
commit
715d9da536
4 changed files with 110 additions and 61 deletions
|
@ -6,6 +6,7 @@ Improvements:
|
|||
* RoomVC: Add a re-request keys button on message unable to decrypt (#1879).
|
||||
|
||||
Bug fix:
|
||||
* RoomVC: Read receipts processing dramatically slows down UI (#1899).
|
||||
|
||||
Changes in 0.6.17 (2018-06-01)
|
||||
===============================================
|
||||
|
|
|
@ -34,10 +34,6 @@ typedef NS_ENUM(NSInteger, RoomBubbleCellDataTag)
|
|||
*/
|
||||
@property(nonatomic) BOOL containsLastMessage;
|
||||
|
||||
/**
|
||||
A Boolean value that determines whether some read receipts are currently displayed in this bubble.
|
||||
*/
|
||||
@property(nonatomic) BOOL hasReadReceipts;
|
||||
|
||||
/**
|
||||
The event id of the current selected event inside the bubble. Default is nil.
|
||||
|
|
|
@ -48,13 +48,9 @@ static NSAttributedString *readReceiptVerticalWhitespace = nil;
|
|||
// Increase maximum number of components
|
||||
self.maxComponentCount = 20;
|
||||
|
||||
// Initialize receipts flag
|
||||
_hasReadReceipts = NO;
|
||||
|
||||
// Force the update of the text message to take into account the potential read receipts in the bubble display.
|
||||
// Note: we don't update this attributed string here because the RoomBubbleCellData instances are created on a processing
|
||||
// thread different from the UI thread.
|
||||
self.attributedTextMessage = nil;
|
||||
// Initialize read receipts
|
||||
self.readReceipts = [NSMutableDictionary dictionary];
|
||||
self.readReceipts[event.eventId] = [roomDataSource.room getEventReceipts:event.eventId sorted:YES];
|
||||
}
|
||||
|
||||
return self;
|
||||
|
@ -79,7 +75,6 @@ static NSAttributedString *readReceiptVerticalWhitespace = nil;
|
|||
[self refreshBubbleComponentsPosition];
|
||||
}
|
||||
|
||||
|
||||
shouldUpdateComponentsPosition = NO;
|
||||
}
|
||||
}
|
||||
|
@ -163,9 +158,6 @@ static NSAttributedString *readReceiptVerticalWhitespace = nil;
|
|||
|
||||
NSMutableAttributedString *currentAttributedTextMsg;
|
||||
|
||||
// Refresh the receipt flag during this process
|
||||
_hasReadReceipts = NO;
|
||||
|
||||
NSInteger selectedComponentIndex = self.selectedComponentIndex;
|
||||
NSInteger lastMessageIndex = self.containsLastMessage ? self.mostRecentComponentIndex : NSNotFound;
|
||||
|
||||
|
@ -204,10 +196,9 @@ static NSAttributedString *readReceiptVerticalWhitespace = nil;
|
|||
currentAttributedTextMsg = [[NSMutableAttributedString alloc] initWithAttributedString:componentString];
|
||||
}
|
||||
|
||||
// Vertical whitespace is added in case of read receipts
|
||||
if ([roomDataSource.room getEventReceipts:component.event.eventId sorted:NO])
|
||||
if (self.readReceipts[component.event.eventId].count)
|
||||
{
|
||||
_hasReadReceipts = YES;
|
||||
// Add vertical whitespace in case of read receipts
|
||||
[currentAttributedTextMsg appendAttributedString:[RoomBubbleCellData readReceiptVerticalWhitespace]];
|
||||
}
|
||||
|
||||
|
@ -246,10 +237,9 @@ static NSAttributedString *readReceiptVerticalWhitespace = nil;
|
|||
// Append attributed text
|
||||
[currentAttributedTextMsg appendAttributedString:componentString];
|
||||
|
||||
// Add vertical whitespace in case of read receipts
|
||||
if ([roomDataSource.room getEventReceipts:component.event.eventId sorted:NO])
|
||||
if (self.readReceipts[component.event.eventId].count)
|
||||
{
|
||||
_hasReadReceipts = YES;
|
||||
// Add vertical whitespace in case of read receipts
|
||||
[currentAttributedTextMsg appendAttributedString:[RoomBubbleCellData readReceiptVerticalWhitespace]];
|
||||
}
|
||||
}
|
||||
|
@ -262,9 +252,6 @@ static NSAttributedString *readReceiptVerticalWhitespace = nil;
|
|||
{
|
||||
// CAUTION: This method must be called on the main thread.
|
||||
|
||||
// Refresh the receipt flag during this process.
|
||||
_hasReadReceipts = NO;
|
||||
|
||||
@synchronized(bubbleComponents)
|
||||
{
|
||||
// Check whether there is at least one component.
|
||||
|
@ -283,7 +270,6 @@ static NSAttributedString *readReceiptVerticalWhitespace = nil;
|
|||
|
||||
if (component.attributedTextMessage)
|
||||
{
|
||||
_hasReadReceipts = ([roomDataSource.room getEventReceipts:component.event.eventId sorted:NO] != nil);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -308,7 +294,7 @@ static NSAttributedString *readReceiptVerticalWhitespace = nil;
|
|||
}
|
||||
|
||||
// Vertical whitespace is added in case of read receipts
|
||||
if (_hasReadReceipts)
|
||||
if (self.readReceipts.count)
|
||||
{
|
||||
[attributedString appendAttributedString:[RoomBubbleCellData readReceiptVerticalWhitespace]];
|
||||
}
|
||||
|
@ -348,9 +334,8 @@ static NSAttributedString *readReceiptVerticalWhitespace = nil;
|
|||
component.position = CGPointMake(0, positionY);
|
||||
|
||||
// Add vertical whitespace in case of read receipts.
|
||||
if ([roomDataSource.room getEventReceipts:component.event.eventId sorted:NO])
|
||||
if (self.readReceipts[component.event.eventId])
|
||||
{
|
||||
_hasReadReceipts = YES;
|
||||
[attributedString appendAttributedString:[RoomBubbleCellData readReceiptVerticalWhitespace]];
|
||||
}
|
||||
|
||||
|
@ -379,19 +364,6 @@ static NSAttributedString *readReceiptVerticalWhitespace = nil;
|
|||
}
|
||||
}
|
||||
|
||||
- (void)setHasReadReceipts:(BOOL)hasReadReceipts
|
||||
{
|
||||
// Check whether there is something to do
|
||||
if (_hasReadReceipts || hasReadReceipts)
|
||||
{
|
||||
// Update flag
|
||||
_hasReadReceipts = hasReadReceipts;
|
||||
|
||||
// Recompute the text message layout
|
||||
self.attributedTextMessage = nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setSelectedEventId:(NSString *)selectedEventId
|
||||
{
|
||||
// Check whether there is something to do
|
||||
|
@ -517,6 +489,9 @@ static NSAttributedString *readReceiptVerticalWhitespace = nil;
|
|||
return NO;
|
||||
}
|
||||
|
||||
// Update read receipts for this bubble
|
||||
self.readReceipts[event.eventId] = [roomDataSource.room getEventReceipts:event.eventId sorted:YES];
|
||||
|
||||
return [super addEvent:event andRoomState:roomState];
|
||||
}
|
||||
|
||||
|
|
|
@ -96,24 +96,101 @@
|
|||
|
||||
- (void)didReceiveReceiptEvent:(MXEvent *)receiptEvent roomState:(MXRoomState *)roomState
|
||||
{
|
||||
// Override this callback to force rendering of each cell with read receipts information.
|
||||
// Do the processing on the same processing queue as MXKRoomDataSource
|
||||
dispatch_async(MXKRoomDataSource.processingQueue, ^{
|
||||
|
||||
// Remove the previous displayed read receipt for each user who sent a
|
||||
// new read receipt.
|
||||
// To implement it, we need to find the sender id of each new read receipt
|
||||
// among the read receipts array of all events in all bubbles.
|
||||
NSMutableArray *readReceiptSenders = [receiptEvent.readReceiptSenders mutableCopy];
|
||||
|
||||
@synchronized(bubbles)
|
||||
{
|
||||
NSMutableDictionary<NSString* /* eventId */, NSMutableArray<MXReceiptData*> *> *updatedCellDataReadReceipts = [NSMutableDictionary dictionary];
|
||||
for (RoomBubbleCellData *cellData in bubbles)
|
||||
{
|
||||
cellData.hasReadReceipts = NO;
|
||||
for (NSString *eventId in cellData.readReceipts)
|
||||
{
|
||||
for (MXReceiptData *receiptData in cellData.readReceipts[eventId])
|
||||
{
|
||||
NSMutableArray *foundSenders = [NSMutableArray array];
|
||||
for (NSString *senderId in readReceiptSenders)
|
||||
{
|
||||
if ([receiptData.userId isEqualToString:senderId])
|
||||
{
|
||||
// We find an existing displayed receipt, remove it
|
||||
[foundSenders addObject:senderId];
|
||||
|
||||
if (!updatedCellDataReadReceipts[eventId])
|
||||
{
|
||||
updatedCellDataReadReceipts[eventId] = [cellData.readReceipts[eventId] mutableCopy];
|
||||
}
|
||||
|
||||
[updatedCellDataReadReceipts[eventId] removeObject:receiptData];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// As there is one (the last) read receipt displayed per user,
|
||||
// we do not need to search for other read receipts of found users.
|
||||
[readReceiptSenders removeObjectsInArray:foundSenders];
|
||||
if (!readReceiptSenders.count)
|
||||
{
|
||||
// All senders have been found
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Flush found changed to the cell data
|
||||
for (NSString *eventId in updatedCellDataReadReceipts)
|
||||
{
|
||||
if (updatedCellDataReadReceipts[eventId].count)
|
||||
{
|
||||
cellData.readReceipts[eventId] = updatedCellDataReadReceipts[eventId];
|
||||
}
|
||||
else
|
||||
{
|
||||
cellData.readReceipts[eventId] = nil;
|
||||
}
|
||||
}
|
||||
|
||||
if (!readReceiptSenders.count)
|
||||
{
|
||||
// All senders have been found
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update cell data we have received a read receipt for
|
||||
NSArray *readEventIds = receiptEvent.readReceiptEventIds;
|
||||
for (NSString* eventId in readEventIds)
|
||||
{
|
||||
RoomBubbleCellData *cellData = [self cellDataOfEventWithEventId:eventId];
|
||||
if (cellData)
|
||||
{
|
||||
@synchronized(bubbles)
|
||||
{
|
||||
if (!cellData.hasNoDisplay)
|
||||
{
|
||||
cellData.readReceipts[eventId] = [self.room getEventReceipts:eventId sorted:YES];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Ignore the read receipts on the events without an actual display.
|
||||
cellData.hasReadReceipts = !cellData.hasNoDisplay;
|
||||
cellData.readReceipts[eventId] = nil;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
// TODO: Be smarter and update only updated cells
|
||||
[super didReceiveReceiptEvent:receiptEvent roomState:roomState];
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
@ -181,7 +258,7 @@
|
|||
// Handle read receipts and read marker display.
|
||||
// Ignore the read receipts on the bubble without actual display.
|
||||
// Ignore the read receipts on collapsed bubbles
|
||||
if ((self.showBubbleReceipts && cellData.hasReadReceipts && !isCollapsableCellCollapsed) || self.showReadMarker)
|
||||
if ((self.showBubbleReceipts && cellData.readReceipts.count && !isCollapsableCellCollapsed) || self.showReadMarker)
|
||||
{
|
||||
// Read receipts container are inserted here on the right side into the content view.
|
||||
// Some vertical whitespaces are added in message text view (see RoomBubbleCellData class) to insert correctly multiple receipts.
|
||||
|
@ -194,10 +271,10 @@
|
|||
if (component.event.sentState != MXEventSentStateFailed)
|
||||
{
|
||||
// Handle read receipts (if any)
|
||||
if (self.showBubbleReceipts && cellData.hasReadReceipts && !isCollapsableCellCollapsed)
|
||||
if (self.showBubbleReceipts && cellData.readReceipts.count && !isCollapsableCellCollapsed)
|
||||
{
|
||||
// Get the events receipts by ignoring the current user receipt.
|
||||
NSArray* receipts = [self.room getEventReceipts:component.event.eventId sorted:YES];
|
||||
NSArray* receipts = cellData.readReceipts[component.event.eventId];
|
||||
NSMutableArray *roomMembers;
|
||||
NSMutableArray *placeholders;
|
||||
|
||||
|
|
Loading…
Reference in a new issue