Pop out of Threads Activity Centre (#12136)
* Add `Thread Activity centre` labs flag * Rename translation string * WIP Thread Activity Centre * Update supportedLevels * css lint * i18n lint * Fix labs subsection test * Update Threads Activity Centre label * Rename Thread Activity Centre to Threads Activity Centre * Use compound `MenuItem` instead of custom button * Color thread icon when hovered * Make the pop-up scrollable and add a max height * Remove Math.random in key * Remove unused class * Change add comments on `mx_ThreadsActivityRows` and `mx_ThreadsActivityRow` * Make threads activity centre labs flag split out unread counts Just shows notif & unread counts for main thread if the TAC is enabled. * Fix tests * Simpler fix * Open thread panel when thread clicke in Threads Activity Centre Hopefully this is a sensible enough way. The panel will stay open of course (ie. if you go to a different room & come back), but that's the nature of the right panel. * Dynamic state of room * Add doc * Use the StatelessNotificationBadge component in ThreadsActivityCentre and re-use the existing NotificationLevel * Remove unused style * Add room sorting * Fix `ThreadsActivityRow` props doc * Pass in & cache the status of the TAC labs flag * Pass includeThreads as setting to doesRoomHaveUnreadMessages too * Fix tests * Add analytics to the TAC (#12179) * Update TAC label (#12186) * Add `IndicatorIcon` to the TAC button (#12182) Add `IndicatorIcon` to the TAC button * Threads don't have activity if the room is muted This makes it match the computation in determineUnreadState. Ideally this logic should all be in one place. * Re-use doesRoomHaveUnreadThreads for useRoomThreadNotifications This incorporates the logic of not showing unread dots if the room is muted * Add TAC description in labs (#12197) * Fox position & size of dot on the tac button IndicatorIcon doesn't like having the size of its icon adjusted and we probably shouldn't do it anyway: better to specify to the component what size we want it. * TAC: Utils tests (#12200) * Add tests for `doesRoomHaveUnreadThreads` * Add tests for `getThreadNotificationLevel` * Add test for the ThreadsActivityCentre component * Add snapshot test * Fix narrow hover background on TAC button Make the button 32x32 (and the inner icon 24x24) * Add caption for empty TAC * s/tac/threads_activity_centre/ * Fix i18n & add tests * Add playwright tests for the TAC (#12227) * Fox comments --------- Co-authored-by: David Baker <dbkr@users.noreply.github.com>
This commit is contained in:
parent
3052025dd0
commit
a4987060b7
24 changed files with 1455 additions and 14 deletions
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
*
|
||||
* Copyright 2024 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* /
|
||||
*/
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { ClientEvent, MatrixClient, Room } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import { doesRoomHaveUnreadThreads } from "../../../../Unread";
|
||||
import { NotificationLevel } from "../../../../stores/notifications/NotificationLevel";
|
||||
import { getThreadNotificationLevel } from "../../../../utils/notifications";
|
||||
import { useSettingValue } from "../../../../hooks/useSettings";
|
||||
import { useMatrixClientContext } from "../../../../contexts/MatrixClientContext";
|
||||
import { useEventEmitter } from "../../../../hooks/useEventEmitter";
|
||||
import { VisibilityProvider } from "../../../../stores/room-list/filters/VisibilityProvider";
|
||||
|
||||
type Result = {
|
||||
greatestNotificationLevel: NotificationLevel;
|
||||
rooms: Array<{ room: Room; notificationLevel: NotificationLevel }>;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the greatest notification level of all thread, the list of rooms with unread threads, and their notification level.
|
||||
* The result is computed when the client syncs, or when forceComputation is true
|
||||
* @param forceComputation
|
||||
* @returns {Result}
|
||||
*/
|
||||
export function useUnreadThreadRooms(forceComputation: boolean): Result {
|
||||
const msc3946ProcessDynamicPredecessor = useSettingValue<boolean>("feature_dynamic_room_predecessors");
|
||||
const mxClient = useMatrixClientContext();
|
||||
|
||||
const [result, setResult] = useState<Result>({ greatestNotificationLevel: NotificationLevel.None, rooms: [] });
|
||||
|
||||
// Listen to sync events to update the result
|
||||
useEventEmitter(mxClient, ClientEvent.Sync, () => {
|
||||
setResult(computeUnreadThreadRooms(mxClient, msc3946ProcessDynamicPredecessor));
|
||||
});
|
||||
|
||||
// Force the list computation
|
||||
useEffect(() => {
|
||||
if (forceComputation) {
|
||||
setResult(computeUnreadThreadRooms(mxClient, msc3946ProcessDynamicPredecessor));
|
||||
}
|
||||
}, [mxClient, msc3946ProcessDynamicPredecessor, forceComputation]);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the greatest notification level of all thread, the list of rooms with unread threads, and their notification level.
|
||||
* @param mxClient - MatrixClient
|
||||
* @param msc3946ProcessDynamicPredecessor
|
||||
*/
|
||||
function computeUnreadThreadRooms(mxClient: MatrixClient, msc3946ProcessDynamicPredecessor: boolean): Result {
|
||||
// Only count visible rooms to not torment the user with notification counts in rooms they can't see.
|
||||
// This will include highlights from the previous version of the room internally
|
||||
const visibleRooms = mxClient.getVisibleRooms(msc3946ProcessDynamicPredecessor);
|
||||
|
||||
let greatestNotificationLevel = NotificationLevel.None;
|
||||
const rooms = [];
|
||||
|
||||
for (const room of visibleRooms) {
|
||||
// We only care about rooms with unread threads
|
||||
if (VisibilityProvider.instance.isRoomVisible(room) && doesRoomHaveUnreadThreads(room)) {
|
||||
// Get the greatest notification level of all rooms
|
||||
const notificationLevel = getThreadNotificationLevel(room);
|
||||
if (notificationLevel > greatestNotificationLevel) {
|
||||
greatestNotificationLevel = notificationLevel;
|
||||
}
|
||||
|
||||
rooms.push({ room, notificationLevel });
|
||||
}
|
||||
}
|
||||
|
||||
const sortedRooms = rooms.sort((a, b) => sortRoom(a.notificationLevel, b.notificationLevel));
|
||||
return { greatestNotificationLevel, rooms: sortedRooms };
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort notification level by the most important notification level to the least important
|
||||
* Highlight > Notification > Activity
|
||||
* @param notificationLevelA - notification level of room A
|
||||
* @param notificationLevelB - notification level of room B
|
||||
* @returns {number}
|
||||
*/
|
||||
function sortRoom(notificationLevelA: NotificationLevel, notificationLevelB: NotificationLevel): number {
|
||||
// NotificationLevel is a numeric enum, so we can compare them directly
|
||||
if (notificationLevelA > notificationLevelB) return -1;
|
||||
else if (notificationLevelB > notificationLevelA) return 1;
|
||||
else return 0;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue