| ... | @@ -17,7 +17,11 @@ import type { | ... | @@ -17,7 +17,11 @@ import type { |
| 17 | import * as Haptics from "expo-haptics"; | 17 | import * as Haptics from "expo-haptics"; |
| 18 | import { memo, useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react"; | 18 | import { memo, useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react"; |
| 19 | import { Platform, View, type GestureResponderEvent } from "react-native"; | 19 | import { Platform, View, type GestureResponderEvent } from "react-native"; |
| 20 | import { KeyboardController, KeyboardStickyView } from "react-native-keyboard-controller"; | 20 | import { |
| | 21 | KeyboardController, |
| | 22 | KeyboardStickyView, |
| | 23 | useKeyboardState, |
| | 24 | } from "react-native-keyboard-controller"; |
| 21 | import Animated, { FadeInDown, FadeOut } from "react-native-reanimated"; | 25 | import Animated, { FadeInDown, FadeOut } from "react-native-reanimated"; |
| 22 | import { useSafeAreaInsets } from "react-native-safe-area-context"; | 26 | import { useSafeAreaInsets } from "react-native-safe-area-context"; |
| 23 | | 27 | |
| ... | @@ -183,7 +187,11 @@ export const ThreadDetailScreen = memo(function ThreadDetailScreen(props: Thread | ... | @@ -183,7 +187,11 @@ export const ThreadDetailScreen = memo(function ThreadDetailScreen(props: Thread |
| 183 | const lastScrolledAnchorMessageIdRef = useRef<MessageId | null>(null); | 187 | const lastScrolledAnchorMessageIdRef = useRef<MessageId | null>(null); |
| 184 | const [composerExpanded, setComposerExpanded] = useState(false); | 188 | const [composerExpanded, setComposerExpanded] = useState(false); |
| 185 | const [anchorMessageId, setAnchorMessageId] = useState<MessageId | null>(null); | 189 | 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); |
| 187 | const contentPresentationKind = props.contentPresentation.kind; | 195 | const contentPresentationKind = props.contentPresentation.kind; |
| 188 | // The raw sync status enters "synchronizing" on every full fetch, cached or | 196 | // The raw sync status enters "synchronizing" on every full fetch, cached or |
| 189 | // not. Whether messages are already on screen decides the pill label: no | 197 | // not. Whether messages are already on screen decides the pill label: no |