From bcb1a7ae266c4beb41dd896e11c39720eac48b9c Mon Sep 17 00:00:00 2001 From: Alexander Zinchuk Date: Mon, 25 Sep 2023 13:00:11 +0200 Subject: [PATCH] SVG: Ask before download (#3872) --- src/components/common/Document.tsx | 91 ++++++++++++++----- src/components/left/search/FileResults.tsx | 2 + .../search/helpers/createMapStateToProps.ts | 2 + src/components/middle/message/Message.tsx | 8 +- src/components/right/Profile.tsx | 4 + src/global/initialState.ts | 1 + src/types/index.ts | 1 + 7 files changed, 82 insertions(+), 27 deletions(-) diff --git a/src/components/common/Document.tsx b/src/components/common/Document.tsx index caa13d529..eeee7a972 100644 --- a/src/components/common/Document.tsx +++ b/src/components/common/Document.tsx @@ -22,10 +22,13 @@ import { getDocumentExtension, getDocumentHasPreview } from './helpers/documentI import useFlag from '../../hooks/useFlag'; import { useIsIntersecting } from '../../hooks/useIntersectionObserver'; +import useLang from '../../hooks/useLang'; import useLastCallback from '../../hooks/useLastCallback'; import useMedia from '../../hooks/useMedia'; import useMediaWithLoadProgress from '../../hooks/useMediaWithLoadProgress'; +import Checkbox from '../ui/Checkbox'; +import ConfirmDialog from '../ui/ConfirmDialog'; import File from './File'; type OwnProps = { @@ -42,12 +45,14 @@ type OwnProps = { sender?: string; autoLoadFileMaxSizeMb?: number; isDownloading?: boolean; + shouldWarnAboutSvg?: boolean; onCancelUpload?: () => void; onMediaClick?: () => void; onDateClick?: (messageId: number, chatId: string) => void; }; const BYTES_PER_MB = 1024 * 1024; +const SVG_EXTENSIONS = new Set(['svg', 'svgz']); const Document: FC = ({ message, @@ -62,16 +67,21 @@ const Document: FC = ({ sender, isSelected, isSelectable, + shouldWarnAboutSvg, + isDownloading, onCancelUpload, onMediaClick, onDateClick, - isDownloading, }) => { - const dispatch = getActions(); + const { cancelMessageMediaDownload, downloadMessageMedia, setSettingOption } = getActions(); // eslint-disable-next-line no-null/no-null const ref = useRef(null); + const lang = useLang(); + const [isSvgDialogOpen, openSvgDialog, closeSvgDialog] = useFlag(); + const [shouldNotWarnAboutSvg, setShouldNotWarnAboutSvg] = useState(false); + const document = message.content.document!; const { fileName, size, timestamp } = document; const extension = getDocumentExtension(document) || ''; @@ -110,6 +120,10 @@ const Document: FC = ({ SUPPORTED_VIDEO_CONTENT_TYPES.has(document.mimeType) || SUPPORTED_IMAGE_CONTENT_TYPES.has(document.mimeType) ); + const handleDownload = useLastCallback(() => { + downloadMessageMedia({ message }); + }); + const handleClick = useLastCallback(() => { if (isUploading) { if (onCancelUpload) { @@ -119,7 +133,7 @@ const Document: FC = ({ } if (isDownloading) { - dispatch.cancelMessageMediaDownload({ message }); + cancelMessageMediaDownload({ message }); return; } @@ -130,9 +144,21 @@ const Document: FC = ({ if (withMediaViewer) { onMediaClick!(); - } else { - dispatch.downloadMessageMedia({ message }); + return; } + + if (SVG_EXTENSIONS.has(extension) && shouldWarnAboutSvg) { + openSvgDialog(); + return; + } + + handleDownload(); + }); + + const handleSvgConfirm = useLastCallback(() => { + setSettingOption({ shouldWarnAboutSvg: !shouldNotWarnAboutSvg }); + closeSvgDialog(); + handleDownload(); }); const handleDateClick = useLastCallback(() => { @@ -140,26 +166,41 @@ const Document: FC = ({ }); return ( - + <> + + + {lang('lng_launch_svg_warning')} + + + ); }; diff --git a/src/components/left/search/FileResults.tsx b/src/components/left/search/FileResults.tsx index cfcecd472..8c632f92c 100644 --- a/src/components/left/search/FileResults.tsx +++ b/src/components/left/search/FileResults.tsx @@ -43,6 +43,7 @@ const FileResults: FC = ({ globalMessagesByChatId, foundIds, activeDownloads, + shouldWarnAboutSvg, }) => { const { searchMessagesGlobal, @@ -117,6 +118,7 @@ const FileResults: FC = ({ sender={getSenderName(lang, message, chatsById, usersById)} className="scroll-item" isDownloading={activeDownloads[message.chatId]?.ids?.includes(message.id)} + shouldWarnAboutSvg={shouldWarnAboutSvg} observeIntersection={observeIntersectionForMedia} onDateClick={handleMessageFocus} /> diff --git a/src/components/left/search/helpers/createMapStateToProps.ts b/src/components/left/search/helpers/createMapStateToProps.ts index 166367f68..6eabcfa88 100644 --- a/src/components/left/search/helpers/createMapStateToProps.ts +++ b/src/components/left/search/helpers/createMapStateToProps.ts @@ -16,6 +16,7 @@ export type StateProps = { searchChatId?: string; activeDownloads: TabState['activeDownloads']['byChatId']; isChatProtected?: boolean; + shouldWarnAboutSvg?: boolean; }; export function createMapStateToProps(type: ApiGlobalMessageSearchType) { @@ -48,6 +49,7 @@ export function createMapStateToProps(type: ApiGlobalMessageSearchType) { searchChatId: chatId, activeDownloads, isChatProtected: chatId ? selectChat(global, chatId)?.isProtected : undefined, + shouldWarnAboutSvg: global.settings.byKey.shouldWarnAboutSvg, }; }; } diff --git a/src/components/middle/message/Message.tsx b/src/components/middle/message/Message.tsx index f41f99f5e..aa7e6ea03 100644 --- a/src/components/middle/message/Message.tsx +++ b/src/components/middle/message/Message.tsx @@ -191,8 +191,8 @@ type OwnProps = appearanceOrder: number; isJustAdded: boolean; memoFirstUnreadIdRef: { current: number | undefined }; - onPinnedIntersectionChange: PinnedIntersectionChangedCallback; getIsMessageListReady: Signal; + onPinnedIntersectionChange: PinnedIntersectionChangedCallback; } & MessagePositionProperties; @@ -261,6 +261,7 @@ type StateProps = { withStickerEffects?: boolean; webPageStory?: ApiTypeStory; isConnected: boolean; + shouldWarnAboutSvg?: boolean; }; type MetaPosition = @@ -367,8 +368,9 @@ const Message: FC = ({ withStickerEffects, webPageStory, isConnected, - onPinnedIntersectionChange, getIsMessageListReady, + shouldWarnAboutSvg, + onPinnedIntersectionChange, }) => { const { toggleMessageSelection, @@ -1094,6 +1096,7 @@ const Message: FC = ({ onMediaClick={handleMediaClick} onCancelUpload={handleCancelUpload} isDownloading={isDownloading} + shouldWarnAboutSvg={shouldWarnAboutSvg} /> )} {storyData && !isStoryMention && ( @@ -1584,6 +1587,7 @@ export default memo(withGlobal( withStickerEffects: selectPerformanceSettingsValue(global, 'stickerEffects'), webPageStory, isConnected, + shouldWarnAboutSvg: global.settings.byKey.shouldWarnAboutSvg, ...((canShowSender || isLocation) && { sender }), ...(isOutgoing && { outgoingStatus: selectOutgoingStatus(global, message, messageListType === 'scheduled') }), ...(typeof uploadProgress === 'number' && { uploadProgress }), diff --git a/src/components/right/Profile.tsx b/src/components/right/Profile.tsx index 28216b5e9..168280bfa 100644 --- a/src/components/right/Profile.tsx +++ b/src/components/right/Profile.tsx @@ -112,6 +112,7 @@ type StateProps = { activeDownloadIds?: number[]; isChatProtected?: boolean; nextProfileTab?: ProfileTabType; + shouldWarnAboutSvg?: boolean; }; const TABS = [ @@ -156,6 +157,7 @@ const Profile: FC = ({ activeDownloadIds, isChatProtected, nextProfileTab, + shouldWarnAboutSvg, }) => { const { setLocalMediaSearchType, @@ -441,6 +443,7 @@ const Profile: FC = ({ isDownloading={activeDownloadIds?.includes(id)} observeIntersection={observeIntersectionForMedia} onDateClick={handleMessageFocus} + shouldWarnAboutSvg={shouldWarnAboutSvg} /> )) ) : resultType === 'links' ? ( @@ -646,6 +649,7 @@ export default memo(withGlobal( storyByIds, isChatProtected: chat?.isProtected, nextProfileTab: selectTabState(global).nextProfileTab, + shouldWarnAboutSvg: global.settings.byKey.shouldWarnAboutSvg, ...(hasMembersTab && members && { members, adminMembersById }), ...(hasCommonChatsTab && user && { commonChatIds: user.commonChats?.ids }), }; diff --git a/src/global/initialState.ts b/src/global/initialState.ts index 3c43be7b0..9cdc497e0 100644 --- a/src/global/initialState.ts +++ b/src/global/initialState.ts @@ -237,6 +237,7 @@ export const INITIAL_GLOBAL_STATE: GlobalState = { doNotTranslate: [], canDisplayChatInTitle: true, shouldAllowHttpTransport: true, + shouldWarnAboutSvg: true, }, themes: { light: { diff --git a/src/types/index.ts b/src/types/index.ts index c82b6576f..a58eb22e2 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -107,6 +107,7 @@ export interface ISettings extends NotifySettings, Record { shouldAllowHttpTransport?: boolean; shouldCollectDebugLogs?: boolean; shouldDebugExportedSenders?: boolean; + shouldWarnAboutSvg?: boolean; } export interface ApiPrivacySettings {