diff --git a/src/screens/Messages/components/MessageComposer.tsx b/src/screens/Messages/components/MessageComposer.tsx index 926a3cccca..6cdc756bb3 100644 --- a/src/screens/Messages/components/MessageComposer.tsx +++ b/src/screens/Messages/components/MessageComposer.tsx @@ -37,13 +37,14 @@ import {PaperPlaneVertical_Filled_Stroke2_Corner1_Rounded as PaperPlaneIcon} fro import {Loader} from '#/components/Loader' import * as Toast from '#/components/Toast' import {IS_ANDROID, IS_IOS, IS_LIQUID_GLASS, IS_NATIVE, IS_WEB} from '#/env' +import {type MessageEmbedState} from './MessageInputEmbed' const MIN_HEIGHT = 40 export function MessageComposer({ textInputId, onSendMessage, - hasEmbed, + messageEmbed, setEmbed, children, loading = false, @@ -51,9 +52,10 @@ export function MessageComposer({ textInputId?: string onSendMessage: ( message: string, + embed?: MessageEmbedState, replyTo?: $Typed, ) => void - hasEmbed: boolean + messageEmbed: MessageEmbedState | undefined setEmbed: (embedUrl: string | undefined) => void children?: React.ReactNode loading?: boolean @@ -89,14 +91,16 @@ export function MessageComposer({ }, }) - const submitDisabled = !editable || (!hasEmbed && text.trim().length === 0) + const submitDisabled = + !editable || (!messageEmbed && text.trim().length === 0) const onSubmit = ( message: string, + embed: MessageEmbedState | undefined, replyTo: ChatBskyConvoDefs.MessageView | null, ) => { if (!editable) return - if (!hasEmbed && message.trim() === '') return + if (!embed && message.trim() === '') return const graphemeCount = countGraphemes(message) if (graphemeCount > MAX_DM_GRAPHEME_LENGTH) { Toast.show( @@ -120,6 +124,7 @@ export function MessageComposer({ requestAnimationFrame(() => { onSendMessage( message, + embed, replyTo ? { ...replyTo, @@ -152,18 +157,18 @@ export function MessageComposer({ setTimeout(() => { if (isFlushingAutocorrectSuggestion.current) { isFlushingAutocorrectSuggestion.current = false - onSubmit(text, replyTo) + onSubmit(text, messageEmbed, replyTo) } }, 20) } else { - onSubmit(text, replyTo) + onSubmit(text, messageEmbed, replyTo) } } const handleChange = (nextText: string) => { if (IS_IOS && isFlushingAutocorrectSuggestion.current) { isFlushingAutocorrectSuggestion.current = false - onSubmit(nextText, replyTo) + onSubmit(nextText, messageEmbed, replyTo) } else { setText(nextText) } diff --git a/src/screens/Messages/components/MessageInput.tsx b/src/screens/Messages/components/MessageInput.tsx index cbd47151d7..441fd75fa4 100644 --- a/src/screens/Messages/components/MessageInput.tsx +++ b/src/screens/Messages/components/MessageInput.tsx @@ -34,7 +34,10 @@ import {Loader} from '#/components/Loader' import * as Toast from '#/components/Toast' import {IS_ANDROID, IS_IOS, IS_WEB} from '#/env' import {ComposerContainer} from './MessageComposer' -import {useExtractEmbedFromFacets} from './MessageInputEmbed' +import { + type MessageEmbedState, + useExtractEmbedFromFacets, +} from './MessageInputEmbed' const AnimatedTextInput = Animated.createAnimatedComponent(TextInput) @@ -43,7 +46,7 @@ const MIN_HEIGHT = 40 export function MessageInput({ textInputId, onSendMessage, - hasEmbed, + messageEmbed, setEmbed, children, loading = false, @@ -51,9 +54,10 @@ export function MessageInput({ textInputId?: string onSendMessage: ( message: string, + embed?: MessageEmbedState, replyTo?: $Typed, ) => Promise | void - hasEmbed: boolean + messageEmbed: MessageEmbedState | undefined setEmbed: (embedUrl: string | undefined) => void children?: React.ReactNode loading?: boolean @@ -85,7 +89,7 @@ export function MessageInput({ if (!editable) { return } - if (!hasEmbed && message.trim() === '') { + if (!messageEmbed && message.trim() === '') { return } if (countGraphemes(message) > MAX_DM_GRAPHEME_LENGTH) { @@ -96,6 +100,8 @@ export function MessageInput({ } clearDraft() playHaptic() + // Capture the embed before clearing - the deferred send below reads it. + const embed = messageEmbed setEmbed(undefined) setMessage('') // Capture the reply before clearing - the deferred send below reads it. @@ -115,6 +121,7 @@ export function MessageInput({ requestAnimationFrame(() => { void onSendMessage( message, + embed, reply ? {...reply, $type: 'chat.bsky.convo.defs#messageView'} : undefined, @@ -122,7 +129,7 @@ export function MessageInput({ }) }, [ editable, - hasEmbed, + messageEmbed, message, clearDraft, onSendMessage, @@ -159,7 +166,8 @@ export function MessageInput({ scrollEnabled: isInputScrollable.get(), })) - const submitDisabled = !editable || (!hasEmbed && message.trim().length === 0) + const submitDisabled = + !editable || (!messageEmbed && message.trim().length === 0) const blur = useCallback(() => { inputRef.current?.blur() diff --git a/src/screens/Messages/components/MessageInput.web.tsx b/src/screens/Messages/components/MessageInput.web.tsx index 2fe3d86fa1..6142528f85 100644 --- a/src/screens/Messages/components/MessageInput.web.tsx +++ b/src/screens/Messages/components/MessageInput.web.tsx @@ -21,20 +21,24 @@ import {EmojiArc_Stroke2_Corner0_Rounded as EmojiSmile} from '#/components/icons import {PaperPlane_Stroke2_Corner0_Rounded as PaperPlane} from '#/components/icons/PaperPlane' import * as Toast from '#/components/Toast' import {IS_WEB_SAFARI, IS_WEB_TOUCH_DEVICE} from '#/env' -import {useExtractEmbedFromFacets} from './MessageInputEmbed' +import { + type MessageEmbedState, + useExtractEmbedFromFacets, +} from './MessageInputEmbed' export function MessageInput({ onSendMessage, - hasEmbed, + messageEmbed, setEmbed, children, loading = false, }: { onSendMessage: ( message: string, + embed?: MessageEmbedState, replyTo?: $Typed, ) => void - hasEmbed: boolean + messageEmbed: MessageEmbedState | undefined setEmbed: (embedUrl: string | undefined) => void children?: React.ReactNode loading?: boolean @@ -54,7 +58,7 @@ export function MessageInput({ const textAreaRef = useRef(null) const onSubmit = useCallback(() => { - if (!hasEmbed && message.trim() === '') { + if (!messageEmbed && message.trim() === '') { return } if (countGraphemes(message) > MAX_DM_GRAPHEME_LENGTH) { @@ -66,6 +70,7 @@ export function MessageInput({ clearDraft() onSendMessage( message, + messageEmbed, replyTo ? {...replyTo, $type: 'chat.bsky.convo.defs#messageView'} : undefined, @@ -78,7 +83,7 @@ export function MessageInput({ onSendMessage, l, clearDraft, - hasEmbed, + messageEmbed, setEmbed, replyTo, clearReply, diff --git a/src/screens/Messages/components/MessagesList.tsx b/src/screens/Messages/components/MessagesList.tsx index be8ebcb8a9..8fbfa88e04 100644 --- a/src/screens/Messages/components/MessagesList.tsx +++ b/src/screens/Messages/components/MessagesList.tsx @@ -378,7 +378,11 @@ export function MessagesList({ // -- Message sending const onSendMessage = useCallback( - async (text: string, reply?: $Typed) => { + async ( + text: string, + embedState?: MessageEmbedState, + reply?: $Typed, + ) => { let rt = new RichText({text: text.trimEnd()}, {cleanNewlines: true}) // detect facets without resolution first - this is used to see if there's @@ -416,9 +420,9 @@ export function MessagesList({ } } - if (messageEmbed?.type === 'post') { + if (embedState?.type === 'post') { try { - const post = await getPost({uri: messageEmbed.uri}) + const post = await getPost({uri: embedState.uri}) if (post) { embed = { $type: 'app.bsky.embed.record', @@ -445,8 +449,8 @@ export function MessagesList({ } catch (error) { logger.error('Failed to get post as quote for DM', {error}) } - } else if (messageEmbed?.type === 'invite') { - const code = messageEmbed.code + } else if (embedState?.type === 'invite') { + const code = embedState.code embed = { $type: 'chat.bsky.embed.joinLink', code, @@ -512,7 +516,6 @@ export function MessagesList({ [ agent, convoState, - messageEmbed, getPost, getJoinLinkPreview, hasSession, @@ -737,6 +740,7 @@ function Composer({ textInputId: string onSendMessage: ( message: string, + embed?: MessageEmbedState, replyTo?: $Typed, ) => Promise messageEmbed: MessageEmbedState | undefined @@ -745,8 +749,12 @@ function Composer({ useNewComposer: boolean }) { const handleSendMessage = useNonReactiveCallback( - (message: string, replyTo?: $Typed) => { - void onSendMessage(message, replyTo) + ( + message: string, + embed?: MessageEmbedState, + replyTo?: $Typed, + ) => { + void onSendMessage(message, embed, replyTo) }, ) @@ -761,7 +769,7 @@ function Composer({ {previews} @@ -770,7 +778,7 @@ function Composer({ {previews}