mirror of
				https://github.com/cinnyapp/cinny.git
				synced 2025-11-04 06:20:28 +03:00 
			
		
		
		
	handle error in loading screen (#1823)
* handle client boot error in loading screen * use sync state hook in client root * add loading screen options * removed extra condition in loading finish * add sync connection status bar
This commit is contained in:
		
							parent
							
								
									e046c59f7c
								
							
						
					
					
						commit
						e2228a18c1
					
				
					 62 changed files with 609 additions and 510 deletions
				
			
		| 
						 | 
				
			
			@ -53,7 +53,7 @@ const RoomNavItemMenu = forwardRef<HTMLDivElement, RoomNavItemMenuProps>(
 | 
			
		|||
    const canInvite = canDoAction('invite', getPowerLevel(mx.getUserId() ?? ''));
 | 
			
		||||
 | 
			
		||||
    const handleMarkAsRead = () => {
 | 
			
		||||
      markAsRead(room.roomId);
 | 
			
		||||
      markAsRead(mx, room.roomId);
 | 
			
		||||
      requestClose();
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,10 +11,12 @@ import { PowerLevelsContextProvider, usePowerLevels } from '../../hooks/usePower
 | 
			
		|||
import { useRoom } from '../../hooks/useRoom';
 | 
			
		||||
import { useKeyDown } from '../../hooks/useKeyDown';
 | 
			
		||||
import { markAsRead } from '../../../client/action/notifications';
 | 
			
		||||
import { useMatrixClient } from '../../hooks/useMatrixClient';
 | 
			
		||||
 | 
			
		||||
export function Room() {
 | 
			
		||||
  const { eventId } = useParams();
 | 
			
		||||
  const room = useRoom();
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
 | 
			
		||||
  const [isDrawer] = useSetting(settingsAtom, 'isPeopleDrawer');
 | 
			
		||||
  const screenSize = useScreenSizeContext();
 | 
			
		||||
| 
						 | 
				
			
			@ -25,7 +27,7 @@ export function Room() {
 | 
			
		|||
    useCallback(
 | 
			
		||||
      (evt) => {
 | 
			
		||||
        if (isKeyHotkey('escape', evt)) {
 | 
			
		||||
          markAsRead(room.roomId);
 | 
			
		||||
          markAsRead(mx, room.roomId);
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      [room.roomId]
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -597,7 +597,7 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli
 | 
			
		|||
        // so timeline can be updated with evt like: edits, reactions etc
 | 
			
		||||
        if (atBottomRef.current) {
 | 
			
		||||
          if (document.hasFocus() && (!unreadInfo || mEvt.getSender() === mx.getUserId())) {
 | 
			
		||||
            requestAnimationFrame(() => markAsRead(mEvt.getRoomId()));
 | 
			
		||||
            requestAnimationFrame(() => markAsRead(mx, mEvt.getRoomId()));
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          if (document.hasFocus()) {
 | 
			
		||||
| 
						 | 
				
			
			@ -658,15 +658,15 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli
 | 
			
		|||
 | 
			
		||||
  const tryAutoMarkAsRead = useCallback(() => {
 | 
			
		||||
    if (!unreadInfo) {
 | 
			
		||||
      requestAnimationFrame(() => markAsRead(room.roomId));
 | 
			
		||||
      requestAnimationFrame(() => markAsRead(mx, room.roomId));
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    const evtTimeline = getEventTimeline(room, unreadInfo.readUptoEventId);
 | 
			
		||||
    const latestTimeline = evtTimeline && getFirstLinkedTimeline(evtTimeline, Direction.Forward);
 | 
			
		||||
    if (latestTimeline === room.getLiveTimeline()) {
 | 
			
		||||
      requestAnimationFrame(() => markAsRead(room.roomId));
 | 
			
		||||
      requestAnimationFrame(() => markAsRead(mx, room.roomId));
 | 
			
		||||
    }
 | 
			
		||||
  }, [room, unreadInfo]);
 | 
			
		||||
  }, [mx, room, unreadInfo]);
 | 
			
		||||
 | 
			
		||||
  const debounceSetAtBottom = useDebounce(
 | 
			
		||||
    useCallback((entry: IntersectionObserverEntry) => {
 | 
			
		||||
| 
						 | 
				
			
			@ -832,7 +832,7 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli
 | 
			
		|||
  };
 | 
			
		||||
 | 
			
		||||
  const handleMarkAsRead = () => {
 | 
			
		||||
    markAsRead(room.roomId);
 | 
			
		||||
    markAsRead(mx, room.roomId);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const handleOpenReply: MouseEventHandler<HTMLButtonElement> = useCallback(
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -40,28 +40,30 @@ export function RoomTombstone({ roomId, body, replacementRoomId }: RoomTombstone
 | 
			
		|||
          </Text>
 | 
			
		||||
        )}
 | 
			
		||||
      </Box>
 | 
			
		||||
      {replacementRoom?.getMyMembership() === Membership.Join ||
 | 
			
		||||
      joinState.status === AsyncStatus.Success ? (
 | 
			
		||||
        <Button onClick={handleOpen} size="300" variant="Success" fill="Solid" radii="300">
 | 
			
		||||
          <Text size="B300">Open New Room</Text>
 | 
			
		||||
        </Button>
 | 
			
		||||
      ) : (
 | 
			
		||||
        <Button
 | 
			
		||||
          onClick={handleJoin}
 | 
			
		||||
          size="300"
 | 
			
		||||
          variant="Primary"
 | 
			
		||||
          fill="Solid"
 | 
			
		||||
          radii="300"
 | 
			
		||||
          before={
 | 
			
		||||
            joinState.status === AsyncStatus.Loading && (
 | 
			
		||||
              <Spinner size="100" variant="Primary" fill="Solid" />
 | 
			
		||||
            )
 | 
			
		||||
          }
 | 
			
		||||
          disabled={joinState.status === AsyncStatus.Loading}
 | 
			
		||||
        >
 | 
			
		||||
          <Text size="B300">Join New Room</Text>
 | 
			
		||||
        </Button>
 | 
			
		||||
      )}
 | 
			
		||||
      <Box shrink="No">
 | 
			
		||||
        {replacementRoom?.getMyMembership() === Membership.Join ||
 | 
			
		||||
        joinState.status === AsyncStatus.Success ? (
 | 
			
		||||
          <Button onClick={handleOpen} size="300" variant="Success" fill="Solid" radii="300">
 | 
			
		||||
            <Text size="B300">Open New Room</Text>
 | 
			
		||||
          </Button>
 | 
			
		||||
        ) : (
 | 
			
		||||
          <Button
 | 
			
		||||
            onClick={handleJoin}
 | 
			
		||||
            size="300"
 | 
			
		||||
            variant="Primary"
 | 
			
		||||
            fill="Solid"
 | 
			
		||||
            radii="300"
 | 
			
		||||
            before={
 | 
			
		||||
              joinState.status === AsyncStatus.Loading && (
 | 
			
		||||
                <Spinner size="100" variant="Primary" fill="Solid" />
 | 
			
		||||
              )
 | 
			
		||||
            }
 | 
			
		||||
            disabled={joinState.status === AsyncStatus.Loading}
 | 
			
		||||
          >
 | 
			
		||||
            <Text size="B300">Join New Room</Text>
 | 
			
		||||
          </Button>
 | 
			
		||||
        )}
 | 
			
		||||
      </Box>
 | 
			
		||||
    </RoomInputPlaceholder>
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -74,7 +74,7 @@ const RoomMenu = forwardRef<HTMLDivElement, RoomMenuProps>(
 | 
			
		|||
    const canInvite = canDoAction('invite', getPowerLevel(mx.getUserId() ?? ''));
 | 
			
		||||
 | 
			
		||||
    const handleMarkAsRead = () => {
 | 
			
		||||
      markAsRead(room.roomId);
 | 
			
		||||
      markAsRead(mx, room.roomId);
 | 
			
		||||
      requestClose();
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,10 +1,9 @@
 | 
			
		|||
/* eslint-disable import/prefer-default-export */
 | 
			
		||||
import { useState, useEffect } from 'react';
 | 
			
		||||
 | 
			
		||||
import initMatrix from '../../client/initMatrix';
 | 
			
		||||
import { useMatrixClient } from './useMatrixClient';
 | 
			
		||||
 | 
			
		||||
export function useAccountData(eventType) {
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
  const [event, setEvent] = useState(mx.getAccountData(eventType));
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
| 
						 | 
				
			
			@ -16,7 +15,7 @@ export function useAccountData(eventType) {
 | 
			
		|||
    return () => {
 | 
			
		||||
      mx.removeListener('accountData', handleChange);
 | 
			
		||||
    };
 | 
			
		||||
  }, [eventType]);
 | 
			
		||||
  }, [mx, eventType]);
 | 
			
		||||
 | 
			
		||||
  return event;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -92,9 +92,9 @@ export const useCommands = (mx: MatrixClient, room: Room): CommandRecord => {
 | 
			
		|||
              return;
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
          const devices = await Promise.all(userIds.map(hasDevices));
 | 
			
		||||
          const devices = await Promise.all(userIds.map(uid => hasDevices(mx, uid)));
 | 
			
		||||
          const isEncrypt = devices.every((hasDevice) => hasDevice);
 | 
			
		||||
          const result = await roomActions.createDM(userIds, isEncrypt);
 | 
			
		||||
          const result = await roomActions.createDM(mx, userIds, isEncrypt);
 | 
			
		||||
          navigateRoom(result.room_id);
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
| 
						 | 
				
			
			@ -106,7 +106,7 @@ export const useCommands = (mx: MatrixClient, room: Room): CommandRecord => {
 | 
			
		|||
          const roomIds = rawIds.filter(
 | 
			
		||||
            (idOrAlias) => isRoomId(idOrAlias) || isRoomAlias(idOrAlias)
 | 
			
		||||
          );
 | 
			
		||||
          roomIds.map((id) => roomActions.join(id));
 | 
			
		||||
          roomIds.map((id) => roomActions.join(mx, id));
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
      [Command.Leave]: {
 | 
			
		||||
| 
						 | 
				
			
			@ -127,7 +127,7 @@ export const useCommands = (mx: MatrixClient, room: Room): CommandRecord => {
 | 
			
		|||
        description: 'Invite user to room. Example: /invite userId1 userId2 [-r reason]',
 | 
			
		||||
        exe: async (payload) => {
 | 
			
		||||
          const { users, reason } = parseUsersAndReason(payload);
 | 
			
		||||
          users.map((id) => roomActions.invite(room.roomId, id, reason));
 | 
			
		||||
          users.map((id) => mx.invite(room.roomId, id, reason));
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
      [Command.DisInvite]: {
 | 
			
		||||
| 
						 | 
				
			
			@ -135,7 +135,7 @@ export const useCommands = (mx: MatrixClient, room: Room): CommandRecord => {
 | 
			
		|||
        description: 'Disinvite user to room. Example: /disinvite userId1 userId2 [-r reason]',
 | 
			
		||||
        exe: async (payload) => {
 | 
			
		||||
          const { users, reason } = parseUsersAndReason(payload);
 | 
			
		||||
          users.map((id) => roomActions.kick(room.roomId, id, reason));
 | 
			
		||||
          users.map((id) => mx.kick(room.roomId, id, reason));
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
      [Command.Kick]: {
 | 
			
		||||
| 
						 | 
				
			
			@ -143,7 +143,7 @@ export const useCommands = (mx: MatrixClient, room: Room): CommandRecord => {
 | 
			
		|||
        description: 'Kick user from room. Example: /kick userId1 userId2 [-r reason]',
 | 
			
		||||
        exe: async (payload) => {
 | 
			
		||||
          const { users, reason } = parseUsersAndReason(payload);
 | 
			
		||||
          users.map((id) => roomActions.kick(room.roomId, id, reason));
 | 
			
		||||
          users.map((id) => mx.kick(room.roomId, id, reason));
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
      [Command.Ban]: {
 | 
			
		||||
| 
						 | 
				
			
			@ -151,7 +151,7 @@ export const useCommands = (mx: MatrixClient, room: Room): CommandRecord => {
 | 
			
		|||
        description: 'Ban user from room. Example: /ban userId1 userId2 [-r reason]',
 | 
			
		||||
        exe: async (payload) => {
 | 
			
		||||
          const { users, reason } = parseUsersAndReason(payload);
 | 
			
		||||
          users.map((id) => roomActions.ban(room.roomId, id, reason));
 | 
			
		||||
          users.map((id) => mx.ban(room.roomId, id, reason));
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
      [Command.UnBan]: {
 | 
			
		||||
| 
						 | 
				
			
			@ -160,7 +160,7 @@ export const useCommands = (mx: MatrixClient, room: Room): CommandRecord => {
 | 
			
		|||
        exe: async (payload) => {
 | 
			
		||||
          const rawIds = payload.split(' ');
 | 
			
		||||
          const users = rawIds.filter((id) => isUserId(id));
 | 
			
		||||
          users.map((id) => roomActions.unban(room.roomId, id));
 | 
			
		||||
          users.map((id) => mx.unban(room.roomId, id));
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
      [Command.Ignore]: {
 | 
			
		||||
| 
						 | 
				
			
			@ -169,7 +169,7 @@ export const useCommands = (mx: MatrixClient, room: Room): CommandRecord => {
 | 
			
		|||
        exe: async (payload) => {
 | 
			
		||||
          const rawIds = payload.split(' ');
 | 
			
		||||
          const userIds = rawIds.filter((id) => isUserId(id));
 | 
			
		||||
          if (userIds.length > 0) roomActions.ignore(userIds);
 | 
			
		||||
          if (userIds.length > 0) roomActions.ignore(mx, userIds);
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
      [Command.UnIgnore]: {
 | 
			
		||||
| 
						 | 
				
			
			@ -178,7 +178,7 @@ export const useCommands = (mx: MatrixClient, room: Room): CommandRecord => {
 | 
			
		|||
        exe: async (payload) => {
 | 
			
		||||
          const rawIds = payload.split(' ');
 | 
			
		||||
          const userIds = rawIds.filter((id) => isUserId(id));
 | 
			
		||||
          if (userIds.length > 0) roomActions.unignore(userIds);
 | 
			
		||||
          if (userIds.length > 0) roomActions.unignore(mx, userIds);
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
      [Command.MyRoomNick]: {
 | 
			
		||||
| 
						 | 
				
			
			@ -187,7 +187,7 @@ export const useCommands = (mx: MatrixClient, room: Room): CommandRecord => {
 | 
			
		|||
        exe: async (payload) => {
 | 
			
		||||
          const nick = payload.trim();
 | 
			
		||||
          if (nick === '') return;
 | 
			
		||||
          roomActions.setMyRoomNick(room.roomId, nick);
 | 
			
		||||
          roomActions.setMyRoomNick(mx, room.roomId, nick);
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
      [Command.MyRoomAvatar]: {
 | 
			
		||||
| 
						 | 
				
			
			@ -195,7 +195,7 @@ export const useCommands = (mx: MatrixClient, room: Room): CommandRecord => {
 | 
			
		|||
        description: 'Change profile picture in current room. Example /myroomavatar mxc://xyzabc',
 | 
			
		||||
        exe: async (payload) => {
 | 
			
		||||
          if (payload.match(/^mxc:\/\/\S+$/)) {
 | 
			
		||||
            roomActions.setMyRoomAvatar(room.roomId, payload);
 | 
			
		||||
            roomActions.setMyRoomAvatar(mx, room.roomId, payload);
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
| 
						 | 
				
			
			@ -203,14 +203,14 @@ export const useCommands = (mx: MatrixClient, room: Room): CommandRecord => {
 | 
			
		|||
        name: Command.ConvertToDm,
 | 
			
		||||
        description: 'Convert room to direct message',
 | 
			
		||||
        exe: async () => {
 | 
			
		||||
          roomActions.convertToDm(room.roomId);
 | 
			
		||||
          roomActions.convertToDm(mx, room.roomId);
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
      [Command.ConvertToRoom]: {
 | 
			
		||||
        name: Command.ConvertToRoom,
 | 
			
		||||
        description: 'Convert direct message to room',
 | 
			
		||||
        exe: async () => {
 | 
			
		||||
          roomActions.convertToRoom(room.roomId);
 | 
			
		||||
          roomActions.convertToRoom(mx, room.roomId);
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
    }),
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,12 +1,12 @@
 | 
			
		|||
/* eslint-disable import/prefer-default-export */
 | 
			
		||||
import { useState, useEffect } from 'react';
 | 
			
		||||
 | 
			
		||||
import initMatrix from '../../client/initMatrix';
 | 
			
		||||
import { hasCrossSigningAccountData } from '../../util/matrixUtil';
 | 
			
		||||
import { useMatrixClient } from './useMatrixClient';
 | 
			
		||||
 | 
			
		||||
export function useCrossSigningStatus() {
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
  const [isCSEnabled, setIsCSEnabled] = useState(hasCrossSigningAccountData());
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
  const [isCSEnabled, setIsCSEnabled] = useState(hasCrossSigningAccountData(mx));
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    if (isCSEnabled) return undefined;
 | 
			
		||||
| 
						 | 
				
			
			@ -20,6 +20,6 @@ export function useCrossSigningStatus() {
 | 
			
		|||
    return () => {
 | 
			
		||||
      mx.removeListener('accountData', handleAccountData);
 | 
			
		||||
    };
 | 
			
		||||
  }, [isCSEnabled === false]);
 | 
			
		||||
  }, [mx, isCSEnabled]);
 | 
			
		||||
  return isCSEnabled;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,10 +1,9 @@
 | 
			
		|||
/* eslint-disable import/prefer-default-export */
 | 
			
		||||
import { useState, useEffect } from 'react';
 | 
			
		||||
 | 
			
		||||
import initMatrix from '../../client/initMatrix';
 | 
			
		||||
import { useMatrixClient } from './useMatrixClient';
 | 
			
		||||
 | 
			
		||||
export function useDeviceList() {
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
  const [deviceList, setDeviceList] = useState(null);
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
| 
						 | 
				
			
			@ -27,6 +26,6 @@ export function useDeviceList() {
 | 
			
		|||
      mx.removeListener('crypto.devicesUpdated', handleDevicesUpdate);
 | 
			
		||||
      isMounted = false;
 | 
			
		||||
    };
 | 
			
		||||
  }, []);
 | 
			
		||||
  }, [mx]);
 | 
			
		||||
  return deviceList;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,13 +2,13 @@ import { ClientEvent, ClientEventHandlerMap, MatrixClient } from 'matrix-js-sdk'
 | 
			
		|||
import { useEffect } from 'react';
 | 
			
		||||
 | 
			
		||||
export const useSyncState = (
 | 
			
		||||
  mx: MatrixClient,
 | 
			
		||||
  mx: MatrixClient | undefined,
 | 
			
		||||
  onChange: ClientEventHandlerMap[ClientEvent.Sync]
 | 
			
		||||
): void => {
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    mx.on(ClientEvent.Sync, onChange);
 | 
			
		||||
    mx?.on(ClientEvent.Sync, onChange);
 | 
			
		||||
    return () => {
 | 
			
		||||
      mx.removeListener(ClientEvent.Sync, onChange);
 | 
			
		||||
      mx?.removeListener(ClientEvent.Sync, onChange);
 | 
			
		||||
    };
 | 
			
		||||
  }, [mx, onChange]);
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,5 @@
 | 
			
		|||
import React from 'react';
 | 
			
		||||
 | 
			
		||||
import initMatrix from '../../../client/initMatrix';
 | 
			
		||||
import { openReusableContextMenu } from '../../../client/action/navigation';
 | 
			
		||||
import { getEventCords } from '../../../util/common';
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -14,6 +13,7 @@ import NotificationSelector from './NotificationSelector';
 | 
			
		|||
import ChevronBottomIC from '../../../../public/res/ic/outlined/chevron-bottom.svg';
 | 
			
		||||
 | 
			
		||||
import { useAccountData } from '../../hooks/useAccountData';
 | 
			
		||||
import { useMatrixClient } from '../../hooks/useMatrixClient';
 | 
			
		||||
 | 
			
		||||
export const notifType = {
 | 
			
		||||
  ON: 'on',
 | 
			
		||||
| 
						 | 
				
			
			@ -52,7 +52,7 @@ export function getTypeActions(type, highlightValue = false) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
function useGlobalNotif() {
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
  const pushRules = useAccountData('m.push_rules')?.getContent();
 | 
			
		||||
  const underride = pushRules?.global?.underride ?? [];
 | 
			
		||||
  const rulesToType = {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,7 +1,6 @@
 | 
			
		|||
import React from 'react';
 | 
			
		||||
import './IgnoreUserList.scss';
 | 
			
		||||
 | 
			
		||||
import initMatrix from '../../../client/initMatrix';
 | 
			
		||||
import * as roomActions from '../../../client/action/room';
 | 
			
		||||
 | 
			
		||||
import Text from '../../atoms/text/Text';
 | 
			
		||||
| 
						 | 
				
			
			@ -14,10 +13,12 @@ import SettingTile from '../setting-tile/SettingTile';
 | 
			
		|||
import CrossIC from '../../../../public/res/ic/outlined/cross.svg';
 | 
			
		||||
 | 
			
		||||
import { useAccountData } from '../../hooks/useAccountData';
 | 
			
		||||
import { useMatrixClient } from '../../hooks/useMatrixClient';
 | 
			
		||||
 | 
			
		||||
function IgnoreUserList() {
 | 
			
		||||
  useAccountData('m.ignored_user_list');
 | 
			
		||||
  const ignoredUsers = initMatrix.matrixClient.getIgnoredUsers();
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
  const ignoredUsers = mx.getIgnoredUsers();
 | 
			
		||||
 | 
			
		||||
  const handleSubmit = (evt) => {
 | 
			
		||||
    evt.preventDefault();
 | 
			
		||||
| 
						 | 
				
			
			@ -26,7 +27,7 @@ function IgnoreUserList() {
 | 
			
		|||
    const userIds = value.split(' ').filter((v) => v.match(/^@\S+:\S+$/));
 | 
			
		||||
    if (userIds.length === 0) return;
 | 
			
		||||
    ignoreInput.value = '';
 | 
			
		||||
    roomActions.ignore(userIds);
 | 
			
		||||
    roomActions.ignore(mx, userIds);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
| 
						 | 
				
			
			@ -49,7 +50,7 @@ function IgnoreUserList() {
 | 
			
		|||
                    key={uId}
 | 
			
		||||
                    text={uId}
 | 
			
		||||
                    iconColor={CrossIC}
 | 
			
		||||
                    onClick={() => roomActions.unignore([uId])}
 | 
			
		||||
                    onClick={() => roomActions.unignore(mx, [uId])}
 | 
			
		||||
                  />
 | 
			
		||||
                ))}
 | 
			
		||||
              </div>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,7 +1,6 @@
 | 
			
		|||
import React from 'react';
 | 
			
		||||
import './KeywordNotification.scss';
 | 
			
		||||
 | 
			
		||||
import initMatrix from '../../../client/initMatrix';
 | 
			
		||||
import { openReusableContextMenu } from '../../../client/action/navigation';
 | 
			
		||||
import { getEventCords } from '../../../util/common';
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -21,6 +20,7 @@ import { useAccountData } from '../../hooks/useAccountData';
 | 
			
		|||
import {
 | 
			
		||||
  notifType, typeToLabel, getActionType, getTypeActions,
 | 
			
		||||
} from './GlobalNotification';
 | 
			
		||||
import { useMatrixClient } from '../../hooks/useMatrixClient';
 | 
			
		||||
 | 
			
		||||
const DISPLAY_NAME = '.m.rule.contains_display_name';
 | 
			
		||||
const ROOM_PING = '.m.rule.roomnotif';
 | 
			
		||||
| 
						 | 
				
			
			@ -28,7 +28,7 @@ const USERNAME = '.m.rule.contains_user_name';
 | 
			
		|||
const KEYWORD = 'keyword';
 | 
			
		||||
 | 
			
		||||
function useKeywordNotif() {
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
  const pushRules = useAccountData('m.push_rules')?.getContent();
 | 
			
		||||
  const override = pushRules?.global?.override ?? [];
 | 
			
		||||
  const content = pushRules?.global?.content ?? [];
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,7 +4,6 @@ import React, {
 | 
			
		|||
import PropTypes from 'prop-types';
 | 
			
		||||
import './ImagePack.scss';
 | 
			
		||||
 | 
			
		||||
import initMatrix from '../../../client/initMatrix';
 | 
			
		||||
import { openReusableDialog } from '../../../client/action/navigation';
 | 
			
		||||
import { suffixRename } from '../../../util/common';
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -19,6 +18,7 @@ import { confirmDialog } from '../confirm-dialog/ConfirmDialog';
 | 
			
		|||
import ImagePackProfile from './ImagePackProfile';
 | 
			
		||||
import ImagePackItem from './ImagePackItem';
 | 
			
		||||
import ImagePackUpload from './ImagePackUpload';
 | 
			
		||||
import { useMatrixClient } from '../../hooks/useMatrixClient';
 | 
			
		||||
 | 
			
		||||
const renameImagePackItem = (shortcode) => new Promise((resolve) => {
 | 
			
		||||
  let isCompleted = false;
 | 
			
		||||
| 
						 | 
				
			
			@ -63,8 +63,7 @@ function getUsage(usage) {
 | 
			
		|||
  return 'both';
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function isGlobalPack(roomId, stateKey) {
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
function isGlobalPack(mx, roomId, stateKey) {
 | 
			
		||||
  const globalContent = mx.getAccountData('im.ponies.emote_rooms')?.getContent();
 | 
			
		||||
  if (typeof globalContent !== 'object') return false;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -75,13 +74,13 @@ function isGlobalPack(roomId, stateKey) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
function useRoomImagePack(roomId, stateKey) {
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
  const room = mx.getRoom(roomId);
 | 
			
		||||
 | 
			
		||||
  const packEvent = room.currentState.getStateEvents('im.ponies.room_emotes', stateKey);
 | 
			
		||||
  const pack = useMemo(() => (
 | 
			
		||||
    ImagePackBuilder.parsePack(packEvent.getId(), packEvent.getContent())
 | 
			
		||||
  ), [room, stateKey]);
 | 
			
		||||
  const pack = useMemo(() => {
 | 
			
		||||
    const packEvent = room.currentState.getStateEvents('im.ponies.room_emotes', stateKey);
 | 
			
		||||
    return ImagePackBuilder.parsePack(packEvent.getId(), packEvent.getContent())
 | 
			
		||||
  }, [room, stateKey]);
 | 
			
		||||
 | 
			
		||||
  const sendPackContent = (content) => {
 | 
			
		||||
    mx.sendStateEvent(roomId, 'im.ponies.room_emotes', content, stateKey);
 | 
			
		||||
| 
						 | 
				
			
			@ -94,14 +93,14 @@ function useRoomImagePack(roomId, stateKey) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
function useUserImagePack() {
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
  const packEvent = mx.getAccountData('im.ponies.user_emotes');
 | 
			
		||||
  const pack = useMemo(() => (
 | 
			
		||||
    ImagePackBuilder.parsePack(mx.getUserId(), packEvent?.getContent() ?? {
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
  const pack = useMemo(() => {
 | 
			
		||||
    const packEvent = mx.getAccountData('im.ponies.user_emotes');
 | 
			
		||||
    return ImagePackBuilder.parsePack(mx.getUserId(), packEvent?.getContent() ?? {
 | 
			
		||||
      pack: { display_name: 'Personal' },
 | 
			
		||||
      images: {},
 | 
			
		||||
    })
 | 
			
		||||
  ), []);
 | 
			
		||||
  }, [mx]);
 | 
			
		||||
 | 
			
		||||
  const sendPackContent = (content) => {
 | 
			
		||||
    mx.setAccountData('im.ponies.user_emotes', content);
 | 
			
		||||
| 
						 | 
				
			
			@ -223,10 +222,10 @@ function removeGlobalImagePack(mx, roomId, stateKey) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
function ImagePack({ roomId, stateKey, handlePackDelete }) {
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
  const room = mx.getRoom(roomId);
 | 
			
		||||
  const [viewMore, setViewMore] = useState(false);
 | 
			
		||||
  const [isGlobal, setIsGlobal] = useState(isGlobalPack(roomId, stateKey));
 | 
			
		||||
  const [isGlobal, setIsGlobal] = useState(isGlobalPack(mx, roomId, stateKey));
 | 
			
		||||
 | 
			
		||||
  const { pack, sendPackContent } = useRoomImagePack(roomId, stateKey);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -331,7 +330,7 @@ ImagePack.propTypes = {
 | 
			
		|||
};
 | 
			
		||||
 | 
			
		||||
function ImagePackUser() {
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
  const [viewMore, setViewMore] = useState(false);
 | 
			
		||||
 | 
			
		||||
  const { pack, sendPackContent } = useUserImagePack();
 | 
			
		||||
| 
						 | 
				
			
			@ -397,7 +396,7 @@ function ImagePackUser() {
 | 
			
		|||
 | 
			
		||||
function useGlobalImagePack() {
 | 
			
		||||
  const [, forceUpdate] = useReducer((count) => count + 1, 0);
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
 | 
			
		||||
  const roomIdToStateKeys = new Map();
 | 
			
		||||
  const globalContent = mx.getAccountData('im.ponies.emote_rooms')?.getContent() ?? { rooms: {} };
 | 
			
		||||
| 
						 | 
				
			
			@ -419,13 +418,13 @@ function useGlobalImagePack() {
 | 
			
		|||
    return () => {
 | 
			
		||||
      mx.removeListener('accountData', handleEvent);
 | 
			
		||||
    };
 | 
			
		||||
  }, []);
 | 
			
		||||
  }, [mx]);
 | 
			
		||||
 | 
			
		||||
  return roomIdToStateKeys;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function ImagePackGlobal() {
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
  const roomIdToStateKeys = useGlobalImagePack();
 | 
			
		||||
 | 
			
		||||
  const handleChange = (roomId, stateKey) => {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,7 +2,6 @@ import React, { useState, useRef } from 'react';
 | 
			
		|||
import PropTypes from 'prop-types';
 | 
			
		||||
import './ImagePackUpload.scss';
 | 
			
		||||
 | 
			
		||||
import initMatrix from '../../../client/initMatrix';
 | 
			
		||||
import { scaleDownImage } from '../../../util/common';
 | 
			
		||||
 | 
			
		||||
import Text from '../../atoms/text/Text';
 | 
			
		||||
| 
						 | 
				
			
			@ -10,9 +9,10 @@ import Button from '../../atoms/button/Button';
 | 
			
		|||
import Input from '../../atoms/input/Input';
 | 
			
		||||
import IconButton from '../../atoms/button/IconButton';
 | 
			
		||||
import CirclePlusIC from '../../../../public/res/ic/outlined/circle-plus.svg';
 | 
			
		||||
import { useMatrixClient } from '../../hooks/useMatrixClient';
 | 
			
		||||
 | 
			
		||||
function ImagePackUpload({ onUpload }) {
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
  const inputRef = useRef(null);
 | 
			
		||||
  const shortcodeRef = useRef(null);
 | 
			
		||||
  const [imgFile, setImgFile] = useState(null);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,7 +2,6 @@ import React, { useState, useRef } from 'react';
 | 
			
		|||
import PropTypes from 'prop-types';
 | 
			
		||||
import './ImageUpload.scss';
 | 
			
		||||
 | 
			
		||||
import initMatrix from '../../../client/initMatrix';
 | 
			
		||||
 | 
			
		||||
import Text from '../../atoms/text/Text';
 | 
			
		||||
import Avatar from '../../atoms/avatar/Avatar';
 | 
			
		||||
| 
						 | 
				
			
			@ -10,6 +9,7 @@ import Spinner from '../../atoms/spinner/Spinner';
 | 
			
		|||
import RawIcon from '../../atoms/system-icons/RawIcon';
 | 
			
		||||
 | 
			
		||||
import PlusIC from '../../../../public/res/ic/outlined/plus.svg';
 | 
			
		||||
import { useMatrixClient } from '../../hooks/useMatrixClient';
 | 
			
		||||
 | 
			
		||||
function ImageUpload({
 | 
			
		||||
  text, bgColor, imageSrc, onUpload, onRequestRemove,
 | 
			
		||||
| 
						 | 
				
			
			@ -17,12 +17,13 @@ function ImageUpload({
 | 
			
		|||
}) {
 | 
			
		||||
  const [uploadPromise, setUploadPromise] = useState(null);
 | 
			
		||||
  const uploadImageRef = useRef(null);
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
 | 
			
		||||
  async function uploadImage(e) {
 | 
			
		||||
    const file = e.target.files.item(0);
 | 
			
		||||
    if (file === null) return;
 | 
			
		||||
    try {
 | 
			
		||||
      const uPromise = initMatrix.matrixClient.uploadContent(file);
 | 
			
		||||
      const uPromise = mx.uploadContent(file);
 | 
			
		||||
      setUploadPromise(uPromise);
 | 
			
		||||
 | 
			
		||||
      const res = await uPromise;
 | 
			
		||||
| 
						 | 
				
			
			@ -35,7 +36,7 @@ function ImageUpload({
 | 
			
		|||
  }
 | 
			
		||||
 | 
			
		||||
  function cancelUpload() {
 | 
			
		||||
    initMatrix.matrixClient.cancelUpload(uploadPromise);
 | 
			
		||||
    mx.cancelUpload(uploadPromise);
 | 
			
		||||
    setUploadPromise(null);
 | 
			
		||||
    uploadImageRef.current.value = null;
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,7 +3,6 @@ import './ExportE2ERoomKeys.scss';
 | 
			
		|||
 | 
			
		||||
import FileSaver from 'file-saver';
 | 
			
		||||
 | 
			
		||||
import initMatrix from '../../../client/initMatrix';
 | 
			
		||||
import cons from '../../../client/state/cons';
 | 
			
		||||
import { encryptMegolmKeyFile } from '../../../util/cryptE2ERoomKeys';
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -13,8 +12,10 @@ import Input from '../../atoms/input/Input';
 | 
			
		|||
import Spinner from '../../atoms/spinner/Spinner';
 | 
			
		||||
 | 
			
		||||
import { useStore } from '../../hooks/useStore';
 | 
			
		||||
import { useMatrixClient } from '../../hooks/useMatrixClient';
 | 
			
		||||
 | 
			
		||||
function ExportE2ERoomKeys() {
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
  const isMountStore = useStore();
 | 
			
		||||
  const [status, setStatus] = useState({
 | 
			
		||||
    isOngoing: false,
 | 
			
		||||
| 
						 | 
				
			
			@ -40,7 +41,7 @@ function ExportE2ERoomKeys() {
 | 
			
		|||
      type: cons.status.IN_FLIGHT,
 | 
			
		||||
    });
 | 
			
		||||
    try {
 | 
			
		||||
      const keys = await initMatrix.matrixClient.exportRoomKeys();
 | 
			
		||||
      const keys = await mx.exportRoomKeys();
 | 
			
		||||
      if (isMountStore.getItem()) {
 | 
			
		||||
        setStatus({
 | 
			
		||||
          isOngoing: true,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,7 +1,6 @@
 | 
			
		|||
import React, { useState, useEffect, useRef } from 'react';
 | 
			
		||||
import './ImportE2ERoomKeys.scss';
 | 
			
		||||
 | 
			
		||||
import initMatrix from '../../../client/initMatrix';
 | 
			
		||||
import cons from '../../../client/state/cons';
 | 
			
		||||
import { decryptMegolmKeyFile } from '../../../util/cryptE2ERoomKeys';
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -14,8 +13,10 @@ import Spinner from '../../atoms/spinner/Spinner';
 | 
			
		|||
import CirclePlusIC from '../../../../public/res/ic/outlined/circle-plus.svg';
 | 
			
		||||
 | 
			
		||||
import { useStore } from '../../hooks/useStore';
 | 
			
		||||
import { useMatrixClient } from '../../hooks/useMatrixClient';
 | 
			
		||||
 | 
			
		||||
function ImportE2ERoomKeys() {
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
  const isMountStore = useStore();
 | 
			
		||||
  const [keyFile, setKeyFile] = useState(null);
 | 
			
		||||
  const [status, setStatus] = useState({
 | 
			
		||||
| 
						 | 
				
			
			@ -45,7 +46,7 @@ function ImportE2ERoomKeys() {
 | 
			
		|||
          type: cons.status.IN_FLIGHT,
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
      await initMatrix.matrixClient.importRoomKeys(JSON.parse(keys));
 | 
			
		||||
      await mx.importRoomKeys(JSON.parse(keys));
 | 
			
		||||
      if (isMountStore.getItem()) {
 | 
			
		||||
        setStatus({
 | 
			
		||||
          isOngoing: false,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,7 +2,6 @@ import React, { useState, useEffect } from 'react';
 | 
			
		|||
import PropTypes from 'prop-types';
 | 
			
		||||
import './RoomAliases.scss';
 | 
			
		||||
 | 
			
		||||
import initMatrix from '../../../client/initMatrix';
 | 
			
		||||
import cons from '../../../client/state/cons';
 | 
			
		||||
import { Debounce } from '../../../util/common';
 | 
			
		||||
import { isRoomAliasAvailable } from '../../../util/matrixUtil';
 | 
			
		||||
| 
						 | 
				
			
			@ -16,8 +15,10 @@ import { MenuHeader } from '../../atoms/context-menu/ContextMenu';
 | 
			
		|||
import SettingTile from '../setting-tile/SettingTile';
 | 
			
		||||
 | 
			
		||||
import { useStore } from '../../hooks/useStore';
 | 
			
		||||
import { useMatrixClient } from '../../hooks/useMatrixClient';
 | 
			
		||||
 | 
			
		||||
function useValidate(hsString) {
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
  const [debounce] = useState(new Debounce());
 | 
			
		||||
  const [validate, setValidate] = useState({ alias: null, status: cons.status.PRE_FLIGHT });
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -62,7 +63,7 @@ function useValidate(hsString) {
 | 
			
		|||
        msg: `validating ${alias}...`,
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      const isValid = await isRoomAliasAvailable(alias);
 | 
			
		||||
      const isValid = await isRoomAliasAvailable(mx, alias);
 | 
			
		||||
      setValidate(() => {
 | 
			
		||||
        if (e.target.value !== value) {
 | 
			
		||||
          return { alias: null, status: cons.status.PRE_FLIGHT };
 | 
			
		||||
| 
						 | 
				
			
			@ -79,8 +80,7 @@ function useValidate(hsString) {
 | 
			
		|||
  return [validate, setValidateToDefault, handleAliasChange];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function getAliases(roomId) {
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
function getAliases(mx, roomId) {
 | 
			
		||||
  const room = mx.getRoom(roomId);
 | 
			
		||||
 | 
			
		||||
  const main = room.getCanonicalAlias();
 | 
			
		||||
| 
						 | 
				
			
			@ -95,7 +95,7 @@ function getAliases(roomId) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
function RoomAliases({ roomId }) {
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
  const room = mx.getRoom(roomId);
 | 
			
		||||
  const userId = mx.getUserId();
 | 
			
		||||
  const hsString = userId.slice(userId.indexOf(':') + 1);
 | 
			
		||||
| 
						 | 
				
			
			@ -103,7 +103,7 @@ function RoomAliases({ roomId }) {
 | 
			
		|||
  const isMountedStore = useStore();
 | 
			
		||||
  const [isPublic, setIsPublic] = useState(false);
 | 
			
		||||
  const [isLocalVisible, setIsLocalVisible] = useState(false);
 | 
			
		||||
  const [aliases, setAliases] = useState(getAliases(roomId));
 | 
			
		||||
  const [aliases, setAliases] = useState(getAliases(mx, roomId));
 | 
			
		||||
  const [selectedAlias, setSelectedAlias] = useState(null);
 | 
			
		||||
  const [deleteAlias, setDeleteAlias] = useState(null);
 | 
			
		||||
  const [validate, setValidateToDefault, handleAliasChange] = useValidate(hsString);
 | 
			
		||||
| 
						 | 
				
			
			@ -140,7 +140,7 @@ function RoomAliases({ roomId }) {
 | 
			
		|||
    return () => {
 | 
			
		||||
      isUnmounted = true;
 | 
			
		||||
    };
 | 
			
		||||
  }, [roomId]);
 | 
			
		||||
  }, [mx, roomId]);
 | 
			
		||||
 | 
			
		||||
  const toggleDirectoryVisibility = () => {
 | 
			
		||||
    mx.setRoomDirectoryVisibility(roomId, isPublic ? 'private' : 'public');
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,7 +2,6 @@ import React, { useReducer, useEffect } from 'react';
 | 
			
		|||
import PropTypes from 'prop-types';
 | 
			
		||||
import './RoomEmojis.scss';
 | 
			
		||||
 | 
			
		||||
import initMatrix from '../../../client/initMatrix';
 | 
			
		||||
import { suffixRename } from '../../../util/common';
 | 
			
		||||
 | 
			
		||||
import { MenuHeader } from '../../atoms/context-menu/ContextMenu';
 | 
			
		||||
| 
						 | 
				
			
			@ -10,9 +9,10 @@ import Text from '../../atoms/text/Text';
 | 
			
		|||
import Input from '../../atoms/input/Input';
 | 
			
		||||
import Button from '../../atoms/button/Button';
 | 
			
		||||
import ImagePack from '../image-pack/ImagePack';
 | 
			
		||||
import { useMatrixClient } from '../../hooks/useMatrixClient';
 | 
			
		||||
 | 
			
		||||
function useRoomPacks(room) {
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
  const [, forceUpdate] = useReducer((count) => count + 1, 0);
 | 
			
		||||
 | 
			
		||||
  const packEvents = room.currentState.getStateEvents('im.ponies.room_emotes');
 | 
			
		||||
| 
						 | 
				
			
			@ -75,7 +75,7 @@ function useRoomPacks(room) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
function RoomEmojis({ roomId }) {
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
  const room = mx.getRoom(roomId);
 | 
			
		||||
 | 
			
		||||
  const { usablePacks, createPack, deletePack } = useRoomPacks(room);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,16 +2,16 @@ import React, { useState } from 'react';
 | 
			
		|||
import PropTypes from 'prop-types';
 | 
			
		||||
import './RoomEncryption.scss';
 | 
			
		||||
 | 
			
		||||
import initMatrix from '../../../client/initMatrix';
 | 
			
		||||
 | 
			
		||||
import Text from '../../atoms/text/Text';
 | 
			
		||||
import Toggle from '../../atoms/button/Toggle';
 | 
			
		||||
import SettingTile from '../setting-tile/SettingTile';
 | 
			
		||||
 | 
			
		||||
import { confirmDialog } from '../confirm-dialog/ConfirmDialog';
 | 
			
		||||
import { useMatrixClient } from '../../hooks/useMatrixClient';
 | 
			
		||||
 | 
			
		||||
function RoomEncryption({ roomId }) {
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
  const room = mx.getRoom(roomId);
 | 
			
		||||
  const encryptionEvents = room.currentState.getStateEvents('m.room.encryption');
 | 
			
		||||
  const [isEncrypted, setIsEncrypted] = useState(encryptionEvents.length > 0);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,11 +2,11 @@ import React, { useState, useEffect, useCallback } from 'react';
 | 
			
		|||
import PropTypes from 'prop-types';
 | 
			
		||||
import './RoomHistoryVisibility.scss';
 | 
			
		||||
 | 
			
		||||
import initMatrix from '../../../client/initMatrix';
 | 
			
		||||
 | 
			
		||||
import Text from '../../atoms/text/Text';
 | 
			
		||||
import RadioButton from '../../atoms/button/RadioButton';
 | 
			
		||||
import { MenuItem } from '../../atoms/context-menu/ContextMenu';
 | 
			
		||||
import { useMatrixClient } from '../../hooks/useMatrixClient';
 | 
			
		||||
 | 
			
		||||
const visibility = {
 | 
			
		||||
  WORLD_READABLE: 'world_readable',
 | 
			
		||||
| 
						 | 
				
			
			@ -33,38 +33,33 @@ const items = [{
 | 
			
		|||
  type: visibility.JOINED,
 | 
			
		||||
}];
 | 
			
		||||
 | 
			
		||||
function setHistoryVisibility(roomId, type) {
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
 | 
			
		||||
  return mx.sendStateEvent(
 | 
			
		||||
    roomId, 'm.room.history_visibility',
 | 
			
		||||
    {
 | 
			
		||||
      history_visibility: type,
 | 
			
		||||
    },
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function useVisibility(roomId) {
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
  const room = mx.getRoom(roomId);
 | 
			
		||||
 | 
			
		||||
  const [activeType, setActiveType] = useState(room.getHistoryVisibility());
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    setActiveType(room.getHistoryVisibility());
 | 
			
		||||
  }, [roomId]);
 | 
			
		||||
  }, [room]);
 | 
			
		||||
 | 
			
		||||
  const setVisibility = useCallback((item) => {
 | 
			
		||||
    if (item.type === activeType.type) return;
 | 
			
		||||
    setActiveType(item.type);
 | 
			
		||||
    setHistoryVisibility(roomId, item.type);
 | 
			
		||||
  }, [activeType, roomId]);
 | 
			
		||||
    mx.sendStateEvent(
 | 
			
		||||
      roomId, 'm.room.history_visibility',
 | 
			
		||||
      {
 | 
			
		||||
        history_visibility: item.type,
 | 
			
		||||
      },
 | 
			
		||||
    );
 | 
			
		||||
  }, [mx, activeType, roomId]);
 | 
			
		||||
 | 
			
		||||
  return [activeType, setVisibility];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function RoomHistoryVisibility({ roomId }) {
 | 
			
		||||
  const [activeType, setVisibility] = useVisibility(roomId);
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
  const userId = mx.getUserId();
 | 
			
		||||
  const room = mx.getRoom(roomId);
 | 
			
		||||
  const { currentState } = room;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,7 +4,6 @@ import React, {
 | 
			
		|||
import PropTypes from 'prop-types';
 | 
			
		||||
import './RoomMembers.scss';
 | 
			
		||||
 | 
			
		||||
import initMatrix from '../../../client/initMatrix';
 | 
			
		||||
import colorMXID from '../../../util/colorMXID';
 | 
			
		||||
import { openProfileViewer } from '../../../client/action/navigation';
 | 
			
		||||
import { getUsernameOfRoomMember, getPowerLabel } from '../../../util/matrixUtil';
 | 
			
		||||
| 
						 | 
				
			
			@ -17,11 +16,11 @@ import Input from '../../atoms/input/Input';
 | 
			
		|||
import { MenuHeader } from '../../atoms/context-menu/ContextMenu';
 | 
			
		||||
import SegmentedControls from '../../atoms/segmented-controls/SegmentedControls';
 | 
			
		||||
import PeopleSelector from '../people-selector/PeopleSelector';
 | 
			
		||||
import { useMatrixClient } from '../../hooks/useMatrixClient';
 | 
			
		||||
 | 
			
		||||
const PER_PAGE_MEMBER = 50;
 | 
			
		||||
 | 
			
		||||
function normalizeMembers(members) {
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
function normalizeMembers(mx, members) {
 | 
			
		||||
  return members.map((member) => ({
 | 
			
		||||
    userId: member.userId,
 | 
			
		||||
    name: getUsernameOfRoomMember(member),
 | 
			
		||||
| 
						 | 
				
			
			@ -33,7 +32,7 @@ function normalizeMembers(members) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
function useMemberOfMembership(roomId, membership) {
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
  const room = mx.getRoom(roomId);
 | 
			
		||||
  const [members, setMembers] = useState([]);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -45,6 +44,7 @@ function useMemberOfMembership(roomId, membership) {
 | 
			
		|||
      if (isLoadingMembers) return;
 | 
			
		||||
      if (event && event?.getRoomId() !== roomId) return;
 | 
			
		||||
      const memberOfMembership = normalizeMembers(
 | 
			
		||||
        mx,
 | 
			
		||||
        room.getMembersWithMembership(membership)
 | 
			
		||||
          .sort(memberByAtoZ).sort(memberByPowerLevel),
 | 
			
		||||
      );
 | 
			
		||||
| 
						 | 
				
			
			@ -66,7 +66,7 @@ function useMemberOfMembership(roomId, membership) {
 | 
			
		|||
      mx.removeListener('RoomMember.membership', updateMemberList);
 | 
			
		||||
      mx.removeListener('RoomMember.powerLevel', updateMemberList);
 | 
			
		||||
    };
 | 
			
		||||
  }, [membership]);
 | 
			
		||||
  }, [mx, membership]);
 | 
			
		||||
 | 
			
		||||
  return [members];
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,7 +2,6 @@ import React, { useState, useEffect, useCallback } from 'react';
 | 
			
		|||
import PropTypes from 'prop-types';
 | 
			
		||||
import './RoomNotification.scss';
 | 
			
		||||
 | 
			
		||||
import initMatrix from '../../../client/initMatrix';
 | 
			
		||||
import cons from '../../../client/state/cons';
 | 
			
		||||
 | 
			
		||||
import Text from '../../atoms/text/Text';
 | 
			
		||||
| 
						 | 
				
			
			@ -14,6 +13,7 @@ import BellRingIC from '../../../../public/res/ic/outlined/bell-ring.svg';
 | 
			
		|||
import BellPingIC from '../../../../public/res/ic/outlined/bell-ping.svg';
 | 
			
		||||
import BellOffIC from '../../../../public/res/ic/outlined/bell-off.svg';
 | 
			
		||||
import { getNotificationType } from '../../utils/room';
 | 
			
		||||
import { useMatrixClient } from '../../hooks/useMatrixClient';
 | 
			
		||||
 | 
			
		||||
const items = [
 | 
			
		||||
  {
 | 
			
		||||
| 
						 | 
				
			
			@ -38,8 +38,7 @@ const items = [
 | 
			
		|||
  },
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
function setRoomNotifType(roomId, newType) {
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
function setRoomNotifType(mx, roomId, newType) {
 | 
			
		||||
  let roomPushRule;
 | 
			
		||||
  try {
 | 
			
		||||
    roomPushRule = mx.getRoomPushRule('global', roomId);
 | 
			
		||||
| 
						 | 
				
			
			@ -108,7 +107,7 @@ function setRoomNotifType(roomId, newType) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
function useNotifications(roomId) {
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
  const [activeType, setActiveType] = useState(getNotificationType(mx, roomId));
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    setActiveType(getNotificationType(mx, roomId));
 | 
			
		||||
| 
						 | 
				
			
			@ -118,9 +117,9 @@ function useNotifications(roomId) {
 | 
			
		|||
    (item) => {
 | 
			
		||||
      if (item.type === activeType.type) return;
 | 
			
		||||
      setActiveType(item.type);
 | 
			
		||||
      setRoomNotifType(roomId, item.type);
 | 
			
		||||
      setRoomNotifType(mx, roomId, item.type);
 | 
			
		||||
    },
 | 
			
		||||
    [activeType, roomId]
 | 
			
		||||
    [mx, activeType, roomId]
 | 
			
		||||
  );
 | 
			
		||||
  return [activeType, setNotification];
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,7 +2,6 @@ import React, { useEffect } from 'react';
 | 
			
		|||
import PropTypes from 'prop-types';
 | 
			
		||||
import './RoomPermissions.scss';
 | 
			
		||||
 | 
			
		||||
import initMatrix from '../../../client/initMatrix';
 | 
			
		||||
import { getPowerLabel } from '../../../util/matrixUtil';
 | 
			
		||||
import { openReusableContextMenu } from '../../../client/action/navigation';
 | 
			
		||||
import { getEventCords } from '../../../util/common';
 | 
			
		||||
| 
						 | 
				
			
			@ -16,6 +15,7 @@ import SettingTile from '../setting-tile/SettingTile';
 | 
			
		|||
import ChevronBottomIC from '../../../../public/res/ic/outlined/chevron-bottom.svg';
 | 
			
		||||
 | 
			
		||||
import { useForceUpdate } from '../../hooks/useForceUpdate';
 | 
			
		||||
import { useMatrixClient } from '../../hooks/useMatrixClient';
 | 
			
		||||
 | 
			
		||||
const permissionsInfo = {
 | 
			
		||||
  users_default: {
 | 
			
		||||
| 
						 | 
				
			
			@ -157,7 +157,7 @@ const spacePermsGroups = {
 | 
			
		|||
 | 
			
		||||
function useRoomStateUpdate(roomId) {
 | 
			
		||||
  const [, forceUpdate] = useForceUpdate();
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    const handleStateEvent = (event) => {
 | 
			
		||||
| 
						 | 
				
			
			@ -169,12 +169,12 @@ function useRoomStateUpdate(roomId) {
 | 
			
		|||
    return () => {
 | 
			
		||||
      mx.removeListener('RoomState.events', handleStateEvent);
 | 
			
		||||
    };
 | 
			
		||||
  }, [roomId]);
 | 
			
		||||
  }, [mx, roomId]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function RoomPermissions({ roomId }) {
 | 
			
		||||
  useRoomStateUpdate(roomId);
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
  const room = mx.getRoom(roomId);
 | 
			
		||||
  const pLEvent = room.currentState.getStateEvents('m.room.power_levels')[0];
 | 
			
		||||
  const permissions = pLEvent.getContent();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,7 +4,6 @@ import { useAtomValue } from 'jotai';
 | 
			
		|||
import Linkify from 'linkify-react';
 | 
			
		||||
import './RoomProfile.scss';
 | 
			
		||||
 | 
			
		||||
import initMatrix from '../../../client/initMatrix';
 | 
			
		||||
import cons from '../../../client/state/cons';
 | 
			
		||||
import colorMXID from '../../../util/colorMXID';
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -22,6 +21,7 @@ import { useForceUpdate } from '../../hooks/useForceUpdate';
 | 
			
		|||
import { confirmDialog } from '../confirm-dialog/ConfirmDialog';
 | 
			
		||||
import { mDirectAtom } from '../../state/mDirectList';
 | 
			
		||||
import { LINKIFY_OPTS } from '../../plugins/react-custom-html-parser';
 | 
			
		||||
import { useMatrixClient } from '../../hooks/useMatrixClient';
 | 
			
		||||
 | 
			
		||||
function RoomProfile({ roomId }) {
 | 
			
		||||
  const isMountStore = useStore();
 | 
			
		||||
| 
						 | 
				
			
			@ -32,7 +32,7 @@ function RoomProfile({ roomId }) {
 | 
			
		|||
    type: cons.status.PRE_FLIGHT,
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
  const mDirects = useAtomValue(mDirectAtom);
 | 
			
		||||
  const isDM = mDirects.has(roomId);
 | 
			
		||||
  let avatarSrc = mx.getRoom(roomId).getAvatarUrl(mx.baseUrl, 36, 36, 'crop');
 | 
			
		||||
| 
						 | 
				
			
			@ -67,7 +67,7 @@ function RoomProfile({ roomId }) {
 | 
			
		|||
      });
 | 
			
		||||
      setIsEditing(false);
 | 
			
		||||
    };
 | 
			
		||||
  }, [roomId]);
 | 
			
		||||
  }, [mx, roomId]);
 | 
			
		||||
 | 
			
		||||
  const handleOnSubmit = async (e) => {
 | 
			
		||||
    e.preventDefault();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,7 +2,6 @@ import React, { useState, useEffect, useCallback } from 'react';
 | 
			
		|||
import PropTypes from 'prop-types';
 | 
			
		||||
import './RoomVisibility.scss';
 | 
			
		||||
 | 
			
		||||
import initMatrix from '../../../client/initMatrix';
 | 
			
		||||
 | 
			
		||||
import Text from '../../atoms/text/Text';
 | 
			
		||||
import RadioButton from '../../atoms/button/RadioButton';
 | 
			
		||||
| 
						 | 
				
			
			@ -14,6 +13,7 @@ import HashGlobeIC from '../../../../public/res/ic/outlined/hash-globe.svg';
 | 
			
		|||
import SpaceIC from '../../../../public/res/ic/outlined/space.svg';
 | 
			
		||||
import SpaceLockIC from '../../../../public/res/ic/outlined/space-lock.svg';
 | 
			
		||||
import SpaceGlobeIC from '../../../../public/res/ic/outlined/space-globe.svg';
 | 
			
		||||
import { useMatrixClient } from '../../hooks/useMatrixClient';
 | 
			
		||||
 | 
			
		||||
const visibility = {
 | 
			
		||||
  INVITE: 'invite',
 | 
			
		||||
| 
						 | 
				
			
			@ -21,8 +21,7 @@ const visibility = {
 | 
			
		|||
  PUBLIC: 'public',
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
function setJoinRule(roomId, type) {
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
function setJoinRule(mx, roomId, type) {
 | 
			
		||||
  let allow;
 | 
			
		||||
  if (type === visibility.RESTRICTED) {
 | 
			
		||||
    const { currentState } = mx.getRoom(roomId);
 | 
			
		||||
| 
						 | 
				
			
			@ -46,26 +45,26 @@ function setJoinRule(roomId, type) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
function useVisibility(roomId) {
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
  const room = mx.getRoom(roomId);
 | 
			
		||||
 | 
			
		||||
  const [activeType, setActiveType] = useState(room.getJoinRule());
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    setActiveType(room.getJoinRule());
 | 
			
		||||
  }, [roomId]);
 | 
			
		||||
  }, [room]);
 | 
			
		||||
 | 
			
		||||
  const setNotification = useCallback((item) => {
 | 
			
		||||
    if (item.type === activeType.type) return;
 | 
			
		||||
    setActiveType(item.type);
 | 
			
		||||
    setJoinRule(roomId, item.type);
 | 
			
		||||
  }, [activeType, roomId]);
 | 
			
		||||
    setJoinRule(mx, roomId, item.type);
 | 
			
		||||
  }, [mx, activeType, roomId]);
 | 
			
		||||
 | 
			
		||||
  return [activeType, setNotification];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function RoomVisibility({ roomId }) {
 | 
			
		||||
  const [activeType, setVisibility] = useVisibility(roomId);
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
  const room = mx.getRoom(roomId);
 | 
			
		||||
  const isSpace = room.isSpaceRoom();
 | 
			
		||||
  const { currentState } = room;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,7 +3,6 @@ import PropTypes from 'prop-types';
 | 
			
		|||
import { useAtomValue } from 'jotai';
 | 
			
		||||
import './SpaceAddExisting.scss';
 | 
			
		||||
 | 
			
		||||
import initMatrix from '../../../client/initMatrix';
 | 
			
		||||
import cons from '../../../client/state/cons';
 | 
			
		||||
import navigation from '../../../client/state/navigation';
 | 
			
		||||
import { joinRuleToIconSrc, getIdServer, genRoomVia } from '../../../util/matrixUtil';
 | 
			
		||||
| 
						 | 
				
			
			@ -27,6 +26,7 @@ import { roomToParentsAtom } from '../../state/room/roomToParents';
 | 
			
		|||
import { useDirects, useRooms, useSpaces } from '../../state/hooks/roomList';
 | 
			
		||||
import { allRoomsAtom } from '../../state/room-list/roomList';
 | 
			
		||||
import { mDirectAtom } from '../../state/mDirectList';
 | 
			
		||||
import { useMatrixClient } from '../../hooks/useMatrixClient';
 | 
			
		||||
 | 
			
		||||
function SpaceAddExistingContent({ roomId, spaces: onlySpaces }) {
 | 
			
		||||
  const mountStore = useStore(roomId);
 | 
			
		||||
| 
						 | 
				
			
			@ -35,7 +35,7 @@ function SpaceAddExistingContent({ roomId, spaces: onlySpaces }) {
 | 
			
		|||
  const [allRoomIds, setAllRoomIds] = useState([]);
 | 
			
		||||
  const [selected, setSelected] = useState([]);
 | 
			
		||||
  const [searchIds, setSearchIds] = useState(null);
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
  const roomIdToParents = useAtomValue(roomToParentsAtom);
 | 
			
		||||
  const mDirects = useAtomValue(mDirectAtom);
 | 
			
		||||
  const spaces = useSpaces(mx, allRoomsAtom);
 | 
			
		||||
| 
						 | 
				
			
			@ -48,7 +48,7 @@ function SpaceAddExistingContent({ roomId, spaces: onlySpaces }) {
 | 
			
		|||
      (rId) => rId !== roomId && !roomIdToParents.get(rId)?.has(roomId)
 | 
			
		||||
    );
 | 
			
		||||
    setAllRoomIds(allIds);
 | 
			
		||||
  }, [roomId, onlySpaces]);
 | 
			
		||||
  }, [spaces, rooms, directs, roomIdToParents, roomId, onlySpaces]);
 | 
			
		||||
 | 
			
		||||
  const toggleSelection = (rId) => {
 | 
			
		||||
    if (process !== null) return;
 | 
			
		||||
| 
						 | 
				
			
			@ -215,7 +215,7 @@ function useVisibilityToggle() {
 | 
			
		|||
 | 
			
		||||
function SpaceAddExisting() {
 | 
			
		||||
  const [data, requestClose] = useVisibilityToggle();
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
  const room = mx.getRoom(data?.roomId);
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,7 +2,6 @@ import React, { useState, useEffect, useRef } from 'react';
 | 
			
		|||
import PropTypes from 'prop-types';
 | 
			
		||||
import './CreateRoom.scss';
 | 
			
		||||
 | 
			
		||||
import initMatrix from '../../../client/initMatrix';
 | 
			
		||||
import cons from '../../../client/state/cons';
 | 
			
		||||
import navigation from '../../../client/state/navigation';
 | 
			
		||||
import { openReusableContextMenu } from '../../../client/action/navigation';
 | 
			
		||||
| 
						 | 
				
			
			@ -32,6 +31,7 @@ import SpaceGlobeIC from '../../../../public/res/ic/outlined/space-globe.svg';
 | 
			
		|||
import ChevronBottomIC from '../../../../public/res/ic/outlined/chevron-bottom.svg';
 | 
			
		||||
import CrossIC from '../../../../public/res/ic/outlined/cross.svg';
 | 
			
		||||
import { useRoomNavigate } from '../../hooks/useRoomNavigate';
 | 
			
		||||
import { useMatrixClient } from '../../hooks/useMatrixClient';
 | 
			
		||||
 | 
			
		||||
function CreateRoomContent({ isSpace, parentId, onRequestClose }) {
 | 
			
		||||
  const [joinRule, setJoinRule] = useState(parentId ? 'restricted' : 'invite');
 | 
			
		||||
| 
						 | 
				
			
			@ -46,7 +46,7 @@ function CreateRoomContent({ isSpace, parentId, onRequestClose }) {
 | 
			
		|||
 | 
			
		||||
  const addressRef = useRef(null);
 | 
			
		||||
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
  const userHs = getIdServer(mx.getUserId());
 | 
			
		||||
 | 
			
		||||
  const handleSubmit = async (evt) => {
 | 
			
		||||
| 
						 | 
				
			
			@ -69,7 +69,7 @@ function CreateRoomContent({ isSpace, parentId, onRequestClose }) {
 | 
			
		|||
    const powerLevel = roleIndex === 1 ? 101 : undefined;
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
      const data = await roomActions.createRoom({
 | 
			
		||||
      const data = await roomActions.createRoom(mx, {
 | 
			
		||||
        name,
 | 
			
		||||
        topic,
 | 
			
		||||
        joinRule,
 | 
			
		||||
| 
						 | 
				
			
			@ -113,7 +113,7 @@ function CreateRoomContent({ isSpace, parentId, onRequestClose }) {
 | 
			
		|||
      if (roomAlias === '') return;
 | 
			
		||||
      const roomAddress = `#${roomAlias}:${userHs}`;
 | 
			
		||||
 | 
			
		||||
      if (await isRoomAliasAvailable(roomAddress)) {
 | 
			
		||||
      if (await isRoomAliasAvailable(mx, roomAddress)) {
 | 
			
		||||
        setIsValidAddress(true);
 | 
			
		||||
      } else {
 | 
			
		||||
        setIsValidAddress(false);
 | 
			
		||||
| 
						 | 
				
			
			@ -278,7 +278,7 @@ function useWindowToggle() {
 | 
			
		|||
function CreateRoom() {
 | 
			
		||||
  const [create, onRequestClose] = useWindowToggle();
 | 
			
		||||
  const { isSpace, parentId } = create ?? {};
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
  const room = mx.getRoom(parentId);
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,7 +3,6 @@ import React, { useState, useEffect } from 'react';
 | 
			
		|||
import PropTypes from 'prop-types';
 | 
			
		||||
import './EmojiVerification.scss';
 | 
			
		||||
 | 
			
		||||
import initMatrix from '../../../client/initMatrix';
 | 
			
		||||
import cons from '../../../client/state/cons';
 | 
			
		||||
import navigation from '../../../client/state/navigation';
 | 
			
		||||
import { hasPrivateKey } from '../../../client/state/secretStorageKeys';
 | 
			
		||||
| 
						 | 
				
			
			@ -18,23 +17,24 @@ import Dialog from '../../molecules/dialog/Dialog';
 | 
			
		|||
import CrossIC from '../../../../public/res/ic/outlined/cross.svg';
 | 
			
		||||
import { useStore } from '../../hooks/useStore';
 | 
			
		||||
import { accessSecretStorage } from '../settings/SecretStorageAccess';
 | 
			
		||||
import { useMatrixClient } from '../../hooks/useMatrixClient';
 | 
			
		||||
 | 
			
		||||
function EmojiVerificationContent({ data, requestClose }) {
 | 
			
		||||
  const [sas, setSas] = useState(null);
 | 
			
		||||
  const [process, setProcess] = useState(false);
 | 
			
		||||
  const { request, targetDevice } = data;
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
  const mountStore = useStore();
 | 
			
		||||
  const beginStore = useStore();
 | 
			
		||||
 | 
			
		||||
  const beginVerification = async () => {
 | 
			
		||||
    if (
 | 
			
		||||
      isCrossVerified(mx.deviceId) &&
 | 
			
		||||
      isCrossVerified(mx, mx.deviceId) &&
 | 
			
		||||
      (mx.getCrossSigningId() === null ||
 | 
			
		||||
        (await mx.crypto.crossSigningInfo.isStoredInKeyCache('self_signing')) === false)
 | 
			
		||||
    ) {
 | 
			
		||||
      if (!hasPrivateKey(getDefaultSSKey())) {
 | 
			
		||||
        const keyData = await accessSecretStorage('Emoji verification');
 | 
			
		||||
      if (!hasPrivateKey(getDefaultSSKey(mx))) {
 | 
			
		||||
        const keyData = await accessSecretStorage(mx, 'Emoji verification');
 | 
			
		||||
        if (!keyData) {
 | 
			
		||||
          request.cancel();
 | 
			
		||||
          return;
 | 
			
		||||
| 
						 | 
				
			
			@ -158,7 +158,7 @@ EmojiVerificationContent.propTypes = {
 | 
			
		|||
 | 
			
		||||
function useVisibilityToggle() {
 | 
			
		||||
  const [data, setData] = useState(null);
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    const handleOpen = (request, targetDevice) => {
 | 
			
		||||
| 
						 | 
				
			
			@ -170,7 +170,7 @@ function useVisibilityToggle() {
 | 
			
		|||
      navigation.removeListener(cons.events.navigation.EMOJI_VERIFICATION_OPENED, handleOpen);
 | 
			
		||||
      mx.removeListener('crypto.verification.request', handleOpen);
 | 
			
		||||
    };
 | 
			
		||||
  }, []);
 | 
			
		||||
  }, [mx]);
 | 
			
		||||
 | 
			
		||||
  const requestClose = () => setData(null);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,7 +2,6 @@ import React, { useState, useEffect, useRef } from 'react';
 | 
			
		|||
import PropTypes from 'prop-types';
 | 
			
		||||
import './InviteUser.scss';
 | 
			
		||||
 | 
			
		||||
import initMatrix from '../../../client/initMatrix';
 | 
			
		||||
import * as roomActions from '../../../client/action/room';
 | 
			
		||||
import { hasDevices } from '../../../util/matrixUtil';
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -18,6 +17,7 @@ import CrossIC from '../../../../public/res/ic/outlined/cross.svg';
 | 
			
		|||
import UserIC from '../../../../public/res/ic/outlined/user.svg';
 | 
			
		||||
import { useRoomNavigate } from '../../hooks/useRoomNavigate';
 | 
			
		||||
import { getDMRoomFor } from '../../utils/matrix';
 | 
			
		||||
import { useMatrixClient } from '../../hooks/useMatrixClient';
 | 
			
		||||
 | 
			
		||||
function InviteUser({ isOpen, roomId, searchTerm, onRequestClose }) {
 | 
			
		||||
  const [isSearching, updateIsSearching] = useState(false);
 | 
			
		||||
| 
						 | 
				
			
			@ -34,7 +34,7 @@ function InviteUser({ isOpen, roomId, searchTerm, onRequestClose }) {
 | 
			
		|||
 | 
			
		||||
  const usernameRef = useRef(null);
 | 
			
		||||
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
  const { navigateRoom } = useRoomNavigate();
 | 
			
		||||
 | 
			
		||||
  function getMapCopy(myMap) {
 | 
			
		||||
| 
						 | 
				
			
			@ -118,7 +118,7 @@ function InviteUser({ isOpen, roomId, searchTerm, onRequestClose }) {
 | 
			
		|||
      procUserError.delete(userId);
 | 
			
		||||
      updateUserProcError(getMapCopy(procUserError));
 | 
			
		||||
 | 
			
		||||
      const result = await roomActions.createDM(userId, await hasDevices(userId));
 | 
			
		||||
      const result = await roomActions.createDM(mx, userId, await hasDevices(mx, userId));
 | 
			
		||||
      roomIdToUserId.set(result.room_id, userId);
 | 
			
		||||
      updateRoomIdToUserId(getMapCopy(roomIdToUserId));
 | 
			
		||||
      onDMCreated(result.room_id);
 | 
			
		||||
| 
						 | 
				
			
			@ -137,7 +137,7 @@ function InviteUser({ isOpen, roomId, searchTerm, onRequestClose }) {
 | 
			
		|||
      procUserError.delete(userId);
 | 
			
		||||
      updateUserProcError(getMapCopy(procUserError));
 | 
			
		||||
 | 
			
		||||
      await roomActions.invite(roomId, userId);
 | 
			
		||||
      await mx.invite(roomId, userId);
 | 
			
		||||
 | 
			
		||||
      invitedUserIds.add(userId);
 | 
			
		||||
      updateInvitedUserIds(new Set(Array.from(invitedUserIds)));
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,7 +2,6 @@ import React, { useState, useEffect } from 'react';
 | 
			
		|||
import PropTypes from 'prop-types';
 | 
			
		||||
import './JoinAlias.scss';
 | 
			
		||||
 | 
			
		||||
import initMatrix from '../../../client/initMatrix';
 | 
			
		||||
import cons from '../../../client/state/cons';
 | 
			
		||||
import navigation from '../../../client/state/navigation';
 | 
			
		||||
import { join } from '../../../client/action/room';
 | 
			
		||||
| 
						 | 
				
			
			@ -18,6 +17,7 @@ import CrossIC from '../../../../public/res/ic/outlined/cross.svg';
 | 
			
		|||
 | 
			
		||||
import { useStore } from '../../hooks/useStore';
 | 
			
		||||
import { useRoomNavigate } from '../../hooks/useRoomNavigate';
 | 
			
		||||
import { useMatrixClient } from '../../hooks/useMatrixClient';
 | 
			
		||||
 | 
			
		||||
const ALIAS_OR_ID_REG = /^[#|!].+:.+\..+$/;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -25,7 +25,7 @@ function JoinAliasContent({ term, requestClose }) {
 | 
			
		|||
  const [process, setProcess] = useState(false);
 | 
			
		||||
  const [error, setError] = useState(undefined);
 | 
			
		||||
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
  const mountStore = useStore();
 | 
			
		||||
 | 
			
		||||
  const { navigateRoom } = useRoomNavigate();
 | 
			
		||||
| 
						 | 
				
			
			@ -63,7 +63,7 @@ function JoinAliasContent({ term, requestClose }) {
 | 
			
		|||
      }
 | 
			
		||||
    }
 | 
			
		||||
    try {
 | 
			
		||||
      const roomId = await join(alias, false, via);
 | 
			
		||||
      const roomId = await join(mx, alias, false, via);
 | 
			
		||||
      if (!mountStore.getItem()) return;
 | 
			
		||||
      openRoom(roomId);
 | 
			
		||||
    } catch {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,7 +1,6 @@
 | 
			
		|||
import React, { useState, useEffect, useRef } from 'react';
 | 
			
		||||
import PropTypes from 'prop-types';
 | 
			
		||||
 | 
			
		||||
import initMatrix from '../../../client/initMatrix';
 | 
			
		||||
import colorMXID from '../../../util/colorMXID';
 | 
			
		||||
 | 
			
		||||
import Text from '../../atoms/text/Text';
 | 
			
		||||
| 
						 | 
				
			
			@ -14,10 +13,11 @@ import PencilIC from '../../../../public/res/ic/outlined/pencil.svg';
 | 
			
		|||
import { confirmDialog } from '../../molecules/confirm-dialog/ConfirmDialog';
 | 
			
		||||
 | 
			
		||||
import './ProfileEditor.scss';
 | 
			
		||||
import { useMatrixClient } from '../../hooks/useMatrixClient';
 | 
			
		||||
 | 
			
		||||
function ProfileEditor({ userId }) {
 | 
			
		||||
  const [isEditing, setIsEditing] = useState(false);
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
  const user = mx.getUser(mx.getUserId());
 | 
			
		||||
 | 
			
		||||
  const displayNameRef = useRef(null);
 | 
			
		||||
| 
						 | 
				
			
			@ -37,7 +37,7 @@ function ProfileEditor({ userId }) {
 | 
			
		|||
    return () => {
 | 
			
		||||
      isMounted = false;
 | 
			
		||||
    };
 | 
			
		||||
  }, [userId]);
 | 
			
		||||
  }, [mx, userId]);
 | 
			
		||||
 | 
			
		||||
  const handleAvatarUpload = async (url) => {
 | 
			
		||||
    if (url === null) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,7 +2,6 @@ import React, { useState, useEffect, useRef } from 'react';
 | 
			
		|||
import PropTypes from 'prop-types';
 | 
			
		||||
import './ProfileViewer.scss';
 | 
			
		||||
 | 
			
		||||
import initMatrix from '../../../client/initMatrix';
 | 
			
		||||
import cons from '../../../client/state/cons';
 | 
			
		||||
import navigation from '../../../client/state/navigation';
 | 
			
		||||
import { openReusableContextMenu } from '../../../client/action/navigation';
 | 
			
		||||
| 
						 | 
				
			
			@ -36,9 +35,10 @@ import { useForceUpdate } from '../../hooks/useForceUpdate';
 | 
			
		|||
import { confirmDialog } from '../../molecules/confirm-dialog/ConfirmDialog';
 | 
			
		||||
import { useRoomNavigate } from '../../hooks/useRoomNavigate';
 | 
			
		||||
import { getDMRoomFor } from '../../utils/matrix';
 | 
			
		||||
import { useMatrixClient } from '../../hooks/useMatrixClient';
 | 
			
		||||
 | 
			
		||||
function ModerationTools({ roomId, userId }) {
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
  const room = mx.getRoom(roomId);
 | 
			
		||||
  const roomMember = room.getMember(userId);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -56,13 +56,13 @@ function ModerationTools({ roomId, userId }) {
 | 
			
		|||
  const handleKick = (e) => {
 | 
			
		||||
    e.preventDefault();
 | 
			
		||||
    const kickReason = e.target.elements['kick-reason']?.value.trim();
 | 
			
		||||
    roomActions.kick(roomId, userId, kickReason !== '' ? kickReason : undefined);
 | 
			
		||||
    mx.kick(roomId, userId, kickReason !== '' ? kickReason : undefined);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const handleBan = (e) => {
 | 
			
		||||
    e.preventDefault();
 | 
			
		||||
    const banReason = e.target.elements['ban-reason']?.value.trim();
 | 
			
		||||
    roomActions.ban(roomId, userId, banReason !== '' ? banReason : undefined);
 | 
			
		||||
    mx.ban(roomId, userId, banReason !== '' ? banReason : undefined);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
| 
						 | 
				
			
			@ -90,7 +90,7 @@ ModerationTools.propTypes = {
 | 
			
		|||
function SessionInfo({ userId }) {
 | 
			
		||||
  const [devices, setDevices] = useState(null);
 | 
			
		||||
  const [isVisible, setIsVisible] = useState(false);
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    let isUnmounted = false;
 | 
			
		||||
| 
						 | 
				
			
			@ -111,7 +111,7 @@ function SessionInfo({ userId }) {
 | 
			
		|||
    return () => {
 | 
			
		||||
      isUnmounted = true;
 | 
			
		||||
    };
 | 
			
		||||
  }, [userId]);
 | 
			
		||||
  }, [mx, userId]);
 | 
			
		||||
 | 
			
		||||
  function renderSessionChips() {
 | 
			
		||||
    if (!isVisible) return null;
 | 
			
		||||
| 
						 | 
				
			
			@ -139,7 +139,7 @@ function SessionInfo({ userId }) {
 | 
			
		|||
      >
 | 
			
		||||
        <Text variant="b2">{`View ${
 | 
			
		||||
          devices?.length > 0
 | 
			
		||||
            ? `${devices.length} ${devices.length == 1 ? 'session' : 'sessions'}`
 | 
			
		||||
            ? `${devices.length} ${devices.length === 1 ? 'session' : 'sessions'}`
 | 
			
		||||
            : 'sessions'
 | 
			
		||||
        }`}</Text>
 | 
			
		||||
      </MenuItem>
 | 
			
		||||
| 
						 | 
				
			
			@ -155,10 +155,10 @@ SessionInfo.propTypes = {
 | 
			
		|||
function ProfileFooter({ roomId, userId, onRequestClose }) {
 | 
			
		||||
  const [isCreatingDM, setIsCreatingDM] = useState(false);
 | 
			
		||||
  const [isIgnoring, setIsIgnoring] = useState(false);
 | 
			
		||||
  const [isUserIgnored, setIsUserIgnored] = useState(initMatrix.matrixClient.isUserIgnored(userId));
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
  const [isUserIgnored, setIsUserIgnored] = useState(mx.isUserIgnored(userId));
 | 
			
		||||
 | 
			
		||||
  const isMountedRef = useRef(true);
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
  const { navigateRoom } = useRoomNavigate();
 | 
			
		||||
  const room = mx.getRoom(roomId);
 | 
			
		||||
  const member = room.getMember(userId);
 | 
			
		||||
| 
						 | 
				
			
			@ -182,10 +182,10 @@ function ProfileFooter({ roomId, userId, onRequestClose }) {
 | 
			
		|||
  };
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    setIsUserIgnored(initMatrix.matrixClient.isUserIgnored(userId));
 | 
			
		||||
    setIsUserIgnored(mx.isUserIgnored(userId));
 | 
			
		||||
    setIsIgnoring(false);
 | 
			
		||||
    setIsInviting(false);
 | 
			
		||||
  }, [userId]);
 | 
			
		||||
  }, [mx, userId]);
 | 
			
		||||
 | 
			
		||||
  const openDM = async () => {
 | 
			
		||||
    // Check and open if user already have a DM with userId.
 | 
			
		||||
| 
						 | 
				
			
			@ -199,7 +199,7 @@ function ProfileFooter({ roomId, userId, onRequestClose }) {
 | 
			
		|||
    // Create new DM
 | 
			
		||||
    try {
 | 
			
		||||
      setIsCreatingDM(true);
 | 
			
		||||
      const result = await roomActions.createDM(userId, await hasDevices(userId));
 | 
			
		||||
      const result = await roomActions.createDM(mx, userId, await hasDevices(mx, userId));
 | 
			
		||||
      onCreated(result.room_id);
 | 
			
		||||
    } catch {
 | 
			
		||||
      if (isMountedRef.current === false) return;
 | 
			
		||||
| 
						 | 
				
			
			@ -213,9 +213,9 @@ function ProfileFooter({ roomId, userId, onRequestClose }) {
 | 
			
		|||
    try {
 | 
			
		||||
      setIsIgnoring(true);
 | 
			
		||||
      if (isIgnored) {
 | 
			
		||||
        await roomActions.unignore([userId]);
 | 
			
		||||
        await roomActions.unignore(mx, [userId]);
 | 
			
		||||
      } else {
 | 
			
		||||
        await roomActions.ignore([userId]);
 | 
			
		||||
        await roomActions.ignore(mx, [userId]);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (isMountedRef.current === false) return;
 | 
			
		||||
| 
						 | 
				
			
			@ -230,9 +230,9 @@ function ProfileFooter({ roomId, userId, onRequestClose }) {
 | 
			
		|||
    try {
 | 
			
		||||
      setIsInviting(true);
 | 
			
		||||
      let isInviteSent = false;
 | 
			
		||||
      if (isInvited) await roomActions.kick(roomId, userId);
 | 
			
		||||
      if (isInvited) await mx.kick(roomId, userId);
 | 
			
		||||
      else {
 | 
			
		||||
        await roomActions.invite(roomId, userId);
 | 
			
		||||
        await mx.invite(roomId, userId);
 | 
			
		||||
        isInviteSent = true;
 | 
			
		||||
      }
 | 
			
		||||
      if (isMountedRef.current === false) return;
 | 
			
		||||
| 
						 | 
				
			
			@ -249,7 +249,7 @@ function ProfileFooter({ roomId, userId, onRequestClose }) {
 | 
			
		|||
        {isCreatingDM ? 'Creating room...' : 'Message'}
 | 
			
		||||
      </Button>
 | 
			
		||||
      {isBanned && canIKick && (
 | 
			
		||||
        <Button variant="positive" onClick={() => roomActions.unban(roomId, userId)}>
 | 
			
		||||
        <Button variant="positive" onClick={() => mx.unban(roomId, userId)}>
 | 
			
		||||
          Unban
 | 
			
		||||
        </Button>
 | 
			
		||||
      )}
 | 
			
		||||
| 
						 | 
				
			
			@ -306,7 +306,7 @@ function useToggleDialog() {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
function useRerenderOnProfileChange(roomId, userId) {
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
  const [, forceUpdate] = useForceUpdate();
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    const handleProfileChange = (mEvent, member) => {
 | 
			
		||||
| 
						 | 
				
			
			@ -323,19 +323,19 @@ function useRerenderOnProfileChange(roomId, userId) {
 | 
			
		|||
      mx.removeListener('RoomMember.powerLevel', handleProfileChange);
 | 
			
		||||
      mx.removeListener('RoomMember.membership', handleProfileChange);
 | 
			
		||||
    };
 | 
			
		||||
  }, [roomId, userId]);
 | 
			
		||||
  }, [mx, roomId, userId]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function ProfileViewer() {
 | 
			
		||||
  const [isOpen, roomId, userId, closeDialog, handleAfterClose] = useToggleDialog();
 | 
			
		||||
  useRerenderOnProfileChange(roomId, userId);
 | 
			
		||||
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
  const room = mx.getRoom(roomId);
 | 
			
		||||
 | 
			
		||||
  const renderProfile = () => {
 | 
			
		||||
    const roomMember = room.getMember(userId);
 | 
			
		||||
    const username = roomMember ? getUsernameOfRoomMember(roomMember) : getUsername(userId);
 | 
			
		||||
    const username = roomMember ? getUsernameOfRoomMember(roomMember) : getUsername(mx, userId);
 | 
			
		||||
    const avatarMxc = roomMember?.getMxcAvatarUrl?.() || mx.getUser(userId)?.avatarUrl;
 | 
			
		||||
    const avatarUrl =
 | 
			
		||||
      avatarMxc && avatarMxc !== 'null' ? mx.mxcUrlToHttp(avatarMxc, 80, 80, 'crop') : null;
 | 
			
		||||
| 
						 | 
				
			
			@ -364,9 +364,9 @@ function ProfileViewer() {
 | 
			
		|||
          'caution'
 | 
			
		||||
        );
 | 
			
		||||
        if (!isConfirmed) return;
 | 
			
		||||
        roomActions.setPowerLevel(roomId, userId, newPowerLevel);
 | 
			
		||||
        roomActions.setPowerLevel(mx, roomId, userId, newPowerLevel);
 | 
			
		||||
      } else {
 | 
			
		||||
        roomActions.setPowerLevel(roomId, userId, newPowerLevel);
 | 
			
		||||
        roomActions.setPowerLevel(mx, roomId, userId, newPowerLevel);
 | 
			
		||||
      }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,7 +2,6 @@ import React, { useState, useEffect } from 'react';
 | 
			
		|||
import PropTypes from 'prop-types';
 | 
			
		||||
import './RoomSettings.scss';
 | 
			
		||||
 | 
			
		||||
import initMatrix from '../../../client/initMatrix';
 | 
			
		||||
import cons from '../../../client/state/cons';
 | 
			
		||||
import navigation from '../../../client/state/navigation';
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -30,6 +29,7 @@ import CrossIC from '../../../../public/res/ic/outlined/cross.svg';
 | 
			
		|||
import { confirmDialog } from '../../molecules/confirm-dialog/ConfirmDialog';
 | 
			
		||||
import PopupWindow from '../../molecules/popup-window/PopupWindow';
 | 
			
		||||
import IconButton from '../../atoms/button/IconButton';
 | 
			
		||||
import { useMatrixClient } from '../../hooks/useMatrixClient';
 | 
			
		||||
 | 
			
		||||
const tabText = {
 | 
			
		||||
  GENERAL: 'General',
 | 
			
		||||
| 
						 | 
				
			
			@ -68,7 +68,7 @@ const tabItems = [
 | 
			
		|||
];
 | 
			
		||||
 | 
			
		||||
function GeneralSettings({ roomId }) {
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
  const room = mx.getRoom(roomId);
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
| 
						 | 
				
			
			@ -155,7 +155,8 @@ function RoomSettings() {
 | 
			
		|||
  const [window, requestClose] = useWindowToggle(setSelectedTab);
 | 
			
		||||
  const isOpen = window !== null;
 | 
			
		||||
  const roomId = window?.roomId;
 | 
			
		||||
  const room = initMatrix.matrixClient.getRoom(roomId);
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
  const room = mx.getRoom(roomId);
 | 
			
		||||
 | 
			
		||||
  const handleTabChange = (tabItem) => {
 | 
			
		||||
    setSelectedTab(tabItem);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,12 +2,10 @@ import React, { useState, useEffect, useRef, useCallback } from 'react';
 | 
			
		|||
import { useAtomValue } from 'jotai';
 | 
			
		||||
import './Search.scss';
 | 
			
		||||
 | 
			
		||||
import initMatrix from '../../../client/initMatrix';
 | 
			
		||||
import cons from '../../../client/state/cons';
 | 
			
		||||
import navigation from '../../../client/state/navigation';
 | 
			
		||||
import AsyncSearch from '../../../util/AsyncSearch';
 | 
			
		||||
import { joinRuleToIconSrc } from '../../../util/matrixUtil';
 | 
			
		||||
import { roomIdByActivity } from '../../../util/sort';
 | 
			
		||||
 | 
			
		||||
import Text from '../../atoms/text/Text';
 | 
			
		||||
import RawIcon from '../../atoms/system-icons/RawIcon';
 | 
			
		||||
| 
						 | 
				
			
			@ -27,6 +25,8 @@ import { allRoomsAtom } from '../../state/room-list/roomList';
 | 
			
		|||
import { mDirectAtom } from '../../state/mDirectList';
 | 
			
		||||
import { useKeyDown } from '../../hooks/useKeyDown';
 | 
			
		||||
import { openSearch } from '../../../client/action/navigation';
 | 
			
		||||
import { useMatrixClient } from '../../hooks/useMatrixClient';
 | 
			
		||||
import { factoryRoomIdByActivity } from '../../utils/sort';
 | 
			
		||||
 | 
			
		||||
function useVisiblityToggle(setResult) {
 | 
			
		||||
  const [isOpen, setIsOpen] = useState(false);
 | 
			
		||||
| 
						 | 
				
			
			@ -77,9 +77,7 @@ function useVisiblityToggle(setResult) {
 | 
			
		|||
  return [isOpen, requestClose];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function mapRoomIds(roomIds, directs, roomIdToParents) {
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
 | 
			
		||||
function mapRoomIds(mx, roomIds, directs, roomIdToParents) {
 | 
			
		||||
  return roomIds.map((roomId) => {
 | 
			
		||||
    const room = mx.getRoom(roomId);
 | 
			
		||||
    const parentSet = roomIdToParents.get(roomId);
 | 
			
		||||
| 
						 | 
				
			
			@ -107,7 +105,7 @@ function Search() {
 | 
			
		|||
  const [asyncSearch] = useState(new AsyncSearch());
 | 
			
		||||
  const [isOpen, requestClose] = useVisiblityToggle(setResult);
 | 
			
		||||
  const searchRef = useRef(null);
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
  const { navigateRoom, navigateSpace } = useRoomNavigate();
 | 
			
		||||
  const mDirects = useAtomValue(mDirectAtom);
 | 
			
		||||
  const spaces = useSpaces(mx, allRoomsAtom);
 | 
			
		||||
| 
						 | 
				
			
			@ -141,8 +139,8 @@ function Search() {
 | 
			
		|||
      ids = [...rooms].concat([...directs], [...spaces]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ids.sort(roomIdByActivity);
 | 
			
		||||
    const mappedIds = mapRoomIds(ids, directs, roomToParents);
 | 
			
		||||
    ids.sort(factoryRoomIdByActivity(mx));
 | 
			
		||||
    const mappedIds = mapRoomIds(mx, ids, directs, roomToParents);
 | 
			
		||||
    asyncSearch.setup(mappedIds, { keys: 'name', isContain: true, limit: 20 });
 | 
			
		||||
    if (prefix) handleSearchResults(mappedIds, prefix);
 | 
			
		||||
    else asyncSearch.search(term);
 | 
			
		||||
| 
						 | 
				
			
			@ -150,7 +148,7 @@ function Search() {
 | 
			
		|||
 | 
			
		||||
  const loadRecentRooms = () => {
 | 
			
		||||
    const recentRooms = [];
 | 
			
		||||
    handleSearchResults(mapRoomIds(recentRooms, directs, roomToParents).reverse());
 | 
			
		||||
    handleSearchResults(mapRoomIds(mx, recentRooms, directs, roomToParents).reverse());
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const handleAfterOpen = () => {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,7 +2,6 @@ import React, { useState } from 'react';
 | 
			
		|||
import PropTypes from 'prop-types';
 | 
			
		||||
import './AuthRequest.scss';
 | 
			
		||||
 | 
			
		||||
import initMatrix from '../../../client/initMatrix';
 | 
			
		||||
import { openReusableDialog } from '../../../client/action/navigation';
 | 
			
		||||
 | 
			
		||||
import Text from '../../atoms/text/Text';
 | 
			
		||||
| 
						 | 
				
			
			@ -11,6 +10,7 @@ import Input from '../../atoms/input/Input';
 | 
			
		|||
import Spinner from '../../atoms/spinner/Spinner';
 | 
			
		||||
 | 
			
		||||
import { useStore } from '../../hooks/useStore';
 | 
			
		||||
import { getSecret } from '../../../client/state/auth';
 | 
			
		||||
 | 
			
		||||
let lastUsedPassword;
 | 
			
		||||
const getAuthId = (password) => ({
 | 
			
		||||
| 
						 | 
				
			
			@ -18,7 +18,7 @@ const getAuthId = (password) => ({
 | 
			
		|||
  password,
 | 
			
		||||
  identifier: {
 | 
			
		||||
    type: 'm.id.user',
 | 
			
		||||
    user: initMatrix.matrixClient.getUserId(),
 | 
			
		||||
    user: getSecret().userId,
 | 
			
		||||
  },
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,7 +4,6 @@ import './CrossSigning.scss';
 | 
			
		|||
import FileSaver from 'file-saver';
 | 
			
		||||
import { Formik } from 'formik';
 | 
			
		||||
 | 
			
		||||
import initMatrix from '../../../client/initMatrix';
 | 
			
		||||
import { openReusableDialog } from '../../../client/action/navigation';
 | 
			
		||||
import { copyToClipboard } from '../../../util/common';
 | 
			
		||||
import { clearSecretStorageKeys } from '../../../client/state/secretStorageKeys';
 | 
			
		||||
| 
						 | 
				
			
			@ -17,6 +16,7 @@ import SettingTile from '../../molecules/setting-tile/SettingTile';
 | 
			
		|||
 | 
			
		||||
import { authRequest } from './AuthRequest';
 | 
			
		||||
import { useCrossSigningStatus } from '../../hooks/useCrossSigningStatus';
 | 
			
		||||
import { useMatrixClient } from '../../hooks/useMatrixClient';
 | 
			
		||||
 | 
			
		||||
const failedDialog = () => {
 | 
			
		||||
  const renderFailure = (requestClose) => (
 | 
			
		||||
| 
						 | 
				
			
			@ -73,9 +73,9 @@ const securityKeyDialog = (key) => {
 | 
			
		|||
function CrossSigningSetup() {
 | 
			
		||||
  const initialValues = { phrase: '', confirmPhrase: '' };
 | 
			
		||||
  const [genWithPhrase, setGenWithPhrase] = useState(undefined);
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
 | 
			
		||||
  const setup = async (securityPhrase = undefined) => {
 | 
			
		||||
    const mx = initMatrix.matrixClient;
 | 
			
		||||
    setGenWithPhrase(typeof securityPhrase === 'string');
 | 
			
		||||
    const recoveryKey = await mx.createRecoveryKeyFromPassphrase(securityPhrase);
 | 
			
		||||
    clearSecretStorageKeys();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,7 +2,6 @@ import React, { useState, useEffect } from 'react';
 | 
			
		|||
import './DeviceManage.scss';
 | 
			
		||||
import dateFormat from 'dateformat';
 | 
			
		||||
 | 
			
		||||
import initMatrix from '../../../client/initMatrix';
 | 
			
		||||
import { isCrossVerified } from '../../../util/matrixUtil';
 | 
			
		||||
import { openReusableDialog, openEmojiVerification } from '../../../client/action/navigation';
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -26,6 +25,7 @@ import { useStore } from '../../hooks/useStore';
 | 
			
		|||
import { useDeviceList } from '../../hooks/useDeviceList';
 | 
			
		||||
import { useCrossSigningStatus } from '../../hooks/useCrossSigningStatus';
 | 
			
		||||
import { accessSecretStorage } from './SecretStorageAccess';
 | 
			
		||||
import { useMatrixClient } from '../../hooks/useMatrixClient';
 | 
			
		||||
 | 
			
		||||
const promptDeviceName = async (deviceName) => new Promise((resolve) => {
 | 
			
		||||
  let isCompleted = false;
 | 
			
		||||
| 
						 | 
				
			
			@ -63,14 +63,14 @@ const promptDeviceName = async (deviceName) => new Promise((resolve) => {
 | 
			
		|||
 | 
			
		||||
function DeviceManage() {
 | 
			
		||||
  const TRUNCATED_COUNT = 4;
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
  const isCSEnabled = useCrossSigningStatus();
 | 
			
		||||
  const deviceList = useDeviceList();
 | 
			
		||||
  const [processing, setProcessing] = useState([]);
 | 
			
		||||
  const [truncated, setTruncated] = useState(true);
 | 
			
		||||
  const mountStore = useStore();
 | 
			
		||||
  mountStore.setItem(true);
 | 
			
		||||
  const isMeVerified = isCrossVerified(mx.deviceId);
 | 
			
		||||
  const isMeVerified = isCrossVerified(mx, mx.deviceId);
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    setProcessing([]);
 | 
			
		||||
| 
						 | 
				
			
			@ -130,7 +130,7 @@ function DeviceManage() {
 | 
			
		|||
  };
 | 
			
		||||
 | 
			
		||||
  const verifyWithKey = async (device) => {
 | 
			
		||||
    const keyData = await accessSecretStorage('Session verification');
 | 
			
		||||
    const keyData = await accessSecretStorage(mx, 'Session verification');
 | 
			
		||||
    if (!keyData) return;
 | 
			
		||||
    addToProcessing(device);
 | 
			
		||||
    await mx.checkOwnCrossSigningTrust();
 | 
			
		||||
| 
						 | 
				
			
			@ -191,7 +191,7 @@ function DeviceManage() {
 | 
			
		|||
            )}
 | 
			
		||||
            {isCurrentDevice && (
 | 
			
		||||
              <Text style={{ marginTop: 'var(--sp-ultra-tight)' }} variant="b3">
 | 
			
		||||
                {`Session Key: ${initMatrix.matrixClient.getDeviceEd25519Key().match(/.{1,4}/g).join(' ')}`}
 | 
			
		||||
                {`Session Key: ${mx.getDeviceEd25519Key().match(/.{1,4}/g).join(' ')}`}
 | 
			
		||||
              </Text>
 | 
			
		||||
            )}
 | 
			
		||||
          </>
 | 
			
		||||
| 
						 | 
				
			
			@ -204,7 +204,7 @@ function DeviceManage() {
 | 
			
		|||
  const verified = [];
 | 
			
		||||
  const noEncryption = [];
 | 
			
		||||
  deviceList.sort((a, b) => b.last_seen_ts - a.last_seen_ts).forEach((device) => {
 | 
			
		||||
    const isVerified = isCrossVerified(device.device_id);
 | 
			
		||||
    const isVerified = isCrossVerified(mx, device.device_id);
 | 
			
		||||
    if (isVerified === true) {
 | 
			
		||||
      verified.push(device);
 | 
			
		||||
    } else if (isVerified === false) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,7 +3,6 @@ import React, { useState, useEffect } from 'react';
 | 
			
		|||
import PropTypes from 'prop-types';
 | 
			
		||||
import './KeyBackup.scss';
 | 
			
		||||
 | 
			
		||||
import initMatrix from '../../../client/initMatrix';
 | 
			
		||||
import { openReusableDialog } from '../../../client/action/navigation';
 | 
			
		||||
import { deletePrivateKey } from '../../../client/state/secretStorageKeys';
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -22,10 +21,11 @@ import DownloadIC from '../../../../public/res/ic/outlined/download.svg';
 | 
			
		|||
 | 
			
		||||
import { useStore } from '../../hooks/useStore';
 | 
			
		||||
import { useCrossSigningStatus } from '../../hooks/useCrossSigningStatus';
 | 
			
		||||
import { useMatrixClient } from '../../hooks/useMatrixClient';
 | 
			
		||||
 | 
			
		||||
function CreateKeyBackupDialog({ keyData }) {
 | 
			
		||||
  const [done, setDone] = useState(false);
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
  const mountStore = useStore();
 | 
			
		||||
 | 
			
		||||
  const doBackup = async () => {
 | 
			
		||||
| 
						 | 
				
			
			@ -80,7 +80,7 @@ CreateKeyBackupDialog.propTypes = {
 | 
			
		|||
 | 
			
		||||
function RestoreKeyBackupDialog({ keyData }) {
 | 
			
		||||
  const [status, setStatus] = useState(false);
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
  const mountStore = useStore();
 | 
			
		||||
 | 
			
		||||
  const restoreBackup = async () => {
 | 
			
		||||
| 
						 | 
				
			
			@ -150,7 +150,7 @@ RestoreKeyBackupDialog.propTypes = {
 | 
			
		|||
 | 
			
		||||
function DeleteKeyBackupDialog({ requestClose }) {
 | 
			
		||||
  const [isDeleting, setIsDeleting] = useState(false);
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
  const mountStore = useStore();
 | 
			
		||||
 | 
			
		||||
  const deleteBackup = async () => {
 | 
			
		||||
| 
						 | 
				
			
			@ -187,7 +187,7 @@ DeleteKeyBackupDialog.propTypes = {
 | 
			
		|||
};
 | 
			
		||||
 | 
			
		||||
function KeyBackup() {
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
  const isCSEnabled = useCrossSigningStatus();
 | 
			
		||||
  const [keyBackup, setKeyBackup] = useState(undefined);
 | 
			
		||||
  const mountStore = useStore();
 | 
			
		||||
| 
						 | 
				
			
			@ -215,7 +215,7 @@ function KeyBackup() {
 | 
			
		|||
  }, [isCSEnabled]);
 | 
			
		||||
 | 
			
		||||
  const openCreateKeyBackup = async () => {
 | 
			
		||||
    const keyData = await accessSecretStorage('Create Key Backup');
 | 
			
		||||
    const keyData = await accessSecretStorage(mx, 'Create Key Backup');
 | 
			
		||||
    if (keyData === null) return;
 | 
			
		||||
 | 
			
		||||
    openReusableDialog(
 | 
			
		||||
| 
						 | 
				
			
			@ -228,7 +228,7 @@ function KeyBackup() {
 | 
			
		|||
  };
 | 
			
		||||
 | 
			
		||||
  const openRestoreKeyBackup = async () => {
 | 
			
		||||
    const keyData = await accessSecretStorage('Restore Key Backup');
 | 
			
		||||
    const keyData = await accessSecretStorage(mx, 'Restore Key Backup');
 | 
			
		||||
    if (keyData === null) return;
 | 
			
		||||
 | 
			
		||||
    openReusableDialog(
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,7 +3,6 @@ import PropTypes from 'prop-types';
 | 
			
		|||
import './SecretStorageAccess.scss';
 | 
			
		||||
import { deriveKey } from 'matrix-js-sdk/lib/crypto/key_passphrase';
 | 
			
		||||
 | 
			
		||||
import initMatrix from '../../../client/initMatrix';
 | 
			
		||||
import { openReusableDialog } from '../../../client/action/navigation';
 | 
			
		||||
import { getDefaultSSKey, getSSKeyInfo } from '../../../util/matrixUtil';
 | 
			
		||||
import { storePrivateKey, hasPrivateKey, getPrivateKey } from '../../../client/state/secretStorageKeys';
 | 
			
		||||
| 
						 | 
				
			
			@ -14,11 +13,12 @@ import Input from '../../atoms/input/Input';
 | 
			
		|||
import Spinner from '../../atoms/spinner/Spinner';
 | 
			
		||||
 | 
			
		||||
import { useStore } from '../../hooks/useStore';
 | 
			
		||||
import { useMatrixClient } from '../../hooks/useMatrixClient';
 | 
			
		||||
 | 
			
		||||
function SecretStorageAccess({ onComplete }) {
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
  const sSKeyId = getDefaultSSKey();
 | 
			
		||||
  const sSKeyInfo = getSSKeyInfo(sSKeyId);
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
  const sSKeyId = getDefaultSSKey(mx);
 | 
			
		||||
  const sSKeyInfo = getSSKeyInfo(mx, sSKeyId);
 | 
			
		||||
  const isPassphrase = !!sSKeyInfo.passphrase;
 | 
			
		||||
  const [withPhrase, setWithPhrase] = useState(isPassphrase);
 | 
			
		||||
  const [process, setProcess] = useState(false);
 | 
			
		||||
| 
						 | 
				
			
			@ -98,12 +98,13 @@ SecretStorageAccess.propTypes = {
 | 
			
		|||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @param {MatrixClient} mx Matrix client
 | 
			
		||||
 * @param {string} title Title of secret storage access dialog
 | 
			
		||||
 * @returns {Promise<keyData | null>} resolve to keyData or null
 | 
			
		||||
 */
 | 
			
		||||
export const accessSecretStorage = (title) => new Promise((resolve) => {
 | 
			
		||||
export const accessSecretStorage = (mx, title) => new Promise((resolve) => {
 | 
			
		||||
  let isCompleted = false;
 | 
			
		||||
  const defaultSSKey = getDefaultSSKey();
 | 
			
		||||
  const defaultSSKey = getDefaultSSKey(mx);
 | 
			
		||||
  if (hasPrivateKey(defaultSSKey)) {
 | 
			
		||||
    resolve({ keyId: defaultSSKey, privateKey: getPrivateKey(defaultSSKey) });
 | 
			
		||||
    return;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,7 +1,7 @@
 | 
			
		|||
import React, { useState, useEffect } from 'react';
 | 
			
		||||
import './Settings.scss';
 | 
			
		||||
 | 
			
		||||
import initMatrix from '../../../client/initMatrix';
 | 
			
		||||
import { clearCacheAndReload, logoutClient } from '../../../client/initMatrix';
 | 
			
		||||
import cons from '../../../client/state/cons';
 | 
			
		||||
import settings from '../../../client/state/settings';
 | 
			
		||||
import navigation from '../../../client/state/navigation';
 | 
			
		||||
| 
						 | 
				
			
			@ -47,6 +47,7 @@ import { useSetting } from '../../state/hooks/settings';
 | 
			
		|||
import { settingsAtom } from '../../state/settings';
 | 
			
		||||
import { isMacOS } from '../../utils/user-agent';
 | 
			
		||||
import { KeySymbol } from '../../utils/key-symbol';
 | 
			
		||||
import { useMatrixClient } from '../../hooks/useMatrixClient';
 | 
			
		||||
 | 
			
		||||
function AppearanceSection() {
 | 
			
		||||
  const [, updateState] = useState({});
 | 
			
		||||
| 
						 | 
				
			
			@ -332,6 +333,8 @@ function SecuritySection() {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
function AboutSection() {
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
  
 | 
			
		||||
  return (
 | 
			
		||||
    <div className="settings-about">
 | 
			
		||||
      <div className="settings-about__card">
 | 
			
		||||
| 
						 | 
				
			
			@ -348,7 +351,7 @@ function AboutSection() {
 | 
			
		|||
            <div className="settings-about__btns">
 | 
			
		||||
              <Button onClick={() => window.open('https://github.com/ajbura/cinny')}>Source code</Button>
 | 
			
		||||
              <Button onClick={() => window.open('https://cinny.in/#sponsor')}>Support</Button>
 | 
			
		||||
              <Button onClick={() => initMatrix.clearCacheAndReload()} variant="danger">Clear cache & reload</Button>
 | 
			
		||||
              <Button onClick={() => clearCacheAndReload(mx)} variant="danger">Clear cache & reload</Button>
 | 
			
		||||
            </div>
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
| 
						 | 
				
			
			@ -437,11 +440,12 @@ function useWindowToggle(setSelectedTab) {
 | 
			
		|||
function Settings() {
 | 
			
		||||
  const [selectedTab, setSelectedTab] = useState(tabItems[0]);
 | 
			
		||||
  const [isOpen, requestClose] = useWindowToggle(setSelectedTab);
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
 | 
			
		||||
  const handleTabChange = (tabItem) => setSelectedTab(tabItem);
 | 
			
		||||
  const handleLogout = async () => {
 | 
			
		||||
    if (await confirmDialog('Logout', 'Are you sure that you want to logout your session?', 'Logout', 'danger')) {
 | 
			
		||||
      initMatrix.logout();
 | 
			
		||||
      logoutClient(mx);
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -462,7 +466,7 @@ function Settings() {
 | 
			
		|||
    >
 | 
			
		||||
      {isOpen && (
 | 
			
		||||
        <div className="settings-window__content">
 | 
			
		||||
          <ProfileEditor userId={initMatrix.matrixClient.getUserId()} />
 | 
			
		||||
          <ProfileEditor userId={mx.getUserId()} />
 | 
			
		||||
          <Tabs
 | 
			
		||||
            items={tabItems}
 | 
			
		||||
            defaultSelected={tabItems.findIndex((tab) => tab.text === selectedTab.text)}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,7 +2,6 @@ import React, { useState, useEffect } from 'react';
 | 
			
		|||
import PropTypes from 'prop-types';
 | 
			
		||||
import './SpaceSettings.scss';
 | 
			
		||||
 | 
			
		||||
import initMatrix from '../../../client/initMatrix';
 | 
			
		||||
import cons from '../../../client/state/cons';
 | 
			
		||||
import navigation from '../../../client/state/navigation';
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -59,8 +58,8 @@ const tabItems = [
 | 
			
		|||
];
 | 
			
		||||
 | 
			
		||||
function GeneralSettings({ roomId }) {
 | 
			
		||||
  const roomName = initMatrix.matrixClient.getRoom(roomId)?.name;
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
  const roomName = mx.getRoom(roomId)?.name;
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <>
 | 
			
		||||
| 
						 | 
				
			
			@ -124,7 +123,7 @@ function SpaceSettings() {
 | 
			
		|||
  const isOpen = window !== null;
 | 
			
		||||
  const roomId = window?.roomId;
 | 
			
		||||
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
  const room = mx.getRoom(roomId);
 | 
			
		||||
 | 
			
		||||
  const handleTabChange = (tabItem) => {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,7 +7,7 @@ type ClientLayoutProps = {
 | 
			
		|||
};
 | 
			
		||||
export function ClientLayout({ nav, children }: ClientLayoutProps) {
 | 
			
		||||
  return (
 | 
			
		||||
    <Box style={{ height: '100%' }}>
 | 
			
		||||
    <Box grow="Yes">
 | 
			
		||||
      <Box shrink="No">{nav}</Box>
 | 
			
		||||
      <Box grow="Yes">{children}</Box>
 | 
			
		||||
    </Box>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,27 @@
 | 
			
		|||
import { Box, Spinner, Text } from 'folds';
 | 
			
		||||
import React, { ReactNode, useEffect, useState } from 'react';
 | 
			
		||||
import initMatrix from '../../../client/initMatrix';
 | 
			
		||||
import {
 | 
			
		||||
  Box,
 | 
			
		||||
  Button,
 | 
			
		||||
  config,
 | 
			
		||||
  Dialog,
 | 
			
		||||
  Icon,
 | 
			
		||||
  IconButton,
 | 
			
		||||
  Icons,
 | 
			
		||||
  Menu,
 | 
			
		||||
  MenuItem,
 | 
			
		||||
  PopOut,
 | 
			
		||||
  RectCords,
 | 
			
		||||
  Spinner,
 | 
			
		||||
  Text,
 | 
			
		||||
} from 'folds';
 | 
			
		||||
import { HttpApiEvent, HttpApiEventHandlerMap, MatrixClient } from 'matrix-js-sdk';
 | 
			
		||||
import FocusTrap from 'focus-trap-react';
 | 
			
		||||
import React, { MouseEventHandler, ReactNode, useCallback, useEffect, useState } from 'react';
 | 
			
		||||
import {
 | 
			
		||||
  clearCacheAndReload,
 | 
			
		||||
  initClient,
 | 
			
		||||
  logoutClient,
 | 
			
		||||
  startClient,
 | 
			
		||||
} from '../../../client/initMatrix';
 | 
			
		||||
import { getSecret } from '../../../client/state/auth';
 | 
			
		||||
import { SplashScreen } from '../../components/splash-screen';
 | 
			
		||||
import { CapabilitiesAndMediaConfigLoader } from '../../components/CapabilitiesAndMediaConfigLoader';
 | 
			
		||||
| 
						 | 
				
			
			@ -13,6 +34,10 @@ import Dialogs from '../../organisms/pw/Dialogs';
 | 
			
		|||
import ReusableContextMenu from '../../atoms/context-menu/ReusableContextMenu';
 | 
			
		||||
import { useSetting } from '../../state/hooks/settings';
 | 
			
		||||
import { settingsAtom } from '../../state/settings';
 | 
			
		||||
import { AsyncStatus, useAsyncCallback } from '../../hooks/useAsyncCallback';
 | 
			
		||||
import { useSyncState } from '../../hooks/useSyncState';
 | 
			
		||||
import { stopPropagation } from '../../utils/keyboard';
 | 
			
		||||
import { SyncStatus } from './SyncStatus';
 | 
			
		||||
 | 
			
		||||
function SystemEmojiFeature() {
 | 
			
		||||
  const [twitterEmoji] = useSetting(settingsAtom, 'twitterEmoji');
 | 
			
		||||
| 
						 | 
				
			
			@ -37,6 +62,89 @@ function ClientRootLoading() {
 | 
			
		|||
  );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function ClientRootOptions({ mx }: { mx: MatrixClient }) {
 | 
			
		||||
  const [menuAnchor, setMenuAnchor] = useState<RectCords>();
 | 
			
		||||
 | 
			
		||||
  const handleToggle: MouseEventHandler<HTMLButtonElement> = (evt) => {
 | 
			
		||||
    const cords = evt.currentTarget.getBoundingClientRect();
 | 
			
		||||
    setMenuAnchor((currentState) => {
 | 
			
		||||
      if (currentState) return undefined;
 | 
			
		||||
      return cords;
 | 
			
		||||
    });
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <IconButton
 | 
			
		||||
      style={{
 | 
			
		||||
        position: 'absolute',
 | 
			
		||||
        top: config.space.S100,
 | 
			
		||||
        right: config.space.S100,
 | 
			
		||||
      }}
 | 
			
		||||
      variant="Background"
 | 
			
		||||
      fill="None"
 | 
			
		||||
      onClick={handleToggle}
 | 
			
		||||
    >
 | 
			
		||||
      <Icon size="200" src={Icons.VerticalDots} />
 | 
			
		||||
      <PopOut
 | 
			
		||||
        anchor={menuAnchor}
 | 
			
		||||
        position="Bottom"
 | 
			
		||||
        align="End"
 | 
			
		||||
        offset={6}
 | 
			
		||||
        content={
 | 
			
		||||
          <FocusTrap
 | 
			
		||||
            focusTrapOptions={{
 | 
			
		||||
              initialFocus: false,
 | 
			
		||||
              returnFocusOnDeactivate: false,
 | 
			
		||||
              onDeactivate: () => setMenuAnchor(undefined),
 | 
			
		||||
              clickOutsideDeactivates: true,
 | 
			
		||||
              isKeyForward: (evt: KeyboardEvent) => evt.key === 'ArrowDown',
 | 
			
		||||
              isKeyBackward: (evt: KeyboardEvent) => evt.key === 'ArrowUp',
 | 
			
		||||
              escapeDeactivates: stopPropagation,
 | 
			
		||||
            }}
 | 
			
		||||
          >
 | 
			
		||||
            <Menu>
 | 
			
		||||
              <Box direction="Column" gap="100" style={{ padding: config.space.S100 }}>
 | 
			
		||||
                <MenuItem onClick={() => clearCacheAndReload(mx)} size="300" radii="300">
 | 
			
		||||
                  <Text as="span" size="T300" truncate>
 | 
			
		||||
                    Clear Cache and Reload
 | 
			
		||||
                  </Text>
 | 
			
		||||
                </MenuItem>
 | 
			
		||||
                <MenuItem
 | 
			
		||||
                  onClick={() => logoutClient(mx)}
 | 
			
		||||
                  size="300"
 | 
			
		||||
                  radii="300"
 | 
			
		||||
                  variant="Critical"
 | 
			
		||||
                  fill="None"
 | 
			
		||||
                >
 | 
			
		||||
                  <Text as="span" size="T300" truncate>
 | 
			
		||||
                    Logout
 | 
			
		||||
                  </Text>
 | 
			
		||||
                </MenuItem>
 | 
			
		||||
              </Box>
 | 
			
		||||
            </Menu>
 | 
			
		||||
          </FocusTrap>
 | 
			
		||||
        }
 | 
			
		||||
      />
 | 
			
		||||
    </IconButton>
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const useLogoutListener = (mx?: MatrixClient) => {
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    const handleLogout: HttpApiEventHandlerMap[HttpApiEvent.SessionLoggedOut] = async () => {
 | 
			
		||||
      mx?.stopClient();
 | 
			
		||||
      await mx?.clearStores();
 | 
			
		||||
      window.localStorage.clear();
 | 
			
		||||
      window.location.reload();
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    mx?.on(HttpApiEvent.SessionLoggedOut, handleLogout);
 | 
			
		||||
    return () => {
 | 
			
		||||
      mx?.removeListener(HttpApiEvent.SessionLoggedOut, handleLogout);
 | 
			
		||||
    };
 | 
			
		||||
  }, [mx]);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
type ClientRootProps = {
 | 
			
		||||
  children: ReactNode;
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -44,30 +152,71 @@ export function ClientRoot({ children }: ClientRootProps) {
 | 
			
		|||
  const [loading, setLoading] = useState(true);
 | 
			
		||||
  const { baseUrl } = getSecret();
 | 
			
		||||
 | 
			
		||||
  const [loadState, loadMatrix] = useAsyncCallback<MatrixClient, Error, []>(
 | 
			
		||||
    useCallback(() => initClient(getSecret() as any), [])
 | 
			
		||||
  );
 | 
			
		||||
  const mx = loadState.status === AsyncStatus.Success ? loadState.data : undefined;
 | 
			
		||||
  const [startState, startMatrix] = useAsyncCallback<void, Error, [MatrixClient]>(
 | 
			
		||||
    useCallback((m) => startClient(m), [])
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  useLogoutListener(mx);
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    const handleStart = () => {
 | 
			
		||||
      setLoading(false);
 | 
			
		||||
    };
 | 
			
		||||
    initMatrix.once('init_loading_finished', handleStart);
 | 
			
		||||
    if (!initMatrix.matrixClient) initMatrix.init();
 | 
			
		||||
    return () => {
 | 
			
		||||
      initMatrix.removeListener('init_loading_finished', handleStart);
 | 
			
		||||
    };
 | 
			
		||||
  }, []);
 | 
			
		||||
    if (loadState.status === AsyncStatus.Idle) {
 | 
			
		||||
      loadMatrix();
 | 
			
		||||
    }
 | 
			
		||||
  }, [loadState, loadMatrix]);
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    if (mx && !mx.clientRunning) {
 | 
			
		||||
      startMatrix(mx);
 | 
			
		||||
    }
 | 
			
		||||
  }, [mx, startMatrix]);
 | 
			
		||||
 | 
			
		||||
  useSyncState(
 | 
			
		||||
    mx,
 | 
			
		||||
    useCallback((state) => {
 | 
			
		||||
      if (state === 'PREPARED') {
 | 
			
		||||
        setLoading(false);
 | 
			
		||||
      }
 | 
			
		||||
    }, [])
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <SpecVersions baseUrl={baseUrl!}>
 | 
			
		||||
      {loading ? (
 | 
			
		||||
      {mx && <SyncStatus mx={mx} />}
 | 
			
		||||
      {loading && mx && <ClientRootOptions mx={mx} />}
 | 
			
		||||
      {(loadState.status === AsyncStatus.Error || startState.status === AsyncStatus.Error) && (
 | 
			
		||||
        <SplashScreen>
 | 
			
		||||
          <Box direction="Column" grow="Yes" alignItems="Center" justifyContent="Center" gap="400">
 | 
			
		||||
            <Dialog>
 | 
			
		||||
              <Box direction="Column" gap="400" style={{ padding: config.space.S400 }}>
 | 
			
		||||
                {loadState.status === AsyncStatus.Error && (
 | 
			
		||||
                  <Text>{`Failed to load. ${loadState.error.message}`}</Text>
 | 
			
		||||
                )}
 | 
			
		||||
                {startState.status === AsyncStatus.Error && (
 | 
			
		||||
                  <Text>{`Failed to load. ${startState.error.message}`}</Text>
 | 
			
		||||
                )}
 | 
			
		||||
                <Button variant="Critical" onClick={loadMatrix}>
 | 
			
		||||
                  <Text as="span" size="B400">
 | 
			
		||||
                    Retry
 | 
			
		||||
                  </Text>
 | 
			
		||||
                </Button>
 | 
			
		||||
              </Box>
 | 
			
		||||
            </Dialog>
 | 
			
		||||
          </Box>
 | 
			
		||||
        </SplashScreen>
 | 
			
		||||
      )}
 | 
			
		||||
      {loading || !mx ? (
 | 
			
		||||
        <ClientRootLoading />
 | 
			
		||||
      ) : (
 | 
			
		||||
        <MatrixClientProvider value={initMatrix.matrixClient!}>
 | 
			
		||||
        <MatrixClientProvider value={mx}>
 | 
			
		||||
          <CapabilitiesAndMediaConfigLoader>
 | 
			
		||||
            {(capabilities, mediaConfig) => (
 | 
			
		||||
              <CapabilitiesProvider value={capabilities ?? {}}>
 | 
			
		||||
                <MediaConfigProvider value={mediaConfig ?? {}}>
 | 
			
		||||
                  {children}
 | 
			
		||||
 | 
			
		||||
                  {/* TODO: remove these components after navigation refactor */}
 | 
			
		||||
                  <Windows />
 | 
			
		||||
                  <Dialogs />
 | 
			
		||||
                  <ReusableContextMenu />
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										87
									
								
								src/app/pages/client/SyncStatus.tsx
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								src/app/pages/client/SyncStatus.tsx
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,87 @@
 | 
			
		|||
import { MatrixClient, SyncState } from 'matrix-js-sdk';
 | 
			
		||||
import React, { useCallback, useState } from 'react';
 | 
			
		||||
import { Box, config, Line, Text } from 'folds';
 | 
			
		||||
import { useSyncState } from '../../hooks/useSyncState';
 | 
			
		||||
import { ContainerColor } from '../../styles/ContainerColor.css';
 | 
			
		||||
 | 
			
		||||
type StateData = {
 | 
			
		||||
  current: SyncState | null;
 | 
			
		||||
  previous: SyncState | null | undefined;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
type SyncStatusProps = {
 | 
			
		||||
  mx: MatrixClient;
 | 
			
		||||
};
 | 
			
		||||
export function SyncStatus({ mx }: SyncStatusProps) {
 | 
			
		||||
  const [stateData, setStateData] = useState<StateData>({
 | 
			
		||||
    current: null,
 | 
			
		||||
    previous: undefined,
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  useSyncState(
 | 
			
		||||
    mx,
 | 
			
		||||
    useCallback((current, previous) => {
 | 
			
		||||
      setStateData((s) => {
 | 
			
		||||
        if (s.current === current && s.previous === previous) {
 | 
			
		||||
          return s;
 | 
			
		||||
        }
 | 
			
		||||
        return { current, previous };
 | 
			
		||||
      });
 | 
			
		||||
    }, [])
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  if (
 | 
			
		||||
    (stateData.current === SyncState.Prepared ||
 | 
			
		||||
      stateData.current === SyncState.Syncing ||
 | 
			
		||||
      stateData.current === SyncState.Catchup) &&
 | 
			
		||||
    stateData.previous !== SyncState.Syncing
 | 
			
		||||
  ) {
 | 
			
		||||
    return (
 | 
			
		||||
      <Box direction="Column" shrink="No">
 | 
			
		||||
        <Box
 | 
			
		||||
          className={ContainerColor({ variant: 'Success' })}
 | 
			
		||||
          style={{ padding: `${config.space.S100} 0` }}
 | 
			
		||||
          alignItems="Center"
 | 
			
		||||
          justifyContent="Center"
 | 
			
		||||
        >
 | 
			
		||||
          <Text size="L400">Connecting...</Text>
 | 
			
		||||
        </Box>
 | 
			
		||||
        <Line variant="Success" size="300" />
 | 
			
		||||
      </Box>
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (stateData.current === SyncState.Reconnecting) {
 | 
			
		||||
    return (
 | 
			
		||||
      <Box direction="Column" shrink="No">
 | 
			
		||||
        <Box
 | 
			
		||||
          className={ContainerColor({ variant: 'Warning' })}
 | 
			
		||||
          style={{ padding: `${config.space.S100} 0` }}
 | 
			
		||||
          alignItems="Center"
 | 
			
		||||
          justifyContent="Center"
 | 
			
		||||
        >
 | 
			
		||||
          <Text size="L400">Connection Lost! Reconnecting...</Text>
 | 
			
		||||
        </Box>
 | 
			
		||||
        <Line variant="Warning" size="300" />
 | 
			
		||||
      </Box>
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (stateData.current === SyncState.Error) {
 | 
			
		||||
    return (
 | 
			
		||||
      <Box direction="Column" shrink="No">
 | 
			
		||||
        <Box
 | 
			
		||||
          className={ContainerColor({ variant: 'Critical' })}
 | 
			
		||||
          style={{ padding: `${config.space.S100} 0` }}
 | 
			
		||||
          alignItems="Center"
 | 
			
		||||
          justifyContent="Center"
 | 
			
		||||
        >
 | 
			
		||||
          <Text size="L400">Connection Lost!</Text>
 | 
			
		||||
        </Box>
 | 
			
		||||
        <Line variant="Critical" size="300" />
 | 
			
		||||
      </Box>
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return null;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -18,7 +18,7 @@ export function WelcomePage() {
 | 
			
		|||
            title="Welcome to Cinny"
 | 
			
		||||
            subTitle={
 | 
			
		||||
              <span>
 | 
			
		||||
                Yet anothor matrix client.{' '}
 | 
			
		||||
                Yet another matrix client.{' '}
 | 
			
		||||
                <a
 | 
			
		||||
                  href="https://github.com/cinnyapp/cinny/releases"
 | 
			
		||||
                  target="_blank"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -50,12 +50,13 @@ type DirectMenuProps = {
 | 
			
		|||
  requestClose: () => void;
 | 
			
		||||
};
 | 
			
		||||
const DirectMenu = forwardRef<HTMLDivElement, DirectMenuProps>(({ requestClose }, ref) => {
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
  const orphanRooms = useDirectRooms();
 | 
			
		||||
  const unread = useRoomsUnread(orphanRooms, roomToUnreadAtom);
 | 
			
		||||
 | 
			
		||||
  const handleMarkAsRead = () => {
 | 
			
		||||
    if (!unread) return;
 | 
			
		||||
    orphanRooms.forEach((rId) => markAsRead(rId));
 | 
			
		||||
    orphanRooms.forEach((rId) => markAsRead(mx, rId));
 | 
			
		||||
    requestClose();
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -55,10 +55,11 @@ type HomeMenuProps = {
 | 
			
		|||
const HomeMenu = forwardRef<HTMLDivElement, HomeMenuProps>(({ requestClose }, ref) => {
 | 
			
		||||
  const orphanRooms = useHomeRooms();
 | 
			
		||||
  const unread = useRoomsUnread(orphanRooms, roomToUnreadAtom);
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
 | 
			
		||||
  const handleMarkAsRead = () => {
 | 
			
		||||
    if (!unread) return;
 | 
			
		||||
    orphanRooms.forEach((rId) => markAsRead(rId));
 | 
			
		||||
    orphanRooms.forEach((rId) => markAsRead(mx, rId));
 | 
			
		||||
    requestClose();
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -356,7 +356,7 @@ function RoomNotificationsGroupComp({
 | 
			
		|||
    onOpen(room.roomId, eventId);
 | 
			
		||||
  };
 | 
			
		||||
  const handleMarkAsRead = () => {
 | 
			
		||||
    markAsRead(room.roomId);
 | 
			
		||||
    markAsRead(mx, room.roomId);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -30,10 +30,11 @@ type DirectMenuProps = {
 | 
			
		|||
const DirectMenu = forwardRef<HTMLDivElement, DirectMenuProps>(({ requestClose }, ref) => {
 | 
			
		||||
  const orphanRooms = useDirectRooms();
 | 
			
		||||
  const unread = useRoomsUnread(orphanRooms, roomToUnreadAtom);
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
 | 
			
		||||
  const handleMarkAsRead = () => {
 | 
			
		||||
    if (!unread) return;
 | 
			
		||||
    orphanRooms.forEach((rId) => markAsRead(rId));
 | 
			
		||||
    orphanRooms.forEach((rId) => markAsRead(mx, rId));
 | 
			
		||||
    requestClose();
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -31,10 +31,11 @@ type HomeMenuProps = {
 | 
			
		|||
const HomeMenu = forwardRef<HTMLDivElement, HomeMenuProps>(({ requestClose }, ref) => {
 | 
			
		||||
  const orphanRooms = useHomeRooms();
 | 
			
		||||
  const unread = useRoomsUnread(orphanRooms, roomToUnreadAtom);
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
 | 
			
		||||
  const handleMarkAsRead = () => {
 | 
			
		||||
    if (!unread) return;
 | 
			
		||||
    orphanRooms.forEach((rId) => markAsRead(rId));
 | 
			
		||||
    orphanRooms.forEach((rId) => markAsRead(mx, rId));
 | 
			
		||||
    requestClose();
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -114,7 +114,7 @@ const SpaceMenu = forwardRef<HTMLDivElement, SpaceMenuProps>(
 | 
			
		|||
    const unread = useRoomsUnread(allChild, roomToUnreadAtom);
 | 
			
		||||
 | 
			
		||||
    const handleMarkAsRead = () => {
 | 
			
		||||
      allChild.forEach((childRoomId) => markAsRead(childRoomId));
 | 
			
		||||
      allChild.forEach((childRoomId) => markAsRead(mx, childRoomId));
 | 
			
		||||
      requestClose();
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -95,7 +95,7 @@ const SpaceMenu = forwardRef<HTMLDivElement, SpaceMenuProps>(({ room, requestClo
 | 
			
		|||
  const unread = useRoomsUnread(allChild, roomToUnreadAtom);
 | 
			
		||||
 | 
			
		||||
  const handleMarkAsRead = () => {
 | 
			
		||||
    allChild.forEach((childRoomId) => markAsRead(childRoomId));
 | 
			
		||||
    allChild.forEach((childRoomId) => markAsRead(mx, childRoomId));
 | 
			
		||||
    requestClose();
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,13 +1,11 @@
 | 
			
		|||
import initMatrix from '../initMatrix';
 | 
			
		||||
import { MatrixClient } from "matrix-js-sdk";
 | 
			
		||||
 | 
			
		||||
// eslint-disable-next-line import/prefer-default-export
 | 
			
		||||
export async function markAsRead(roomId) {
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
export async function markAsRead(mx: MatrixClient, roomId: string) {
 | 
			
		||||
  const room = mx.getRoom(roomId);
 | 
			
		||||
  if (!room) return;
 | 
			
		||||
 | 
			
		||||
  const timeline = room.getLiveTimeline().getEvents();
 | 
			
		||||
  const readEventId = room.getEventReadUpTo(mx.getUserId());
 | 
			
		||||
  const readEventId = room.getEventReadUpTo(mx.getUserId()!);
 | 
			
		||||
 | 
			
		||||
  const getLatestValidEvent = () => {
 | 
			
		||||
    for (let i = timeline.length - 1; i >= 0; i -= 1) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1,16 +1,13 @@
 | 
			
		|||
import initMatrix from '../initMatrix';
 | 
			
		||||
import appDispatcher from '../dispatcher';
 | 
			
		||||
import cons from '../state/cons';
 | 
			
		||||
import { getIdServer } from '../../util/matrixUtil';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * https://github.com/matrix-org/matrix-react-sdk/blob/1e6c6e9d800890c732d60429449bc280de01a647/src/Rooms.js#L73
 | 
			
		||||
 * @param {MatrixClient} mx Matrix client
 | 
			
		||||
 * @param {string} roomId Id of room to add
 | 
			
		||||
 * @param {string} userId User id to which dm || undefined to remove
 | 
			
		||||
 * @returns {Promise} A promise
 | 
			
		||||
 */
 | 
			
		||||
function addRoomToMDirect(roomId, userId) {
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
function addRoomToMDirect(mx, roomId, userId) {
 | 
			
		||||
  const mDirectsEvent = mx.getAccountData('m.direct');
 | 
			
		||||
  let userIdToRoomIds = {};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -79,24 +76,22 @@ function guessDMRoomTargetId(room, myUserId) {
 | 
			
		|||
  return oldestMember.userId;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function convertToDm(roomId) {
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
function convertToDm(mx, roomId) {
 | 
			
		||||
  const room = mx.getRoom(roomId);
 | 
			
		||||
  return addRoomToMDirect(roomId, guessDMRoomTargetId(room, mx.getUserId()));
 | 
			
		||||
  return addRoomToMDirect(mx, roomId, guessDMRoomTargetId(room, mx.getUserId()));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function convertToRoom(roomId) {
 | 
			
		||||
  return addRoomToMDirect(roomId, undefined);
 | 
			
		||||
function convertToRoom(mx, roomId) {
 | 
			
		||||
  return addRoomToMDirect(mx, roomId, undefined);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *
 | 
			
		||||
 * @param {MatrixClient} mx
 | 
			
		||||
 * @param {string} roomId
 | 
			
		||||
 * @param {boolean} isDM
 | 
			
		||||
 * @param {string[]} via
 | 
			
		||||
 */
 | 
			
		||||
async function join(roomIdOrAlias, isDM = false, via = undefined) {
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
async function join(mx, roomIdOrAlias, isDM = false, via = undefined) {
 | 
			
		||||
  const roomIdParts = roomIdOrAlias.split(':');
 | 
			
		||||
  const viaServers = via || [roomIdParts[1]];
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -105,7 +100,7 @@ async function join(roomIdOrAlias, isDM = false, via = undefined) {
 | 
			
		|||
 | 
			
		||||
    if (isDM) {
 | 
			
		||||
      const targetUserId = guessDMRoomTargetId(mx.getRoom(resultRoom.roomId), mx.getUserId());
 | 
			
		||||
      await addRoomToMDirect(resultRoom.roomId, targetUserId);
 | 
			
		||||
      await addRoomToMDirect(mx, resultRoom.roomId, targetUserId);
 | 
			
		||||
    }
 | 
			
		||||
    return resultRoom.roomId;
 | 
			
		||||
  } catch (e) {
 | 
			
		||||
| 
						 | 
				
			
			@ -113,12 +108,11 @@ async function join(roomIdOrAlias, isDM = false, via = undefined) {
 | 
			
		|||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function create(options, isDM = false) {
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
async function create(mx, options, isDM = false) {
 | 
			
		||||
  try {
 | 
			
		||||
    const result = await mx.createRoom(options);
 | 
			
		||||
    if (isDM && typeof options.invite?.[0] === 'string') {
 | 
			
		||||
      await addRoomToMDirect(result.room_id, options.invite[0]);
 | 
			
		||||
      await addRoomToMDirect(mx, result.room_id, options.invite[0]);
 | 
			
		||||
    }
 | 
			
		||||
    return result;
 | 
			
		||||
  } catch (e) {
 | 
			
		||||
| 
						 | 
				
			
			@ -130,7 +124,7 @@ async function create(options, isDM = false) {
 | 
			
		|||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function createDM(userIdOrIds, isEncrypted = true) {
 | 
			
		||||
async function createDM(mx, userIdOrIds, isEncrypted = true) {
 | 
			
		||||
  const options = {
 | 
			
		||||
    is_direct: true,
 | 
			
		||||
    invite: Array.isArray(userIdOrIds) ? userIdOrIds : [userIdOrIds],
 | 
			
		||||
| 
						 | 
				
			
			@ -148,11 +142,11 @@ async function createDM(userIdOrIds, isEncrypted = true) {
 | 
			
		|||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const result = await create(options, true);
 | 
			
		||||
  const result = await create(mx, options, true);
 | 
			
		||||
  return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function createRoom(opts) {
 | 
			
		||||
async function createRoom(mx, opts) {
 | 
			
		||||
  // joinRule: 'public' | 'invite' | 'restricted'
 | 
			
		||||
  const { name, topic, joinRule } = opts;
 | 
			
		||||
  const alias = opts.alias ?? undefined;
 | 
			
		||||
| 
						 | 
				
			
			@ -162,7 +156,6 @@ async function createRoom(opts) {
 | 
			
		|||
  const powerLevel = opts.powerLevel ?? undefined;
 | 
			
		||||
  const blockFederation = opts.blockFederation ?? false;
 | 
			
		||||
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
  const visibility = joinRule === 'public' ? 'public' : 'private';
 | 
			
		||||
  const options = {
 | 
			
		||||
    creation_content: undefined,
 | 
			
		||||
| 
						 | 
				
			
			@ -225,7 +218,7 @@ async function createRoom(opts) {
 | 
			
		|||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const result = await create(options);
 | 
			
		||||
  const result = await create(mx, options);
 | 
			
		||||
 | 
			
		||||
  if (parentId) {
 | 
			
		||||
    await mx.sendStateEvent(parentId, 'm.space.child', {
 | 
			
		||||
| 
						 | 
				
			
			@ -238,51 +231,19 @@ async function createRoom(opts) {
 | 
			
		|||
  return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function invite(roomId, userId, reason) {
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
 | 
			
		||||
  const result = await mx.invite(roomId, userId, undefined, reason);
 | 
			
		||||
  return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function kick(roomId, userId, reason) {
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
 | 
			
		||||
  const result = await mx.kick(roomId, userId, reason);
 | 
			
		||||
  return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function ban(roomId, userId, reason) {
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
 | 
			
		||||
  const result = await mx.ban(roomId, userId, reason);
 | 
			
		||||
  return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function unban(roomId, userId) {
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
 | 
			
		||||
  const result = await mx.unban(roomId, userId);
 | 
			
		||||
  return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function ignore(userIds) {
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
async function ignore(mx, userIds) {
 | 
			
		||||
 | 
			
		||||
  let ignoredUsers = mx.getIgnoredUsers().concat(userIds);
 | 
			
		||||
  ignoredUsers = [...new Set(ignoredUsers)];
 | 
			
		||||
  await mx.setIgnoredUsers(ignoredUsers);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function unignore(userIds) {
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
 | 
			
		||||
async function unignore(mx, userIds) {
 | 
			
		||||
  const ignoredUsers = mx.getIgnoredUsers();
 | 
			
		||||
  await mx.setIgnoredUsers(ignoredUsers.filter((id) => !userIds.includes(id)));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function setPowerLevel(roomId, userId, powerLevel) {
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
async function setPowerLevel(mx, roomId, userId, powerLevel) {
 | 
			
		||||
  const room = mx.getRoom(roomId);
 | 
			
		||||
 | 
			
		||||
  const powerlevelEvent = room.currentState.getStateEvents('m.room.power_levels')[0];
 | 
			
		||||
| 
						 | 
				
			
			@ -291,8 +252,7 @@ async function setPowerLevel(roomId, userId, powerLevel) {
 | 
			
		|||
  return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function setMyRoomNick(roomId, nick) {
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
async function setMyRoomNick(mx, roomId, nick) {
 | 
			
		||||
  const room = mx.getRoom(roomId);
 | 
			
		||||
  const mEvent = room.currentState.getStateEvents('m.room.member', mx.getUserId());
 | 
			
		||||
  const content = mEvent?.getContent();
 | 
			
		||||
| 
						 | 
				
			
			@ -303,8 +263,7 @@ async function setMyRoomNick(roomId, nick) {
 | 
			
		|||
  }, mx.getUserId());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function setMyRoomAvatar(roomId, mxc) {
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
async function setMyRoomAvatar(mx, roomId, mxc) {
 | 
			
		||||
  const room = mx.getRoom(roomId);
 | 
			
		||||
  const mEvent = room.currentState.getStateEvents('m.room.member', mx.getUserId());
 | 
			
		||||
  const content = mEvent?.getContent();
 | 
			
		||||
| 
						 | 
				
			
			@ -320,7 +279,6 @@ export {
 | 
			
		|||
  convertToRoom,
 | 
			
		||||
  join,
 | 
			
		||||
  createDM, createRoom,
 | 
			
		||||
  invite, kick, ban, unban,
 | 
			
		||||
  ignore, unignore,
 | 
			
		||||
  setPowerLevel,
 | 
			
		||||
  setMyRoomNick, setMyRoomAvatar,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,128 +0,0 @@
 | 
			
		|||
import EventEmitter from 'events';
 | 
			
		||||
import * as sdk from 'matrix-js-sdk';
 | 
			
		||||
import Olm from '@matrix-org/olm';
 | 
			
		||||
import { logger } from 'matrix-js-sdk/lib/logger';
 | 
			
		||||
 | 
			
		||||
import { getSecret } from './state/auth';
 | 
			
		||||
import { cryptoCallbacks } from './state/secretStorageKeys';
 | 
			
		||||
 | 
			
		||||
global.Olm = Olm;
 | 
			
		||||
 | 
			
		||||
if (import.meta.env.PROD) {
 | 
			
		||||
  logger.disableAll();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class InitMatrix extends EventEmitter {
 | 
			
		||||
  async init() {
 | 
			
		||||
    if (this.matrixClient || this.initializing) {
 | 
			
		||||
      console.warn('Client is already initialized!')
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    this.initializing = true;
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
      await this.startClient();
 | 
			
		||||
      this.setupSync();
 | 
			
		||||
      this.listenEvents();
 | 
			
		||||
      this.initializing = false;
 | 
			
		||||
    } catch {
 | 
			
		||||
      this.initializing = false;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async startClient() {
 | 
			
		||||
    const indexedDBStore = new sdk.IndexedDBStore({
 | 
			
		||||
      indexedDB: global.indexedDB,
 | 
			
		||||
      localStorage: global.localStorage,
 | 
			
		||||
      dbName: 'web-sync-store',
 | 
			
		||||
    });
 | 
			
		||||
    await indexedDBStore.startup();
 | 
			
		||||
    const secret = getSecret();
 | 
			
		||||
 | 
			
		||||
    this.matrixClient = sdk.createClient({
 | 
			
		||||
      baseUrl: secret.baseUrl,
 | 
			
		||||
      accessToken: secret.accessToken,
 | 
			
		||||
      userId: secret.userId,
 | 
			
		||||
      store: indexedDBStore,
 | 
			
		||||
      cryptoStore: new sdk.IndexedDBCryptoStore(global.indexedDB, 'crypto-store'),
 | 
			
		||||
      deviceId: secret.deviceId,
 | 
			
		||||
      timelineSupport: true,
 | 
			
		||||
      cryptoCallbacks,
 | 
			
		||||
      verificationMethods: [
 | 
			
		||||
        'm.sas.v1',
 | 
			
		||||
      ],
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    await this.matrixClient.initCrypto();
 | 
			
		||||
 | 
			
		||||
    await this.matrixClient.startClient({
 | 
			
		||||
      lazyLoadMembers: true,
 | 
			
		||||
    });
 | 
			
		||||
    this.matrixClient.setGlobalErrorOnUnknownDevices(false);
 | 
			
		||||
    this.matrixClient.setMaxListeners(50);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  setupSync() {
 | 
			
		||||
    const sync = {
 | 
			
		||||
      NULL: () => {
 | 
			
		||||
        console.log('NULL state');
 | 
			
		||||
      },
 | 
			
		||||
      SYNCING: () => {
 | 
			
		||||
        console.log('SYNCING state');
 | 
			
		||||
      },
 | 
			
		||||
      PREPARED: (prevState) => {
 | 
			
		||||
        console.log('PREPARED state');
 | 
			
		||||
        console.log('Previous state: ', prevState);
 | 
			
		||||
        global.initMatrix = this;
 | 
			
		||||
        if (prevState === null) {
 | 
			
		||||
          this.emit('init_loading_finished');
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      RECONNECTING: () => {
 | 
			
		||||
        console.log('RECONNECTING state');
 | 
			
		||||
      },
 | 
			
		||||
      CATCHUP: () => {
 | 
			
		||||
        console.log('CATCHUP state');
 | 
			
		||||
      },
 | 
			
		||||
      ERROR: () => {
 | 
			
		||||
        console.log('ERROR state');
 | 
			
		||||
      },
 | 
			
		||||
      STOPPED: () => {
 | 
			
		||||
        console.log('STOPPED state');
 | 
			
		||||
      },
 | 
			
		||||
    };
 | 
			
		||||
    this.matrixClient.on('sync', (state, prevState) => sync[state](prevState));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  listenEvents() {
 | 
			
		||||
    this.matrixClient.on('Session.logged_out', async () => {
 | 
			
		||||
      this.matrixClient.stopClient();
 | 
			
		||||
      await this.matrixClient.clearStores();
 | 
			
		||||
      window.localStorage.clear();
 | 
			
		||||
      window.location.reload();
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async logout() {
 | 
			
		||||
    this.matrixClient.stopClient();
 | 
			
		||||
    try {
 | 
			
		||||
      await this.matrixClient.logout();
 | 
			
		||||
    } catch {
 | 
			
		||||
      // ignore if failed to logout
 | 
			
		||||
    }
 | 
			
		||||
    await this.matrixClient.clearStores();
 | 
			
		||||
    window.localStorage.clear();
 | 
			
		||||
    window.location.reload();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  clearCacheAndReload() {
 | 
			
		||||
    this.matrixClient.stopClient();
 | 
			
		||||
    this.matrixClient.store.deleteAllData().then(() => {
 | 
			
		||||
      window.location.reload();
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const initMatrix = new InitMatrix();
 | 
			
		||||
 | 
			
		||||
export default initMatrix;
 | 
			
		||||
							
								
								
									
										70
									
								
								src/client/initMatrix.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								src/client/initMatrix.ts
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,70 @@
 | 
			
		|||
import { createClient, MatrixClient, IndexedDBStore, IndexedDBCryptoStore } from 'matrix-js-sdk';
 | 
			
		||||
import Olm from '@matrix-org/olm';
 | 
			
		||||
import { logger } from 'matrix-js-sdk/lib/logger';
 | 
			
		||||
 | 
			
		||||
import { cryptoCallbacks } from './state/secretStorageKeys';
 | 
			
		||||
 | 
			
		||||
global.Olm = Olm;
 | 
			
		||||
 | 
			
		||||
if (import.meta.env.PROD) {
 | 
			
		||||
  logger.disableAll();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Session = {
 | 
			
		||||
  baseUrl: string;
 | 
			
		||||
  accessToken: string;
 | 
			
		||||
  userId: string;
 | 
			
		||||
  deviceId: string;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const initClient = async (session: Session): Promise<MatrixClient> => {
 | 
			
		||||
  const indexedDBStore = new IndexedDBStore({
 | 
			
		||||
    indexedDB: global.indexedDB,
 | 
			
		||||
    localStorage: global.localStorage,
 | 
			
		||||
    dbName: 'web-sync-store',
 | 
			
		||||
  });
 | 
			
		||||
  await indexedDBStore.startup();
 | 
			
		||||
 | 
			
		||||
  const mx = createClient({
 | 
			
		||||
    baseUrl: session.baseUrl,
 | 
			
		||||
    accessToken: session.accessToken,
 | 
			
		||||
    userId: session.userId,
 | 
			
		||||
    store: indexedDBStore,
 | 
			
		||||
    cryptoStore: new IndexedDBCryptoStore(global.indexedDB, 'crypto-store'),
 | 
			
		||||
    deviceId: session.deviceId,
 | 
			
		||||
    timelineSupport: true,
 | 
			
		||||
    cryptoCallbacks: cryptoCallbacks as any,
 | 
			
		||||
    verificationMethods: ['m.sas.v1'],
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  await mx.initCrypto();
 | 
			
		||||
 | 
			
		||||
  mx.setGlobalErrorOnUnknownDevices(false);
 | 
			
		||||
  mx.setMaxListeners(50);
 | 
			
		||||
 | 
			
		||||
  return mx;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const startClient = async (mx: MatrixClient) => {
 | 
			
		||||
  await mx.startClient({
 | 
			
		||||
    lazyLoadMembers: true,
 | 
			
		||||
  });
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const clearCacheAndReload = async (mx: MatrixClient) => {
 | 
			
		||||
  mx.stopClient();
 | 
			
		||||
  await mx.store.deleteAllData();
 | 
			
		||||
  window.location.reload();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const logoutClient = async (mx: MatrixClient) => {
 | 
			
		||||
  mx.stopClient();
 | 
			
		||||
  try {
 | 
			
		||||
    await mx.logout();
 | 
			
		||||
  } catch {
 | 
			
		||||
    // ignore if failed to logout
 | 
			
		||||
  }
 | 
			
		||||
  await mx.clearStores();
 | 
			
		||||
  window.localStorage.clear();
 | 
			
		||||
  window.location.reload();
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -1,7 +0,0 @@
 | 
			
		|||
import { MatrixClient } from 'matrix-js-sdk';
 | 
			
		||||
import initMatrix from './initMatrix';
 | 
			
		||||
 | 
			
		||||
export const mx = (): MatrixClient => {
 | 
			
		||||
  if (!initMatrix.matrixClient) console.error('Matrix client is used before initialization!');
 | 
			
		||||
  return initMatrix.matrixClient!;
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -409,6 +409,8 @@ body {
 | 
			
		|||
#root {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  height: 100%;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
*,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,3 @@
 | 
			
		|||
import initMatrix from '../client/initMatrix';
 | 
			
		||||
 | 
			
		||||
import HashIC from '../../public/res/ic/outlined/hash.svg';
 | 
			
		||||
import HashGlobeIC from '../../public/res/ic/outlined/hash-globe.svg';
 | 
			
		||||
import HashLockIC from '../../public/res/ic/outlined/hash-lock.svg';
 | 
			
		||||
| 
						 | 
				
			
			@ -24,8 +22,7 @@ export async function getBaseUrl(servername) {
 | 
			
		|||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function getUsername(userId) {
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
export function getUsername(mx, userId) {
 | 
			
		||||
  const user = mx.getUser(userId);
 | 
			
		||||
  if (user === null) return userId;
 | 
			
		||||
  let username = user.displayName;
 | 
			
		||||
| 
						 | 
				
			
			@ -39,9 +36,9 @@ export function getUsernameOfRoomMember(roomMember) {
 | 
			
		|||
  return roomMember.name || roomMember.userId;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function isRoomAliasAvailable(alias) {
 | 
			
		||||
export async function isRoomAliasAvailable(mx, alias) {
 | 
			
		||||
  try {
 | 
			
		||||
    const result = await initMatrix.matrixClient.getRoomIdForAlias(alias);
 | 
			
		||||
    const result = await mx.getRoomIdForAlias(alias);
 | 
			
		||||
    if (result.room_id) return false;
 | 
			
		||||
    return false;
 | 
			
		||||
  } catch (e) {
 | 
			
		||||
| 
						 | 
				
			
			@ -159,9 +156,8 @@ export function genRoomVia(room) {
 | 
			
		|||
  return via.concat(mostPop3.slice(0, 2));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function isCrossVerified(deviceId) {
 | 
			
		||||
export function isCrossVerified(mx, deviceId) {
 | 
			
		||||
  try {
 | 
			
		||||
    const mx = initMatrix.matrixClient;
 | 
			
		||||
    const crossSignInfo = mx.getStoredCrossSigningForUser(mx.getUserId());
 | 
			
		||||
    const deviceInfo = mx.getStoredDevice(mx.getUserId(), deviceId);
 | 
			
		||||
    const deviceTrust = crossSignInfo.checkDeviceTrust(crossSignInfo, deviceInfo, false, true);
 | 
			
		||||
| 
						 | 
				
			
			@ -172,14 +168,12 @@ export function isCrossVerified(deviceId) {
 | 
			
		|||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function hasCrossSigningAccountData() {
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
export function hasCrossSigningAccountData(mx) {
 | 
			
		||||
  const masterKeyData = mx.getAccountData('m.cross_signing.master');
 | 
			
		||||
  return !!masterKeyData;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function getDefaultSSKey() {
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
export function getDefaultSSKey(mx) {
 | 
			
		||||
  try {
 | 
			
		||||
    return mx.getAccountData('m.secret_storage.default_key').getContent().key;
 | 
			
		||||
  } catch {
 | 
			
		||||
| 
						 | 
				
			
			@ -187,8 +181,7 @@ export function getDefaultSSKey() {
 | 
			
		|||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function getSSKeyInfo(key) {
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
export function getSSKeyInfo(mx, key) {
 | 
			
		||||
  try {
 | 
			
		||||
    return mx.getAccountData(`m.secret_storage.key.${key}`).getContent();
 | 
			
		||||
  } catch {
 | 
			
		||||
| 
						 | 
				
			
			@ -196,8 +189,7 @@ export function getSSKeyInfo(key) {
 | 
			
		|||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function hasDevices(userId) {
 | 
			
		||||
  const mx = initMatrix.matrixClient;
 | 
			
		||||
export async function hasDevices(mx, userId) {
 | 
			
		||||
  try {
 | 
			
		||||
    const usersDeviceMap = await mx.downloadKeys([userId, mx.getUserId()]);
 | 
			
		||||
    return Object.values(usersDeviceMap)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,30 +1,3 @@
 | 
			
		|||
import initMatrix from '../client/initMatrix';
 | 
			
		||||
 | 
			
		||||
export function roomIdByActivity(id1, id2) {
 | 
			
		||||
  const room1 = initMatrix.matrixClient.getRoom(id1);
 | 
			
		||||
  const room2 = initMatrix.matrixClient.getRoom(id2);
 | 
			
		||||
 | 
			
		||||
  return room2.getLastActiveTimestamp() - room1.getLastActiveTimestamp();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function roomIdByAtoZ(aId, bId) {
 | 
			
		||||
  let aName = initMatrix.matrixClient.getRoom(aId).name;
 | 
			
		||||
  let bName = initMatrix.matrixClient.getRoom(bId).name;
 | 
			
		||||
 | 
			
		||||
  // remove "#" from the room name
 | 
			
		||||
  // To ignore it in sorting
 | 
			
		||||
  aName = aName.replace(/#/g, '');
 | 
			
		||||
  bName = bName.replace(/#/g, '');
 | 
			
		||||
 | 
			
		||||
  if (aName.toLowerCase() < bName.toLowerCase()) {
 | 
			
		||||
    return -1;
 | 
			
		||||
  }
 | 
			
		||||
  if (aName.toLowerCase() > bName.toLowerCase()) {
 | 
			
		||||
    return 1;
 | 
			
		||||
  }
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function memberByAtoZ(m1, m2) {
 | 
			
		||||
  const aName = m1.name;
 | 
			
		||||
  const bName = m2.name;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue