Composer: Various improvements for attachments (audio, video, photo) (#1443)
This commit is contained in:
parent
d121b82de7
commit
fdda362cb3
@ -515,6 +515,7 @@ async function uploadMedia(localMessage: ApiMessage, attachment: ApiAttachment,
|
||||
duration,
|
||||
w: width,
|
||||
h: height,
|
||||
supportsStreaming: true,
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
@ -156,12 +156,11 @@ const Audio: FC<OwnProps> = ({
|
||||
transitionClassNames: spinnerClassNames,
|
||||
} = useShowTransition(isTransferring);
|
||||
|
||||
const handleButtonClick = useCallback(() => {
|
||||
if (isUploading && !isPlaying) {
|
||||
if (onCancelUpload) {
|
||||
onCancelUpload();
|
||||
}
|
||||
const shouldRenderCross = shouldRenderSpinner && (isLoadingForPlaying || isUploading);
|
||||
|
||||
const handleButtonClick = useCallback(() => {
|
||||
if (isUploading) {
|
||||
onCancelUpload?.();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -269,7 +268,7 @@ const Audio: FC<OwnProps> = ({
|
||||
);
|
||||
|
||||
const buttonClassNames = ['toggle-play'];
|
||||
if (isLoadingForPlaying) {
|
||||
if (shouldRenderCross) {
|
||||
buttonClassNames.push('loading');
|
||||
} else if (isPlaying) {
|
||||
buttonClassNames.push('pause');
|
||||
@ -334,13 +333,13 @@ const Audio: FC<OwnProps> = ({
|
||||
<i className="icon-pause" />
|
||||
</Button>
|
||||
{shouldRenderSpinner && (
|
||||
<div className={buildClassName('media-loading', spinnerClassNames, isLoadingForPlaying && 'interactive')}>
|
||||
<div className={buildClassName('media-loading', spinnerClassNames, shouldRenderCross && 'interactive')}>
|
||||
<ProgressSpinner
|
||||
progress={transferProgress}
|
||||
transparent
|
||||
size="m"
|
||||
onClick={isLoadingForPlaying ? handleButtonClick : undefined}
|
||||
noCross={!isLoadingForPlaying}
|
||||
onClick={shouldRenderCross ? handleButtonClick : undefined}
|
||||
noCross={!shouldRenderCross}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@ -151,12 +151,15 @@ const AttachmentModal: FC<OwnProps> = ({
|
||||
|
||||
const areAllPhotos = renderingAttachments.every((a) => a.mimeType.startsWith('image/'));
|
||||
const areAllVideos = renderingAttachments.every((a) => a.mimeType.startsWith('video/'));
|
||||
const areAllAudios = renderingAttachments.every((a) => a.mimeType.startsWith('audio/'));
|
||||
|
||||
let title = '';
|
||||
if (areAllPhotos) {
|
||||
title = lang('PreviewSender.SendPhoto', renderingAttachments.length, 'i');
|
||||
} else if (areAllVideos) {
|
||||
title = lang('PreviewSender.SendVideo', renderingAttachments.length, 'i');
|
||||
} else if (areAllAudios) {
|
||||
title = lang('PreviewSender.SendAudio', renderingAttachments.length, 'i');
|
||||
} else {
|
||||
title = lang('PreviewSender.SendFile', renderingAttachments.length, 'i');
|
||||
}
|
||||
|
||||
@ -1,7 +1,12 @@
|
||||
import { ApiAttachment } from '../../../../api/types';
|
||||
import { preloadImage, preloadVideo, createPosterForVideo } from '../../../../util/files';
|
||||
import {
|
||||
preloadImage,
|
||||
preloadVideo,
|
||||
createPosterForVideo,
|
||||
fetchBlob,
|
||||
} from '../../../../util/files';
|
||||
import { scaleImage } from '../../../../util/imageResize';
|
||||
|
||||
const MAX_QUICK_VIDEO_SIZE = 10 * 1024 ** 2; // 10 MB
|
||||
const MAX_QUICK_IMG_SIZE = 1280; // px
|
||||
|
||||
export default async function buildAttachment(
|
||||
@ -18,13 +23,10 @@ export default async function buildAttachment(
|
||||
const { width, height } = img;
|
||||
|
||||
if (width > MAX_QUICK_IMG_SIZE || height > MAX_QUICK_IMG_SIZE || mimeType !== 'image/jpeg') {
|
||||
const newBlob = await squeezeImage(img);
|
||||
if (newBlob) {
|
||||
URL.revokeObjectURL(blobUrl);
|
||||
return buildAttachment(filename, newBlob, true, options);
|
||||
} else {
|
||||
return buildAttachment(filename, blob, false, options);
|
||||
}
|
||||
const resizedUrl = await scaleImage(blobUrl, MAX_QUICK_IMG_SIZE / Math.max(width, height), 'image/jpeg');
|
||||
URL.revokeObjectURL(blobUrl);
|
||||
const newBlob = await fetchBlob(resizedUrl);
|
||||
return buildAttachment(filename, newBlob, true, options);
|
||||
}
|
||||
|
||||
quick = { width, height };
|
||||
@ -32,12 +34,8 @@ export default async function buildAttachment(
|
||||
previewBlobUrl = blobUrl;
|
||||
}
|
||||
} else if (mimeType.startsWith('video/')) {
|
||||
// Videos < 10 MB are always sent in quick mode (in other clients).
|
||||
// Quick mode for videos > 10 MB is not supported until client-side video squeezing is implemented.
|
||||
if (size < MAX_QUICK_VIDEO_SIZE) {
|
||||
const { videoWidth: width, videoHeight: height, duration } = await preloadVideo(blobUrl);
|
||||
quick = { width, height, duration };
|
||||
}
|
||||
const { videoWidth: width, videoHeight: height, duration } = await preloadVideo(blobUrl);
|
||||
quick = { width, height, duration };
|
||||
|
||||
previewBlobUrl = await createPosterForVideo(blobUrl);
|
||||
}
|
||||
@ -52,28 +50,3 @@ export default async function buildAttachment(
|
||||
...options,
|
||||
};
|
||||
}
|
||||
|
||||
function squeezeImage(img: HTMLImageElement): Promise<Blob | null> {
|
||||
return new Promise((resolve) => {
|
||||
const canvas = document.createElement('canvas');
|
||||
const ctx = canvas.getContext('2d')!;
|
||||
|
||||
let { width, height } = img;
|
||||
|
||||
if (width > MAX_QUICK_IMG_SIZE || height > MAX_QUICK_IMG_SIZE) {
|
||||
if (width >= height) {
|
||||
height *= MAX_QUICK_IMG_SIZE / width;
|
||||
width = MAX_QUICK_IMG_SIZE;
|
||||
} else {
|
||||
width *= MAX_QUICK_IMG_SIZE / height;
|
||||
height = MAX_QUICK_IMG_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
|
||||
ctx.drawImage(img, 0, 0, img.width, img.height, 0, 0, width, height);
|
||||
canvas.toBlob(resolve, 'image/jpeg', 100);
|
||||
});
|
||||
}
|
||||
|
||||
@ -194,7 +194,9 @@ const Video: FC<OwnProps> = ({
|
||||
<i className="icon-download" />
|
||||
)}
|
||||
{isTransferring ? (
|
||||
<span className="message-upload-progress">...</span>
|
||||
<span className="message-upload-progress">
|
||||
{isUploading ? `${Math.round(transferProgress * 100)}%` : '...'}
|
||||
</span>
|
||||
) : (
|
||||
<div className="message-media-duration">
|
||||
{video.isGif ? 'GIF' : formatMediaDuration(Math.max(duration - playProgress, 0))}
|
||||
|
||||
@ -122,7 +122,7 @@ export const MENU_TRANSITION_DURATION = 200;
|
||||
export const SLIDE_TRANSITION_DURATION = 450;
|
||||
|
||||
export const CONTENT_TYPES_FOR_QUICK_UPLOAD = new Set([
|
||||
'image/png', 'image/gif', 'image/jpeg', 'video/mp4', 'video/avi', 'video/quicktime',
|
||||
'image/png', 'image/gif', 'image/jpeg',
|
||||
]);
|
||||
|
||||
// eslint-disable-next-line max-len
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user