Merge pull request #144 from matrix-org/thumbnails
Use thumbnails api instead of mxc download
This commit is contained in:
commit
32c6119243
7 changed files with 133 additions and 32 deletions
|
@ -16,13 +16,16 @@ limitations under the License.
|
|||
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { Group, Room, User } from '../matrix-cypher';
|
||||
|
||||
import { getMediaQueryFromMCX } from '../utils/cypher-wrapper';
|
||||
import { Group, Room, User } from '../matrix-cypher';
|
||||
import useHSs from '../utils/getHS';
|
||||
import { getThumbnailURI } from '../utils/cypher-wrapper';
|
||||
import logo from '../imgs/chat-icon.svg';
|
||||
|
||||
import './Avatar.scss';
|
||||
|
||||
const AVATAR_SIZE = 96;
|
||||
|
||||
interface IProps {
|
||||
className?: string;
|
||||
avatarUrl: string;
|
||||
|
@ -56,12 +59,20 @@ interface IPropsUserAvatar {
|
|||
export const UserAvatar: React.FC<IPropsUserAvatar> = ({
|
||||
user,
|
||||
userId,
|
||||
}: IPropsUserAvatar) => (
|
||||
}: IPropsUserAvatar) => {
|
||||
const [hs] = useHSs({ identifier: userId });
|
||||
return (
|
||||
<Avatar
|
||||
avatarUrl={getMediaQueryFromMCX(user.avatar_url)}
|
||||
avatarUrl={getThumbnailURI(
|
||||
hs,
|
||||
AVATAR_SIZE,
|
||||
AVATAR_SIZE,
|
||||
user.avatar_url
|
||||
)}
|
||||
label={user.displayname ? user.displayname : userId}
|
||||
/>
|
||||
);
|
||||
);
|
||||
};
|
||||
|
||||
interface IPropsRoomAvatar {
|
||||
room: Room;
|
||||
|
@ -69,24 +80,42 @@ interface IPropsRoomAvatar {
|
|||
|
||||
export const RoomAvatar: React.FC<IPropsRoomAvatar> = ({
|
||||
room,
|
||||
}: IPropsRoomAvatar) => (
|
||||
}: IPropsRoomAvatar) => {
|
||||
const [hs] = useHSs({ identifier: room.room_id });
|
||||
return (
|
||||
<Avatar
|
||||
avatarUrl={getMediaQueryFromMCX(room.avatar_url)}
|
||||
avatarUrl={getThumbnailURI(
|
||||
hs,
|
||||
AVATAR_SIZE,
|
||||
AVATAR_SIZE,
|
||||
room.avatar_url
|
||||
)}
|
||||
label={room.name || room.room_id}
|
||||
/>
|
||||
);
|
||||
);
|
||||
};
|
||||
|
||||
interface IPropsGroupAvatar {
|
||||
group: Group;
|
||||
groupId: string;
|
||||
}
|
||||
|
||||
export const GroupAvatar: React.FC<IPropsGroupAvatar> = ({
|
||||
group,
|
||||
}: IPropsGroupAvatar) => (
|
||||
groupId,
|
||||
}: IPropsGroupAvatar) => {
|
||||
const [hs] = useHSs({ identifier: groupId });
|
||||
return (
|
||||
<Avatar
|
||||
avatarUrl={getMediaQueryFromMCX(group.avatar_url)}
|
||||
avatarUrl={getThumbnailURI(
|
||||
hs,
|
||||
AVATAR_SIZE,
|
||||
AVATAR_SIZE,
|
||||
group.avatar_url
|
||||
)}
|
||||
label={group.name}
|
||||
/>
|
||||
);
|
||||
);
|
||||
};
|
||||
|
||||
export default Avatar;
|
||||
|
|
|
@ -23,9 +23,10 @@ import './GroupPreview.scss';
|
|||
|
||||
interface IProps {
|
||||
group: Group;
|
||||
groupId: string;
|
||||
}
|
||||
|
||||
const GroupPreview: React.FC<IProps> = ({ group }: IProps) => {
|
||||
const GroupPreview: React.FC<IProps> = ({ group, groupId }: IProps) => {
|
||||
const description = group.long_description
|
||||
? group.long_description
|
||||
: group.short_description
|
||||
|
@ -34,7 +35,7 @@ const GroupPreview: React.FC<IProps> = ({ group }: IProps) => {
|
|||
|
||||
return (
|
||||
<div className="groupPreview">
|
||||
<GroupAvatar group={group} />
|
||||
<GroupAvatar group={group} groupId={groupId}/>
|
||||
<h1>{group.name}</h1>
|
||||
{description ? <p>{description}</p> : null}
|
||||
</div>
|
||||
|
|
|
@ -92,6 +92,7 @@ const invite = async ({
|
|||
return (
|
||||
<GroupPreview
|
||||
group={await getGroup(clientAddress, link.identifier)}
|
||||
groupId={link.identifier}
|
||||
/>
|
||||
);
|
||||
|
||||
|
@ -126,7 +127,7 @@ const LinkPreview: React.FC<IProps> = ({ link }: IProps) => {
|
|||
let content: JSX.Element;
|
||||
const [showHSOptions, setShowHSOPtions] = useState(false);
|
||||
|
||||
const hses = useHSs(link);
|
||||
const hses = useHSs({link});
|
||||
|
||||
if (!hses.length) {
|
||||
content = (
|
||||
|
|
|
@ -84,7 +84,7 @@ export const WrappedInviterPreview: React.FC<WrappedInviterProps> = ({
|
|||
link,
|
||||
}: WrappedInviterProps) => {
|
||||
const [user, setUser] = useState<User | undefined>(undefined);
|
||||
const hss = useHSs(link);
|
||||
const hss = useHSs({link});
|
||||
useEffect(() => {
|
||||
if (hss.length) {
|
||||
client(hss[0])
|
||||
|
|
|
@ -182,6 +182,21 @@ export async function getGroupDetails(
|
|||
.then(GroupSchema.parse);
|
||||
}
|
||||
|
||||
export function getThumbnailURI(
|
||||
clientURL: string,
|
||||
mxcId: string,
|
||||
height: number,
|
||||
width: number,
|
||||
): string {
|
||||
const mxcParse = mxcId.match(/mxc:\/\/(?<server>.+)\/(?<mediaId>.+)/);
|
||||
if (!mxcParse || !mxcParse.groups) {
|
||||
throw new Error(`mxc invalid. mxc: ${mxcId}`);
|
||||
}
|
||||
// eslint-disable-next-line max-len
|
||||
return `https://${clientURL}/_matrix/media/r0/thumbnail/${mxcParse.groups.server}/${mxcParse.groups.mediaId}?height=${height}&width=${width}&method=crop`;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Gets an mxc resource
|
||||
*/
|
||||
|
|
|
@ -30,6 +30,7 @@ import {
|
|||
getUserDetails,
|
||||
convertMXCtoMediaQuery,
|
||||
getGroupDetails,
|
||||
getThumbnailURI as cypherGetThumbnailURI,
|
||||
} from '../matrix-cypher';
|
||||
import { LinkKind, Permalink } from '../parser/types';
|
||||
|
||||
|
@ -177,6 +178,24 @@ export function getMediaQueryFromMCX(mxc?: string): string {
|
|||
}
|
||||
}
|
||||
|
||||
export function getThumbnailURI(
|
||||
clientURL: string,
|
||||
height: number,
|
||||
width: number,
|
||||
mxcId?: string,
|
||||
): string {
|
||||
if (!mxcId) {
|
||||
return '';
|
||||
}
|
||||
|
||||
try {
|
||||
return cypherGetThumbnailURI(clientURL, mxcId, height, width);
|
||||
} catch (e){
|
||||
console.error(e);
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
export async function getGroup(
|
||||
clientURL: string,
|
||||
groupId: string
|
||||
|
|
|
@ -22,7 +22,34 @@ import HSContext, {
|
|||
} from '../contexts/HSContext';
|
||||
import { SafeLink } from '../parser/types';
|
||||
|
||||
function selectedClient(link: SafeLink, hsOptions: State): string[] {
|
||||
function selectedClient({ link, identifier, hsOptions }: {
|
||||
link?: SafeLink,
|
||||
identifier?: string;
|
||||
hsOptions: State
|
||||
}): string[] {
|
||||
const linkHSs = link ? [
|
||||
...link.identifier
|
||||
.split('/')
|
||||
.map((i) => 'https://' + i.split(':')[1]),
|
||||
...link.arguments.vias,
|
||||
] : [];
|
||||
const identifierHS: string[] = [];
|
||||
|
||||
try {
|
||||
if (identifier) {
|
||||
const match = identifier.match(/^.*:(?<server>.*)$/);
|
||||
if (match && match.groups) {
|
||||
const server = match.groups.server;
|
||||
if (server) {
|
||||
identifierHS.push(server);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(`Could parse user identifier: ${identifier}`);
|
||||
console.error(e);
|
||||
}
|
||||
|
||||
switch (hsOptions.option) {
|
||||
case HSOptions.Unset:
|
||||
return [];
|
||||
|
@ -30,22 +57,31 @@ function selectedClient(link: SafeLink, hsOptions: State): string[] {
|
|||
return [hsOptions.hs];
|
||||
case HSOptions.Any:
|
||||
return [
|
||||
...link.identifier
|
||||
.split('/')
|
||||
.map((i) => 'https://' + i.split(':')[1]),
|
||||
...link.arguments.vias,
|
||||
...linkHSs,
|
||||
...identifierHS,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
export default function useHSs(link: SafeLink): string[] {
|
||||
export default function useHSs({ link, identifier }: {
|
||||
link?: SafeLink,
|
||||
identifier?: string,
|
||||
}): string[] {
|
||||
const [HSState] = useContext(HSContext);
|
||||
const [TempHSState] = useContext(TempHSContext);
|
||||
|
||||
if (HSState.option !== HSOptions.Unset) {
|
||||
return selectedClient(link, HSState);
|
||||
return selectedClient({
|
||||
link,
|
||||
identifier,
|
||||
hsOptions: HSState
|
||||
});
|
||||
} else if (TempHSState.option !== HSOptions.Unset) {
|
||||
return selectedClient(link, TempHSState);
|
||||
return selectedClient({
|
||||
link,
|
||||
identifier,
|
||||
hsOptions: TempHSState
|
||||
});
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue