Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion src/app/components/RenderMessageContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -184,13 +184,32 @@ export function RenderMessageContent({
}

if (msgType === MsgType.Image) {
const content: IImageContent = getContent();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IImageContent already provide the thumbnail image along with dimensions, should not we be passing that to ImageContent component?

const width = content?.info?.w;
const height = content?.info?.h;
let thumbnail: {
imgWidth: number,
imgHeight: number,
resizeMethod: string
} | undefined;
if (width && height) {
const scale = (width > height ? width : height) / 800;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we already has a standard thumbnail scaling function getThumbnailDimensions which is used to generate the thumbnail while sending images.

if (width > 800 || height > 800 && scale > 1) {
thumbnail = {
imgWidth: width / scale,
imgHeight: height / scale,
resizeMethod: "scale",
}
}
}
return (
<>
<MImage
content={getContent()}
content={content}
renderImageContent={(props) => (
<ImageContent
{...props}
{...thumbnail}
autoPlay={mediaAutoLoad}
renderImage={(p) => <Image {...p} loading="lazy" />}
renderViewer={(p) => <ImageViewer {...p} />}
Expand Down
32 changes: 24 additions & 8 deletions src/app/components/message/content/ImageContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ export type ImageContentProps = {
autoPlay?: boolean;
markedAsSpoiler?: boolean;
spoilerReason?: string;
imgWidth?: number;
imgHeight?: number;
resizeMethod?: string;
renderViewer: (props: RenderViewerProps) => ReactNode;
renderImage: (props: RenderImageProps) => ReactNode;
};
Expand All @@ -70,6 +73,9 @@ export const ImageContent = as<'div', ImageContentProps>(
autoPlay,
markedAsSpoiler,
spoilerReason,
imgWidth,
imgHeight,
resizeMethod,
renderViewer,
renderImage,
...props
Expand All @@ -84,26 +90,36 @@ export const ImageContent = as<'div', ImageContentProps>(
const [error, setError] = useState(false);
const [viewer, setViewer] = useState(false);
const [blurred, setBlurred] = useState(markedAsSpoiler ?? false);
const [useThumbnail, setUseThumbnail] = useState(imgWidth && imgHeight && resizeMethod);

const [srcState, loadSrc] = useAsyncCallback(
useCallback(async () => {
const mediaUrl = mxcUrlToHttp(mx, url, useAuthentication) ?? url;
const mediaUrl = (useThumbnail ? mxcUrlToHttp(mx, url, useAuthentication, imgWidth, imgHeight, resizeMethod) : mxcUrlToHttp(mx, url, useAuthentication)) ?? url;
if (encInfo) {
const fileContent = await downloadEncryptedMedia(mediaUrl, (encBuf) =>
decryptFile(encBuf, mimeType ?? FALLBACK_MIMETYPE, encInfo)
);
const decrypt = (encBuf: ArrayBuffer) => decryptFile(encBuf, mimeType ?? FALLBACK_MIMETYPE, encInfo);
let fileContent;
try {
fileContent = await downloadEncryptedMedia(mediaUrl, decrypt);
} catch {
fileContent = await downloadEncryptedMedia(mxcUrlToHttp(mx, url, useAuthentication) ?? url, decrypt);
}
Comment on lines +99 to +105
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should always use the original url for encrypted image as it is always going to fail to generate thumbnail for it.

return URL.createObjectURL(fileContent);
}
return mediaUrl;
}, [mx, url, useAuthentication, mimeType, encInfo])
}, [mx, url, useAuthentication, mimeType, encInfo, useThumbnail, imgWidth, imgHeight, resizeMethod])
);

const handleLoad = () => {
setLoad(true);
};
const handleError = () => {
setLoad(false);
setError(true);
if (useThumbnail) {
setUseThumbnail(false);
loadSrc();
} else {
setLoad(false);
setError(true);
}
Comment on lines +116 to +122
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there any particular reason to use this fallback strategy?

};

const handleRetry = () => {
Expand Down Expand Up @@ -134,7 +150,7 @@ export const ImageContent = as<'div', ImageContentProps>(
onContextMenu={(evt: any) => evt.stopPropagation()}
>
{renderViewer({
src: srcState.data,
src: useThumbnail ? (mxcUrlToHttp(mx, url, useAuthentication) ?? url) : srcState.data,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since encrypted message always going to use full image we should use srcState.data for them and url for normal images.

alt: body,
requestClose: () => setViewer(false),
})}
Expand Down
1 change: 1 addition & 0 deletions src/types/matrix/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ export type IImageContent = {
url?: string;
info?: IImageInfo & IThumbnailContent;
file?: IEncryptedFile;
info?: { h: number, w: number };
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

info is already described at line 50.

[MATRIX_SPOILER_PROPERTY_NAME]?: boolean;
[MATRIX_SPOILER_REASON_PROPERTY_NAME]?: string;
};
Expand Down