diff --git a/src/Unread.ts b/src/Unread.ts index 91e192b371..3dfd63614c 100644 --- a/src/Unread.ts +++ b/src/Unread.ts @@ -21,6 +21,8 @@ import { EventType } from "matrix-js-sdk/src/@types/event"; import { MatrixClientPeg } from "./MatrixClientPeg"; import shouldHideEvent from './shouldHideEvent'; import { haveTileForEvent } from "./components/views/rooms/EventTile"; +import SettingsStore from "./settings/SettingsStore"; +import { RoomNotificationStateStore } from "./stores/notifications/RoomNotificationStateStore"; /** * Returns true if this event arriving in a room should affect the room's @@ -57,14 +59,21 @@ export function doesRoomHaveUnreadMessages(room: Room): boolean { // despite the name of the method :(( const readUpToId = room.getEventReadUpTo(myUserId); - // as we don't send RRs for our own messages, make sure we special case that - // if *we* sent the last message into the room, we consider it not unread! - // Should fix: https://github.com/vector-im/element-web/issues/3263 - // https://github.com/vector-im/element-web/issues/2427 - // ...and possibly some of the others at - // https://github.com/vector-im/element-web/issues/3363 - if (room.timeline.length && room.timeline[room.timeline.length - 1].getSender() === myUserId) { - return false; + if (!SettingsStore.getValue("feature_thread")) { + // as we don't send RRs for our own messages, make sure we special case that + // if *we* sent the last message into the room, we consider it not unread! + // Should fix: https://github.com/vector-im/element-web/issues/3263 + // https://github.com/vector-im/element-web/issues/2427 + // ...and possibly some of the others at + // https://github.com/vector-im/element-web/issues/3363 + if (room.timeline.length && room.timeline[room.timeline.length - 1].getSender() === myUserId) { + return false; + } + } else { + const threadState = RoomNotificationStateStore.instance.getThreadsRoomState(room); + if (threadState.color > 0) { + return true; + } } // if the read receipt relates to an event is that part of a thread diff --git a/src/stores/notifications/RoomNotificationState.ts b/src/stores/notifications/RoomNotificationState.ts index 517a23fa97..c4c803483d 100644 --- a/src/stores/notifications/RoomNotificationState.ts +++ b/src/stores/notifications/RoomNotificationState.ts @@ -25,17 +25,21 @@ import { EffectiveMembership, getEffectiveMembership } from "../../utils/members import { readReceiptChangeIsFor } from "../../utils/read-receipts"; import * as RoomNotifs from '../../RoomNotifs'; import * as Unread from '../../Unread'; -import { NotificationState } from "./NotificationState"; +import { NotificationState, NotificationStateEvents } from "./NotificationState"; import { getUnsentMessages } from "../../components/structures/RoomStatusBar"; +import { ThreadsRoomNotificationState } from "./ThreadsRoomNotificationState"; export class RoomNotificationState extends NotificationState implements IDestroyable { - constructor(public readonly room: Room) { + constructor(public readonly room: Room, private readonly threadsState?: ThreadsRoomNotificationState) { super(); this.room.on(RoomEvent.Receipt, this.handleReadReceipt); this.room.on(RoomEvent.Timeline, this.handleRoomEventUpdate); this.room.on(RoomEvent.Redaction, this.handleRoomEventUpdate); this.room.on(RoomEvent.MyMembership, this.handleMembershipUpdate); this.room.on(RoomEvent.LocalEchoUpdated, this.handleLocalEchoUpdated); + if (threadsState) { + threadsState.on(NotificationStateEvents.Update, this.handleThreadsUpdate); + } MatrixClientPeg.get().on(MatrixEventEvent.Decrypted, this.onEventDecrypted); MatrixClientPeg.get().on(ClientEvent.AccountData, this.handleAccountDataUpdate); this.updateNotificationState(); @@ -52,12 +56,19 @@ export class RoomNotificationState extends NotificationState implements IDestroy this.room.removeListener(RoomEvent.Redaction, this.handleRoomEventUpdate); this.room.removeListener(RoomEvent.MyMembership, this.handleMembershipUpdate); this.room.removeListener(RoomEvent.LocalEchoUpdated, this.handleLocalEchoUpdated); + if (this.threadsState) { + this.threadsState.removeListener(NotificationStateEvents.Update, this.handleThreadsUpdate); + } if (MatrixClientPeg.get()) { MatrixClientPeg.get().removeListener(MatrixEventEvent.Decrypted, this.onEventDecrypted); MatrixClientPeg.get().removeListener(ClientEvent.AccountData, this.handleAccountDataUpdate); } } + private handleThreadsUpdate = () => { + this.updateNotificationState(); + }; + private handleLocalEchoUpdated = () => { this.updateNotificationState(); }; diff --git a/src/stores/notifications/RoomNotificationStateStore.ts b/src/stores/notifications/RoomNotificationStateStore.ts index 6090797384..887e1a7332 100644 --- a/src/stores/notifications/RoomNotificationStateStore.ts +++ b/src/stores/notifications/RoomNotificationStateStore.ts @@ -82,12 +82,13 @@ export class RoomNotificationStateStore extends AsyncStoreWithClient { */ public getRoomState(room: Room): RoomNotificationState { if (!this.roomMap.has(room)) { - this.roomMap.set(room, new RoomNotificationState(room)); // Not very elegant, but that way we ensure that we start tracking // threads notification at the same time at rooms. // There are multiple entry points, and it's unclear which one gets // called first - this.roomThreadsMap.set(room, new ThreadsRoomNotificationState(room)); + const threadState = new ThreadsRoomNotificationState(room); + this.roomThreadsMap.set(room, threadState); + this.roomMap.set(room, new RoomNotificationState(room, threadState)); } return this.roomMap.get(room); }