From 3f1e56b715c8ccacc78819441be0b7dad5dc6c55 Mon Sep 17 00:00:00 2001 From: R Midhun Suresh Date: Mon, 24 Mar 2025 22:21:42 +0530 Subject: [PATCH] RoomListStore: Unread filter should match rooms that were marked as unread (#29580) * Unread filter should match rooms marked as unread * Re-insert room into skip list on account data So that filters are re-calculated when rooms are marked as unread. * Write test --- src/stores/room-list-v3/RoomListStoreV3.ts | 10 ++++++ .../skip-list/filters/UnreadFilter.ts | 3 +- .../room-list-v3/RoomListStoreV3-test.ts | 31 +++++++++++++++++++ 3 files changed, 43 insertions(+), 1 deletion(-) diff --git a/src/stores/room-list-v3/RoomListStoreV3.ts b/src/stores/room-list-v3/RoomListStoreV3.ts index 286a5f0554..3d4af05e39 100644 --- a/src/stores/room-list-v3/RoomListStoreV3.ts +++ b/src/stores/room-list-v3/RoomListStoreV3.ts @@ -33,6 +33,7 @@ import { MentionsFilter } from "./skip-list/filters/MentionsFilter"; import { LowPriorityFilter } from "./skip-list/filters/LowPriorityFilter"; import { type Sorter, SortingAlgorithm } from "./skip-list/sorters"; import { SettingLevel } from "../../settings/SettingLevel"; +import { MARKED_UNREAD_TYPE_STABLE, MARKED_UNREAD_TYPE_UNSTABLE } from "../../utils/notifications"; /** * These are the filters passed to the room skip list. @@ -156,6 +157,15 @@ export class RoomListStoreV3Class extends AsyncStoreWithClient { break; } + case "MatrixActions.Room.accountData": { + const eventType = payload.event_type; + if (eventType === MARKED_UNREAD_TYPE_STABLE || eventType === MARKED_UNREAD_TYPE_UNSTABLE) { + const room = payload.room; + this.addRoomAndEmit(room); + } + break; + } + case "MatrixActions.Event.decrypted": { const roomId = payload.event.getRoomId(); if (!roomId) return; diff --git a/src/stores/room-list-v3/skip-list/filters/UnreadFilter.ts b/src/stores/room-list-v3/skip-list/filters/UnreadFilter.ts index e2ffc8f0f4..db29861cd1 100644 --- a/src/stores/room-list-v3/skip-list/filters/UnreadFilter.ts +++ b/src/stores/room-list-v3/skip-list/filters/UnreadFilter.ts @@ -8,10 +8,11 @@ import type { Room } from "matrix-js-sdk/src/matrix"; import type { Filter } from "."; import { FilterKey } from "."; import { RoomNotificationStateStore } from "../../../notifications/RoomNotificationStateStore"; +import { getMarkedUnreadState } from "../../../../utils/notifications"; export class UnreadFilter implements Filter { public matches(room: Room): boolean { - return RoomNotificationStateStore.instance.getRoomState(room).hasUnreadCount; + return RoomNotificationStateStore.instance.getRoomState(room).hasUnreadCount || !!getMarkedUnreadState(room); } public get key(): FilterKey.UnreadFilter { diff --git a/test/unit-tests/stores/room-list-v3/RoomListStoreV3-test.ts b/test/unit-tests/stores/room-list-v3/RoomListStoreV3-test.ts index 573e7a38b4..73fb72ea17 100644 --- a/test/unit-tests/stores/room-list-v3/RoomListStoreV3-test.ts +++ b/test/unit-tests/stores/room-list-v3/RoomListStoreV3-test.ts @@ -26,6 +26,7 @@ import { RoomNotificationStateStore } from "../../../../src/stores/notifications import DMRoomMap from "../../../../src/utils/DMRoomMap"; import { SortingAlgorithm } from "../../../../src/stores/room-list-v3/skip-list/sorters"; import SettingsStore from "../../../../src/settings/SettingsStore"; +import * as utils from "../../../../src/utils/notifications"; describe("RoomListStoreV3", () => { async function getRoomListStore() { @@ -474,6 +475,36 @@ describe("RoomListStoreV3", () => { } }); + it("unread filter matches rooms that are marked as unread", async () => { + const { client, rooms } = getClientAndRooms(); + // Let's choose 5 rooms to put in space + const { spaceRoom, roomIds } = createSpace(rooms, [6, 8, 13, 27, 75], client); + + setupMocks(spaceRoom, roomIds); + const store = new RoomListStoreV3Class(dispatcher); + await store.start(); + + // Since there's no unread yet, we expect zero results + let result = store.getSortedRoomsInActiveSpace([FilterKey.UnreadFilter]); + expect(result).toHaveLength(0); + + // Mock so that room at index 8 is marked as unread + jest.spyOn(utils, "getMarkedUnreadState").mockImplementation((room) => room.roomId === rooms[8].roomId); + dispatcher.dispatch( + { + action: "MatrixActions.Room.accountData", + room: rooms[8], + event_type: utils.MARKED_UNREAD_TYPE_STABLE, + }, + true, + ); + + // Now we expect room at index 8 to show as unread + result = store.getSortedRoomsInActiveSpace([FilterKey.UnreadFilter]); + expect(result).toHaveLength(1); + expect(result).toContain(rooms[8]); + }); + it("supports filtering by people and rooms", async () => { const { client, rooms } = getClientAndRooms(); // Let's choose 5 rooms to put in space