* Experimental SSS Working branch to get SSS functional on element-web. Requires https://github.com/matrix-org/matrix-js-sdk/pull/4400 * Adjust tests to use new behaviour * Remove well-known proxy URL lookup; always use native This is actually required for SSS because otherwise it would use the proxy over native support. * Linting * Debug logging * Control the race condition when swapping between rooms * Dont' filter by space as synapse doesn't support it * Remove SS code related to registering lists and managing ranges - Update the spidering code to spider all the relevant lists. - Add canonical alias to the required_state to allow room name calcs to work. Room sort order is busted because we don't yet look at `bump_stamp`. * User bumpStamp if it is present * Drop initial room load from 20 per list to 10 * Half the batch size to trickle more quickly * Prettier * prettier on tests too * Remove proxy URL & unused import * Hopefully fix tests to assert what the behaviour is supposed to be * Move the singleton to the manager tyo fix import loop * Very well, code, I will remove you Why were you there in the first place? * Strip out more unused stuff * Fix playwright test Seems like this lack of order updating unless a room is selected was just always a bug with both regular and non-sliding sync. I have no idea how the test passed on develop because it won't run. * Fix test to do maybe what it was supposed to do... possibly? * Remove test for old pre-simplified sliding sync behaviour * Unused import * Remove sliding sync proxy & test I was wrong about what this test was asserting, it was suposed to assert that notification dots aren't shown (because SS didn't support them somehow I guess) but they are fine in SSS so the test is just no longer relevant. * Remove now pointless credentials * Remove subscription removal as SSS doesn't do that * Update tests * add test * Switch to new labs flag & break if old labs flag is enabled * Remove unused import & fix test * Fix other test * Remove name & description from old labs flag as they're not displayed anywhere so not useful * Remove old sliding sync option by making it not a feature * Add back unread nindicator test but inverted and minus the bit about disabling notification which surely would have defeated the original point anyway? * Reinstate test for room_subscriptions ...and also make tests actually use sliding sync * Use UserFriendlyError * Remove empty constructor * Remove unrelated changes * Unused import * Fix import * Avoid moving import --------- Co-authored-by: Kegan Dougal <7190048+kegsay@users.noreply.github.com>
146 lines
5.4 KiB
TypeScript
146 lines
5.4 KiB
TypeScript
/*
|
|
Copyright 2024 New Vector Ltd.
|
|
Copyright 2015-2023 The Matrix.org Foundation C.I.C.
|
|
|
|
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
|
|
Please see LICENSE files in the repository root for full details.
|
|
*/
|
|
|
|
import { M_BEACON, type Room, Thread, type MatrixEvent, EventType, type MatrixClient } from "matrix-js-sdk/src/matrix";
|
|
import { logger } from "matrix-js-sdk/src/logger";
|
|
|
|
import shouldHideEvent from "./shouldHideEvent";
|
|
import { haveRendererForEvent } from "./events/EventTileFactory";
|
|
import { RoomNotifState, getRoomNotifsState } from "./RoomNotifs";
|
|
|
|
/**
|
|
* Returns true if this event arriving in a room should affect the room's
|
|
* count of unread messages
|
|
*
|
|
* @param client The Matrix Client instance of the logged-in user
|
|
* @param {Object} ev The event
|
|
* @returns {boolean} True if the given event should affect the unread message count
|
|
*/
|
|
export function eventTriggersUnreadCount(client: MatrixClient, ev: MatrixEvent): boolean {
|
|
if (ev.getSender() === client.getSafeUserId()) {
|
|
return false;
|
|
}
|
|
|
|
switch (ev.getType()) {
|
|
case EventType.RoomMember:
|
|
case EventType.RoomThirdPartyInvite:
|
|
case EventType.CallAnswer:
|
|
case EventType.CallHangup:
|
|
case EventType.RoomCanonicalAlias:
|
|
case EventType.RoomServerAcl:
|
|
case M_BEACON.name:
|
|
case M_BEACON.altName:
|
|
return false;
|
|
}
|
|
|
|
if (ev.isRedacted()) return false;
|
|
return haveRendererForEvent(ev, client, false /* hidden messages should never trigger unread counts anyways */);
|
|
}
|
|
|
|
export function doesRoomHaveUnreadMessages(room: Room, includeThreads: boolean): boolean {
|
|
const toCheck: Array<Room | Thread> = [room];
|
|
if (includeThreads) {
|
|
toCheck.push(...room.getThreads());
|
|
}
|
|
|
|
for (const withTimeline of toCheck) {
|
|
if (doesTimelineHaveUnreadMessages(room, withTimeline.timeline)) {
|
|
// We found an unread, so the room is unread
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// If we got here then no timelines were found with unread messages.
|
|
return false;
|
|
}
|
|
|
|
function doesTimelineHaveUnreadMessages(room: Room, timeline: Array<MatrixEvent>): boolean {
|
|
// The room is a space, let's ignore it
|
|
if (room.isSpaceRoom()) return false;
|
|
|
|
const myUserId = room.client.getSafeUserId();
|
|
const latestImportantEventId = findLatestImportantEvent(room.client, timeline)?.getId();
|
|
if (latestImportantEventId) {
|
|
return !room.hasUserReadEvent(myUserId, latestImportantEventId);
|
|
} else {
|
|
// We couldn't find an important event to check - check the unimportant ones.
|
|
const earliestUnimportantEventId = timeline.at(0)?.getId();
|
|
if (!earliestUnimportantEventId) {
|
|
// There are no events in this timeline - it is uninitialised, so we
|
|
// consider it read
|
|
return false;
|
|
} else if (room.hasUserReadEvent(myUserId, earliestUnimportantEventId)) {
|
|
// Some of the unimportant events are read, and there are no
|
|
// important ones after them, so we've read everything.
|
|
return false;
|
|
} else {
|
|
// We have events. and none of them are read. We must guess that
|
|
// the timeline is unread, because there could be older unread
|
|
// important events that we don't have loaded.
|
|
logger.warn("Falling back to unread room because of no read receipt or counting message found", {
|
|
roomId: room.roomId,
|
|
earliestUnimportantEventId: earliestUnimportantEventId,
|
|
});
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns true if this room has unread threads.
|
|
* @param room The room to check
|
|
* @returns {boolean} True if the given room has unread threads
|
|
*/
|
|
export function doesRoomHaveUnreadThreads(room: Room): boolean {
|
|
if (getRoomNotifsState(room.client, room.roomId) === RoomNotifState.Mute) {
|
|
// No unread for muted rooms, nor their threads
|
|
// NB. This logic duplicated in RoomNotifs.determineUnreadState
|
|
return false;
|
|
}
|
|
|
|
for (const thread of room.getThreads()) {
|
|
if (doesTimelineHaveUnreadMessages(room, thread.timeline)) {
|
|
// We found an unread, so the room has an unread thread
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// If we got here then no threads were found with unread messages.
|
|
return false;
|
|
}
|
|
|
|
export function doesRoomOrThreadHaveUnreadMessages(roomOrThread: Room | Thread): boolean {
|
|
const room = roomOrThread instanceof Thread ? roomOrThread.room : roomOrThread;
|
|
const events = roomOrThread instanceof Thread ? roomOrThread.timeline : room.getLiveTimeline().getEvents();
|
|
return doesTimelineHaveUnreadMessages(room, events);
|
|
}
|
|
|
|
/**
|
|
* Look backwards through the timeline and find the last event that is
|
|
* "important" in the sense of isImportantEvent.
|
|
*
|
|
* @returns the latest important event, or null if none were found
|
|
*/
|
|
function findLatestImportantEvent(client: MatrixClient, timeline: Array<MatrixEvent>): MatrixEvent | null {
|
|
for (let index = timeline.length - 1; index >= 0; index--) {
|
|
const event = timeline[index];
|
|
if (isImportantEvent(client, event)) {
|
|
return event;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Given this event does not have a receipt, is it important enough to make
|
|
* this room unread?
|
|
*/
|
|
function isImportantEvent(client: MatrixClient, event: MatrixEvent): boolean {
|
|
return !shouldHideEvent(event) && eventTriggersUnreadCount(client, event);
|
|
}
|