use authenticated media everywhere (almost)

This commit is contained in:
OfficialDakari 2024-12-30 21:27:53 +05:00
parent 2e5507cf94
commit 659b7d5e12
39 changed files with 342 additions and 359 deletions

21
package-lock.json generated
View file

@ -37,6 +37,7 @@
"domhandler": "5.0.3",
"emojibase": "6.1.0",
"emojibase-data": "7.0.1",
"eruda": "3.4.1",
"file-saver": "2.0.5",
"flux": "4.0.3",
"focus-trap-react": "10.0.2",
@ -46,7 +47,6 @@
"html-dom-parser": "4.0.0",
"html-react-parser": "4.2.0",
"immer": "9.0.16",
"is-hotkey": "0.2.0",
"jotai": "2.6.0",
"leaflet": "1.9.4",
"linkify-react": "4.1.3",
@ -87,6 +87,7 @@
"@rollup/plugin-inject": "5.0.3",
"@rollup/plugin-wasm": "6.1.1",
"@types/file-saver": "2.0.5",
"@types/is-hotkey": "0.1.10",
"@types/leaflet": "1.9.12",
"@types/md5": "2.3.5",
"@types/node": "18.11.18",
@ -111,6 +112,7 @@
"eslint-plugin-jsx-a11y": "6.6.1",
"eslint-plugin-react": "7.31.11",
"eslint-plugin-react-hooks": "4.6.0",
"is-hotkey": "0.2.0",
"prettier": "2.8.1",
"sass": "1.56.2",
"typescript": "4.9.4",
@ -5580,6 +5582,13 @@
"hoist-non-react-statics": "^3.3.0"
}
},
"node_modules/@types/is-hotkey": {
"version": "0.1.10",
"resolved": "https://registry.npmjs.org/@types/is-hotkey/-/is-hotkey-0.1.10.tgz",
"integrity": "sha512-RvC8KMw5BCac1NvRRyaHgMMEtBaZ6wh0pyPTBu7izn4Sj/AX9Y4aXU5c7rX8PnM/knsuUpC1IeoBkANtxBypsQ==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/json-schema": {
"version": "7.0.11",
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz",
@ -7394,6 +7403,12 @@
"is-arrayish": "^0.2.1"
}
},
"node_modules/eruda": {
"version": "3.4.1",
"resolved": "https://registry.npmjs.org/eruda/-/eruda-3.4.1.tgz",
"integrity": "sha512-RmaO5yD97URY/9Q0lye3cmmNPoXNKreeePIw7c/zllbscR92CjGFZFuQ70+0fLIvLcKW3Xha8DS8NFhmeNbEBQ==",
"license": "MIT"
},
"node_modules/es-abstract": {
"version": "1.23.3",
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz",
@ -9165,7 +9180,9 @@
"node_modules/is-hotkey": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/is-hotkey/-/is-hotkey-0.2.0.tgz",
"integrity": "sha512-UknnZK4RakDmTgz4PI1wIph5yxSs/mvChWs9ifnlXsKuXgWmOkY/hAE0H/k2MIqH0RlRye0i1oC07MCRSD28Mw=="
"integrity": "sha512-UknnZK4RakDmTgz4PI1wIph5yxSs/mvChWs9ifnlXsKuXgWmOkY/hAE0H/k2MIqH0RlRye0i1oC07MCRSD28Mw==",
"dev": true,
"license": "MIT"
},
"node_modules/is-module": {
"version": "1.0.0",

View file

@ -48,6 +48,7 @@
"domhandler": "5.0.3",
"emojibase": "6.1.0",
"emojibase-data": "7.0.1",
"eruda": "3.4.1",
"file-saver": "2.0.5",
"flux": "4.0.3",
"focus-trap-react": "10.0.2",
@ -57,7 +58,6 @@
"html-dom-parser": "4.0.0",
"html-react-parser": "4.2.0",
"immer": "9.0.16",
"is-hotkey": "0.2.0",
"jotai": "2.6.0",
"leaflet": "1.9.4",
"linkify-react": "4.1.3",
@ -98,6 +98,7 @@
"@rollup/plugin-inject": "5.0.3",
"@rollup/plugin-wasm": "6.1.1",
"@types/file-saver": "2.0.5",
"@types/is-hotkey": "0.1.10",
"@types/leaflet": "1.9.12",
"@types/md5": "2.3.5",
"@types/node": "18.11.18",
@ -122,6 +123,7 @@
"eslint-plugin-jsx-a11y": "6.6.1",
"eslint-plugin-react": "7.31.11",
"eslint-plugin-react-hooks": "4.6.0",
"is-hotkey": "0.2.0",
"prettier": "2.8.1",
"sass": "1.56.2",
"typescript": "4.9.4",

View file

@ -17,6 +17,7 @@ import { IEmoji, emojis } from '../../../plugins/emoji';
import { ExtendedPackImage, PackUsage } from '../../../plugins/custom-emoji';
import { useKeyDown } from '../../../hooks/useKeyDown';
import { ListItemButton, ListItemIcon, ListItemText, Typography } from '@mui/material';
import { mxcUrlToHttp } from '../../../utils/matrix';
type EmoticonCompleteHandler = (key: string, shortcode: string) => void;
@ -76,7 +77,7 @@ export function EmoticonAutocomplete({
const ta = textAreaRef.current;
if (!ta) return;
const mxc = key.startsWith('mxc://');
const src = mxc ? mx.mxcUrlToHttp(key) : key;
const src = mxc ? mxcUrlToHttp(mx, key) : key;
console.log(src, key, shortcode);
var v = ta.value;
@ -127,7 +128,7 @@ export function EmoticonAutocomplete({
<Box
shrink="No"
as="img"
src={mx.mxcUrlToHttp(key) || key}
src={mxcUrlToHttp(mx, key) || key}
alt={emoticon.shortcode}
style={{ width: toRem(24), height: toRem(24), objectFit: 'contain' }}
/>

View file

@ -33,7 +33,7 @@ import { useRelevantImagePacks } from '../../hooks/useImagePacks';
import { useMatrixClient } from '../../hooks/useMatrixClient';
import { useRecentEmoji } from '../../hooks/useRecentEmoji';
import { ExtendedPackImage, ImagePack, PackUsage } from '../../plugins/custom-emoji';
import { isUserId } from '../../utils/matrix';
import { isUserId, mxcUrlToHttp } from '../../utils/matrix';
import { editableActiveElement, isIntersectingScrollView, targetFromEvent } from '../../utils/dom';
import { useAsyncSearch, UseAsyncSearchOptions } from '../../hooks/useAsyncSearch';
import { useDebounce } from '../../hooks/useDebounce';
@ -41,11 +41,8 @@ import { useThrottle } from '../../hooks/useThrottle';
import { addRecentEmoji } from '../../plugins/recent-emoji';
import { mobileOrTablet } from '../../utils/user-agent';
import { getText } from '../../../lang';
import { useSetting } from '../../state/hooks/settings';
import { settingsAtom } from '../../state/settings';
import { openJoinAlias } from '../../../client/action/navigation';
import Icon from '@mdi/react';
import { mdiArrowRight, mdiHistory, mdiMagnify, mdiSticker, mdiStickerOutline } from '@mdi/js';
import { mdiHistory, mdiStickerOutline } from '@mdi/js';
import { Divider, IconButton, Tab, Tabs, Theme, Tooltip, useTheme } from '@mui/material';
import { SearchContainer, SearchIcon, SearchIconWrapper, SearchInputBase } from '../../atoms/search/Search';
import { MotionBox } from '../../atoms/motion/Animated';
@ -367,7 +364,7 @@ function ImagePackSidebarStack({
height: toRem(24),
objectFit: 'contain',
}}
src={mx.mxcUrlToHttp(pack.getPackAvatarUrl(usage) ?? '') || pack.avatarUrl}
src={mxcUrlToHttp(mx, pack.getPackAvatarUrl(usage) ?? '') || pack.avatarUrl}
alt={label || getText('emojiboard.unknown_pack')}
/>
</SidebarBtn>

View file

@ -5,7 +5,7 @@ import { MatrixClient, MatrixEvent, Room } from 'matrix-js-sdk';
import * as css from './Reaction.css';
import { getHexcodeForEmoji, getShortcodeFor } from '../../plugins/emoji';
import { getMemberDisplayName } from '../../utils/room';
import { eventWithShortcode, getMxIdLocalPart } from '../../utils/matrix';
import { eventWithShortcode, getMxIdLocalPart, mxcUrlToHttp } from '../../utils/matrix';
import { getText } from '../../../lang';
import { Typography, useTheme } from '@mui/material';
@ -32,7 +32,7 @@ export const Reaction = as<
{reaction.startsWith('mxc://') ? (
<img
className={css.ReactionImg}
src={mx.mxcUrlToHttp(reaction) ?? reaction}
src={mxcUrlToHttp(mx, reaction) ?? reaction}
alt={reaction}
/>
) : (

View file

@ -21,6 +21,7 @@ import Icon from '@mdi/react';
import { mdiPause, mdiPlayOutline, mdiVolumeHigh, mdiVolumeMute } from '@mdi/js';
import { CircularProgress, IconButton, Slider } from '@mui/material';
import { AccessTime, Pause, PlayArrow } from '@mui/icons-material';
import { mxcUrlToHttp } from '../../../utils/matrix';
const PLAY_TIME_THROTTLE_OPS = {
wait: 500,
@ -51,7 +52,7 @@ export function AudioContent({
const [srcState, loadSrc] = useAsyncCallback(
useCallback(
() => getFileSrcUrl(mx.mxcUrlToHttp(url, undefined, undefined, undefined, false, true, true) ?? '', mimeType, encInfo, mx, !('cordova' in window)),
() => getFileSrcUrl(mxcUrlToHttp(mx, url) ?? '', mimeType, encInfo, mx, !('cordova' in window)),
[mx, url, mimeType, encInfo]
)
);

View file

@ -24,6 +24,7 @@ import { LoadingButton } from '@mui/lab';
import { BackButtonHandler } from '../../../hooks/useBackButton';
import { useModals } from '../../../hooks/useModals';
import { v4 } from 'uuid';
import { mxcUrlToHttp } from '../../../utils/matrix';
const renderErrorButton = (retry: () => void, text: string) => (
<Tooltip title={getText('msg.file.failed')}>
@ -58,7 +59,7 @@ export function ReadTextFile({ body, mimeType, url, encInfo, renderViewer, forma
const [textViewer, setTextViewer] = useState(false);
const loadSrc = useCallback(
() => getFileSrcUrl(mx.mxcUrlToHttp(url, undefined, undefined, undefined, false, true, true) ?? '', mimeType, encInfo),
() => getFileSrcUrl(mxcUrlToHttp(mx, url) ?? '', mimeType, encInfo),
[mx, url, mimeType, encInfo]
);
@ -132,7 +133,7 @@ export function ReadPdfFile({ body, mimeType, url, encInfo, renderViewer, format
const [pdfState, loadPdf] = useAsyncCallback(
useCallback(async () => {
const httpUrl = await getFileSrcUrl(mx.mxcUrlToHttp(url) ?? '', mimeType, encInfo);
const httpUrl = await getFileSrcUrl(mxcUrlToHttp(mx, url) ?? '', mimeType, encInfo);
setPdfViewer(true);
return httpUrl;
}, [mx, url, mimeType, encInfo])
@ -192,7 +193,7 @@ export function DownloadFile({ body, mimeType, url, info, encInfo, filename }: D
const [downloadState, download] = useAsyncCallback(
useCallback(async () => {
const httpUrl = await getFileSrcUrl(mx.mxcUrlToHttp(url, undefined, undefined, undefined, false, true, true) ?? '', mimeType, encInfo, mx);
const httpUrl = await getFileSrcUrl(mxcUrlToHttp(mx, url) ?? '', mimeType, encInfo, mx);
saveFile(httpUrl, filename ?? body);
return httpUrl;
}, [mx, url, mimeType, encInfo, body, filename])

View file

@ -5,7 +5,6 @@ import {
} from 'folds';
import classNames from 'classnames';
import { BlurhashCanvas } from 'react-blurhash';
import FocusTrap from 'focus-trap-react';
import { EncryptedAttachmentInfo } from 'browser-encrypt-attachment';
import { IImageInfo, MATRIX_BLUR_HASH_PROPERTY_NAME } from '../../../../types/matrix/common';
import { AsyncStatus, useAsyncCallback } from '../../../hooks/useAsyncCallback';
@ -14,13 +13,11 @@ import { getFileSrcUrl } from './util';
import * as css from './style.css';
import { bytesToSize } from '../../../utils/common';
import { FALLBACK_MIMETYPE } from '../../../utils/mimeTypes';
import { RenderBody } from '../RenderBody';
import HTMLReactParser, { HTMLReactParserOptions } from 'html-react-parser';
import { getReactCustomHtmlParser } from '../../../plugins/react-custom-html-parser';
import { getText } from '../../../../lang';
import { mdiAlert, mdiImage } from '@mdi/js';
import Icon from '@mdi/react';
import { Button, CircularProgress, Dialog, DialogTitle, Tooltip } from '@mui/material';
import { Button, CircularProgress, Dialog, Tooltip } from '@mui/material';
import { mxcUrlToHttp } from '../../../utils/matrix';
type RenderViewerProps = {
src: string;
@ -77,7 +74,7 @@ export const ImageContent = as<'div', ImageContentProps>(
const [srcState, loadSrc] = useAsyncCallback(
useCallback(
() => getFileSrcUrl(mx.mxcUrlToHttp(url, undefined, undefined, undefined, false, true, true) ?? '', mimeType || FALLBACK_MIMETYPE, encInfo, mx),
() => getFileSrcUrl(mxcUrlToHttp(mx, url) ?? '', mimeType || FALLBACK_MIMETYPE, encInfo, mx),
[mx, url, mimeType, encInfo]
)
);

View file

@ -4,6 +4,7 @@ import { useMatrixClient } from '../../../hooks/useMatrixClient';
import { AsyncStatus, useAsyncCallback } from '../../../hooks/useAsyncCallback';
import { getFileSrcUrl } from './util';
import { getText } from '../../../../lang';
import { mxcUrlToHttp } from '../../../utils/matrix';
export type ThumbnailContentProps = {
info: IThumbnailContent;
@ -20,7 +21,7 @@ export function ThumbnailContent({ info, renderImage }: ThumbnailContentProps) {
throw new Error(getText('msg.thumbnail.failed'));
}
return getFileSrcUrl(
mx.mxcUrlToHttp(thumbMxcUrl, undefined, undefined, undefined, false, true, true) ?? '',
mxcUrlToHttp(mx, thumbMxcUrl) ?? '',
thumbInfo.mimetype,
info.thumbnail_file,
mx

View file

@ -21,6 +21,7 @@ import { getText } from '../../../../lang';
import Icon from '@mdi/react';
import { mdiAlert, mdiPlay } from '@mdi/js';
import { Button, Chip, CircularProgress, Fab, Tooltip, Typography } from '@mui/material';
import { mxcUrlToHttp } from '../../../utils/matrix';
type RenderVideoProps = {
title: string;
@ -64,7 +65,7 @@ export const VideoContent = as<'div', VideoContentProps>(
const [srcState, loadSrc] = useAsyncCallback(
useCallback(
() => getFileSrcUrl(mx.mxcUrlToHttp(url, undefined, undefined, undefined, false, true, true) ?? '', mimeType, encInfo, mx, !('cordova' in window)),
() => getFileSrcUrl(mxcUrlToHttp(mx, url) ?? '', mimeType, encInfo, mx, !('cordova' in window)),
[mx, url, mimeType, encInfo]
)
);

View file

@ -1,8 +1,7 @@
/* eslint-disable jsx-a11y/media-has-caption */
import React, { ReactNode, useCallback, useEffect, useRef, useState } from 'react';
import { Box, Text, toRem } from 'folds';
import React, { ReactNode, useCallback, useRef, useState } from 'react';
import { Box, Text } from 'folds';
import { EncryptedAttachmentInfo } from 'browser-encrypt-attachment';
import { Range } from 'react-range';
import { useMatrixClient } from '../../../hooks/useMatrixClient';
import { AsyncStatus, useAsyncCallback } from '../../../hooks/useAsyncCallback';
import { getFileSrcUrl } from './util';
@ -20,6 +19,7 @@ import { secondsToMinutesAndSeconds } from '../../../utils/common';
import Icon from '@mdi/react';
import { mdiPause, mdiPlay } from '@mdi/js';
import { CircularProgress, IconButton, Slider, useTheme } from '@mui/material';
import { mxcUrlToHttp } from '../../../utils/matrix';
const PLAY_TIME_THROTTLE_OPS = {
wait: 500,
@ -51,7 +51,7 @@ export function VoiceContent({
const [srcState, loadSrc] = useAsyncCallback(
useCallback(
() => getFileSrcUrl(mx.mxcUrlToHttp(url, undefined, undefined, undefined, false, true, true) ?? '', mimeType, encInfo, mx, !('cordova' in window)),
() => getFileSrcUrl(mxcUrlToHttp(mx, url) ?? '', mimeType, encInfo, mx, !('cordova' in window)),
[mx, url, mimeType, encInfo]
)
);

View file

@ -9,7 +9,7 @@ import {
import classNames from 'classnames';
import * as css from './style.css';
import { RoomAvatar } from '../room-avatar';
import { getMxIdLocalPart } from '../../utils/matrix';
import { getMxIdLocalPart, mxcUrlToHttp } from '../../utils/matrix';
import { nameInitials } from '../../utils/common';
import { millify } from '../../plugins/millify';
import { useMatrixClient } from '../../hooks/useMatrixClient';
@ -144,7 +144,7 @@ export const RoomCard = as<'div', RoomCardProps>(
const avatar = joinedRoom
? getRoomAvatarUrl(mx, joinedRoom, 96)
: avatarUrl && mx.mxcUrlToHttp(avatarUrl, 96, 96, 'crop');
: avatarUrl && mxcUrlToHttp(mx, avatarUrl, 96, 96, 'crop');
const roomName = joinedRoom?.name || name || fallbackName;
const roomTopic =

View file

@ -6,7 +6,7 @@ import { openInviteUser } from '../../../client/action/navigation';
import { IRoomCreateContent, Membership, StateEvent } from '../../../types/matrix/room';
import { getMemberDisplayName, getStateEvent } from '../../utils/room';
import { useMatrixClient } from '../../hooks/useMatrixClient';
import { getMxIdLocalPart } from '../../utils/matrix';
import { getMxIdLocalPart, mxcUrlToHttp } from '../../utils/matrix';
import { AsyncStatus, useAsyncCallback } from '../../hooks/useAsyncCallback';
import { timeDayMonthYear, timeHourMinute } from '../../utils/time';
import { useRoomNavigate } from '../../hooks/useRoomNavigate';
@ -32,7 +32,7 @@ export const RoomIntro = as<'div', RoomIntroProps>(({ room, ...props }, ref) =>
const avatarMxc = useRoomAvatar(room, mDirects.has(room.roomId));
const name = useRoomName(room);
const topic = useRoomTopic(room);
const avatarHttpUrl = avatarMxc ? mx.mxcUrlToHttp(avatarMxc) : undefined;
const avatarHttpUrl = avatarMxc ? mxcUrlToHttp(mx, avatarMxc) : undefined;
const createContent = createEvent?.getContent<IRoomCreateContent>();
const ts = createEvent?.getTs();

View file

@ -11,6 +11,7 @@ import {
import * as css from './UrlPreviewCard.css';
import Icon from '@mdi/react';
import { mdiArrowLeft, mdiArrowRight } from '@mdi/js';
import { mxcUrlToHttp } from '../../utils/matrix';
const linkStyles = { color: color.Success.Main };
@ -28,7 +29,7 @@ export const UrlPreviewCard = as<'div', { url: string; ts: number }>(
if (previewStatus.status === AsyncStatus.Error) return null;
const renderContent = (prev: IPreviewUrlResponse) => {
const imgUrl = mx.mxcUrlToHttp(prev['og:image'] || '', 256, 256, 'scale', false);
const imgUrl = mxcUrlToHttp(mx, prev['og:image'] || '', 256, 256, 'scale');
return (
<>

View file

@ -1,13 +0,0 @@
import { style } from '@vanilla-extract/css';
import { config } from 'folds';
export const Header = style({
borderBottomColor: 'transparent',
});
export const HeaderTopic = style({
':hover': {
cursor: 'pointer',
opacity: config.opacity.P500,
textDecoration: 'underline',
},
});

View file

@ -2,31 +2,23 @@ import React, { MouseEventHandler, forwardRef, useState } from 'react';
import {
Avatar,
Box,
RectCords,
Text,
config,
toRem,
} from 'folds';
import FocusTrap from 'focus-trap-react';
import { PageHeader } from '../../components/page';
import { useSetSetting } from '../../state/hooks/settings';
import { settingsAtom } from '../../state/settings';
import { useRoomAvatar, useRoomName } from '../../hooks/useRoomMeta';
import { useSpace } from '../../hooks/useSpace';
import { useMatrixClient } from '../../hooks/useMatrixClient';
import { RoomAvatar } from '../../components/room-avatar';
import { nameInitials } from '../../utils/common';
import * as css from './LobbyHeader.css';
import { openInviteUser, openSpaceSettings } from '../../../client/action/navigation';
import { IPowerLevels, usePowerLevelsAPI } from '../../hooks/usePowerLevels';
import { UseStateProvider } from '../../components/UseStateProvider';
import { LeaveSpacePrompt } from '../../components/leave-space-prompt';
import { getText } from '../../../lang';
import Icon from '@mdi/react';
import { mdiAccount, mdiAccountPlus, mdiArrowLeft, mdiCog, mdiDotsVertical } from '@mdi/js';
import { AppBar, Divider, IconButton, ListItemIcon, ListItemText, Menu, MenuItem, Toolbar, Tooltip } from '@mui/material';
import { ArrowBack, MoreVert, Person, PersonAdd, Settings } from '@mui/icons-material';
import { BackRouteHandler } from '../../components/BackRouteHandler';
import { mxcUrlToHttp } from '../../utils/matrix';
type LobbyMenuProps = {
roomId: string;
@ -115,7 +107,7 @@ export function LobbyHeader({ showProfile, powerLevels }: LobbyHeaderProps) {
const name = useRoomName(space);
const avatarMxc = useRoomAvatar(space);
const avatarUrl = avatarMxc ? mx.mxcUrlToHttp(avatarMxc, 96, 96, 'crop') ?? undefined : undefined;
const avatarUrl = avatarMxc ? mxcUrlToHttp(mx, avatarMxc, 96, 96, 'crop') ?? undefined : undefined;
const handleOpenMenu: MouseEventHandler<HTMLButtonElement> = (evt) => {
setMenuAnchor(evt.currentTarget);

View file

@ -12,6 +12,7 @@ import { PageHero } from '../../components/page';
import { onEnterOrSpace } from '../../utils/keyboard';
import { Dialog } from '@mui/material';
import { BackButtonHandler } from '../../hooks/useBackButton';
import { mxcUrlToHttp } from '../../utils/matrix';
export function LobbyHero() {
const mx = useMatrixClient();
@ -20,7 +21,7 @@ export function LobbyHero() {
const name = useRoomName(space);
const topic = useRoomTopic(space);
const avatarMxc = useRoomAvatar(space);
const avatarUrl = avatarMxc ? mx.mxcUrlToHttp(avatarMxc, 96, 96, 'crop') ?? undefined : undefined;
const avatarUrl = avatarMxc ? mxcUrlToHttp(mx, avatarMxc, 96, 96, 'crop') ?? undefined : undefined;
return (
<PageHero

View file

@ -5,7 +5,6 @@ import {
as,
toRem,
} from 'folds';
import FocusTrap from 'focus-trap-react';
import { JoinRule, MatrixError, Room } from 'matrix-js-sdk';
import { RoomAvatar, RoomIcon } from '../../components/room-avatar';
import { SequenceCard } from '../../components/sequence-card';
@ -27,11 +26,10 @@ import { ErrorCode } from '../../cs-errorcode';
import { getDirectRoomAvatarUrl, getRoomAvatarUrl } from '../../utils/room';
import { ItemDraggableTarget, useDraggableItem } from './DnD';
import { getText } from '../../../lang';
import Icon from '@mdi/react';
import { mdiAlert, mdiArrowRight, mdiPlus } from '@mdi/js';
import { Chip, Dialog, Divider, IconButton, Tooltip, Typography } from '@mui/material';
import { ArrowForward, Warning } from '@mui/icons-material';
import { BackButtonHandler } from '../../hooks/useBackButton';
import { mxcUrlToHttp } from '../../utils/matrix';
type RoomJoinButtonProps = {
roomId: string;
@ -352,7 +350,7 @@ export const RoomItemCard = as<'div', RoomItemCardProps>(
topic={summaryState.data.topic}
avatarUrl={
summaryState.data?.avatar_url
? mx.mxcUrlToHttp(summaryState.data.avatar_url, 96, 96, 'crop') ??
? mxcUrlToHttp(mx, summaryState.data.avatar_url, 96, 96, 'crop') ??
undefined
: undefined
}

View file

@ -4,12 +4,10 @@ import {
Avatar,
as,
toRem,
config,
Chip,
Text,
Badge,
} from 'folds';
import FocusTrap from 'focus-trap-react';
import classNames from 'classnames';
import { MatrixError, Room } from 'matrix-js-sdk';
import { HierarchyItem } from '../../hooks/useSpaceHierarchy';
@ -32,6 +30,7 @@ import { mdiChevronDown, mdiChevronRight, mdiPlus } from '@mdi/js';
import Icon from '@mdi/react';
import { Button, CircularProgress, ListItemText, Menu, MenuItem } from '@mui/material';
import { Add } from '@mui/icons-material';
import { mxcUrlToHttp } from '../../utils/matrix';
function SpaceProfileLoading() {
return (
@ -427,7 +426,7 @@ export const SpaceItemCard = as<'div', SpaceItemCardProps>(
name={summaryState.data.name || summaryState.data.canonical_alias || roomId}
avatarUrl={
summaryState.data?.avatar_url
? mx.mxcUrlToHttp(summaryState.data.avatar_url, 96, 96, 'crop') ??
? mxcUrlToHttp(mx, summaryState.data.avatar_url, 96, 96, 'crop') ??
undefined
: undefined
}

View file

@ -8,7 +8,7 @@ import {
getReactCustomHtmlParser,
makeHighlightRegex,
} from '../../plugins/react-custom-html-parser';
import { getMxIdLocalPart, isRoomId, isUserId } from '../../utils/matrix';
import { getMxIdLocalPart, isRoomId, isUserId, mxcUrlToHttp } from '../../utils/matrix';
import { openJoinAlias, openProfileViewer } from '../../../client/action/navigation';
import { useMatrixEventRenderer } from '../../hooks/useMatrixEventRenderer';
import { GetContentCallback, MessageEvent, StateEvent } from '../../../types/matrix/room';
@ -218,7 +218,7 @@ export function SearchResultGroup({
userId={event.sender}
src={
senderAvatarMxc
? mx.mxcUrlToHttp(senderAvatarMxc, 48, 48, 'crop') ?? undefined
? mxcUrlToHttp(mx, senderAvatarMxc, 48, 48, 'crop') ?? undefined
: undefined
}
alt={displayName}

View file

@ -7,7 +7,7 @@ import { useVirtualizer } from "@tanstack/react-virtual";
import { useRoomNavigate } from "../../hooks/useRoomNavigate";
import { HTMLReactParserOptions } from "html-react-parser";
import { getReactCustomHtmlParser } from "../../plugins/react-custom-html-parser";
import { getMxIdLocalPart, isRoomId, isUserId } from "../../utils/matrix";
import { getMxIdLocalPart, isRoomId, isUserId, mxcUrlToHttp } from "../../utils/matrix";
import { openJoinAlias, openProfileViewer } from "../../../client/action/navigation";
import { useSetting } from "../../state/hooks/settings";
import { settingsAtom } from "../../state/settings";
@ -108,7 +108,7 @@ function PinnedMessage({ room, eventId, renderContent, requestOpen, canUnpin }:
userId={sender}
src={
senderAvatarMxc
? mx.mxcUrlToHttp(senderAvatarMxc, 48, 48, 'crop', false, false, true) ??
? mxcUrlToHttp(mx, senderAvatarMxc, 48, 48, 'crop') ??
undefined
: undefined
}

View file

@ -1,7 +1,7 @@
import React, { CSSProperties, useCallback, useEffect, useRef, useState } from 'react';
import { Avatar, Box, IconButton, Text } from "folds";
import { CallEvent, Room, User } from "matrix-js-sdk";
import { CallEvent, Room } from "matrix-js-sdk";
import * as css from './RoomCall.css';
import { UserAvatar } from '../../components/user-avatar';
@ -9,10 +9,10 @@ import { useMatrixClient } from '../../hooks/useMatrixClient';
import { AvatarBase } from '../../components/message';
import { CallErrorCode, CallState, MatrixCall } from 'matrix-js-sdk/lib/webrtc/call';
import { CallFeed } from 'matrix-js-sdk/lib/webrtc/callFeed';
import { SDPStreamMetadataPurpose } from 'matrix-js-sdk/lib/webrtc/callEventTypes';
import Icon, { Icon as MDIcon } from '@mdi/react';
import { mdiAccount, mdiCamera, mdiCameraOff, mdiMicrophone, mdiMicrophoneOff, mdiPhone, mdiPhoneHangup, mdiVideo, mdiVideoOff } from '@mdi/js';
import { mdiAccount, mdiMicrophone, mdiMicrophoneOff, mdiPhone, mdiPhoneHangup, mdiVideo, mdiVideoOff } from '@mdi/js';
import { translate } from '../../../lang';
import { mxcUrlToHttp } from '../../utils/matrix';
// TODO refactor
const styles: Record<CallState | string, CSSProperties> = {
@ -57,8 +57,6 @@ export function RoomCall({ room, call, onHangup, invitation, video }: RoomCallPr
if (!recipient) return;
const audioRef = useRef<HTMLAudioElement>(null);
const [userStyle, setUserStyle] = useState<CSSProperties>();
const [recipientStyle, setRecipientStyle] = useState<CSSProperties>();
const [recipientShowVideo, setRecipientShowVideo] = useState(false);
@ -198,14 +196,11 @@ export function RoomCall({ room, call, onHangup, invitation, video }: RoomCallPr
<video controls={false} autoPlay className={css.VideoFeed} style={{ display: localShowVideo ? 'block' : 'none' }} ref={localVideoRef} />
{!localShowVideo && (
<AvatarBase className={css.UserAvatar}>
<Avatar
style={userStyle}
>
<Avatar>
<UserAvatar
userId={user.userId}
alt={user.displayName ?? user.userId}
src={typeof user.avatarUrl === 'string' ? mx.mxcUrlToHttp(user.avatarUrl, 96, 96, 'scale', true) ?? undefined : undefined}
renderFallback={() => <Icon size={1} path={mdiAccount} />}
src={typeof user.avatarUrl === 'string' ? mxcUrlToHttp(mx, user.avatarUrl, 96, 96, 'scale') ?? undefined : undefined}
/>
</Avatar>
</AvatarBase>
@ -221,8 +216,7 @@ export function RoomCall({ room, call, onHangup, invitation, video }: RoomCallPr
<UserAvatar
userId={recipient.userId}
alt={recipient.displayName ?? recipient.userId}
src={typeof recipient.avatarUrl === 'string' ? mx.mxcUrlToHttp(recipient.avatarUrl, 96, 96, 'scale', true) ?? undefined : undefined}
renderFallback={() => <Icon size={1} path={mdiAccount} />}
src={typeof recipient.avatarUrl === 'string' ? mxcUrlToHttp(mx, recipient.avatarUrl, 96, 96, 'scale') ?? undefined : undefined}
/>
</Avatar>
</AvatarBase>

View file

@ -1,9 +1,6 @@
import React, {
Dispatch,
KeyboardEventHandler,
MouseEvent,
MouseEventHandler,
PointerEvent,
RefObject,
forwardRef,
useCallback,
@ -21,7 +18,6 @@ import {
Overlay,
OverlayBackdrop,
OverlayCenter,
PopOut,
Scroll,
Text,
config,
@ -41,7 +37,6 @@ import {
RoomMentionAutocomplete,
UserMentionAutocomplete,
EmoticonAutocomplete,
resetEditorHistory,
customHtmlEqualsPlainText,
trimCustomHtml,
isEmptyEditor,
@ -50,8 +45,7 @@ import {
getMentions
} from '../../components/editor';
import { EmojiBoard, EmojiBoardTab } from '../../components/emoji-board';
import { UseStateProvider } from '../../components/UseStateProvider';
import { TUploadContent, encryptFile, getImageInfo, getMxIdLocalPart } from '../../utils/matrix';
import { TUploadContent, encryptFile, getImageInfo, getMxIdLocalPart, mxcUrlToHttp } from '../../utils/matrix';
import { useTypingStatusUpdater } from '../../hooks/useTypingStatusUpdater';
import { useFilePicker } from '../../hooks/useFilePicker';
import { useFilePasteHandler } from '../../hooks/useFilePasteHandler';
@ -100,15 +94,14 @@ import { sanitizeText } from '../../utils/sanitize';
import { CommandAutocomplete } from './CommandAutocomplete';
import { Command, SHRUG, LENNY, TABLEFLIP, UNFLIP, useCommands } from '../../hooks/useCommands';
import { mobileOrTablet } from '../../utils/user-agent';
import { useElementSizeObserver } from '../../hooks/useElementSizeObserver';
import { ReplyLayout } from '../../components/message';
import { markAsRead } from '../../../client/action/notifications';
import { roomToParentsAtom } from '../../state/room/roomToParents';
import { getText } from '../../../lang';
import { openHiddenRooms, openReusableContextMenu } from '../../../client/action/navigation';
import { openReusableContextMenu } from '../../../client/action/navigation';
import { ScreenSize, useScreenSize } from '../../hooks/useScreenSize';
import Icon from '@mdi/react';
import { mdiAt, mdiBell, mdiBellOff, mdiCheckAll, mdiClose, mdiEmoticon, mdiEmoticonOutline, mdiEye, mdiEyeOff, mdiFile, mdiMicrophone, mdiPlusCircle, mdiPlusCircleOutline, mdiSend, mdiSendOutline, mdiSticker, mdiStickerOutline } from '@mdi/js';
import { mdiBell, mdiBellOff, mdiClose, mdiEmoticon, mdiEmoticonOutline, mdiEye, mdiEyeOff, mdiFile, mdiMicrophone, mdiPlusCircleOutline, mdiSendOutline, mdiSticker, mdiStickerOutline } from '@mdi/js';
import { usePowerLevelsAPI, usePowerLevelsContext } from '../../hooks/usePowerLevels';
import { useVoiceRecorder } from '../../hooks/useVoiceRecorder';
import { getEventCords } from '../../../util/common';
@ -525,7 +518,7 @@ export const RoomInput = forwardRef<HTMLDivElement, RoomInputProps>(
}, [textAreaRef]);
const handleStickerSelect = async (mxc: string, shortcode: string, label: string) => {
const stickerUrl = mx.mxcUrlToHttp(mxc);
const stickerUrl = mxcUrlToHttp(mx, mxc);
if (!stickerUrl) return;
const info = await getImageInfo(

View file

@ -29,6 +29,7 @@ import { v4 } from 'uuid';
import { generateConferenceID } from '../../../util/conferenceID';
import { getIntegrationManagerURL } from '../../hooks/useIntegrationManager';
import wallpaperDB from '../../utils/wallpaper';
import { mxcUrlToHttp } from '../../utils/matrix';
export function RoomView({ room, eventId }: { room: Room; eventId?: string; }) {
const roomInputRef = useRef(null);
@ -79,7 +80,7 @@ export function RoomView({ room, eventId }: { room: Room; eventId?: string; }) {
matrix_user_id: myUserId,
matrix_room_id: room.roomId,
matrix_display_name: profile?.displayName ?? myUserId,
matrix_avatar_url: profile?.avatarUrl && mx.mxcUrlToHttp(profile?.avatarUrl),
matrix_avatar_url: profile?.avatarUrl && mxcUrlToHttp(mx, profile?.avatarUrl, undefined, undefined, undefined, true),
...content.data
};
var url = `${content.url}`; // Should not be a reference

View file

@ -28,7 +28,7 @@ import {
withOriginBaseUrl,
withSearchParam,
} from '../../pages/pathUtils';
import { getCanonicalAliasOrRoomId, isRoomId, isUserId } from '../../utils/matrix';
import { getCanonicalAliasOrRoomId, isRoomId, isUserId, mxcUrlToHttp } from '../../utils/matrix';
import { _SearchPathSearchParams } from '../../pages/paths';
import * as css from './RoomViewHeader.css';
import { useRoomUnread } from '../../state/hooks/unread';
@ -261,7 +261,7 @@ export function RoomViewHeader({
const [showPinned, setShowPinned] = useState(false);
const [showWidgets, setShowWidgets] = useState(false);
const [widgets, setWidgets] = useState<ReactNode[]>([]);
const avatarUrl = avatarMxc ? mx.mxcUrlToHttp(avatarMxc, 96, 96, 'crop') ?? undefined : undefined;
const avatarUrl = avatarMxc ? mxcUrlToHttp(mx, avatarMxc, 96, 96, 'crop') ?? undefined : undefined;
const powerLevels = usePowerLevelsContext();
const { getPowerLevel, canSendStateEvent, canDoAction } = usePowerLevelsAPI(powerLevels);
const myUserId = mx.getUserId();

View file

@ -41,7 +41,7 @@ import {
getMemberAvatarMxc,
getMemberDisplayName,
} from '../../../utils/room';
import { getCanonicalAliasOrRoomId, getMxIdLocalPart, isRoomId, isUserId } from '../../../utils/matrix';
import { getCanonicalAliasOrRoomId, getMxIdLocalPart, isRoomId, isUserId, mxcUrlToHttp } from '../../../utils/matrix';
import { MessageLayout, MessageSpacing, settingsAtom } from '../../../state/settings';
import { useMatrixClient } from '../../../hooks/useMatrixClient';
import { useRecentEmoji } from '../../../hooks/useRecentEmoji';
@ -300,7 +300,7 @@ export const MessageFileDownloadItem = as<
const mxc = url ?? content.file?.url;
const fileInfo = content?.info;
const handleClick = async () => {
const httpUrl = mx.mxcUrlToHttp(mxc, undefined, undefined, undefined, false, true, true);
const httpUrl = mxcUrlToHttp(mx, mxc);
if (!httpUrl) return onClose?.();
const Url = await getFileSrcUrl(
httpUrl,
@ -1265,7 +1265,7 @@ export const Message = as<'div', MessageProps>(
userId={senderId}
src={
senderAvatarMxc
? mx.mxcUrlToHttp(senderAvatarMxc, 48, 48, 'crop') ?? undefined
? mxcUrlToHttp(mx, senderAvatarMxc, 48, 48, 'crop') ?? undefined
: undefined
}
alt={senderDisplayName}

View file

@ -22,6 +22,7 @@ import ImagePackUpload from './ImagePackUpload';
import { getText } from '../../../lang';
import { Button, Checkbox, DialogActions, DialogContent, TextField } from '@mui/material';
import { useForceUpdate } from '../../hooks/useForceUpdate';
import { mxcUrlToHttp } from '../../utils/matrix';
const renameImagePackItem = (shortcode) => new Promise((resolve) => {
let isCompleted = false;
@ -270,7 +271,7 @@ function ImagePack({ roomId, stateKey, handlePackDelete }) {
return (
<div className="image-pack">
<ImagePackProfile
avatarUrl={pack.avatarUrl ? mx.mxcUrlToHttp(pack.avatarUrl, 42, 42, 'crop') : null}
avatarUrl={pack.avatarUrl ? mxcUrlToHttp(mx, pack.avatarUrl, 42, 42, 'crop') : null}
displayName={pack.displayName ?? 'Unknown'}
attribution={pack.attribution}
usage={getUsage(pack.usage)}
@ -291,7 +292,7 @@ function ImagePack({ roomId, stateKey, handlePackDelete }) {
{images.map(([shortcode, image]) => (
<ImagePackItem
key={shortcode}
url={mx.mxcUrlToHttp(image.mxc)}
url={mxcUrlToHttp(mx, image.mxc)}
shortcode={shortcode}
usage={getUsage(image.usage)}
onUsageChange={canChange ? handleUsageItem : undefined}
@ -356,7 +357,7 @@ function ImagePackUser() {
return (
<div className="image-pack">
<ImagePackProfile
avatarUrl={pack.avatarUrl ? mx.mxcUrlToHttp(pack.avatarUrl, 42, 42, 'crop') : null}
avatarUrl={pack.avatarUrl ? mxcUrlToHttp(mx, pack.avatarUrl, 42, 42, 'crop') : null}
displayName={pack.displayName ?? getText('emojiboard.personal_pack')}
attribution={pack.attribution}
usage={getUsage(pack.usage)}
@ -375,7 +376,7 @@ function ImagePackUser() {
{images.map(([shortcode, image]) => (
<ImagePackItem
key={shortcode}
url={mx.mxcUrlToHttp(image.mxc)}
url={mxcUrlToHttp(mx, image.mxc)}
shortcode={shortcode}
usage={getUsage(image.usage)}
onUsageChange={handleUsageItem}

View file

@ -10,7 +10,7 @@ import Text from '../../atoms/text/Text';
import RoomTile from '../../molecules/room-tile/RoomTile';
import { useRoomNavigate } from '../../hooks/useRoomNavigate';
import { getDMRoomFor, getRoomNameOrId } from '../../utils/matrix';
import { getDMRoomFor, getRoomNameOrId, mxcUrlToHttp } from '../../utils/matrix';
import { getText } from '../../../lang';
import { BackButtonHandler, useBackButton } from '../../hooks/useBackButton';
import { mdiAccount, mdiClose } from '@mdi/js';
@ -219,7 +219,7 @@ function InviteUser({ isOpen, roomId, searchTerm, onRequestClose }) {
key={userId}
avatarSrc={
typeof user.avatar_url === 'string'
? mx.mxcUrlToHttp(user.avatar_url, 42, 42, 'crop')
? mxcUrlToHttp(mx, user.avatar_url, 42, 42, 'crop')
: null
}
name={name}

View file

@ -2,6 +2,7 @@ import { useRef, useState } from 'react';
import { useMatrixClient } from '../../hooks/useMatrixClient';
import './Banner.scss';
import initMatrix from '../../../client/initMatrix';
import { mxcUrlToHttp } from '../../utils/matrix';
export default function Banner({ url, noBorder, onUpload, emptyBanner }) {
const mx = useMatrixClient();
const uploadImageRef = useRef(null);
@ -38,7 +39,7 @@ export default function Banner({ url, noBorder, onUpload, emptyBanner }) {
<div onClick={handleClick} className={noBorder ? 'banner-container-nb' : 'banner-container'}>
{
!emptyBanner ?
<img src={mx.mxcUrlToHttp(url)} className='profile-banner' /> :
<img src={mxcUrlToHttp(mx, url)} className='profile-banner' /> :
<div style={{ height: '150px', backgroundColor: emptyBanner }} />
}
<input type='file' accept='image/*' onChange={uploadImage} ref={uploadImageRef} style={{ display: 'none' }} />

View file

@ -18,6 +18,7 @@ import { Box } from 'folds';
import { useMatrixClient } from '../../hooks/useMatrixClient';
import { useAccountData } from '../../hooks/useAccountData';
import { copyToClipboard } from '../../../util/common';
import { mxcUrlToHttp } from '../../utils/matrix';
function ProfileEditor({ userId }) {
const [isEditing, setIsEditing] = useState(false);
@ -26,7 +27,7 @@ function ProfileEditor({ userId }) {
const displayNameRef = useRef(null);
const [avatarSrc, setAvatarSrc] = useState(
user.avatarUrl ? mx.mxcUrlToHttp(user.avatarUrl, 80, 80, 'crop') : null
user.avatarUrl ? mxcUrlToHttp(mx, user.avatarUrl, 80, 80, 'crop') : null
);
const [username, setUsername] = useState(user.displayName);
const [disabled, setDisabled] = useState(true);
@ -35,7 +36,7 @@ function ProfileEditor({ userId }) {
let isMounted = true;
mx.getProfileInfo(mx.getUserId()).then((info) => {
if (!isMounted) return;
setAvatarSrc(info.avatar_url ? mx.mxcUrlToHttp(info.avatar_url, 80, 80, 'crop') : null);
setAvatarSrc(info.avatar_url ? mxcUrlToHttp(mx, info.avatar_url, 80, 80, 'crop') : null);
setUsername(info.displayname);
});
return () => {
@ -58,7 +59,7 @@ function ProfileEditor({ userId }) {
return;
}
mx.setAvatarUrl(url);
setAvatarSrc(mx.mxcUrlToHttp(url, 80, 80, 'crop'));
setAvatarSrc(mxcUrlToHttp(mx, url, 80, 80, 'crop'));
};
const saveDisplayName = () => {
@ -186,7 +187,7 @@ function ProfileEditor({ userId }) {
};
const bannerUrl = useMemo(() => {
return mx.mxcUrlToHttp(bannerSrc, null, null, null, false, true, true);
return mxcUrlToHttp(mx, bannerSrc);
}, [mx, bannerSrc]);
const [snackbarOpen, setSnackbar] = useState(false);

View file

@ -1,4 +1,4 @@
import React, { useState, useEffect, useRef } from 'react';
import React, { useState, useEffect, useRef, useMemo } from 'react';
import PropTypes from 'prop-types';
import './ProfileViewer.scss';
@ -25,7 +25,7 @@ import PowerLevelSelector from '../../molecules/power-level-selector/PowerLevelS
import { useForceUpdate } from '../../hooks/useForceUpdate';
import { confirmDialog } from '../../molecules/confirm-dialog/ConfirmDialog';
import { useRoomNavigate } from '../../hooks/useRoomNavigate';
import { getDMRoomFor, getMxIdLocalPart, getMxIdServer } from '../../utils/matrix';
import { getDMRoomFor, getMxIdLocalPart, getMxIdServer, mxcUrlToHttp } from '../../utils/matrix';
import { EventTimeline } from 'matrix-js-sdk';
import Banner from './Banner';
import { getText, translate } from '../../../lang';
@ -480,7 +480,7 @@ function ProfileViewer() {
const username = roomMember ? getUsernameOfRoomMember(roomMember) : getUsername(userId);
const avatarMxc = roomMember?.getMxcAvatarUrl?.() || mx.getUser(userId)?.avatarUrl;
const avatarUrl =
avatarMxc && avatarMxc !== 'null' ? mx.mxcUrlToHttp(avatarMxc, 80, 80, 'crop') : null;
avatarMxc && avatarMxc !== 'null' ? mxcUrlToHttp(mx, avatarMxc, 80, 80, 'crop') : null;
const powerLevel = roomMember?.powerLevel || 0;
const myPowerLevel = room.getMember(mx.getUserId())?.powerLevel || 0;
@ -489,13 +489,13 @@ function ProfileViewer() {
const membership = roomState.getStateEvents('m.room.member', userId);
const membershipContent = membership?.getContent() ?? {};
var bannerUrl;
console.log(membershipContent);
if (typeof membershipContent[cons.EXTERA_BANNER_URL] === 'string' && membershipContent[cons.EXTERA_BANNER_URL].startsWith('mxc://')) {
bannerUrl = mx.mxcUrlToHttp(membershipContent[cons.EXTERA_BANNER_URL], false, false, false, false, true, true);
}
const bannerUrl = useMemo(() => {
if (typeof membershipContent[cons.EXTERA_BANNER_URL] === 'string' && membershipContent[cons.EXTERA_BANNER_URL].startsWith('mxc://')) {
return mxcUrlToHttp(mx, membershipContent[cons.EXTERA_BANNER_URL]);
} else {
return null;
}
}, [mx, membershipContent]);
const canChangeRole =
room.currentState.maySendEvent('m.room.power_levels', mx.getUserId()) &&

View file

@ -185,7 +185,6 @@ function RoomMembersItem({ room, onClick }) {
}
function RoomSettings() {
const mx = useMatrixClient();
const [selectedTab, setSelectedTab] = useState(0);
const [isEditing, setEditing] = useState(false);
const [window, requestClose] = useWindowToggle(setSelectedTab);

View file

@ -10,6 +10,7 @@ import { Close } from "@mui/icons-material";
import { getText } from "../../../lang";
import { Box } from "folds";
import { useMatrixClient } from "../../hooks/useMatrixClient";
import { mxcUrlToHttp } from "../../utils/matrix";
function Theme({ theme, onToggle, onRemove }) {
return (
@ -52,7 +53,7 @@ export default function Themes() {
const onAdd = (evt) => {
evt.preventDefault();
const { name, url } = evt.target.elements;
const cssUrl = mx.mxcUrlToHttp(url.value, false, false, false, true, true);
const cssUrl = mxcUrlToHttp(mx, url.value);
setThemes([
...themes,
{

View file

@ -22,7 +22,7 @@ import {
isNotificationEvent,
} from '../../utils/room';
import { NotificationType, UnreadInfo } from '../../../types/matrix/room';
import { getMxIdLocalPart } from '../../utils/matrix';
import { getMxIdLocalPart, mxcUrlToHttp } from '../../utils/matrix';
import { useSelectedRoom } from '../../hooks/router/useSelectedRoom';
import { useInboxNotificationsSelected } from '../../hooks/router/useInbox';
import { enablePush } from '../../../push';
@ -197,7 +197,7 @@ function MessageNotifications() {
plugin.local.schedule({
id,
title: roomName,
icon: roomAvatar ? mx.mxcUrlToHttp(roomAvatar, 96, 96, 'scale', true) : undefined,
icon: roomAvatar ? mxcUrlToHttp(mx, roomAvatar, 96, 96, 'scale', true) : undefined,
text,
data: {
roomId
@ -266,7 +266,7 @@ function MessageNotifications() {
notify({
roomName: room.name ?? 'Unknown',
roomAvatar: avatarMxc
? mx.mxcUrlToHttp(avatarMxc, 96, 96, 'crop') ?? undefined
? mxcUrlToHttp(mx, avatarMxc, 96, 96, 'crop') ?? undefined
: undefined,
username: getMemberDisplayName(room, sender) ?? getMxIdLocalPart(sender) ?? sender,
roomId: room.roomId,

View file

@ -23,7 +23,7 @@ import { useVirtualizer } from '@tanstack/react-virtual';
import { HTMLReactParserOptions } from 'html-react-parser';
import { Page, PageContent, PageContentCenter, PageHeader } from '../../../components/page';
import { useMatrixClient } from '../../../hooks/useMatrixClient';
import { getMxIdLocalPart, isRoomId, isUserId } from '../../../utils/matrix';
import { getMxIdLocalPart, isRoomId, isUserId, mxcUrlToHttp } from '../../../utils/matrix';
import { InboxNotificationsPathSearchParams } from '../../paths';
import { AsyncStatus, useAsyncCallback } from '../../../hooks/useAsyncCallback';
import { SequenceCard } from '../../../components/sequence-card';
@ -418,7 +418,7 @@ function RoomNotificationsGroupComp({
userId={event.sender}
src={
senderAvatarMxc
? mx.mxcUrlToHttp(senderAvatarMxc, 48, 48, 'crop') ?? undefined
? mxcUrlToHttp(mx, senderAvatarMxc, 48, 48, 'crop') ?? undefined
: undefined
}
alt={displayName}

View file

@ -1,4 +1,4 @@
import React, { ChangeEventHandler, EventHandler, KeyboardEventHandler, RefObject, SyntheticEvent, useEffect, useMemo, useRef, useState } from 'react';
import React, { KeyboardEventHandler, RefObject, SyntheticEvent, useEffect, useRef, useState } from 'react';
import { PageNav, PageNavContent } from '../../../components/page';
import { AppBar, Box, CircularProgress, IconButton, LinearProgress, Tab, Tabs, Toolbar, useTheme } from '@mui/material';
import { useNavHidden } from '../../../hooks/useHideableNav';
@ -6,15 +6,10 @@ import { MenuOpen, Menu as MenuIcon, Close, Message as MessageIcon } from '@mui/
import SearchBar from '../SearchBar';
import { getText } from '../../../../lang';
import { MatrixEvent, Room } from 'matrix-js-sdk';
import { Scroll } from 'folds';
import { useVirtualizer } from '@tanstack/react-virtual';
import { useMatrixClient } from '../../../hooks/useMatrixClient';
import { VirtualTile } from '../../../components/virtualizer';
import { RoomNavItem } from '../../../features/room-nav';
import { useRoomNavigate } from '../../../hooks/useRoomNavigate';
import { getHomeRoomPath } from '../../pathUtils';
import { getCanonicalAliasOrRoomId, getDMRoomFor, searchRoom } from '../../../utils/matrix';
import { useAtom, useAtomValue } from 'jotai';
import { getDMRoomFor, mxcUrlToHttp, searchRoom } from '../../../utils/matrix';
import { useAtomValue } from 'jotai';
import { muteChangesAtom } from '../../../state/room-list/mutedRoomList';
import { roomToUnreadAtom } from '../../../state/room/roomToUnread';
import RoomSelector from '../../../molecules/room-selector/RoomSelector';
@ -22,9 +17,6 @@ import RoomTile from '../../../molecules/room-tile/RoomTile';
import * as roomActions from '../../../../client/action/room';
import { hasDevices } from '../../../../util/matrixUtil';
import { LoadingButton } from '@mui/lab';
import { MessageSearchParams, useMessageSearch } from '../../../features/message-search/useMessageSearch';
import { useInfiniteQuery } from '@tanstack/react-query';
import { MessageSearch } from '../../../features/message-search';
import { useRooms } from '../../../state/hooks/roomList';
import { mDirectAtom } from '../../../state/mDirectList';
@ -130,7 +122,7 @@ function SearchUsers({ users }: { users: UserProfile[] }) {
key={userId}
avatarSrc={
typeof user.avatar_url === 'string'
? mx.mxcUrlToHttp(user.avatar_url, 42, 42, 'crop')
? mxcUrlToHttp(mx, user.avatar_url, 42, 42, 'crop')
: null
}
name={name}

View file

@ -8,280 +8,280 @@ import { StateEvent } from '../../types/matrix/room';
export type PackEventIdToUnknown = Record<string, unknown>;
export type EmoteRoomIdToPackEvents = Record<string, PackEventIdToUnknown>;
export type EmoteRoomsContent = {
rooms?: EmoteRoomIdToPackEvents;
rooms?: EmoteRoomIdToPackEvents;
};
export enum PackUsage {
Emoticon = 'emoticon',
Sticker = 'sticker',
Emoticon = 'emoticon',
Sticker = 'sticker',
}
export type PackImage = {
url: string;
body?: string;
usage?: PackUsage[];
info?: IImageInfo;
url: string;
body?: string;
usage?: PackUsage[];
info?: IImageInfo;
};
export type PackImages = Record<string, PackImage>;
export type PackMeta = {
display_name?: string;
avatar_url?: string;
attribution?: string;
usage?: PackUsage[];
display_name?: string;
avatar_url?: string;
attribution?: string;
usage?: PackUsage[];
};
export type ExtendedPackImage = PackImage & {
shortcode: string;
shortcode: string;
};
export type PackContent = {
pack?: PackMeta;
images?: PackImages;
pack?: PackMeta;
images?: PackImages;
};
export class ImagePack {
public id: string;
public id: string;
public content: PackContent;
public content: PackContent;
public displayName?: string;
public displayName?: string;
public avatarUrl?: string;
public avatarUrl?: string;
public usage?: PackUsage[];
public usage?: PackUsage[];
public attribution?: string;
public attribution?: string;
public images: Map<string, ExtendedPackImage>;
public images: Map<string, ExtendedPackImage>;
public emoticons: ExtendedPackImage[];
public emoticons: ExtendedPackImage[];
public stickers: ExtendedPackImage[];
public stickers: ExtendedPackImage[];
static parsePack(eventId: string, packContent: PackContent) {
if (!eventId || typeof packContent?.images !== 'object') {
return undefined;
static parsePack(eventId: string, packContent: PackContent) {
if (!eventId || typeof packContent?.images !== 'object') {
return undefined;
}
return new ImagePack(eventId, packContent);
}
return new ImagePack(eventId, packContent);
}
constructor(eventId: string, content: PackContent) {
this.id = eventId;
this.content = JSON.parse(JSON.stringify(content));
constructor(eventId: string, content: PackContent) {
this.id = eventId;
this.content = JSON.parse(JSON.stringify(content));
this.images = new Map();
this.emoticons = [];
this.stickers = [];
this.images = new Map();
this.emoticons = [];
this.stickers = [];
this.applyPackMeta(content);
this.applyImages(content);
}
applyPackMeta(content: PackContent) {
const pack = content.pack ?? {};
this.displayName = pack.display_name;
this.avatarUrl = pack.avatar_url;
this.usage = pack.usage ?? [PackUsage.Emoticon, PackUsage.Sticker];
this.attribution = pack.attribution;
}
applyImages(content: PackContent) {
this.images = new Map();
this.emoticons = [];
this.stickers = [];
if (!content.images) return;
Object.entries(content.images).forEach(([shortcode, data]) => {
const { url } = data;
const body = data.body ?? shortcode;
const usage = data.usage ?? this.usage;
const { info } = data;
if (!url) return;
const image: ExtendedPackImage = {
shortcode,
url,
body,
usage,
info,
};
this.images.set(shortcode, image);
if (usage && usage.includes(PackUsage.Emoticon)) {
this.emoticons.push(image);
}
if (usage && usage.includes(PackUsage.Sticker)) {
this.stickers.push(image);
}
});
}
getImages() {
return this.images;
}
getEmojis() {
return this.emoticons;
}
getStickers() {
return this.stickers;
}
getImagesFor(usage: PackUsage) {
if (usage === PackUsage.Emoticon) return this.getEmojis();
if (usage === PackUsage.Sticker) return this.getStickers();
return this.getEmojis();
}
getContent() {
return this.content;
}
getPackAvatarUrl(usage: PackUsage): string | undefined {
return this.avatarUrl || this.getImagesFor(usage)[0].url;
}
private updatePackProperty<K extends keyof PackMeta>(property: K, value: PackMeta[K]) {
if (this.content.pack === undefined) {
this.content.pack = {};
this.applyPackMeta(content);
this.applyImages(content);
}
this.content.pack[property] = value;
this.applyPackMeta(this.content);
}
setAvatarUrl(avatarUrl?: string) {
this.updatePackProperty('avatar_url', avatarUrl);
}
applyPackMeta(content: PackContent) {
const pack = content.pack ?? {};
setDisplayName(displayName?: string) {
this.updatePackProperty('display_name', displayName);
}
this.displayName = pack.display_name;
this.avatarUrl = pack.avatar_url;
this.usage = pack.usage ?? [PackUsage.Emoticon, PackUsage.Sticker];
this.attribution = pack.attribution;
}
setAttribution(attribution?: string) {
this.updatePackProperty('attribution', attribution);
}
applyImages(content: PackContent) {
this.images = new Map();
this.emoticons = [];
this.stickers = [];
if (!content.images) return;
setUsage(usage?: PackUsage[]) {
this.updatePackProperty('usage', usage);
}
Object.entries(content.images).forEach(([shortcode, data]) => {
const { url } = data;
const body = data.body ?? shortcode;
const usage = data.usage ?? this.usage;
const { info } = data;
addImage(key: string, imgContent: PackImage) {
this.content.images = {
[key]: imgContent,
...this.content.images,
};
this.applyImages(this.content);
}
if (!url) return;
const image: ExtendedPackImage = {
shortcode,
url,
body,
usage,
info,
};
removeImage(key: string) {
if (!this.content.images) return;
if (this.content.images[key] === undefined) return;
delete this.content.images[key];
this.applyImages(this.content);
}
this.images.set(shortcode, image);
if (usage && usage.includes(PackUsage.Emoticon)) {
this.emoticons.push(image);
}
if (usage && usage.includes(PackUsage.Sticker)) {
this.stickers.push(image);
}
});
}
updateImageKey(key: string, newKey: string) {
const { images } = this.content;
if (!images) return;
if (images[key] === undefined) return;
const copyImages: PackImages = {};
Object.keys(images).forEach((imgKey) => {
copyImages[imgKey === key ? newKey : imgKey] = images[imgKey];
});
this.content.images = copyImages;
this.applyImages(this.content);
}
getImages() {
return this.images;
}
private updateImageProperty<K extends keyof PackImage>(
key: string,
property: K,
value: PackImage[K]
) {
if (!this.content.images) return;
if (this.content.images[key] === undefined) return;
this.content.images[key][property] = value;
this.applyImages(this.content);
}
getEmojis() {
return this.emoticons;
}
setImageUrl(key: string, url: string) {
this.updateImageProperty(key, 'url', url);
}
getStickers() {
return this.stickers;
}
setImageBody(key: string, body?: string) {
this.updateImageProperty(key, 'body', body);
}
getImagesFor(usage: PackUsage) {
if (usage === PackUsage.Emoticon) return this.getEmojis();
if (usage === PackUsage.Sticker) return this.getStickers();
return this.getEmojis();
}
setImageInfo(key: string, info?: IImageInfo) {
this.updateImageProperty(key, 'info', info);
}
getContent() {
return this.content;
}
setImageUsage(key: string, usage?: PackUsage[]) {
this.updateImageProperty(key, 'usage', usage);
}
getPackAvatarUrl(usage: PackUsage): string | undefined {
return this.avatarUrl || this.getImagesFor(usage)[0].url;
}
private updatePackProperty<K extends keyof PackMeta>(property: K, value: PackMeta[K]) {
if (this.content.pack === undefined) {
this.content.pack = {};
}
this.content.pack[property] = value;
this.applyPackMeta(this.content);
}
setAvatarUrl(avatarUrl?: string) {
this.updatePackProperty('avatar_url', avatarUrl);
}
setDisplayName(displayName?: string) {
this.updatePackProperty('display_name', displayName);
}
setAttribution(attribution?: string) {
this.updatePackProperty('attribution', attribution);
}
setUsage(usage?: PackUsage[]) {
this.updatePackProperty('usage', usage);
}
addImage(key: string, imgContent: PackImage) {
this.content.images = {
[key]: imgContent,
...this.content.images,
};
this.applyImages(this.content);
}
removeImage(key: string) {
if (!this.content.images) return;
if (this.content.images[key] === undefined) return;
delete this.content.images[key];
this.applyImages(this.content);
}
updateImageKey(key: string, newKey: string) {
const { images } = this.content;
if (!images) return;
if (images[key] === undefined) return;
const copyImages: PackImages = {};
Object.keys(images).forEach((imgKey) => {
copyImages[imgKey === key ? newKey : imgKey] = images[imgKey];
});
this.content.images = copyImages;
this.applyImages(this.content);
}
private updateImageProperty<K extends keyof PackImage>(
key: string,
property: K,
value: PackImage[K]
) {
if (!this.content.images) return;
if (this.content.images[key] === undefined) return;
this.content.images[key][property] = value;
this.applyImages(this.content);
}
setImageUrl(key: string, url: string) {
this.updateImageProperty(key, 'url', url);
}
setImageBody(key: string, body?: string) {
this.updateImageProperty(key, 'body', body);
}
setImageInfo(key: string, info?: IImageInfo) {
this.updateImageProperty(key, 'info', info);
}
setImageUsage(key: string, usage?: PackUsage[]) {
this.updateImageProperty(key, 'usage', usage);
}
}
export function packEventsToImagePacks(packEvents: MatrixEvent[]): ImagePack[] {
return packEvents.reduce<ImagePack[]>((imagePacks, packEvent) => {
const packId = packEvent?.getId();
const content = packEvent?.getContent() as PackContent | undefined;
if (!packId || !content) return imagePacks;
const pack = ImagePack.parsePack(packId, content);
if (pack) {
imagePacks.push(pack);
}
return imagePacks;
}, []);
return packEvents.reduce<ImagePack[]>((imagePacks, packEvent) => {
const packId = packEvent?.getId();
const content = packEvent?.getContent() as PackContent | undefined;
if (!packId || !content) return imagePacks;
const pack = ImagePack.parsePack(packId, content);
if (pack) {
imagePacks.push(pack);
}
return imagePacks;
}, []);
}
export function getRoomImagePacks(room: Room): ImagePack[] {
const dataEvents = getStateEvents(room, StateEvent.PoniesRoomEmotes);
return packEventsToImagePacks(dataEvents);
const dataEvents = getStateEvents(room, StateEvent.PoniesRoomEmotes);
return packEventsToImagePacks(dataEvents);
}
export function getGlobalImagePacks(mx: MatrixClient): ImagePack[] {
const emoteRoomsContent = getAccountData(mx, AccountDataEvent.PoniesEmoteRooms)?.getContent() as
| EmoteRoomsContent
| undefined;
if (typeof emoteRoomsContent !== 'object') return [];
const emoteRoomsContent = getAccountData(mx, AccountDataEvent.PoniesEmoteRooms)?.getContent() as
| EmoteRoomsContent
| undefined;
if (typeof emoteRoomsContent !== 'object') return [];
const { rooms } = emoteRoomsContent;
if (typeof rooms !== 'object') return [];
const { rooms } = emoteRoomsContent;
if (typeof rooms !== 'object') return [];
const roomIds = Object.keys(rooms);
const roomIds = Object.keys(rooms);
const packs = roomIds.flatMap((roomId) => {
if (typeof rooms[roomId] !== 'object') return [];
const room = mx.getRoom(roomId);
if (!room) return [];
const packEventIdToUnknown = rooms[roomId];
const roomPacks = getStateEvents(room, StateEvent.PoniesRoomEmotes);
const globalPacks = roomPacks.filter((mE) => {
const packKey = mE.getStateKey();
if (typeof packKey === 'string') return !!packEventIdToUnknown[packKey];
return false;
const packs = roomIds.flatMap((roomId) => {
if (typeof rooms[roomId] !== 'object') return [];
const room = mx.getRoom(roomId);
if (!room) return [];
const packEventIdToUnknown = rooms[roomId];
const roomPacks = getStateEvents(room, StateEvent.PoniesRoomEmotes);
const globalPacks = roomPacks.filter((mE) => {
const packKey = mE.getStateKey();
if (typeof packKey === 'string') return !!packEventIdToUnknown[packKey];
return false;
});
return packEventsToImagePacks(globalPacks);
});
return packEventsToImagePacks(globalPacks);
});
return packs;
return packs;
}
export function getUserImagePack(mx: MatrixClient): ImagePack | undefined {
const userPackContent = getAccountData(mx, AccountDataEvent.PoniesUserEmotes)?.getContent() as
| PackContent
| undefined;
const userId = mx.getUserId();
if (!userPackContent || !userId) {
return undefined;
}
const userPackContent = getAccountData(mx, AccountDataEvent.PoniesUserEmotes)?.getContent() as
| PackContent
| undefined;
const userId = mx.getUserId();
if (!userPackContent || !userId) {
return undefined;
}
const userImagePack = ImagePack.parsePack(userId, userPackContent);
return userImagePack;
const userImagePack = ImagePack.parsePack(userId, userPackContent);
return userImagePack;
}
/**
@ -290,14 +290,14 @@ export function getUserImagePack(mx: MatrixClient): ImagePack | undefined {
* @returns {ImagePack[]} packs
*/
export function getRelevantPacks(mx?: MatrixClient, rooms?: Room[]): ImagePack[] {
const userPack = mx && getUserImagePack(mx);
const userPacks = userPack ? [userPack] : [];
const globalPacks = mx ? getGlobalImagePacks(mx) : [];
const globalPackIds = new Set(globalPacks.map((pack) => pack.id));
const roomsPack = rooms?.flatMap(getRoomImagePacks) ?? [];
const userPack = mx && getUserImagePack(mx);
const userPacks = userPack ? [userPack] : [];
const globalPacks = mx ? getGlobalImagePacks(mx) : [];
const globalPackIds = new Set(globalPacks.map((pack) => pack.id));
const roomsPack = rooms?.flatMap(getRoomImagePacks) ?? [];
return userPacks.concat(
globalPacks,
roomsPack.filter((pack) => !globalPackIds.has(pack.id))
);
return userPacks.concat(
globalPacks,
roomsPack.filter((pack) => !globalPackIds.has(pack.id))
);
}

View file

@ -14,7 +14,7 @@ import { Opts as LinkifyOpts } from 'linkifyjs';
import Linkify from 'linkify-react';
import { ErrorBoundary } from 'react-error-boundary';
import * as css from '../styles/CustomHtml.css';
import { getMxIdLocalPart, getCanonicalAliasRoomId } from '../utils/matrix';
import { getMxIdLocalPart, getCanonicalAliasRoomId, mxcUrlToHttp } from '../utils/matrix';
import { getMemberDisplayName } from '../utils/room';
import { EMOJI_PATTERN, URL_NEG_LB } from '../utils/regex';
import { getHexcodeForEmoji, getShortcodeFor } from './emoji';
@ -289,7 +289,7 @@ export const getReactCustomHtmlParser = (
}
if (name === 'img') {
const htmlSrc = mx.mxcUrlToHttp(props.src);
const htmlSrc = mxcUrlToHttp(mx, props.src);
if (htmlSrc && props.src.startsWith('mxc://') === false) {
return (
<a href={htmlSrc} target="_blank" rel="noreferrer noopener">

View file

@ -285,3 +285,7 @@ export const removeRoomIdFromMDirect = async (mx: MatrixClient, roomId: string):
await mx.setAccountData(AccountDataEvent.Direct, userIdToRoomIds);
};
export const mxcUrlToHttp = (mx: MatrixClient, mxcUrl: string, width?: number, height?: number, resizeMethod?: 'crop' | 'scale', doNotAuthenticate?: boolean) => {
return mx.mxcUrlToHttp(mxcUrl, width, height, resizeMethod, false, true, !doNotAuthenticate);
};