fix(mobile): replace KeyboardAvoidingView with Keyboard API listener
KeyboardAvoidingView was causing two issues: scrolling the page to the top on focus, and not restoring the layout when dismissing the keyboard. New approach uses Keyboard.addListener to track keyboard height and applies it as paddingBottom on the message bar directly. This works reliably on both iOS and Android regardless of softInputMode. - Removed softwareKeyboardLayoutMode: "pan" from app.json - Replaced KAV with plain View + dynamic keyboard padding - Reverted SpawnSession/Settings screens to simple iOS-only KAV Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
a685565bbb
commit
ba2053dd4c
|
|
@ -30,8 +30,7 @@
|
|||
"foregroundImage": "./assets/adaptive-icon.png",
|
||||
"backgroundColor": "#0d1117"
|
||||
},
|
||||
"package": "com.composio.aomobile",
|
||||
"softwareKeyboardLayoutMode": "pan"
|
||||
"package": "com.composio.aomobile"
|
||||
},
|
||||
"web": {
|
||||
"favicon": "./assets/favicon.png"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React, { useState, useCallback, useRef } from "react";
|
||||
import React, { useState, useCallback, useRef, useEffect } from "react";
|
||||
import {
|
||||
View,
|
||||
Text,
|
||||
|
|
@ -8,7 +8,7 @@ import {
|
|||
TouchableOpacity,
|
||||
Alert,
|
||||
ActivityIndicator,
|
||||
KeyboardAvoidingView,
|
||||
Keyboard,
|
||||
Platform,
|
||||
Linking,
|
||||
} from "react-native";
|
||||
|
|
@ -43,6 +43,24 @@ export default function SessionDetailScreen({ route, navigation }: Props) {
|
|||
const [ciFixState, setCiFixState] = useState<ActionButtonState>("idle");
|
||||
const [commentFixStates, setCommentFixStates] = useState<Record<string, ActionButtonState>>({});
|
||||
const scrollRef = useRef<ScrollView>(null);
|
||||
const [keyboardHeight, setKeyboardHeight] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
const showEvent = Platform.OS === "ios" ? "keyboardWillShow" : "keyboardDidShow";
|
||||
const hideEvent = Platform.OS === "ios" ? "keyboardWillHide" : "keyboardDidHide";
|
||||
|
||||
const showSub = Keyboard.addListener(showEvent, (e) => {
|
||||
setKeyboardHeight(e.endCoordinates.height);
|
||||
});
|
||||
const hideSub = Keyboard.addListener(hideEvent, () => {
|
||||
setKeyboardHeight(0);
|
||||
});
|
||||
|
||||
return () => {
|
||||
showSub.remove();
|
||||
hideSub.remove();
|
||||
};
|
||||
}, []);
|
||||
|
||||
const handleSend = useCallback(async () => {
|
||||
if (!message.trim()) return;
|
||||
|
|
@ -162,11 +180,7 @@ export default function SessionDetailScreen({ route, navigation }: Props) {
|
|||
const unresolvedComments = pr?.unresolvedComments ?? [];
|
||||
|
||||
return (
|
||||
<KeyboardAvoidingView
|
||||
style={styles.root}
|
||||
behavior="padding"
|
||||
keyboardVerticalOffset={Platform.OS === "ios" ? 88 : 140}
|
||||
>
|
||||
<View style={styles.root}>
|
||||
<ScrollView ref={scrollRef} style={styles.container} contentContainerStyle={styles.content} keyboardShouldPersistTaps="handled">
|
||||
{/* Header row */}
|
||||
<View style={[styles.headerCard, { borderLeftColor: color }]}>
|
||||
|
|
@ -336,7 +350,7 @@ export default function SessionDetailScreen({ route, navigation }: Props) {
|
|||
|
||||
{/* Message input — only show for active sessions */}
|
||||
{!isDone && (
|
||||
<View style={styles.messageBar}>
|
||||
<View style={[styles.messageBar, { paddingBottom: keyboardHeight > 0 ? keyboardHeight - (Platform.OS === "ios" ? 34 : 0) : 10 }]}>
|
||||
<TextInput
|
||||
style={styles.messageInput}
|
||||
placeholder="Send message to agent..."
|
||||
|
|
@ -347,9 +361,6 @@ export default function SessionDetailScreen({ route, navigation }: Props) {
|
|||
returnKeyType="send"
|
||||
onSubmitEditing={handleSend}
|
||||
blurOnSubmit={false}
|
||||
onFocus={() => {
|
||||
setTimeout(() => scrollRef.current?.scrollToEnd({ animated: true }), 300);
|
||||
}}
|
||||
/>
|
||||
<TouchableOpacity
|
||||
style={[styles.sendButton, (!message.trim() || sending) && styles.sendButtonDisabled]}
|
||||
|
|
@ -364,7 +375,7 @@ export default function SessionDetailScreen({ route, navigation }: Props) {
|
|||
</TouchableOpacity>
|
||||
</View>
|
||||
)}
|
||||
</KeyboardAvoidingView>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -132,8 +132,7 @@ export default function SettingsScreen({ navigation }: Props) {
|
|||
return (
|
||||
<KeyboardAvoidingView
|
||||
style={styles.root}
|
||||
behavior="padding"
|
||||
keyboardVerticalOffset={Platform.OS === "ios" ? 88 : 140}
|
||||
behavior={Platform.OS === "ios" ? "padding" : undefined}
|
||||
>
|
||||
<ScrollView style={styles.container} contentContainerStyle={styles.content}>
|
||||
<View style={styles.section}>
|
||||
|
|
|
|||
|
|
@ -52,8 +52,7 @@ export default function SpawnSessionScreen({ navigation }: Props) {
|
|||
return (
|
||||
<KeyboardAvoidingView
|
||||
style={styles.root}
|
||||
behavior="padding"
|
||||
keyboardVerticalOffset={Platform.OS === "ios" ? 88 : 140}
|
||||
behavior={Platform.OS === "ios" ? "padding" : undefined}
|
||||
>
|
||||
<ScrollView style={styles.container} contentContainerStyle={styles.content}>
|
||||
<View style={styles.section}>
|
||||
|
|
|
|||
Loading…
Reference in New Issue