Attachment Modal: Support hd photo (#5994)
This commit is contained in:
parent
a85fec6c65
commit
c8360b2e5e
@ -36,6 +36,7 @@ export interface ApiOnProgress {
|
||||
}
|
||||
|
||||
export interface ApiAttachment {
|
||||
blob: Blob;
|
||||
blobUrl: string;
|
||||
compressedBlobUrl?: string;
|
||||
filename: string;
|
||||
@ -62,6 +63,7 @@ export interface ApiAttachment {
|
||||
|
||||
uniqueId?: string;
|
||||
ttlSeconds?: number;
|
||||
shouldSendInHighQuality?: boolean;
|
||||
}
|
||||
|
||||
export interface ApiWallpaper {
|
||||
|
||||
1
src/assets/font-icons/hd-photo.svg
Normal file
1
src/assets/font-icons/hd-photo.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="none"><path fill="#000" d="M27.33 2.468A4.924 4.924 0 0 1 32 7.385v17.23l-.006.254a4.924 4.924 0 0 1-4.664 4.663l-.253.006H4.923l-.253-.006A4.925 4.925 0 0 1 .006 24.87L0 24.615V7.385a4.924 4.924 0 0 1 4.67-4.917l.253-.006h22.154zM4.923 4.923a2.46 2.46 0 0 0-2.461 2.462v17.23a2.46 2.46 0 0 0 2.46 2.462h22.155a2.46 2.46 0 0 0 2.461-2.462V7.385a2.46 2.46 0 0 0-2.46-2.462zm16 3.692a6.155 6.155 0 0 1 6.154 6.155V16l-.009.316a6.154 6.154 0 0 1-6.145 5.838H17.23V8.615zm-6.154 0c.68 0 1.23.551 1.23 1.23v11.078a1.23 1.23 0 1 1-2.46 0V17.23H7.383v3.692a1.23 1.23 0 0 1-2.462 0V9.846a1.231 1.231 0 0 1 2.462 0v4.924h6.154V9.846c0-.68.55-1.23 1.23-1.23m4.923 11.077h1.23A3.69 3.69 0 0 0 24.616 16v-1.23a3.69 3.69 0 0 0-3.692-3.693h-1.23z"/></svg>
|
||||
|
After Width: | Height: | Size: 810 B |
1
src/assets/font-icons/sd-photo.svg
Normal file
1
src/assets/font-icons/sd-photo.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="none"><path fill="#000" d="M27.33 2.467A4.924 4.924 0 0 1 32 7.384v17.232l-.006.253a4.925 4.925 0 0 1-4.664 4.664l-.253.006H4.923l-.253-.006a4.925 4.925 0 0 1-4.664-4.664L0 24.616V7.384a4.924 4.924 0 0 1 4.67-4.917l.253-.006h22.154zM4.923 4.923a2.46 2.46 0 0 0-2.461 2.461v17.232c0 1.359 1.102 2.46 2.46 2.46h22.155c1.36 0 2.46-1.101 2.461-2.46V7.384a2.46 2.46 0 0 0-2.46-2.46zm16 3.693a6.154 6.154 0 0 1 6.154 6.153V16l-.009.316a6.154 6.154 0 0 1-6.145 5.838H17.23V8.616zm-1.23 11.076h1.23A3.69 3.69 0 0 0 24.615 16V14.77a3.69 3.69 0 0 0-3.692-3.692h-1.23z"/><path fill="#000" d="M13.41 12.418c-.624 0-1.104-.523-1.504-1.002a2 2 0 0 0-.367-.335q-.675-.48-1.757-.479-.76 0-1.305.23-.544.229-.833.622t-.295.898q0 .42.19.728.198.308.532.525.334.21.74.354t.82.242l1.259.315q.76.176 1.461.479.709.3 1.266.76.564.459.891 1.108.328.65.328 1.52 0 1.181-.603 2.08-.603.89-1.744 1.396-1.134.498-2.747.498-1.566 0-2.72-.485-1.147-.486-1.797-1.416a3.7 3.7 0 0 1-.492-1.024c-.204-.66.372-1.245 1.062-1.245.636 0 1.115.536 1.479 1.058q.039.056.082.11.38.465.99.694.616.23 1.377.23.793-.001 1.39-.236.602-.243.944-.67.34-.432.347-1.009-.006-.525-.308-.865-.302-.348-.846-.577a8 8 0 0 0-1.259-.42l-1.527-.393q-1.659-.426-2.623-1.292-.957-.87-.957-2.314 0-1.186.643-2.078.649-.891 1.763-1.383 1.115-.499 2.524-.499 1.43 0 2.505.499 1.08.492 1.698 1.37.261.37.416.789c.236.64-.34 1.217-1.023 1.217"/></svg>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
@ -2017,6 +2017,8 @@
|
||||
"ValueGiftSortByNumber" = "Number";
|
||||
"ResellGiftsNoFound" = "No gifts found";
|
||||
"ResellGiftsClearFilters" = "Clear Filters";
|
||||
"SendInStandardQuality" = "Send In Standard Quality";
|
||||
"SendInHighQuality" = "Send In High Quality";
|
||||
"MonoforumBadge" = "DIRECT";
|
||||
"MonoforumStatus" = "Channel messages";
|
||||
"MonoforumComposerPlaceholder" = "Choose a message to reply";
|
||||
|
||||
@ -635,7 +635,6 @@ const Composer: FC<OwnProps & StateProps> = ({
|
||||
});
|
||||
|
||||
const {
|
||||
shouldSuggestCompression,
|
||||
shouldForceCompression,
|
||||
shouldForceAsFile,
|
||||
handleAppendFiles,
|
||||
@ -655,6 +654,7 @@ const Composer: FC<OwnProps & StateProps> = ({
|
||||
canSendDocuments,
|
||||
insertNextText,
|
||||
editedMessage: editingMessage,
|
||||
shouldSendInHighQuality: attachmentSettings.shouldSendInHighQuality,
|
||||
});
|
||||
|
||||
const [isBotKeyboardOpen, openBotKeyboard, closeBotKeyboard] = useFlag();
|
||||
@ -1848,7 +1848,6 @@ const Composer: FC<OwnProps & StateProps> = ({
|
||||
attachments={attachments}
|
||||
getHtml={getHtml}
|
||||
isReady={isReady}
|
||||
shouldSuggestCompression={shouldSuggestCompression}
|
||||
shouldForceCompression={shouldForceCompression}
|
||||
shouldForceAsFile={shouldForceAsFile}
|
||||
isForCurrentMessageList={isForCurrentMessageList}
|
||||
|
||||
@ -3,6 +3,7 @@ import {
|
||||
memo, useEffect,
|
||||
useMemo,
|
||||
} from '../../../lib/teact/teact';
|
||||
import { getActions } from '../../../global';
|
||||
|
||||
import type { ApiAttachMenuPeerType, ApiMessage } from '../../../api/types';
|
||||
import type { GlobalState } from '../../../global/types';
|
||||
@ -55,7 +56,7 @@ export type OwnProps = {
|
||||
peerType?: ApiAttachMenuPeerType;
|
||||
shouldCollectDebugLogs?: boolean;
|
||||
theme: ThemeKey;
|
||||
onFileSelect: (files: File[], shouldSuggestCompression?: boolean) => void;
|
||||
onFileSelect: (files: File[]) => void;
|
||||
onPollCreate: NoneToVoidFunction;
|
||||
onMenuOpen: NoneToVoidFunction;
|
||||
onMenuClose: NoneToVoidFunction;
|
||||
@ -89,6 +90,9 @@ const AttachMenu: FC<OwnProps> = ({
|
||||
messageListType,
|
||||
paidMessagesStars,
|
||||
}) => {
|
||||
const {
|
||||
updateAttachmentSettings,
|
||||
} = getActions();
|
||||
const [isAttachMenuOpen, openAttachMenu, closeAttachMenu] = useFlag();
|
||||
const [handleMouseEnter, handleMouseLeave, markMouseInside] = useMouseInside(isAttachMenuOpen, closeAttachMenu);
|
||||
|
||||
@ -126,29 +130,31 @@ const AttachMenu: FC<OwnProps> = ({
|
||||
}
|
||||
});
|
||||
|
||||
const handleFileSelect = useLastCallback((e: Event, shouldSuggestCompression?: boolean) => {
|
||||
const handleFileSelect = useLastCallback((e: Event) => {
|
||||
const { files } = e.target as HTMLInputElement;
|
||||
const validatedFiles = validateFiles(files);
|
||||
|
||||
if (validatedFiles?.length) {
|
||||
onFileSelect(validatedFiles, shouldSuggestCompression);
|
||||
onFileSelect(validatedFiles);
|
||||
}
|
||||
});
|
||||
|
||||
const handleQuickSelect = useLastCallback(() => {
|
||||
updateAttachmentSettings({ shouldCompress: true });
|
||||
openSystemFilesDialog(
|
||||
Array.from(canSendVideoAndPhoto ? CONTENT_TYPES_WITH_PREVIEW : (
|
||||
canSendPhotos ? SUPPORTED_PHOTO_CONTENT_TYPES : SUPPORTED_VIDEO_CONTENT_TYPES
|
||||
)).join(','),
|
||||
(e) => handleFileSelect(e, true),
|
||||
(e) => handleFileSelect(e),
|
||||
);
|
||||
});
|
||||
|
||||
const handleDocumentSelect = useLastCallback(() => {
|
||||
updateAttachmentSettings({ shouldCompress: false });
|
||||
openSystemFilesDialog(!canSendDocuments && canSendAudios
|
||||
? Array.from(SUPPORTED_AUDIO_CONTENT_TYPES).join(',') : (
|
||||
'*'
|
||||
), (e) => handleFileSelect(e, false));
|
||||
), (e) => handleFileSelect(e));
|
||||
});
|
||||
|
||||
const handleSendLogs = useLastCallback(() => {
|
||||
|
||||
@ -75,7 +75,6 @@ export type OwnProps = {
|
||||
isReady: boolean;
|
||||
isForMessage?: boolean;
|
||||
shouldSchedule?: boolean;
|
||||
shouldSuggestCompression?: boolean;
|
||||
shouldForceCompression?: boolean;
|
||||
shouldForceAsFile?: boolean;
|
||||
isForCurrentMessageList?: boolean;
|
||||
@ -113,6 +112,7 @@ type StateProps = {
|
||||
const ATTACHMENT_MODAL_INPUT_ID = 'caption-input-text';
|
||||
const DROP_LEAVE_TIMEOUT_MS = 150;
|
||||
const MAX_LEFT_CHARS_TO_SHOW = 100;
|
||||
const CLOSE_MENU_ANIMATION_DURATION = 200;
|
||||
|
||||
const AttachmentModal: FC<OwnProps & StateProps> = ({
|
||||
chatId,
|
||||
@ -134,7 +134,6 @@ const AttachmentModal: FC<OwnProps & StateProps> = ({
|
||||
shouldSuggestCustomEmoji,
|
||||
customEmojiForEmoji,
|
||||
attachmentSettings,
|
||||
shouldSuggestCompression,
|
||||
shouldForceCompression,
|
||||
shouldForceAsFile,
|
||||
isForCurrentMessageList,
|
||||
@ -176,14 +175,16 @@ const AttachmentModal: FC<OwnProps & StateProps> = ({
|
||||
|
||||
const [isSymbolMenuOpen, openSymbolMenu, closeSymbolMenu] = useFlag();
|
||||
|
||||
const [shouldSendCompressed, setShouldSendCompressed] = useState(
|
||||
shouldSuggestCompression ?? attachmentSettings.shouldCompress,
|
||||
);
|
||||
const shouldSendCompressed = attachmentSettings.shouldCompress;
|
||||
const isSendingCompressed = Boolean(
|
||||
(shouldSendCompressed || shouldForceCompression || isInAlbum) && !shouldForceAsFile,
|
||||
);
|
||||
const [shouldSendGrouped, setShouldSendGrouped] = useState(attachmentSettings.shouldSendGrouped);
|
||||
const isInvertedMedia = attachmentSettings.isInvertedMedia;
|
||||
const [shouldSendInHighQuality, setShouldSendInHighQuality] = useState(
|
||||
attachmentSettings.shouldSendInHighQuality,
|
||||
);
|
||||
const [renderingShouldSendInHighQuality, setRenderingShouldSendInHighQuality] = useState(shouldSendInHighQuality);
|
||||
|
||||
const {
|
||||
handleScroll: handleAttachmentsScroll,
|
||||
@ -197,6 +198,8 @@ const AttachmentModal: FC<OwnProps & StateProps> = ({
|
||||
const renderingIsOpen = Boolean(renderingAttachments?.length);
|
||||
const [isHovered, markHovered, unmarkHovered] = useFlag();
|
||||
|
||||
const timerRef = useRef<number | undefined>();
|
||||
|
||||
useEffect(() => {
|
||||
if (!isOpen) {
|
||||
closeSymbolMenu();
|
||||
@ -269,16 +272,16 @@ const AttachmentModal: FC<OwnProps & StateProps> = ({
|
||||
|
||||
useEffect(() => {
|
||||
if (isOpen) {
|
||||
setShouldSendCompressed(shouldSuggestCompression ?? attachmentSettings.shouldCompress);
|
||||
setShouldSendGrouped(attachmentSettings.shouldSendGrouped);
|
||||
setShouldSendInHighQuality(attachmentSettings.shouldSendInHighQuality);
|
||||
}
|
||||
}, [attachmentSettings, isOpen, shouldSuggestCompression]);
|
||||
}, [attachmentSettings, isOpen]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isOpen) {
|
||||
updateAttachmentSettings({ isInvertedMedia: undefined });
|
||||
}
|
||||
}, [updateAttachmentSettings, isOpen, shouldSuggestCompression]);
|
||||
}, [updateAttachmentSettings, isOpen]);
|
||||
|
||||
function setIsInvertedMedia(value?: true) {
|
||||
updateAttachmentSettings({ isInvertedMedia: value });
|
||||
@ -303,9 +306,10 @@ const AttachmentModal: FC<OwnProps & StateProps> = ({
|
||||
: isSilent ? onSendSilent : onSend;
|
||||
send(isSendingCompressed, shouldSendGrouped, isInvertedMedia);
|
||||
updateAttachmentSettings({
|
||||
shouldCompress: shouldSuggestCompression === undefined ? isSendingCompressed : undefined,
|
||||
shouldCompress: isSendingCompressed,
|
||||
shouldSendGrouped,
|
||||
isInvertedMedia,
|
||||
shouldSendInHighQuality,
|
||||
});
|
||||
}
|
||||
});
|
||||
@ -387,6 +391,17 @@ const AttachmentModal: FC<OwnProps & StateProps> = ({
|
||||
})));
|
||||
});
|
||||
|
||||
const handleToggleShouldCompress = useLastCallback(() => {
|
||||
const newValue = !shouldSendCompressed;
|
||||
updateAttachmentSettings({ shouldCompress: newValue });
|
||||
});
|
||||
|
||||
const handleToggleQuality = useLastCallback(() => {
|
||||
const newValue = !shouldSendInHighQuality;
|
||||
setShouldSendInHighQuality(newValue);
|
||||
updateAttachmentSettings({ shouldSendInHighQuality: newValue });
|
||||
});
|
||||
|
||||
const handleDisableSpoilers = useLastCallback(() => {
|
||||
onAttachmentsUpdate(attachments.map((a) => ({ ...a, shouldSendAsSpoiler: undefined })));
|
||||
});
|
||||
@ -458,12 +473,13 @@ const AttachmentModal: FC<OwnProps & StateProps> = ({
|
||||
|
||||
const isQuickGallery = isSendingCompressed && hasOnlyMedia;
|
||||
|
||||
const [areAllPhotos, areAllVideos, areAllAudios] = useMemo(() => {
|
||||
const [areAllPhotos, areAllVideos, areAllAudios, hasAnyPhoto] = useMemo(() => {
|
||||
if (!isQuickGallery || !renderingAttachments) return [false, false, false];
|
||||
const everyPhoto = renderingAttachments.every((a) => SUPPORTED_PHOTO_CONTENT_TYPES.has(a.mimeType));
|
||||
const everyVideo = renderingAttachments.every((a) => SUPPORTED_VIDEO_CONTENT_TYPES.has(a.mimeType));
|
||||
const everyAudio = renderingAttachments.every((a) => SUPPORTED_AUDIO_CONTENT_TYPES.has(a.mimeType));
|
||||
return [everyPhoto, everyVideo, everyAudio];
|
||||
const hasAnyPhoto = renderingAttachments.some((a) => SUPPORTED_PHOTO_CONTENT_TYPES.has(a.mimeType));
|
||||
return [everyPhoto, everyVideo, everyAudio, hasAnyPhoto];
|
||||
}, [renderingAttachments, isQuickGallery]);
|
||||
|
||||
const hasAnySpoilerable = useMemo(() => {
|
||||
@ -471,6 +487,20 @@ const AttachmentModal: FC<OwnProps & StateProps> = ({
|
||||
return renderingAttachments.some((a) => !SUPPORTED_AUDIO_CONTENT_TYPES.has(a.mimeType));
|
||||
}, [renderingAttachments]);
|
||||
|
||||
useEffect(() => {
|
||||
if (shouldSendInHighQuality === renderingShouldSendInHighQuality) return;
|
||||
if (timerRef.current) clearTimeout(timerRef.current);
|
||||
timerRef.current = window.setTimeout(() => {
|
||||
setRenderingShouldSendInHighQuality(shouldSendInHighQuality);
|
||||
}, CLOSE_MENU_ANIMATION_DURATION);
|
||||
return () => {
|
||||
if (timerRef.current) {
|
||||
clearTimeout(timerRef.current);
|
||||
timerRef.current = undefined;
|
||||
}
|
||||
};
|
||||
}, [shouldSendInHighQuality, renderingShouldSendInHighQuality]);
|
||||
|
||||
if (!renderingAttachments) {
|
||||
return undefined;
|
||||
}
|
||||
@ -536,16 +566,24 @@ const AttachmentModal: FC<OwnProps & StateProps> = ({
|
||||
{
|
||||
!shouldForceAsFile && !shouldForceCompression && (isSendingCompressed ? (
|
||||
|
||||
<MenuItem icon="document" onClick={() => setShouldSendCompressed(false)}>
|
||||
<MenuItem icon="document" onClick={handleToggleShouldCompress}>
|
||||
{oldLang(isMultiple ? 'Attachment.SendAsFiles' : 'Attachment.SendAsFile')}
|
||||
</MenuItem>
|
||||
) : (
|
||||
|
||||
<MenuItem icon="photo" onClick={() => setShouldSendCompressed(true)}>
|
||||
<MenuItem icon="photo" onClick={handleToggleShouldCompress}>
|
||||
{isMultiple ? 'Send All as Media' : 'Send as Media'}
|
||||
</MenuItem>
|
||||
))
|
||||
}
|
||||
{isSendingCompressed && !editingMessage && hasAnyPhoto && (
|
||||
<MenuItem
|
||||
icon={renderingShouldSendInHighQuality ? 'sd-photo' : 'hd-photo'}
|
||||
onClick={handleToggleQuality}
|
||||
>
|
||||
{lang(renderingShouldSendInHighQuality ? 'SendInStandardQuality' : 'SendInHighQuality')}
|
||||
</MenuItem>
|
||||
)}
|
||||
{isSendingCompressed && hasAnySpoilerable && Boolean(!editingMessage) && (
|
||||
hasSpoiler ? (
|
||||
<MenuItem icon="spoiler-disable" onClick={handleDisableSpoilers}>
|
||||
|
||||
@ -25,7 +25,7 @@ export type OwnProps = {
|
||||
isOpen: boolean;
|
||||
withQuick?: boolean;
|
||||
onHide: NoneToVoidFunction;
|
||||
onFileSelect: (files: File[], suggestCompression?: boolean) => void;
|
||||
onFileSelect: (files: File[]) => void;
|
||||
editingMessage?: ApiMessage | undefined;
|
||||
};
|
||||
|
||||
@ -41,7 +41,7 @@ const DropArea: FC<OwnProps> = ({
|
||||
isOpen, withQuick, onHide, onFileSelect, editingMessage,
|
||||
}) => {
|
||||
const lang = useLang();
|
||||
const { showNotification } = getActions();
|
||||
const { showNotification, updateAttachmentSettings } = getActions();
|
||||
const hideTimeoutRef = useRef<number>();
|
||||
const prevWithQuick = usePreviousDeprecated(withQuick);
|
||||
const { shouldRender, transitionClassNames } = useShowTransitionDeprecated(isOpen);
|
||||
@ -78,7 +78,8 @@ const DropArea: FC<OwnProps> = ({
|
||||
}
|
||||
|
||||
onHide();
|
||||
onFileSelect(files, withQuick ? false : undefined);
|
||||
updateAttachmentSettings({ shouldCompress: withQuick ? false : undefined });
|
||||
onFileSelect(files);
|
||||
});
|
||||
|
||||
const handleQuickFilesDrop = useLastCallback(async (e: React.DragEvent<HTMLDivElement>) => {
|
||||
@ -102,7 +103,8 @@ const DropArea: FC<OwnProps> = ({
|
||||
}
|
||||
|
||||
onHide();
|
||||
onFileSelect(files, true);
|
||||
updateAttachmentSettings({ shouldCompress: true });
|
||||
onFileSelect(files);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@ -14,7 +14,8 @@ import {
|
||||
} from '../../../../util/files';
|
||||
import { scaleImage } from '../../../../util/imageResize';
|
||||
|
||||
const MAX_QUICK_IMG_SIZE = 1280; // px
|
||||
const MAX_STANDARD_QUALITY_IMG_SIZE = 1280; // px
|
||||
const MAX_HIGH_QUALITY_IMG_SIZE = 2560;
|
||||
const MAX_THUMB_IMG_SIZE = 40; // px
|
||||
const MAX_ASPECT_RATIO = 20;
|
||||
const FILE_EXT_REGEX = /\.[^/.]+$/;
|
||||
@ -28,22 +29,25 @@ export default async function buildAttachment(
|
||||
let audio;
|
||||
let previewBlobUrl;
|
||||
let shouldSendAsFile;
|
||||
const shouldSendInHighQuality = options?.shouldSendInHighQuality;
|
||||
|
||||
if (SUPPORTED_PHOTO_CONTENT_TYPES.has(mimeType)) {
|
||||
const img = await preloadImage(blobUrl);
|
||||
const { width, height } = img;
|
||||
shouldSendAsFile = !validateAspectRatio(width, height);
|
||||
|
||||
const shouldShrink = Math.max(width, height) > MAX_QUICK_IMG_SIZE;
|
||||
const maxQuickImgSize = shouldSendInHighQuality ? MAX_HIGH_QUALITY_IMG_SIZE : MAX_STANDARD_QUALITY_IMG_SIZE;
|
||||
const shouldShrink = Math.max(width, height) > maxQuickImgSize;
|
||||
const isGif = mimeType === GIF_MIME_TYPE;
|
||||
|
||||
if (!shouldSendAsFile) {
|
||||
if (!options?.compressedBlobUrl && !isGif && (shouldShrink || mimeType !== 'image/jpeg')) {
|
||||
const resizedUrl = await scaleImage(
|
||||
blobUrl, shouldShrink ? MAX_QUICK_IMG_SIZE / Math.max(width, height) : 1, 'image/jpeg',
|
||||
blobUrl, shouldShrink ? maxQuickImgSize / Math.max(width, height) : 1, 'image/jpeg',
|
||||
);
|
||||
URL.revokeObjectURL(blobUrl);
|
||||
return buildAttachment(filename, blob, {
|
||||
...options,
|
||||
compressedBlobUrl: resizedUrl,
|
||||
});
|
||||
}
|
||||
@ -88,6 +92,7 @@ export default async function buildAttachment(
|
||||
}
|
||||
|
||||
return {
|
||||
blob,
|
||||
blobUrl,
|
||||
filename,
|
||||
mimeType,
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { useState } from '../../../../lib/teact/teact';
|
||||
import { useEffect, useState } from '../../../../lib/teact/teact';
|
||||
import { getActions } from '../../../../global';
|
||||
|
||||
import type { ApiAttachment, ApiMessage } from '../../../../api/types';
|
||||
@ -22,6 +22,7 @@ export default function useAttachmentModal({
|
||||
canSendDocuments,
|
||||
insertNextText,
|
||||
editedMessage,
|
||||
shouldSendInHighQuality,
|
||||
}: {
|
||||
attachments: ApiAttachment[];
|
||||
fileSizeLimit: number;
|
||||
@ -34,12 +35,12 @@ export default function useAttachmentModal({
|
||||
canSendDocuments?: boolean;
|
||||
insertNextText: VoidFunction;
|
||||
editedMessage: ApiMessage | undefined;
|
||||
shouldSendInHighQuality?: boolean;
|
||||
}) {
|
||||
const lang = useLang();
|
||||
const { openLimitReachedModal, showAllowedMessageTypesNotification, showNotification } = getActions();
|
||||
const [shouldForceAsFile, setShouldForceAsFile] = useState<boolean>(false);
|
||||
const [shouldForceCompression, setShouldForceCompression] = useState<boolean>(false);
|
||||
const [shouldSuggestCompression, setShouldSuggestCompression] = useState<boolean | undefined>(undefined);
|
||||
|
||||
const handleClearAttachments = useLastCallback(() => {
|
||||
setAttachments(MEMO_EMPTY_ARRAY);
|
||||
@ -99,13 +100,14 @@ export default function useAttachmentModal({
|
||||
}
|
||||
} else {
|
||||
const newAttachments = await Promise.all(files.map((file) => (
|
||||
buildAttachment(file.name, file, { shouldSendAsSpoiler: isSpoiler || undefined })
|
||||
buildAttachment(file.name, file,
|
||||
{ shouldSendAsSpoiler: isSpoiler || undefined, shouldSendInHighQuality })
|
||||
)));
|
||||
handleSetAttachments([...attachments, ...newAttachments]);
|
||||
}
|
||||
});
|
||||
|
||||
const handleFileSelect = useLastCallback(async (files: File[], suggestCompression?: boolean) => {
|
||||
const handleFileSelect = useLastCallback(async (files: File[]) => {
|
||||
if (editedMessage) {
|
||||
const newAttachment = await buildAttachment(files[0].name, files[0]);
|
||||
const canReplace = editedMessage && canReplaceMessageMedia(editedMessage, newAttachment);
|
||||
@ -120,14 +122,23 @@ export default function useAttachmentModal({
|
||||
handleSetAttachments([newAttachment]);
|
||||
}
|
||||
} else {
|
||||
const newAttachments = await Promise.all(files.map((file) => buildAttachment(file.name, file)));
|
||||
const newAttachments = await Promise.all(files.map((file) =>
|
||||
buildAttachment(file.name, file, { shouldSendInHighQuality })));
|
||||
handleSetAttachments(newAttachments);
|
||||
}
|
||||
setShouldSuggestCompression(suggestCompression);
|
||||
});
|
||||
|
||||
const handleUpdateAttachmentsQuality = useLastCallback(async () => {
|
||||
const newAttachments = await Promise.all(attachments.map((attachment) =>
|
||||
buildAttachment(attachment.filename, attachment.blob, { shouldSendInHighQuality })));
|
||||
handleSetAttachments(newAttachments);
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
handleUpdateAttachmentsQuality();
|
||||
}, [shouldSendInHighQuality]);
|
||||
|
||||
return {
|
||||
shouldSuggestCompression,
|
||||
handleAppendFiles,
|
||||
handleFileSelect,
|
||||
onCaptionUpdate: setHtml,
|
||||
|
||||
@ -529,17 +529,11 @@ addActionHandler('requestWave', (global, actions, payload): ActionReturnType =>
|
||||
});
|
||||
|
||||
addActionHandler('updateAttachmentSettings', (global, actions, payload): ActionReturnType => {
|
||||
const {
|
||||
shouldCompress, shouldSendGrouped, isInvertedMedia, webPageMediaSize,
|
||||
} = payload;
|
||||
|
||||
return {
|
||||
...global,
|
||||
attachmentSettings: {
|
||||
shouldCompress: shouldCompress ?? global.attachmentSettings.shouldCompress,
|
||||
shouldSendGrouped: shouldSendGrouped ?? global.attachmentSettings.shouldSendGrouped,
|
||||
isInvertedMedia,
|
||||
webPageMediaSize,
|
||||
...global.attachmentSettings,
|
||||
...payload,
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
@ -180,6 +180,7 @@ export const INITIAL_GLOBAL_STATE: GlobalState = {
|
||||
shouldSendGrouped: true,
|
||||
isInvertedMedia: undefined,
|
||||
webPageMediaSize: undefined,
|
||||
shouldSendInHighQuality: false,
|
||||
},
|
||||
|
||||
scheduledMessages: {
|
||||
|
||||
@ -2193,6 +2193,7 @@ export interface ActionPayloads {
|
||||
shouldSendGrouped?: boolean;
|
||||
isInvertedMedia?: true;
|
||||
webPageMediaSize?: WebPageMediaSize;
|
||||
shouldSendInHighQuality?: boolean;
|
||||
};
|
||||
|
||||
saveEffectInDraft: {
|
||||
|
||||
@ -120,6 +120,7 @@ export type GlobalState = {
|
||||
shouldSendGrouped: boolean;
|
||||
isInvertedMedia?: true;
|
||||
webPageMediaSize?: WebPageMediaSize;
|
||||
shouldSendInHighQuality?: boolean;
|
||||
};
|
||||
|
||||
attachMenu: {
|
||||
|
||||
@ -140,166 +140,168 @@ $icons-map: (
|
||||
"grouped": "\f167",
|
||||
"hand-stop": "\f168",
|
||||
"hashtag": "\f169",
|
||||
"heart-outline": "\f16a",
|
||||
"heart": "\f16b",
|
||||
"help": "\f16c",
|
||||
"info-filled": "\f16d",
|
||||
"info": "\f16e",
|
||||
"install": "\f16f",
|
||||
"italic": "\f170",
|
||||
"key": "\f171",
|
||||
"keyboard": "\f172",
|
||||
"lamp": "\f173",
|
||||
"language": "\f174",
|
||||
"large-pause": "\f175",
|
||||
"large-play": "\f176",
|
||||
"link-badge": "\f177",
|
||||
"link-broken": "\f178",
|
||||
"link": "\f179",
|
||||
"location": "\f17a",
|
||||
"lock-badge": "\f17b",
|
||||
"lock": "\f17c",
|
||||
"logout": "\f17d",
|
||||
"loop": "\f17e",
|
||||
"mention": "\f17f",
|
||||
"message-failed": "\f180",
|
||||
"message-pending": "\f181",
|
||||
"message-read": "\f182",
|
||||
"message-succeeded": "\f183",
|
||||
"message": "\f184",
|
||||
"microphone-alt": "\f185",
|
||||
"microphone": "\f186",
|
||||
"monospace": "\f187",
|
||||
"more-circle": "\f188",
|
||||
"more": "\f189",
|
||||
"move-caption-down": "\f18a",
|
||||
"move-caption-up": "\f18b",
|
||||
"mute": "\f18c",
|
||||
"muted": "\f18d",
|
||||
"my-notes": "\f18e",
|
||||
"new-chat-filled": "\f18f",
|
||||
"next": "\f190",
|
||||
"nochannel": "\f191",
|
||||
"noise-suppression": "\f192",
|
||||
"non-contacts": "\f193",
|
||||
"one-filled": "\f194",
|
||||
"open-in-new-tab": "\f195",
|
||||
"password-off": "\f196",
|
||||
"pause": "\f197",
|
||||
"permissions": "\f198",
|
||||
"phone-discard-outline": "\f199",
|
||||
"phone-discard": "\f19a",
|
||||
"phone": "\f19b",
|
||||
"photo": "\f19c",
|
||||
"pin-badge": "\f19d",
|
||||
"pin-list": "\f19e",
|
||||
"pin": "\f19f",
|
||||
"pinned-chat": "\f1a0",
|
||||
"pinned-message": "\f1a1",
|
||||
"pip": "\f1a2",
|
||||
"play-story": "\f1a3",
|
||||
"play": "\f1a4",
|
||||
"poll": "\f1a5",
|
||||
"previous": "\f1a6",
|
||||
"privacy-policy": "\f1a7",
|
||||
"proof-of-ownership": "\f1a8",
|
||||
"quote-text": "\f1a9",
|
||||
"quote": "\f1aa",
|
||||
"radial-badge": "\f1ab",
|
||||
"readchats": "\f1ac",
|
||||
"recent": "\f1ad",
|
||||
"reload": "\f1ae",
|
||||
"remove-quote": "\f1af",
|
||||
"remove": "\f1b0",
|
||||
"reopen-topic": "\f1b1",
|
||||
"replace": "\f1b2",
|
||||
"replies": "\f1b3",
|
||||
"reply-filled": "\f1b4",
|
||||
"reply": "\f1b5",
|
||||
"revenue-split": "\f1b6",
|
||||
"revote": "\f1b7",
|
||||
"save-story": "\f1b8",
|
||||
"saved-messages": "\f1b9",
|
||||
"schedule": "\f1ba",
|
||||
"search": "\f1bb",
|
||||
"select": "\f1bc",
|
||||
"sell-outline": "\f1bd",
|
||||
"sell": "\f1be",
|
||||
"send-outline": "\f1bf",
|
||||
"send": "\f1c0",
|
||||
"settings-filled": "\f1c1",
|
||||
"settings": "\f1c2",
|
||||
"share-filled": "\f1c3",
|
||||
"share-screen-outlined": "\f1c4",
|
||||
"share-screen-stop": "\f1c5",
|
||||
"share-screen": "\f1c6",
|
||||
"show-message": "\f1c7",
|
||||
"sidebar": "\f1c8",
|
||||
"skip-next": "\f1c9",
|
||||
"skip-previous": "\f1ca",
|
||||
"smallscreen": "\f1cb",
|
||||
"smile": "\f1cc",
|
||||
"sort-by-date": "\f1cd",
|
||||
"sort-by-number": "\f1ce",
|
||||
"sort-by-price": "\f1cf",
|
||||
"sort": "\f1d0",
|
||||
"speaker-muted-story": "\f1d1",
|
||||
"speaker-outline": "\f1d2",
|
||||
"speaker-story": "\f1d3",
|
||||
"speaker": "\f1d4",
|
||||
"spoiler-disable": "\f1d5",
|
||||
"spoiler": "\f1d6",
|
||||
"sport": "\f1d7",
|
||||
"star": "\f1d8",
|
||||
"stars-lock": "\f1d9",
|
||||
"stats": "\f1da",
|
||||
"stealth-future": "\f1db",
|
||||
"stealth-past": "\f1dc",
|
||||
"stickers": "\f1dd",
|
||||
"stop-raising-hand": "\f1de",
|
||||
"stop": "\f1df",
|
||||
"story-caption": "\f1e0",
|
||||
"story-expired": "\f1e1",
|
||||
"story-priority": "\f1e2",
|
||||
"story-reply": "\f1e3",
|
||||
"strikethrough": "\f1e4",
|
||||
"tag-add": "\f1e5",
|
||||
"tag-crossed": "\f1e6",
|
||||
"tag-filter": "\f1e7",
|
||||
"tag-name": "\f1e8",
|
||||
"tag": "\f1e9",
|
||||
"timer": "\f1ea",
|
||||
"toncoin": "\f1eb",
|
||||
"trade": "\f1ec",
|
||||
"transcribe": "\f1ed",
|
||||
"truck": "\f1ee",
|
||||
"unarchive": "\f1ef",
|
||||
"underlined": "\f1f0",
|
||||
"unique-profile": "\f1f1",
|
||||
"unlist-outline": "\f1f2",
|
||||
"unlist": "\f1f3",
|
||||
"unlock-badge": "\f1f4",
|
||||
"unlock": "\f1f5",
|
||||
"unmute": "\f1f6",
|
||||
"unpin": "\f1f7",
|
||||
"unread": "\f1f8",
|
||||
"up": "\f1f9",
|
||||
"user-filled": "\f1fa",
|
||||
"user-online": "\f1fb",
|
||||
"user": "\f1fc",
|
||||
"video-outlined": "\f1fd",
|
||||
"video-stop": "\f1fe",
|
||||
"video": "\f1ff",
|
||||
"view-once": "\f200",
|
||||
"voice-chat": "\f201",
|
||||
"volume-1": "\f202",
|
||||
"volume-2": "\f203",
|
||||
"volume-3": "\f204",
|
||||
"web": "\f205",
|
||||
"webapp": "\f206",
|
||||
"word-wrap": "\f207",
|
||||
"zoom-in": "\f208",
|
||||
"zoom-out": "\f209",
|
||||
"hd-photo": "\f16a",
|
||||
"heart-outline": "\f16b",
|
||||
"heart": "\f16c",
|
||||
"help": "\f16d",
|
||||
"info-filled": "\f16e",
|
||||
"info": "\f16f",
|
||||
"install": "\f170",
|
||||
"italic": "\f171",
|
||||
"key": "\f172",
|
||||
"keyboard": "\f173",
|
||||
"lamp": "\f174",
|
||||
"language": "\f175",
|
||||
"large-pause": "\f176",
|
||||
"large-play": "\f177",
|
||||
"link-badge": "\f178",
|
||||
"link-broken": "\f179",
|
||||
"link": "\f17a",
|
||||
"location": "\f17b",
|
||||
"lock-badge": "\f17c",
|
||||
"lock": "\f17d",
|
||||
"logout": "\f17e",
|
||||
"loop": "\f17f",
|
||||
"mention": "\f180",
|
||||
"message-failed": "\f181",
|
||||
"message-pending": "\f182",
|
||||
"message-read": "\f183",
|
||||
"message-succeeded": "\f184",
|
||||
"message": "\f185",
|
||||
"microphone-alt": "\f186",
|
||||
"microphone": "\f187",
|
||||
"monospace": "\f188",
|
||||
"more-circle": "\f189",
|
||||
"more": "\f18a",
|
||||
"move-caption-down": "\f18b",
|
||||
"move-caption-up": "\f18c",
|
||||
"mute": "\f18d",
|
||||
"muted": "\f18e",
|
||||
"my-notes": "\f18f",
|
||||
"new-chat-filled": "\f190",
|
||||
"next": "\f191",
|
||||
"nochannel": "\f192",
|
||||
"noise-suppression": "\f193",
|
||||
"non-contacts": "\f194",
|
||||
"one-filled": "\f195",
|
||||
"open-in-new-tab": "\f196",
|
||||
"password-off": "\f197",
|
||||
"pause": "\f198",
|
||||
"permissions": "\f199",
|
||||
"phone-discard-outline": "\f19a",
|
||||
"phone-discard": "\f19b",
|
||||
"phone": "\f19c",
|
||||
"photo": "\f19d",
|
||||
"pin-badge": "\f19e",
|
||||
"pin-list": "\f19f",
|
||||
"pin": "\f1a0",
|
||||
"pinned-chat": "\f1a1",
|
||||
"pinned-message": "\f1a2",
|
||||
"pip": "\f1a3",
|
||||
"play-story": "\f1a4",
|
||||
"play": "\f1a5",
|
||||
"poll": "\f1a6",
|
||||
"previous": "\f1a7",
|
||||
"privacy-policy": "\f1a8",
|
||||
"proof-of-ownership": "\f1a9",
|
||||
"quote-text": "\f1aa",
|
||||
"quote": "\f1ab",
|
||||
"radial-badge": "\f1ac",
|
||||
"readchats": "\f1ad",
|
||||
"recent": "\f1ae",
|
||||
"reload": "\f1af",
|
||||
"remove-quote": "\f1b0",
|
||||
"remove": "\f1b1",
|
||||
"reopen-topic": "\f1b2",
|
||||
"replace": "\f1b3",
|
||||
"replies": "\f1b4",
|
||||
"reply-filled": "\f1b5",
|
||||
"reply": "\f1b6",
|
||||
"revenue-split": "\f1b7",
|
||||
"revote": "\f1b8",
|
||||
"save-story": "\f1b9",
|
||||
"saved-messages": "\f1ba",
|
||||
"schedule": "\f1bb",
|
||||
"sd-photo": "\f1bc",
|
||||
"search": "\f1bd",
|
||||
"select": "\f1be",
|
||||
"sell-outline": "\f1bf",
|
||||
"sell": "\f1c0",
|
||||
"send-outline": "\f1c1",
|
||||
"send": "\f1c2",
|
||||
"settings-filled": "\f1c3",
|
||||
"settings": "\f1c4",
|
||||
"share-filled": "\f1c5",
|
||||
"share-screen-outlined": "\f1c6",
|
||||
"share-screen-stop": "\f1c7",
|
||||
"share-screen": "\f1c8",
|
||||
"show-message": "\f1c9",
|
||||
"sidebar": "\f1ca",
|
||||
"skip-next": "\f1cb",
|
||||
"skip-previous": "\f1cc",
|
||||
"smallscreen": "\f1cd",
|
||||
"smile": "\f1ce",
|
||||
"sort-by-date": "\f1cf",
|
||||
"sort-by-number": "\f1d0",
|
||||
"sort-by-price": "\f1d1",
|
||||
"sort": "\f1d2",
|
||||
"speaker-muted-story": "\f1d3",
|
||||
"speaker-outline": "\f1d4",
|
||||
"speaker-story": "\f1d5",
|
||||
"speaker": "\f1d6",
|
||||
"spoiler-disable": "\f1d7",
|
||||
"spoiler": "\f1d8",
|
||||
"sport": "\f1d9",
|
||||
"star": "\f1da",
|
||||
"stars-lock": "\f1db",
|
||||
"stats": "\f1dc",
|
||||
"stealth-future": "\f1dd",
|
||||
"stealth-past": "\f1de",
|
||||
"stickers": "\f1df",
|
||||
"stop-raising-hand": "\f1e0",
|
||||
"stop": "\f1e1",
|
||||
"story-caption": "\f1e2",
|
||||
"story-expired": "\f1e3",
|
||||
"story-priority": "\f1e4",
|
||||
"story-reply": "\f1e5",
|
||||
"strikethrough": "\f1e6",
|
||||
"tag-add": "\f1e7",
|
||||
"tag-crossed": "\f1e8",
|
||||
"tag-filter": "\f1e9",
|
||||
"tag-name": "\f1ea",
|
||||
"tag": "\f1eb",
|
||||
"timer": "\f1ec",
|
||||
"toncoin": "\f1ed",
|
||||
"trade": "\f1ee",
|
||||
"transcribe": "\f1ef",
|
||||
"truck": "\f1f0",
|
||||
"unarchive": "\f1f1",
|
||||
"underlined": "\f1f2",
|
||||
"unique-profile": "\f1f3",
|
||||
"unlist-outline": "\f1f4",
|
||||
"unlist": "\f1f5",
|
||||
"unlock-badge": "\f1f6",
|
||||
"unlock": "\f1f7",
|
||||
"unmute": "\f1f8",
|
||||
"unpin": "\f1f9",
|
||||
"unread": "\f1fa",
|
||||
"up": "\f1fb",
|
||||
"user-filled": "\f1fc",
|
||||
"user-online": "\f1fd",
|
||||
"user": "\f1fe",
|
||||
"video-outlined": "\f1ff",
|
||||
"video-stop": "\f200",
|
||||
"video": "\f201",
|
||||
"view-once": "\f202",
|
||||
"voice-chat": "\f203",
|
||||
"volume-1": "\f204",
|
||||
"volume-2": "\f205",
|
||||
"volume-3": "\f206",
|
||||
"web": "\f207",
|
||||
"webapp": "\f208",
|
||||
"word-wrap": "\f209",
|
||||
"zoom-in": "\f20a",
|
||||
"zoom-out": "\f20b",
|
||||
);
|
||||
|
||||
.icon-active-sessions::before {
|
||||
@ -617,6 +619,9 @@ $icons-map: (
|
||||
.icon-hashtag::before {
|
||||
content: map.get($icons-map, "hashtag");
|
||||
}
|
||||
.icon-hd-photo::before {
|
||||
content: map.get($icons-map, "hd-photo");
|
||||
}
|
||||
.icon-heart-outline::before {
|
||||
content: map.get($icons-map, "heart-outline");
|
||||
}
|
||||
@ -860,6 +865,9 @@ $icons-map: (
|
||||
.icon-schedule::before {
|
||||
content: map.get($icons-map, "schedule");
|
||||
}
|
||||
.icon-sd-photo::before {
|
||||
content: map.get($icons-map, "sd-photo");
|
||||
}
|
||||
.icon-search::before {
|
||||
content: map.get($icons-map, "search");
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@ -104,6 +104,7 @@ export type FontIconName =
|
||||
| 'grouped'
|
||||
| 'hand-stop'
|
||||
| 'hashtag'
|
||||
| 'hd-photo'
|
||||
| 'heart-outline'
|
||||
| 'heart'
|
||||
| 'help'
|
||||
@ -185,6 +186,7 @@ export type FontIconName =
|
||||
| 'save-story'
|
||||
| 'saved-messages'
|
||||
| 'schedule'
|
||||
| 'sd-photo'
|
||||
| 'search'
|
||||
| 'select'
|
||||
| 'sell-outline'
|
||||
|
||||
2
src/types/language.d.ts
vendored
2
src/types/language.d.ts
vendored
@ -1530,6 +1530,8 @@ export interface LangPair {
|
||||
'ValueGiftSortByNumber': undefined;
|
||||
'ResellGiftsNoFound': undefined;
|
||||
'ResellGiftsClearFilters': undefined;
|
||||
'SendInStandardQuality': undefined;
|
||||
'SendInHighQuality': undefined;
|
||||
'MonoforumBadge': undefined;
|
||||
'MonoforumStatus': undefined;
|
||||
'MonoforumComposerPlaceholder': undefined;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user