Files
cinny/src/app/utils/notifications.ts
T

51 lines
2.2 KiB
TypeScript
Raw Normal View History

import { MatrixClient, NotificationCountType, ReceiptType } from 'matrix-js-sdk';
import { getSettings } from '../state/settings';
2022-03-18 09:09:14 +05:30
export async function markAsRead(mx: MatrixClient, roomId: string, privateReceipt: boolean) {
const { privateReadReceipts } = getSettings();
2022-03-18 09:09:14 +05:30
const room = mx.getRoom(roomId);
if (!room) return;
const receiptType =
privateReceipt || privateReadReceipts ? ReceiptType.ReadPrivate : ReceiptType.Read;
2022-03-18 09:09:14 +05:30
const timeline = room.getLiveTimeline().getEvents();
2024-07-22 16:17:19 +05:30
const readEventId = room.getEventReadUpTo(mx.getUserId()!);
2022-03-18 09:09:14 +05:30
const getLatestValidEvent = () => {
for (let i = timeline.length - 1; i >= 0; i -= 1) {
const latestEvent = timeline[i];
if (latestEvent.getId() === readEventId) return null;
if (!latestEvent.isSending()) return latestEvent;
}
return null;
};
const latestEvent = timeline.length > 0 ? getLatestValidEvent() : null;
if (latestEvent) {
// Unthreaded receipt: with client threadSupport enabled the SDK would
// otherwise scope this to the main timeline (thread_id: "main"). Unthreaded
// clears the main timeline + every event up to this one, in any thread.
await mx.sendReadReceipt(latestEvent, receiptType, true);
}
// ...but a thread reply NEWER than the main-timeline tail is not covered by
// the receipt above (threadSupport moves thread replies out of the main
// timeline), so its per-thread notification count — and the room's unread dot,
// which sums thread counts — would linger even after "reading" the room. Send
// a threaded receipt at the latest reply of every thread that still has unread
// counts. Also runs when the main timeline is already read (latestEvent null).
const threads = room.getThreads();
await Promise.all(
threads.map((thread) => {
const unread =
room.getThreadUnreadNotificationCount(thread.id, NotificationCountType.Total) ?? 0;
if (unread <= 0) return undefined;
const lastReply = thread.lastReply() ?? thread.rootEvent;
if (!lastReply || lastReply.isSending()) return undefined;
// Threaded receipt (unthreaded = false → the SDK scopes it to this thread).
return mx.sendReadReceipt(lastReply, receiptType, false).catch(() => undefined);
}),
2025-02-26 21:44:53 +11:00
);
2022-03-18 09:09:14 +05:30
}