Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Mark a thread as unread in the threads list due to activity. #9738

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/Unread.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export function doesRoomHaveUnreadMessages(room: Room): boolean {
return false;
}

function doesRoomOrThreadHaveUnreadMessages(room: Room | Thread): boolean {
export function doesRoomOrThreadHaveUnreadMessages(room: Room | Thread): boolean {
const myUserId = MatrixClientPeg.get().getUserId();

// as we don't send RRs for our own messages, make sure we special case that
Expand Down
13 changes: 8 additions & 5 deletions src/hooks/useUnreadNotifications.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,13 @@ limitations under the License.
*/

import { NotificationCount, NotificationCountType, Room, RoomEvent } from "matrix-js-sdk/src/models/room";
import { Thread } from "matrix-js-sdk/src/models/thread";
import { useCallback, useEffect, useState } from "react";

import { getUnsentMessages } from "../components/structures/RoomStatusBar";
import { getRoomNotifsState, getUnreadNotificationCount, RoomNotifState } from "../RoomNotifs";
import { NotificationColor } from "../stores/notifications/NotificationColor";
import { doesRoomHaveUnreadMessages } from "../Unread";
import { doesRoomOrThreadHaveUnreadMessages } from "../Unread";
import { EffectiveMembership, getEffectiveMembership } from "../utils/membership";
import { useEventEmitter } from "./useEventEmitter";

Expand Down Expand Up @@ -75,12 +76,14 @@ export const useUnreadNotifications = (
setColor(NotificationColor.Red);
} else if (greyNotifs > 0) {
setColor(NotificationColor.Grey);
} else if (!threadId) {
// TODO: No support for `Bold` on threads at the moment

} else {
// We don't have any notified messages, but we might have unread messages. Let's
// find out.
const hasUnread = doesRoomHaveUnreadMessages(room);
let roomOrThread: Room | Thread = room;
if (threadId) {
roomOrThread = room.getThread(threadId)!;
}
const hasUnread = doesRoomOrThreadHaveUnreadMessages(roomOrThread);
setColor(hasUnread ? NotificationColor.Bold : NotificationColor.None);
}
}
Expand Down
3 changes: 2 additions & 1 deletion test/components/views/rooms/EventTile-test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,8 @@ describe("EventTile", () => {
it("shows an unread notification bage", () => {
const { container } = getComponent({}, TimelineRenderingType.ThreadsList);

expect(container.getElementsByClassName("mx_NotificationBadge")).toHaveLength(0);
// By default, the thread will assume there's unread activity in it.
expect(container.getElementsByClassName("mx_NotificationBadge")).toHaveLength(1);

act(() => {
room.setThreadUnreadNotificationCount(mxEvent.getId(), NotificationCountType.Total, 3);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,14 @@ limitations under the License.
import React from "react";
import "jest-mock";
import { screen, act, render } from "@testing-library/react";
import { MatrixClient, PendingEventOrdering } from "matrix-js-sdk/src/client";
import { MsgType } from "matrix-js-sdk/src/matrix";
import { PendingEventOrdering } from "matrix-js-sdk/src/client";
import { NotificationCountType, Room } from "matrix-js-sdk/src/models/room";
import { mocked } from "jest-mock";
import { EventStatus } from "matrix-js-sdk/src/models/event-status";

import { mkThread } from "../../../../test-utils/threads";
import { UnreadNotificationBadge } from "../../../../../src/components/views/rooms/NotificationBadge/UnreadNotificationBadge";
import { mkMessage, stubClient } from "../../../../test-utils/test-utils";
import { mkEvent, mkMessage, stubClient } from "../../../../test-utils/test-utils";
import { MatrixClientPeg } from "../../../../../src/MatrixClientPeg";
import * as RoomNotifs from "../../../../../src/RoomNotifs";

Expand All @@ -34,28 +35,38 @@ jest.mock("../../../../../src/RoomNotifs", () => ({
}));

const ROOM_ID = "!roomId:example.org";
let THREAD_ID;
let THREAD_ID: string;

describe("UnreadNotificationBadge", () => {
let mockClient: MatrixClient;
stubClient();
const client = MatrixClientPeg.get();
let room: Room;

function getComponent(threadId?: string) {
return <UnreadNotificationBadge room={room} threadId={threadId} />;
}

beforeAll(() => {
client.supportsExperimentalThreads = () => true;
});

beforeEach(() => {
jest.clearAllMocks();

stubClient();
mockClient = mocked(MatrixClientPeg.get());

room = new Room(ROOM_ID, mockClient, mockClient.getUserId() ?? "", {
room = new Room(ROOM_ID, client, client.getUserId()!, {
pendingEventOrdering: PendingEventOrdering.Detached,
});
room.setUnreadNotificationCount(NotificationCountType.Total, 1);
room.setUnreadNotificationCount(NotificationCountType.Highlight, 0);

const { rootEvent } = mkThread({
room,
client,
authorId: client.getUserId()!,
participantUserIds: [client.getUserId()!],
});
THREAD_ID = rootEvent.getId()!;

room.setThreadUnreadNotificationCount(THREAD_ID, NotificationCountType.Total, 1);
room.setThreadUnreadNotificationCount(THREAD_ID, NotificationCountType.Highlight, 0);

Expand Down Expand Up @@ -125,4 +136,33 @@ describe("UnreadNotificationBadge", () => {
const { container } = render(getComponent());
expect(container.querySelector(".mx_NotificationBadge")).toBeNull();
});

it("activity renders unread notification badge", () => {
act(() => {
room.setThreadUnreadNotificationCount(THREAD_ID, NotificationCountType.Total, 0);
room.setThreadUnreadNotificationCount(THREAD_ID, NotificationCountType.Highlight, 0);

// Add another event on the thread which is not sent by us.
const event = mkEvent({
event: true,
type: "m.room.message",
user: "@alice:server.org",
room: room.roomId,
content: {
"msgtype": MsgType.Text,
"body": "Hello from Bob",
"m.relates_to": {
event_id: THREAD_ID,
rel_type: "m.thread",
},
},
});
room.addLiveEvents([event]);
});

const { container } = render(getComponent(THREAD_ID));
expect(container.querySelector(".mx_NotificationBadge_dot")).toBeTruthy();
expect(container.querySelector(".mx_NotificationBadge_visible")).toBeTruthy();
expect(container.querySelector(".mx_NotificationBadge_highlighted")).toBeFalsy();
});
});