authorgravatar for paul.trinko95@gmail.comPavlo Trinko <paul.trinko95@gmail.com> 2026-08-11 02:31:00+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-08-10 20:31:00-04:00
loge5c82d79a09e010d1a87c715f405635f8c45f1f7
treeeb265948369ce7f2b56fb6c044f602e3cdf1bd83
parent9afef94a61466422128da9c3b723b633d4c7ed1d
signature Signed by PGP key B5690EEEBB952194

fix(mobile): keep chat composer above the Android gesture bar (#5988)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>

1 files changed, 10 insertions(+), 2 deletions(-)

apps/mobile/src/features/threads/ThreadDetailScreen.tsx+10-2
......@@ -17,7 +17,11 @@ import type {
1717import * as Haptics from "expo-haptics";
1818import { memo, useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
1919import { Platform, View, type GestureResponderEvent } from "react-native";
20import { KeyboardController, KeyboardStickyView } from "react-native-keyboard-controller";
20import {
21 KeyboardController,
22 KeyboardStickyView,
23 useKeyboardState,
24} from "react-native-keyboard-controller";
2125import Animated, { FadeInDown, FadeOut } from "react-native-reanimated";
2226import { useSafeAreaInsets } from "react-native-safe-area-context";
2327
......@@ -183,7 +187,11 @@ export const ThreadDetailScreen = memo(function ThreadDetailScreen(props: Thread
183187 const lastScrolledAnchorMessageIdRef = useRef<MessageId | null>(null);
184188 const [composerExpanded, setComposerExpanded] = useState(false);
185189 const [anchorMessageId, setAnchorMessageId] = useState<MessageId | null>(null);
186 const composerBottomInset = composerExpanded ? 0 : Math.max(insets.bottom, 12);
190 // Key the safe-area padding on keyboard visibility, not focus: on Android
191 // the back gesture closes the keyboard while the editor stays focused, and
192 // a focus-keyed inset would leave the toolbar under the gesture bar.
193 const isKeyboardVisible = useKeyboardState((state) => state.isVisible);
194 const composerBottomInset = isKeyboardVisible ? 0 : Math.max(insets.bottom, 12);
187195 const contentPresentationKind = props.contentPresentation.kind;
188196 // The raw sync status enters "synchronizing" on every full fetch, cached or
189197 // not. Whether messages are already on screen decides the pill label: no