@@ -564,7 +564,7 @@ export default class MessagePanel extends React.Component<IProps, IState> {
564564 /**
565565 * Find the next event in the list, and the next visible event in the list.
566566 *
567- * @param event - the list of events to look in and whether they are shown
567+ * @param events - the list of events to look in and whether they are shown
568568 * @param i - where in the list we are now
569569 *
570570 * @returns { nextEvent, nextTile }
@@ -578,14 +578,14 @@ export default class MessagePanel extends React.Component<IProps, IState> {
578578 private getNextEventInfo (
579579 events : EventAndShouldShow [ ] ,
580580 i : number ,
581- ) : { nextEvent : MatrixEvent | null ; nextTile : MatrixEvent | null } {
581+ ) : { nextEventAndShouldShow : EventAndShouldShow | null ; nextTile : MatrixEvent | null } {
582582 // WARNING: this method is on a hot path.
583583
584- const nextEvent = i < events . length - 1 ? events [ i + 1 ] . event : null ;
584+ const nextEventAndShouldShow = i < events . length - 1 ? events [ i + 1 ] : null ;
585585
586586 const nextTile = findFirstShownAfter ( i , events ) ;
587587
588- return { nextEvent , nextTile } ;
588+ return { nextEventAndShouldShow , nextTile } ;
589589 }
590590
591591 private get pendingEditItem ( ) : string | undefined {
@@ -615,16 +615,16 @@ export default class MessagePanel extends React.Component<IProps, IState> {
615615
616616 let lastShownNonLocalEchoIndex = - 1 ;
617617 for ( let i = events . length - 1 ; i >= 0 ; i -- ) {
618- const { event : mxEv , shouldShow } = events [ i ] ;
618+ const { event, shouldShow } = events [ i ] ;
619619 if ( ! shouldShow ) {
620620 continue ;
621621 }
622622
623623 if ( lastShownEvent === undefined ) {
624- lastShownEvent = mxEv ;
624+ lastShownEvent = event ;
625625 }
626626
627- if ( mxEv . status ) {
627+ if ( event . status ) {
628628 // this is a local echo
629629 continue ;
630630 }
@@ -641,20 +641,21 @@ export default class MessagePanel extends React.Component<IProps, IState> {
641641 // to assume that sent receipts are to be shown more often.
642642 this . readReceiptsByEvent = { } ;
643643 if ( this . props . showReadReceipts ) {
644- this . readReceiptsByEvent = this . getReadReceiptsByShownEvent ( ) ;
644+ this . readReceiptsByEvent = this . getReadReceiptsByShownEvent ( events ) ;
645645 }
646646
647647 let grouper : BaseGrouper | null = null ;
648648
649649 for ( let i = 0 ; i < events . length ; i ++ ) {
650- const { event : mxEv , shouldShow } = events [ i ] ;
651- const eventId = mxEv . getId ( ) ;
652- const last = mxEv === lastShownEvent ;
653- const { nextEvent, nextTile } = this . getNextEventInfo ( events , i ) ;
650+ const eventAndShouldShow = events [ i ] ;
651+ const { event, shouldShow } = eventAndShouldShow ;
652+ const eventId = event . getId ( ) ;
653+ const last = event === lastShownEvent ;
654+ const { nextEventAndShouldShow, nextTile } = this . getNextEventInfo ( events , i ) ;
654655
655656 if ( grouper ) {
656- if ( grouper . shouldGroup ( mxEv ) ) {
657- grouper . add ( mxEv ) ;
657+ if ( grouper . shouldGroup ( eventAndShouldShow ) ) {
658+ grouper . add ( eventAndShouldShow ) ;
658659 continue ;
659660 } else {
660661 // not part of group, so get the group tiles, close the
@@ -666,8 +667,15 @@ export default class MessagePanel extends React.Component<IProps, IState> {
666667 }
667668
668669 for ( const Grouper of groupers ) {
669- if ( Grouper . canStartGroup ( this , mxEv ) && ! this . props . disableGrouping ) {
670- grouper = new Grouper ( this , mxEv , prevEvent , lastShownEvent , nextEvent , nextTile ) ;
670+ if ( Grouper . canStartGroup ( this , eventAndShouldShow ) && ! this . props . disableGrouping ) {
671+ grouper = new Grouper (
672+ this ,
673+ eventAndShouldShow ,
674+ prevEvent ,
675+ lastShownEvent ,
676+ nextEventAndShouldShow ,
677+ nextTile ,
678+ ) ;
671679 break ; // break on first grouper
672680 }
673681 }
@@ -677,8 +685,8 @@ export default class MessagePanel extends React.Component<IProps, IState> {
677685 // make sure we unpack the array returned by getTilesForEvent,
678686 // otherwise React will auto-generate keys, and we will end up
679687 // replacing all the DOM elements every time we paginate.
680- ret . push ( ...this . getTilesForEvent ( prevEvent , mxEv , last , false , nextEvent , nextTile ) ) ;
681- prevEvent = mxEv ;
688+ ret . push ( ...this . getTilesForEvent ( prevEvent , event , last , false , nextEventAndShouldShow , nextTile ) ) ;
689+ prevEvent = event ;
682690 }
683691
684692 const readMarker = this . readMarkerForEvent ( eventId , i >= lastShownNonLocalEchoIndex ) ;
@@ -698,8 +706,8 @@ export default class MessagePanel extends React.Component<IProps, IState> {
698706 mxEv : MatrixEvent ,
699707 last = false ,
700708 isGrouped = false ,
701- nextEvent ?: MatrixEvent ,
702- nextEventWithTile ? : MatrixEvent ,
709+ nextEvent : EventAndShouldShow | null = null ,
710+ nextEventWithTile : MatrixEvent | null = null ,
703711 ) : ReactNode [ ] {
704712 const ret : ReactNode [ ] = [ ] ;
705713
@@ -745,20 +753,20 @@ export default class MessagePanel extends React.Component<IProps, IState> {
745753 const readReceipts = this . readReceiptsByEvent [ eventId ] ;
746754
747755 let isLastSuccessful = false ;
748- const isSentState = ( s : EventStatus ) : boolean => ! s || s === EventStatus . SENT ;
756+ const isSentState = ( s : EventStatus | null ) : boolean => ! s || s === EventStatus . SENT ;
749757 const isSent = isSentState ( mxEv . getAssociatedStatus ( ) ) ;
750- const hasNextEvent = nextEvent && this . shouldShowEvent ( nextEvent ) ;
758+ const hasNextEvent = nextEvent ?. shouldShow ;
751759 if ( ! hasNextEvent && isSent ) {
752760 isLastSuccessful = true ;
753- } else if ( hasNextEvent && isSent && ! isSentState ( nextEvent . getAssociatedStatus ( ) ) ) {
761+ } else if ( hasNextEvent && isSent && ! isSentState ( nextEvent . event . getAssociatedStatus ( ) ) ) {
754762 isLastSuccessful = true ;
755763 }
756764
757765 // This is a bit nuanced, but if our next event is hidden but a future event is not
758766 // hidden then we're not the last successful.
759767 if (
760768 nextEventWithTile &&
761- nextEventWithTile !== nextEvent &&
769+ nextEventWithTile !== nextEvent ?. event &&
762770 isSentState ( nextEventWithTile . getAssociatedStatus ( ) )
763771 ) {
764772 isLastSuccessful = false ;
@@ -861,7 +869,7 @@ export default class MessagePanel extends React.Component<IProps, IState> {
861869 // Get an object that maps from event ID to a list of read receipts that
862870 // should be shown next to that event. If a hidden event has read receipts,
863871 // they are folded into the receipts of the last shown event.
864- private getReadReceiptsByShownEvent ( ) : Record < string , IReadReceiptProps [ ] > {
872+ private getReadReceiptsByShownEvent ( events : EventAndShouldShow [ ] ) : Record < string , IReadReceiptProps [ ] > {
865873 const receiptsByEvent : Record < string , IReadReceiptProps [ ] > = { } ;
866874 const receiptsByUserId : Record <
867875 string ,
@@ -872,8 +880,8 @@ export default class MessagePanel extends React.Component<IProps, IState> {
872880 > = { } ;
873881
874882 let lastShownEventId ;
875- for ( const event of this . props . events ) {
876- if ( this . shouldShowEvent ( event ) ) {
883+ for ( const { event, shouldShow } of events ) {
884+ if ( shouldShow ) {
877885 lastShownEventId = event . getId ( ) ;
878886 }
879887 if ( ! lastShownEventId ) {
@@ -1065,7 +1073,7 @@ interface EventAndShouldShow {
10651073}
10661074
10671075abstract class BaseGrouper {
1068- public static canStartGroup = ( panel : MessagePanel , ev : MatrixEvent ) : boolean => true ;
1076+ public static canStartGroup = ( _panel : MessagePanel , _ev : EventAndShouldShow ) : boolean => true ;
10691077
10701078 public events : MatrixEvent [ ] = [ ] ;
10711079 // events that we include in the group but then eject out and place above the group.
@@ -1074,17 +1082,20 @@ abstract class BaseGrouper {
10741082
10751083 public constructor (
10761084 public readonly panel : MessagePanel ,
1077- public readonly event : MatrixEvent ,
1085+ public readonly firstEventAndShouldShow : EventAndShouldShow ,
10781086 public readonly prevEvent : MatrixEvent | null ,
1079- public readonly lastShownEvent : MatrixEvent ,
1080- public readonly nextEvent ?: MatrixEvent ,
1081- public readonly nextEventTile ?: MatrixEvent ,
1087+ public readonly lastShownEvent : MatrixEvent | undefined ,
1088+ public readonly nextEvent : EventAndShouldShow | null ,
1089+ public readonly nextEventTile ?: MatrixEvent | null ,
10821090 ) {
1083- this . readMarker = panel . readMarkerForEvent ( event . getId ( ) , event === lastShownEvent ) ;
1091+ this . readMarker = panel . readMarkerForEvent (
1092+ firstEventAndShouldShow . event . getId ( ) ,
1093+ firstEventAndShouldShow . event === lastShownEvent ,
1094+ ) ;
10841095 }
10851096
1086- public abstract shouldGroup ( ev : MatrixEvent ) : boolean ;
1087- public abstract add ( ev : MatrixEvent ) : void ;
1097+ public abstract shouldGroup ( ev : EventAndShouldShow ) : boolean ;
1098+ public abstract add ( ev : EventAndShouldShow ) : void ;
10881099 public abstract getTiles ( ) : ReactNode [ ] ;
10891100 public abstract getNewPrevEvent ( ) : MatrixEvent ;
10901101}
@@ -1105,28 +1116,27 @@ abstract class BaseGrouper {
11051116// Grouping only events sent by the same user that sent the `m.room.create` and only until
11061117// the first non-state event, beacon_info event or membership event which is not regarding the sender of the `m.room.create` event
11071118class CreationGrouper extends BaseGrouper {
1108- public static canStartGroup = function ( panel : MessagePanel , ev : MatrixEvent ) : boolean {
1109- return ev . getType ( ) === EventType . RoomCreate ;
1119+ public static canStartGroup = function ( _panel : MessagePanel , { event } : EventAndShouldShow ) : boolean {
1120+ return event . getType ( ) === EventType . RoomCreate ;
11101121 } ;
11111122
1112- public shouldGroup ( ev : MatrixEvent ) : boolean {
1123+ public shouldGroup ( { event , shouldShow } : EventAndShouldShow ) : boolean {
11131124 const panel = this . panel ;
1114- const createEvent = this . event ;
1115- if ( ! panel . shouldShowEvent ( ev ) ) {
1125+ const createEvent = this . firstEventAndShouldShow . event ;
1126+ if ( ! shouldShow ) {
11161127 return true ;
11171128 }
1118- if ( panel . wantsDateSeparator ( this . event , ev . getDate ( ) ) ) {
1129+ if ( panel . wantsDateSeparator ( this . firstEventAndShouldShow . event , event . getDate ( ) ) ) {
11191130 return false ;
11201131 }
1132+ const eventType = event . getType ( ) ;
11211133 if (
1122- ev . getType ( ) === EventType . RoomMember &&
1123- ( ev . getStateKey ( ) !== createEvent . getSender ( ) || ev . getContent ( ) [ "membership" ] !== "join" )
1134+ eventType === EventType . RoomMember &&
1135+ ( event . getStateKey ( ) !== createEvent . getSender ( ) || event . getContent ( ) [ "membership" ] !== "join" )
11241136 ) {
11251137 return false ;
11261138 }
11271139
1128- const eventType = ev . getType ( ) ;
1129-
11301140 // beacons are not part of room creation configuration
11311141 // should be shown in timeline
11321142 if ( M_BEACON_INFO . matches ( eventType ) ) {
@@ -1138,17 +1148,17 @@ class CreationGrouper extends BaseGrouper {
11381148 return false ;
11391149 }
11401150
1141- if ( ev . isState ( ) && ev . getSender ( ) === createEvent . getSender ( ) ) {
1151+ if ( event . isState ( ) && event . getSender ( ) === createEvent . getSender ( ) ) {
11421152 return true ;
11431153 }
11441154
11451155 return false ;
11461156 }
11471157
1148- public add ( ev : MatrixEvent ) : void {
1158+ public add ( { event : ev , shouldShow } : EventAndShouldShow ) : void {
11491159 const panel = this . panel ;
11501160 this . readMarker = this . readMarker || panel . readMarkerForEvent ( ev . getId ( ) , ev === this . lastShownEvent ) ;
1151- if ( ! panel . shouldShowEvent ( ev ) ) {
1161+ if ( ! shouldShow ) {
11521162 return ;
11531163 }
11541164 if ( ev . getType ( ) === EventType . RoomEncryption ) {
@@ -1167,26 +1177,28 @@ class CreationGrouper extends BaseGrouper {
11671177 const panel = this . panel ;
11681178 const ret : ReactNode [ ] = [ ] ;
11691179 const isGrouped = true ;
1170- const createEvent = this . event ;
1180+ const createEvent = this . firstEventAndShouldShow ;
11711181 const lastShownEvent = this . lastShownEvent ;
11721182
1173- if ( panel . wantsDateSeparator ( this . prevEvent , createEvent . getDate ( ) ) ) {
1174- const ts = createEvent . getTs ( ) ;
1183+ if ( panel . wantsDateSeparator ( this . prevEvent , createEvent . event . getDate ( ) ) ) {
1184+ const ts = createEvent . event . getTs ( ) ;
11751185 ret . push (
11761186 < li key = { ts + "~" } >
1177- < DateSeparator roomId = { createEvent . getRoomId ( ) } ts = { ts } />
1187+ < DateSeparator roomId = { createEvent . event . getRoomId ( ) } ts = { ts } />
11781188 </ li > ,
11791189 ) ;
11801190 }
11811191
11821192 // If this m.room.create event should be shown (room upgrade) then show it before the summary
1183- if ( panel . shouldShowEvent ( createEvent ) ) {
1193+ if ( createEvent . shouldShow ) {
11841194 // pass in the createEvent as prevEvent as well so no extra DateSeparator is rendered
1185- ret . push ( ...panel . getTilesForEvent ( createEvent , createEvent ) ) ;
1195+ ret . push ( ...panel . getTilesForEvent ( createEvent . event , createEvent . event ) ) ;
11861196 }
11871197
11881198 for ( const ejected of this . ejectedEvents ) {
1189- ret . push ( ...panel . getTilesForEvent ( createEvent , ejected , createEvent === lastShownEvent , isGrouped ) ) ;
1199+ ret . push (
1200+ ...panel . getTilesForEvent ( createEvent . event , ejected , createEvent . event === lastShownEvent , isGrouped ) ,
1201+ ) ;
11901202 }
11911203
11921204 const eventTiles = this . events
@@ -1233,14 +1245,17 @@ class CreationGrouper extends BaseGrouper {
12331245 }
12341246
12351247 public getNewPrevEvent ( ) : MatrixEvent {
1236- return this . event ;
1248+ return this . firstEventAndShouldShow . event ;
12371249 }
12381250}
12391251
12401252// Wrap consecutive grouped events in a ListSummary
12411253class MainGrouper extends BaseGrouper {
1242- public static canStartGroup = function ( panel : MessagePanel , ev : MatrixEvent ) : boolean {
1243- if ( ! panel . shouldShowEvent ( ev ) ) return false ;
1254+ public static canStartGroup = function (
1255+ panel : MessagePanel ,
1256+ { event : ev , shouldShow } : EventAndShouldShow ,
1257+ ) : boolean {
1258+ if ( ! shouldShow ) return false ;
12441259
12451260 if ( ev . isState ( ) && groupedStateEvents . includes ( ev . getType ( ) as EventType ) ) {
12461261 return true ;
@@ -1259,18 +1274,18 @@ class MainGrouper extends BaseGrouper {
12591274
12601275 public constructor (
12611276 public readonly panel : MessagePanel ,
1262- public readonly event : MatrixEvent ,
1277+ public readonly firstEventAndShouldShow : EventAndShouldShow ,
12631278 public readonly prevEvent : MatrixEvent | null ,
1264- public readonly lastShownEvent : MatrixEvent ,
1265- nextEvent : MatrixEvent ,
1266- nextEventTile : MatrixEvent ,
1279+ public readonly lastShownEvent : MatrixEvent | undefined ,
1280+ nextEvent : EventAndShouldShow | null ,
1281+ nextEventTile : MatrixEvent | null ,
12671282 ) {
1268- super ( panel , event , prevEvent , lastShownEvent , nextEvent , nextEventTile ) ;
1269- this . events = [ event ] ;
1283+ super ( panel , firstEventAndShouldShow , prevEvent , lastShownEvent , nextEvent , nextEventTile ) ;
1284+ this . events = [ firstEventAndShouldShow . event ] ;
12701285 }
12711286
1272- public shouldGroup ( ev : MatrixEvent ) : boolean {
1273- if ( ! this . panel . shouldShowEvent ( ev ) ) {
1287+ public shouldGroup ( { event : ev , shouldShow } : EventAndShouldShow ) : boolean {
1288+ if ( ! shouldShow ) {
12741289 // absorb hidden events so that they do not break up streams of messages & redaction events being grouped
12751290 return true ;
12761291 }
@@ -1289,13 +1304,13 @@ class MainGrouper extends BaseGrouper {
12891304 return false ;
12901305 }
12911306
1292- public add ( ev : MatrixEvent ) : void {
1307+ public add ( { event : ev , shouldShow } : EventAndShouldShow ) : void {
12931308 if ( ev . getType ( ) === EventType . RoomMember ) {
12941309 // We can ignore any events that don't actually have a message to display
12951310 if ( ! hasText ( ev , this . panel . showHiddenEvents ) ) return ;
12961311 }
12971312 this . readMarker = this . readMarker || this . panel . readMarkerForEvent ( ev . getId ( ) , ev === this . lastShownEvent ) ;
1298- if ( ! this . panel . showHiddenEvents && ! this . panel . shouldShowEvent ( ev ) ) {
1313+ if ( ! this . panel . showHiddenEvents && ! shouldShow ) {
12991314 // absorb hidden events to not split the summary
13001315 return ;
13011316 }
@@ -1399,6 +1414,10 @@ const groupers = [CreationGrouper, MainGrouper];
13991414 * event that is >start items through the list, and is shown.
14001415 */
14011416function findFirstShownAfter ( start : number , events : EventAndShouldShow [ ] ) : MatrixEvent | null {
1417+ // Note: this could be done with something like:
1418+ // events.slice(i + 1).find((e) => e.shouldShow)?.event ?? null;
1419+ // but it is ~10% slower, and this is on the critical path.
1420+
14021421 for ( let n = start + 1 ; n < events . length ; n ++ ) {
14031422 const { event, shouldShow } = events [ n ] ;
14041423 if ( shouldShow ) {
0 commit comments