60 lines
2.5 KiB
TypeScript
60 lines
2.5 KiB
TypeScript
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<Set<string>>(new Set());
|
|
|
|
useEffect(() => {
|
|
const nextRooms = new Set<string>();
|
|
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;
|
|
}
|