// Copyright 2022 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only import React, { useEffect, useState } from 'react'; import { get, has } from 'lodash'; import type { AttachmentType, InMemoryAttachmentDraftType, } from '../types/Attachment'; import type { LinkPreviewSourceType } from '../types/LinkPreview'; import type { LinkPreviewType } from '../types/message/LinkPreviews'; import type { LocalizerType } from '../types/Util'; import type { Props as StickerButtonProps } from './stickers/StickerButton'; import type { PropsType as SendStoryModalPropsType } from './SendStoryModal'; import type { UUIDStringType } from '../types/UUID'; import { IMAGE_JPEG, TEXT_ATTACHMENT } from '../types/MIME'; import { isVideoAttachment } from '../types/Attachment'; import { SendStoryModal } from './SendStoryModal'; import { MediaEditor } from './MediaEditor'; import { TextStoryCreator } from './TextStoryCreator'; import type { SmartCompositionTextAreaProps } from '../state/smart/CompositionTextArea'; export type PropsType = { debouncedMaybeGrabLinkPreview: ( message: string, source: LinkPreviewSourceType ) => unknown; file?: File; i18n: LocalizerType; linkPreview?: LinkPreviewType; onClose: () => unknown; onSend: ( listIds: Array, conversationIds: Array, attachment: AttachmentType ) => unknown; processAttachment: ( file: File ) => Promise; renderCompositionTextArea: ( props: SmartCompositionTextAreaProps ) => JSX.Element; sendStoryModalOpenStateChanged: (isOpen: boolean) => unknown; } & Pick & Pick< SendStoryModalPropsType, | 'candidateConversations' | 'distributionLists' | 'getPreferredBadge' | 'groupConversations' | 'groupStories' | 'hasFirstStoryPostExperience' | 'me' | 'onDeleteList' | 'onDistributionListCreated' | 'onHideMyStoriesFrom' | 'onRemoveMember' | 'onRepliesNReactionsChanged' | 'onSelectedStoryList' | 'onViewersUpdated' | 'setMyStoriesToAllSignalConnections' | 'signalConnections' | 'toggleGroupsForStorySend' | 'toggleSignalConnectionsModal' >; export const StoryCreator = ({ candidateConversations, debouncedMaybeGrabLinkPreview, distributionLists, file, getPreferredBadge, groupConversations, groupStories, hasFirstStoryPostExperience, i18n, installedPacks, linkPreview, me, onClose, onDeleteList, onDistributionListCreated, onHideMyStoriesFrom, onRemoveMember, onRepliesNReactionsChanged, onSelectedStoryList, onSend, onViewersUpdated, processAttachment, recentStickers, renderCompositionTextArea, sendStoryModalOpenStateChanged, setMyStoriesToAllSignalConnections, signalConnections, toggleGroupsForStorySend, toggleSignalConnectionsModal, }: PropsType): JSX.Element => { const [draftAttachment, setDraftAttachment] = useState< AttachmentType | undefined >(); const [attachmentUrl, setAttachmentUrl] = useState(); useEffect(() => { let url: string | undefined; let unmounted = false; async function loadAttachment(): Promise { if (!file || unmounted) { return; } const attachment = await processAttachment(file); if (!attachment || unmounted) { return; } if (isVideoAttachment(attachment)) { setDraftAttachment(attachment); } else if (attachment && has(attachment, 'data')) { url = URL.createObjectURL(new Blob([get(attachment, 'data')])); setAttachmentUrl(url); } } loadAttachment(); return () => { unmounted = true; if (url) { URL.revokeObjectURL(url); } }; }, [file, processAttachment]); useEffect(() => { sendStoryModalOpenStateChanged(Boolean(draftAttachment)); }, [draftAttachment, sendStoryModalOpenStateChanged]); return ( <> {draftAttachment && ( setDraftAttachment(undefined)} onDeleteList={onDeleteList} onDistributionListCreated={onDistributionListCreated} onHideMyStoriesFrom={onHideMyStoriesFrom} onRemoveMember={onRemoveMember} onRepliesNReactionsChanged={onRepliesNReactionsChanged} onSelectedStoryList={onSelectedStoryList} onSend={(listIds, groupIds) => { onSend(listIds, groupIds, draftAttachment); setDraftAttachment(undefined); onClose(); }} onViewersUpdated={onViewersUpdated} setMyStoriesToAllSignalConnections={ setMyStoriesToAllSignalConnections } signalConnections={signalConnections} toggleGroupsForStorySend={toggleGroupsForStorySend} toggleSignalConnectionsModal={toggleSignalConnectionsModal} /> )} {attachmentUrl && ( { setDraftAttachment({ contentType: IMAGE_JPEG, data, size: data.byteLength, caption, }); }} recentStickers={recentStickers} /> )} {!file && ( { setDraftAttachment({ contentType: TEXT_ATTACHMENT, textAttachment, size: textAttachment.text?.length || 0, }); }} /> )} ); };