feat: enhance incoming call notification logic to track seen calls and filter fresh calls

This commit is contained in:
2026-04-21 07:57:28 +10:00
parent e5f74ec13e
commit 7c824392b7

View File

@@ -102,6 +102,7 @@ export function IncomingCallNotification() {
const { activeCall, startCall } = useCall();
const [incomingCall, setIncomingCall] = useState<IncomingCall | null>(null);
const [declinedRooms, setDeclinedRooms] = useState<Set<string>>(new Set());
const [seenCalls, setSeenCalls] = useState<Map<string, number>>(new Map());
/**
* Checks all rooms for incoming calls
@@ -118,15 +119,25 @@ export function IncomingCallNotification() {
// Check all joined rooms for calls
const rooms = mx.getRooms();
const now = Date.now();
const MAX_CALL_AGE = 10000; // 10 seconds
// Find the first room with an incoming call
const incomingRoom = rooms.find((room) => {
// Only monitor DMs and small groups
if (!isDirectOrSmallGroup(room)) return false;
// Only monitor 1-1 DMs (exactly 2 members)
if (room.getJoinedMemberCount() !== 2) return false;
// Skip rooms we've declined
if (declinedRooms.has(room.roomId)) return false;
const { members } = getOtherCallMembersWithTime(room, myUserId);
return members.length > 0;
const { members, earliestTime } = getOtherCallMembersWithTime(room, myUserId);
if (members.length === 0) return false;
// Skip if we've already seen this exact call session
const lastSeenTime = seenCalls.get(room.roomId);
if (lastSeenTime && lastSeenTime === earliestTime) return false;
// Only show if the call is fresh (less than 10 seconds old)
const callAge = now - earliestTime;
return callAge < MAX_CALL_AGE;
});
if (incomingRoom) {
@@ -140,28 +151,33 @@ export function IncomingCallNotification() {
} else {
setIncomingCall(null);
}
}, [mx, activeCall, declinedRooms]);
}, [mx, activeCall, declinedRooms, seenCalls]);
/**
* Handles state events for call member changes
*/
const handleStateEvent = useCallback((event: MatrixEvent) => {
if (event.getType() === CALL_MEMBER_EVENT_TYPE) {
// Clear declined status if call ended in that room
// Clear declined status and seen calls if call ended in that room
const roomId = event.getRoomId();
if (roomId && declinedRooms.has(roomId)) {
if (roomId) {
const room = mx.getRoom(roomId);
if (room) {
const myUserId = mx.getUserId();
if (myUserId) {
const members = getOtherCallMembers(room, myUserId);
if (members.length === 0) {
// Call ended, remove from declined
// Call ended, clear tracking
setDeclinedRooms((prev) => {
const newSet = new Set(prev);
newSet.delete(roomId);
return newSet;
});
setSeenCalls((prev) => {
const newMap = new Map(prev);
newMap.delete(roomId);
return newMap;
});
}
}
}
@@ -183,9 +199,12 @@ export function IncomingCallNotification() {
}, [mx, handleStateEvent, checkForIncomingCalls]);
// Play/stop dialing sound based on incoming call state
// Only play sound if call started less than 15 seconds ago
// Mark call as seen when displayed
useEffect(() => {
if (incomingCall) {
// Mark this call as seen so we don't notify again
setSeenCalls((prev) => new Map(prev).set(incomingCall.roomId, incomingCall.startTime));
const callAge = Date.now() - incomingCall.startTime;
const MAX_CALL_AGE_FOR_SOUND = 15000; // 15 seconds
@@ -212,6 +231,7 @@ export function IncomingCallNotification() {
if (!incomingCall) return;
getCallSounds().stopDialingLoop();
setSeenCalls((prev) => new Map(prev).set(incomingCall.roomId, incomingCall.startTime));
try {
await startCall(incomingCall.roomId, CallType.Voice);
} catch (error) {
@@ -226,6 +246,7 @@ export function IncomingCallNotification() {
if (!incomingCall) return;
getCallSounds().stopDialingLoop();
setSeenCalls((prev) => new Map(prev).set(incomingCall.roomId, incomingCall.startTime));
setDeclinedRooms((prev) => new Set(prev).add(incomingCall.roomId));
setIncomingCall(null);
}, [incomingCall]);
@@ -237,6 +258,7 @@ export function IncomingCallNotification() {
const room = mx.getRoom(incomingCall.roomId);
const firstCaller = incomingCall.callerIds[0];
const isGroupCall = room ? room.getJoinedMemberCount() > 2 : false;
/**
* Gets the display name for a user
@@ -287,10 +309,12 @@ export function IncomingCallNotification() {
</span>
)}
</Text>
<Text size="T200" className={css.RoomName}>
<Icon size="100" src={Icons.Phone} />
<span>Calling from {incomingCall.roomName}</span>
</Text>
{!isGroupCall && (
<Text size="T200" className={css.RoomName}>
<Icon size="100" src={Icons.Phone} />
<span>Calling from {incomingCall.roomName}</span>
</Text>
)}
</Box>
</div>