From 6159cd7777e7847367eff57c1c48474802230211 Mon Sep 17 00:00:00 2001 From: DS Boyce <260543580+ds-boyce@users.noreply.github.com> Date: Fri, 22 May 2026 13:57:19 -0700 Subject: [PATCH] Add loading state to message composer and input (#10595) --- .../Messages/components/MessageComposer.tsx | 25 +++++++++++--- .../Messages/components/MessageInput.tsx | 33 ++++++++++++------- 2 files changed, 43 insertions(+), 15 deletions(-) diff --git a/src/screens/Messages/components/MessageComposer.tsx b/src/screens/Messages/components/MessageComposer.tsx index 8433da2ffd..b486ceddc7 100644 --- a/src/screens/Messages/components/MessageComposer.tsx +++ b/src/screens/Messages/components/MessageComposer.tsx @@ -32,6 +32,7 @@ import * as EmojiPicker from '#/components/EmojiPicker' import {GlassView} from '#/components/GlassView' import {EmojiArc_Stroke2_Corner0_Rounded as EmojiSmileIcon} from '#/components/icons/Emoji' import {PaperPlaneVertical_Filled_Stroke2_Corner1_Rounded as PaperPlaneIcon} from '#/components/icons/PaperPlane' +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' @@ -43,18 +44,20 @@ export function MessageComposer({ hasEmbed, setEmbed, children, + loading = false, }: { textInputId?: string onSendMessage: (message: string) => void hasEmbed: boolean setEmbed: (embedUrl: string | undefined) => void children?: React.ReactNode + loading?: boolean }) { const t = useTheme() const {t: l} = useLingui() const playHaptic = useHaptics() const {needsEmailVerification} = useEmail() - const editable = !needsEmailVerification + const editable = !needsEmailVerification && !loading const {getDraft, clearDraft} = useMessageDraft() const composerInternalApiRef = useComposerInternalApiRef() @@ -209,7 +212,11 @@ export function MessageComposer({ - + @@ -248,9 +259,11 @@ export function MessageComposer({ function SubmitButton({ onPress, disabled, + loading, }: { onPress: () => void disabled: boolean + loading: boolean }) { const {t: l} = useLingui() const t = useTheme() @@ -279,7 +292,11 @@ function SubmitButton({ ]} onPress={onPress} disabled={disabled}> - + {loading ? ( + + ) : ( + + )} ) diff --git a/src/screens/Messages/components/MessageInput.tsx b/src/screens/Messages/components/MessageInput.tsx index f52bbbeb43..dbe716efb1 100644 --- a/src/screens/Messages/components/MessageInput.tsx +++ b/src/screens/Messages/components/MessageInput.tsx @@ -28,6 +28,7 @@ import { import {atoms as a, platform, tokens, useTheme} from '#/alf' import {GlassView} from '#/components/GlassView' import {PaperPlaneVertical_Filled_Stroke2_Corner1_Rounded as PaperPlaneIcon} from '#/components/icons/PaperPlane' +import {Loader} from '#/components/Loader' import * as Toast from '#/components/Toast' import {IS_ANDROID, IS_IOS, IS_WEB} from '#/env' import {ComposerContainer} from './MessageComposer' @@ -43,12 +44,14 @@ export function MessageInput({ hasEmbed, setEmbed, children, + loading = false, }: { textInputId?: string onSendMessage: (message: string) => Promise | void hasEmbed: boolean setEmbed: (embedUrl: string | undefined) => void children?: React.ReactNode + loading?: boolean }) { const {t: l} = useLingui() const t = useTheme() @@ -67,12 +70,13 @@ export function MessageInput({ const [shouldEnforceClear, setShouldEnforceClear] = useState(false) const {needsEmailVerification} = useEmail() + const editable = !needsEmailVerification && !loading useSaveMessageDraft(message) useExtractEmbedFromFacets(message, setEmbed) const onSubmit = useCallback(() => { - if (needsEmailVerification) { + if (!editable) { return } if (!hasEmbed && message.trim() === '') { @@ -103,7 +107,7 @@ export function MessageInput({ void onSendMessage(message) }) }, [ - needsEmailVerification, + editable, hasEmbed, message, clearDraft, @@ -139,8 +143,7 @@ export function MessageInput({ scrollEnabled: isInputScrollable.get(), })) - const submitDisabled = - needsEmailVerification || (!hasEmbed && message.trim().length === 0) + const submitDisabled = !editable || (!hasEmbed && message.trim().length === 0) const blur = useCallback(() => { inputRef.current?.blur() @@ -209,7 +212,7 @@ export function MessageInput({ ref={inputRef} hitSlop={HITSLOP_10} animatedProps={animatedProps} - editable={!needsEmailVerification} + editable={editable} /> - + {loading ? ( + + ) : ( + + )}