Track next event [tile] over group boundaries

Fixes https://github.com/vector-im/element-web/issues/16745
pull/21833/head
Travis Ralston 2021-03-22 21:39:07 -06:00
parent 3f74c43fc5
commit 026aa6f88d
1 changed files with 25 additions and 13 deletions

View File

@ -452,6 +452,20 @@ export default class MessagePanel extends React.Component {
}); });
}; };
_getNextEventInfo(arr, i) {
const nextEvent = i < arr.length - 1
? arr[i + 1]
: null;
// The next event with tile is used to to determine the 'last successful' flag
// when rendering the tile. The shouldShowEvent function is pretty quick at what
// it does, so this should have no significant cost even when a room is used for
// not-chat purposes.
const nextTile = arr.slice(i + 1).find(e => this._shouldShowEvent(e));
return {nextEvent, nextTile};
}
_getEventTiles() { _getEventTiles() {
this.eventNodes = {}; this.eventNodes = {};
@ -503,6 +517,7 @@ export default class MessagePanel extends React.Component {
const mxEv = this.props.events[i]; const mxEv = this.props.events[i];
const eventId = mxEv.getId(); const eventId = mxEv.getId();
const last = (mxEv === lastShownEvent); const last = (mxEv === lastShownEvent);
const {nextEvent, nextTile} = this._getNextEventInfo(this.props.events, i);
if (grouper) { if (grouper) {
if (grouper.shouldGroup(mxEv)) { if (grouper.shouldGroup(mxEv)) {
@ -519,21 +534,13 @@ export default class MessagePanel extends React.Component {
for (const Grouper of groupers) { for (const Grouper of groupers) {
if (Grouper.canStartGroup(this, mxEv)) { if (Grouper.canStartGroup(this, mxEv)) {
grouper = new Grouper(this, mxEv, prevEvent, lastShownEvent); grouper = new Grouper(this, mxEv, prevEvent, lastShownEvent, nextEvent, nextTile);
} }
} }
if (!grouper) { if (!grouper) {
const wantTile = this._shouldShowEvent(mxEv); const wantTile = this._shouldShowEvent(mxEv);
if (wantTile) { if (wantTile) {
const nextEvent = i < this.props.events.length - 1 const {nextEvent, nextTile} = this._getNextEventInfo(this.props.events, i);
? this.props.events[i + 1]
: null;
// The next event with tile is used to to determine the 'last successful' flag
// when rendering the tile. The shouldShowEvent function is pretty quick at what
// it does, so this should have no significant cost even when a room is used for
// not-chat purposes.
const nextTile = this.props.events.slice(i + 1).find(e => this._shouldShowEvent(e));
// make sure we unpack the array returned by _getTilesForEvent, // make sure we unpack the array returned by _getTilesForEvent,
// otherwise react will auto-generate keys and we will end up // otherwise react will auto-generate keys and we will end up
@ -982,7 +989,7 @@ class CreationGrouper {
)); ));
} }
const eventTiles = this.events.map((e) => { const eventTiles = this.events.map((e, i) => {
// In order to prevent DateSeparators from appearing in the expanded form // In order to prevent DateSeparators from appearing in the expanded form
// of EventListSummary, render each member event as if the previous // of EventListSummary, render each member event as if the previous
// one was itself. This way, the timestamp of the previous event === the // one was itself. This way, the timestamp of the previous event === the
@ -1032,7 +1039,7 @@ class RedactionGrouper {
return panel._shouldShowEvent(ev) && ev.isRedacted(); return panel._shouldShowEvent(ev) && ev.isRedacted();
} }
constructor(panel, ev, prevEvent, lastShownEvent) { constructor(panel, ev, prevEvent, lastShownEvent, nextEvent, nextEventTile) {
this.panel = panel; this.panel = panel;
this.readMarker = panel._readMarkerForEvent( this.readMarker = panel._readMarkerForEvent(
ev.getId(), ev.getId(),
@ -1041,6 +1048,8 @@ class RedactionGrouper {
this.events = [ev]; this.events = [ev];
this.prevEvent = prevEvent; this.prevEvent = prevEvent;
this.lastShownEvent = lastShownEvent; this.lastShownEvent = lastShownEvent;
this.nextEvent = nextEvent;
this.nextEventTile = nextEventTile;
} }
shouldGroup(ev) { shouldGroup(ev) {
@ -1089,7 +1098,10 @@ class RedactionGrouper {
const senders = new Set(); const senders = new Set();
let eventTiles = this.events.map((e, i) => { let eventTiles = this.events.map((e, i) => {
senders.add(e.sender); senders.add(e.sender);
return panel._getTilesForEvent(i === 0 ? this.prevEvent : this.events[i - 1], e, e === lastShownEvent); return panel._getTilesForEvent(
i === 0 ? this.prevEvent : this.events[i - 1],
e, e === lastShownEvent,
this.nextEvent, this.nextEventTile);
}).reduce((a, b) => a.concat(b), []); }).reduce((a, b) => a.concat(b), []);
if (eventTiles.length === 0) { if (eventTiles.length === 0) {