diff --git a/apps/mobile/src/features/threads/ThreadDetailScreen.tsx b/apps/mobile/src/features/threads/ThreadDetailScreen.tsx index 6961f7428724..b079dd7ebaee 100644 --- a/apps/mobile/src/features/threads/ThreadDetailScreen.tsx +++ b/apps/mobile/src/features/threads/ThreadDetailScreen.tsx @@ -530,22 +530,22 @@ export const ThreadDetailScreen = function ThreadDetailScreen(props: ThreadDetai const selectedThreadKeyRef = useRef(selectedThreadKey); const lastScrolledSubmittedMessageIdRef = useRef(null); const [composerExpanded, setComposerExpanded] = useState(false); - const [composerFocused, setComposerFocused] = useState(false); - const handleComposerFocusChange = (focused: boolean) => { - setComposerFocused(focused); - handleOwnedInputFocusChange(focused); - }; const [anchorMessageId, setAnchorMessageId] = useState(null); const [submittedMessageId, setSubmittedMessageId] = useState(null); const [endFollowEnabled, setEndFollowEnabled] = useState(true); // Android Back hides the keyboard without blurring. Keep its safe-area padding // fixed through the animation and cancel it with matching composer/list offsets. const bottomBarInset = useDuoBottomBarInset(); + // The pill already adds its own gutter; iPad and Duo align its edge with the native bar. + const alignedBottomInset = + bottomBarInset ?? + (Platform.OS === "ios" && Platform.isPad ? Math.max(insets.bottom, 12) : undefined); + // A hardware keyboard can focus the editor without occupying any screen height. const composerBottomInset = - Platform.OS === "ios" && (composerExpanded || composerFocused) + Platform.OS === "ios" && (composerExpanded || liveKeyboardHeight > 0) ? 0 - : bottomBarInset !== undefined - ? bottomBarInset - THREAD_COMPOSER_BOTTOM_GUTTER + : alignedBottomInset !== undefined + ? Math.max(0, alignedBottomInset - THREAD_COMPOSER_BOTTOM_GUTTER) : Math.max(insets.bottom, 12); const composerKeyboardOffset = Platform.OS === "android" ? composerBottomInset : 0; const contentPresentationKind = props.contentPresentation.kind; @@ -1088,9 +1088,7 @@ export const ThreadDetailScreen = function ThreadDetailScreen(props: ThreadDetai useLayoutEffect(() => { selectedThreadKeyRef.current = selectedThreadKey; - // A replaced or unmounted native editor may not emit a blur event. - setComposerFocused(false); - }, [selectedThreadKey, showContent]); + }, [selectedThreadKey]); useEffect(() => { setAnchorMessageId(null); @@ -1665,7 +1663,7 @@ export const ThreadDetailScreen = function ThreadDetailScreen(props: ThreadDetai onUpdateRuntimeMode={props.onUpdateThreadRuntimeMode} onUpdateInteractionMode={props.onUpdateThreadInteractionMode} onExpandedChange={setComposerExpanded} - onEditorFocusChange={handleComposerFocusChange} + onEditorFocusChange={handleOwnedInputFocusChange} /> )}