diff --git a/apps/mobile/src/features/threads/ThreadFeed.tsx b/apps/mobile/src/features/threads/ThreadFeed.tsx index 33a57859ff8b3..cd9700e22fbda 100644 --- a/apps/mobile/src/features/threads/ThreadFeed.tsx +++ b/apps/mobile/src/features/threads/ThreadFeed.tsx @@ -124,6 +124,7 @@ import { useWindowDimensions, View, } from "react-native"; +import { KeyboardController } from "react-native-keyboard-controller"; import { Image as ExpoImage } from "expo-image"; import { useResolveClassNames } from "uniwind"; import { useFilePreviewGallery, FilePreviewGallery } from "../../components/FilePreviewGallery"; @@ -2761,6 +2762,9 @@ export const ThreadFeed = memo(function ThreadFeed({ } }; const handleScrollBeginDrag = () => { + if (Platform.OS === "android") { + void KeyboardController.dismiss(); + } clearUserScrollSettle(); userScrollSessionRef.current = true; cancelReflow(); @@ -3302,7 +3306,7 @@ export const ThreadFeed = memo(function ThreadFeed({ onItemSizeChanged={handleItemSizeChanged} drawDistance={500} keyboardShouldPersistTaps="always" - keyboardDismissMode="none" + keyboardDismissMode={Platform.OS === "ios" ? "interactive" : "on-drag"} keyboardLiftBehavior="whenAtEnd" // Seed viewport size to skip programmatic attach-time positioning, which races UIKit's adjustedContentInset. {...(viewportHeight > 0 && viewportWidth > 0 diff --git a/apps/mobile/src/lib/filePreview.test.ts b/apps/mobile/src/lib/filePreview.test.ts index 97a5051577026..e7bb9baad2a37 100644 --- a/apps/mobile/src/lib/filePreview.test.ts +++ b/apps/mobile/src/lib/filePreview.test.ts @@ -99,6 +99,9 @@ vi.mock("react-native", () => ({ props.children, ), })); +vi.mock("react-native-keyboard-controller", () => ({ + KeyboardController: { dismiss: vi.fn(async () => {}) }, +})); vi.mock("../components/PierreEntryIcon", () => ({ PierreEntryIcon: () => null })); vi.mock("../components/ui/AppText", () => ({ AppText: ({ children }: { children?: ReactNode }) => createElement("span", null, children),