Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
abd713d693 | ||
|
|
802357b7a0 | ||
|
|
c5d4530947 | ||
|
|
367397fdd4 | ||
|
|
63fa60e7f4 | ||
|
|
544a06964d | ||
|
|
50583f9474 | ||
|
|
1ad7fe8deb | ||
|
|
752a19a4e7 |
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "cinny",
|
||||
"version": "4.9.0",
|
||||
"version": "4.9.1",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "cinny",
|
||||
"version": "4.9.0",
|
||||
"version": "4.9.1",
|
||||
"license": "AGPL-3.0-only",
|
||||
"dependencies": {
|
||||
"@atlaskit/pragmatic-drag-and-drop": "1.1.6",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "cinny",
|
||||
"version": "4.9.0",
|
||||
"version": "4.9.1",
|
||||
"description": "Yet another matrix client",
|
||||
"main": "index.js",
|
||||
"type": "module",
|
||||
|
||||
@@ -23,6 +23,7 @@ import { UserAvatar } from '../user-avatar';
|
||||
import { useMediaAuthentication } from '../../hooks/useMediaAuthentication';
|
||||
import { useOpenUserRoomProfile } from '../../state/hooks/userRoomProfile';
|
||||
import { useSpaceOptionally } from '../../hooks/useSpace';
|
||||
import { getMouseEventCords } from '../../utils/dom';
|
||||
|
||||
export type EventReadersProps = {
|
||||
room: Room;
|
||||
@@ -83,7 +84,7 @@ export const EventReaders = as<'div', EventReadersProps>(
|
||||
room.roomId,
|
||||
space?.roomId,
|
||||
readerId,
|
||||
event.currentTarget.getBoundingClientRect(),
|
||||
getMouseEventCords(event.nativeEvent),
|
||||
'Bottom'
|
||||
);
|
||||
}}
|
||||
|
||||
131
src/app/components/join-address-prompt/JoinAddressPrompt.tsx
Normal file
131
src/app/components/join-address-prompt/JoinAddressPrompt.tsx
Normal file
@@ -0,0 +1,131 @@
|
||||
import React, { FormEventHandler, useState } from 'react';
|
||||
import FocusTrap from 'focus-trap-react';
|
||||
import {
|
||||
Dialog,
|
||||
Overlay,
|
||||
OverlayCenter,
|
||||
OverlayBackdrop,
|
||||
Header,
|
||||
config,
|
||||
Box,
|
||||
Text,
|
||||
IconButton,
|
||||
Icon,
|
||||
Icons,
|
||||
Button,
|
||||
Input,
|
||||
color,
|
||||
} from 'folds';
|
||||
import { stopPropagation } from '../../utils/keyboard';
|
||||
import { isRoomAlias, isRoomId } from '../../utils/matrix';
|
||||
import { parseMatrixToRoom, parseMatrixToRoomEvent, testMatrixTo } from '../../plugins/matrix-to';
|
||||
import { tryDecodeURIComponent } from '../../utils/dom';
|
||||
|
||||
type JoinAddressProps = {
|
||||
onOpen: (roomIdOrAlias: string, via?: string[], eventId?: string) => void;
|
||||
onCancel: () => void;
|
||||
};
|
||||
export function JoinAddressPrompt({ onOpen, onCancel }: JoinAddressProps) {
|
||||
const [invalid, setInvalid] = useState(false);
|
||||
|
||||
const handleSubmit: FormEventHandler<HTMLFormElement> = (evt) => {
|
||||
evt.preventDefault();
|
||||
setInvalid(false);
|
||||
|
||||
const target = evt.target as HTMLFormElement | undefined;
|
||||
const addressInput = target?.addressInput as HTMLInputElement | undefined;
|
||||
const address = addressInput?.value.trim();
|
||||
if (!address) return;
|
||||
|
||||
if (isRoomId(address) || isRoomAlias(address)) {
|
||||
onOpen(address);
|
||||
return;
|
||||
}
|
||||
|
||||
if (testMatrixTo(address)) {
|
||||
const decodedAddress = tryDecodeURIComponent(address);
|
||||
const toRoom = parseMatrixToRoom(decodedAddress);
|
||||
if (toRoom) {
|
||||
onOpen(toRoom.roomIdOrAlias, toRoom.viaServers);
|
||||
return;
|
||||
}
|
||||
|
||||
const toEvent = parseMatrixToRoomEvent(decodedAddress);
|
||||
if (toEvent) {
|
||||
onOpen(toEvent.roomIdOrAlias, toEvent.viaServers, toEvent.eventId);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
setInvalid(true);
|
||||
};
|
||||
|
||||
return (
|
||||
<Overlay open backdrop={<OverlayBackdrop />}>
|
||||
<OverlayCenter>
|
||||
<FocusTrap
|
||||
focusTrapOptions={{
|
||||
initialFocus: false,
|
||||
onDeactivate: onCancel,
|
||||
clickOutsideDeactivates: true,
|
||||
escapeDeactivates: stopPropagation,
|
||||
}}
|
||||
>
|
||||
<Dialog variant="Surface">
|
||||
<Header
|
||||
style={{
|
||||
padding: `0 ${config.space.S200} 0 ${config.space.S400}`,
|
||||
}}
|
||||
variant="Surface"
|
||||
size="500"
|
||||
>
|
||||
<Box grow="Yes">
|
||||
<Text size="H4">Join with Address</Text>
|
||||
</Box>
|
||||
<IconButton size="300" onClick={onCancel} radii="300">
|
||||
<Icon src={Icons.Cross} />
|
||||
</IconButton>
|
||||
</Header>
|
||||
<Box
|
||||
as="form"
|
||||
onSubmit={handleSubmit}
|
||||
style={{ padding: config.space.S400, paddingTop: 0 }}
|
||||
direction="Column"
|
||||
gap="400"
|
||||
>
|
||||
<Box direction="Column" gap="200">
|
||||
<Text priority="400" size="T300">
|
||||
Enter public address to join the community. Addresses looks like:
|
||||
</Text>
|
||||
<Text as="ul" size="T200" priority="300" style={{ paddingLeft: config.space.S400 }}>
|
||||
<li>#community:server</li>
|
||||
<li>https://matrix.to/#/#community:server</li>
|
||||
<li>https://matrix.to/#/!xYzAj?via=server</li>
|
||||
</Text>
|
||||
</Box>
|
||||
<Box direction="Column" gap="100">
|
||||
<Text size="L400">Address</Text>
|
||||
<Input
|
||||
size="500"
|
||||
autoFocus
|
||||
name="addressInput"
|
||||
variant="Background"
|
||||
placeholder="#community:server"
|
||||
required
|
||||
/>
|
||||
{invalid && (
|
||||
<Text size="T200" style={{ color: color.Critical.Main }}>
|
||||
<b>Invalid Address</b>
|
||||
</Text>
|
||||
)}
|
||||
</Box>
|
||||
<Button type="submit" variant="Primary">
|
||||
<Text size="B400">Open</Text>
|
||||
</Button>
|
||||
</Box>
|
||||
</Dialog>
|
||||
</FocusTrap>
|
||||
</OverlayCenter>
|
||||
</Overlay>
|
||||
);
|
||||
}
|
||||
1
src/app/components/join-address-prompt/index.ts
Normal file
1
src/app/components/join-address-prompt/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from './JoinAddressPrompt';
|
||||
@@ -124,8 +124,8 @@ export function UserRoomProfile({ userId }: UserRoomProfileProps) {
|
||||
{server && <ServerChip server={server} />}
|
||||
<ShareChip userId={userId} />
|
||||
{creator ? <CreatorChip /> : <PowerChip userId={userId} />}
|
||||
<MutualRoomsChip userId={userId} />
|
||||
<OptionsChip userId={userId} />
|
||||
{userId !== myUserId && <MutualRoomsChip userId={userId} />}
|
||||
{userId !== myUserId && <OptionsChip userId={userId} />}
|
||||
</Box>
|
||||
</Box>
|
||||
{ignored && <IgnoredUserAlert />}
|
||||
|
||||
@@ -55,6 +55,7 @@ import {
|
||||
import { useSpaceOptionally } from '../../../hooks/useSpace';
|
||||
import { useFlattenPowerTagMembers, useGetMemberPowerTag } from '../../../hooks/useMemberPowerTag';
|
||||
import { useRoomCreators } from '../../../hooks/useRoomCreators';
|
||||
import { getMouseEventCords } from '../../../utils/dom';
|
||||
|
||||
const SEARCH_OPTIONS: UseAsyncSearchOptions = {
|
||||
limit: 1000,
|
||||
@@ -145,7 +146,7 @@ export function Members({ requestClose }: MembersProps) {
|
||||
const btn = evt.currentTarget as HTMLButtonElement;
|
||||
const userId = btn.getAttribute('data-user-id');
|
||||
if (userId) {
|
||||
openProfile(room.roomId, space?.roomId, userId, btn.getBoundingClientRect());
|
||||
openProfile(room.roomId, space?.roomId, userId, getMouseEventCords(evt.nativeEvent));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ import { UserAvatar } from '../../../components/user-avatar';
|
||||
import { useMediaAuthentication } from '../../../hooks/useMediaAuthentication';
|
||||
import { useOpenUserRoomProfile } from '../../../state/hooks/userRoomProfile';
|
||||
import { useSpaceOptionally } from '../../../hooks/useSpace';
|
||||
import { getMouseEventCords } from '../../../utils/dom';
|
||||
|
||||
export type ReactionViewerProps = {
|
||||
room: Room;
|
||||
@@ -136,7 +137,7 @@ export const ReactionViewer = as<'div', ReactionViewerProps>(
|
||||
room.roomId,
|
||||
space?.roomId,
|
||||
senderId,
|
||||
event.currentTarget.getBoundingClientRect(),
|
||||
getMouseEventCords(event.nativeEvent),
|
||||
'Bottom'
|
||||
);
|
||||
}}
|
||||
|
||||
@@ -51,7 +51,7 @@ const DEFAULT_TAGS: PowerLevelTags = {
|
||||
color: '#ff6a00',
|
||||
},
|
||||
150: {
|
||||
name: 'Co-Founder',
|
||||
name: 'Manager',
|
||||
color: '#ff6a7f',
|
||||
},
|
||||
101: {
|
||||
|
||||
@@ -15,7 +15,7 @@ export function AuthFooter() {
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
v4.9.0
|
||||
v4.9.1
|
||||
</Text>
|
||||
<Text as="a" size="T300" href="https://twitter.com/cinnyapp" target="_blank" rel="noreferrer">
|
||||
Twitter
|
||||
|
||||
@@ -24,7 +24,7 @@ export function WelcomePage() {
|
||||
target="_blank"
|
||||
rel="noreferrer noopener"
|
||||
>
|
||||
v4.9.0
|
||||
v4.9.1
|
||||
</a>
|
||||
</span>
|
||||
}
|
||||
|
||||
@@ -30,10 +30,12 @@ import {
|
||||
NavLink,
|
||||
} from '../../../components/nav';
|
||||
import {
|
||||
encodeSearchParamValueArray,
|
||||
getExplorePath,
|
||||
getHomeCreatePath,
|
||||
getHomeRoomPath,
|
||||
getHomeSearchPath,
|
||||
withSearchParam,
|
||||
} from '../../pathUtils';
|
||||
import { getCanonicalAliasOrRoomId } from '../../../utils/matrix';
|
||||
import { useSelectedRoom } from '../../../hooks/router/useSelectedRoom';
|
||||
@@ -49,7 +51,6 @@ import { makeNavCategoryId } from '../../../state/closedNavCategories';
|
||||
import { roomToUnreadAtom } from '../../../state/room/roomToUnread';
|
||||
import { useCategoryHandler } from '../../../hooks/useCategoryHandler';
|
||||
import { useNavToActivePathMapper } from '../../../hooks/useNavToActivePathMapper';
|
||||
import { openJoinAlias } from '../../../../client/action/navigation';
|
||||
import { PageNav, PageNavHeader, PageNavContent } from '../../../components/page';
|
||||
import { useRoomsUnread } from '../../../state/hooks/unread';
|
||||
import { markAsRead } from '../../../../client/action/notifications';
|
||||
@@ -61,6 +62,9 @@ import {
|
||||
getRoomNotificationMode,
|
||||
useRoomsNotificationPreferencesContext,
|
||||
} from '../../../hooks/useRoomsNotificationPreferences';
|
||||
import { UseStateProvider } from '../../../components/UseStateProvider';
|
||||
import { JoinAddressPrompt } from '../../../components/join-address-prompt';
|
||||
import { _RoomSearchParams } from '../../paths';
|
||||
|
||||
type HomeMenuProps = {
|
||||
requestClose: () => void;
|
||||
@@ -77,11 +81,6 @@ const HomeMenu = forwardRef<HTMLDivElement, HomeMenuProps>(({ requestClose }, re
|
||||
requestClose();
|
||||
};
|
||||
|
||||
const handleJoinAddress = () => {
|
||||
openJoinAlias();
|
||||
requestClose();
|
||||
};
|
||||
|
||||
return (
|
||||
<Menu ref={ref} style={{ maxWidth: toRem(160), width: '100vw' }}>
|
||||
<Box direction="Column" gap="100" style={{ padding: config.space.S100 }}>
|
||||
@@ -96,16 +95,6 @@ const HomeMenu = forwardRef<HTMLDivElement, HomeMenuProps>(({ requestClose }, re
|
||||
Mark as Read
|
||||
</Text>
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
onClick={handleJoinAddress}
|
||||
size="300"
|
||||
radii="300"
|
||||
after={<Icon size="100" src={Icons.Link} />}
|
||||
>
|
||||
<Text style={{ flexGrow: 1 }} as="span" size="T300" truncate>
|
||||
Join with Address
|
||||
</Text>
|
||||
</MenuItem>
|
||||
</Box>
|
||||
</Menu>
|
||||
);
|
||||
@@ -268,22 +257,44 @@ export function Home() {
|
||||
</NavItemContent>
|
||||
</NavButton>
|
||||
</NavItem>
|
||||
<NavItem variant="Background" radii="400">
|
||||
<NavButton onClick={() => openJoinAlias()}>
|
||||
<NavItemContent>
|
||||
<Box as="span" grow="Yes" alignItems="Center" gap="200">
|
||||
<Avatar size="200" radii="400">
|
||||
<Icon src={Icons.Link} size="100" />
|
||||
</Avatar>
|
||||
<Box as="span" grow="Yes">
|
||||
<Text as="span" size="Inherit" truncate>
|
||||
Join with Address
|
||||
</Text>
|
||||
</Box>
|
||||
</Box>
|
||||
</NavItemContent>
|
||||
</NavButton>
|
||||
</NavItem>
|
||||
<UseStateProvider initial={false}>
|
||||
{(open, setOpen) => (
|
||||
<>
|
||||
<NavItem variant="Background" radii="400">
|
||||
<NavButton onClick={() => setOpen(true)}>
|
||||
<NavItemContent>
|
||||
<Box as="span" grow="Yes" alignItems="Center" gap="200">
|
||||
<Avatar size="200" radii="400">
|
||||
<Icon src={Icons.Link} size="100" />
|
||||
</Avatar>
|
||||
<Box as="span" grow="Yes">
|
||||
<Text as="span" size="Inherit" truncate>
|
||||
Join with Address
|
||||
</Text>
|
||||
</Box>
|
||||
</Box>
|
||||
</NavItemContent>
|
||||
</NavButton>
|
||||
</NavItem>
|
||||
{open && (
|
||||
<JoinAddressPrompt
|
||||
onCancel={() => setOpen(false)}
|
||||
onOpen={(roomIdOrAlias, viaServers, eventId) => {
|
||||
setOpen(false);
|
||||
const path = getHomeRoomPath(roomIdOrAlias, eventId);
|
||||
navigate(
|
||||
viaServers
|
||||
? withSearchParam<_RoomSearchParams>(path, {
|
||||
viaServers: encodeSearchParamValueArray(viaServers),
|
||||
})
|
||||
: path
|
||||
);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</UseStateProvider>
|
||||
<NavItem variant="Background" radii="400" aria-selected={searchSelected}>
|
||||
<NavLink to={getHomeSearchPath()}>
|
||||
<NavItemContent>
|
||||
|
||||
@@ -7,15 +7,22 @@ import { stopPropagation } from '../../../utils/keyboard';
|
||||
import { SequenceCard } from '../../../components/sequence-card';
|
||||
import { SettingTile } from '../../../components/setting-tile';
|
||||
import { ContainerColor } from '../../../styles/ContainerColor.css';
|
||||
import { openJoinAlias } from '../../../../client/action/navigation';
|
||||
import { getCreatePath } from '../../pathUtils';
|
||||
import {
|
||||
encodeSearchParamValueArray,
|
||||
getCreatePath,
|
||||
getSpacePath,
|
||||
withSearchParam,
|
||||
} from '../../pathUtils';
|
||||
import { useCreateSelected } from '../../../hooks/router/useCreateSelected';
|
||||
import { JoinAddressPrompt } from '../../../components/join-address-prompt';
|
||||
import { _RoomSearchParams } from '../../paths';
|
||||
|
||||
export function CreateTab() {
|
||||
const createSelected = useCreateSelected();
|
||||
|
||||
const navigate = useNavigate();
|
||||
const [menuCords, setMenuCords] = useState<RectCords>();
|
||||
const [joinAddress, setJoinAddress] = useState(false);
|
||||
|
||||
const handleMenu: MouseEventHandler<HTMLButtonElement> = (evt) => {
|
||||
setMenuCords(menuCords ? undefined : evt.currentTarget.getBoundingClientRect());
|
||||
@@ -27,7 +34,7 @@ export function CreateTab() {
|
||||
};
|
||||
|
||||
const handleJoinWithAddress = () => {
|
||||
openJoinAlias();
|
||||
setJoinAddress(true);
|
||||
setMenuCords(undefined);
|
||||
};
|
||||
|
||||
@@ -103,6 +110,22 @@ export function CreateTab() {
|
||||
>
|
||||
<Icon src={Icons.Plus} />
|
||||
</SidebarAvatar>
|
||||
{joinAddress && (
|
||||
<JoinAddressPrompt
|
||||
onCancel={() => setJoinAddress(false)}
|
||||
onOpen={(roomIdOrAlias, viaServers) => {
|
||||
setJoinAddress(false);
|
||||
const path = getSpacePath(roomIdOrAlias);
|
||||
navigate(
|
||||
viaServers
|
||||
? withSearchParam<_RoomSearchParams>(path, {
|
||||
viaServers: encodeSearchParamValueArray(viaServers),
|
||||
})
|
||||
: path
|
||||
);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</PopOut>
|
||||
)}
|
||||
</SidebarItemTooltip>
|
||||
|
||||
@@ -297,7 +297,7 @@ function SpaceHeader() {
|
||||
type SpaceTombstoneProps = { roomId: string; replacementRoomId: string };
|
||||
export function SpaceTombstone({ roomId, replacementRoomId }: SpaceTombstoneProps) {
|
||||
const mx = useMatrixClient();
|
||||
const { navigateRoom } = useRoomNavigate();
|
||||
const { navigateSpace } = useRoomNavigate();
|
||||
|
||||
const [joinState, handleJoin] = useAsyncCallback(
|
||||
useCallback(() => {
|
||||
@@ -311,8 +311,8 @@ export function SpaceTombstone({ roomId, replacementRoomId }: SpaceTombstoneProp
|
||||
const replacementRoom = mx.getRoom(replacementRoomId);
|
||||
|
||||
const handleOpen = () => {
|
||||
if (replacementRoom) navigateRoom(replacementRoom.roomId);
|
||||
if (joinState.status === AsyncStatus.Success) navigateRoom(joinState.data.roomId);
|
||||
if (replacementRoom) navigateSpace(replacementRoom.roomId);
|
||||
if (joinState.status === AsyncStatus.Success) navigateSpace(joinState.data.roomId);
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@@ -42,9 +42,9 @@ const MATRIX_TO = /^https?:\/\/matrix\.to\S*$/;
|
||||
export const testMatrixTo = (href: string): boolean => MATRIX_TO.test(href);
|
||||
|
||||
const MATRIX_TO_USER = /^https?:\/\/matrix\.to\/#\/(@[^:\s]+:[^?/\s]+)\/?$/;
|
||||
const MATRIX_TO_ROOM = /^https?:\/\/matrix\.to\/#\/([#!][^:\s]+:[^?/\s]+)\/?(\?[\S]*)?$/;
|
||||
const MATRIX_TO_ROOM = /^https?:\/\/matrix\.to\/#\/([#!][^?/\s]+)\/?(\?[\S]*)?$/;
|
||||
const MATRIX_TO_ROOM_EVENT =
|
||||
/^https?:\/\/matrix\.to\/#\/([#!][^:\s]+:[^?/\s]+)\/(\$[^?/\s]+)\/?(\?[\S]*)?$/;
|
||||
/^https?:\/\/matrix\.to\/#\/([#!][^?/\s]+)\/(\$[^?/\s]+)\/?(\?[\S]*)?$/;
|
||||
|
||||
export const parseMatrixToUser = (href: string): string | undefined => {
|
||||
const match = href.match(MATRIX_TO_USER);
|
||||
|
||||
@@ -1,11 +1,19 @@
|
||||
import { Room } from 'matrix-js-sdk';
|
||||
import { IPowerLevels } from '../hooks/usePowerLevels';
|
||||
import { getMxIdServer } from '../utils/matrix';
|
||||
import { StateEvent } from '../../types/matrix/room';
|
||||
import { creatorsSupported, getMxIdServer } from '../utils/matrix';
|
||||
import { IRoomCreateContent, StateEvent } from '../../types/matrix/room';
|
||||
import { getStateEvent } from '../utils/room';
|
||||
|
||||
export const getViaServers = (room: Room): string[] => {
|
||||
const getHighestPowerUserId = (): string | undefined => {
|
||||
const creatorEvent = getStateEvent(room, StateEvent.RoomCreate);
|
||||
if (
|
||||
creatorEvent &&
|
||||
creatorsSupported(creatorEvent.getContent<IRoomCreateContent>().room_version)
|
||||
) {
|
||||
return creatorEvent.getSender();
|
||||
}
|
||||
|
||||
const powerLevels = getStateEvent(room, StateEvent.RoomPowerLevels)?.getContent<IPowerLevels>();
|
||||
|
||||
if (!powerLevels) return undefined;
|
||||
|
||||
@@ -43,6 +43,17 @@ export const canFitInScrollView = (
|
||||
|
||||
export type FilesOrFile<T extends boolean | undefined = undefined> = T extends true ? File[] : File;
|
||||
|
||||
export const getFilesFromFileList = (fileList: FileList): File[] => {
|
||||
const files: File[] = [];
|
||||
|
||||
for (let i = 0; i < fileList.length; i += 1) {
|
||||
const file: File | undefined = fileList[i];
|
||||
if (file instanceof File) files.push(file);
|
||||
}
|
||||
|
||||
return files;
|
||||
};
|
||||
|
||||
export const selectFile = <M extends boolean | undefined = undefined>(
|
||||
accept: string,
|
||||
multiple?: M
|
||||
@@ -58,7 +69,7 @@ export const selectFile = <M extends boolean | undefined = undefined>(
|
||||
if (!fileList) {
|
||||
resolve(undefined);
|
||||
} else {
|
||||
const files: File[] = [...fileList].filter((file) => file);
|
||||
const files: File[] = getFilesFromFileList(fileList);
|
||||
resolve((multiple ? files : files[0]) as FilesOrFile<M>);
|
||||
}
|
||||
input.removeEventListener('change', changeHandler);
|
||||
@@ -70,7 +81,7 @@ export const selectFile = <M extends boolean | undefined = undefined>(
|
||||
|
||||
export const getDataTransferFiles = (dataTransfer: DataTransfer): File[] | undefined => {
|
||||
const fileList = dataTransfer.files;
|
||||
const files = [...fileList].filter((file) => file);
|
||||
const files: File[] = getFilesFromFileList(fileList);
|
||||
if (files.length === 0) return undefined;
|
||||
return files;
|
||||
};
|
||||
@@ -224,3 +235,10 @@ export const notificationPermission = (permission: NotificationPermission) => {
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
export const getMouseEventCords = (event: MouseEvent) => ({
|
||||
x: event.clientX,
|
||||
y: event.clientY,
|
||||
width: 0,
|
||||
height: 0,
|
||||
});
|
||||
|
||||
@@ -20,6 +20,7 @@ import {
|
||||
import { CryptoBackend } from 'matrix-js-sdk/lib/common-crypto/CryptoBackend';
|
||||
import { AccountDataEvent } from '../../types/matrix/accountData';
|
||||
import {
|
||||
IRoomCreateContent,
|
||||
Membership,
|
||||
MessageEvent,
|
||||
NotificationType,
|
||||
@@ -43,7 +44,7 @@ export const getStateEvents = (room: Room, eventType: StateEvent): MatrixEvent[]
|
||||
export const getAccountData = (
|
||||
mx: MatrixClient,
|
||||
eventType: AccountDataEvent
|
||||
): MatrixEvent | undefined => mx.getAccountData(eventType);
|
||||
): MatrixEvent | undefined => mx.getAccountData(eventType as any);
|
||||
|
||||
export const getMDirects = (mDirectEvent: MatrixEvent): Set<string> => {
|
||||
const roomIds = new Set<string>();
|
||||
@@ -480,6 +481,23 @@ export const bannedInRooms = (mx: MatrixClient, rooms: string[], otherUserId: st
|
||||
return banned;
|
||||
});
|
||||
|
||||
export const getAllVersionsRoomCreator = (room: Room): Set<string> => {
|
||||
const creators = new Set<string>();
|
||||
|
||||
const createEvent = getStateEvent(room, StateEvent.RoomCreate);
|
||||
const createContent = createEvent?.getContent<IRoomCreateContent>();
|
||||
const creator = createEvent?.getSender();
|
||||
if (typeof creator === 'string') creators.add(creator);
|
||||
|
||||
if (createContent && Array.isArray(createContent.additional_creators)) {
|
||||
createContent.additional_creators.forEach((c) => {
|
||||
if (typeof c === 'string') creators.add(c);
|
||||
});
|
||||
}
|
||||
|
||||
return creators;
|
||||
};
|
||||
|
||||
export const guessPerfectParent = (
|
||||
mx: MatrixClient,
|
||||
roomId: string,
|
||||
@@ -490,15 +508,29 @@ export const guessPerfectParent = (
|
||||
}
|
||||
|
||||
const getSpecialUsers = (rId: string): string[] => {
|
||||
const specialUsers: Set<string> = new Set();
|
||||
|
||||
const r = mx.getRoom(rId);
|
||||
const powerLevels =
|
||||
r && getStateEvent(r, StateEvent.RoomPowerLevels)?.getContent<IPowerLevelsContent>();
|
||||
if (!r) return [];
|
||||
|
||||
getAllVersionsRoomCreator(r).forEach((c) => specialUsers.add(c));
|
||||
|
||||
const powerLevels = getStateEvent(
|
||||
r,
|
||||
StateEvent.RoomPowerLevels
|
||||
)?.getContent<IPowerLevelsContent>();
|
||||
|
||||
const { users_default: usersDefault, users } = powerLevels ?? {};
|
||||
if (typeof users !== 'object') return [];
|
||||
|
||||
const defaultPower = typeof usersDefault === 'number' ? usersDefault : 0;
|
||||
return Object.keys(users).filter((userId) => users[userId] > defaultPower);
|
||||
|
||||
if (typeof users === 'object')
|
||||
Object.keys(users).forEach((userId) => {
|
||||
if (users[userId] > defaultPower) {
|
||||
specialUsers.add(userId);
|
||||
}
|
||||
});
|
||||
|
||||
return Array.from(specialUsers);
|
||||
};
|
||||
|
||||
let perfectParent: string | undefined;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
const cons = {
|
||||
version: '4.9.0',
|
||||
version: '4.9.1',
|
||||
secretKey: {
|
||||
ACCESS_TOKEN: 'cinny_access_token',
|
||||
DEVICE_ID: 'cinny_device_id',
|
||||
|
||||
@@ -70,6 +70,7 @@ export type IRoomCreateContent = {
|
||||
['m.federate']?: boolean;
|
||||
room_version: string;
|
||||
type?: string;
|
||||
additional_creators?: string[];
|
||||
predecessor?: {
|
||||
event_id?: string;
|
||||
room_id: string;
|
||||
|
||||
Reference in New Issue
Block a user