diff --git a/src/components/structures/RoomView.tsx b/src/components/structures/RoomView.tsx index cb3256dc65..5f717873f3 100644 --- a/src/components/structures/RoomView.tsx +++ b/src/components/structures/RoomView.tsx @@ -185,12 +185,20 @@ interface IRoomProps extends RoomViewProps { * If true, hide the pinned messages banner */ hidePinnedMessageBanner?: boolean; + + /** + * If true, the read receipts and markers are only send when the room view is focused. + * The user has to focus the room view in order to clear any unreads and to move the unread marker to the bottom of the view. + * Otherwise, if the user interacts with the UI when the room view is displayed, read receipts and markers are sent. + */ + disableReadReceiptsAndMarkersOnActivity?: boolean; } export { MainSplitContentType }; export interface IRoomState { room?: Room; + roomId?: string; roomAlias?: string; roomLoading: boolean; @@ -2176,6 +2184,19 @@ export class RoomView extends React.Component { } }; + /** + * Handles the focus event on the RoomView component. + * + * Sends read receipts and updates the read marker if the + * disableReadReceiptsAndMarkersOnActivity prop is set. + */ + private onFocus = (): void => { + if (!this.props.disableReadReceiptsAndMarkersOnActivity) return; + + this.messagePanel?.sendReadReceipts(); + this.messagePanel?.updateReadMarker(); + }; + public render(): ReactNode { if (!this.context.client) return null; const { isRoomEncrypted } = this.state; @@ -2533,7 +2554,9 @@ export class RoomView extends React.Component { timelineSet={this.state.room.getUnfilteredTimelineSet()} showReadReceipts={this.state.showReadReceipts} manageReadReceipts={!this.state.isPeeking} - sendReadReceiptOnLoad={!this.state.wasContextSwitch} + sendReadReceiptOnLoad={ + !this.state.wasContextSwitch && !this.props.disableReadReceiptsAndMarkersOnActivity + } manageReadMarkers={!this.state.isPeeking} hidden={hideMessagePanel} highlightedEventId={highlightedEventId} @@ -2550,6 +2573,7 @@ export class RoomView extends React.Component { showReactions={true} layout={this.state.layout} editState={this.state.editState} + disableReadReceiptsAndMarkersOnActivity={this.props.disableReadReceiptsAndMarkersOnActivity} /> ); } @@ -2677,7 +2701,7 @@ export class RoomView extends React.Component { return ( -
+
{showChatEffects && this.roomView.current && ( )} diff --git a/src/components/structures/TimelinePanel.tsx b/src/components/structures/TimelinePanel.tsx index c112d341b3..658853ce5e 100644 --- a/src/components/structures/TimelinePanel.tsx +++ b/src/components/structures/TimelinePanel.tsx @@ -139,6 +139,11 @@ interface IProps { hideThreadedMessages?: boolean; disableGrouping?: boolean; + + /** + * Disable updating the read receipts and markers on user activity. + */ + disableReadReceiptsAndMarkersOnActivity?: boolean; } interface IState { @@ -302,10 +307,10 @@ class TimelinePanel extends React.Component { this.props.timelineSet.room?.on(ThreadEvent.Update, this.onThreadUpdate); - if (this.props.manageReadReceipts) { + if (this.props.manageReadReceipts && !this.props.disableReadReceiptsAndMarkersOnActivity) { this.updateReadReceiptOnUserActivity(); } - if (this.props.manageReadMarkers) { + if (this.props.manageReadMarkers && !this.props.disableReadReceiptsAndMarkersOnActivity) { this.updateReadMarkerOnUserActivity(); } this.initTimeline(this.props); @@ -1028,7 +1033,10 @@ class TimelinePanel extends React.Component { ); } - private sendReadReceipts = async (): Promise => { + /** + * Sends read receipts and fully read markers as appropriate. + */ + public sendReadReceipts = async (): Promise => { if (SettingsStore.getValue("lowBandwidth")) return; if (!this.messagePanel.current) return; if (!this.props.manageReadReceipts) return; @@ -1134,9 +1142,12 @@ class TimelinePanel extends React.Component { } } - // if the read marker is on the screen, we can now assume we've caught up to the end - // of the screen, so move the marker down to the bottom of the screen. - private updateReadMarker = async (): Promise => { + /** + * Move the marker to the bottom of the screen. + * If the read marker is on the screen, we can now assume we've caught up to the end + * of the screen, so move the marker down to the bottom of the screen. + */ + public updateReadMarker = async (): Promise => { if (!this.props.manageReadMarkers) return; if (this.getReadMarkerPosition() === 1) { // the read marker is at an event below the viewport,