From dbe56829f104fbbe82443c032348797e757f488b Mon Sep 17 00:00:00 2001 From: manuroe Date: Fri, 18 Jun 2021 15:44:57 +0200 Subject: [PATCH 1/2] Room lists: Avoid app freezes by building them on a separated thread #3777 --- CHANGES.rst | 1 + .../Recents/DataSources/RecentsDataSource.m | 737 ++++++++++-------- .../DataSources/RecentsDataSourceState.swift | 79 ++ 3 files changed, 500 insertions(+), 317 deletions(-) create mode 100644 Riot/Modules/Common/Recents/DataSources/RecentsDataSourceState.swift diff --git a/CHANGES.rst b/CHANGES.rst index 0bae4ae8e..ed19d3fdb 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -14,6 +14,7 @@ Changes to be released in next version * Security settings: The Secure backup section has been updated to match element-web UX (#4430). * Wording: Replace Recovery Passphrase and Recovery Key by Security Phrase and Security Key (#4268). * Room directory: Join room by alias or id (#4429). + * Room lists: Avoid app freezes by building them on a separated thread (#3777). 🐛 Bugfix * StartChatViewController: Add more helpful message when trying to start DM with a user that does not exist (#224). diff --git a/Riot/Modules/Common/Recents/DataSources/RecentsDataSource.m b/Riot/Modules/Common/Recents/DataSources/RecentsDataSource.m index 207e1975f..ea4eb52ec 100644 --- a/Riot/Modules/Common/Recents/DataSources/RecentsDataSource.m +++ b/Riot/Modules/Common/Recents/DataSources/RecentsDataSource.m @@ -43,12 +43,8 @@ NSString *const kRecentsDataSourceTapOnDirectoryServerChange = @"kRecentsDataSou @interface RecentsDataSource() { - NSMutableArray* invitesCellDataArray; - NSMutableArray* favoriteCellDataArray; - NSMutableArray* peopleCellDataArray; - NSMutableArray* conversationCellDataArray; - NSMutableArray* lowPriorityCellDataArray; - NSMutableArray* serverNoticeCellDataArray; + RecentsDataSourceState *state; + dispatch_queue_t processingQueue; NSInteger shrinkedSectionsBitMask; @@ -72,19 +68,13 @@ NSString *const kRecentsDataSourceTapOnDirectoryServerChange = @"kRecentsDataSou @implementation RecentsDataSource @synthesize directorySection, invitesSection, favoritesSection, peopleSection, conversationSection, lowPrioritySection, serverNoticeSection, secureBackupBannerSection, crossSigningBannerSection; @synthesize hiddenCellIndexPath, droppingCellIndexPath, droppingCellBackGroundView; -@synthesize invitesCellDataArray, favoriteCellDataArray, peopleCellDataArray, conversationCellDataArray, lowPriorityCellDataArray, serverNoticeCellDataArray; - (instancetype)init { self = [super init]; if (self) { - invitesCellDataArray = [[NSMutableArray alloc] init]; - favoriteCellDataArray = [[NSMutableArray alloc] init]; - peopleCellDataArray = [[NSMutableArray alloc] init]; - lowPriorityCellDataArray = [[NSMutableArray alloc] init]; - serverNoticeCellDataArray = [[NSMutableArray alloc] init]; - conversationCellDataArray = [[NSMutableArray alloc] init]; + processingQueue = dispatch_queue_create("MXRestClient", DISPATCH_QUEUE_SERIAL); _crossSigningBannerDisplay = CrossSigningBannerDisplayNone; crossSigningBannerSection = -1; @@ -112,6 +102,71 @@ NSString *const kRecentsDataSourceTapOnDirectoryServerChange = @"kRecentsDataSou return self; } + +#pragma mark - Properties + +- (NSArray *)invitesCellDataArray +{ + return state.invitesCellDataArray; +} +- (NSArray *)favoriteCellDataArray +{ + return state.favoriteCellDataArray; +} +- (NSArray *)peopleCellDataArray +{ + return state.peopleCellDataArray; +} +- (NSArray *)conversationCellDataArray +{ + return state.conversationCellDataArray; +} +- (NSArray *)lowPriorityCellDataArray +{ + return state.lowPriorityCellDataArray; +} +- (NSArray *)serverNoticeCellDataArray +{ + return state.serverNoticeCellDataArray; +} + +- (NSUInteger)missedFavouriteDiscussionsCount +{ + return state.favouriteMissedDiscussionsCount.count; +} +- (NSUInteger)missedHighlightFavouriteDiscussionsCount +{ + return state.favouriteMissedDiscussionsCount.highlightCount; +} + +- (NSUInteger)missedDirectDiscussionsCount +{ + return state.directMissedDiscussionsCount.count; +} +- (NSUInteger)missedHighlightDirectDiscussionsCount +{ + return state.directMissedDiscussionsCount.highlightCount; +} + +- (NSUInteger)missedGroupDiscussionsCount +{ + return state.groupMissedDiscussionsCount.count; +} +- (NSUInteger)groupMissedDiscussionsCount +{ + return state.favouriteMissedDiscussionsCount.highlightCount; +} + +- (NSUInteger)unsentMessagesDirectDiscussionsCount +{ + return state.unsentMessagesDirectDiscussionsCount; +} +- (NSUInteger)unsentMessagesGroupDiscussionsCount +{ + return state.unsentMessagesGroupDiscussionsCount; +} + + #pragma mark - - (void)setDelegate:(id)delegate andRecentsDataSourceMode:(RecentsDataSourceMode)recentsDataSourceMode @@ -364,10 +419,10 @@ NSString *const kRecentsDataSourceTapOnDirectoryServerChange = @"kRecentsDataSou // Refresh is disabled during drag&drop animation" if (!self.droppingCellIndexPath) { - [self refreshRoomsSections]; - - // And inform the delegate about the update - [self.delegate dataSource:self didCellChange:nil]; + [self refreshRoomsSection:^{ + // And inform the delegate about the update + [self.delegate dataSource:self didCellChange:nil]; + }]; } } @@ -407,12 +462,12 @@ NSString *const kRecentsDataSourceTapOnDirectoryServerChange = @"kRecentsDataSou secureBackupBannerSection = sectionsCount++; } - if (invitesCellDataArray.count > 0) + if (self.invitesCellDataArray.count > 0) { invitesSection = sectionsCount++; } - if (favoriteCellDataArray.count > 0) + if (self.favoriteCellDataArray.count > 0) { favoritesSection = sectionsCount++; } @@ -435,12 +490,12 @@ NSString *const kRecentsDataSourceTapOnDirectoryServerChange = @"kRecentsDataSou directorySection = sectionsCount++; } - if (lowPriorityCellDataArray.count > 0) + if (self.lowPriorityCellDataArray.count > 0) { lowPrioritySection = sectionsCount++; } - if (serverNoticeCellDataArray.count > 0) + if (self.serverNoticeCellDataArray.count > 0) { serverNoticeSection = sectionsCount++; } @@ -470,15 +525,15 @@ NSString *const kRecentsDataSourceTapOnDirectoryServerChange = @"kRecentsDataSou } else if (section == favoritesSection && !(shrinkedSectionsBitMask & RECENTSDATASOURCE_SECTION_FAVORITES)) { - count = favoriteCellDataArray.count; + count = self.favoriteCellDataArray.count; } else if (section == peopleSection && !(shrinkedSectionsBitMask & RECENTSDATASOURCE_SECTION_PEOPLE)) { - count = peopleCellDataArray.count ? peopleCellDataArray.count : 1; + count = self.peopleCellDataArray.count ? self.peopleCellDataArray.count : 1; } else if (section == conversationSection && !(shrinkedSectionsBitMask & RECENTSDATASOURCE_SECTION_CONVERSATIONS)) { - count = conversationCellDataArray.count ? conversationCellDataArray.count : 1; + count = self.conversationCellDataArray.count ? self.conversationCellDataArray.count : 1; } else if (section == directorySection && !(shrinkedSectionsBitMask & RECENTSDATASOURCE_SECTION_DIRECTORY)) { @@ -486,15 +541,15 @@ NSString *const kRecentsDataSourceTapOnDirectoryServerChange = @"kRecentsDataSou } else if (section == lowPrioritySection && !(shrinkedSectionsBitMask & RECENTSDATASOURCE_SECTION_LOWPRIORITY)) { - count = lowPriorityCellDataArray.count; + count = self.lowPriorityCellDataArray.count; } else if (section == serverNoticeSection && !(shrinkedSectionsBitMask & RECENTSDATASOURCE_SECTION_SERVERNOTICE)) { - count = serverNoticeCellDataArray.count; + count = self.serverNoticeCellDataArray.count; } else if (section == invitesSection && !(shrinkedSectionsBitMask & RECENTSDATASOURCE_SECTION_INVITES)) { - count = invitesCellDataArray.count; + count = self.invitesCellDataArray.count; } // Adjust this count according to the potential dragged cell. @@ -535,17 +590,17 @@ NSString *const kRecentsDataSourceTapOnDirectoryServerChange = @"kRecentsDataSou if (section == favoritesSection) { - count = favoriteCellDataArray.count; + count = self.favoriteCellDataArray.count; title = NSLocalizedStringFromTable(@"room_recents_favourites_section", @"Vector", nil); } else if (section == peopleSection) { - count = peopleCellDataArray.count; + count = self.peopleCellDataArray.count; title = NSLocalizedStringFromTable(@"room_recents_people_section", @"Vector", nil); } else if (section == conversationSection) { - count = conversationCellDataArray.count; + count = self.conversationCellDataArray.count; if (_recentsDataSourceMode == RecentsDataSourceModePeople) { @@ -562,17 +617,17 @@ NSString *const kRecentsDataSourceTapOnDirectoryServerChange = @"kRecentsDataSou } else if (section == lowPrioritySection) { - count = lowPriorityCellDataArray.count; + count = self.lowPriorityCellDataArray.count; title = NSLocalizedStringFromTable(@"room_recents_low_priority_section", @"Vector", nil); } else if (section == serverNoticeSection) { - count = serverNoticeCellDataArray.count; + count = self.serverNoticeCellDataArray.count; title = NSLocalizedStringFromTable(@"room_recents_server_notice_section", @"Vector", nil); } else if (section == invitesSection) { - count = invitesCellDataArray.count; + count = self.invitesCellDataArray.count; if (_recentsDataSourceMode == RecentsDataSourceModePeople) { @@ -616,23 +671,23 @@ NSString *const kRecentsDataSourceTapOnDirectoryServerChange = @"kRecentsDataSou if (section == favoritesSection) { - sectionArray = favoriteCellDataArray; + sectionArray = self.favoriteCellDataArray; } else if (section == peopleSection) { - sectionArray = peopleCellDataArray; + sectionArray = self.peopleCellDataArray; } else if (section == conversationSection) { - sectionArray = conversationCellDataArray; + sectionArray = self.conversationCellDataArray; } else if (section == lowPrioritySection) { - sectionArray = lowPriorityCellDataArray; + sectionArray = self.lowPriorityCellDataArray; } else if (section == serverNoticeSection) { - sectionArray = serverNoticeCellDataArray; + sectionArray = self.serverNoticeCellDataArray; } BOOL highlight = NO; @@ -877,8 +932,8 @@ NSString *const kRecentsDataSourceTapOnDirectoryServerChange = @"kRecentsDataSou return cell; } - else if ((indexPath.section == conversationSection && !conversationCellDataArray.count) - || (indexPath.section == peopleSection && !peopleCellDataArray.count)) + else if ((indexPath.section == conversationSection && !self.conversationCellDataArray.count) + || (indexPath.section == peopleSection && !self.peopleCellDataArray.count)) { MXKTableViewCell *tableViewCell = [tableView dequeueReusableCellWithIdentifier:[MXKTableViewCell defaultReuseIdentifier]]; if (!tableViewCell) @@ -927,44 +982,44 @@ NSString *const kRecentsDataSourceTapOnDirectoryServerChange = @"kRecentsDataSou if (tableSection == favoritesSection) { - if (cellDataIndex < favoriteCellDataArray.count) + if (cellDataIndex < self.favoriteCellDataArray.count) { - cellData = favoriteCellDataArray[cellDataIndex]; + cellData = self.favoriteCellDataArray[cellDataIndex]; } } else if (tableSection == peopleSection) { - if (cellDataIndex < peopleCellDataArray.count) + if (cellDataIndex < self.peopleCellDataArray.count) { - cellData = peopleCellDataArray[cellDataIndex]; + cellData = self.peopleCellDataArray[cellDataIndex]; } } else if (tableSection== conversationSection) { - if (cellDataIndex < conversationCellDataArray.count) + if (cellDataIndex < self.conversationCellDataArray.count) { - cellData = conversationCellDataArray[cellDataIndex]; + cellData = self.conversationCellDataArray[cellDataIndex]; } } else if (tableSection == lowPrioritySection) { - if (cellDataIndex < lowPriorityCellDataArray.count) + if (cellDataIndex < self.lowPriorityCellDataArray.count) { - cellData = lowPriorityCellDataArray[cellDataIndex]; + cellData = self.lowPriorityCellDataArray[cellDataIndex]; } } else if (tableSection == serverNoticeSection) { - if (cellDataIndex < serverNoticeCellDataArray.count) + if (cellDataIndex < self.serverNoticeCellDataArray.count) { - cellData = serverNoticeCellDataArray[cellDataIndex]; + cellData = self.serverNoticeCellDataArray[cellDataIndex]; } } else if (tableSection == invitesSection) { - if (cellDataIndex < invitesCellDataArray.count) + if (cellDataIndex < self.invitesCellDataArray.count) { - cellData = invitesCellDataArray[cellDataIndex]; + cellData = self.invitesCellDataArray[cellDataIndex]; } } @@ -981,8 +1036,8 @@ NSString *const kRecentsDataSourceTapOnDirectoryServerChange = @"kRecentsDataSou { return self.droppingCellBackGroundView.frame.size.height; } - if ((indexPath.section == conversationSection && !conversationCellDataArray.count) - || (indexPath.section == peopleSection && !peopleCellDataArray.count)) + if ((indexPath.section == conversationSection && !self.conversationCellDataArray.count) + || (indexPath.section == peopleSection && !self.peopleCellDataArray.count)) { return 50.0; } @@ -1015,7 +1070,7 @@ NSString *const kRecentsDataSourceTapOnDirectoryServerChange = @"kRecentsDataSou #pragma mark - -- (NSInteger)cellIndexPosWithRoomId:(NSString*)roomId andMatrixSession:(MXSession*)matrixSession within:(NSMutableArray*)cellDataArray +- (NSInteger)cellIndexPosWithRoomId:(NSString*)roomId andMatrixSession:(MXSession*)matrixSession within:(NSArray*)cellDataArray { if (roomId && matrixSession && cellDataArray.count) { @@ -1040,7 +1095,7 @@ NSString *const kRecentsDataSourceTapOnDirectoryServerChange = @"kRecentsDataSou if (invitesSection >= 0) { - index = [self cellIndexPosWithRoomId:roomId andMatrixSession:matrixSession within:invitesCellDataArray]; + index = [self cellIndexPosWithRoomId:roomId andMatrixSession:matrixSession within:self.invitesCellDataArray]; if (index != NSNotFound) { @@ -1055,7 +1110,7 @@ NSString *const kRecentsDataSourceTapOnDirectoryServerChange = @"kRecentsDataSou if (!indexPath && (favoritesSection >= 0)) { - index = [self cellIndexPosWithRoomId:roomId andMatrixSession:matrixSession within:favoriteCellDataArray]; + index = [self cellIndexPosWithRoomId:roomId andMatrixSession:matrixSession within:self.favoriteCellDataArray]; if (index != NSNotFound) { @@ -1070,7 +1125,7 @@ NSString *const kRecentsDataSourceTapOnDirectoryServerChange = @"kRecentsDataSou if (!indexPath && (peopleSection >= 0)) { - index = [self cellIndexPosWithRoomId:roomId andMatrixSession:matrixSession within:peopleCellDataArray]; + index = [self cellIndexPosWithRoomId:roomId andMatrixSession:matrixSession within:self.peopleCellDataArray]; if (index != NSNotFound) { @@ -1085,7 +1140,7 @@ NSString *const kRecentsDataSourceTapOnDirectoryServerChange = @"kRecentsDataSou if (!indexPath && (conversationSection >= 0)) { - index = [self cellIndexPosWithRoomId:roomId andMatrixSession:matrixSession within:conversationCellDataArray]; + index = [self cellIndexPosWithRoomId:roomId andMatrixSession:matrixSession within:self.conversationCellDataArray]; if (index != NSNotFound) { @@ -1100,7 +1155,7 @@ NSString *const kRecentsDataSourceTapOnDirectoryServerChange = @"kRecentsDataSou if (!indexPath && (lowPrioritySection >= 0)) { - index = [self cellIndexPosWithRoomId:roomId andMatrixSession:matrixSession within:lowPriorityCellDataArray]; + index = [self cellIndexPosWithRoomId:roomId andMatrixSession:matrixSession within:self.lowPriorityCellDataArray]; if (index != NSNotFound) { @@ -1115,7 +1170,7 @@ NSString *const kRecentsDataSourceTapOnDirectoryServerChange = @"kRecentsDataSou if (!indexPath && (serverNoticeSection >= 0)) { - index = [self cellIndexPosWithRoomId:roomId andMatrixSession:matrixSession within:serverNoticeCellDataArray]; + index = [self cellIndexPosWithRoomId:roomId andMatrixSession:matrixSession within:self.serverNoticeCellDataArray]; if (index != NSNotFound) { @@ -1134,268 +1189,266 @@ NSString *const kRecentsDataSourceTapOnDirectoryServerChange = @"kRecentsDataSou #pragma mark - MXKDataSourceDelegate -- (void)refreshRoomsSections +- (void)refreshRoomsSection:(void (^)(void))onComplete; { - NSDate *startDate = [NSDate date]; - - [invitesCellDataArray removeAllObjects]; - [favoriteCellDataArray removeAllObjects]; - [peopleCellDataArray removeAllObjects]; - [conversationCellDataArray removeAllObjects]; - [lowPriorityCellDataArray removeAllObjects]; - [serverNoticeCellDataArray removeAllObjects]; - - _missedFavouriteDiscussionsCount = _missedHighlightFavouriteDiscussionsCount = 0; - _missedDirectDiscussionsCount = _missedHighlightDirectDiscussionsCount = 0; - _missedGroupDiscussionsCount = _missedHighlightGroupDiscussionsCount = 0; - _unsentMessagesDirectDiscussionsCount = 0; - _unsentMessagesGroupDiscussionsCount = 0; - secureBackupBannerSection = directorySection = favoritesSection = peopleSection = conversationSection = lowPrioritySection = serverNoticeSection = invitesSection = -1; - + if (displayedRecentsDataSourceArray.count > 0) { // FIXME manage multi accounts MXKSessionRecentsDataSource *recentsDataSource = displayedRecentsDataSourceArray[0]; - MXSession* session = recentsDataSource.mxSession; + NSMutableArray> *cells = [NSMutableArray new]; NSInteger count = recentsDataSource.numberOfCells; - for (int index = 0; index < count; index++) + for (NSUInteger index = 0; index < count; index++) { - id recentCellDataStoring = [recentsDataSource cellDataAtIndex:index]; - MXRoom* room = recentCellDataStoring.roomSummary.room; + id cell = [recentsDataSource cellDataAtIndex:index]; + [cells addObject:cell]; + } + + MXWeakify(self); + [self computeStateAsyncWithCells:cells recentsDataSourceMode:self.recentsDataSourceMode matrixSession:recentsDataSource.mxSession onComplete:^(RecentsDataSourceState *newState) { + MXStrongifyAndReturnIfNil(self); - if (_recentsDataSourceMode == RecentsDataSourceModeHome) + self->state = newState; + onComplete(); + }]; + } + else + { + onComplete(); + } +} + +- (void)computeStateAsyncWithCells:(NSArray> *)cells + recentsDataSourceMode:(RecentsDataSourceMode)recentsDataSourceMode + matrixSession:(MXSession*)mxSession + onComplete:(void (^)(RecentsDataSourceState *newState))onComplete +{ + dispatch_async(processingQueue, ^{ + RecentsDataSourceState *newState = [RecentsDataSource computeStateWithCells:cells recentsDataSourceMode:recentsDataSourceMode matrixSession:mxSession]; + dispatch_async(dispatch_get_main_queue(), ^{ + onComplete(newState); + }); + }); +} + ++ (RecentsDataSourceState *)computeStateWithCells:(NSArray> *)cells + recentsDataSourceMode:(RecentsDataSourceMode)recentsDataSourceMode + matrixSession:(MXSession*)mxSession +{ + NSDate *startDate = [NSDate date]; + + NSMutableArray> *invitesCellDataArray = [NSMutableArray new]; + NSMutableArray> *favoriteCellDataArray = [NSMutableArray new]; + NSMutableArray> *peopleCellDataArray = [NSMutableArray new]; + NSMutableArray> *conversationCellDataArray = [NSMutableArray new]; + NSMutableArray> *lowPriorityCellDataArray = [NSMutableArray new]; + NSMutableArray> *serverNoticeCellDataArray = [NSMutableArray new]; + + MissedDiscussionsCount *favouriteMissedDiscussionsCount = [MissedDiscussionsCount new]; + MissedDiscussionsCount *directMissedDiscussionsCount = [MissedDiscussionsCount new]; + MissedDiscussionsCount *groupMissedDiscussionsCount = [MissedDiscussionsCount new]; + NSUInteger unsentMessagesDirectDiscussionsCount = 0; + NSUInteger unsentMessagesGroupDiscussionsCount = 0; + + for (id recentCellDataStoring in cells) + { + MXRoom* room = recentCellDataStoring.roomSummary.room; + + if (recentsDataSourceMode == RecentsDataSourceModeHome) + { + if (room.accountData.tags[kMXRoomTagServerNotice]) { - if (room.accountData.tags[kMXRoomTagServerNotice]) - { - [serverNoticeCellDataArray addObject:recentCellDataStoring]; - } - else if (room.accountData.tags[kMXRoomTagFavourite]) - { - [favoriteCellDataArray addObject:recentCellDataStoring]; - } - else if (room.accountData.tags[kMXRoomTagLowPriority]) - { - [lowPriorityCellDataArray addObject:recentCellDataStoring]; - } - else if (room.summary.membership == MXMembershipInvite) - { - [invitesCellDataArray addObject:recentCellDataStoring]; - } - else if (room.isDirect) - { - [peopleCellDataArray addObject:recentCellDataStoring]; - } - else - { - // Hide spaces from home (keep space invites) - if (room.summary.roomType != MXRoomTypeSpace) - { - [conversationCellDataArray addObject:recentCellDataStoring]; - } - } + [serverNoticeCellDataArray addObject:recentCellDataStoring]; } - else if (_recentsDataSourceMode == RecentsDataSourceModeFavourites) + else if (room.accountData.tags[kMXRoomTagFavourite]) { - // Keep only the favourites rooms. - if (room.accountData.tags[kMXRoomTagFavourite]) - { - [favoriteCellDataArray addObject:recentCellDataStoring]; - } + [favoriteCellDataArray addObject:recentCellDataStoring]; } - else if (_recentsDataSourceMode == RecentsDataSourceModePeople) + else if (room.accountData.tags[kMXRoomTagLowPriority]) { - // Keep only the direct rooms which are not low priority - if (room.isDirect && !room.accountData.tags[kMXRoomTagLowPriority]) - { - if (room.summary.membership == MXMembershipInvite) - { - [invitesCellDataArray addObject:recentCellDataStoring]; - } - else - { - [conversationCellDataArray addObject:recentCellDataStoring]; - } - } - } - else if (_recentsDataSourceMode == RecentsDataSourceModeRooms) - { - // Consider only non direct rooms. - if (!room.isDirect) - { - // Keep only the invites, the favourites and the rooms without tag and room type different from space - if (room.summary.membership == MXMembershipInvite) - { - [invitesCellDataArray addObject:recentCellDataStoring]; - } - else if ((!room.accountData.tags.count || room.accountData.tags[kMXRoomTagFavourite]) && room.summary.roomType != MXRoomTypeSpace) - { - [conversationCellDataArray addObject:recentCellDataStoring]; - } - } - } - - // Update missed conversations counts - NSUInteger notificationCount = recentCellDataStoring.roomSummary.notificationCount; - - // Ignore the regular notification count if the room is in 'mentions only" mode at the Riot level. - if (room.isMentionsOnly) - { - // Only the highlighted missed messages must be considered here. - notificationCount = recentCellDataStoring.roomSummary.highlightCount; - } - - if (notificationCount) - { - if (room.accountData.tags[kMXRoomTagFavourite]) - { - _missedFavouriteDiscussionsCount ++; - - if (recentCellDataStoring.roomSummary.highlightCount) - { - _missedHighlightFavouriteDiscussionsCount ++; - } - } - - if (room.isDirect) - { - _missedDirectDiscussionsCount ++; - - if (recentCellDataStoring.roomSummary.highlightCount) - { - _missedHighlightDirectDiscussionsCount ++; - } - } - else if (!room.accountData.tags.count || room.accountData.tags[kMXRoomTagFavourite]) - { - _missedGroupDiscussionsCount ++; - - if (recentCellDataStoring.roomSummary.highlightCount) - { - _missedHighlightGroupDiscussionsCount ++; - } - } + [lowPriorityCellDataArray addObject:recentCellDataStoring]; } else if (room.summary.membership == MXMembershipInvite) { - if (room.isDirect) - { - _missedDirectDiscussionsCount ++; - } - else - { - _missedGroupDiscussionsCount ++; - } + [invitesCellDataArray addObject:recentCellDataStoring]; } - - if (room.sentStatus != RoomSentStatusOk) + else if (room.isDirect) { - if (room.isDirect) + [peopleCellDataArray addObject:recentCellDataStoring]; + } + else + { + // Hide spaces from home (keep space invites) + if (room.summary.roomType != MXRoomTypeSpace) { - _unsentMessagesDirectDiscussionsCount ++; + [conversationCellDataArray addObject:recentCellDataStoring]; + } + } + } + else if (recentsDataSourceMode == RecentsDataSourceModeFavourites) + { + // Keep only the favourites rooms. + if (room.accountData.tags[kMXRoomTagFavourite]) + { + [favoriteCellDataArray addObject:recentCellDataStoring]; + } + } + else if (recentsDataSourceMode == RecentsDataSourceModePeople) + { + // Keep only the direct rooms which are not low priority + if (room.isDirect && !room.accountData.tags[kMXRoomTagLowPriority]) + { + if (room.summary.membership == MXMembershipInvite) + { + [invitesCellDataArray addObject:recentCellDataStoring]; } else { - _unsentMessagesGroupDiscussionsCount ++; + [conversationCellDataArray addObject:recentCellDataStoring]; + } + } + } + else if (recentsDataSourceMode == RecentsDataSourceModeRooms) + { + // Consider only non direct rooms. + if (!room.isDirect) + { + // Keep only the invites, the favourites and the rooms without tag and room type different from space + if (room.summary.membership == MXMembershipInvite) + { + [invitesCellDataArray addObject:recentCellDataStoring]; + } + else if ((!room.accountData.tags.count || room.accountData.tags[kMXRoomTagFavourite]) && room.summary.roomType != MXRoomTypeSpace) + { + [conversationCellDataArray addObject:recentCellDataStoring]; } } - } - if (_recentsDataSourceMode == RecentsDataSourceModeHome) + // Update missed conversations counts + NSUInteger notificationCount = recentCellDataStoring.roomSummary.notificationCount; + + // Ignore the regular notification count if the room is in 'mentions only" mode at the Riot level. + if (room.isMentionsOnly) { - BOOL pinMissedNotif = RiotSettings.shared.pinRoomsWithMissedNotificationsOnHome; - BOOL pinUnread = RiotSettings.shared.pinRoomsWithUnreadMessagesOnHome; - NSComparator comparator = nil; - - if (pinMissedNotif) + // Only the highlighted missed messages must be considered here. + notificationCount = recentCellDataStoring.roomSummary.highlightCount; + } + + if (notificationCount) + { + if (room.accountData.tags[kMXRoomTagFavourite]) { - // Sort each rooms collection by considering first the rooms with some missed notifs, the rooms with unread, then the others. - comparator = ^NSComparisonResult(id recentCellData1, id recentCellData2) { - - if (recentCellData1.roomSummary.room.sentStatus != RoomSentStatusOk - && recentCellData2.roomSummary.room.sentStatus == RoomSentStatusOk) - { - return NSOrderedAscending; - } - - if (recentCellData2.roomSummary.room.sentStatus != RoomSentStatusOk - && recentCellData1.roomSummary.room.sentStatus == RoomSentStatusOk) - { - return NSOrderedDescending; - } - - if (recentCellData1.highlightCount) - { - if (recentCellData2.highlightCount) - { - return NSOrderedSame; - } - else - { - return NSOrderedAscending; - } - } - else if (recentCellData2.highlightCount) - { - return NSOrderedDescending; - } - else if (recentCellData1.notificationCount) - { - if (recentCellData2.notificationCount) - { - return NSOrderedSame; - } - else - { - return NSOrderedAscending; - } - } - else if (recentCellData2.notificationCount) - { - return NSOrderedDescending; - } - else if (pinUnread) - { - if (recentCellData1.hasUnread) - { - if (recentCellData2.hasUnread) - { - return NSOrderedSame; - } - else - { - return NSOrderedAscending; - } - } - else if (recentCellData2.hasUnread) - { - return NSOrderedDescending; - } - } - - return NSOrderedSame; - }; + favouriteMissedDiscussionsCount.count ++; + + if (recentCellDataStoring.roomSummary.highlightCount) + { + favouriteMissedDiscussionsCount.highlightCount ++; + } } - else if (pinUnread) + + if (room.isDirect) { - // Sort each rooms collection by considering first the rooms with some unread messages then the others. - comparator = ^NSComparisonResult(id recentCellData1, id recentCellData2) { - - if (recentCellData1.roomSummary.room.sentStatus != RoomSentStatusOk - && recentCellData2.roomSummary.room.sentStatus == RoomSentStatusOk) + directMissedDiscussionsCount.count ++; + + if (recentCellDataStoring.roomSummary.highlightCount) + { + directMissedDiscussionsCount.highlightCount ++; + } + } + else if (!room.accountData.tags.count || room.accountData.tags[kMXRoomTagFavourite]) + { + groupMissedDiscussionsCount.count ++; + + if (recentCellDataStoring.roomSummary.highlightCount) + { + groupMissedDiscussionsCount.highlightCount ++; + } + } + } + else if (room.summary.membership == MXMembershipInvite) + { + if (room.isDirect) + { + directMissedDiscussionsCount.count ++; + } + else + { + groupMissedDiscussionsCount.highlightCount ++; + } + } + + if (room.sentStatus != RoomSentStatusOk) + { + if (room.isDirect) + { + unsentMessagesDirectDiscussionsCount ++; + } + else + { + unsentMessagesGroupDiscussionsCount ++; + } + } + } + + if (recentsDataSourceMode == RecentsDataSourceModeHome) + { + BOOL pinMissedNotif = RiotSettings.shared.pinRoomsWithMissedNotificationsOnHome; + BOOL pinUnread = RiotSettings.shared.pinRoomsWithUnreadMessagesOnHome; + NSComparator comparator = nil; + + if (pinMissedNotif) + { + // Sort each rooms collection by considering first the rooms with some missed notifs, the rooms with unread, then the others. + comparator = ^NSComparisonResult(id recentCellData1, id recentCellData2) { + + if (recentCellData1.roomSummary.room.sentStatus != RoomSentStatusOk + && recentCellData2.roomSummary.room.sentStatus == RoomSentStatusOk) + { + return NSOrderedAscending; + } + + if (recentCellData2.roomSummary.room.sentStatus != RoomSentStatusOk + && recentCellData1.roomSummary.room.sentStatus == RoomSentStatusOk) + { + return NSOrderedDescending; + } + + if (recentCellData1.highlightCount) + { + if (recentCellData2.highlightCount) + { + return NSOrderedSame; + } + else { return NSOrderedAscending; } - - if (recentCellData2.roomSummary.room.sentStatus != RoomSentStatusOk - && recentCellData1.roomSummary.room.sentStatus == RoomSentStatusOk) + } + else if (recentCellData2.highlightCount) + { + return NSOrderedDescending; + } + else if (recentCellData1.notificationCount) + { + if (recentCellData2.notificationCount) { - return NSOrderedDescending; + return NSOrderedSame; } - + else + { + return NSOrderedAscending; + } + } + else if (recentCellData2.notificationCount) + { + return NSOrderedDescending; + } + else if (pinUnread) + { if (recentCellData1.hasUnread) { if (recentCellData2.hasUnread) @@ -1411,33 +1464,15 @@ NSString *const kRecentsDataSourceTapOnDirectoryServerChange = @"kRecentsDataSou { return NSOrderedDescending; } - - return NSOrderedSame; - }; - } - - if (comparator) - { - // Sort the rooms collections - [favoriteCellDataArray sortUsingComparator:comparator]; - [peopleCellDataArray sortUsingComparator:comparator]; - [conversationCellDataArray sortUsingComparator:comparator]; - [lowPriorityCellDataArray sortUsingComparator:comparator]; - [serverNoticeCellDataArray sortUsingComparator:comparator]; - } - } - else if (favoriteCellDataArray.count > 0 && _recentsDataSourceMode == RecentsDataSourceModeFavourites) - { - // Sort them according to their tag order - [favoriteCellDataArray sortUsingComparator:^NSComparisonResult(id recentCellData1, id recentCellData2) { + } - return [session compareRoomsByTag:kMXRoomTagFavourite room1:recentCellData1.roomSummary.room room2:recentCellData2.roomSummary.room]; - - }]; + return NSOrderedSame; + }; } - else if (conversationCellDataArray.count > 0 && (_recentsDataSourceMode == RecentsDataSourceModeRooms || _recentsDataSourceMode == RecentsDataSourceModePeople)) + else if (pinUnread) { - [conversationCellDataArray sortUsingComparator:^NSComparisonResult(id recentCellData1, id recentCellData2) { + // Sort each rooms collection by considering first the rooms with some unread messages then the others. + comparator = ^NSComparisonResult(id recentCellData1, id recentCellData2) { if (recentCellData1.roomSummary.room.sentStatus != RoomSentStatusOk && recentCellData2.roomSummary.room.sentStatus == RoomSentStatusOk) @@ -1450,13 +1485,80 @@ NSString *const kRecentsDataSourceTapOnDirectoryServerChange = @"kRecentsDataSou { return NSOrderedDescending; } - - return NSOrderedAscending; - }]; + + if (recentCellData1.hasUnread) + { + if (recentCellData2.hasUnread) + { + return NSOrderedSame; + } + else + { + return NSOrderedAscending; + } + } + else if (recentCellData2.hasUnread) + { + return NSOrderedDescending; + } + + return NSOrderedSame; + }; + } + + if (comparator) + { + // Sort the rooms collections + [favoriteCellDataArray sortUsingComparator:comparator]; + [peopleCellDataArray sortUsingComparator:comparator]; + [conversationCellDataArray sortUsingComparator:comparator]; + [lowPriorityCellDataArray sortUsingComparator:comparator]; + [serverNoticeCellDataArray sortUsingComparator:comparator]; } } - + else if (favoriteCellDataArray.count > 0 && recentsDataSourceMode == RecentsDataSourceModeFavourites) + { + // Sort them according to their tag order + [favoriteCellDataArray sortUsingComparator:^NSComparisonResult(id recentCellData1, id recentCellData2) { + + return [mxSession compareRoomsByTag:kMXRoomTagFavourite room1:recentCellData1.roomSummary.room room2:recentCellData2.roomSummary.room]; + + }]; + } + else if (conversationCellDataArray.count > 0 && (recentsDataSourceMode == RecentsDataSourceModeRooms || recentsDataSourceMode == RecentsDataSourceModePeople)) + { + [conversationCellDataArray sortUsingComparator:^NSComparisonResult(id recentCellData1, id recentCellData2) { + + if (recentCellData1.roomSummary.room.sentStatus != RoomSentStatusOk + && recentCellData2.roomSummary.room.sentStatus == RoomSentStatusOk) + { + return NSOrderedAscending; + } + + if (recentCellData2.roomSummary.room.sentStatus != RoomSentStatusOk + && recentCellData1.roomSummary.room.sentStatus == RoomSentStatusOk) + { + return NSOrderedDescending; + } + + return NSOrderedAscending; + }]; + } + MXLogDebug(@"[RecentsDataSource] refreshRoomsSections: Done in %.0fms", [[NSDate date] timeIntervalSinceDate:startDate] * 1000); + + return [[RecentsDataSourceState alloc] + initWithInvitesCellDataArray:invitesCellDataArray + favoriteCellDataArray:favoriteCellDataArray + peopleCellDataArray:peopleCellDataArray + conversationCellDataArray:conversationCellDataArray + lowPriorityCellDataArray:lowPriorityCellDataArray + serverNoticeCellDataArray:serverNoticeCellDataArray + favouriteMissedDiscussionsCount:favouriteMissedDiscussionsCount + directMissedDiscussionsCount:directMissedDiscussionsCount + groupMissedDiscussionsCount:groupMissedDiscussionsCount + unsentMessagesDirectDiscussionsCount:unsentMessagesDirectDiscussionsCount + unsentMessagesGroupDiscussionsCount:unsentMessagesGroupDiscussionsCount]; } - (void)dataSource:(MXKDataSource*)dataSource didCellChange:(id)changes @@ -1479,10 +1581,11 @@ NSString *const kRecentsDataSourceTapOnDirectoryServerChange = @"kRecentsDataSou // 2 - call [self refreshRoomsSections] // refresh the sections - [self refreshRoomsSections]; - - // Call super to keep update readyRecentsDataSourceArray. - [super dataSource:dataSource didCellChange:changes]; + [self refreshRoomsSection:^{ + // Call super to keep update readyRecentsDataSourceArray. + [super dataSource:dataSource didCellChange:changes]; + }]; + } #pragma mark - Drag & Drop handling diff --git a/Riot/Modules/Common/Recents/DataSources/RecentsDataSourceState.swift b/Riot/Modules/Common/Recents/DataSources/RecentsDataSourceState.swift new file mode 100644 index 000000000..5f7b376dd --- /dev/null +++ b/Riot/Modules/Common/Recents/DataSources/RecentsDataSourceState.swift @@ -0,0 +1,79 @@ +// +// Copyright 2021 New Vector 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 Foundation + +/// The state for a room list screens. +@objcMembers +class RecentsDataSourceState: NSObject { + + // MARK: - Properties + + // MARK: Cells + let invitesCellDataArray: [MXKRecentCellDataStoring] + let favoriteCellDataArray: [MXKRecentCellDataStoring] + let peopleCellDataArray: [MXKRecentCellDataStoring] + let conversationCellDataArray: [MXKRecentCellDataStoring] + let lowPriorityCellDataArray: [MXKRecentCellDataStoring] + let serverNoticeCellDataArray: [MXKRecentCellDataStoring] + + // MARK: Notifications counts + let favouriteMissedDiscussionsCount: MissedDiscussionsCount + let directMissedDiscussionsCount: MissedDiscussionsCount + let groupMissedDiscussionsCount: MissedDiscussionsCount + + // MARK: Unsent counts + let unsentMessagesDirectDiscussionsCount: UInt + let unsentMessagesGroupDiscussionsCount: UInt + + + // MARK: - Setup + init(invitesCellDataArray: [MXKRecentCellDataStoring], + favoriteCellDataArray: [MXKRecentCellDataStoring], + peopleCellDataArray: [MXKRecentCellDataStoring], + conversationCellDataArray: [MXKRecentCellDataStoring], + lowPriorityCellDataArray: [MXKRecentCellDataStoring], + serverNoticeCellDataArray: [MXKRecentCellDataStoring], + favouriteMissedDiscussionsCount: MissedDiscussionsCount, + directMissedDiscussionsCount: MissedDiscussionsCount, + groupMissedDiscussionsCount: MissedDiscussionsCount, + unsentMessagesDirectDiscussionsCount: UInt, + unsentMessagesGroupDiscussionsCount: UInt) { + self.invitesCellDataArray = invitesCellDataArray + self.favoriteCellDataArray = favoriteCellDataArray + self.peopleCellDataArray = peopleCellDataArray + self.conversationCellDataArray = conversationCellDataArray + self.lowPriorityCellDataArray = lowPriorityCellDataArray + self.serverNoticeCellDataArray = serverNoticeCellDataArray + self.favouriteMissedDiscussionsCount = favouriteMissedDiscussionsCount + self.directMissedDiscussionsCount = directMissedDiscussionsCount + self.groupMissedDiscussionsCount = groupMissedDiscussionsCount + self.unsentMessagesDirectDiscussionsCount = unsentMessagesDirectDiscussionsCount + self.unsentMessagesGroupDiscussionsCount = unsentMessagesGroupDiscussionsCount + super.init() + } +} + + +/// Noticiations counts per section +@objcMembers +class MissedDiscussionsCount: NSObject { + /// Regular notifications + var count: UInt = 0 + + /// Mentions like notications + var highlightCount: UInt = 0 +} From a27a4d235f44fa95d6c21617f266a91ad12ac35e Mon Sep 17 00:00:00 2001 From: manuroe Date: Fri, 18 Jun 2021 16:34:38 +0200 Subject: [PATCH 2/2] Update Riot/Modules/Common/Recents/DataSources/RecentsDataSource.m Co-authored-by: ismailgulek --- Riot/Modules/Common/Recents/DataSources/RecentsDataSource.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Riot/Modules/Common/Recents/DataSources/RecentsDataSource.m b/Riot/Modules/Common/Recents/DataSources/RecentsDataSource.m index ea4eb52ec..a63d14489 100644 --- a/Riot/Modules/Common/Recents/DataSources/RecentsDataSource.m +++ b/Riot/Modules/Common/Recents/DataSources/RecentsDataSource.m @@ -74,7 +74,7 @@ NSString *const kRecentsDataSourceTapOnDirectoryServerChange = @"kRecentsDataSou self = [super init]; if (self) { - processingQueue = dispatch_queue_create("MXRestClient", DISPATCH_QUEUE_SERIAL); + processingQueue = dispatch_queue_create("RecentsDataSource", DISPATCH_QUEUE_SERIAL); _crossSigningBannerDisplay = CrossSigningBannerDisplayNone; crossSigningBannerSection = -1;