mirror of
https://github.com/cinnyapp/cinny.git
synced 2025-11-06 15:30:27 +03:00
Remove unneeded comments and imports and clean up name of Edget to SmallWidget
This commit is contained in:
parent
9c5fde3258
commit
eba9670664
1 changed files with 73 additions and 145 deletions
|
|
@ -1,209 +1,149 @@
|
||||||
import React, { useEffect, useRef, useMemo } from 'react';
|
import React, { useEffect, useRef } from 'react';
|
||||||
import { logger } from 'matrix-js-sdk/lib/logger';
|
import { logger } from 'matrix-js-sdk/lib/logger';
|
||||||
import { ClientWidgetApi, IWidgetApiRequest, MatrixCapabilities } from 'matrix-widget-api'; // Assuming imports
|
import { ClientWidgetApi, IWidgetApiRequest } from 'matrix-widget-api';
|
||||||
|
import { Box } from 'folds';
|
||||||
// --- Required Imports (Adjust paths as needed) ---
|
|
||||||
import { useCallState } from '../client/CallProvider';
|
import { useCallState } from '../client/CallProvider';
|
||||||
import {
|
import {
|
||||||
createVirtualWidget,
|
createVirtualWidget,
|
||||||
Edget,
|
SmallWidget,
|
||||||
getWidgetData,
|
getWidgetData,
|
||||||
getWidgetUrl,
|
getWidgetUrl,
|
||||||
} from '../../features/room/SmallWidget';
|
} from '../../features/room/SmallWidget';
|
||||||
import { useMatrixClient } from '../../hooks/useMatrixClient';
|
import { useMatrixClient } from '../../hooks/useMatrixClient';
|
||||||
import { RoomViewHeader } from '../../features/room/RoomViewHeader';
|
import { RoomViewHeader } from '../../features/room/RoomViewHeader';
|
||||||
import { PowerLevelsContextProvider, usePowerLevels } from '../../hooks/usePowerLevels';
|
|
||||||
import { Box } from 'folds';
|
|
||||||
import { IsDirectRoomProvider, RoomProvider, useRoom } from '../../hooks/useRoom';
|
|
||||||
import { useSelectedRoom } from '../../hooks/router/useSelectedRoom';
|
|
||||||
import { Page, PageRoot } from '../../components/page';
|
import { Page, PageRoot } from '../../components/page';
|
||||||
import { RouteSpaceProvider, Space, SpaceRouteRoomProvider } from '../client/space';
|
import { RouteSpaceProvider, Space, SpaceRouteRoomProvider } from '../client/space';
|
||||||
import { MobileFriendlyPageNav } from '../MobileFriendly';
|
import { MobileFriendlyPageNav } from '../MobileFriendly';
|
||||||
import { SPACE_PATH } from '../paths';
|
import { SPACE_PATH } from '../paths';
|
||||||
import { SpaceProvider } from '../../hooks/useSpace';
|
import { PowerLevelsContextProvider } from '../../hooks/usePowerLevels';
|
||||||
import { useSelectedSpace } from '../../hooks/router/useSelectedSpace';
|
import { useSelectedRoom } from '../../hooks/router/useSelectedRoom';
|
||||||
import { useAtomValue } from 'jotai';
|
|
||||||
import { mDirectAtom } from '../../state/mDirectList';
|
|
||||||
|
|
||||||
// --- Component Props ---
|
|
||||||
interface PersistentCallContainerProps {
|
interface PersistentCallContainerProps {
|
||||||
isVisible: boolean; // Prop passed from parent to control display
|
isVisible: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- PersistentCallContainer Component ---
|
|
||||||
|
|
||||||
export function PersistentCallContainer({ isVisible }: PersistentCallContainerProps) {
|
export function PersistentCallContainer({ isVisible }: PersistentCallContainerProps) {
|
||||||
// Global state access
|
const { activeCallRoomId, setActiveCallRoomId } = useCallState();
|
||||||
const { activeCallRoomId, setActiveCallRoomId } = useCallState(); // Get setter for hangup action
|
|
||||||
const mx = useMatrixClient();
|
const mx = useMatrixClient();
|
||||||
|
const room = useSelectedRoom();
|
||||||
|
|
||||||
|
logger.info(room);
|
||||||
|
|
||||||
// Refs
|
|
||||||
const iframeRef = useRef<HTMLIFrameElement | null>(null);
|
const iframeRef = useRef<HTMLIFrameElement | null>(null);
|
||||||
const widgetApiRef = useRef<ClientWidgetApi | null>(null);
|
const widgetApiRef = useRef<ClientWidgetApi | null>(null);
|
||||||
const edgetRef = useRef<Edget | null>(null);
|
const smallWidgetRef = useRef<SmallWidget | null>(null);
|
||||||
|
|
||||||
// Effect to manage iframe src and Widget API lifecycle based SOLELY on activeCallRoomId
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Store the room ID associated with the current Edget instance for clearer cleanup logging
|
const cleanupRoomId = smallWidgetRef.current?.roomId;
|
||||||
const cleanupRoomId = edgetRef.current?.roomId;
|
|
||||||
logger.debug(`PersistentCallContainer effect running. activeCallRoomId: ${activeCallRoomId}`);
|
logger.debug(`PersistentCallContainer effect running. activeCallRoomId: ${activeCallRoomId}`);
|
||||||
|
|
||||||
// --- Cleanup Function ---
|
|
||||||
// This runs BEFORE the effect runs again OR when the component unmounts.
|
|
||||||
// Crucially, it cleans up resources associated with the *previous* activeCallRoomId.
|
|
||||||
const cleanup = () => {
|
const cleanup = () => {
|
||||||
logger.info(`PersistentCallContainer: Cleaning up for previous room: ${cleanupRoomId}`);
|
logger.error(`PersistentCallContainer: Cleaning up for previous room: ${cleanupRoomId}`);
|
||||||
if (edgetRef.current) {
|
if (smallWidgetRef.current) {
|
||||||
// Ensure stopMessaging handles removing listeners etc.
|
smallWidgetRef.current.stopMessaging();
|
||||||
edgetRef.current.stopMessaging();
|
|
||||||
}
|
}
|
||||||
// Potentially call widgetApi.stop() or similar if the API instance has it
|
// Potentially call widgetApi.stop() or similar if the API instance has it
|
||||||
if (widgetApiRef.current) {
|
if (widgetApiRef.current) {
|
||||||
// widgetApiRef.current.stop?.(); // Example
|
// widgetApiRef.current.stop?.();
|
||||||
}
|
}
|
||||||
// Clear refs for the old instances
|
|
||||||
widgetApiRef.current = null;
|
widgetApiRef.current = null;
|
||||||
edgetRef.current = null;
|
smallWidgetRef.current = null;
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- Setup Logic for NEW activeCallRoomId ---
|
|
||||||
if (activeCallRoomId && mx?.getUserId()) {
|
if (activeCallRoomId && mx?.getUserId()) {
|
||||||
// --- 1. Generate new URL and App definition ---
|
const newUrl = getWidgetUrl(mx, activeCallRoomId);
|
||||||
const newUrl = getWidgetUrl(mx, activeCallRoomId); // Use activeCallRoomId
|
|
||||||
const userId = mx.getUserId() ?? '';
|
const userId = mx.getUserId() ?? '';
|
||||||
const app = createVirtualWidget(
|
const app = createVirtualWidget(
|
||||||
mx,
|
mx,
|
||||||
`element-call-${activeCallRoomId}`, // ID based on active room
|
`element-call-${activeCallRoomId}`,
|
||||||
userId,
|
userId,
|
||||||
'Element Call',
|
'Element Call',
|
||||||
'm.call',
|
'm.call',
|
||||||
newUrl,
|
newUrl,
|
||||||
false,
|
false,
|
||||||
// Pass activeCallRoomId to getWidgetData
|
getWidgetData(mx, activeCallRoomId, {}, { skipLobby: true }),
|
||||||
getWidgetData(mx, activeCallRoomId, {}, { skipLobby: true /* other configs */ }),
|
activeCallRoomId
|
||||||
activeCallRoomId // Pass activeCallRoomId as the room ID for the widget context
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// --- 2. Update iframe src ---
|
|
||||||
// This triggers the iframe reload if the src is different.
|
|
||||||
// The cleanup function from the *previous* effect run will have already cleaned up the old API connection.
|
|
||||||
if (iframeRef.current && iframeRef.current.src !== newUrl.toString()) {
|
if (iframeRef.current && iframeRef.current.src !== newUrl.toString()) {
|
||||||
logger.info(
|
logger.info(
|
||||||
`PersistentCallContainer: Updating iframe src for ${activeCallRoomId} to ${newUrl.toString()}`
|
`PersistentCallContainer: Updating iframe src for ${activeCallRoomId} to ${newUrl.toString()}`
|
||||||
);
|
);
|
||||||
iframeRef.current.src = newUrl.toString();
|
iframeRef.current.src = newUrl.toString();
|
||||||
} else if (iframeRef.current && !iframeRef.current.src) {
|
} else if (iframeRef.current && !iframeRef.current.src) {
|
||||||
// Handle initial load case if src starts blank
|
|
||||||
logger.info(
|
logger.info(
|
||||||
`PersistentCallContainer: Setting initial iframe src for ${activeCallRoomId} to ${newUrl.toString()}`
|
`PersistentCallContainer: Setting initial iframe src for ${activeCallRoomId} to ${newUrl.toString()}`
|
||||||
);
|
);
|
||||||
iframeRef.current.src = newUrl.toString();
|
iframeRef.current.src = newUrl.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- 3. Setup new Widget API connection ---
|
|
||||||
const iframeElement = iframeRef.current;
|
const iframeElement = iframeRef.current;
|
||||||
if (!iframeElement) {
|
if (!iframeElement) {
|
||||||
logger.error('PersistentCallContainer: iframeRef is null, cannot setup API.');
|
logger.error('PersistentCallContainer: iframeRef is null, cannot setup API.');
|
||||||
return cleanup; // Should not happen if iframe is always rendered
|
return cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create and store new Edget instance
|
logger.debug(`PersistentCallContainer: Creating new SmallWidget/API for ${activeCallRoomId}`);
|
||||||
logger.debug(`PersistentCallContainer: Creating new Edget/API for ${activeCallRoomId}`);
|
const smallWidget = new SmallWidget(app);
|
||||||
const edget = new Edget(app);
|
smallWidgetRef.current = smallWidget;
|
||||||
edgetRef.current = edget; // Store ref to new instance
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const widgetApiInstance = edget.startMessaging(iframeElement);
|
const widgetApiInstance = smallWidget.startMessaging(iframeElement);
|
||||||
widgetApiRef.current = widgetApiInstance; // Store ref to new instance
|
widgetApiRef.current = widgetApiInstance;
|
||||||
|
|
||||||
// --- 4. Add necessary listeners to the NEW widgetApiInstance ---
|
|
||||||
widgetApiInstance.once('ready', () => {
|
widgetApiInstance.once('ready', () => {
|
||||||
logger.info(`PersistentCallContainer: Widget for ${activeCallRoomId} is ready.`);
|
logger.info(`PersistentCallContainer: Widget for ${activeCallRoomId} is ready.`);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Example listener for read_events (adjust as needed)
|
/* Default handling seems bugged on this. Element does not need this in their driver or codebase, but
|
||||||
|
we do. I believe down the road update_state will be used by element-call and this can be removed.
|
||||||
|
*/
|
||||||
widgetApiInstance.on(
|
widgetApiInstance.on(
|
||||||
'action:org.matrix.msc2876.read_events',
|
'action:org.matrix.msc2876.read_events',
|
||||||
(ev: CustomEvent<IWidgetApiRequest>) => {
|
(ev: CustomEvent<IWidgetApiRequest>) => {
|
||||||
logger.info(`PersistentCallContainer: Widget requested 'read_events':`, ev.detail.data);
|
logger.info(`PersistentCallContainer: Widget requested 'read_events':`, ev.detail.data);
|
||||||
ev.preventDefault(); // Prevent default driver handling
|
ev.preventDefault();
|
||||||
// Use the current widgetApiRef to reply
|
|
||||||
widgetApiRef.current?.transport?.reply(ev.detail, { approved: true });
|
widgetApiRef.current?.transport?.reply(ev.detail, { approved: true });
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
// Listener for hangup action from the widget
|
|
||||||
widgetApiInstance.on('action:im.vector.hangup', () => {
|
widgetApiInstance.on('action:im.vector.hangup', () => {
|
||||||
logger.info(
|
logger.info(
|
||||||
`PersistentCallContainer: Received hangup action from widget in room ${activeCallRoomId}.`
|
`PersistentCallContainer: Received hangup action from widget in room ${activeCallRoomId}.`
|
||||||
);
|
);
|
||||||
// Call the global state function to clear the active call
|
if (smallWidgetRef.current?.roomId === activeCallRoomId) {
|
||||||
// Check if we are still the active call before clearing, prevents race conditions
|
|
||||||
if (edgetRef.current?.roomId === activeCallRoomId) {
|
|
||||||
setActiveCallRoomId(null);
|
setActiveCallRoomId(null);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Add other listeners (TURN servers, etc.)...
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error(
|
logger.error(
|
||||||
`PersistentCallContainer: Error initializing widget messaging for ${activeCallRoomId}:`,
|
`PersistentCallContainer: Error initializing widget messaging for ${activeCallRoomId}:`,
|
||||||
error
|
error
|
||||||
);
|
);
|
||||||
// Cleanup immediately if setup fails
|
|
||||||
cleanup();
|
cleanup();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// --- No active call ---
|
|
||||||
// Ensure src is blank and perform cleanup for any previous instance
|
|
||||||
if (iframeRef.current && iframeRef.current.src !== 'about:blank') {
|
if (iframeRef.current && iframeRef.current.src !== 'about:blank') {
|
||||||
logger.info('PersistentCallContainer: No active call, setting src to about:blank');
|
logger.info('PersistentCallContainer: No active call, setting src to about:blank');
|
||||||
iframeRef.current.src = 'about:blank';
|
iframeRef.current.src = 'about:blank';
|
||||||
}
|
}
|
||||||
// Run cleanup in case an instance was active before becoming null
|
|
||||||
cleanup();
|
cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the cleanup function to be executed when dependencies change or component unmounts
|
|
||||||
return cleanup;
|
return cleanup;
|
||||||
|
|
||||||
// CRITICAL Dependencies: This effect manages the lifecycle based on the active call ID
|
|
||||||
}, [activeCallRoomId, mx, setActiveCallRoomId]);
|
}, [activeCallRoomId, mx, setActiveCallRoomId]);
|
||||||
|
|
||||||
// --- Render ---
|
|
||||||
// Apply conditional styling based on the isVisible prop passed by the parent
|
|
||||||
const containerStyle: React.CSSProperties = {
|
const containerStyle: React.CSSProperties = {
|
||||||
width: '100%',
|
width: '100%',
|
||||||
height: '100%',
|
height: '100%',
|
||||||
// --- Visibility Control ---
|
|
||||||
top: '1',
|
top: '1',
|
||||||
left: '1',
|
left: '1',
|
||||||
display: isVisible ? 'flex' : 'none', // Use flex/block as appropriate for your layout
|
display: isVisible ? 'flex' : 'none',
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
//overflow: 'hidden',
|
|
||||||
};
|
};
|
||||||
const roomId = useSelectedRoom();
|
|
||||||
const room = mx.getRoom(roomId);
|
|
||||||
const selectedSpaceId = useSelectedSpace();
|
|
||||||
const space = mx.getRoom(selectedSpaceId);
|
|
||||||
const mDirects = useAtomValue(mDirectAtom);
|
|
||||||
const powerLevels = usePowerLevels(room);
|
|
||||||
|
|
||||||
// Assuming necessary imports: React, Box, Page, PageRoot, MobileFriendlyPageNav,
|
|
||||||
// Space, RoomViewHeader, iframeRef, PowerLevelsContextProvider,
|
|
||||||
// RouteSpaceProvider, SpaceRouteRoomProvider, SPACE_PATH, powerLevels, containerStyle
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
// Outer container div controlled by parent via isVisible prop
|
<Page style={containerStyle}>
|
||||||
<div style={containerStyle}>
|
|
||||||
{/* Context provider(s) needed by components inside */}
|
|
||||||
{/* Pass actual powerLevels if required */}
|
|
||||||
<PowerLevelsContextProvider value={powerLevels}>
|
|
||||||
{/* Route/Space specific context providers MUST wrap both Space and Header */}
|
|
||||||
{/* Main layout container inside providers: Flex Row */}
|
|
||||||
{/* Assuming Box handles flex layout */}
|
|
||||||
<Box direction="Row" grow="Yes" style={{ height: '100%', width: '100%' }}>
|
<Box direction="Row" grow="Yes" style={{ height: '100%', width: '100%' }}>
|
||||||
{/* --- Left Side (Nav/Space) --- */}
|
{activeCallRoomId && room && (
|
||||||
<Box
|
<Box
|
||||||
shrink="No"
|
shrink="No"
|
||||||
style={{
|
style={{
|
||||||
|
|
@ -215,13 +155,9 @@ export function PersistentCallContainer({ isVisible }: PersistentCallContainerPr
|
||||||
>
|
>
|
||||||
<RouteSpaceProvider>
|
<RouteSpaceProvider>
|
||||||
<SpaceRouteRoomProvider>
|
<SpaceRouteRoomProvider>
|
||||||
{' '}
|
|
||||||
{/* Example style */}
|
|
||||||
{/* PageRoot likely renders the nav prop */}
|
|
||||||
<PageRoot
|
<PageRoot
|
||||||
nav={
|
nav={
|
||||||
<MobileFriendlyPageNav path={SPACE_PATH}>
|
<MobileFriendlyPageNav path={SPACE_PATH}>
|
||||||
{/* Space component requires the providers above */}
|
|
||||||
<Space />
|
<Space />
|
||||||
</MobileFriendlyPageNav>
|
</MobileFriendlyPageNav>
|
||||||
}
|
}
|
||||||
|
|
@ -229,33 +165,28 @@ export function PersistentCallContainer({ isVisible }: PersistentCallContainerPr
|
||||||
</SpaceRouteRoomProvider>
|
</SpaceRouteRoomProvider>
|
||||||
</RouteSpaceProvider>
|
</RouteSpaceProvider>
|
||||||
</Box>
|
</Box>
|
||||||
{/* --- Right Side (Header + Iframe) --- */}
|
)}
|
||||||
{/* This Box takes remaining space and arranges header/iframe vertically */}
|
|
||||||
<Box
|
<Box
|
||||||
grow="Yes"
|
grow="Yes"
|
||||||
direction="Column"
|
direction="Column"
|
||||||
style={{ height: '100%', width: '100%', overflow: 'hidden' }}
|
style={{ height: '100%', width: '100%', overflow: 'hidden' }}
|
||||||
>
|
>
|
||||||
{/* Header Area */}
|
{activeCallRoomId && room && (
|
||||||
<Box grow="No">
|
<Box grow="No">
|
||||||
{' '}
|
<PowerLevelsContextProvider value={null}>
|
||||||
{/* Header doesn't grow/shrink */}
|
|
||||||
{/* RoomViewHeader requires the providers above */}
|
|
||||||
<RouteSpaceProvider>
|
<RouteSpaceProvider>
|
||||||
<SpaceRouteRoomProvider>
|
<SpaceRouteRoomProvider>
|
||||||
<RoomViewHeader />
|
<RoomViewHeader />
|
||||||
</SpaceRouteRoomProvider>
|
</SpaceRouteRoomProvider>
|
||||||
</RouteSpaceProvider>
|
</RouteSpaceProvider>
|
||||||
|
</PowerLevelsContextProvider>
|
||||||
</Box>
|
</Box>
|
||||||
|
)}
|
||||||
{/* Iframe Area (takes remaining space) */}
|
|
||||||
<Box grow="Yes" style={{ position: 'relative' }}>
|
<Box grow="Yes" style={{ position: 'relative' }}>
|
||||||
{' '}
|
|
||||||
{/* Use relative positioning for absolute child */}
|
|
||||||
<iframe
|
<iframe
|
||||||
ref={iframeRef}
|
ref={iframeRef}
|
||||||
style={{
|
style={{
|
||||||
// Use absolute positioning to fill the parent Box
|
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
top: 0,
|
top: 0,
|
||||||
left: 0,
|
left: 0,
|
||||||
|
|
@ -266,14 +197,11 @@ export function PersistentCallContainer({ isVisible }: PersistentCallContainerPr
|
||||||
title={`Persistent Element Call`}
|
title={`Persistent Element Call`}
|
||||||
sandbox="allow-forms allow-scripts allow-same-origin allow-popups allow-modals allow-downloads"
|
sandbox="allow-forms allow-scripts allow-same-origin allow-popups allow-modals allow-downloads"
|
||||||
allow="microphone; camera; display-capture; autoplay; clipboard-write;"
|
allow="microphone; camera; display-capture; autoplay; clipboard-write;"
|
||||||
src="about:blank" // useEffect sets the correct src
|
src="about:blank"
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>{' '}
|
</Box>
|
||||||
{/* End Right Side Box */}
|
</Box>
|
||||||
</Box>{' '}
|
</Page>
|
||||||
{/* End Main Layout Box (Row) */}
|
|
||||||
</PowerLevelsContextProvider>
|
|
||||||
</div> // End Outer Container Div
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue