From 32ede5388bb6c66c5d5679c2d73fd6ec6b2342bf Mon Sep 17 00:00:00 2001
From: Matthias Nott <mnott@mnsoft.org>
Date: Sun, 15 Mar 2026 13:43:18 +0100
Subject: [PATCH] Update splash screen config and add session unread indicator

---
 app.json                     |    7 +++
 components/SessionDrawer.tsx |   55 +++++++++++++++++++++------
 components/SessionPicker.tsx |   11 +++++
 3 files changed, 59 insertions(+), 14 deletions(-)

diff --git a/app.json b/app.json
index ef9c6c9..678d8d4 100644
--- a/app.json
+++ b/app.json
@@ -9,7 +9,7 @@
     "newArchEnabled": true,
     "scheme": "pailot",
     "splash": {
-      "image": "./assets/splash-icon.png",
+      "image": "./assets/icon.png",
       "resizeMode": "contain",
       "backgroundColor": "#0A0A0F"
     },
@@ -45,6 +45,11 @@
       "bundler": "metro"
     },
     "plugins": [
+      ["expo-splash-screen", {
+        "image": "./assets/icon.png",
+        "backgroundColor": "#0A0A0F",
+        "imageWidth": 200
+      }],
       "expo-router",
       [
         "expo-audio",
diff --git a/components/SessionDrawer.tsx b/components/SessionDrawer.tsx
index be58cef..9d8d8d7 100644
--- a/components/SessionDrawer.tsx
+++ b/components/SessionDrawer.tsx
@@ -44,6 +44,7 @@
 function SessionRow({
   session,
   unreadCount,
+  isUnread,
   onSwitch,
   onLongPress,
   onDelete,
@@ -53,6 +54,7 @@
 }: {
   session: WsSession;
   unreadCount: number;
+  isUnread: boolean;
   onSwitch: () => void;
   onLongPress: () => void;
   onDelete: () => void;
@@ -152,16 +154,32 @@
 
             {/* Name + subtitle — middle */}
             <View style={{ flex: 1, marginLeft: 14 }}>
-              <Text
-                style={{
-                  color: session.isActive ? colors.accent : colors.text,
-                  fontSize: 17,
-                  fontWeight: session.isActive ? "700" : "600",
-                }}
-                numberOfLines={1}
-              >
-                {session.name}
-              </Text>
+              <View style={{ flexDirection: "row", alignItems: "center" }}>
+                <Text
+                  style={{
+                    color: session.isActive ? colors.accent : colors.text,
+                    fontSize: 17,
+                    fontWeight: session.isActive ? "700" : "600",
+                    flexShrink: 1,
+                  }}
+                  numberOfLines={1}
+                >
+                  {session.name}
+                </Text>
+                {/* Server-pushed unread dot — shown when the server signals new activity */}
+                {isUnread && unreadCount === 0 && (
+                  <View
+                    style={{
+                      width: 8,
+                      height: 8,
+                      borderRadius: 4,
+                      backgroundColor: colors.accent,
+                      marginLeft: 6,
+                      flexShrink: 0,
+                    }}
+                  />
+                )}
+              </View>
               <Text
                 style={{
                   color: colors.textMuted,
@@ -266,6 +284,7 @@
     fetchProjects,
     projects,
     unreadCounts,
+    unreadSessions,
   } = useChat();
   const { colors } = useTheme();
   const [editingId, setEditingId] = useState<string | null>(null);
@@ -276,6 +295,7 @@
   const [rendered, setRendered] = useState(false);
   const [keyboardHeight, setKeyboardHeight] = useState(0);
   const pickerScrollRef = useRef<ScrollView>(null);
+  const listRef = useRef<DraggableFlatList<WsSession>>(null);
 
   useEffect(() => {
     const showSub = Keyboard.addListener("keyboardWillShow", (e) => {
@@ -361,7 +381,16 @@
   const handleStartRename = useCallback((session: WsSession) => {
     Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
     setEditingId(session.id);
-  }, []);
+    // Scroll to the item after keyboard appears so it's visible
+    const idx = orderedSessions.findIndex(s => s.id === session.id);
+    if (idx >= 0 && listRef.current) {
+      setTimeout(() => {
+        try {
+          (listRef.current as any)?.scrollToIndex({ index: idx, animated: true, viewPosition: 0.3 });
+        } catch { /* ignore if index out of range */ }
+      }, 400);
+    }
+  }, [orderedSessions]);
 
   const handleConfirmRename = useCallback(
     (sessionId: string, newName: string) => {
@@ -414,6 +443,7 @@
           <SessionRow
             session={item}
             unreadCount={unreadCounts[item.id] ?? 0}
+            isUnread={unreadSessions.has(item.id)}
             onSwitch={() => handleSwitch(item)}
             onLongPress={() => handleStartRename(item)}
             onDelete={() => handleRemove(item)}
@@ -424,7 +454,7 @@
         </ScaleDecorator>
       );
     },
-    [editingId, unreadCounts, colors, handleSwitch, handleStartRename, handleRemove, handleConfirmRename],
+    [editingId, unreadCounts, unreadSessions, colors, handleSwitch, handleStartRename, handleRemove, handleConfirmRename],
   );
 
   const keyExtractor = useCallback((item: WsSession) => item.id, []);
@@ -537,6 +567,7 @@
               </View>
             ) : (
               <DraggableFlatList
+                ref={listRef}
                 data={orderedSessions}
                 keyExtractor={keyExtractor}
                 renderItem={renderItem}
diff --git a/components/SessionPicker.tsx b/components/SessionPicker.tsx
index 349d47a..2ae9a26 100644
--- a/components/SessionPicker.tsx
+++ b/components/SessionPicker.tsx
@@ -265,6 +265,7 @@
   } = useChat();
   const [editingId, setEditingId] = useState<string | null>(null);
   const [keyboardHeight, setKeyboardHeight] = useState(0);
+  const sessionScrollRef = useRef<ScrollView>(null);
 
   // Sort: active first, then by index
   const sortedSessions = [...sessions].sort((a, b) => {
@@ -312,7 +313,14 @@
   const handleStartRename = useCallback((session: WsSession) => {
     Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
     setEditingId(session.id);
-  }, []);
+    // Scroll down after keyboard appears so the rename field is visible
+    const idx = sortedSessions.findIndex(s => s.id === session.id);
+    if (idx >= 0 && sessionScrollRef.current) {
+      setTimeout(() => {
+        sessionScrollRef.current?.scrollTo({ y: idx * 60, animated: true });
+      }, 400);
+    }
+  }, [sortedSessions]);
 
   const handleConfirmRename = useCallback(
     (sessionId: string, newName: string) => {
@@ -407,6 +415,7 @@
 
             {/* Session list */}
             <ScrollView
+              ref={sessionScrollRef}
               style={{ paddingHorizontal: 16 }}
               showsVerticalScrollIndicator={false}
               keyboardShouldPersistTaps="handled"

--
Gitblit v1.3.1