import React, { memo, useCallback, useMemo, } from '../../lib/teact/teact'; import { getActions, withGlobal } from '../../global'; import type { FC } from '../../lib/teact/teact'; import type { ApiMessage, ApiPhoto, ApiChat, ApiUser, } from '../../api/types'; import type { MessageListType } from '../../global/types'; import type { MenuItemProps } from '../ui/MenuItem'; import { selectIsDownloading, selectIsMessageProtected, selectAllowedMessageActions, selectCurrentMessageList, selectIsChatProtected, } from '../../global/selectors'; import { getMessageMediaFormat, getMessageMediaHash, isUserId } from '../../global/helpers'; import useLang from '../../hooks/useLang'; import useMediaWithLoadProgress from '../../hooks/useMediaWithLoadProgress'; import useFlag from '../../hooks/useFlag'; import useAppLayout from '../../hooks/useAppLayout'; import useZoomChange from './hooks/useZoomChangeSignal'; import Button from '../ui/Button'; import DropdownMenu from '../ui/DropdownMenu'; import MenuItem from '../ui/MenuItem'; import ProgressSpinner from '../ui/ProgressSpinner'; import DeleteMessageModal from '../common/DeleteMessageModal'; import DeleteProfilePhotoModal from '../common/DeleteProfilePhotoModal'; import './MediaViewerActions.scss'; type StateProps = { isDownloading: boolean; isProtected?: boolean; isChatProtected?: boolean; canDelete?: boolean; canUpdate?: boolean; messageListType?: MessageListType; avatarOwnerId?: string; }; type OwnProps = { mediaData?: string; isVideo: boolean; message?: ApiMessage; canUpdateMedia?: boolean; isSingleMedia?: boolean; avatarPhoto?: ApiPhoto; avatarOwner?: ApiChat | ApiUser; fileName?: string; canReport?: boolean; selectMedia: (mediaId?: number) => void; onReport: NoneToVoidFunction; onBeforeDelete: NoneToVoidFunction; onCloseMediaViewer: NoneToVoidFunction; onForward: NoneToVoidFunction; }; const MediaViewerActions: FC = ({ mediaData, isVideo, message, avatarPhoto, avatarOwnerId, fileName, isChatProtected, isDownloading, isProtected, canReport, canDelete, canUpdate, messageListType, selectMedia, onReport, onCloseMediaViewer, onBeforeDelete, onForward, }) => { const [isDeleteModalOpen, openDeleteModal, closeDeleteModal] = useFlag(false); const [getZoomChange, setZoomChange] = useZoomChange(); const { isMobile } = useAppLayout(); const { downloadMessageMedia, cancelMessageMediaDownload, updateProfilePhoto, updateChatPhoto, } = getActions(); const { loadProgress: downloadProgress } = useMediaWithLoadProgress( message && getMessageMediaHash(message, 'download'), !isDownloading, message && getMessageMediaFormat(message, 'download'), ); const handleDownloadClick = useCallback(() => { if (isDownloading) { cancelMessageMediaDownload({ message: message! }); } else { downloadMessageMedia({ message: message! }); } }, [cancelMessageMediaDownload, downloadMessageMedia, isDownloading, message]); const handleZoomOut = useCallback(() => { const zoomChange = getZoomChange(); const change = zoomChange < 0 ? zoomChange : 0; setZoomChange(change - 1); }, [getZoomChange, setZoomChange]); const handleZoomIn = useCallback(() => { const zoomChange = getZoomChange(); const change = zoomChange > 0 ? zoomChange : 0; setZoomChange(change + 1); }, [getZoomChange, setZoomChange]); const handleUpdate = useCallback(() => { if (!avatarPhoto || !avatarOwnerId) return; if (isUserId(avatarOwnerId)) { updateProfilePhoto({ photo: avatarPhoto }); } else { updateChatPhoto({ chatId: avatarOwnerId, photo: avatarPhoto }); } selectMedia(0); }, [avatarPhoto, avatarOwnerId, selectMedia, updateProfilePhoto, updateChatPhoto]); const lang = useLang(); const MenuButton: FC<{ onTrigger: () => void; isOpen?: boolean }> = useMemo(() => { return ({ onTrigger, isOpen }) => ( ); }, []); function renderDeleteModals() { return message ? ( ) : (avatarOwnerId && avatarPhoto) ? ( ) : undefined; } function renderDownloadButton() { if (isProtected) { return undefined; } return isVideo ? ( ) : ( ); } if (isMobile) { const menuItems: MenuItemProps[] = []; if (!message?.isForwardingAllowed && !isChatProtected) { menuItems.push({ icon: 'forward', onClick: onForward, children: lang('Forward'), }); } if (!isProtected) { if (isVideo) { menuItems.push({ icon: isDownloading ? 'cancel' : 'download', onClick: handleDownloadClick, children: isDownloading ? `${Math.round(downloadProgress * 100)}% Downloading...` : 'Download', }); } else { menuItems.push({ icon: 'download', href: mediaData, download: fileName, children: lang('AccActionDownload'), }); } } if (canReport) { menuItems.push({ icon: 'report', onClick: onReport, children: lang('ReportPeer.Report'), }); } if (canUpdate) { menuItems.push({ icon: 'copy-media', onClick: handleUpdate, children: lang('ProfilePhoto.SetMainPhoto'), }); } if (canDelete) { menuItems.push({ icon: 'delete', onClick: openDeleteModal, children: lang('Delete'), }); } if (menuItems.length === 0) { return undefined; } return (
{menuItems.map(({ icon, onClick, href, download, children, }) => ( {children} ))} {isDownloading && } {canDelete && renderDeleteModals()}
); } return (
{message?.isForwardingAllowed && !isChatProtected && ( )} {renderDownloadButton()} {canReport && ( )} {canUpdate && ( )} {canDelete && ( )} {canDelete && renderDeleteModals()}
); }; export default memo(withGlobal( (global, { message, canUpdateMedia, avatarPhoto, avatarOwner, }): StateProps => { const currentMessageList = selectCurrentMessageList(global); const { threadId } = selectCurrentMessageList(global) || {}; const isDownloading = message ? selectIsDownloading(global, message) : false; const isProtected = selectIsMessageProtected(global, message); const isChatProtected = message && selectIsChatProtected(global, message?.chatId); const { canDelete: canDeleteMessage } = (threadId && message && selectAllowedMessageActions(global, message, threadId)) || {}; const isCurrentAvatar = avatarPhoto && (avatarPhoto.id === avatarOwner?.avatarHash); const canDeleteAvatar = canUpdateMedia && !!avatarPhoto; const canDelete = canDeleteMessage || canDeleteAvatar; const canUpdate = canUpdateMedia && !!avatarPhoto && !isCurrentAvatar; const messageListType = currentMessageList?.type; return { isDownloading, isProtected, isChatProtected, canDelete, canUpdate, messageListType, avatarOwnerId: avatarOwner?.id, }; }, )(MediaViewerActions));