import { useEffect, useRef } from 'react'; import { useAtomValue } from 'jotai'; import { roomToUnreadAtom } from '../state/room/roomToUnread'; // Tauri v2 injects __TAURI_INTERNALS__ into the webview at runtime. // We use it directly so cinny doesn't need @tauri-apps/api as a dependency. type TauriInternals = { invoke: (cmd: string, args?: Record) => Promise }; const tauriInvoke = (): TauriInternals['invoke'] | undefined => (window as unknown as { __TAURI_INTERNALS__?: TauriInternals }).__TAURI_INTERNALS__?.invoke; export function useTauriNotificationBadge() { const roomToUnread = useAtomValue(roomToUnreadAtom); const prevHighlightsRef = useRef(0); useEffect(() => { const invoke = tauriInvoke(); if (!invoke) return; let totalHighlights = 0; roomToUnread.forEach((unread) => { // Sum only leaf rooms (from === null); roomToUnread also holds per-ancestor // space aggregates (from = Set), so counting all entries double-counts a // space-nested room. Mirrors the favicon fix in ClientNonUIFeatures. if (unread.from !== null) return; totalHighlights += unread.highlight; }); invoke('set_badge_count', { count: totalHighlights }).catch(() => {}); // Mirror the unread state onto the tray icon (visible when minimized to tray). invoke('set_tray_unread', { unread: totalHighlights > 0 }).catch(() => {}); // Flash the taskbar button when new mentions arrive and the window is not // focused, then reset the baseline. if (totalHighlights > prevHighlightsRef.current && !document.hasFocus()) { invoke('flash_window').catch(() => {}); } prevHighlightsRef.current = totalHighlights; }, [roomToUnread]); }