Matthias Nott
2026-03-07 d97d98a524d2b2dd56c718a806eecab0b3270c88
fix: scroll-to-bottom on restart, keyboard avoiding in project picker

- MessageList fires 3 scroll attempts (100/300/700ms) for bulk loads
to catch lazy FlatList rendering on app restart
- SessionDrawer wrapped in KeyboardAvoidingView so custom path input
stays visible when keyboard opens
2 files modified
changed files
components/SessionDrawer.tsx patch | view | blame | history
components/chat/MessageList.tsx patch | view | blame | history
components/SessionDrawer.tsx
....@@ -9,7 +9,9 @@
99 Animated,
1010 Dimensions,
1111 Keyboard,
12
+ KeyboardAvoidingView,
1213 LayoutAnimation,
14
+ Platform,
1315 Pressable,
1416 ScrollView,
1517 StyleSheet,
....@@ -471,6 +473,10 @@
471473 elevation: 20,
472474 }}
473475 >
476
+ <KeyboardAvoidingView
477
+ style={{ flex: 1 }}
478
+ behavior={Platform.OS === "ios" ? "padding" : undefined}
479
+ >
474480 <GestureHandlerRootView style={{ flex: 1 }}>
475481 {/* Header */}
476482 <View
....@@ -673,6 +679,7 @@
673679 </Text>
674680 </View>
675681 </GestureHandlerRootView>
682
+ </KeyboardAvoidingView>
676683 </Animated.View>
677684 </View>
678685 </View>
components/chat/MessageList.tsx
....@@ -20,14 +20,21 @@
2020
2121 useEffect(() => {
2222 if (messages.length > 0) {
23
- // If the message count changed by more than 1, it's a session switch or
24
- // initial load — snap to bottom instantly instead of visibly scrolling.
2523 const delta = Math.abs(messages.length - prevLengthRef.current);
26
- const animated = delta === 1;
27
- const delay = delta > 1 ? 200 : 50;
28
- setTimeout(() => {
29
- listRef.current?.scrollToEnd({ animated });
30
- }, delay);
24
+ if (delta > 1) {
25
+ // Bulk load (restart, session switch) — FlatList renders lazily,
26
+ // so fire multiple scroll attempts to catch late renders.
27
+ for (const delay of [100, 300, 700]) {
28
+ setTimeout(() => {
29
+ listRef.current?.scrollToEnd({ animated: false });
30
+ }, delay);
31
+ }
32
+ } else {
33
+ // Single new message — smooth scroll
34
+ setTimeout(() => {
35
+ listRef.current?.scrollToEnd({ animated: true });
36
+ }, 50);
37
+ }
3138 }
3239 prevLengthRef.current = messages.length;
3340 }, [messages.length, isTyping, lastContent]);