Add mark as read option in room setting (#9798)

This commit is contained in:
Germain 2022-12-22 13:18:38 +00:00 committed by GitHub
parent ce75d3381f
commit e9224f6fce
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 378 additions and 37 deletions

View file

@ -23,11 +23,14 @@ import RoomListActions from "../../../actions/RoomListActions";
import MatrixClientContext from "../../../contexts/MatrixClientContext";
import dis from "../../../dispatcher/dispatcher";
import { useEventEmitterState } from "../../../hooks/useEventEmitter";
import { useUnreadNotifications } from "../../../hooks/useUnreadNotifications";
import { getKeyBindingsManager } from "../../../KeyBindingsManager";
import { _t } from "../../../languageHandler";
import { NotificationColor } from "../../../stores/notifications/NotificationColor";
import { DefaultTagID, TagID } from "../../../stores/room-list/models";
import RoomListStore, { LISTS_UPDATE_EVENT } from "../../../stores/room-list/RoomListStore";
import DMRoomMap from "../../../utils/DMRoomMap";
import { clearRoomNotification } from "../../../utils/notifications";
import { IProps as IContextMenuProps } from "../../structures/ContextMenu";
import IconizedContextMenu, {
IconizedContextMenuCheckbox,
@ -36,7 +39,7 @@ import IconizedContextMenu, {
} from "../context_menus/IconizedContextMenu";
import { ButtonEvent } from "../elements/AccessibleButton";
interface IProps extends IContextMenuProps {
export interface RoomGeneralContextMenuProps extends IContextMenuProps {
room: Room;
onPostFavoriteClick?: (event: ButtonEvent) => void;
onPostLowPriorityClick?: (event: ButtonEvent) => void;
@ -58,7 +61,7 @@ export const RoomGeneralContextMenu = ({
onPostLeaveClick,
onPostForgetClick,
...props
}: IProps) => {
}: RoomGeneralContextMenuProps) => {
const cli = useContext(MatrixClientContext);
const roomTags = useEventEmitterState(RoomListStore.instance, LISTS_UPDATE_EVENT, () =>
RoomListStore.instance.getTagsForRoom(room),
@ -115,8 +118,8 @@ export const RoomGeneralContextMenu = ({
/>
);
let inviteOption: JSX.Element;
if (room.canInvite(cli.getUserId()) && !isDm) {
let inviteOption: JSX.Element | null = null;
if (room.canInvite(cli.getUserId()!) && !isDm) {
inviteOption = (
<IconizedContextMenuOption
onClick={wrapHandler(
@ -133,7 +136,7 @@ export const RoomGeneralContextMenu = ({
);
}
let copyLinkOption: JSX.Element;
let copyLinkOption: JSX.Element | null = null;
if (!isDm) {
copyLinkOption = (
<IconizedContextMenuOption
@ -201,17 +204,34 @@ export const RoomGeneralContextMenu = ({
);
}
const { color } = useUnreadNotifications(room);
const markAsReadOption: JSX.Element | null =
color > NotificationColor.None ? (
<IconizedContextMenuCheckbox
onClick={() => {
clearRoomNotification(room, cli);
onFinished?.();
}}
active={false}
label={_t("Mark as read")}
iconClassName="mx_RoomGeneralContextMenu_iconMarkAsRead"
/>
) : null;
return (
<IconizedContextMenu {...props} onFinished={onFinished} className="mx_RoomGeneralContextMenu" compact>
{!roomTags.includes(DefaultTagID.Archived) && (
<IconizedContextMenuOptionList>
{favoriteOption}
{lowPriorityOption}
{inviteOption}
{copyLinkOption}
{settingsOption}
</IconizedContextMenuOptionList>
)}
<IconizedContextMenuOptionList>
{markAsReadOption}
{!roomTags.includes(DefaultTagID.Archived) && (
<>
{favoriteOption}
{lowPriorityOption}
{inviteOption}
{copyLinkOption}
{settingsOption}
</>
)}
</IconizedContextMenuOptionList>
<IconizedContextMenuOptionList red>{leaveOption}</IconizedContextMenuOptionList>
</IconizedContextMenu>
);

View file

@ -3187,6 +3187,7 @@
"Copy room link": "Copy room link",
"Low Priority": "Low Priority",
"Forget Room": "Forget Room",
"Mark as read": "Mark as read",
"Use default": "Use default",
"Mentions & Keywords": "Mentions & Keywords",
"See room timeline (devtools)": "See room timeline (devtools)",

View file

@ -18,7 +18,7 @@ import { MatrixClient } from "matrix-js-sdk/src/client";
import { LOCAL_NOTIFICATION_SETTINGS_PREFIX } from "matrix-js-sdk/src/@types/event";
import { LocalNotificationSettings } from "matrix-js-sdk/src/@types/local_notifications";
import { ReceiptType } from "matrix-js-sdk/src/@types/read_receipts";
import { Room } from "matrix-js-sdk/src/models/room";
import { NotificationCountType, Room } from "matrix-js-sdk/src/models/room";
import SettingsStore from "../settings/SettingsStore";
@ -59,27 +59,57 @@ export function localNotificationsAreSilenced(cli: MatrixClient): boolean {
return event?.getContent<LocalNotificationSettings>()?.is_silenced ?? false;
}
export function clearAllNotifications(client: MatrixClient): Promise<Array<{}>> {
const receiptPromises = client.getRooms().reduce((promises, room: Room) => {
/**
* Mark a room as read
* @param room
* @param client
* @returns a promise that resolves when the room has been marked as read
*/
export async function clearRoomNotification(room: Room, client: MatrixClient): Promise<{} | undefined> {
const roomEvents = room.getLiveTimeline().getEvents();
const lastThreadEvents = room.lastThread?.events;
const lastRoomEvent = roomEvents?.[roomEvents?.length - 1];
const lastThreadLastEvent = lastThreadEvents?.[lastThreadEvents?.length - 1];
const lastEvent =
(lastRoomEvent?.getTs() ?? 0) > (lastThreadLastEvent?.getTs() ?? 0) ? lastRoomEvent : lastThreadLastEvent;
try {
if (lastEvent) {
const receiptType = SettingsStore.getValue("sendReadReceipts", room.roomId)
? ReceiptType.Read
: ReceiptType.ReadPrivate;
return await client.sendReadReceipt(lastEvent, receiptType, true);
} else {
return {};
}
} finally {
// We've had a lot of stuck unread notifications that in e2ee rooms
// They occur on event decryption when clients try to replicate the logic
//
// This resets the notification on a room, even though no read receipt
// has been sent, particularly useful when the clients has incorrectly
// notified a user.
room.setUnreadNotificationCount(NotificationCountType.Highlight, 0);
room.setUnreadNotificationCount(NotificationCountType.Total, 0);
for (const thread of room.getThreads()) {
room.setThreadUnreadNotificationCount(thread.id, NotificationCountType.Highlight, 0);
room.setThreadUnreadNotificationCount(thread.id, NotificationCountType.Total, 0);
}
}
}
/**
* Marks all rooms with an unread counter as read
* @param client The matrix client
* @returns a promise that resolves when all rooms have been marked as read
*/
export function clearAllNotifications(client: MatrixClient): Promise<Array<{} | undefined>> {
const receiptPromises = client.getRooms().reduce((promises: Array<Promise<{} | undefined>>, room: Room) => {
if (room.getUnreadNotificationCount() > 0) {
const roomEvents = room.getLiveTimeline().getEvents();
const lastThreadEvents = room.lastThread?.events;
const lastRoomEvent = roomEvents?.[roomEvents?.length - 1];
const lastThreadLastEvent = lastThreadEvents?.[lastThreadEvents?.length - 1];
const lastEvent =
(lastRoomEvent?.getTs() ?? 0) > (lastThreadLastEvent?.getTs() ?? 0)
? lastRoomEvent
: lastThreadLastEvent;
if (lastEvent) {
const receiptType = SettingsStore.getValue("sendReadReceipts", room.roomId)
? ReceiptType.Read
: ReceiptType.ReadPrivate;
const promise = client.sendReadReceipt(lastEvent, receiptType, true);
promises.push(promise);
}
const promise = clearRoomNotification(room, client);
promises.push(promise);
}
return promises;