diff --git a/src/components/structures/RoomView.tsx b/src/components/structures/RoomView.tsx index 8d85b54df72..221d2151efd 100644 --- a/src/components/structures/RoomView.tsx +++ b/src/components/structures/RoomView.tsx @@ -223,6 +223,7 @@ export interface IRoomState { narrow: boolean; // List of undecryptable events currently visible on-screen visibleDecryptionFailures?: MatrixEvent[]; + msc3946ProcessDynamicPredecessor: boolean; } interface LocalRoomViewProps { @@ -416,6 +417,7 @@ export class RoomView extends React.Component { liveTimeline: undefined, narrow: false, visibleDecryptionFailures: [], + msc3946ProcessDynamicPredecessor: SettingsStore.getValue("feature_dynamic_room_predecessors"), }; this.dispatcherRef = dis.register(this.onAction); @@ -467,6 +469,9 @@ export class RoomView extends React.Component { ), SettingsStore.watchSetting("urlPreviewsEnabled", null, this.onUrlPreviewsEnabledChange), SettingsStore.watchSetting("urlPreviewsEnabled_e2ee", null, this.onUrlPreviewsEnabledChange), + SettingsStore.watchSetting("feature_dynamic_room_predecessors", null, (...[, , , value]) => + this.setState({ msc3946ProcessDynamicPredecessor: value as boolean }), + ), ]; } @@ -1798,10 +1803,8 @@ export class RoomView extends React.Component { }; private getOldRoom(): Room | null { - const createEvent = this.state.room.currentState.getStateEvents(EventType.RoomCreate, ""); - if (!createEvent || !createEvent.getContent()["predecessor"]) return null; - - return this.context.client.getRoom(createEvent.getContent()["predecessor"]["room_id"]); + const { roomId } = this.state.room?.findPredecessor(this.state.msc3946ProcessDynamicPredecessor) || {}; + return this.context.client?.getRoom(roomId) || null; } public getHiddenHighlightCount(): number { diff --git a/src/contexts/RoomContext.ts b/src/contexts/RoomContext.ts index f5990205224..9d3eeff564f 100644 --- a/src/contexts/RoomContext.ts +++ b/src/contexts/RoomContext.ts @@ -65,6 +65,7 @@ const RoomContext = createContext({ liveTimeline: undefined, narrow: false, activeCall: null, + msc3946ProcessDynamicPredecessor: false, }); RoomContext.displayName = "RoomContext"; export default RoomContext; diff --git a/test/components/structures/RoomView-test.tsx b/test/components/structures/RoomView-test.tsx index b740ffe5a3e..e9860f5bbaa 100644 --- a/test/components/structures/RoomView-test.tsx +++ b/test/components/structures/RoomView-test.tsx @@ -55,6 +55,7 @@ const RoomView = wrapInMatrixClientContext(_RoomView); describe("RoomView", () => { let cli: MockedObject; let room: Room; + let rooms: Map; let roomCount = 0; let stores: SdkContextClass; @@ -64,8 +65,11 @@ describe("RoomView", () => { cli = mocked(MatrixClientPeg.get()); room = new Room(`!${roomCount++}:example.org`, cli, "@alice:example.org"); + jest.spyOn(room, "findPredecessor"); room.getPendingEvents = () => []; - cli.getRoom.mockImplementation(() => room); + rooms = new Map(); + rooms.set(room.roomId, room); + cli.getRoom.mockImplementation((roomId: string | undefined) => rooms.get(roomId || "") || null); // Re-emit certain events on the mocked client room.on(RoomEvent.Timeline, (...args) => cli.emit(RoomEvent.Timeline, ...args)); room.on(RoomEvent.TimelineReset, (...args) => cli.emit(RoomEvent.TimelineReset, ...args)); @@ -158,6 +162,42 @@ describe("RoomView", () => { const getRoomViewInstance = async (): Promise<_RoomView> => (await mountRoomView()).find(_RoomView).instance() as _RoomView; + it("when there is no room predecessor, getHiddenHighlightCount should return 0", async () => { + const instance = await getRoomViewInstance(); + expect(instance.getHiddenHighlightCount()).toBe(0); + }); + + describe("when there is an old room", () => { + let instance: _RoomView; + let oldRoom: Room; + + beforeEach(async () => { + instance = await getRoomViewInstance(); + oldRoom = new Room("!old:example.com", cli, cli.getSafeUserId()); + rooms.set(oldRoom.roomId, oldRoom); + jest.spyOn(room, "findPredecessor").mockReturnValue({ roomId: oldRoom.roomId, eventId: null }); + }); + + it("and it has 0 unreads, getHiddenHighlightCount should return 0", async () => { + jest.spyOn(oldRoom, "getUnreadNotificationCount").mockReturnValue(0); + expect(instance.getHiddenHighlightCount()).toBe(0); + // assert that msc3946ProcessDynamicPredecessor is false by default + expect(room.findPredecessor).toHaveBeenCalledWith(false); + }); + + it("and it has 23 unreads, getHiddenHighlightCount should return 23", async () => { + jest.spyOn(oldRoom, "getUnreadNotificationCount").mockReturnValue(23); + expect(instance.getHiddenHighlightCount()).toBe(23); + }); + + it("and feature_dynamic_room_predecessors is enabled it should pass the setting to findPredecessor", async () => { + SettingsStore.setValue("feature_dynamic_room_predecessors", null, SettingLevel.DEVICE, true); + expect(instance.getHiddenHighlightCount()).toBe(0); + expect(room.findPredecessor).toHaveBeenCalledWith(true); + SettingsStore.setValue("feature_dynamic_room_predecessors", null, SettingLevel.DEVICE, null); + }); + }); + it("updates url preview visibility on encryption state change", async () => { // we should be starting unencrypted expect(cli.isCryptoEnabled()).toEqual(false); @@ -248,6 +288,7 @@ describe("RoomView", () => { beforeEach(async () => { localRoom = room = await createDmLocalRoom(cli, [new DirectoryMember({ user_id: "@user:example.com" })]); + rooms.set(localRoom.roomId, localRoom); cli.store.storeRoom(room); }); diff --git a/test/components/views/rooms/SendMessageComposer-test.tsx b/test/components/views/rooms/SendMessageComposer-test.tsx index 1005758ae99..7dcc89be1ef 100644 --- a/test/components/views/rooms/SendMessageComposer-test.tsx +++ b/test/components/views/rooms/SendMessageComposer-test.tsx @@ -78,6 +78,7 @@ describe("", () => { resizing: false, narrow: false, activeCall: null, + msc3946ProcessDynamicPredecessor: false, }; describe("createMessageContent", () => { const permalinkCreator = jest.fn() as any; diff --git a/test/test-utils/room.ts b/test/test-utils/room.ts index d20200bef18..af2487a6043 100644 --- a/test/test-utils/room.ts +++ b/test/test-utils/room.ts @@ -86,6 +86,7 @@ export function getRoomContext(room: Room, override: Partial): IRoom resizing: false, narrow: false, activeCall: null, + msc3946ProcessDynamicPredecessor: false, ...override, };