From cf7e14e36b0e231347f77dd244c1b23e3fc77899 Mon Sep 17 00:00:00 2001 From: Mohamed Boudra Date: Sun, 26 Oct 2025 16:19:30 +0100 Subject: [PATCH] fix(keyboard): use transform instead of padding for keyboard animation --- packages/app/src/app/agent/[id].tsx | 56 +++++++++++-------- .../app/src/components/agent-stream-view.tsx | 25 ++------- packages/server/agents.json | 4 +- 3 files changed, 40 insertions(+), 45 deletions(-) diff --git a/packages/app/src/app/agent/[id].tsx b/packages/app/src/app/agent/[id].tsx index 3fe5d7f5e..7201106d1 100644 --- a/packages/app/src/app/agent/[id].tsx +++ b/packages/app/src/app/agent/[id].tsx @@ -3,7 +3,7 @@ import { View, Text, ActivityIndicator } from "react-native"; import { useLocalSearchParams } from "expo-router"; import { useSafeAreaInsets } from "react-native-safe-area-context"; import { useReanimatedKeyboardAnimation } from "react-native-keyboard-controller"; -import ReanimatedAnimated, { useAnimatedStyle } from "react-native-reanimated"; +import ReanimatedAnimated, { useAnimatedStyle, useSharedValue } from "react-native-reanimated"; import { StyleSheet, useUnistyles } from "react-native-unistyles"; import { BackHeader } from "@/components/headers/back-header"; import { AgentStreamView } from "@/components/agent-stream-view"; @@ -20,13 +20,18 @@ export default function AgentScreen() { // Keyboard animation const { height: keyboardHeight } = useReanimatedKeyboardAnimation(); - const bottomInset = insets.bottom; + const bottomInset = useSharedValue(insets.bottom); + + useEffect(() => { + bottomInset.value = insets.bottom; + }, [insets.bottom, bottomInset]); + const animatedKeyboardStyle = useAnimatedStyle(() => { "worklet"; const absoluteHeight = Math.abs(keyboardHeight.value); - const padding = Math.max(0, absoluteHeight - bottomInset); + const shift = Math.max(0, absoluteHeight - bottomInset.value); return { - paddingBottom: padding, + transform: [{ translateY: -shift }], }; }); @@ -81,25 +86,26 @@ export default function AgentScreen() { {/* Content Area with Keyboard Animation */} - - {isInitializing ? ( - - - Loading agent... - - ) : ( - - respondToPermission(requestId, id!, agent.sessionId || "", [optionId]) - } - keyboardHeight={keyboardHeight} - /> - )} - + + + {isInitializing ? ( + + + Loading agent... + + ) : ( + + respondToPermission(requestId, id!, agent.sessionId || "", [optionId]) + } + /> + )} + + ); } @@ -109,6 +115,10 @@ const styles = StyleSheet.create((theme) => ({ flex: 1, backgroundColor: theme.colors.background, }, + contentContainer: { + flex: 1, + overflow: "hidden", + }, content: { flex: 1, }, diff --git a/packages/app/src/components/agent-stream-view.tsx b/packages/app/src/components/agent-stream-view.tsx index 49466e1bf..552bb7fbe 100644 --- a/packages/app/src/components/agent-stream-view.tsx +++ b/packages/app/src/components/agent-stream-view.tsx @@ -3,7 +3,7 @@ import { View, Text, ScrollView, Pressable } from "react-native"; import { useSafeAreaInsets } from "react-native-safe-area-context"; import { StyleSheet, useUnistyles } from "react-native-unistyles"; import { BottomSheetModal } from "@gorhom/bottom-sheet"; -import Animated, { FadeIn, FadeOut, useAnimatedStyle, SharedValue } from "react-native-reanimated"; +import Animated, { FadeIn, FadeOut } from "react-native-reanimated"; import { ChevronDown } from "lucide-react-native"; import { AssistantMessage, @@ -25,7 +25,6 @@ export interface AgentStreamViewProps { streamItems: StreamItem[]; pendingPermissions: Map; onPermissionResponse: (requestId: string, optionId: string) => void; - keyboardHeight: SharedValue; } export function AgentStreamView({ @@ -34,7 +33,6 @@ export function AgentStreamView({ streamItems, pendingPermissions, onPermissionResponse, - keyboardHeight, }: AgentStreamViewProps) { const scrollViewRef = useRef(null); const bottomSheetRef = useRef(null); @@ -44,17 +42,6 @@ export function AgentStreamView({ const [isNearBottom, setIsNearBottom] = useState(true); const hasScrolledInitially = useRef(false); - // Animated content padding that responds to keyboard - const contentPaddingStyle = useAnimatedStyle(() => { - "worklet"; - const absoluteHeight = Math.abs(keyboardHeight.value); - const keyboardPadding = Math.max(0, absoluteHeight - insets.bottom); - const basePadding = Math.max(insets.bottom, 32); - return { - paddingBottom: basePadding + keyboardPadding, - }; - }, [insets.bottom]); - // Scroll to bottom immediately on initial load, then animate for new messages useEffect(() => { if (isNearBottom) { @@ -95,12 +82,10 @@ export function AgentStreamView({ diff --git a/packages/server/agents.json b/packages/server/agents.json index 1d53d7bb9..99430e83f 100644 --- a/packages/server/agents.json +++ b/packages/server/agents.json @@ -374,13 +374,13 @@ { "id": "97423777-33d3-414a-ae79-ea303230010a", "title": "Commit Local Changes", - "sessionId": "019a20d4-5fd4-76db-8021-697b8204597e", + "sessionId": "addbd42f-dbb1-4536-bc2b-e70a64587de6", "options": { "type": "claude", "sessionId": "addbd42f-dbb1-4536-bc2b-e70a64587de6" }, "createdAt": "2025-10-26T14:02:59.844Z", - "lastActivityAt": "2025-10-26T14:03:22.696Z", + "lastActivityAt": "2025-10-26T14:08:58.462Z", "cwd": "/Users/moboudra/dev/voice-dev" } ] \ No newline at end of file