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

Commit

Permalink
Combine an event and its shouldShow info into a single object
Browse files Browse the repository at this point in the history
  • Loading branch information
andybalaam committed Mar 10, 2023
1 parent 16c2429 commit fdf9698
Showing 1 changed file with 42 additions and 27 deletions.
69 changes: 42 additions & 27 deletions src/components/structures/MessagePanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -564,35 +564,26 @@ export default class MessagePanel extends React.Component<IProps, IState> {
/**
* Find the next event in the list, and the next visible event in the list.
*
* @param arr - the list of events to look in
* @param shouldShow - which of these events should be shown (a cache of
* calling this.shouldShowEvent(e) for each e in arr)
* @param event - the list of events to look in and whether they are shown
* @param i - where in the list we are now
*
* @returns { nextEvent, nextTile }
*
* nextEvent is the last event in the supplied array.
* nextEvent is the event after i in the supplied array.
*
* nextTile is the last event in the array that we will show a tile for. It
* is used to to determine the 'last successful' flag when rendering the
* tile.
* nextTile is the first event in the array after i that we will show a tile
* for. It is used to to determine the 'last successful' flag when rendering
* the tile.
*/
private getNextEventInfo(
arr: MatrixEvent[],
shouldShow: boolean[],
events: EventAndShouldShow[],
i: number,
): { nextEvent: MatrixEvent; nextTile: MatrixEvent } {
): { nextEvent: MatrixEvent | null; nextTile: MatrixEvent | null } {
// WARNING: this method is on a hot path.

const nextEvent = i < arr.length - 1 ? arr[i + 1] : null;
const nextEvent = i < events.length - 1 ? events[i + 1].event : null;

let nextTile = null;
for (let n = i + 1; n < arr.length; n++) {
if (shouldShow[n]) {
nextTile = arr[n];
break;
}
}
const nextTile = findFirstShownAfter(i, events);

return { nextEvent, nextTile };
}
Expand All @@ -618,14 +609,16 @@ export default class MessagePanel extends React.Component<IProps, IState> {
// we also need to figure out which is the last event we show which isn't
// a local echo, to manage the read-marker.
let lastShownEvent: MatrixEvent | undefined;
const shouldShow = this.props.events.map((e) => this.shouldShowEvent(e));
const events: EventAndShouldShow[] = this.props.events.map((event) => {
return { event, shouldShow: this.shouldShowEvent(event) };
});

let lastShownNonLocalEchoIndex = -1;
for (let i = this.props.events.length - 1; i >= 0; i--) {
if (!shouldShow[i]) {
for (let i = events.length - 1; i >= 0; i--) {
const { event: mxEv, shouldShow } = events[i];
if (!shouldShow) {
continue;
}
const mxEv = this.props.events[i];

if (lastShownEvent === undefined) {
lastShownEvent = mxEv;
Expand Down Expand Up @@ -654,12 +647,11 @@ export default class MessagePanel extends React.Component<IProps, IState> {

let grouper: BaseGrouper = null;

for (let i = 0; i < this.props.events.length; i++) {
const mxEv = this.props.events[i];
const shouldShowEv = shouldShow[i];
for (let i = 0; i < events.length; i++) {
const { event: mxEv, shouldShow } = events[i];
const eventId = mxEv.getId();
const last = mxEv === lastShownEvent;
const { nextEvent, nextTile } = this.getNextEventInfo(this.props.events, shouldShow, i);
const { nextEvent, nextTile } = this.getNextEventInfo(events, i);

if (grouper) {
if (grouper.shouldGroup(mxEv)) {
Expand All @@ -682,7 +674,7 @@ export default class MessagePanel extends React.Component<IProps, IState> {
}

if (!grouper) {
if (shouldShowEv) {
if (shouldShow) {
// make sure we unpack the array returned by getTilesForEvent,
// otherwise React will auto-generate keys, and we will end up
// replacing all the DOM elements every time we paginate.
Expand Down Expand Up @@ -1064,6 +1056,15 @@ export default class MessagePanel extends React.Component<IProps, IState> {
}
}

/**
* Holds on to an event, caching the information about whether it should be
* shown. Avoids calling shouldShowEvent more times than we need to.
*/
interface EventAndShouldShow {
event: MatrixEvent;
shouldShow: boolean;
}

abstract class BaseGrouper {
public static canStartGroup = (panel: MessagePanel, ev: MatrixEvent): boolean => true;

Expand Down Expand Up @@ -1393,3 +1394,17 @@ class MainGrouper extends BaseGrouper {

// all the grouper classes that we use, ordered by priority
const groupers = [CreationGrouper, MainGrouper];

/**
* Look through the supplied list of EventAndShouldShow, and return the first
* event that is >start items through the list, and is shown.
*/
function findFirstShownAfter(start: number, events: EventAndShouldShow[]): MatrixEvent | null {
for (let n = start + 1; n < events.length; n++) {
const { event, shouldShow } = events[n];
if (shouldShow) {
return event;
}
}
return null;
}

0 comments on commit fdf9698

Please sign in to comment.