mirror of
https://github.com/multica-ai/multica.git
synced 2026-07-13 05:16:29 +02:00
Surface the same unread signals web puts on the sidebar (inbox) and the ChatFab (chat). On a phone the user lives on the tab bar, so mounting badges directly on the Inbox and Chat tabs is the closest equivalent. Display semantics mirror web exactly (apps/mobile/CLAUDE.md "counts must agree"): - Inbox badge = `deduplicateInboxItems(items).filter(i => !i.read).length`, same as web's `useInboxUnreadCount` (packages/core/inbox/queries.ts:22). 99+ truncation matches the sidebar. - Chat badge = `sessions.filter(s => s.has_unread).length`, same as web's ChatFab (packages/views/chat/components/chat-fab.tsx:29). 9+ truncation matches the fab. Implementation: - New `apps/mobile/lib/unread-counts.ts` with two `useQuery + select` hooks; mirror-don't-import the web design. - Wired into `(tabs)/_layout.tsx` as React Navigation's native `tabBarBadge` + `tabBarBadgeStyle`. Style is JUST `backgroundColor` (brand blue `#4571e0`); @react-navigation/elements `Badge` internally uses `borderRadius = size / 2` and `minWidth = size`, so the single-character badge renders as a true circle. Overriding minWidth / fontSize / fontWeight breaks that geometry — keep the override minimal. - Brand blue chosen over the iOS default red: matches web's ChatFab `bg-brand` pip and avoids the "error / critical" connotation red carries for an everyday new-comment notification. Both queries (`inboxListOptions`, `chatSessionsOptions`) are already kept fresh by listing-level realtime hooks mounted in `app/(app)/[workspace]/_layout.tsx` (`useInboxRealtime` / `useChatSessionsRealtime`), so badges update via WS events without a poll or focus refetch. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>