import { useEffect, useMemo, useState } from 'react'; import { MatrixEvent, RoomStateEvent } from 'matrix-js-sdk'; import { MatrixRTCSessionManagerEvents } from 'matrix-js-sdk/lib/matrixrtc/MatrixRTCSessionManager'; import { useMatrixClient } from './useMatrixClient'; import { StateEvent } from '../../types/matrix/room'; /** * [Gitea #148] Whether any of the given rooms has a live MatrixRTC call. * Derived from the same session memberships the sidebar voice rows use; * recomputed only when a session starts/ends or a call-member state event * lands in one of the rooms — no per-render scans. */ export function useAnyRoomLiveCall(roomIds: string[]): boolean { const mx = useMatrixClient(); const idSet = useMemo(() => new Set(roomIds), [roomIds]); const compute = () => roomIds.some((id) => { const room = mx.getRoom(id); return !!room && mx.matrixRTC.getRoomSession(room).memberships.length > 0; }); const [live, setLive] = useState(compute); useEffect(() => { setLive(compute()); const onSession = (roomId: string) => { if (idSet.has(roomId)) setLive(compute()); }; const onState = (event: MatrixEvent) => { if (event.getType() !== StateEvent.GroupCallMemberPrefix) return; const roomId = event.getRoomId(); if (roomId && idSet.has(roomId)) setLive(compute()); }; mx.matrixRTC.on(MatrixRTCSessionManagerEvents.SessionStarted, onSession); mx.matrixRTC.on(MatrixRTCSessionManagerEvents.SessionEnded, onSession); mx.on(RoomStateEvent.Events, onState); return () => { mx.matrixRTC.off(MatrixRTCSessionManagerEvents.SessionStarted, onSession); mx.matrixRTC.off(MatrixRTCSessionManagerEvents.SessionEnded, onSession); mx.off(RoomStateEvent.Events, onState); }; // compute closes over roomIds; idSet changes exactly when roomIds does // eslint-disable-next-line react-hooks/exhaustive-deps }, [mx, idSet]); return live; }