From d97d98a524d2b2dd56c718a806eecab0b3270c88 Mon Sep 17 00:00:00 2001
From: Matthias Nott <mnott@mnsoft.org>
Date: Sat, 07 Mar 2026 14:10:48 +0100
Subject: [PATCH] fix: scroll-to-bottom on restart, keyboard avoiding in project picker

---
 components/SessionDrawer.tsx    |    7 +++++++
 components/chat/MessageList.tsx |   21 ++++++++++++++-------
 2 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/components/SessionDrawer.tsx b/components/SessionDrawer.tsx
index 8557fa0..d7a1998 100644
--- a/components/SessionDrawer.tsx
+++ b/components/SessionDrawer.tsx
@@ -9,7 +9,9 @@
   Animated,
   Dimensions,
   Keyboard,
+  KeyboardAvoidingView,
   LayoutAnimation,
+  Platform,
   Pressable,
   ScrollView,
   StyleSheet,
@@ -471,6 +473,10 @@
             elevation: 20,
           }}
         >
+          <KeyboardAvoidingView
+            style={{ flex: 1 }}
+            behavior={Platform.OS === "ios" ? "padding" : undefined}
+          >
           <GestureHandlerRootView style={{ flex: 1 }}>
             {/* Header */}
             <View
@@ -673,6 +679,7 @@
               </Text>
             </View>
           </GestureHandlerRootView>
+          </KeyboardAvoidingView>
         </Animated.View>
       </View>
     </View>
diff --git a/components/chat/MessageList.tsx b/components/chat/MessageList.tsx
index b413d2b..5ff7aea 100644
--- a/components/chat/MessageList.tsx
+++ b/components/chat/MessageList.tsx
@@ -20,14 +20,21 @@
 
   useEffect(() => {
     if (messages.length > 0) {
-      // If the message count changed by more than 1, it's a session switch or
-      // initial load — snap to bottom instantly instead of visibly scrolling.
       const delta = Math.abs(messages.length - prevLengthRef.current);
-      const animated = delta === 1;
-      const delay = delta > 1 ? 200 : 50;
-      setTimeout(() => {
-        listRef.current?.scrollToEnd({ animated });
-      }, delay);
+      if (delta > 1) {
+        // Bulk load (restart, session switch) — FlatList renders lazily,
+        // so fire multiple scroll attempts to catch late renders.
+        for (const delay of [100, 300, 700]) {
+          setTimeout(() => {
+            listRef.current?.scrollToEnd({ animated: false });
+          }, delay);
+        }
+      } else {
+        // Single new message — smooth scroll
+        setTimeout(() => {
+          listRef.current?.scrollToEnd({ animated: true });
+        }, 50);
+      }
     }
     prevLengthRef.current = messages.length;
   }, [messages.length, isTyping, lastContent]);

--
Gitblit v1.3.1