redo roomcallnavstatus ui, force user preferred mute/video states when first joining calls, update variable names and remove unnecessary logic
This commit is contained in:
parent
e481116b04
commit
990a92a32c
4 changed files with 175 additions and 169 deletions
|
|
@ -5,7 +5,7 @@ import { useCallState } from '../../pages/client/call/CallProvider';
|
||||||
import { useCallMembers } from '../../hooks/useCallMemberships';
|
import { useCallMembers } from '../../hooks/useCallMemberships';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
PrimaryRefContext,
|
CallRefContext,
|
||||||
} from '../../pages/client/call/PersistentCallContainer';
|
} from '../../pages/client/call/PersistentCallContainer';
|
||||||
import { ScreenSize, useScreenSizeContext } from '../../hooks/useScreenSize';
|
import { ScreenSize, useScreenSizeContext } from '../../hooks/useScreenSize';
|
||||||
import { useDebounce } from '../../hooks/useDebounce';
|
import { useDebounce } from '../../hooks/useDebounce';
|
||||||
|
|
@ -42,7 +42,7 @@ export function CallViewUserGrid({ children }: { children: ReactNode }) {
|
||||||
|
|
||||||
|
|
||||||
export function CallView({ room }: { room: Room }) {
|
export function CallView({ room }: { room: Room }) {
|
||||||
const primaryIframeRef = useContext(PrimaryRefContext);
|
const callIframeRef = useContext(CallRefContext);
|
||||||
const iframeHostRef = useRef<HTMLDivElement>(null);
|
const iframeHostRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
const originalIframeStylesRef = useRef<OriginalStyles | null>(null);
|
const originalIframeStylesRef = useRef<OriginalStyles | null>(null);
|
||||||
|
|
@ -60,7 +60,7 @@ export function CallView({ room }: { room: Room }) {
|
||||||
} = useCallState();
|
} = useCallState();
|
||||||
|
|
||||||
const isActiveCallRoom = activeCallRoomId === room.roomId
|
const isActiveCallRoom = activeCallRoomId === room.roomId
|
||||||
const shouldDisplayCall = isActiveCallRoom && isActiveCallReady;
|
const callIsCurrentAndReady = isActiveCallRoom && isActiveCallReady;
|
||||||
const callMembers = useCallMembers(mx, room.roomId)
|
const callMembers = useCallMembers(mx, room.roomId)
|
||||||
|
|
||||||
const getName = (userId: string) => getMemberDisplayName(room, userId) ?? getMxIdLocalPart(userId);
|
const getName = (userId: string) => getMemberDisplayName(room, userId) ?? getMxIdLocalPart(userId);
|
||||||
|
|
@ -71,8 +71,7 @@ export function CallView({ room }: { room: Room }) {
|
||||||
const screenSize = useScreenSizeContext();
|
const screenSize = useScreenSizeContext();
|
||||||
const isMobile = screenSize === ScreenSize.Mobile;
|
const isMobile = screenSize === ScreenSize.Mobile;
|
||||||
|
|
||||||
/* eslint-disable-next-line no-nested-ternary */
|
const activeIframeDisplayRef = callIframeRef
|
||||||
const activeIframeDisplayRef = primaryIframeRef
|
|
||||||
|
|
||||||
const applyFixedPositioningToIframe = useCallback(() => {
|
const applyFixedPositioningToIframe = useCallback(() => {
|
||||||
const iframeElement = activeIframeDisplayRef?.current;
|
const iframeElement = activeIframeDisplayRef?.current;
|
||||||
|
|
@ -118,7 +117,7 @@ export function CallView({ room }: { room: Room }) {
|
||||||
const iframeElement = activeIframeDisplayRef?.current;
|
const iframeElement = activeIframeDisplayRef?.current;
|
||||||
const hostElement = iframeHostRef?.current;
|
const hostElement = iframeHostRef?.current;
|
||||||
|
|
||||||
if (room.isCallRoom() || (shouldDisplayCall && iframeElement && hostElement)) {
|
if (room.isCallRoom() || (callIsCurrentAndReady && iframeElement && hostElement)) {
|
||||||
applyFixedPositioningToIframe();
|
applyFixedPositioningToIframe();
|
||||||
|
|
||||||
const resizeObserver = new ResizeObserver(debouncedApplyFixedPositioning);
|
const resizeObserver = new ResizeObserver(debouncedApplyFixedPositioning);
|
||||||
|
|
@ -146,7 +145,7 @@ export function CallView({ room }: { room: Room }) {
|
||||||
activeIframeDisplayRef,
|
activeIframeDisplayRef,
|
||||||
applyFixedPositioningToIframe,
|
applyFixedPositioningToIframe,
|
||||||
debouncedApplyFixedPositioning,
|
debouncedApplyFixedPositioning,
|
||||||
shouldDisplayCall,
|
callIsCurrentAndReady,
|
||||||
room,
|
room,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
@ -157,7 +156,7 @@ export function CallView({ room }: { room: Room }) {
|
||||||
setViewedCallRoomId(room.roomId);
|
setViewedCallRoomId(room.roomId);
|
||||||
navigateRoom(room.roomId);
|
navigateRoom(room.roomId);
|
||||||
}
|
}
|
||||||
if (!shouldDisplayCall) {
|
if (!callIsCurrentAndReady) {
|
||||||
hangUp(room.roomId);
|
hangUp(room.roomId);
|
||||||
setActiveCallRoomId(room.roomId);
|
setActiveCallRoomId(room.roomId);
|
||||||
}
|
}
|
||||||
|
|
@ -185,11 +184,11 @@ export function CallView({ room }: { room: Room }) {
|
||||||
height: '100%',
|
height: '100%',
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
pointerEvents: 'none',
|
pointerEvents: 'none',
|
||||||
display: shouldDisplayCall ? 'flex' : 'none',
|
display: callIsCurrentAndReady ? 'flex' : 'none',
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Box grow='Yes' justifyContent='Center' alignItems='Center' direction="Column" gap="300" style={{
|
<Box grow='Yes' justifyContent='Center' alignItems='Center' direction="Column" gap="300" style={{
|
||||||
display: shouldDisplayCall ? 'none' : 'flex',
|
display: callIsCurrentAndReady ? 'none' : 'flex',
|
||||||
}}>
|
}}>
|
||||||
<CallViewUserGrid>
|
<CallViewUserGrid>
|
||||||
{callMembers.map(callMember => (
|
{callMembers.map(callMember => (
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,8 @@ export function CallNavStatus() {
|
||||||
const {
|
const {
|
||||||
activeCallRoomId,
|
activeCallRoomId,
|
||||||
isAudioEnabled,
|
isAudioEnabled,
|
||||||
isVideoEnabled,
|
isVideoEnabled,
|
||||||
isActiveCallReady,
|
isActiveCallReady,
|
||||||
toggleAudio,
|
toggleAudio,
|
||||||
toggleVideo,
|
toggleVideo,
|
||||||
hangUp,
|
hangUp,
|
||||||
|
|
@ -21,9 +21,6 @@ export function CallNavStatus() {
|
||||||
navigateRoom(activeCallRoomId);
|
navigateRoom(activeCallRoomId);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if (!isActiveCallReady) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
|
|
@ -34,56 +31,10 @@ export function CallNavStatus() {
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Box direction="Row" style={{ justifyContent: 'center' }}>
|
<Box direction="Row" justifyContent='SpaceBetween' alignItems='Center'>
|
||||||
{/* Going to need better icons for this */}
|
{/* Going to need better icons for this */}
|
||||||
<TooltipProvider
|
|
||||||
position="Top"
|
|
||||||
offset={4}
|
|
||||||
tooltip={
|
|
||||||
<Tooltip>
|
|
||||||
<Text>{!isAudioEnabled ? 'Unmute' : 'Mute'}</Text>
|
|
||||||
</Tooltip>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{(triggerRef) => (
|
|
||||||
<IconButton variant="Background" ref={triggerRef} onClick={toggleAudio}>
|
|
||||||
<Icon src={!isAudioEnabled ? Icons.MicMute : Icons.Mic} />
|
|
||||||
</IconButton>
|
|
||||||
)}
|
|
||||||
</TooltipProvider>
|
|
||||||
<TooltipProvider
|
|
||||||
position="Top"
|
|
||||||
offset={4}
|
|
||||||
tooltip={
|
|
||||||
<Tooltip>
|
|
||||||
<Text>{!isVideoEnabled ? 'Video On' : 'Video Off'}</Text>
|
|
||||||
</Tooltip>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{(triggerRef) => (
|
|
||||||
<IconButton variant="Background" ref={triggerRef} onClick={toggleVideo}>
|
|
||||||
<Icon src={!isVideoEnabled ? Icons.VideoCameraMute : Icons.VideoCamera} />
|
|
||||||
</IconButton>
|
|
||||||
)}
|
|
||||||
</TooltipProvider>
|
|
||||||
|
|
||||||
<TooltipProvider
|
<Box>
|
||||||
position="Top"
|
|
||||||
offset={4}
|
|
||||||
tooltip={
|
|
||||||
<Tooltip>
|
|
||||||
<Text>Hang Up</Text>
|
|
||||||
</Tooltip>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{(triggerRef) => (
|
|
||||||
<IconButton variant="Background" ref={triggerRef} onClick={hangUp}>
|
|
||||||
<Icon src={Icons.Phone} />
|
|
||||||
</IconButton>
|
|
||||||
)}
|
|
||||||
</TooltipProvider>
|
|
||||||
|
|
||||||
<Box grow="Yes" justifyContent="Center" alignItems="Center">
|
|
||||||
<TooltipProvider
|
<TooltipProvider
|
||||||
position="Top"
|
position="Top"
|
||||||
offset={4}
|
offset={4}
|
||||||
|
|
@ -101,7 +52,13 @@ export function CallNavStatus() {
|
||||||
as="button"
|
as="button"
|
||||||
onClick={handleGoToCallRoom}
|
onClick={handleGoToCallRoom}
|
||||||
ref={triggerRef}
|
ref={triggerRef}
|
||||||
|
style={{
|
||||||
|
display: isActiveCallReady ? 'flex' : 'none',
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "center"
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
|
<Icon src={Icons.VolumeHigh}/>
|
||||||
<Text style={{ flexGrow: 1 }} size="B400" truncate>
|
<Text style={{ flexGrow: 1 }} size="B400" truncate>
|
||||||
{mx.getRoom(activeCallRoomId)?.name}
|
{mx.getRoom(activeCallRoomId)?.name}
|
||||||
</Text>
|
</Text>
|
||||||
|
|
@ -109,6 +66,62 @@ export function CallNavStatus() {
|
||||||
)}
|
)}
|
||||||
</TooltipProvider>
|
</TooltipProvider>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
|
<Box>
|
||||||
|
<TooltipProvider
|
||||||
|
position="Top"
|
||||||
|
offset={4}
|
||||||
|
tooltip={
|
||||||
|
<Tooltip>
|
||||||
|
<Text>{!isAudioEnabled ? 'Unmute' : 'Mute'}</Text>
|
||||||
|
</Tooltip>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{(triggerRef) => (
|
||||||
|
<IconButton variant="Background" ref={triggerRef} onClick={toggleAudio}>
|
||||||
|
<Icon src={!isAudioEnabled ? Icons.MicMute : Icons.Mic} />
|
||||||
|
</IconButton>
|
||||||
|
)}
|
||||||
|
</TooltipProvider>
|
||||||
|
<TooltipProvider
|
||||||
|
position="Top"
|
||||||
|
offset={4}
|
||||||
|
tooltip={
|
||||||
|
<Tooltip>
|
||||||
|
<Text>{!isVideoEnabled ? 'Video On' : 'Video Off'}</Text>
|
||||||
|
</Tooltip>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{(triggerRef) => (
|
||||||
|
<IconButton variant="Background" ref={triggerRef} onClick={toggleVideo}>
|
||||||
|
<Icon src={!isVideoEnabled ? Icons.VideoCameraMute : Icons.VideoCamera} />
|
||||||
|
</IconButton>
|
||||||
|
)}
|
||||||
|
</TooltipProvider>
|
||||||
|
|
||||||
|
<TooltipProvider
|
||||||
|
position="Top"
|
||||||
|
offset={4}
|
||||||
|
tooltip={
|
||||||
|
<Tooltip>
|
||||||
|
<Text>Hang Up</Text>
|
||||||
|
</Tooltip>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{(triggerRef) => (
|
||||||
|
<IconButton
|
||||||
|
variant="Background"
|
||||||
|
ref={triggerRef}
|
||||||
|
onClick={hangUp}
|
||||||
|
style={{
|
||||||
|
display: isActiveCallReady ? 'block' : 'none'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Icon src={Icons.Phone} />
|
||||||
|
</IconButton>
|
||||||
|
)}
|
||||||
|
</TooltipProvider>
|
||||||
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -65,39 +65,24 @@ const DEFAULT_CALL_ACTIVE = false;
|
||||||
export function CallProvider({ children }: CallProviderProps) {
|
export function CallProvider({ children }: CallProviderProps) {
|
||||||
const [activeCallRoomId, setActiveCallRoomIdState] = useState<string | null>(null);
|
const [activeCallRoomId, setActiveCallRoomIdState] = useState<string | null>(null);
|
||||||
const [viewedCallRoomId, setViewedCallRoomIdState] = useState<string | null>(null);
|
const [viewedCallRoomId, setViewedCallRoomIdState] = useState<string | null>(null);
|
||||||
const [activeClientWidgetApi, setActiveClientWidgetApiState] = useState<ClientWidgetApi | null>(
|
|
||||||
null
|
const [activeClientWidgetApi, setActiveClientWidgetApiState] = useState<ClientWidgetApi | null>(null);
|
||||||
);
|
|
||||||
const [activeClientWidget, setActiveClientWidget] = useState<SmallWidget | null>(null);
|
const [activeClientWidget, setActiveClientWidget] = useState<SmallWidget | null>(null);
|
||||||
const [activeClientWidgetApiRoomId, setActiveClientWidgetApiRoomId] = useState<string | null>(
|
const [activeClientWidgetApiRoomId, setActiveClientWidgetApiRoomId] = useState<string | null>(null);
|
||||||
null
|
|
||||||
);
|
|
||||||
|
|
||||||
const [isAudioEnabled, setIsAudioEnabledState] = useState<boolean>(DEFAULT_AUDIO_ENABLED);
|
const [isAudioEnabled, setIsAudioEnabledState] = useState<boolean>(DEFAULT_AUDIO_ENABLED);
|
||||||
const [isVideoEnabled, setIsVideoEnabledState] = useState<boolean>(DEFAULT_VIDEO_ENABLED);
|
const [isVideoEnabled, setIsVideoEnabledState] = useState<boolean>(DEFAULT_VIDEO_ENABLED);
|
||||||
const [isChatOpen, setIsChatOpenState] = useState<boolean>(DEFAULT_CHAT_OPENED);
|
const [isChatOpen, setIsChatOpenState] = useState<boolean>(DEFAULT_CHAT_OPENED);
|
||||||
const [isActiveCallReady, setIsCallActive] = useState<boolean>(DEFAULT_CALL_ACTIVE);
|
const [isActiveCallReady, setIsActiveCallReady] = useState<boolean>(DEFAULT_CALL_ACTIVE);
|
||||||
|
|
||||||
const { roomIdOrAlias: viewedRoomId } = useParams<{ roomIdOrAlias: string }>();
|
const { roomIdOrAlias: viewedRoomId } = useParams<{ roomIdOrAlias: string }>();
|
||||||
|
|
||||||
const resetMediaState = useCallback(() => {
|
|
||||||
logger.debug('CallContext: Resetting media state to defaults.');
|
|
||||||
setIsAudioEnabledState(DEFAULT_AUDIO_ENABLED);
|
|
||||||
setIsVideoEnabledState(DEFAULT_VIDEO_ENABLED);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const setActiveCallRoomId = useCallback(
|
const setActiveCallRoomId = useCallback(
|
||||||
(roomId: string | null) => {
|
(roomId: string | null) => {
|
||||||
logger.warn(`CallContext: Setting activeCallRoomId to ${roomId}`);
|
logger.warn(`CallContext: Setting activeCallRoomId to ${roomId}`);
|
||||||
const previousRoomId = activeCallRoomId;
|
|
||||||
setActiveCallRoomIdState(roomId);
|
setActiveCallRoomIdState(roomId);
|
||||||
|
|
||||||
if (roomId !== previousRoomId) {
|
|
||||||
logger.debug(`CallContext: Active call room changed, resetting media state.`);
|
|
||||||
resetMediaState();
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
[resetMediaState, activeCallRoomId]
|
[]
|
||||||
);
|
);
|
||||||
|
|
||||||
const setViewedCallRoomId = useCallback(
|
const setViewedCallRoomId = useCallback(
|
||||||
|
|
@ -136,10 +121,9 @@ export function CallProvider({ children }: CallProviderProps) {
|
||||||
setActiveClientWidgetApi(clientWidgetApi, clientWidget, roomId);
|
setActiveClientWidgetApi(clientWidgetApi, clientWidget, roomId);
|
||||||
} else if (roomId === activeClientWidgetApiRoomId || roomId === null) {
|
} else if (roomId === activeClientWidgetApiRoomId || roomId === null) {
|
||||||
setActiveClientWidgetApi(null, null, null);
|
setActiveClientWidgetApi(null, null, null);
|
||||||
resetMediaState();
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[activeClientWidgetApi, activeClientWidgetApiRoomId, setActiveClientWidgetApi, resetMediaState]
|
[activeClientWidgetApi, activeClientWidgetApiRoomId, setActiveClientWidgetApi]
|
||||||
);
|
);
|
||||||
|
|
||||||
const hangUp = useCallback(
|
const hangUp = useCallback(
|
||||||
|
|
@ -147,7 +131,7 @@ export function CallProvider({ children }: CallProviderProps) {
|
||||||
setActiveClientWidgetApi(null, null, null);
|
setActiveClientWidgetApi(null, null, null);
|
||||||
setActiveCallRoomIdState(null);
|
setActiveCallRoomIdState(null);
|
||||||
activeClientWidgetApi?.transport.send(`${WIDGET_HANGUP_ACTION}`, {});
|
activeClientWidgetApi?.transport.send(`${WIDGET_HANGUP_ACTION}`, {});
|
||||||
setIsCallActive(false);
|
setIsActiveCallReady(false);
|
||||||
|
|
||||||
logger.debug(`CallContext: Hang up called.`);
|
logger.debug(`CallContext: Hang up called.`);
|
||||||
},
|
},
|
||||||
|
|
@ -157,6 +141,71 @@ export function CallProvider({ children }: CallProviderProps) {
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
const sendWidgetAction = useCallback(
|
||||||
|
async <T = unknown,>(action: WidgetApiToWidgetAction | string, data: T): Promise<void> => {
|
||||||
|
if (!activeClientWidgetApi) {
|
||||||
|
logger.warn(
|
||||||
|
`CallContext: Cannot send action '${action}', no active API clientWidgetApi registered.`
|
||||||
|
);
|
||||||
|
return Promise.reject(new Error('No active call clientWidgetApi'));
|
||||||
|
}
|
||||||
|
if (!activeClientWidgetApiRoomId || activeClientWidgetApiRoomId !== activeCallRoomId) {
|
||||||
|
logger.debug(
|
||||||
|
`CallContext: Cannot send action '${action}', clientWidgetApi room (${activeClientWidgetApiRoomId}) does not match active call room (${activeCallRoomId}). Stale clientWidgetApi?`
|
||||||
|
);
|
||||||
|
return Promise.reject(new Error('Mismatched active call clientWidgetApi'));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
logger.debug(
|
||||||
|
`CallContext: Sending action '${action}' via active clientWidgetApi (room: ${activeClientWidgetApiRoomId}) with data:`,
|
||||||
|
data
|
||||||
|
);
|
||||||
|
await activeClientWidgetApi.transport.send(action as WidgetApiAction, data);
|
||||||
|
},
|
||||||
|
[activeClientWidgetApi, activeCallRoomId, activeClientWidgetApiRoomId]
|
||||||
|
);
|
||||||
|
|
||||||
|
const toggleAudio = useCallback(async () => {
|
||||||
|
const newState = !isAudioEnabled;
|
||||||
|
logger.debug(`CallContext: Toggling audio. New state: enabled=${newState}`);
|
||||||
|
setIsAudioEnabledState(newState);
|
||||||
|
|
||||||
|
if(isActiveCallReady) {
|
||||||
|
try {
|
||||||
|
await sendWidgetAction(WIDGET_MEDIA_STATE_UPDATE_ACTION, {
|
||||||
|
audio_enabled: newState,
|
||||||
|
video_enabled: isVideoEnabled,
|
||||||
|
});
|
||||||
|
logger.debug(`CallContext: Successfully sent audio toggle action.`);
|
||||||
|
} catch (error) {
|
||||||
|
setIsAudioEnabledState(!newState);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [isAudioEnabled, isVideoEnabled, sendWidgetAction, isActiveCallReady]);
|
||||||
|
|
||||||
|
const toggleVideo = useCallback(async () => {
|
||||||
|
const newState = !isVideoEnabled;
|
||||||
|
logger.debug(`CallContext: Toggling video. New state: enabled=${newState}`);
|
||||||
|
setIsVideoEnabledState(newState);
|
||||||
|
|
||||||
|
if(isActiveCallReady){
|
||||||
|
try {
|
||||||
|
await sendWidgetAction(WIDGET_MEDIA_STATE_UPDATE_ACTION, {
|
||||||
|
audio_enabled: isAudioEnabled,
|
||||||
|
video_enabled: newState,
|
||||||
|
});
|
||||||
|
logger.debug(`CallContext: Successfully sent video toggle action.`);
|
||||||
|
} catch (error) {
|
||||||
|
setIsVideoEnabledState(!newState);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [isVideoEnabled, isAudioEnabled, sendWidgetAction, isActiveCallReady]);
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!activeCallRoomId && !viewedCallRoomId) {
|
if (!activeCallRoomId && !viewedCallRoomId) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -179,6 +228,7 @@ export function CallProvider({ children }: CallProviderProps) {
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleMediaStateUpdate = (ev: CustomEvent<MediaStatePayload>) => {
|
const handleMediaStateUpdate = (ev: CustomEvent<MediaStatePayload>) => {
|
||||||
|
if(!isActiveCallReady) return;
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
logger.debug(
|
logger.debug(
|
||||||
`CallContext: Received media state update from widget in room ${activeCallRoomId}:`,
|
`CallContext: Received media state update from widget in room ${activeCallRoomId}:`,
|
||||||
|
|
@ -228,13 +278,19 @@ export function CallProvider({ children }: CallProviderProps) {
|
||||||
});
|
});
|
||||||
logger.debug('Join Call');
|
logger.debug('Join Call');
|
||||||
observer.observe(iframeDoc, { childList: true, subtree: true });
|
observer.observe(iframeDoc, { childList: true, subtree: true });
|
||||||
setIsCallActive(true);
|
setIsActiveCallReady(true);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
logger.debug(
|
logger.debug(
|
||||||
`CallContext: Setting up listeners for clientWidgetApi in room ${activeCallRoomId}`
|
`CallContext: Setting up listeners for clientWidgetApi in room ${activeCallRoomId}`
|
||||||
);
|
);
|
||||||
|
|
||||||
|
sendWidgetAction(WIDGET_MEDIA_STATE_UPDATE_ACTION, {
|
||||||
|
audio_enabled: isAudioEnabled,
|
||||||
|
video_enabled: isVideoEnabled,
|
||||||
|
});
|
||||||
|
|
||||||
api.on(`action:${WIDGET_HANGUP_ACTION}`, handleHangup);
|
api.on(`action:${WIDGET_HANGUP_ACTION}`, handleHangup);
|
||||||
api.on(`action:${WIDGET_MEDIA_STATE_UPDATE_ACTION}`, handleMediaStateUpdate);
|
api.on(`action:${WIDGET_MEDIA_STATE_UPDATE_ACTION}`, handleMediaStateUpdate);
|
||||||
api.on(`action:${WIDGET_TILE_UPDATE}`, handleOnTileLayout);
|
api.on(`action:${WIDGET_TILE_UPDATE}`, handleOnTileLayout);
|
||||||
|
|
@ -255,65 +311,9 @@ export function CallProvider({ children }: CallProviderProps) {
|
||||||
setViewedCallRoomId,
|
setViewedCallRoomId,
|
||||||
activeClientWidget?.iframe?.contentDocument,
|
activeClientWidget?.iframe?.contentDocument,
|
||||||
activeClientWidget?.iframe?.contentWindow?.document,
|
activeClientWidget?.iframe?.contentWindow?.document,
|
||||||
|
sendWidgetAction
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const sendWidgetAction = useCallback(
|
|
||||||
async <T = unknown,>(action: WidgetApiToWidgetAction | string, data: T): Promise<void> => {
|
|
||||||
if (!activeClientWidgetApi) {
|
|
||||||
logger.warn(
|
|
||||||
`CallContext: Cannot send action '${action}', no active API clientWidgetApi registered.`
|
|
||||||
);
|
|
||||||
return Promise.reject(new Error('No active call clientWidgetApi'));
|
|
||||||
}
|
|
||||||
if (!activeClientWidgetApiRoomId || activeClientWidgetApiRoomId !== activeCallRoomId) {
|
|
||||||
logger.debug(
|
|
||||||
`CallContext: Cannot send action '${action}', clientWidgetApi room (${activeClientWidgetApiRoomId}) does not match active call room (${activeCallRoomId}). Stale clientWidgetApi?`
|
|
||||||
);
|
|
||||||
return Promise.reject(new Error('Mismatched active call clientWidgetApi'));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
logger.debug(
|
|
||||||
`CallContext: Sending action '${action}' via active clientWidgetApi (room: ${activeClientWidgetApiRoomId}) with data:`,
|
|
||||||
data
|
|
||||||
);
|
|
||||||
await activeClientWidgetApi.transport.send(action as WidgetApiAction, data);
|
|
||||||
},
|
|
||||||
[activeClientWidgetApi, activeCallRoomId, activeClientWidgetApiRoomId]
|
|
||||||
);
|
|
||||||
|
|
||||||
const toggleAudio = useCallback(async () => {
|
|
||||||
const newState = !isAudioEnabled;
|
|
||||||
logger.debug(`CallContext: Toggling audio. New state: enabled=${newState}`);
|
|
||||||
setIsAudioEnabledState(newState);
|
|
||||||
try {
|
|
||||||
await sendWidgetAction(WIDGET_MEDIA_STATE_UPDATE_ACTION, {
|
|
||||||
audio_enabled: newState,
|
|
||||||
video_enabled: isVideoEnabled,
|
|
||||||
});
|
|
||||||
logger.debug(`CallContext: Successfully sent audio toggle action.`);
|
|
||||||
} catch (error) {
|
|
||||||
setIsAudioEnabledState(!newState);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}, [isAudioEnabled, isVideoEnabled, sendWidgetAction]);
|
|
||||||
|
|
||||||
const toggleVideo = useCallback(async () => {
|
|
||||||
const newState = !isVideoEnabled;
|
|
||||||
logger.debug(`CallContext: Toggling video. New state: enabled=${newState}`);
|
|
||||||
setIsVideoEnabledState(newState);
|
|
||||||
try {
|
|
||||||
await sendWidgetAction(WIDGET_MEDIA_STATE_UPDATE_ACTION, {
|
|
||||||
audio_enabled: isAudioEnabled,
|
|
||||||
video_enabled: newState,
|
|
||||||
});
|
|
||||||
logger.debug(`CallContext: Successfully sent video toggle action.`);
|
|
||||||
} catch (error) {
|
|
||||||
setIsVideoEnabledState(!newState);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}, [isVideoEnabled, isAudioEnabled, sendWidgetAction]);
|
|
||||||
|
|
||||||
const toggleChat = useCallback(async () => {
|
const toggleChat = useCallback(async () => {
|
||||||
const newState = !isChatOpen;
|
const newState = !isChatOpen;
|
||||||
setIsChatOpenState(newState);
|
setIsChatOpenState(newState);
|
||||||
|
|
|
||||||
|
|
@ -19,12 +19,12 @@ interface PersistentCallContainerProps {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const PrimaryRefContext = createContext(null);
|
export const CallRefContext = createContext(null);
|
||||||
|
|
||||||
export function PersistentCallContainer({ children }: PersistentCallContainerProps) {
|
export function PersistentCallContainer({ children }: PersistentCallContainerProps) {
|
||||||
const primaryIframeRef = useRef<HTMLIFrameElement | null>(null);
|
const callIframeRef = useRef<HTMLIFrameElement | null>(null);
|
||||||
const primaryWidgetApiRef = useRef<ClientWidgetApi | null>(null);
|
const callWidgetApiRef = useRef<ClientWidgetApi | null>(null);
|
||||||
const primarySmallWidgetRef = useRef<SmallWidget | null>(null);
|
const callSmallWidgetRef = useRef<SmallWidget | null>(null);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
activeCallRoomId,
|
activeCallRoomId,
|
||||||
|
|
@ -39,11 +39,6 @@ export function PersistentCallContainer({ children }: PersistentCallContainerPro
|
||||||
const screenSize = useScreenSizeContext();
|
const screenSize = useScreenSizeContext();
|
||||||
const theme = useTheme()
|
const theme = useTheme()
|
||||||
const isMobile = screenSize === ScreenSize.Mobile;
|
const isMobile = screenSize === ScreenSize.Mobile;
|
||||||
const { roomIdOrAlias: viewedRoomId } = useParams();
|
|
||||||
const isViewingActiveCall = useMemo(
|
|
||||||
() => activeCallRoomId !== null && activeCallRoomId === viewedRoomId,
|
|
||||||
[activeCallRoomId, viewedRoomId]
|
|
||||||
);
|
|
||||||
|
|
||||||
/* eslint-disable no-param-reassign */
|
/* eslint-disable no-param-reassign */
|
||||||
|
|
||||||
|
|
@ -56,17 +51,19 @@ export function PersistentCallContainer({ children }: PersistentCallContainerPro
|
||||||
themeKind: ThemeKind | null
|
themeKind: ThemeKind | null
|
||||||
) => {
|
) => {
|
||||||
if (mx?.getUserId()) {
|
if (mx?.getUserId()) {
|
||||||
logger.debug(`CallContextJ: iframe src - ${iframeRef.current.src}`)
|
logger.debug(`PersistentCallContainer: (setupWidget) activeCallRoomId: ${activeCallRoomId} viewedId: ${viewedCallRoomId} isactive: ${isActiveCallReady}`)
|
||||||
logger.debug(`CallContextJ: activeCallRoomId: ${activeCallRoomId} viewedId: ${viewedCallRoomId} isactive: ${isActiveCallReady}`)
|
|
||||||
if (
|
if (
|
||||||
(activeCallRoomId !== viewedCallRoomId && isActiveCallReady) ||
|
(activeCallRoomId !== viewedCallRoomId && isActiveCallReady) ||
|
||||||
(activeCallRoomId && !isActiveCallReady) ||
|
(activeCallRoomId && !isActiveCallReady) ||
|
||||||
(!activeCallRoomId && viewedCallRoomId && !isActiveCallReady)
|
(!activeCallRoomId && viewedCallRoomId && !isActiveCallReady)
|
||||||
) {
|
) {
|
||||||
|
|
||||||
const roomIdToSet = (skipLobby ? activeCallRoomId : viewedCallRoomId) ?? '';
|
const roomIdToSet = (skipLobby ? activeCallRoomId : viewedCallRoomId) ?? '';
|
||||||
|
|
||||||
if (roomIdToSet === '') {
|
if (roomIdToSet === '') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const widgetId = `element-call-${roomIdToSet}-${Date.now()}`;
|
const widgetId = `element-call-${roomIdToSet}-${Date.now()}`;
|
||||||
const newUrl = getWidgetUrl(
|
const newUrl = getWidgetUrl(
|
||||||
mx,
|
mx,
|
||||||
|
|
@ -82,8 +79,8 @@ export function PersistentCallContainer({ children }: PersistentCallContainerPro
|
||||||
);
|
);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
primarySmallWidgetRef.current?.roomId &&
|
callSmallWidgetRef.current?.roomId &&
|
||||||
(activeClientWidget?.roomId && activeClientWidget.roomId === primarySmallWidgetRef.current?.roomId)
|
(activeClientWidget?.roomId && activeClientWidget.roomId === callSmallWidgetRef.current?.roomId)
|
||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -134,30 +131,27 @@ export function PersistentCallContainer({ children }: PersistentCallContainerPro
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
logger.debug(`CallContextJ: ${isActiveCallReady} ${isViewingActiveCall}`)
|
|
||||||
}, [isActiveCallReady, isViewingActiveCall])
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (activeCallRoomId){
|
if (activeCallRoomId){
|
||||||
setupWidget(primaryWidgetApiRef, primarySmallWidgetRef, primaryIframeRef, true, theme.kind);
|
setupWidget(callWidgetApiRef, callSmallWidgetRef, callIframeRef, true, theme.kind);
|
||||||
logger.debug(`CallContextJ: set primary widget: ${primaryWidgetApiRef.current?.eventNames()} ${primarySmallWidgetRef.current} ${primaryIframeRef.current?.baseURI}`)
|
logger.debug(`PersistentCallContainer: set call widget: ${callWidgetApiRef.current?.eventNames()} ${callSmallWidgetRef.current} ${callIframeRef.current?.baseURI}`)
|
||||||
}
|
}
|
||||||
}, [
|
}, [
|
||||||
theme,
|
theme,
|
||||||
setupWidget,
|
setupWidget,
|
||||||
primaryWidgetApiRef,
|
callWidgetApiRef,
|
||||||
primarySmallWidgetRef,
|
callSmallWidgetRef,
|
||||||
primaryIframeRef,
|
callIframeRef,
|
||||||
registerActiveClientWidgetApi,
|
registerActiveClientWidgetApi,
|
||||||
activeCallRoomId,
|
activeCallRoomId,
|
||||||
viewedCallRoomId,
|
viewedCallRoomId,
|
||||||
isActiveCallReady
|
isActiveCallReady
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const memoizedIframeRef = useMemo(() => primaryIframeRef, [primaryIframeRef]);
|
const memoizedIframeRef = useMemo(() => callIframeRef, [callIframeRef]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PrimaryRefContext.Provider value={memoizedIframeRef}>
|
<CallRefContext.Provider value={memoizedIframeRef}>
|
||||||
<Box grow="No">
|
<Box grow="No">
|
||||||
<Box
|
<Box
|
||||||
direction="Column"
|
direction="Column"
|
||||||
|
|
@ -176,7 +170,7 @@ export function PersistentCallContainer({ children }: PersistentCallContainerPro
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<iframe
|
<iframe
|
||||||
ref={primaryIframeRef}
|
ref={callIframeRef}
|
||||||
style={{
|
style={{
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
top: 0,
|
top: 0,
|
||||||
|
|
@ -195,6 +189,6 @@ export function PersistentCallContainer({ children }: PersistentCallContainerPro
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
{children}
|
{children}
|
||||||
</PrimaryRefContext.Provider>
|
</CallRefContext.Provider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue