diff --git a/Riot/Modules/MatrixKit/Models/Room/MXKRoomDataSource.m b/Riot/Modules/MatrixKit/Models/Room/MXKRoomDataSource.m index d7bc678227..34e3353870 100644 --- a/Riot/Modules/MatrixKit/Models/Room/MXKRoomDataSource.m +++ b/Riot/Modules/MatrixKit/Models/Room/MXKRoomDataSource.m @@ -2358,18 +2358,46 @@ - (void)didReceiveReceiptEvent:(MXEvent *)receiptEvent roomState:(MXRoomState *) // Update cell data we have received a read receipt for NSArray *readEventIds = receiptEvent.readReceiptEventIds; - for (NSString* eventId in readEventIds) + NSArray *readThreadIds = receiptEvent.readReceiptThreadIds; + for (int i = 0 ; i < readEventIds.count ; i++) { + NSString *eventId = readEventIds[i]; MXKRoomBubbleCellData *cellData = [self cellDataOfEventWithEventId:eventId]; if (cellData) { - @synchronized(self->bubbles) + if ([readThreadIds[i] isEqualToString:kMXEventUnthreaded]) { - dispatch_group_enter(dispatchGroup); - [self addReadReceiptsForEvent:eventId inCellDatas:self->bubbles startingAtCellData:cellData completion:^{ - dispatch_group_leave(dispatchGroup); + // Unthreaded RR must be propagated through all threads. + [self.mxSession.threadingService allThreadsInRoomWithId:self.roomId onlyParticipated:NO completion:^(NSArray> *threads) { + NSMutableArray *threadIds = [NSMutableArray arrayWithObject:kMXEventTimelineMain]; + for (id thread in threads) + { + [threadIds addObject:thread.id]; + } + + for (NSString *threadId in threadIds) + { + @synchronized(self->bubbles) + { + dispatch_group_enter(dispatchGroup); + [self addReadReceiptsForEvent:eventId threadId:threadId inCellDatas:self->bubbles startingAtCellData:cellData completion:^{ + dispatch_group_leave(dispatchGroup); + }]; + } + } }]; } + else + { + NSString *threadId = readThreadIds[i]; + @synchronized(self->bubbles) + { + dispatch_group_enter(dispatchGroup); + [self addReadReceiptsForEvent:eventId threadId:threadId inCellDatas:self->bubbles startingAtCellData:cellData completion:^{ + dispatch_group_leave(dispatchGroup); + }]; + } + } } } @@ -3512,7 +3540,10 @@ - (void)processQueuedEvents:(void (^)(NSUInteger addedHistoryCellNb, NSUInteger @autoreleasepool { dispatch_group_enter(dispatchGroup); - [self addReadReceiptsForEvent:queuedEvent.event.eventId inCellDatas:self->bubblesSnapshot startingAtCellData:self->eventIdToBubbleMap[queuedEvent.event.eventId] completion:^{ + [self addReadReceiptsForEvent:queuedEvent.event.eventId + threadId:queuedEvent.event.threadId + inCellDatas:self->bubblesSnapshot + startingAtCellData:self->eventIdToBubbleMap[queuedEvent.event.eventId] completion:^{ dispatch_group_leave(dispatchGroup); }]; } @@ -3667,16 +3698,22 @@ Add the read receipts of an event into the timeline (which is in array of cell d If the event is not displayed, read receipts will be added to a previous displayed message. @param eventId the id of the event. + @param threadId the Id of the thread related of the event. @param cellDatas the working array of cell datas. @param cellData the original cell data the event belongs to. + @param completion completion block */ -- (void)addReadReceiptsForEvent:(NSString*)eventId inCellDatas:(NSArray>*)cellDatas startingAtCellData:(id)cellData completion:(void (^)(void))completion +- (void)addReadReceiptsForEvent:(NSString*)eventId + threadId:(NSString *)threadId + inCellDatas:(NSArray>*)cellDatas + startingAtCellData:(id)cellData + completion:(void (^)(void))completion { if (self.showBubbleReceipts) { if (self.room) { - [self.room getEventReceipts:eventId sorted:YES completion:^(NSArray * _Nonnull readReceipts) { + [self.room getEventReceipts:eventId threadId:threadId sorted:YES completion:^(NSArray * _Nonnull readReceipts) { if (readReceipts.count) { NSInteger cellDataIndex = [cellDatas indexOfObject:cellData]; diff --git a/Riot/Modules/Room/DataSources/ThreadDataSource.swift b/Riot/Modules/Room/DataSources/ThreadDataSource.swift index 3f69f7a041..603ae8862b 100644 --- a/Riot/Modules/Room/DataSources/ThreadDataSource.swift +++ b/Riot/Modules/Room/DataSources/ThreadDataSource.swift @@ -27,8 +27,8 @@ public class ThreadDataSource: RoomDataSource { public override func finalizeInitialization() { super.finalizeInitialization() - showReadMarker = false - showBubbleReceipts = false + showReadMarker = true + showBubbleReceipts = true showTypingRow = false NotificationCenter.default.addObserver(self, @@ -42,22 +42,6 @@ public class ThreadDataSource: RoomDataSource { object: nil) } - public override var showReadMarker: Bool { - get { - return false - } set { - _ = newValue - } - } - - public override var showBubbleReceipts: Bool { - get { - return false - } set { - _ = newValue - } - } - public override class func load(withRoomId roomId: String!, initialEventId: String!, threadId: String!, diff --git a/Riot/Modules/Room/MXKRoomViewController.m b/Riot/Modules/Room/MXKRoomViewController.m index b0f547bc44..8c1376bce4 100644 --- a/Riot/Modules/Room/MXKRoomViewController.m +++ b/Riot/Modules/Room/MXKRoomViewController.m @@ -368,6 +368,8 @@ - (void)viewDidAppear:(BOOL)animated // Mark all messages as read when the room is displayed [self.roomDataSource.room.summary markAllAsReadLocally]; + + [self updateCurrentEventIdAtTableBottom:YES]; } - (void)viewWillDisappear:(BOOL)animated @@ -2497,7 +2499,10 @@ - (void)updateCurrentEventIdAtTableBottom:(BOOL)acknowledge updateReadMarker = (currentReadMarkerEvent && (currentReadMarkerEvent.originServerTs <= component.event.originServerTs)); } - [roomDataSource.room acknowledgeEvent:component.event andUpdateReadMarker:updateReadMarker]; + if (self.navigationController.viewControllers.lastObject == self) + { + [roomDataSource.room acknowledgeEvent:component.event andUpdateReadMarker:updateReadMarker]; + } } break; } diff --git a/Riot/Modules/Threads/ThreadsCoordinator.swift b/Riot/Modules/Threads/ThreadsCoordinator.swift index bc0a3608a6..9e09cacf5f 100644 --- a/Riot/Modules/Threads/ThreadsCoordinator.swift +++ b/Riot/Modules/Threads/ThreadsCoordinator.swift @@ -68,10 +68,6 @@ final class ThreadsCoordinator: NSObject, ThreadsCoordinatorProtocol { // Detect when view controller has been dismissed by gesture when presented modally (not in full screen). self.navigationRouter.toPresentable().presentationController?.delegate = self - guard parameters.threadId == nil else { - return - } - if self.navigationRouter.modules.isEmpty == false { self.navigationRouter.push(rootCoordinator, animated: true, popCompletion: { [weak self] in self?.remove(childCoordinator: rootCoordinator) diff --git a/RiotNSE/NotificationService.swift b/RiotNSE/NotificationService.swift index 3b48903646..1d7f5cf074 100644 --- a/RiotNSE/NotificationService.swift +++ b/RiotNSE/NotificationService.swift @@ -845,7 +845,7 @@ class NotificationService: UNNotificationServiceExtension { return } - mxRestClient.sendReadReceipt(toRoom: roomId, forEvent: eventId) { response in + mxRestClient.sendReadReceipt(toRoom: roomId, forEvent: eventId, threadId: event.threadId) { response in if response.isSuccess { MXLog.debug("[NotificationService] sendReadReceipt: Read receipt send successfully.") } else if let error = response.error { diff --git a/changelog.d/6663.feature b/changelog.d/6663.feature new file mode 100644 index 0000000000..ce8bdd593d --- /dev/null +++ b/changelog.d/6663.feature @@ -0,0 +1 @@ +Threads: added support to read receipts (MSC3771)