diff --git a/src/api/gramjs/methods/messages.ts b/src/api/gramjs/methods/messages.ts index fb5bedfc4..4d89692de 100644 --- a/src/api/gramjs/methods/messages.ts +++ b/src/api/gramjs/methods/messages.ts @@ -515,6 +515,7 @@ async function uploadMedia(localMessage: ApiMessage, attachment: ApiAttachment, duration, w: width, h: height, + supportsStreaming: true, })); } } diff --git a/src/components/common/Audio.tsx b/src/components/common/Audio.tsx index 3ed415a79..b1f907458 100644 --- a/src/components/common/Audio.tsx +++ b/src/components/common/Audio.tsx @@ -156,12 +156,11 @@ const Audio: FC = ({ 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 = ({ ); const buttonClassNames = ['toggle-play']; - if (isLoadingForPlaying) { + if (shouldRenderCross) { buttonClassNames.push('loading'); } else if (isPlaying) { buttonClassNames.push('pause'); @@ -334,13 +333,13 @@ const Audio: FC = ({ {shouldRenderSpinner && ( -
+
)} diff --git a/src/components/middle/composer/AttachmentModal.tsx b/src/components/middle/composer/AttachmentModal.tsx index c6a93aacb..8c532e55d 100644 --- a/src/components/middle/composer/AttachmentModal.tsx +++ b/src/components/middle/composer/AttachmentModal.tsx @@ -151,12 +151,15 @@ const AttachmentModal: FC = ({ 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'); } diff --git a/src/components/middle/composer/helpers/buildAttachment.ts b/src/components/middle/composer/helpers/buildAttachment.ts index a04268111..9f3f97ed7 100644 --- a/src/components/middle/composer/helpers/buildAttachment.ts +++ b/src/components/middle/composer/helpers/buildAttachment.ts @@ -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 { - 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); - }); -} diff --git a/src/components/middle/message/Video.tsx b/src/components/middle/message/Video.tsx index c0b2520de..8266226a2 100644 --- a/src/components/middle/message/Video.tsx +++ b/src/components/middle/message/Video.tsx @@ -194,7 +194,9 @@ const Video: FC = ({ )} {isTransferring ? ( - ... + + {isUploading ? `${Math.round(transferProgress * 100)}%` : '...'} + ) : (
{video.isGif ? 'GIF' : formatMediaDuration(Math.max(duration - playProgress, 0))} diff --git a/src/config.ts b/src/config.ts index 7b5e8feac..6908dea73 100644 --- a/src/config.ts +++ b/src/config.ts @@ -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