diff --git a/src/MatrixClientPeg.ts b/src/MatrixClientPeg.ts index a281ba6562..e51eb789d8 100644 --- a/src/MatrixClientPeg.ts +++ b/src/MatrixClientPeg.ts @@ -285,7 +285,6 @@ class MatrixClientPegClass implements IMatrixClientPeg { SHOW_QR_CODE_METHOD, verificationMethods.RECIPROCATE_QR_CODE, ], - unstableClientRelationAggregation: true, identityServer: new IdentityAuthClient(), cryptoCallbacks: {}, }; diff --git a/src/components/structures/MessagePanel.tsx b/src/components/structures/MessagePanel.tsx index f0344727b6..3cf8017753 100644 --- a/src/components/structures/MessagePanel.tsx +++ b/src/components/structures/MessagePanel.tsx @@ -469,12 +469,9 @@ export default class MessagePanel extends React.Component { // TODO: Implement granular (per-room) hide options public shouldShowEvent(mxEv: MatrixEvent, forceHideEvents = false): boolean { - if (this.props.hideThreadedMessages && this.threadsEnabled) { - if (mxEv.isThreadRelation) { - return false; - } - - if (this.shouldLiveInThreadOnly(mxEv)) { + if (this.props.hideThreadedMessages && this.threadsEnabled && this.props.room) { + const { shouldLiveInRoom } = this.props.room.eventShouldLiveIn(mxEv, this.props.events); + if (!shouldLiveInRoom) { return false; } } @@ -497,24 +494,6 @@ export default class MessagePanel extends React.Component { return !shouldHideEvent(mxEv, this.context); } - private shouldLiveInThreadOnly(event: MatrixEvent): boolean { - const associatedId = event.getAssociatedId(); - - const targetsThreadRoot = event.threadRootId === associatedId; - if (event.isThreadRoot || targetsThreadRoot || !event.isThreadRelation) { - return false; - } - - // If this is a reply, then we use the associated event to decide whether - // this should be thread only or not - const parentEvent = this.props.room.findEventById(associatedId); - if (parentEvent) { - return this.shouldLiveInThreadOnly(parentEvent); - } else { - return true; - } - } - public readMarkerForEvent(eventId: string, isLastEvent: boolean): ReactNode { const visible = !isLastEvent && this.props.readMarkerVisible; diff --git a/src/components/structures/RoomView.tsx b/src/components/structures/RoomView.tsx index 614bbee387..ed5f60d357 100644 --- a/src/components/structures/RoomView.tsx +++ b/src/components/structures/RoomView.tsx @@ -974,9 +974,8 @@ export class RoomView extends React.Component { CHAT_EFFECTS.forEach(effect => { if (containsEmoji(ev.getContent(), effect.emojis) || ev.getContent().msgtype === effect.msgType) { - // For initial threads launch, chat effects are disabled - // see #19731 - if (!SettingsStore.getValue("feature_thread") || !ev.isThreadRelation) { + // For initial threads launch, chat effects are disabled see #19731 + if (!SettingsStore.getValue("feature_thread") || !ev.isRelation(THREAD_RELATION_TYPE.name)) { dis.dispatch({ action: `effects.${effect.command}` }); } } diff --git a/src/components/structures/TimelinePanel.tsx b/src/components/structures/TimelinePanel.tsx index 846b78be1f..c5e9c77f40 100644 --- a/src/components/structures/TimelinePanel.tsx +++ b/src/components/structures/TimelinePanel.tsx @@ -1425,27 +1425,18 @@ class TimelinePanel extends React.Component { // if we're at the end of the live timeline, append the pending events if (!this.timelineWindow.canPaginate(EventTimeline.FORWARDS)) { const pendingEvents = this.props.timelineSet.getPendingEvents(); - if (this.context.timelineRenderingType === TimelineRenderingType.Thread) { - events.push(...pendingEvents.filter(e => e.threadRootId === this.context.threadId)); - } else { - events.push(...pendingEvents.filter(e => { - const hasNoRelation = !e.getRelation(); - if (hasNoRelation) { - return true; - } + events.push(...pendingEvents.filter(event => { + const { + shouldLiveInRoom, + threadId, + } = this.props.timelineSet.room.eventShouldLiveIn(event, pendingEvents); - if (e.isThreadRelation) { - return false; - } - - const parentEvent = this.props.timelineSet.findEventById(e.getAssociatedId()); - if (!parentEvent) { - return false; - } else { - return !parentEvent.isThreadRelation; - } - })); - } + if (this.context.timelineRenderingType === TimelineRenderingType.Thread) { + return threadId === this.context.threadId; + } { + return shouldLiveInRoom; + } + })); } return { @@ -1678,7 +1669,7 @@ class TimelinePanel extends React.Component { eventId: string, relationType: RelationType, eventType: EventType | string, - ) => this.props.timelineSet.getRelationsForEvent(eventId, relationType, eventType); + ) => this.props.timelineSet.relations?.getChildEventsForEvent(eventId, relationType, eventType); private buildCallEventGroupers(events?: MatrixEvent[]): void { this.callEventGroupers = buildCallEventGroupers(this.callEventGroupers, events); diff --git a/src/components/views/messages/MessageActionBar.tsx b/src/components/views/messages/MessageActionBar.tsx index 690d4d60bb..2788a17e6b 100644 --- a/src/components/views/messages/MessageActionBar.tsx +++ b/src/components/views/messages/MessageActionBar.tsx @@ -189,7 +189,7 @@ const ReplyInThreadButton = ({ mxEvent }: IReplyInThreadButton) => { action: Action.ViewUserSettings, initialTabId: UserTab.Labs, }); - } else if (mxEvent.isThreadRelation) { + } else if (mxEvent.getThread() && !mxEvent.isThreadRoot) { showThread({ rootEvent: mxEvent.getThread().rootEvent, initialEvent: mxEvent, diff --git a/src/components/views/rooms/SendMessageComposer.tsx b/src/components/views/rooms/SendMessageComposer.tsx index c309e0a16c..c115aa0813 100644 --- a/src/components/views/rooms/SendMessageComposer.tsx +++ b/src/components/views/rooms/SendMessageComposer.tsx @@ -285,8 +285,8 @@ export class SendMessageComposer extends React.Component', () => { }, }); // mock the thread stuff - jest.spyOn(threadReplyEvent, 'isThreadRelation', 'get').mockReturnValue(true); + jest.spyOn(threadReplyEvent, 'isThreadRoot', 'get').mockReturnValue(false); // set alicesMessageEvent as the root event jest.spyOn(threadReplyEvent, 'getThread').mockReturnValue( { rootEvent: alicesMessageEvent } as unknown as Thread,