mirror of
				https://github.com/cinnyapp/cinny.git
				synced 2025-11-04 06:20:28 +03:00 
			
		
		
		
	Hidden Typing & Read Receipts (#2230)
* add hide activity toggle * stop sending/receiving typing status * send private read receipt when setting toggle is activated * prevent showing read-receipt when feature toggle in on
This commit is contained in:
		
							parent
							
								
									5c94471956
								
							
						
					
					
						commit
						b7e5e0db3e
					
				
					 21 changed files with 165 additions and 66 deletions
				
			
		| 
						 | 
				
			
			@ -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<HTMLDivElement, RoomNavItemMenuProps>(
 | 
			
		||||
  ({ 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();
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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]
 | 
			
		||||
    )
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -127,6 +127,7 @@ export const RoomInput = forwardRef<HTMLDivElement, RoomInputProps>(
 | 
			
		|||
    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<HTMLButtonElement>(null);
 | 
			
		||||
    const roomToParents = useAtomValue(roomToParentsAtom);
 | 
			
		||||
| 
						 | 
				
			
			@ -382,7 +383,9 @@ export const RoomInput = forwardRef<HTMLDivElement, RoomInputProps>(
 | 
			
		|||
          return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        sendTypingStatus(!isEmptyEditor(editor));
 | 
			
		||||
        if (!hideActivity) {
 | 
			
		||||
          sendTypingStatus(!isEmptyEditor(editor));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const prevWordRange = getPrevWorldRange(editor);
 | 
			
		||||
        const query = prevWordRange
 | 
			
		||||
| 
						 | 
				
			
			@ -390,7 +393,7 @@ export const RoomInput = forwardRef<HTMLDivElement, RoomInputProps>(
 | 
			
		|||
          : undefined;
 | 
			
		||||
        setAutocompleteQuery(query);
 | 
			
		||||
      },
 | 
			
		||||
      [editor, sendTypingStatus]
 | 
			
		||||
      [editor, sendTypingStatus, hideActivity]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const handleCloseAutocomplete = useCallback(() => {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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() ? (
 | 
			
		||||
              <RedactedContent reason={mEvent.getUnsigned().redacted_because?.content.reason} />
 | 
			
		||||
| 
						 | 
				
			
			@ -1119,6 +1121,7 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli
 | 
			
		|||
                />
 | 
			
		||||
              )
 | 
			
		||||
            }
 | 
			
		||||
            hideReadReceipts={hideActivity}
 | 
			
		||||
          >
 | 
			
		||||
            <EncryptedContent mEvent={mEvent}>
 | 
			
		||||
              {() => {
 | 
			
		||||
| 
						 | 
				
			
			@ -1215,6 +1218,7 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli
 | 
			
		|||
                />
 | 
			
		||||
              )
 | 
			
		||||
            }
 | 
			
		||||
            hideReadReceipts={hideActivity}
 | 
			
		||||
          >
 | 
			
		||||
            {mEvent.isRedacted() ? (
 | 
			
		||||
              <RedactedContent reason={mEvent.getUnsigned().redacted_because?.content.reason} />
 | 
			
		||||
| 
						 | 
				
			
			@ -1256,6 +1260,7 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli
 | 
			
		|||
            highlight={highlighted}
 | 
			
		||||
            messageSpacing={messageSpacing}
 | 
			
		||||
            canDelete={canRedact || mEvent.getSender() === mx.getUserId()}
 | 
			
		||||
            hideReadReceipts={hideActivity}
 | 
			
		||||
          >
 | 
			
		||||
            <EventContent
 | 
			
		||||
              messageLayout={messageLayout}
 | 
			
		||||
| 
						 | 
				
			
			@ -1291,6 +1296,7 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli
 | 
			
		|||
            highlight={highlighted}
 | 
			
		||||
            messageSpacing={messageSpacing}
 | 
			
		||||
            canDelete={canRedact || mEvent.getSender() === mx.getUserId()}
 | 
			
		||||
            hideReadReceipts={hideActivity}
 | 
			
		||||
          >
 | 
			
		||||
            <EventContent
 | 
			
		||||
              messageLayout={messageLayout}
 | 
			
		||||
| 
						 | 
				
			
			@ -1327,6 +1333,7 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli
 | 
			
		|||
            highlight={highlighted}
 | 
			
		||||
            messageSpacing={messageSpacing}
 | 
			
		||||
            canDelete={canRedact || mEvent.getSender() === mx.getUserId()}
 | 
			
		||||
            hideReadReceipts={hideActivity}
 | 
			
		||||
          >
 | 
			
		||||
            <EventContent
 | 
			
		||||
              messageLayout={messageLayout}
 | 
			
		||||
| 
						 | 
				
			
			@ -1363,6 +1370,7 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli
 | 
			
		|||
            highlight={highlighted}
 | 
			
		||||
            messageSpacing={messageSpacing}
 | 
			
		||||
            canDelete={canRedact || mEvent.getSender() === mx.getUserId()}
 | 
			
		||||
            hideReadReceipts={hideActivity}
 | 
			
		||||
          >
 | 
			
		||||
            <EventContent
 | 
			
		||||
              messageLayout={messageLayout}
 | 
			
		||||
| 
						 | 
				
			
			@ -1401,6 +1409,7 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli
 | 
			
		|||
          highlight={highlighted}
 | 
			
		||||
          messageSpacing={messageSpacing}
 | 
			
		||||
          canDelete={canRedact || mEvent.getSender() === mx.getUserId()}
 | 
			
		||||
          hideReadReceipts={hideActivity}
 | 
			
		||||
        >
 | 
			
		||||
          <EventContent
 | 
			
		||||
            messageLayout={messageLayout}
 | 
			
		||||
| 
						 | 
				
			
			@ -1444,6 +1453,7 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli
 | 
			
		|||
          highlight={highlighted}
 | 
			
		||||
          messageSpacing={messageSpacing}
 | 
			
		||||
          canDelete={canRedact || mEvent.getSender() === mx.getUserId()}
 | 
			
		||||
          hideReadReceipts={hideActivity}
 | 
			
		||||
        >
 | 
			
		||||
          <EventContent
 | 
			
		||||
            messageLayout={messageLayout}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,12 +13,14 @@ import { RoomTimeline } from './RoomTimeline';
 | 
			
		|||
import { RoomViewTyping } from './RoomViewTyping';
 | 
			
		||||
import { RoomTombstone } from './RoomTombstone';
 | 
			
		||||
import { RoomInput } from './RoomInput';
 | 
			
		||||
import { RoomViewFollowing } from './RoomViewFollowing';
 | 
			
		||||
import { RoomViewFollowing, RoomViewFollowingPlaceholder } from './RoomViewFollowing';
 | 
			
		||||
import { Page } from '../../components/page';
 | 
			
		||||
import { RoomViewHeader } from './RoomViewHeader';
 | 
			
		||||
import { useKeyDown } from '../../hooks/useKeyDown';
 | 
			
		||||
import { editableActiveElement } from '../../utils/dom';
 | 
			
		||||
import navigation from '../../../client/state/navigation';
 | 
			
		||||
import { settingsAtom } from '../../state/settings';
 | 
			
		||||
import { useSetting } from '../../state/hooks/settings';
 | 
			
		||||
 | 
			
		||||
const FN_KEYS_REGEX = /^F\d+$/;
 | 
			
		||||
const shouldFocusMessageField = (evt: KeyboardEvent): boolean => {
 | 
			
		||||
| 
						 | 
				
			
			@ -57,6 +59,8 @@ export function RoomView({ room, eventId }: { room: Room; eventId?: string }) {
 | 
			
		|||
  const roomInputRef = useRef<HTMLDivElement>(null);
 | 
			
		||||
  const roomViewRef = useRef<HTMLDivElement>(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 }) {
 | 
			
		|||
            </>
 | 
			
		||||
          )}
 | 
			
		||||
        </div>
 | 
			
		||||
        <RoomViewFollowing room={room} />
 | 
			
		||||
        {hideActivity ? <RoomViewFollowingPlaceholder /> : <RoomViewFollowing room={room} />}
 | 
			
		||||
      </Box>
 | 
			
		||||
    </Page>
 | 
			
		||||
  );
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,6 +24,10 @@ import { useRoomEventReaders } from '../../hooks/useRoomEventReaders';
 | 
			
		|||
import { EventReaders } from '../../components/event-readers';
 | 
			
		||||
import { stopPropagation } from '../../utils/keyboard';
 | 
			
		||||
 | 
			
		||||
export function RoomViewFollowingPlaceholder() {
 | 
			
		||||
  return <div className={css.RoomViewFollowingPlaceholder} />;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export type RoomViewFollowingProps = {
 | 
			
		||||
  room: Room;
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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<HTMLDivElement, RoomMenuProps>(({ 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();
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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>(
 | 
			
		|||
                              </Text>
 | 
			
		||||
                            </MenuItem>
 | 
			
		||||
                          )}
 | 
			
		||||
                          <MessageReadReceiptItem
 | 
			
		||||
                            room={room}
 | 
			
		||||
                            eventId={mEvent.getId() ?? ''}
 | 
			
		||||
                            onClose={closeMenu}
 | 
			
		||||
                          />
 | 
			
		||||
                          {!hideReadReceipts && (
 | 
			
		||||
                            <MessageReadReceiptItem
 | 
			
		||||
                              room={room}
 | 
			
		||||
                              eventId={mEvent.getId() ?? ''}
 | 
			
		||||
                              onClose={closeMenu}
 | 
			
		||||
                            />
 | 
			
		||||
                          )}
 | 
			
		||||
                          <MessageSourceCodeItem room={room} mEvent={mEvent} onClose={closeMenu} />
 | 
			
		||||
                          <MessageCopyLinkItem room={room} mEvent={mEvent} onClose={closeMenu} />
 | 
			
		||||
                          {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>(
 | 
			
		|||
                    >
 | 
			
		||||
                      <Menu {...props} ref={ref}>
 | 
			
		||||
                        <Box direction="Column" gap="100" className={css.MessageMenuGroup}>
 | 
			
		||||
                          <MessageReadReceiptItem
 | 
			
		||||
                            room={room}
 | 
			
		||||
                            eventId={mEvent.getId() ?? ''}
 | 
			
		||||
                            onClose={closeMenu}
 | 
			
		||||
                          />
 | 
			
		||||
                          {!hideReadReceipts && (
 | 
			
		||||
                            <MessageReadReceiptItem
 | 
			
		||||
                              room={room}
 | 
			
		||||
                              eventId={mEvent.getId() ?? ''}
 | 
			
		||||
                              onClose={closeMenu}
 | 
			
		||||
                            />
 | 
			
		||||
                          )}
 | 
			
		||||
                          <MessageSourceCodeItem room={room} mEvent={mEvent} onClose={closeMenu} />
 | 
			
		||||
                          <MessageCopyLinkItem room={room} mEvent={mEvent} onClose={closeMenu} />
 | 
			
		||||
                        </Box>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 (
 | 
			
		||||
    <Box direction="Column" gap="100">
 | 
			
		||||
| 
						 | 
				
			
			@ -363,6 +364,13 @@ function Editor() {
 | 
			
		|||
          after={<Switch variant="Primary" value={isMarkdown} onChange={setIsMarkdown} />}
 | 
			
		||||
        />
 | 
			
		||||
      </SequenceCard>
 | 
			
		||||
      <SequenceCard className={SequenceCardStyle} variant="SurfaceVariant" direction="Column">
 | 
			
		||||
        <SettingTile
 | 
			
		||||
          title="Hide Typing & Read Receipts"
 | 
			
		||||
          description="Turn off both typing status and read receipts to keep your activity private."
 | 
			
		||||
          after={<Switch variant="Primary" value={hideActivity} onChange={setHideActivity} />}
 | 
			
		||||
        />
 | 
			
		||||
      </SequenceCard>
 | 
			
		||||
    </Box>
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -555,7 +563,13 @@ function Messages() {
 | 
			
		|||
      <SequenceCard className={SequenceCardStyle} variant="SurfaceVariant" direction="Column">
 | 
			
		||||
        <SettingTile
 | 
			
		||||
          title="Disable Media Auto Load"
 | 
			
		||||
          after={<Switch variant="Primary" value={!mediaAutoLoad} onChange={(v) => setMediaAutoLoad(!v)} />}
 | 
			
		||||
          after={
 | 
			
		||||
            <Switch
 | 
			
		||||
              variant="Primary"
 | 
			
		||||
              value={!mediaAutoLoad}
 | 
			
		||||
              onChange={(v) => setMediaAutoLoad(!v)}
 | 
			
		||||
            />
 | 
			
		||||
          }
 | 
			
		||||
        />
 | 
			
		||||
      </SequenceCard>
 | 
			
		||||
      <SequenceCard className={SequenceCardStyle} variant="SurfaceVariant" direction="Column">
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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<HTMLDivElement, DirectMenuProps>(({ 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();
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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<HTMLDivElement, HomeMenuProps>(({ 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();
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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}
 | 
			
		||||
                        />
 | 
			
		||||
                      </VirtualTile>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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<HTMLDivElement, DirectMenuProps>(({ 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();
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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<HTMLDivElement, HomeMenuProps>(({ 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();
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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<HTMLDivElement, SpaceMenuProps>(
 | 
			
		||||
  ({ 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<HTMLDivElement, SpaceMenuProps>(
 | 
			
		|||
    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]
 | 
			
		||||
  );
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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<HTMLDivElement, SpaceMenuProps>(({ 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<HTMLDivElement, SpaceMenuProps>(({ room, requestClo
 | 
			
		|||
  const unread = useRoomsUnread(allChild, roomToUnreadAtom);
 | 
			
		||||
 | 
			
		||||
  const handleMarkAsRead = () => {
 | 
			
		||||
    allChild.forEach((childRoomId) => markAsRead(mx, childRoomId));
 | 
			
		||||
    allChild.forEach((childRoomId) => markAsRead(mx, childRoomId, hideActivity));
 | 
			
		||||
    requestClose();
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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<ReceiptContent>();
 | 
			
		||||
      const myUserId = mx.getUserId();
 | 
			
		||||
      if (!myUserId) return;
 | 
			
		||||
      if (room.isSpaceRoom()) return;
 | 
			
		||||
      const content = mEvent.getContent<ReceiptContent>();
 | 
			
		||||
 | 
			
		||||
        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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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]);
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue