import type { FC } from '../../../lib/teact/teact'; import React, { memo, useEffect, useMemo, } from '../../../lib/teact/teact'; import type { ApiAttachMenuPeerType, ApiMessage } from '../../../api/types'; import type { GlobalState } from '../../../global/types'; import type { ISettings, ThreadId } from '../../../types'; import { CONTENT_TYPES_WITH_PREVIEW, DEBUG_LOG_FILENAME, SUPPORTED_AUDIO_CONTENT_TYPES, SUPPORTED_PHOTO_CONTENT_TYPES, SUPPORTED_VIDEO_CONTENT_TYPES, } from '../../../config'; import { getMessageAudio, getMessageDocument, getMessagePhoto, getMessageVideo, getMessageVoice, getMessageWebPagePhoto, getMessageWebPageVideo, } from '../../../global/helpers'; import { getDebugLogs } from '../../../util/debugConsole'; import { validateFiles } from '../../../util/files'; import { openSystemFilesDialog } from '../../../util/systemFilesDialog'; import { IS_TOUCH_ENV } from '../../../util/windowEnvironment'; import useFlag from '../../../hooks/useFlag'; import useLastCallback from '../../../hooks/useLastCallback'; import useMouseInside from '../../../hooks/useMouseInside'; import useOldLang from '../../../hooks/useOldLang'; import Icon from '../../common/icons/Icon'; import Menu from '../../ui/Menu'; import MenuItem from '../../ui/MenuItem'; import ResponsiveHoverButton from '../../ui/ResponsiveHoverButton'; import AttachBotItem from './AttachBotItem'; import './AttachMenu.scss'; export type OwnProps = { chatId: string; threadId?: ThreadId; isButtonVisible: boolean; canAttachMedia: boolean; canAttachPolls: boolean; canSendPhotos: boolean; canSendVideos: boolean; canSendDocuments: boolean; canSendAudios: boolean; isScheduled?: boolean; attachBots?: GlobalState['attachMenu']['bots']; peerType?: ApiAttachMenuPeerType; shouldCollectDebugLogs?: boolean; theme: ISettings['theme']; onFileSelect: (files: File[], shouldSuggestCompression?: boolean) => void; onPollCreate: NoneToVoidFunction; onMenuOpen: NoneToVoidFunction; onMenuClose: NoneToVoidFunction; canEditMedia?: boolean; editingMessage?: ApiMessage; }; const AttachMenu: FC = ({ chatId, threadId, isButtonVisible, canAttachMedia, canAttachPolls, canSendPhotos, canSendVideos, canSendDocuments, canSendAudios, attachBots, peerType, isScheduled, theme, shouldCollectDebugLogs, onFileSelect, onMenuOpen, onMenuClose, onPollCreate, canEditMedia, editingMessage, }) => { const [isAttachMenuOpen, openAttachMenu, closeAttachMenu] = useFlag(); const [handleMouseEnter, handleMouseLeave, markMouseInside] = useMouseInside(isAttachMenuOpen, closeAttachMenu); const canSendVideoAndPhoto = canSendPhotos && canSendVideos; const canSendVideoOrPhoto = canSendPhotos || canSendVideos; const [isAttachmentBotMenuOpen, markAttachmentBotMenuOpen, unmarkAttachmentBotMenuOpen] = useFlag(); const isMenuOpen = isAttachMenuOpen || isAttachmentBotMenuOpen; const isPhotoOrVideo = editingMessage && editingMessage?.groupedId && Boolean(getMessagePhoto(editingMessage) || getMessageWebPagePhoto(editingMessage) || Boolean(getMessageVideo(editingMessage) || getMessageWebPageVideo(editingMessage))); const isFile = editingMessage && editingMessage?.groupedId && Boolean(getMessageAudio(editingMessage) || getMessageVoice(editingMessage) || getMessageDocument(editingMessage)); useEffect(() => { if (isAttachMenuOpen) { markMouseInside(); } }, [isAttachMenuOpen, markMouseInside]); useEffect(() => { if (isMenuOpen) { onMenuOpen(); } else { onMenuClose(); } }, [isMenuOpen, onMenuClose, onMenuOpen]); const handleToggleAttachMenu = useLastCallback(() => { if (isAttachMenuOpen) { closeAttachMenu(); } else { openAttachMenu(); } }); const handleFileSelect = useLastCallback((e: Event, shouldSuggestCompression?: boolean) => { const { files } = e.target as HTMLInputElement; const validatedFiles = validateFiles(files); if (validatedFiles?.length) { onFileSelect(validatedFiles, shouldSuggestCompression); } }); const handleQuickSelect = useLastCallback(() => { openSystemFilesDialog( Array.from(canSendVideoAndPhoto ? CONTENT_TYPES_WITH_PREVIEW : ( canSendPhotos ? SUPPORTED_PHOTO_CONTENT_TYPES : SUPPORTED_VIDEO_CONTENT_TYPES )).join(','), (e) => handleFileSelect(e, true), ); }); const handleDocumentSelect = useLastCallback(() => { openSystemFilesDialog(!canSendDocuments && canSendAudios ? Array.from(SUPPORTED_AUDIO_CONTENT_TYPES).join(',') : ( '*' ), (e) => handleFileSelect(e, false)); }); const handleSendLogs = useLastCallback(() => { const file = new File([getDebugLogs()], DEBUG_LOG_FILENAME, { type: 'text/plain' }); onFileSelect([file]); }); const bots = useMemo(() => { return attachBots ? Object.values(attachBots).filter((bot) => { if (!peerType || !bot.isForAttachMenu) return false; if (peerType === 'bots' && bot.id === chatId && bot.attachMenuPeerTypes.includes('self')) { return true; } return bot.attachMenuPeerTypes!.includes(peerType); }) : undefined; }, [attachBots, chatId, peerType]); const lang = useOldLang(); if (!isButtonVisible) { return undefined; } return (
{ editingMessage && canEditMedia ? ( ) : ( ) } {/* ** Using ternary operator here causes some attributes from first clause ** transferring to the fragment content in the second clause */} {!canAttachMedia && ( Posting media content is not allowed in this group. )} {canAttachMedia && ( <> {canSendVideoOrPhoto && !isFile && ( {lang(canSendVideoAndPhoto ? 'AttachmentMenu.PhotoOrVideo' : (canSendPhotos ? 'InputAttach.Popover.Photo' : 'InputAttach.Popover.Video'))} )} {((canSendDocuments || canSendAudios) && !isPhotoOrVideo) && ( {lang(!canSendDocuments && canSendAudios ? 'InputAttach.Popover.Music' : 'AttachDocument')} )} {canSendDocuments && shouldCollectDebugLogs && ( {lang('DebugSendLogs')} )} )} {canAttachPolls && !editingMessage && ( {lang('Poll')} )} {!editingMessage && !canEditMedia && !isScheduled && bots?.map((bot) => ( ))}
); }; export default memo(AttachMenu);