diff --git a/src/components/structures/ThreadPanel.tsx b/src/components/structures/ThreadPanel.tsx index 0d279dc1d9..5e0d556c3f 100644 --- a/src/components/structures/ThreadPanel.tsx +++ b/src/components/structures/ThreadPanel.tsx @@ -88,7 +88,7 @@ async function getThreadTimelineSet( const timelineSet = new EventTimelineSet(room, {}); Array.from(room.threads) - .sort(([, threadA], [, threadB]) => threadA.lastReply().getTs() - threadB.lastReply().getTs()) + .sort(([, threadA], [, threadB]) => threadA.replyToEvent.getTs() - threadB.replyToEvent.getTs()) .forEach(([, thread]) => { const isOwnEvent = thread.rootEvent.getSender() === client.getUserId(); if (filterType !== ThreadFilterType.My || isOwnEvent) { diff --git a/src/components/structures/ThreadView.tsx b/src/components/structures/ThreadView.tsx index fc478b9988..ee95eff22c 100644 --- a/src/components/structures/ThreadView.tsx +++ b/src/components/structures/ThreadView.tsx @@ -15,9 +15,13 @@ limitations under the License. */ import React from 'react'; -import { IEventRelation, MatrixEvent, Room } from 'matrix-js-sdk/src'; import { Thread, ThreadEvent } from 'matrix-js-sdk/src/models/thread'; import { RelationType } from 'matrix-js-sdk/src/@types/event'; +import { Room } from 'matrix-js-sdk/src/models/room'; +import { IEventRelation, MatrixEvent } from 'matrix-js-sdk/src/models/event'; +import { TimelineWindow } from 'matrix-js-sdk/src/timeline-window'; +import { Direction } from 'matrix-js-sdk/src/models/event-timeline'; +import { IRelationsRequestOpts } from 'matrix-js-sdk/src/@types/requests'; import classNames from "classnames"; import BaseCard from "../views/right_panel/BaseCard"; @@ -141,7 +145,7 @@ export default class ThreadView extends React.Component { private setupThread = (mxEv: MatrixEvent) => { let thread = this.props.room.threads?.get(mxEv.getId()); if (!thread) { - thread = this.props.room.createThread([mxEv]); + thread = this.props.room.createThread(mxEv); } thread.on(ThreadEvent.Update, this.updateLastThreadReply); thread.once(ThreadEvent.Ready, this.updateThread); @@ -167,10 +171,13 @@ export default class ThreadView extends React.Component { this.setState({ thread, lastThreadReply: thread.lastReply((ev: MatrixEvent) => { - return !ev.status; + return ev.isThreadRelation && !ev.status; }), - }, () => { + }, async () => { thread.emit(ThreadEvent.ViewThread); + if (!thread.initialEventsFetched) { + await thread.fetchInitialEvents(); + } this.timelinePanelRef.current?.refreshTimeline(); }); } @@ -180,7 +187,7 @@ export default class ThreadView extends React.Component { if (this.state.thread) { this.setState({ lastThreadReply: this.state.thread.lastReply((ev: MatrixEvent) => { - return !ev.status; + return ev.isThreadRelation && !ev.status; }), }); } @@ -207,6 +214,31 @@ export default class ThreadView extends React.Component { ; }; + private onPaginationRequest = async ( + timelineWindow: TimelineWindow | null, + direction = Direction.Backward, + limit = 20, + ): Promise => { + if (!this.state.thread.hasServerSideSupport) { + return false; + } + + const timelineIndex = timelineWindow.getTimelineIndex(direction); + + const paginationKey = direction === Direction.Backward ? "from" : "to"; + const paginationToken = timelineIndex.timeline.getPaginationToken(direction); + + const opts: IRelationsRequestOpts = { + limit, + [paginationKey]: paginationToken, + direction, + }; + + await this.state.thread.fetchEvents(opts); + + return timelineWindow.paginate(direction, limit); + }; + public render(): JSX.Element { const highlightedEventId = this.props.isInitialEventHighlighted ? this.props.initialEvent?.getId() @@ -262,6 +294,7 @@ export default class ThreadView extends React.Component { eventId={this.props.initialEvent?.getId()} highlightedEventId={highlightedEventId} onUserScroll={this.onScroll} + onPaginationRequest={this.onPaginationRequest} /> ) } diff --git a/src/components/views/rooms/EventTile.tsx b/src/components/views/rooms/EventTile.tsx index d34dbb1605..f15d28f31a 100644 --- a/src/components/views/rooms/EventTile.tsx +++ b/src/components/views/rooms/EventTile.tsx @@ -407,7 +407,7 @@ export default class EventTile extends React.Component { thread, threadReplyCount: thread?.length, - threadLastReply: thread?.lastReply(), + threadLastReply: thread?.replyToEvent, }; // don't do RR animations until we are mounted @@ -561,7 +561,7 @@ export default class EventTile extends React.Component { } this.setState({ - threadLastReply: thread?.lastReply(), + threadLastReply: thread?.replyToEvent, threadReplyCount: thread?.length, thread, }); @@ -1290,7 +1290,7 @@ export default class EventTile extends React.Component { // Thread panel shows the timestamp of the last reply in that thread const ts = this.props.tileShape !== TileShape.ThreadPanel ? this.props.mxEvent.getTs() - : thread?.lastReply().getTs(); + : thread?.replyToEvent.getTs(); const messageTimestamp =