diff --git a/src/models/event.ts b/src/models/event.ts index 317377b1a..fcbdba3fa 100644 --- a/src/models/event.ts +++ b/src/models/event.ts @@ -420,6 +420,11 @@ export class MatrixEvent extends EventEmitter { || this.thread instanceof Thread; } + public get parentEventId(): string { + return this.replyEventId + || this.getWireContent()["m.relates_to"]?.event_id; + } + /** * Get the previous event content JSON. This will only return something for * state events which exist in the timeline. diff --git a/src/models/room.ts b/src/models/room.ts index ac80d9ceb..41d417417 100644 --- a/src/models/room.ts +++ b/src/models/room.ts @@ -1305,8 +1305,7 @@ export class Room extends EventEmitter { this.handleRemoteEcho(event, existingEvent); } } - - let thread = this.findEventById(event.replyEventId)?.getThread(); + let thread = this.findEventById(event.parentEventId)?.getThread(); if (thread) { thread.addEvent(event); } else { diff --git a/src/models/thread.ts b/src/models/thread.ts index 844fe2210..0415c554a 100644 --- a/src/models/thread.ts +++ b/src/models/thread.ts @@ -149,6 +149,10 @@ export class Thread extends EventEmitter { return this.findEventById(this.root); } + public get roomId(): string { + return this.rootEvent.getRoomId(); + } + /** * The number of messages in the thread */ diff --git a/src/sync.ts b/src/sync.ts index df9842132..0c5a81638 100644 --- a/src/sync.ts +++ b/src/sync.ts @@ -316,8 +316,18 @@ export class SyncApi { if (this.opts.experimentalThreadSupport) { return events.reduce((memo, event: MatrixEvent) => { const room = this.client.getRoom(event.getRoomId()); - const eventInThread = this.shouldLiveInThreadTimeline(event, room); - memo[eventInThread ? 1 : 0].push(event); + // An event should live in the thread timeline if + // - It's a reply in thread event + // - It's related to a reply in thread event + let shouldLiveInThreadTimeline = event.replyInThread; + if (!shouldLiveInThreadTimeline) { + const parentEventId = event.getWireContent()["m.relates_to"]?.event_id; + const parentEvent = room?.findEventById(parentEventId) || events.find((mxEv: MatrixEvent) => { + return mxEv.getId() === parentEventId; + }); + shouldLiveInThreadTimeline = parentEvent?.replyInThread; + } + memo[shouldLiveInThreadTimeline ? 1 : 0].push(event); return memo; }, [[], []]); } else { @@ -330,50 +340,6 @@ export class SyncApi { } } - /** - * @experimental - * An event should live in a thread if it's a threaded reply - * Or if it's related to an event that is a threaded reply - * Things like annotations, redactions, ... - */ - private shouldLiveInThreadTimeline(event: MatrixEvent, room: Room): boolean { - let isThreadReply = event.replyInThread; - - // If the message is sent from a client that does not support threads - // The relation body will not contain `UNSTABLE_ELEMENT_REPLY_IN_THREAD` - // We go up the reply chain looking for an event that has this property - // If we find one, we then decide to render this reply inside the thread - if (!isThreadReply && event.replyEventId) { - isThreadReply = this.ancestorInThread(event, room); - } - - let isRelatedToThreadReply = false; - const relationEventId = event.getRelation()?.event_id; - if (relationEventId) { - const relatedEvent = room.findEventById(relationEventId); - isRelatedToThreadReply = relatedEvent.replyInThread; - } - - return isThreadReply || isRelatedToThreadReply; - } - - /** - * @experimental - * Checks whether an event up in the reply chain has - * the `UNSTABLE_ELEMENT_REPLY_IN_THREAD` property in its - * relations body - */ - private ancestorInThread(event: MatrixEvent, room: Room): boolean { - const relatedEvent = room.findEventById(event.replyEventId); - if (relatedEvent.replyInThread) { - return true; - } else if (relatedEvent.replyEventId) { - return this.ancestorInThread(relatedEvent, room); - } else { - return false; - } - } - /** * Peek into a room. This will result in the room in question being synced so it * is accessible via getRooms(). Live updates for the room will be provided.