Hide existing messages from ignored users (#2236)
authorAjay Bura <32841439+ajbura@users.noreply.github.com>
Fri, 28 Feb 2025 07:47:23 +0000 (18:47 +1100)
committerGitHub <noreply@github.com>
Fri, 28 Feb 2025 07:47:23 +0000 (18:47 +1100)
* add ignored users hook

* remove messages from timeline for ignored users

src/app/features/room/RoomTimeline.tsx
src/app/features/settings/notifications/IgnoredUserList.tsx
src/app/hooks/useIgnoredUsers.ts [new file with mode: 0644]

index 4bcdadbc321045bd159a936d1757569b2db1c773..c9da6e2e042bd13efca9a9350fc67d18a21079c4 100644 (file)
@@ -117,6 +117,7 @@ import { useMentionClickHandler } from '../../hooks/useMentionClickHandler';
 import { useSpoilerClickHandler } from '../../hooks/useSpoilerClickHandler';
 import { useRoomNavigate } from '../../hooks/useRoomNavigate';
 import { useMediaAuthentication } from '../../hooks/useMediaAuthentication';
+import { useIgnoredUsers } from '../../hooks/useIgnoredUsers';
 
 const TimelineFloat = as<'div', css.TimelineFloatVariants>(
   ({ position, className, ...props }, ref) => (
@@ -434,6 +435,10 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli
   const [encUrlPreview] = useSetting(settingsAtom, 'encUrlPreview');
   const showUrlPreview = room.hasEncryptionStateEvent() ? encUrlPreview : urlPreview;
   const [showHiddenEvents] = useSetting(settingsAtom, 'showHiddenEvents');
+
+  const ignoredUsersList = useIgnoredUsers();
+  const ignoredUsersSet = useMemo(() => new Set(ignoredUsersList), [ignoredUsersList]);
+
   const setReplyDraft = useSetAtom(roomIdToReplyDraftAtomFamily(room.roomId));
   const powerLevels = usePowerLevelsContext();
   const { canDoAction, canSendEvent, canSendStateEvent, getPowerLevel } =
@@ -1488,6 +1493,11 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli
 
     if (!mEvent || !mEventId) return null;
 
+    const eventSender = mEvent.getSender();
+    if (eventSender && ignoredUsersSet.has(eventSender)) {
+      return null;
+    }
+
     if (!newDivider && readUptoEventIdRef.current) {
       newDivider = prevEvent?.getId() === readUptoEventIdRef.current;
     }
@@ -1498,9 +1508,9 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli
     const collapsed =
       isPrevRendered &&
       !dayDivider &&
-      (!newDivider || mEvent.getSender() === mx.getUserId()) &&
+      (!newDivider || eventSender === mx.getUserId()) &&
       prevEvent !== undefined &&
-      prevEvent.getSender() === mEvent.getSender() &&
+      prevEvent.getSender() === eventSender &&
       prevEvent.getType() === mEvent.getType() &&
       minuteDifference(prevEvent.getTs(), mEvent.getTs()) < 2;
 
@@ -1519,7 +1529,7 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli
     isPrevRendered = !!eventJSX;
 
     const newDividerJSX =
-      newDivider && eventJSX && mEvent.getSender() !== mx.getUserId() ? (
+      newDivider && eventJSX && eventSender !== mx.getUserId() ? (
         <MessageBase space={messageSpacing}>
           <TimelineDivider style={{ color: color.Success.Main }} variant="Inherit">
             <Badge as="span" size="500" variant="Success" fill="Solid" radii="300">
index 49264e5720835ec71a7908aae093a5c85ad46dd9..0ff3015faca38b4aea9f807c3723c3db65f7be3f 100644 (file)
@@ -1,17 +1,12 @@
-import React, { ChangeEventHandler, FormEventHandler, useCallback, useMemo, useState } from 'react';
+import React, { ChangeEventHandler, FormEventHandler, useCallback, useState } from 'react';
 import { Box, Button, Chip, Icon, IconButton, Icons, Input, Spinner, Text, config } from 'folds';
-import { useAccountData } from '../../../hooks/useAccountData';
-import { AccountDataEvent } from '../../../../types/matrix/accountData';
 import { SequenceCard } from '../../../components/sequence-card';
 import { SequenceCardStyle } from '../styles.css';
 import { SettingTile } from '../../../components/setting-tile';
 import { useMatrixClient } from '../../../hooks/useMatrixClient';
 import { AsyncStatus, useAsyncCallback } from '../../../hooks/useAsyncCallback';
 import { isUserId } from '../../../utils/matrix';
-
-type IgnoredUserListContent = {
-  ignored_users?: Record<string, object>;
-};
+import { useIgnoredUsers } from '../../../hooks/useIgnoredUsers';
 
 function IgnoreUserInput({ userList }: { userList: string[] }) {
   const mx = useMatrixClient();
@@ -129,12 +124,7 @@ function IgnoredUserChip({ userId, userList }: { userId: string; userList: strin
 }
 
 export function IgnoredUserList() {
-  const ignoredUserListEvt = useAccountData(AccountDataEvent.IgnoredUserList);
-  const ignoredUsers = useMemo(() => {
-    const ignoredUsersRecord =
-      ignoredUserListEvt?.getContent<IgnoredUserListContent>().ignored_users ?? {};
-    return Object.keys(ignoredUsersRecord);
-  }, [ignoredUserListEvt]);
+  const ignoredUsers = useIgnoredUsers();
 
   return (
     <Box direction="Column" gap="100">
diff --git a/src/app/hooks/useIgnoredUsers.ts b/src/app/hooks/useIgnoredUsers.ts
new file mode 100644 (file)
index 0000000..baf2327
--- /dev/null
@@ -0,0 +1,18 @@
+import { useMemo } from 'react';
+import { useAccountData } from './useAccountData';
+import { AccountDataEvent } from '../../types/matrix/accountData';
+
+export type IgnoredUserListContent = {
+  ignored_users?: Record<string, object>;
+};
+
+export const useIgnoredUsers = (): string[] => {
+  const ignoredUserListEvt = useAccountData(AccountDataEvent.IgnoredUserList);
+  const ignoredUsers = useMemo(() => {
+    const ignoredUsersRecord =
+      ignoredUserListEvt?.getContent<IgnoredUserListContent>().ignored_users ?? {};
+    return Object.keys(ignoredUsersRecord);
+  }, [ignoredUserListEvt]);
+
+  return ignoredUsers;
+};