From b3de8fdc8f908056e2e5136f96bec130c21fc096 Mon Sep 17 00:00:00 2001 From: maria-rcks Date: Mon, 19 Oct 2026 00:26:36 +0000 Subject: [PATCH 1/2] fix(mobile): lock the composer while queued edits save --- .../src/features/threads/ThreadComposer.tsx | 32 ++++++++++++------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/apps/mobile/src/features/threads/ThreadComposer.tsx b/apps/mobile/src/features/threads/ThreadComposer.tsx index 2a95b632587a..de37c91c6b0c 100644 --- a/apps/mobile/src/features/threads/ThreadComposer.tsx +++ b/apps/mobile/src/features/threads/ThreadComposer.tsx @@ -460,6 +460,7 @@ export const ThreadComposer = function ThreadComposer(props: ThreadComposerProps onChangeDraftMessage: (text) => setComposerDraftText(composerDraftKey, text), onChangeSelection: composerMenu.onSelectionChange, }); + const isSubmissionLocked = queuedEdit?.saving === true || voiceInput.blocksSubmission; const voicePresentation = resolveVoiceComposerPresentation( voiceInput.state, voiceInput.elapsedSeconds, @@ -485,7 +486,7 @@ export const ThreadComposer = function ThreadComposer(props: ThreadComposerProps (props.canOperateThread || props.connectionState !== "connected") && hasContent && !contextImports[composerDraftKey] && - !voiceInput.blocksSubmission && + !isSubmissionLocked && sendBlockedReason === null && !modelUnavailable; @@ -536,7 +537,7 @@ export const ThreadComposer = function ThreadComposer(props: ThreadComposerProps onEditorFocusChange?.(false); }; const handleSend = async (followUp?: ActiveTurnComposerAction) => { - if (voiceInput.blocksSubmission || pendingPastedTextAttachmentCountRef.current > 0) return; + if (isSubmissionLocked || pendingPastedTextAttachmentCountRef.current > 0) return; if (usageLimitsOffered && isUsageLimitsCommand(draftMessage) && draftAttachments.length === 0) { if (openUsageLimits()) onChangeDraftMessage(""); return; @@ -671,7 +672,7 @@ export const ThreadComposer = function ThreadComposer(props: ThreadComposerProps className="relative w-full self-center" style={{ maxWidth: props.contentMaxWidth }} > - {!voiceInput.isBusy && + {!isSubmissionLocked && composerMenu.trigger && (composerMenu.items.length > 0 || composerMenu.trigger.kind === "pull-request") ? ( @@ -736,6 +737,7 @@ export const ThreadComposer = function ThreadComposer(props: ThreadComposerProps > {!isExpanded ? ( @@ -766,11 +768,11 @@ export const ThreadComposer = function ThreadComposer(props: ThreadComposerProps undefined : props.onRemoveDraftImage} - onPressPreview={voiceInput.isBusy ? undefined : onPressPreview} - onPressVideo={voiceInput.isBusy ? undefined : onPressVideo} + onRemove={isSubmissionLocked ? () => undefined : props.onRemoveDraftImage} + onPressPreview={isSubmissionLocked ? undefined : onPressPreview} + onPressVideo={isSubmissionLocked ? undefined : onPressVideo} onPressDocument={ - voiceInput.isBusy + isSubmissionLocked ? undefined : (attachment) => openDraftDocument({ @@ -804,13 +806,18 @@ export const ThreadComposer = function ThreadComposer(props: ThreadComposerProps ref={inputRef} multiline value={draftMessage} - readOnly={voiceInput.freezesEditor} + readOnly={isSubmissionLocked} skills={composerMenu.skills} selection={composerMenu.selection} - onChangeText={props.onChangeDraftMessage} + onChangeText={(text) => { + if (!isSubmissionLocked) props.onChangeDraftMessage(text); + }} onSelectionChange={composerMenu.onSelectionChange} - onPasteImages={(uris) => void props.onNativePasteImages(uris)} + onPasteImages={(uris) => { + if (!isSubmissionLocked) void props.onNativePasteImages(uris); + }} onPasteText={(paste) => { + if (isSubmissionLocked) return; const insertPaste = () => { const insertion = replaceTextSelection({ value: paste.value, @@ -944,6 +951,7 @@ export const ThreadComposer = function ThreadComposer(props: ThreadComposerProps @@ -1009,6 +1017,7 @@ export const ThreadComposer = function ThreadComposer(props: ThreadComposerProps ) : ( Date: Tue, 20 Oct 2026 20:55:38 +0000 Subject: [PATCH 2/2] fix(mobile): collapsed attachment thumbnails respect the submission lock --- apps/mobile/src/features/threads/ThreadComposer.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/mobile/src/features/threads/ThreadComposer.tsx b/apps/mobile/src/features/threads/ThreadComposer.tsx index ab366f9120c9..8dd57c328bd4 100644 --- a/apps/mobile/src/features/threads/ThreadComposer.tsx +++ b/apps/mobile/src/features/threads/ThreadComposer.tsx @@ -1052,8 +1052,8 @@ export const ThreadComposer = function ThreadComposer(props: ThreadComposerProps size={30} borderRadius={8} compact - onPressPreview={onPressPreview} - onPressVideo={onPressVideo} + onPressPreview={isSubmissionLocked ? undefined : onPressPreview} + onPressVideo={isSubmissionLocked ? undefined : onPressVideo} /> ))} {stripAttachments.length > 3 ? (