From fadf874cfc8d4e1cd4bccb1a0b1e2fff514275d3 Mon Sep 17 00:00:00 2001 From: AugusDogus <9794679+AugusDogus@users.noreply.github.com> Date: Thu, 26 Mar 2026 23:43:22 -0500 Subject: [PATCH] Auto-open unread group threads from friends - Pass unread state into Group navigation - Open the viewer automatically for unread group inboxes - Exclude group deliveries from friend row/status calculations --- apps/expo/src/app/friends.tsx | 5 ++++- apps/expo/src/app/group.tsx | 15 +++++++++++++-- apps/expo/src/hooks/useFriendRows.ts | 1 + apps/expo/src/navigation/types.ts | 2 +- packages/api/src/services/message-status.ts | 3 +++ 5 files changed, 22 insertions(+), 4 deletions(-) diff --git a/apps/expo/src/app/friends.tsx b/apps/expo/src/app/friends.tsx index 4b63d47..0d73eee 100644 --- a/apps/expo/src/app/friends.tsx +++ b/apps/expo/src/app/friends.tsx @@ -339,7 +339,10 @@ export default function FriendsScreen() { whispLogo={whispLogo} colorScheme={colorScheme} onPressGroupRow={(group) => { - navigation.navigate("Group", { groupId: group.id }); + navigation.navigate("Group", { + groupId: group.id, + autoOpenUnread: group.unreadCount > 0, + }); }} onLongPressGroupRow={(group) => { void Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium); diff --git a/apps/expo/src/app/group.tsx b/apps/expo/src/app/group.tsx index 91ebb3f..494e4cf 100644 --- a/apps/expo/src/app/group.tsx +++ b/apps/expo/src/app/group.tsx @@ -1,7 +1,7 @@ import type { RouteProp } from "@react-navigation/native"; import type { NativeStackNavigationProp } from "@react-navigation/native-stack"; -import { useCallback, useMemo, useState } from "react"; +import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { FlatList, Pressable, @@ -32,7 +32,7 @@ export default function GroupScreen() { const navigation = useNavigation>(); const route = useRoute>(); - const { groupId } = route.params; + const { groupId, autoOpenUnread = false } = route.params; const insets = useSafeAreaInsets(); const colorScheme = useColorScheme(); const iconColor = colorScheme === "dark" ? "#fff" : "#000"; @@ -58,9 +58,20 @@ export default function GroupScreen() { const { viewer, openViewer, closeViewer, onViewerTap } = useGroupMessageViewer(groupId); + const hasAutoOpenedRef = useRef(false); const isLoading = groupLoading || inboxLoading; + useEffect(() => { + if (!autoOpenUnread) return; + if (hasAutoOpenedRef.current) return; + if (isLoading) return; + if (inboxRaw.length === 0) return; + + hasAutoOpenedRef.current = true; + openViewer(inboxRaw, 0); + }, [autoOpenUnread, inboxRaw, isLoading, openViewer]); + const onSendWhisp = useCallback(() => { navigation.navigate("Main", { screen: "Camera", diff --git a/apps/expo/src/hooks/useFriendRows.ts b/apps/expo/src/hooks/useFriendRows.ts index ebc37b0..a2fada2 100644 --- a/apps/expo/src/hooks/useFriendRows.ts +++ b/apps/expo/src/hooks/useFriendRows.ts @@ -32,6 +32,7 @@ export function useFriendRows({ const senderToLatestMime = new Map(); for (const m of inbox) { if (!m) continue; + if (m.groupId) continue; const count = senderToMessages.get(m.senderId) ?? 0; senderToMessages.set(m.senderId, count + 1); diff --git a/apps/expo/src/navigation/types.ts b/apps/expo/src/navigation/types.ts index 1c3600e..998d933 100644 --- a/apps/expo/src/navigation/types.ts +++ b/apps/expo/src/navigation/types.ts @@ -19,7 +19,7 @@ export interface RootStackParamList extends ParamListBase { color: string; }[]; }; - Group: { groupId: string }; + Group: { groupId: string; autoOpenUnread?: boolean }; GroupSettings: { groupId: string }; GroupAddMembers: { groupId: string }; CreateGroup: undefined; diff --git a/packages/api/src/services/message-status.ts b/packages/api/src/services/message-status.ts index 08b3352..b39d115 100644 --- a/packages/api/src/services/message-status.ts +++ b/packages/api/src/services/message-status.ts @@ -24,6 +24,7 @@ export async function getPendingSentDeliveries( .where( and( inArray(MessageDelivery.recipientId, friendIds), + isNull(MessageDelivery.groupId), isNull(MessageDelivery.readAt), ), ); @@ -73,6 +74,7 @@ export async function getLastSentMimeTypes( .where( and( inArray(MessageDelivery.recipientId, friendIds), + isNull(MessageDelivery.groupId), eq(Message.senderId, me), ), ) @@ -126,6 +128,7 @@ export async function getLastReceivedMimeTypes( .where( and( eq(MessageDelivery.recipientId, me), + isNull(MessageDelivery.groupId), inArray(Message.senderId, friendIds), ), )