mirror of
https://github.com/getpaseo/paseo.git
synced 2026-07-29 12:01:31 +00:00
fix(keyboard): use transform instead of padding for keyboard animation
This commit is contained in:
@@ -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() {
|
||||
<BackHeader title={agent.title || "Agent"} />
|
||||
|
||||
{/* Content Area with Keyboard Animation */}
|
||||
<ReanimatedAnimated.View style={[styles.content, animatedKeyboardStyle]}>
|
||||
{isInitializing ? (
|
||||
<View style={styles.loadingContainer}>
|
||||
<ActivityIndicator size="large" color={theme.colors.primary} />
|
||||
<Text style={styles.loadingText}>Loading agent...</Text>
|
||||
</View>
|
||||
) : (
|
||||
<AgentStreamView
|
||||
agentId={id!}
|
||||
agent={agent}
|
||||
streamItems={streamItems}
|
||||
pendingPermissions={agentPermissions}
|
||||
onPermissionResponse={(requestId, optionId) =>
|
||||
respondToPermission(requestId, id!, agent.sessionId || "", [optionId])
|
||||
}
|
||||
keyboardHeight={keyboardHeight}
|
||||
/>
|
||||
)}
|
||||
</ReanimatedAnimated.View>
|
||||
<View style={styles.contentContainer}>
|
||||
<ReanimatedAnimated.View style={[styles.content, animatedKeyboardStyle]}>
|
||||
{isInitializing ? (
|
||||
<View style={styles.loadingContainer}>
|
||||
<ActivityIndicator size="large" color={theme.colors.primary} />
|
||||
<Text style={styles.loadingText}>Loading agent...</Text>
|
||||
</View>
|
||||
) : (
|
||||
<AgentStreamView
|
||||
agentId={id!}
|
||||
agent={agent}
|
||||
streamItems={streamItems}
|
||||
pendingPermissions={agentPermissions}
|
||||
onPermissionResponse={(requestId, optionId) =>
|
||||
respondToPermission(requestId, id!, agent.sessionId || "", [optionId])
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</ReanimatedAnimated.View>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
@@ -109,6 +115,10 @@ const styles = StyleSheet.create((theme) => ({
|
||||
flex: 1,
|
||||
backgroundColor: theme.colors.background,
|
||||
},
|
||||
contentContainer: {
|
||||
flex: 1,
|
||||
overflow: "hidden",
|
||||
},
|
||||
content: {
|
||||
flex: 1,
|
||||
},
|
||||
|
||||
@@ -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<string, PendingPermission>;
|
||||
onPermissionResponse: (requestId: string, optionId: string) => void;
|
||||
keyboardHeight: SharedValue<number>;
|
||||
}
|
||||
|
||||
export function AgentStreamView({
|
||||
@@ -34,7 +33,6 @@ export function AgentStreamView({
|
||||
streamItems,
|
||||
pendingPermissions,
|
||||
onPermissionResponse,
|
||||
keyboardHeight,
|
||||
}: AgentStreamViewProps) {
|
||||
const scrollViewRef = useRef<ScrollView>(null);
|
||||
const bottomSheetRef = useRef<BottomSheetModal | null>(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({
|
||||
<ScrollView
|
||||
ref={scrollViewRef}
|
||||
style={stylesheet.scrollView}
|
||||
contentContainerStyle={[
|
||||
{
|
||||
paddingTop: 24,
|
||||
},
|
||||
contentPaddingStyle,
|
||||
]}
|
||||
contentContainerStyle={{
|
||||
paddingTop: 24,
|
||||
paddingBottom: Math.max(insets.bottom, 32),
|
||||
}}
|
||||
onScroll={handleScroll}
|
||||
scrollEventThrottle={16}
|
||||
>
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
]
|
||||
Reference in New Issue
Block a user