Fix CallEventGrouper map building to not occur during a Render phase (#7638)

This commit is contained in:
Michael Telatynski 2022-01-27 11:08:28 +00:00 committed by GitHub
parent ae490841c6
commit f2249b3e37
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 45 additions and 23 deletions

View file

@ -170,6 +170,7 @@ export default class CallEventGrouper extends EventEmitter {
};
public add(event: MatrixEvent) {
if (this.events.has(event)) return; // nothing to do
this.events.add(event);
this.setCall();
}

View file

@ -183,6 +183,8 @@ interface IProps {
hideThreadedMessages?: boolean;
disableGrouping?: boolean;
callEventGroupers: Map<string, CallEventGrouper>;
}
interface IState {
@ -254,9 +256,6 @@ export default class MessagePanel extends React.Component<IProps, IState> {
private readonly showTypingNotificationsWatcherRef: string;
private eventTiles: Record<string, EventTile> = {};
// A map of <callId, CallEventGrouper>
private callEventGroupers = new Map<string, CallEventGrouper>();
constructor(props, context) {
super(props, context);
@ -650,20 +649,6 @@ export default class MessagePanel extends React.Component<IProps, IState> {
const last = (mxEv === lastShownEvent);
const { nextEvent, nextTile } = this.getNextEventInfo(this.props.events, i);
if (
mxEv.getType().indexOf("m.call.") === 0 ||
mxEv.getType().indexOf("org.matrix.call.") === 0
) {
const callId = mxEv.getContent().call_id;
if (this.callEventGroupers.has(callId)) {
this.callEventGroupers.get(callId).add(mxEv);
} else {
const callEventGrouper = new CallEventGrouper();
callEventGrouper.add(mxEv);
this.callEventGroupers.set(callId, callEventGrouper);
}
}
if (grouper) {
if (grouper.shouldGroup(mxEv)) {
grouper.add(mxEv, this.showHiddenEvents);
@ -784,7 +769,7 @@ export default class MessagePanel extends React.Component<IProps, IState> {
// it's successful: we received it.
isLastSuccessful = isLastSuccessful && mxEv.getSender() === MatrixClientPeg.get().getUserId();
const callEventGrouper = this.callEventGroupers.get(mxEv.getContent().call_id);
const callEventGrouper = this.props.callEventGroupers.get(mxEv.getContent().call_id);
// use txnId as key if available so that we don't remount during sending
ret.push(
<TileErrorBoundary key={mxEv.getTxnId() || eventId} mxEvent={mxEv}>

View file

@ -51,6 +51,7 @@ import { RoomPermalinkCreator } from "../../utils/permalinks/Permalinks";
import Spinner from "../views/elements/Spinner";
import EditorStateTransfer from '../../utils/EditorStateTransfer';
import ErrorDialog from '../views/dialogs/ErrorDialog';
import CallEventGrouper from "./CallEventGrouper";
const PAGINATE_SIZE = 20;
const INITIAL_SIZE = 20;
@ -237,6 +238,9 @@ class TimelinePanel extends React.Component<IProps, IState> {
private readReceiptActivityTimer: Timer;
private readMarkerActivityTimer: Timer;
// A map of <callId, CallEventGrouper>
private callEventGroupers = new Map<string, CallEventGrouper>();
constructor(props, context) {
super(props, context);
@ -388,6 +392,7 @@ class TimelinePanel extends React.Component<IProps, IState> {
this.timelineWindow.unpaginate(count, backwards);
const { events, liveEvents, firstVisibleEventIndex } = this.getEvents();
this.buildCallEventGroupers(events);
const newState: Partial<IState> = {
events,
liveEvents,
@ -449,6 +454,7 @@ class TimelinePanel extends React.Component<IProps, IState> {
debuglog("paginate complete backwards:"+backwards+"; success:"+r);
const { events, liveEvents, firstVisibleEventIndex } = this.getEvents();
this.buildCallEventGroupers(events);
const newState: Partial<IState> = {
[paginatingKey]: false,
[canPaginateKey]: r,
@ -561,6 +567,7 @@ class TimelinePanel extends React.Component<IProps, IState> {
if (this.unmounted) { return; }
const { events, liveEvents, firstVisibleEventIndex } = this.getEvents();
this.buildCallEventGroupers(events);
const lastLiveEvent = liveEvents[liveEvents.length - 1];
const updatedState: Partial<IState> = {
@ -1231,6 +1238,7 @@ class TimelinePanel extends React.Component<IProps, IState> {
canForwardPaginate: false,
timelineLoading: true,
});
this.buildCallEventGroupers();
prom.then(onLoaded, onError);
}
}
@ -1243,7 +1251,9 @@ class TimelinePanel extends React.Component<IProps, IState> {
// the results if so.
if (this.unmounted) return;
this.setState(this.getEvents());
const state = this.getEvents();
this.buildCallEventGroupers(state.events);
this.setState(state);
}
// Force refresh the timeline before threads support pending events
@ -1512,6 +1522,27 @@ class TimelinePanel extends React.Component<IProps, IState> {
eventType: EventType | string,
) => this.props.timelineSet.getRelationsForEvent(eventId, relationType, eventType);
private buildCallEventGroupers(events?: MatrixEvent[]): void {
const oldCallEventGroupers = this.callEventGroupers;
this.callEventGroupers = new Map();
events?.forEach(ev => {
if (!ev.getType().startsWith("m.call.") && !ev.getType().startsWith("org.matrix.call.")) {
return;
}
const callId = ev.getContent().call_id;
if (!this.callEventGroupers.has(callId)) {
if (oldCallEventGroupers.has(callId)) {
// reuse the CallEventGrouper object where possible
this.callEventGroupers.set(callId, oldCallEventGroupers.get(callId));
} else {
this.callEventGroupers.set(callId, new CallEventGrouper());
}
}
this.callEventGroupers.get(callId).add(ev);
});
}
render() {
// just show a spinner while the timeline loads.
//
@ -1596,6 +1627,7 @@ class TimelinePanel extends React.Component<IProps, IState> {
enableFlair={SettingsStore.getValue(UIFeature.Flair)}
hideThreadedMessages={this.props.hideThreadedMessages}
disableGrouping={this.props.disableGrouping}
callEventGroupers={this.callEventGroupers}
/>
);
}

View file

@ -41,9 +41,8 @@ const room = new Matrix.Room("!roomId:server_name");
// wrap MessagePanel with a component which provides the MatrixClient in the context.
class WrappedMessagePanel extends React.Component {
state = {
resizeNotifier: new EventEmitter(),
};
resizeNotifier = new EventEmitter();
callEventGroupers = new Map();
render() {
const roomContext = {
@ -60,7 +59,12 @@ class WrappedMessagePanel extends React.Component {
return <MatrixClientContext.Provider value={client}>
<RoomContext.Provider value={roomContext}>
<MessagePanel room={room} {...this.props} resizeNotifier={this.state.resizeNotifier} />
<MessagePanel
room={room}
{...this.props}
resizeNotifier={this.resizeNotifier}
callEventGroupers={this.callEventGroupers}
/>
</RoomContext.Provider>
</MatrixClientContext.Provider>;
}