Add authenticated media support (#1930)

* chore: Bump matrix-js-sdk to 34.4.0

* feat: Authenticated media support

* chore: Use Vite PWA for service worker support

* fix: Fix Vite PWA SW entry point

Forget this. :P

* fix: Also add Nginx rewrite for sw.js

* fix: Correct Nginx rewrite

* fix: Add Netlify redirect for sw.js

Otherwise the generic SPA rewrite to index.html would take effect, breaking Service Worker.

* fix: Account for subpath when regisering service worker

* chore: Correct types
This commit is contained in:
夜坂雅 2024-09-07 21:45:55 +08:00 committed by GitHub
parent 043012e809
commit c6a8fb1117
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
46 changed files with 3562 additions and 487 deletions

View file

@ -33,6 +33,8 @@ import { LeaveSpacePrompt } from '../../components/leave-space-prompt';
import { stopPropagation } from '../../utils/keyboard';
import { ScreenSize, useScreenSizeContext } from '../../hooks/useScreenSize';
import { BackRouteHandler } from '../../components/BackRouteHandler';
import { mxcUrlToHttp } from '../../utils/matrix';
import { useSpecVersions } from '../../hooks/useSpecVersions';
type LobbyMenuProps = {
roomId: string;
@ -122,6 +124,8 @@ type LobbyHeaderProps = {
};
export function LobbyHeader({ showProfile, powerLevels }: LobbyHeaderProps) {
const mx = useMatrixClient();
const { versions } = useSpecVersions();
const useAuthentication = versions.includes('v1.11');
const space = useSpace();
const setPeopleDrawer = useSetSetting(settingsAtom, 'isPeopleDrawer');
const [menuAnchor, setMenuAnchor] = useState<RectCords>();
@ -129,7 +133,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, useAuthentication, 96, 96, 'crop') ?? undefined : undefined;
const handleOpenMenu: MouseEventHandler<HTMLButtonElement> = (evt) => {
setMenuAnchor(evt.currentTarget.getBoundingClientRect());

View file

@ -11,15 +11,19 @@ import { RoomTopicViewer } from '../../components/room-topic-viewer';
import * as css from './LobbyHero.css';
import { PageHero } from '../../components/page';
import { onEnterOrSpace, stopPropagation } from '../../utils/keyboard';
import { mxcUrlToHttp } from '../../utils/matrix';
import { useSpecVersions } from '../../hooks/useSpecVersions';
export function LobbyHero() {
const mx = useMatrixClient();
const { versions } = useSpecVersions();
const useAuthentication = versions.includes('v1.11');
const space = useSpace();
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, useAuthentication, 96, 96, 'crop') ?? undefined : undefined;
return (
<PageHero

View file

@ -39,6 +39,8 @@ import { AsyncStatus, useAsyncCallback } from '../../hooks/useAsyncCallback';
import { ErrorCode } from '../../cs-errorcode';
import { getDirectRoomAvatarUrl, getRoomAvatarUrl } from '../../utils/room';
import { ItemDraggableTarget, useDraggableItem } from './DnD';
import { mxcUrlToHttp } from '../../utils/matrix';
import { useSpecVersions } from '../../hooks/useSpecVersions';
type RoomJoinButtonProps = {
roomId: string;
@ -334,6 +336,8 @@ export const RoomItemCard = as<'div', RoomItemCardProps>(
ref
) => {
const mx = useMatrixClient();
const { versions } = useSpecVersions();
const useAuthentication = versions.includes('v1.11');
const { roomId, content } = item;
const room = getRoom(roomId);
const targetRef = useRef<HTMLDivElement>(null);
@ -364,7 +368,7 @@ export const RoomItemCard = as<'div', RoomItemCardProps>(
name={localSummary.name}
topic={localSummary.topic}
avatarUrl={
dm ? getDirectRoomAvatarUrl(mx, room, 96) : getRoomAvatarUrl(mx, room, 96)
dm ? getDirectRoomAvatarUrl(mx, room, 96, useAuthentication) : getRoomAvatarUrl(mx, room, 96, useAuthentication)
}
memberCount={localSummary.memberCount}
suggested={content.suggested}
@ -418,8 +422,8 @@ export const RoomItemCard = as<'div', RoomItemCardProps>(
topic={summaryState.data.topic}
avatarUrl={
summaryState.data?.avatar_url
? mx.mxcUrlToHttp(summaryState.data.avatar_url, 96, 96, 'crop') ??
undefined
? mxcUrlToHttp(mx, summaryState.data.avatar_url, useAuthentication, 96, 96, 'crop') ??
undefined
: undefined
}
memberCount={summaryState.data.num_joined_members}

View file

@ -35,6 +35,8 @@ import { ErrorCode } from '../../cs-errorcode';
import { useDraggableItem } from './DnD';
import { openCreateRoom, openSpaceAddExisting } from '../../../client/action/navigation';
import { stopPropagation } from '../../utils/keyboard';
import { mxcUrlToHttp } from '../../utils/matrix';
import { useSpecVersions } from '../../hooks/useSpecVersions';
function SpaceProfileLoading() {
return (
@ -408,6 +410,8 @@ export const SpaceItemCard = as<'div', SpaceItemCardProps>(
ref
) => {
const mx = useMatrixClient();
const { versions } = useSpecVersions();
const useAuthentication = versions.includes('v1.11');
const { roomId, content } = item;
const space = getRoom(roomId);
const targetRef = useRef<HTMLDivElement>(null);
@ -432,7 +436,7 @@ export const SpaceItemCard = as<'div', SpaceItemCardProps>(
<SpaceProfile
roomId={roomId}
name={localSummary.name}
avatarUrl={getRoomAvatarUrl(mx, space, 96)}
avatarUrl={getRoomAvatarUrl(mx, space, 96, useAuthentication)}
suggested={content.suggested}
closed={closed}
categoryId={categoryId}
@ -469,8 +473,8 @@ 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') ??
undefined
? mxcUrlToHttp(mx, summaryState.data.avatar_url, useAuthentication, 96, 96, 'crop') ??
undefined
: undefined
}
suggested={content.suggested}

View file

@ -13,7 +13,7 @@ import {
makeMentionCustomProps,
renderMatrixMention,
} from '../../plugins/react-custom-html-parser';
import { getMxIdLocalPart } from '../../utils/matrix';
import { getMxIdLocalPart, mxcUrlToHttp } from '../../utils/matrix';
import { useMatrixEventRenderer } from '../../hooks/useMatrixEventRenderer';
import { GetContentCallback, MessageEvent, StateEvent } from '../../../types/matrix/room';
import {
@ -38,6 +38,7 @@ import { SequenceCard } from '../../components/sequence-card';
import { UserAvatar } from '../../components/user-avatar';
import { useMentionClickHandler } from '../../hooks/useMentionClickHandler';
import { useSpoilerClickHandler } from '../../hooks/useSpoilerClickHandler';
import { useSpecVersions } from '../../hooks/useSpecVersions';
type SearchResultGroupProps = {
room: Room;
@ -56,6 +57,8 @@ export function SearchResultGroup({
onOpen,
}: SearchResultGroupProps) {
const mx = useMatrixClient();
const { versions } = useSpecVersions();
const useAuthentication = versions.includes('v1.11');
const highlightRegex = useMemo(() => makeHighlightRegex(highlights), [highlights]);
const mentionClickHandler = useMentionClickHandler(room.roomId);
@ -75,10 +78,11 @@ export function SearchResultGroup({
getReactCustomHtmlParser(mx, room.roomId, {
linkifyOpts,
highlightRegex,
useAuthentication,
handleSpoilerClick: spoilerClickHandler,
handleMentionClick: mentionClickHandler,
}),
[mx, room, linkifyOpts, highlightRegex, mentionClickHandler, spoilerClickHandler]
[mx, room, linkifyOpts, highlightRegex, mentionClickHandler, spoilerClickHandler, useAuthentication]
);
const renderMatrixEvent = useMatrixEventRenderer<[IEventWithRoomId, string, GetContentCallback]>(
@ -161,7 +165,7 @@ export function SearchResultGroup({
<Avatar size="200" radii="300">
<RoomAvatar
roomId={room.roomId}
src={getRoomAvatarUrl(mx, room, 96)}
src={getRoomAvatarUrl(mx, room, 96, useAuthentication)}
alt={room.name}
renderFallback={() => (
<RoomIcon size="50" joinRule={room.getJoinRule() ?? JoinRule.Restricted} filled />
@ -209,7 +213,7 @@ export function SearchResultGroup({
userId={event.sender}
src={
senderAvatarMxc
? mx.mxcUrlToHttp(senderAvatarMxc, 48, 48, 'crop') ?? undefined
? mxcUrlToHttp(mx, senderAvatarMxc, useAuthentication, 48, 48, 'crop') ?? undefined
: undefined
}
alt={displayName}

View file

@ -38,6 +38,7 @@ import { stopPropagation } from '../../utils/keyboard';
import { getMatrixToRoom } from '../../plugins/matrix-to';
import { getCanonicalAliasOrRoomId, isRoomAlias } from '../../utils/matrix';
import { getViaServers } from '../../plugins/via-servers';
import { useSpecVersions } from '../../hooks/useSpecVersions';
type RoomNavItemMenuProps = {
room: Room;
@ -175,6 +176,8 @@ export function RoomNavItem({
linkPath,
}: RoomNavItemProps) {
const mx = useMatrixClient();
const { versions } = useSpecVersions();
const useAuthentication = versions.includes('v1.11');
const [hover, setHover] = useState(false);
const { hoverProps } = useHover({ onHoverChange: setHover });
const { focusWithinProps } = useFocusWithin({ onFocusWithinChange: setHover });
@ -217,7 +220,7 @@ export function RoomNavItem({
<RoomAvatar
roomId={room.roomId}
src={
direct ? getDirectRoomAvatarUrl(mx, room, 96) : getRoomAvatarUrl(mx, room, 96)
direct ? getDirectRoomAvatarUrl(mx, room, 96, useAuthentication) : getRoomAvatarUrl(mx, room, 96, useAuthentication)
}
alt={room.name}
renderFallback={() => (

View file

@ -55,6 +55,7 @@ import { ScrollTopContainer } from '../../components/scroll-top-container';
import { UserAvatar } from '../../components/user-avatar';
import { useRoomTypingMember } from '../../hooks/useRoomTypingMembers';
import { stopPropagation } from '../../utils/keyboard';
import { useSpecVersions } from '../../hooks/useSpecVersions';
export const MembershipFilters = {
filterJoined: (m: RoomMember) => m.membership === Membership.Join,
@ -171,6 +172,8 @@ type MembersDrawerProps = {
};
export function MembersDrawer({ room, members }: MembersDrawerProps) {
const mx = useMatrixClient();
const { versions } = useSpecVersions();
const useAuthentication = versions.includes('v1.11');
const scrollRef = useRef<HTMLDivElement>(null);
const searchInputRef = useRef<HTMLInputElement>(null);
const scrollTopAnchorRef = useRef<HTMLDivElement>(null);
@ -426,9 +429,8 @@ export function MembersDrawer({ room, members }: MembersDrawerProps) {
}}
after={<Icon size="50" src={Icons.Cross} />}
>
<Text size="B300">{`${result.items.length || 'No'} ${
result.items.length === 1 ? 'Result' : 'Results'
}`}</Text>
<Text size="B300">{`${result.items.length || 'No'} ${result.items.length === 1 ? 'Result' : 'Results'
}`}</Text>
</Chip>
)
}
@ -483,14 +485,16 @@ export function MembersDrawer({ room, members }: MembersDrawerProps) {
const member = tagOrMember;
const name = getName(member);
const avatarUrl = member.getAvatarUrl(
mx.baseUrl,
const avatarMxcUrl = member.getMxcAvatarUrl();
const avatarUrl = avatarMxcUrl ? mx.mxcUrlToHttp(
avatarMxcUrl,
100,
100,
'crop',
undefined,
false
);
false,
useAuthentication
) : undefined;
return (
<MenuItem

View file

@ -56,7 +56,7 @@ import {
} 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';
@ -108,6 +108,7 @@ import { mobileOrTablet } from '../../utils/user-agent';
import { useElementSizeObserver } from '../../hooks/useElementSizeObserver';
import { ReplyLayout, ThreadIndicator } from '../../components/message';
import { roomToParentsAtom } from '../../state/room/roomToParents';
import { useSpecVersions } from '../../hooks/useSpecVersions';
interface RoomInputProps {
editor: Editor;
@ -118,6 +119,8 @@ interface RoomInputProps {
export const RoomInput = forwardRef<HTMLDivElement, RoomInputProps>(
({ editor, fileDropContainerRef, roomId, room }, ref) => {
const mx = useMatrixClient();
const { versions } = useSpecVersions();
const useAuthentication = versions.includes('v1.11');
const [enterForNewline] = useSetting(settingsAtom, 'enterForNewline');
const [isMarkdown] = useSetting(settingsAtom, 'isMarkdown');
const commands = useCommands(mx, room);
@ -366,7 +369,7 @@ export const RoomInput = forwardRef<HTMLDivElement, RoomInputProps>(
};
const handleStickerSelect = async (mxc: string, shortcode: string, label: string) => {
const stickerUrl = mx.mxcUrlToHttp(mxc);
const stickerUrl = mxcUrlToHttp(mx, mxc, useAuthentication);
if (!stickerUrl) return;
const info = await getImageInfo(

View file

@ -122,6 +122,7 @@ import { roomToUnreadAtom } from '../../state/room/roomToUnread';
import { useMentionClickHandler } from '../../hooks/useMentionClickHandler';
import { useSpoilerClickHandler } from '../../hooks/useSpoilerClickHandler';
import { useRoomNavigate } from '../../hooks/useRoomNavigate';
import { useSpecVersions } from '../../hooks/useSpecVersions';
const TimelineFloat = as<'div', css.TimelineFloatVariants>(
({ position, className, ...props }, ref) => (
@ -310,9 +311,9 @@ const useTimelinePagination = (
range:
offsetRange > 0
? {
start: currentTimeline.range.start + offsetRange,
end: currentTimeline.range.end + offsetRange,
}
start: currentTimeline.range.start + offsetRange,
end: currentTimeline.range.end + offsetRange,
}
: { ...currentTimeline.range },
}));
};
@ -331,7 +332,7 @@ const useTimelinePagination = (
if (
!paginationToken &&
getTimelinesEventsCount(lTimelines) !==
getTimelinesEventsCount(getLinkedTimelines(timelineToPaginate))
getTimelinesEventsCount(getLinkedTimelines(timelineToPaginate))
) {
recalibratePagination(lTimelines, timelinesEventsCount, backwards);
return;
@ -437,6 +438,8 @@ const getRoomUnreadInfo = (room: Room, scrollTo = false) => {
export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimelineProps) {
const mx = useMatrixClient();
const { versions } = useSpecVersions();
const useAuthentication = versions.includes('v1.11');
const encryptedRoom = mx.isRoomEncrypted(room.roomId);
const [messageLayout] = useSetting(settingsAtom, 'messageLayout');
const [messageSpacing] = useSetting(settingsAtom, 'messageSpacing');
@ -490,10 +493,10 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli
const [focusItem, setFocusItem] = useState<
| {
index: number;
scrollTo: boolean;
highlight: boolean;
}
index: number;
scrollTo: boolean;
highlight: boolean;
}
| undefined
>();
const alive = useAlive();
@ -511,10 +514,11 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli
() =>
getReactCustomHtmlParser(mx, room.roomId, {
linkifyOpts,
useAuthentication,
handleSpoilerClick: spoilerClickHandler,
handleMentionClick: mentionClickHandler,
}),
[mx, room, linkifyOpts, spoilerClickHandler, mentionClickHandler]
[mx, room, linkifyOpts, spoilerClickHandler, mentionClickHandler, useAuthentication]
);
const parseMemberEvent = useMemberEventParser();
@ -1466,14 +1470,14 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli
const eventJSX = reactionOrEditEvent(mEvent)
? null
: renderMatrixEvent(
mEvent.getType(),
typeof mEvent.getStateKey() === 'string',
mEventId,
mEvent,
item,
timelineSet,
collapsed
);
mEvent.getType(),
typeof mEvent.getStateKey() === 'string',
mEventId,
mEvent,
item,
timelineSet,
collapsed
);
prevEvent = mEvent;
isPrevRendered = !!eventJSX;
@ -1555,9 +1559,8 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli
{!canPaginateBack && rangeAtStart && getItems().length > 0 && (
<div
style={{
padding: `${config.space.S700} ${config.space.S400} ${config.space.S600} ${
messageLayout === 1 ? config.space.S400 : toRem(64)
}`,
padding: `${config.space.S700} ${config.space.S400} ${config.space.S600} ${messageLayout === 1 ? config.space.S400 : toRem(64)
}`,
}}
>
<RoomIntro room={room} />

View file

@ -36,7 +36,7 @@ import { useSetSetting } from '../../state/hooks/settings';
import { settingsAtom } from '../../state/settings';
import { useSpaceOptionally } from '../../hooks/useSpace';
import { getHomeSearchPath, getSpaceSearchPath, withSearchParam } from '../../pages/pathUtils';
import { getCanonicalAliasOrRoomId, isRoomAlias } from '../../utils/matrix';
import { getCanonicalAliasOrRoomId, isRoomAlias, mxcUrlToHttp } from '../../utils/matrix';
import { _SearchPathSearchParams } from '../../pages/paths';
import * as css from './RoomViewHeader.css';
import { useRoomUnread } from '../../state/hooks/unread';
@ -53,6 +53,7 @@ import { stopPropagation } from '../../utils/keyboard';
import { getMatrixToRoom } from '../../plugins/matrix-to';
import { getViaServers } from '../../plugins/via-servers';
import { BackRouteHandler } from '../../components/BackRouteHandler';
import { useSpecVersions } from '../../hooks/useSpecVersions';
type RoomMenuProps = {
room: Room;
@ -174,6 +175,8 @@ const RoomMenu = forwardRef<HTMLDivElement, RoomMenuProps>(({ room, requestClose
export function RoomViewHeader() {
const navigate = useNavigate();
const mx = useMatrixClient();
const { versions } = useSpecVersions();
const useAuthentication = versions.includes('v1.11');
const screenSize = useScreenSizeContext();
const room = useRoom();
const space = useSpaceOptionally();
@ -185,7 +188,7 @@ export function RoomViewHeader() {
const avatarMxc = useRoomAvatar(room, mDirects.has(room.roomId));
const name = useRoomName(room);
const topic = useRoomTopic(room);
const avatarUrl = avatarMxc ? mx.mxcUrlToHttp(avatarMxc, 96, 96, 'crop') ?? undefined : undefined;
const avatarUrl = avatarMxc ? mxcUrlToHttp(mx, avatarMxc, useAuthentication, 96, 96, 'crop') ?? undefined : undefined;
const setPeopleDrawer = useSetSetting(settingsAtom, 'isPeopleDrawer');

View file

@ -51,7 +51,7 @@ import {
getMemberAvatarMxc,
getMemberDisplayName,
} from '../../../utils/room';
import { getCanonicalAliasOrRoomId, getMxIdLocalPart, isRoomAlias } from '../../../utils/matrix';
import { getCanonicalAliasOrRoomId, getMxIdLocalPart, isRoomAlias, mxcUrlToHttp } from '../../../utils/matrix';
import { MessageLayout, MessageSpacing } from '../../../state/settings';
import { useMatrixClient } from '../../../hooks/useMatrixClient';
import { useRecentEmoji } from '../../../hooks/useRecentEmoji';
@ -67,6 +67,7 @@ import { copyToClipboard } from '../../../utils/dom';
import { stopPropagation } from '../../../utils/keyboard';
import { getMatrixToRoomEvent } from '../../../plugins/matrix-to';
import { getViaServers } from '../../../plugins/via-servers';
import { useSpecVersions } from '../../../hooks/useSpecVersions';
export type ReactionHandler = (keyOrMxc: string, shortcode: string) => void;
@ -234,9 +235,9 @@ export const MessageSourceCodeItem = as<
const getContent = (evt: MatrixEvent) =>
evt.isEncrypted()
? {
[`<== DECRYPTED_EVENT ==>`]: evt.getEffectiveEvent(),
[`<== ORIGINAL_EVENT ==>`]: evt.event,
}
[`<== DECRYPTED_EVENT ==>`]: evt.getEffectiveEvent(),
[`<== ORIGINAL_EVENT ==>`]: evt.event,
}
: evt.event;
const getText = (): string => {
@ -650,6 +651,8 @@ export const Message = as<'div', MessageProps>(
ref
) => {
const mx = useMatrixClient();
const { versions } = useSpecVersions();
const useAuthentication = versions.includes('v1.11');
const senderId = mEvent.getSender() ?? '';
const [hover, setHover] = useState(false);
const { hoverProps } = useHover({ onHoverChange: setHover });
@ -709,7 +712,7 @@ export const Message = as<'div', MessageProps>(
userId={senderId}
src={
senderAvatarMxc
? mx.mxcUrlToHttp(senderAvatarMxc, 48, 48, 'crop') ?? undefined
? mxcUrlToHttp(mx, senderAvatarMxc, useAuthentication, 48, 48, 'crop') ?? undefined
: undefined
}
alt={senderDisplayName}
@ -950,26 +953,26 @@ export const Message = as<'div', MessageProps>(
</Box>
{((!mEvent.isRedacted() && canDelete) ||
mEvent.getSender() !== mx.getUserId()) && (
<>
<Line size="300" />
<Box direction="Column" gap="100" className={css.MessageMenuGroup}>
{!mEvent.isRedacted() && canDelete && (
<MessageDeleteItem
room={room}
mEvent={mEvent}
onClose={closeMenu}
/>
)}
{mEvent.getSender() !== mx.getUserId() && (
<MessageReportItem
room={room}
mEvent={mEvent}
onClose={closeMenu}
/>
)}
</Box>
</>
)}
<>
<Line size="300" />
<Box direction="Column" gap="100" className={css.MessageMenuGroup}>
{!mEvent.isRedacted() && canDelete && (
<MessageDeleteItem
room={room}
mEvent={mEvent}
onClose={closeMenu}
/>
)}
{mEvent.getSender() !== mx.getUserId() && (
<MessageReportItem
room={room}
mEvent={mEvent}
onClose={closeMenu}
/>
)}
</Box>
</>
)}
</Menu>
</FocusTrap>
}
@ -1093,26 +1096,26 @@ export const Event = as<'div', EventProps>(
</Box>
{((!mEvent.isRedacted() && canDelete && !stateEvent) ||
(mEvent.getSender() !== mx.getUserId() && !stateEvent)) && (
<>
<Line size="300" />
<Box direction="Column" gap="100" className={css.MessageMenuGroup}>
{!mEvent.isRedacted() && canDelete && (
<MessageDeleteItem
room={room}
mEvent={mEvent}
onClose={closeMenu}
/>
)}
{mEvent.getSender() !== mx.getUserId() && (
<MessageReportItem
room={room}
mEvent={mEvent}
onClose={closeMenu}
/>
)}
</Box>
</>
)}
<>
<Line size="300" />
<Box direction="Column" gap="100" className={css.MessageMenuGroup}>
{!mEvent.isRedacted() && canDelete && (
<MessageDeleteItem
room={room}
mEvent={mEvent}
onClose={closeMenu}
/>
)}
{mEvent.getSender() !== mx.getUserId() && (
<MessageReportItem
room={room}
mEvent={mEvent}
onClose={closeMenu}
/>
)}
</Box>
</>
)}
</Menu>
</FocusTrap>
}

View file

@ -22,6 +22,7 @@ import { useRelations } from '../../../hooks/useRelations';
import * as css from './styles.css';
import { ReactionViewer } from '../reaction-viewer';
import { stopPropagation } from '../../../utils/keyboard';
import { useSpecVersions } from '../../../hooks/useSpecVersions';
export type ReactionsProps = {
room: Room;
@ -33,6 +34,8 @@ export type ReactionsProps = {
export const Reactions = as<'div', ReactionsProps>(
({ className, room, relations, mEventId, canSendReaction, onReactionToggle, ...props }, ref) => {
const mx = useMatrixClient();
const { versions } = useSpecVersions();
const useAuthentication = versions.includes('v1.11');
const [viewer, setViewer] = useState<boolean | string>(false);
const myUserId = mx.getUserId();
const reactions = useRelations(
@ -86,6 +89,7 @@ export const Reactions = as<'div', ReactionsProps>(
onClick={canSendReaction ? () => onReactionToggle(mEventId, key) : undefined}
onContextMenu={handleViewReaction}
aria-disabled={!canSendReaction}
useAuthentication={useAuthentication}
/>
)}
</TooltipProvider>

View file

@ -25,6 +25,7 @@ import { useRelations } from '../../../hooks/useRelations';
import { Reaction } from '../../../components/message';
import { getHexcodeForEmoji, getShortcodeFor } from '../../../plugins/emoji';
import { UserAvatar } from '../../../components/user-avatar';
import { useSpecVersions } from '../../../hooks/useSpecVersions';
export type ReactionViewerProps = {
room: Room;
@ -35,6 +36,8 @@ export type ReactionViewerProps = {
export const ReactionViewer = as<'div', ReactionViewerProps>(
({ className, room, initialKey, relations, requestClose, ...props }, ref) => {
const mx = useMatrixClient();
const { versions } = useSpecVersions();
const useAuthentication = versions.includes('v1.11');
const reactions = useRelations(
relations,
useCallback((rel) => [...(rel.getSortedAnnotationsByKey() ?? [])], [])
@ -81,6 +84,7 @@ export const ReactionViewer = as<'div', ReactionViewerProps>(
count={evts.size}
aria-selected={key === selectedKey}
onClick={() => setSelectedKey(key)}
useAuthentication={useAuthentication}
/>
);
})}
@ -107,14 +111,16 @@ export const ReactionViewer = as<'div', ReactionViewerProps>(
const member = room.getMember(senderId);
const name = (member ? getName(member) : getMxIdLocalPart(senderId)) ?? senderId;
const avatarUrl = member?.getAvatarUrl(
mx.baseUrl,
const avatarMxcUrl = member?.getMxcAvatarUrl();
const avatarUrl = avatarMxcUrl ? mx.mxcUrlToHttp(
avatarMxcUrl,
100,
100,
'crop',
undefined,
false
);
false,
useAuthentication
) : undefined;
return (
<MenuItem