import { useEffect, useRef } from 'react'; import { useAtomValue } from 'jotai'; import { incomingCallsAtom } from '../state/incomingCalls'; import { isNativePlatform } from '../utils/capacitor'; // When the in-app incomingCallsAtom drops an entry (user accepted, declined, // other device joined, lifetime expired), also clear the CallStyle notification // the native service posted for that room. The AlarmManager fallback in the // Java service handles killed-process dismiss on lifetime expiry; this hook // covers the live-client paths where JS knows the truth sooner than the alarm. export const useDismissNativeCallNotifications = (): void => { const incoming = useAtomValue(incomingCallsAtom); const prevRoomsRef = useRef>(new Set()); useEffect(() => { const nextRooms = new Set(); incoming.forEach((call) => nextRooms.add(call.roomId)); const dropped: string[] = []; prevRoomsRef.current.forEach((roomId) => { if (!nextRooms.has(roomId)) dropped.push(roomId); }); prevRoomsRef.current = nextRooms; if (dropped.length === 0) return; if (!isNativePlatform()) return; (async () => { const { PushNotifications } = await import('@capacitor/push-notifications'); // Shape mirrors VojoFirebaseMessagingService.showIncomingCallNotification: // tag = "call_" + roomId, id = tag.hashCode(). The Android Capacitor // plugin reads id via JSObject.getInteger (PushNotificationsPlugin.java // line 166), so the id must go over the bridge as a number — the TS // type declares string, hence the cast. const notifications = dropped.map((roomId) => { const tag = `call_${roomId}`; return { id: javaStringHashCode(tag), tag }; }); await PushNotifications.removeDeliveredNotifications({ notifications: notifications as unknown as Parameters< typeof PushNotifications.removeDeliveredNotifications >[0]['notifications'], }).catch(() => { /* best-effort — alarm fallback still dismisses at lifetime expiry */ }); })(); }, [incoming]); }; // Reproduces java.lang.String#hashCode so JS-side ids match the tag ids the // Java service computed. Must stay in sync with CallCancelReceiver / the // tag.hashCode() call in VojoFirebaseMessagingService. function javaStringHashCode(s: string): number { let h = 0; for (let i = 0; i < s.length; i += 1) { // eslint-disable-next-line no-bitwise h = (Math.imul(31, h) + s.charCodeAt(i)) | 0; } return h; }