diff --git a/src/app/features/room-nav/RoomNavItem.tsx b/src/app/features/room-nav/RoomNavItem.tsx index ef59bf98..ffff0f45 100644 --- a/src/app/features/room-nav/RoomNavItem.tsx +++ b/src/app/features/room-nav/RoomNavItem.tsx @@ -39,6 +39,8 @@ import { getMatrixToRoom } from '../../plugins/matrix-to'; import { getCanonicalAliasOrRoomId, isRoomAlias } from '../../utils/matrix'; import { getViaServers } from '../../plugins/via-servers'; import { useMediaAuthentication } from '../../hooks/useMediaAuthentication'; +import { useSetting } from '../../state/hooks/settings'; +import { settingsAtom } from '../../state/settings'; type RoomNavItemMenuProps = { room: Room; @@ -47,13 +49,14 @@ type RoomNavItemMenuProps = { const RoomNavItemMenu = forwardRef( ({ room, requestClose }, ref) => { const mx = useMatrixClient(); + const [hideActivity] = useSetting(settingsAtom, 'hideActivity'); const unread = useRoomUnread(room.roomId, roomToUnreadAtom); const powerLevels = usePowerLevels(room); const { getPowerLevel, canDoAction } = usePowerLevelsAPI(powerLevels); const canInvite = canDoAction('invite', getPowerLevel(mx.getUserId() ?? '')); const handleMarkAsRead = () => { - markAsRead(mx, room.roomId); + markAsRead(mx, room.roomId, hideActivity); requestClose(); }; diff --git a/src/app/features/room/Room.tsx b/src/app/features/room/Room.tsx index ee3e7027..ffc21857 100644 --- a/src/app/features/room/Room.tsx +++ b/src/app/features/room/Room.tsx @@ -20,6 +20,7 @@ export function Room() { const mx = useMatrixClient(); const [isDrawer] = useSetting(settingsAtom, 'isPeopleDrawer'); + const [hideActivity] = useSetting(settingsAtom, 'hideActivity'); const screenSize = useScreenSizeContext(); const powerLevels = usePowerLevels(room); const members = useRoomMembers(mx, room.roomId); @@ -29,10 +30,10 @@ export function Room() { useCallback( (evt) => { if (isKeyHotkey('escape', evt)) { - markAsRead(mx, room.roomId); + markAsRead(mx, room.roomId, hideActivity); } }, - [mx, room.roomId] + [mx, room.roomId, hideActivity] ) ); diff --git a/src/app/features/room/RoomInput.tsx b/src/app/features/room/RoomInput.tsx index faaba90c..97f80595 100644 --- a/src/app/features/room/RoomInput.tsx +++ b/src/app/features/room/RoomInput.tsx @@ -127,6 +127,7 @@ export const RoomInput = forwardRef( const useAuthentication = useMediaAuthentication(); const [enterForNewline] = useSetting(settingsAtom, 'enterForNewline'); const [isMarkdown] = useSetting(settingsAtom, 'isMarkdown'); + const [hideActivity] = useSetting(settingsAtom, 'hideActivity'); const commands = useCommands(mx, room); const emojiBtnRef = useRef(null); const roomToParents = useAtomValue(roomToParentsAtom); @@ -382,7 +383,9 @@ export const RoomInput = forwardRef( return; } - sendTypingStatus(!isEmptyEditor(editor)); + if (!hideActivity) { + sendTypingStatus(!isEmptyEditor(editor)); + } const prevWordRange = getPrevWorldRange(editor); const query = prevWordRange @@ -390,7 +393,7 @@ export const RoomInput = forwardRef( : undefined; setAutocompleteQuery(query); }, - [editor, sendTypingStatus] + [editor, sendTypingStatus, hideActivity] ); const handleCloseAutocomplete = useCallback(() => { diff --git a/src/app/features/room/RoomTimeline.tsx b/src/app/features/room/RoomTimeline.tsx index f6854b43..4bcdadbc 100644 --- a/src/app/features/room/RoomTimeline.tsx +++ b/src/app/features/room/RoomTimeline.tsx @@ -424,6 +424,7 @@ const getRoomUnreadInfo = (room: Room, scrollTo = false) => { export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimelineProps) { const mx = useMatrixClient(); const useAuthentication = useMediaAuthentication(); + const [hideActivity] = useSetting(settingsAtom, 'hideActivity'); const [messageLayout] = useSetting(settingsAtom, 'messageLayout'); const [messageSpacing] = useSetting(settingsAtom, 'messageSpacing'); const [hideMembershipEvents] = useSetting(settingsAtom, 'hideMembershipEvents'); @@ -589,7 +590,7 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli // Check if the document is in focus (user is actively viewing the app), // and either there are no unread messages or the latest message is from the current user. // If either condition is met, trigger the markAsRead function to send a read receipt. - requestAnimationFrame(() => markAsRead(mx, mEvt.getRoomId()!)); + requestAnimationFrame(() => markAsRead(mx, mEvt.getRoomId()!, hideActivity)); } if (!document.hasFocus() && !unreadInfo) { @@ -613,7 +614,7 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli setUnreadInfo(getRoomUnreadInfo(room)); } }, - [mx, room, unreadInfo] + [mx, room, unreadInfo, hideActivity] ) ); @@ -682,15 +683,15 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli const tryAutoMarkAsRead = useCallback(() => { const readUptoEventId = readUptoEventIdRef.current; if (!readUptoEventId) { - requestAnimationFrame(() => markAsRead(mx, room.roomId)); + requestAnimationFrame(() => markAsRead(mx, room.roomId, hideActivity)); return; } const evtTimeline = getEventTimeline(room, readUptoEventId); const latestTimeline = evtTimeline && getFirstLinkedTimeline(evtTimeline, Direction.Forward); if (latestTimeline === room.getLiveTimeline()) { - requestAnimationFrame(() => markAsRead(mx, room.roomId)); + requestAnimationFrame(() => markAsRead(mx, room.roomId, hideActivity)); } - }, [mx, room]); + }, [mx, room, hideActivity]); const debounceSetAtBottom = useDebounce( useCallback((entry: IntersectionObserverEntry) => { @@ -872,7 +873,7 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli }; const handleMarkAsRead = () => { - markAsRead(mx, room.roomId); + markAsRead(mx, room.roomId, hideActivity); }; const handleOpenReply: MouseEventHandler = useCallback( @@ -1047,6 +1048,7 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli /> ) } + hideReadReceipts={hideActivity} > {mEvent.isRedacted() ? ( @@ -1119,6 +1121,7 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli /> ) } + hideReadReceipts={hideActivity} > {() => { @@ -1215,6 +1218,7 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli /> ) } + hideReadReceipts={hideActivity} > {mEvent.isRedacted() ? ( @@ -1256,6 +1260,7 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli highlight={highlighted} messageSpacing={messageSpacing} canDelete={canRedact || mEvent.getSender() === mx.getUserId()} + hideReadReceipts={hideActivity} > { @@ -57,6 +59,8 @@ export function RoomView({ room, eventId }: { room: Room; eventId?: string }) { const roomInputRef = useRef(null); const roomViewRef = useRef(null); + const [hideActivity] = useSetting(settingsAtom, 'hideActivity'); + const { roomId } = room; const editor = useEditor(); @@ -133,7 +137,7 @@ export function RoomView({ room, eventId }: { room: Room; eventId?: string }) { )} - + {hideActivity ? : } ); diff --git a/src/app/features/room/RoomViewFollowing.css.ts b/src/app/features/room/RoomViewFollowing.css.ts index 0a0358e0..18b53ac9 100644 --- a/src/app/features/room/RoomViewFollowing.css.ts +++ b/src/app/features/room/RoomViewFollowing.css.ts @@ -1,6 +1,14 @@ +import { style } from '@vanilla-extract/css'; import { recipe } from '@vanilla-extract/recipes'; import { DefaultReset, color, config, toRem } from 'folds'; +export const RoomViewFollowingPlaceholder = style([ + DefaultReset, + { + height: toRem(28), + }, +]); + export const RoomViewFollowing = recipe({ base: [ DefaultReset, diff --git a/src/app/features/room/RoomViewFollowing.tsx b/src/app/features/room/RoomViewFollowing.tsx index 58d3f64f..5a96e6ad 100644 --- a/src/app/features/room/RoomViewFollowing.tsx +++ b/src/app/features/room/RoomViewFollowing.tsx @@ -24,6 +24,10 @@ import { useRoomEventReaders } from '../../hooks/useRoomEventReaders'; import { EventReaders } from '../../components/event-readers'; import { stopPropagation } from '../../utils/keyboard'; +export function RoomViewFollowingPlaceholder() { + return
; +} + export type RoomViewFollowingProps = { room: Room; }; diff --git a/src/app/features/room/RoomViewHeader.tsx b/src/app/features/room/RoomViewHeader.tsx index 7ee1d302..deac935e 100644 --- a/src/app/features/room/RoomViewHeader.tsx +++ b/src/app/features/room/RoomViewHeader.tsx @@ -33,7 +33,7 @@ import { RoomTopicViewer } from '../../components/room-topic-viewer'; import { StateEvent } from '../../../types/matrix/room'; import { useMatrixClient } from '../../hooks/useMatrixClient'; import { useRoom } from '../../hooks/useRoom'; -import { useSetSetting } from '../../state/hooks/settings'; +import { useSetSetting, useSetting } from '../../state/hooks/settings'; import { settingsAtom } from '../../state/settings'; import { useSpaceOptionally } from '../../hooks/useSpace'; import { getHomeSearchPath, getSpaceSearchPath, withSearchParam } from '../../pages/pathUtils'; @@ -64,13 +64,14 @@ type RoomMenuProps = { }; const RoomMenu = forwardRef(({ room, requestClose }, ref) => { const mx = useMatrixClient(); + const [hideActivity] = useSetting(settingsAtom, 'hideActivity'); const unread = useRoomUnread(room.roomId, roomToUnreadAtom); const powerLevels = usePowerLevelsContext(); const { getPowerLevel, canDoAction } = usePowerLevelsAPI(powerLevels); const canInvite = canDoAction('invite', getPowerLevel(mx.getUserId() ?? '')); const handleMarkAsRead = () => { - markAsRead(mx, room.roomId); + markAsRead(mx, room.roomId, hideActivity); requestClose(); }; diff --git a/src/app/features/room/message/Message.tsx b/src/app/features/room/message/Message.tsx index bde03eb2..d6709a97 100644 --- a/src/app/features/room/message/Message.tsx +++ b/src/app/features/room/message/Message.tsx @@ -671,6 +671,7 @@ export type MessageProps = { onReactionToggle: (targetEventId: string, key: string, shortcode?: string) => void; reply?: ReactNode; reactions?: ReactNode; + hideReadReceipts?: boolean; }; export const Message = as<'div', MessageProps>( ( @@ -695,6 +696,7 @@ export const Message = as<'div', MessageProps>( onEditId, reply, reactions, + hideReadReceipts, children, ...props }, @@ -992,11 +994,13 @@ export const Message = as<'div', MessageProps>( )} - + {!hideReadReceipts && ( + + )} {canPinEvent && ( @@ -1071,9 +1075,23 @@ export type EventProps = { highlight: boolean; canDelete?: boolean; messageSpacing: MessageSpacing; + hideReadReceipts?: boolean; }; export const Event = as<'div', EventProps>( - ({ className, room, mEvent, highlight, canDelete, messageSpacing, children, ...props }, ref) => { + ( + { + className, + room, + mEvent, + highlight, + canDelete, + messageSpacing, + hideReadReceipts, + children, + ...props + }, + ref + ) => { const mx = useMatrixClient(); const [hover, setHover] = useState(false); const { hoverProps } = useHover({ onHoverChange: setHover }); @@ -1138,11 +1156,13 @@ export const Event = as<'div', EventProps>( > - + {!hideReadReceipts && ( + + )} diff --git a/src/app/features/settings/general/General.tsx b/src/app/features/settings/general/General.tsx index d58c99ca..569cd410 100644 --- a/src/app/features/settings/general/General.tsx +++ b/src/app/features/settings/general/General.tsx @@ -344,6 +344,7 @@ function Appearance() { function Editor() { const [enterForNewline, setEnterForNewline] = useSetting(settingsAtom, 'enterForNewline'); const [isMarkdown, setIsMarkdown] = useSetting(settingsAtom, 'isMarkdown'); + const [hideActivity, setHideActivity] = useSetting(settingsAtom, 'hideActivity'); return ( @@ -363,6 +364,13 @@ function Editor() { after={} /> + + } + /> + ); } @@ -555,7 +563,13 @@ function Messages() { setMediaAutoLoad(!v)} />} + after={ + setMediaAutoLoad(!v)} + /> + } /> diff --git a/src/app/pages/client/direct/Direct.tsx b/src/app/pages/client/direct/Direct.tsx index cd19e33e..5e799214 100644 --- a/src/app/pages/client/direct/Direct.tsx +++ b/src/app/pages/client/direct/Direct.tsx @@ -45,18 +45,21 @@ import { useClosedNavCategoriesAtom } from '../../../state/hooks/closedNavCatego import { useRoomsUnread } from '../../../state/hooks/unread'; import { markAsRead } from '../../../../client/action/notifications'; import { stopPropagation } from '../../../utils/keyboard'; +import { useSetting } from '../../../state/hooks/settings'; +import { settingsAtom } from '../../../state/settings'; type DirectMenuProps = { requestClose: () => void; }; const DirectMenu = forwardRef(({ requestClose }, ref) => { const mx = useMatrixClient(); + const [hideActivity] = useSetting(settingsAtom, 'hideActivity'); const orphanRooms = useDirectRooms(); const unread = useRoomsUnread(orphanRooms, roomToUnreadAtom); const handleMarkAsRead = () => { if (!unread) return; - orphanRooms.forEach((rId) => markAsRead(mx, rId)); + orphanRooms.forEach((rId) => markAsRead(mx, rId, hideActivity)); requestClose(); }; diff --git a/src/app/pages/client/home/Home.tsx b/src/app/pages/client/home/Home.tsx index f9923f46..fa5e68ab 100644 --- a/src/app/pages/client/home/Home.tsx +++ b/src/app/pages/client/home/Home.tsx @@ -48,18 +48,21 @@ import { useRoomsUnread } from '../../../state/hooks/unread'; import { markAsRead } from '../../../../client/action/notifications'; import { useClosedNavCategoriesAtom } from '../../../state/hooks/closedNavCategories'; import { stopPropagation } from '../../../utils/keyboard'; +import { useSetting } from '../../../state/hooks/settings'; +import { settingsAtom } from '../../../state/settings'; type HomeMenuProps = { requestClose: () => void; }; const HomeMenu = forwardRef(({ requestClose }, ref) => { const orphanRooms = useHomeRooms(); + const [hideActivity] = useSetting(settingsAtom, 'hideActivity'); const unread = useRoomsUnread(orphanRooms, roomToUnreadAtom); const mx = useMatrixClient(); const handleMarkAsRead = () => { if (!unread) return; - orphanRooms.forEach((rId) => markAsRead(mx, rId)); + orphanRooms.forEach((rId) => markAsRead(mx, rId, hideActivity)); requestClose(); }; diff --git a/src/app/pages/client/inbox/Notifications.tsx b/src/app/pages/client/inbox/Notifications.tsx index 0c832b09..722ce5d3 100644 --- a/src/app/pages/client/inbox/Notifications.tsx +++ b/src/app/pages/client/inbox/Notifications.tsx @@ -182,6 +182,7 @@ type RoomNotificationsGroupProps = { notifications: INotification[]; mediaAutoLoad?: boolean; urlPreview?: boolean; + hideActivity: boolean; onOpen: (roomId: string, eventId: string) => void; }; function RoomNotificationsGroupComp({ @@ -189,6 +190,7 @@ function RoomNotificationsGroupComp({ notifications, mediaAutoLoad, urlPreview, + hideActivity, onOpen, }: RoomNotificationsGroupProps) { const mx = useMatrixClient(); @@ -362,7 +364,7 @@ function RoomNotificationsGroupComp({ onOpen(room.roomId, eventId); }; const handleMarkAsRead = () => { - markAsRead(mx, room.roomId); + markAsRead(mx, room.roomId, hideActivity); }; return ( @@ -496,6 +498,7 @@ const DEFAULT_REFRESH_MS = 7000; export function Notifications() { const mx = useMatrixClient(); + const [hideActivity] = useSetting(settingsAtom, 'hideActivity'); const [mediaAutoLoad] = useSetting(settingsAtom, 'mediaAutoLoad'); const [urlPreview] = useSetting(settingsAtom, 'urlPreview'); const screenSize = useScreenSizeContext(); @@ -656,6 +659,7 @@ export function Notifications() { notifications={group.notifications} mediaAutoLoad={mediaAutoLoad} urlPreview={urlPreview} + hideActivity={hideActivity} onOpen={navigateRoom} /> diff --git a/src/app/pages/client/sidebar/DirectTab.tsx b/src/app/pages/client/sidebar/DirectTab.tsx index 849fc365..bd8090d3 100644 --- a/src/app/pages/client/sidebar/DirectTab.tsx +++ b/src/app/pages/client/sidebar/DirectTab.tsx @@ -23,18 +23,21 @@ import { useNavToActivePathAtom } from '../../../state/hooks/navToActivePath'; import { useDirectRooms } from '../direct/useDirectRooms'; import { markAsRead } from '../../../../client/action/notifications'; import { stopPropagation } from '../../../utils/keyboard'; +import { settingsAtom } from '../../../state/settings'; +import { useSetting } from '../../../state/hooks/settings'; type DirectMenuProps = { requestClose: () => void; }; const DirectMenu = forwardRef(({ requestClose }, ref) => { const orphanRooms = useDirectRooms(); + const [hideActivity] = useSetting(settingsAtom, 'hideActivity'); const unread = useRoomsUnread(orphanRooms, roomToUnreadAtom); const mx = useMatrixClient(); const handleMarkAsRead = () => { if (!unread) return; - orphanRooms.forEach((rId) => markAsRead(mx, rId)); + orphanRooms.forEach((rId) => markAsRead(mx, rId, hideActivity)); requestClose(); }; diff --git a/src/app/pages/client/sidebar/HomeTab.tsx b/src/app/pages/client/sidebar/HomeTab.tsx index dcb0a498..c8a80280 100644 --- a/src/app/pages/client/sidebar/HomeTab.tsx +++ b/src/app/pages/client/sidebar/HomeTab.tsx @@ -24,18 +24,21 @@ import { useNavToActivePathAtom } from '../../../state/hooks/navToActivePath'; import { useHomeRooms } from '../home/useHomeRooms'; import { markAsRead } from '../../../../client/action/notifications'; import { stopPropagation } from '../../../utils/keyboard'; +import { useSetting } from '../../../state/hooks/settings'; +import { settingsAtom } from '../../../state/settings'; type HomeMenuProps = { requestClose: () => void; }; const HomeMenu = forwardRef(({ requestClose }, ref) => { const orphanRooms = useHomeRooms(); + const [hideActivity] = useSetting(settingsAtom, 'hideActivity'); const unread = useRoomsUnread(orphanRooms, roomToUnreadAtom); const mx = useMatrixClient(); const handleMarkAsRead = () => { if (!unread) return; - orphanRooms.forEach((rId) => markAsRead(mx, rId)); + orphanRooms.forEach((rId) => markAsRead(mx, rId, hideActivity)); requestClose(); }; diff --git a/src/app/pages/client/sidebar/SpaceTabs.tsx b/src/app/pages/client/sidebar/SpaceTabs.tsx index 343afae4..96e3b9ad 100644 --- a/src/app/pages/client/sidebar/SpaceTabs.tsx +++ b/src/app/pages/client/sidebar/SpaceTabs.tsx @@ -88,6 +88,8 @@ import { getMatrixToRoom } from '../../../plugins/matrix-to'; import { getViaServers } from '../../../plugins/via-servers'; import { getRoomAvatarUrl } from '../../../utils/room'; import { useMediaAuthentication } from '../../../hooks/useMediaAuthentication'; +import { useSetting } from '../../../state/hooks/settings'; +import { settingsAtom } from '../../../state/settings'; type SpaceMenuProps = { room: Room; @@ -97,6 +99,7 @@ type SpaceMenuProps = { const SpaceMenu = forwardRef( ({ room, requestClose, onUnpin }, ref) => { const mx = useMatrixClient(); + const [hideActivity] = useSetting(settingsAtom, 'hideActivity'); const roomToParents = useAtomValue(roomToParentsAtom); const powerLevels = usePowerLevels(room); const { getPowerLevel, canDoAction } = usePowerLevelsAPI(powerLevels); @@ -110,7 +113,7 @@ const SpaceMenu = forwardRef( const unread = useRoomsUnread(allChild, roomToUnreadAtom); const handleMarkAsRead = () => { - allChild.forEach((childRoomId) => markAsRead(mx, childRoomId)); + allChild.forEach((childRoomId) => markAsRead(mx, childRoomId, hideActivity)); requestClose(); }; @@ -227,18 +230,18 @@ const useDraggableItem = ( return !target ? undefined : draggable({ - element: target, - dragHandle, - getInitialData: () => ({ item }), - onDragStart: () => { - setDragging(true); - onDragging?.(item); - }, - onDrop: () => { - setDragging(false); - onDragging?.(undefined); - }, - }); + element: target, + dragHandle, + getInitialData: () => ({ item }), + onDragStart: () => { + setDragging(true); + onDragging?.(item); + }, + onDrop: () => { + setDragging(false); + onDragging?.(undefined); + }, + }); }, [targetRef, dragHandleRef, item, onDragging]); return dragging; @@ -388,9 +391,9 @@ function SpaceTab({ () => folder ? { - folder, - spaceId: space.roomId, - } + folder, + spaceId: space.roomId, + } : space.roomId, [folder, space] ); diff --git a/src/app/pages/client/space/Space.tsx b/src/app/pages/client/space/Space.tsx index c8e2b783..1714d8ee 100644 --- a/src/app/pages/client/space/Space.tsx +++ b/src/app/pages/client/space/Space.tsx @@ -69,6 +69,8 @@ import { StateEvent } from '../../../../types/matrix/room'; import { stopPropagation } from '../../../utils/keyboard'; import { getMatrixToRoom } from '../../../plugins/matrix-to'; import { getViaServers } from '../../../plugins/via-servers'; +import { useSetting } from '../../../state/hooks/settings'; +import { settingsAtom } from '../../../state/settings'; type SpaceMenuProps = { room: Room; @@ -76,6 +78,7 @@ type SpaceMenuProps = { }; const SpaceMenu = forwardRef(({ room, requestClose }, ref) => { const mx = useMatrixClient(); + const [hideActivity] = useSetting(settingsAtom, 'hideActivity'); const roomToParents = useAtomValue(roomToParentsAtom); const powerLevels = usePowerLevels(room); const { getPowerLevel, canDoAction } = usePowerLevelsAPI(powerLevels); @@ -89,7 +92,7 @@ const SpaceMenu = forwardRef(({ room, requestClo const unread = useRoomsUnread(allChild, roomToUnreadAtom); const handleMarkAsRead = () => { - allChild.forEach((childRoomId) => markAsRead(mx, childRoomId)); + allChild.forEach((childRoomId) => markAsRead(mx, childRoomId, hideActivity)); requestClose(); }; diff --git a/src/app/state/room/roomToUnread.ts b/src/app/state/room/roomToUnread.ts index 8cb9d958..bf99fe34 100644 --- a/src/app/state/room/roomToUnread.ts +++ b/src/app/state/room/roomToUnread.ts @@ -228,20 +228,18 @@ export const useBindRoomToUnreadAtom = ( useEffect(() => { const handleReceipt = (mEvent: MatrixEvent, room: Room) => { - if (mEvent.getType() === 'm.receipt') { - const myUserId = mx.getUserId(); - if (!myUserId) return; - if (room.isSpaceRoom()) return; - const content = mEvent.getContent(); + const myUserId = mx.getUserId(); + if (!myUserId) return; + if (room.isSpaceRoom()) return; + const content = mEvent.getContent(); - const isMyReceipt = Object.keys(content).find((eventId) => - (Object.keys(content[eventId]) as ReceiptType[]).find( - (receiptType) => content[eventId][receiptType][myUserId] - ) - ); - if (isMyReceipt) { - setUnreadAtom({ type: 'DELETE', roomId: room.roomId }); - } + const isMyReceipt = Object.keys(content).find((eventId) => + (Object.keys(content[eventId]) as ReceiptType[]).find( + (receiptType) => content[eventId][receiptType][myUserId] + ) + ); + if (isMyReceipt) { + setUnreadAtom({ type: 'DELETE', roomId: room.roomId }); } }; mx.on(RoomEvent.Receipt, handleReceipt); diff --git a/src/app/state/settings.ts b/src/app/state/settings.ts index ac47e78b..9d979195 100644 --- a/src/app/state/settings.ts +++ b/src/app/state/settings.ts @@ -17,6 +17,7 @@ export interface Settings { editorToolbar: boolean; twitterEmoji: boolean; pageZoom: number; + hideActivity: boolean; isPeopleDrawer: boolean; memberSortFilterIndex: number; @@ -45,6 +46,7 @@ const defaultSettings: Settings = { editorToolbar: false, twitterEmoji: false, pageZoom: 100, + hideActivity: false, isPeopleDrawer: true, memberSortFilterIndex: 0, diff --git a/src/app/state/typingMembers.ts b/src/app/state/typingMembers.ts index 55bf8f62..e94ba972 100644 --- a/src/app/state/typingMembers.ts +++ b/src/app/state/typingMembers.ts @@ -2,6 +2,8 @@ import produce from 'immer'; import { atom, useSetAtom } from 'jotai'; import { MatrixClient, RoomMemberEvent, RoomMemberEventHandlerMap } from 'matrix-js-sdk'; import { useEffect } from 'react'; +import { useSetting } from './hooks/settings'; +import { settingsAtom } from './settings'; export const TYPING_TIMEOUT_MS = 5000; // 5 seconds @@ -127,12 +129,16 @@ export const useBindRoomIdToTypingMembersAtom = ( typingMembersAtom: typeof roomIdToTypingMembersAtom ) => { const setTypingMembers = useSetAtom(typingMembersAtom); + const [hideActivity] = useSetting(settingsAtom, 'hideActivity'); useEffect(() => { const handleTypingEvent: RoomMemberEventHandlerMap[RoomMemberEvent.Typing] = ( event, member ) => { + if (hideActivity) { + return; + } setTypingMembers({ type: member.typing ? 'PUT' : 'DELETE', roomId: member.roomId, @@ -145,5 +151,5 @@ export const useBindRoomIdToTypingMembersAtom = ( return () => { mx.removeListener(RoomMemberEvent.Typing, handleTypingEvent); }; - }, [mx, setTypingMembers]); + }, [mx, setTypingMembers, hideActivity]); }; diff --git a/src/client/action/notifications.ts b/src/client/action/notifications.ts index 17ea1ed6..a23bd1a4 100644 --- a/src/client/action/notifications.ts +++ b/src/client/action/notifications.ts @@ -1,6 +1,6 @@ -import { MatrixClient } from "matrix-js-sdk"; +import { MatrixClient, ReceiptType } from 'matrix-js-sdk'; -export async function markAsRead(mx: MatrixClient, roomId: string) { +export async function markAsRead(mx: MatrixClient, roomId: string, privateReceipt: boolean) { const room = mx.getRoom(roomId); if (!room) return; @@ -19,5 +19,8 @@ export async function markAsRead(mx: MatrixClient, roomId: string) { const latestEvent = getLatestValidEvent(); if (latestEvent === null) return; - await mx.sendReadReceipt(latestEvent); + await mx.sendReadReceipt( + latestEvent, + privateReceipt ? ReceiptType.ReadPrivate : ReceiptType.Read + ); }