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