Merge pull request #144 from matrix-org/thumbnails

Use thumbnails api instead of mxc download
This commit is contained in:
Jorik Schellekens 2020-09-24 10:49:18 +01:00 committed by GitHub
commit 32c6119243
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 133 additions and 32 deletions

View File

@ -16,13 +16,16 @@ limitations under the License.
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import classNames from 'classnames'; 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 logo from '../imgs/chat-icon.svg';
import './Avatar.scss'; import './Avatar.scss';
const AVATAR_SIZE = 96;
interface IProps { interface IProps {
className?: string; className?: string;
avatarUrl: string; avatarUrl: string;
@ -56,12 +59,20 @@ interface IPropsUserAvatar {
export const UserAvatar: React.FC<IPropsUserAvatar> = ({ export const UserAvatar: React.FC<IPropsUserAvatar> = ({
user, user,
userId, userId,
}: IPropsUserAvatar) => ( }: IPropsUserAvatar) => {
const [hs] = useHSs({ identifier: userId });
return (
<Avatar <Avatar
avatarUrl={getMediaQueryFromMCX(user.avatar_url)} avatarUrl={getThumbnailURI(
hs,
AVATAR_SIZE,
AVATAR_SIZE,
user.avatar_url
)}
label={user.displayname ? user.displayname : userId} label={user.displayname ? user.displayname : userId}
/> />
); );
};
interface IPropsRoomAvatar { interface IPropsRoomAvatar {
room: Room; room: Room;
@ -69,24 +80,42 @@ interface IPropsRoomAvatar {
export const RoomAvatar: React.FC<IPropsRoomAvatar> = ({ export const RoomAvatar: React.FC<IPropsRoomAvatar> = ({
room, room,
}: IPropsRoomAvatar) => ( }: IPropsRoomAvatar) => {
const [hs] = useHSs({ identifier: room.room_id });
return (
<Avatar <Avatar
avatarUrl={getMediaQueryFromMCX(room.avatar_url)} avatarUrl={getThumbnailURI(
hs,
AVATAR_SIZE,
AVATAR_SIZE,
room.avatar_url
)}
label={room.name || room.room_id} label={room.name || room.room_id}
/> />
); );
};
interface IPropsGroupAvatar { interface IPropsGroupAvatar {
group: Group; group: Group;
groupId: string;
} }
export const GroupAvatar: React.FC<IPropsGroupAvatar> = ({ export const GroupAvatar: React.FC<IPropsGroupAvatar> = ({
group, group,
}: IPropsGroupAvatar) => ( groupId,
}: IPropsGroupAvatar) => {
const [hs] = useHSs({ identifier: groupId });
return (
<Avatar <Avatar
avatarUrl={getMediaQueryFromMCX(group.avatar_url)} avatarUrl={getThumbnailURI(
hs,
AVATAR_SIZE,
AVATAR_SIZE,
group.avatar_url
)}
label={group.name} label={group.name}
/> />
); );
};
export default Avatar; export default Avatar;

View File

@ -23,9 +23,10 @@ import './GroupPreview.scss';
interface IProps { interface IProps {
group: Group; group: Group;
groupId: string;
} }
const GroupPreview: React.FC<IProps> = ({ group }: IProps) => { const GroupPreview: React.FC<IProps> = ({ group, groupId }: IProps) => {
const description = group.long_description const description = group.long_description
? group.long_description ? group.long_description
: group.short_description : group.short_description
@ -34,7 +35,7 @@ const GroupPreview: React.FC<IProps> = ({ group }: IProps) => {
return ( return (
<div className="groupPreview"> <div className="groupPreview">
<GroupAvatar group={group} /> <GroupAvatar group={group} groupId={groupId}/>
<h1>{group.name}</h1> <h1>{group.name}</h1>
{description ? <p>{description}</p> : null} {description ? <p>{description}</p> : null}
</div> </div>

View File

@ -92,6 +92,7 @@ const invite = async ({
return ( return (
<GroupPreview <GroupPreview
group={await getGroup(clientAddress, link.identifier)} group={await getGroup(clientAddress, link.identifier)}
groupId={link.identifier}
/> />
); );
@ -126,7 +127,7 @@ const LinkPreview: React.FC<IProps> = ({ link }: IProps) => {
let content: JSX.Element; let content: JSX.Element;
const [showHSOptions, setShowHSOPtions] = useState(false); const [showHSOptions, setShowHSOPtions] = useState(false);
const hses = useHSs(link); const hses = useHSs({link});
if (!hses.length) { if (!hses.length) {
content = ( content = (

View File

@ -84,7 +84,7 @@ export const WrappedInviterPreview: React.FC<WrappedInviterProps> = ({
link, link,
}: WrappedInviterProps) => { }: WrappedInviterProps) => {
const [user, setUser] = useState<User | undefined>(undefined); const [user, setUser] = useState<User | undefined>(undefined);
const hss = useHSs(link); const hss = useHSs({link});
useEffect(() => { useEffect(() => {
if (hss.length) { if (hss.length) {
client(hss[0]) client(hss[0])

View File

@ -182,6 +182,21 @@ export async function getGroupDetails(
.then(GroupSchema.parse); .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 * Gets an mxc resource
*/ */

View File

@ -30,6 +30,7 @@ import {
getUserDetails, getUserDetails,
convertMXCtoMediaQuery, convertMXCtoMediaQuery,
getGroupDetails, getGroupDetails,
getThumbnailURI as cypherGetThumbnailURI,
} from '../matrix-cypher'; } from '../matrix-cypher';
import { LinkKind, Permalink } from '../parser/types'; 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( export async function getGroup(
clientURL: string, clientURL: string,
groupId: string groupId: string

View File

@ -22,7 +22,34 @@ import HSContext, {
} from '../contexts/HSContext'; } from '../contexts/HSContext';
import { SafeLink } from '../parser/types'; 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) { switch (hsOptions.option) {
case HSOptions.Unset: case HSOptions.Unset:
return []; return [];
@ -30,22 +57,31 @@ function selectedClient(link: SafeLink, hsOptions: State): string[] {
return [hsOptions.hs]; return [hsOptions.hs];
case HSOptions.Any: case HSOptions.Any:
return [ return [
...link.identifier ...linkHSs,
.split('/') ...identifierHS,
.map((i) => 'https://' + i.split(':')[1]),
...link.arguments.vias,
]; ];
} }
} }
export default function useHSs(link: SafeLink): string[] { export default function useHSs({ link, identifier }: {
link?: SafeLink,
identifier?: string,
}): string[] {
const [HSState] = useContext(HSContext); const [HSState] = useContext(HSContext);
const [TempHSState] = useContext(TempHSContext); const [TempHSState] = useContext(TempHSContext);
if (HSState.option !== HSOptions.Unset) { if (HSState.option !== HSOptions.Unset) {
return selectedClient(link, HSState); return selectedClient({
link,
identifier,
hsOptions: HSState
});
} else if (TempHSState.option !== HSOptions.Unset) { } else if (TempHSState.option !== HSOptions.Unset) {
return selectedClient(link, TempHSState); return selectedClient({
link,
identifier,
hsOptions: TempHSState
});
} else { } else {
return []; return [];
} }