Skip to content
This repository was archived by the owner on Sep 11, 2024. It is now read-only.

Commit 3134d4e

Browse files
author
Germain Souquet
committed
Enable read receipts on thread timelines
1 parent 9e0798f commit 3134d4e

File tree

6 files changed

+55
-38
lines changed

6 files changed

+55
-38
lines changed

src/components/structures/MessagePanel.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -826,8 +826,13 @@ export default class MessagePanel extends React.Component<IProps, IState> {
826826
if (!room) {
827827
return null;
828828
}
829+
830+
const receiptDestination = this.context.threadId
831+
? room.getThread(this.context.threadId)
832+
: room;
833+
829834
const receipts: IReadReceiptProps[] = [];
830-
room.getReceiptsForEvent(event).forEach((r) => {
835+
receiptDestination.getReceiptsForEvent(event).forEach((r) => {
831836
if (
832837
!r.userId ||
833838
!isSupportedReceiptType(r.type) ||

src/components/structures/ThreadPanel.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -282,10 +282,10 @@ const ThreadPanel: React.FC<IProps> = ({
282282
? <TimelinePanel
283283
key={timelineSet.getFilter()?.filterId ?? (roomId + ":" + filterOption)}
284284
ref={timelinePanel}
285-
showReadReceipts={false} // No RR support in thread's MVP
286-
manageReadReceipts={false} // No RR support in thread's MVP
287-
manageReadMarkers={false} // No RM support in thread's MVP
288-
sendReadReceiptOnLoad={false} // No RR support in thread's MVP
285+
showReadReceipts={false} // No RR support in thread's list
286+
manageReadReceipts={false} // No RR support in thread's list
287+
manageReadMarkers={false} // No RM support in thread's list
288+
sendReadReceiptOnLoad={false} // No RR support in thread's list
289289
timelineSet={timelineSet}
290290
showUrlPreview={false} // No URL previews at the threads list level
291291
empty={<EmptyThread

src/components/structures/ThreadView.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -328,8 +328,7 @@ export default class ThreadView extends React.Component<IProps, IState> {
328328
<TimelinePanel
329329
key={this.state.thread.id}
330330
ref={this.timelinePanel}
331-
showReadReceipts={false} // Hide the read receipts
332-
// until homeservers speak threads language
331+
showReadReceipts={true}
333332
manageReadReceipts={true}
334333
manageReadMarkers={true}
335334
sendReadReceiptOnLoad={true}

src/components/structures/TimelinePanel.tsx

Lines changed: 40 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -943,13 +943,13 @@ class TimelinePanel extends React.Component<IProps, IState> {
943943
if (lastReadEventIndex === null) {
944944
shouldSendRR = false;
945945
}
946-
let lastReadEvent = this.state.events[lastReadEventIndex];
946+
let lastReadEvent: MatrixEvent | null = this.state.events[lastReadEventIndex];
947947
shouldSendRR = shouldSendRR &&
948948
// Only send a RR if the last read event is ahead in the timeline relative to
949949
// the current RR event.
950950
lastReadEventIndex > currentRREventIndex &&
951951
// Only send a RR if the last RR set != the one we would send
952-
this.lastRRSentEventId != lastReadEvent.getId();
952+
this.lastRRSentEventId !== lastReadEvent.getId();
953953

954954
// Only send a RM if the last RM sent != the one we would send
955955
const shouldSendRM =
@@ -975,33 +975,43 @@ class TimelinePanel extends React.Component<IProps, IState> {
975975
`prr=${lastReadEvent?.getId()}`,
976976

977977
);
978-
MatrixClientPeg.get().setRoomReadMarkers(
979-
roomId,
980-
this.state.readMarkerEventId,
981-
sendRRs ? lastReadEvent : null, // Public read receipt (could be null)
982-
lastReadEvent, // Private read receipt (could be null)
983-
).catch(async (e) => {
984-
// /read_markers API is not implemented on this HS, fallback to just RR
985-
if (e.errcode === 'M_UNRECOGNIZED' && lastReadEvent) {
986-
const privateField = await getPrivateReadReceiptField(MatrixClientPeg.get());
987-
if (!sendRRs && !privateField) return;
988-
989-
try {
990-
return await MatrixClientPeg.get().sendReadReceipt(
991-
lastReadEvent,
992-
sendRRs ? ReceiptType.Read : privateField,
993-
);
994-
} catch (error) {
978+
979+
if (this.props.timelineSet.thread && sendRRs) {
980+
// There's no support for fully read markers on threads
981+
// as defined by MSC3771
982+
cli.sendReadReceipt(
983+
lastReadEvent,
984+
sendRRs ? ReceiptType.Read : ReceiptType.ReadPrivate,
985+
);
986+
} else {
987+
cli.setRoomReadMarkers(
988+
roomId,
989+
this.state.readMarkerEventId,
990+
sendRRs ? lastReadEvent : null, // Public read receipt (could be null)
991+
lastReadEvent, // Private read receipt (could be null)
992+
).catch(async (e) => {
993+
// /read_markers API is not implemented on this HS, fallback to just RR
994+
if (e.errcode === 'M_UNRECOGNIZED' && lastReadEvent) {
995+
const privateField = await getPrivateReadReceiptField(cli);
996+
if (!sendRRs && !privateField) return;
997+
998+
try {
999+
return await cli.sendReadReceipt(
1000+
lastReadEvent,
1001+
sendRRs ? ReceiptType.Read : privateField,
1002+
);
1003+
} catch (error) {
1004+
logger.error(e);
1005+
this.lastRRSentEventId = undefined;
1006+
}
1007+
} else {
9951008
logger.error(e);
996-
this.lastRRSentEventId = undefined;
9971009
}
998-
} else {
999-
logger.error(e);
1000-
}
1001-
// it failed, so allow retries next time the user is active
1002-
this.lastRRSentEventId = undefined;
1003-
this.lastRMSentEventId = undefined;
1004-
});
1010+
// it failed, so allow retries next time the user is active
1011+
this.lastRRSentEventId = undefined;
1012+
this.lastRMSentEventId = undefined;
1013+
});
1014+
}
10051015

10061016
// do a quick-reset of our unreadNotificationCount to avoid having
10071017
// to wait from the remote echo from the homeserver.
@@ -1654,15 +1664,16 @@ class TimelinePanel extends React.Component<IProps, IState> {
16541664
* SDK.
16551665
* @return {String} the event ID
16561666
*/
1657-
private getCurrentReadReceipt(ignoreSynthesized = false): string {
1667+
private getCurrentReadReceipt(ignoreSynthesized = false): string | null {
16581668
const client = MatrixClientPeg.get();
16591669
// the client can be null on logout
16601670
if (client == null) {
16611671
return null;
16621672
}
16631673

16641674
const myUserId = client.credentials.userId;
1665-
return this.props.timelineSet.room.getEventReadUpTo(myUserId, ignoreSynthesized);
1675+
const receiptStore = this.props.timelineSet.thread ?? this.props.timelineSet.room;
1676+
return receiptStore.getEventReadUpTo(myUserId, ignoreSynthesized);
16661677
}
16671678

16681679
private setReadMarker(eventId: string, eventTs: number, inhibitSetState = false): void {

src/components/views/rooms/EventTile.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1333,6 +1333,7 @@ export class UnwrappedEventTile extends React.Component<IProps, IState> {
13331333
<a href={permalink} onClick={this.onPermalinkClicked}>
13341334
{ timestamp }
13351335
</a>
1336+
{ msgOption }
13361337
</div>,
13371338
reactionsRow,
13381339
]);

src/components/views/settings/Notifications.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -398,12 +398,13 @@ export default class Notifications extends React.PureComponent<IProps, IState> {
398398
};
399399

400400
private onClearNotificationsClicked = () => {
401-
MatrixClientPeg.get().getRooms().forEach(r => {
401+
const client = MatrixClientPeg.get();
402+
client.getRooms().forEach(r => {
402403
if (r.getUnreadNotificationCount() > 0) {
403404
const events = r.getLiveTimeline().getEvents();
404405
if (events.length) {
405406
// noinspection JSIgnoredPromiseFromCall
406-
MatrixClientPeg.get().sendReadReceipt(events[events.length - 1]);
407+
client.sendReadReceipt(events[events.length - 1]);
407408
}
408409
}
409410
});

0 commit comments

Comments
 (0)