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

Commit

Permalink
Advance read receipts into trailing events without tiles
Browse files Browse the repository at this point in the history
This changes read receipt sending logic to allow it advance further into events
without tiles (such as edits or reactions) that may exist after the last
displayed event.

By allowing the read receipt to advance past such events, this also marks as
read any related notifications. For example, edits trigger notifications by
default since they are `m.room.message` events, and with this change, such edit
notifications can finally be marked read.

Part of element-hq/element-web#9745
  • Loading branch information
jryans committed Jun 3, 2019
1 parent ad84144 commit 96b213e
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 3 deletions.
35 changes: 32 additions & 3 deletions src/components/structures/TimelinePanel.js
Original file line number Diff line number Diff line change
Expand Up @@ -648,6 +648,7 @@ const TimelinePanel = React.createClass({

const lastReadEventIndex = this._getLastDisplayedEventIndex({
ignoreOwn: true,
allowEventsWithoutTiles: true,
});
if (lastReadEventIndex === null) {
shouldSendRR = false;
Expand Down Expand Up @@ -1111,14 +1112,18 @@ const TimelinePanel = React.createClass({
const ignoreOwn = opts.ignoreOwn || false;
const ignoreEchoes = opts.ignoreEchoes || false;
const allowPartial = opts.allowPartial || false;
const allowEventsWithoutTiles = opts.allowEventsWithoutTiles || false;

const messagePanel = this.refs.messagePanel;
if (messagePanel === undefined) return null;

const EventTile = sdk.getComponent('rooms.EventTile');

const wrapperRect = ReactDOM.findDOMNode(messagePanel).getBoundingClientRect();
const myUserId = MatrixClientPeg.get().credentials.userId;

for (let i = this.state.events.length-1; i >= 0; --i) {
let lastDisplayedIndex = null;
for (let i = this.state.events.length - 1; i >= 0; --i) {
const ev = this.state.events[i];

if (ignoreOwn && ev.sender && ev.sender.userId == myUserId) {
Expand All @@ -1136,10 +1141,34 @@ const TimelinePanel = React.createClass({
const boundingRect = node.getBoundingClientRect();
if ((allowPartial && boundingRect.top < wrapperRect.bottom) ||
(!allowPartial && boundingRect.bottom < wrapperRect.bottom)) {
return i;
lastDisplayedIndex = i;
break;
}
}
return null;

if (lastDisplayedIndex === null) {
return null;
}

// If events without tiles are allowed, then we walk forward from the
// the last displayed event and advance the index for any events without
// tiles that immediately follow it.
// XXX: We could track the last event without a tile after the last
// displayed event in the loop above so that we only do a single pass
// through the loop, which would be more efficient. Using two passes is
// easier to reason about, so let's start there and optimise later if
// needed.
if (allowEventsWithoutTiles) {
for (let i = lastDisplayedIndex + 1; i < this.state.events.length; i++) {
const ev = this.state.events[i];
if (EventTile.haveTileForEvent(ev)) {
break;
}
lastDisplayedIndex = i;
}
}

return lastDisplayedIndex;
},

/**
Expand Down
3 changes: 3 additions & 0 deletions src/components/views/rooms/EventTile.js
Original file line number Diff line number Diff line change
Expand Up @@ -819,6 +819,9 @@ module.exports.haveTileForEvent = function(e) {
// Only messages have a tile (black-rectangle) if redacted
if (e.isRedacted() && !isMessageEvent(e)) return false;

// No tile for replacement events since they update the original tile
if (e.isRelation("m.replace")) return false;

const handler = getHandlerTile(e);
if (handler === undefined) return false;
if (handler === 'messages.TextualEvent') {
Expand Down
2 changes: 2 additions & 0 deletions src/shouldHideEvent.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ export default function shouldHideEvent(ev) {

// Hide redacted events
if (ev.isRedacted() && !isEnabled('showRedactions')) return true;

// Hide replacement events since they update the original tile
if (ev.isRelation("m.replace")) return true;

const eventDiff = memberEventDiff(ev);
Expand Down

0 comments on commit 96b213e

Please sign in to comment.