clean up ts/eslint errors

This commit is contained in:
YoJames2019 2026-02-10 10:56:00 -05:00
parent 5b3a0f1334
commit 40957632d5
5 changed files with 89 additions and 86 deletions

View file

@ -1,5 +1,5 @@
import { Room } from 'matrix-js-sdk';
import React, { useContext, useMemo, useCallback, useEffect, useRef, MouseEventHandler, useState, ReactNode } from 'react';
import React, { useContext, useCallback, useEffect, useRef, MouseEventHandler, useState, ReactNode } from 'react';
import { Box, Button, config, Spinner, Text } from 'folds';
import { useCallState } from '../../pages/client/call/CallProvider';
import { useCallMembers } from '../../hooks/useCallMemberships';
@ -157,7 +157,7 @@ export function CallView({ room }: { room: Room }) {
navigateRoom(room.roomId);
}
if (!callIsCurrentAndReady) {
hangUp(room.roomId);
hangUp();
setActiveCallRoomId(room.roomId);
}
};

View file

@ -77,6 +77,7 @@ export interface IApp extends IWidget {
roomId: string;
eventId?: string;
avatar_url?: string;
sender: string;
'io.element.managed_hybrid'?: boolean;
}
@ -91,7 +92,7 @@ export class SmallWidget extends EventEmitter {
public url?: string;
public iframe: HTMLElement | null;
public iframe: HTMLIFrameElement | null = null;
private type: string; // Type of the widget (e.g., 'm.call')
@ -143,8 +144,11 @@ export class SmallWidget extends EventEmitter {
// Timelines are most recent last
const events = room.getLiveTimeline()?.getEvents() || [];
const roomEvent = events[events.length - 1];
if (!roomEvent) continue; // force later code to think the room is fresh
this.readUpToMap[room.roomId] = roomEvent.getId()!;
// force later code to think the room is fresh
if (roomEvent) {
const eventId = roomEvent.getId();
if(eventId) this.readUpToMap[room.roomId] = eventId;
}
}
this.messaging.on('action:org.matrix.msc2876.read_events', (ev: CustomEvent) => {
@ -163,28 +167,16 @@ export class SmallWidget extends EventEmitter {
const stateEvents = state.events?.get(type);
for (const [key, eventObject] of stateEvents?.entries() ?? []) {
events.push(eventObject.event);
}
Array.from(stateEvents?.values() ?? []).forEach(eventObject => {
events.push(eventObject.event)
})
return this.messaging?.transport.reply(ev.detail, { events });
});
/*
this.messaging?.on('action:content_loaded', () => {
this.messaging?.transport?.send('io.element.join', {
audioInput: 'true',
videoInput: 'true',
});
});
*/
this.client.on(ClientEvent.Event, this.onEvent);
this.client.on(MatrixEventEvent.Decrypted, this.onEventDecrypted);
//this.client.on(RoomStateEvent.Events, this.onStateUpdate);
this.client.on(ClientEvent.ToDeviceEvent, this.onToDeviceEvent);
//this.client.on(RoomStateEvent.Events, this.onReadEvent);
// this.messaging.setViewedRoomId(this.roomId ?? null);
this.messaging.on(
`action:${WidgetApiFromWidgetAction.UpdateAlwaysOnScreen}`,
async (ev: CustomEvent<IStickyActionRequest>) => {
@ -196,7 +188,7 @@ export class SmallWidget extends EventEmitter {
this.messaging.transport.reply(ev.detail, {});
}
// Stop being persistent can be done instantly
//MAKE PERSISTENT HERE
// MAKE PERSISTENT HERE
// Send the ack after the widget actually has become sticky.
}
}
@ -272,21 +264,28 @@ export class SmallWidget extends EventEmitter {
const timeline = room.getLiveTimeline();
const events = this.arrayFastClone(timeline.getEvents()).reverse().slice(0, 100);
for (const timelineEvent of events) {
if (timelineEvent.getId() === upToEventId) {
let advanced = false;
events.some(timelineEvent => {
const id = timelineEvent.getId();
if (id === upToEventId) {
// The event must be somewhere before the "read up to" marker
return false;
}
if (timelineEvent.getId() === ev.getId()) {
// The event is after the marker; advance it
this.readUpToMap[roomId] = evId;
return true;
}
}
// We can't say for sure whether the widget has seen the event; let's
// just assume that it has
return false;
if (id === evId) {
// The event is after the marker; advance it
this.readUpToMap[roomId] = evId;
advanced = true;
return true;
}
// We can't say for sure whether the widget has seen the event; let's
// just assume that it has
return false;
});
return advanced;
}
private feedEvent(ev: MatrixEvent): void {
@ -401,12 +400,4 @@ export const createVirtualWidget = (
roomId,
// Add other required fields from IWidget if necessary
sender: creatorUserId, // Example: Assuming sender is the creator
content: {
// Example content structure
type,
url: url.toString(),
name,
data,
creatorUserId,
},
});

View file

@ -60,7 +60,7 @@ export function CallNavStatus() {
>
<Icon src={Icons.VolumeHigh}/>
<Text style={{ flexGrow: 1 }} size="B400" truncate>
{mx.getRoom(activeCallRoomId)?.name}
{activeCallRoomId ? mx.getRoom(activeCallRoomId)?.name : ""}
</Text>
</Chip>
)}

View file

@ -8,7 +8,7 @@ import React, {
useEffect,
} from 'react';
import { logger } from 'matrix-js-sdk/lib/logger';
import { WidgetApiToWidgetAction, WidgetApiAction, ClientWidgetApi } from 'matrix-widget-api';
import { WidgetApiToWidgetAction, WidgetApiAction, ClientWidgetApi, IWidgetApiRequestData } from 'matrix-widget-api';
import { useParams } from 'react-router-dom';
import { SmallWidget } from '../../../features/call/SmallWidget';
@ -30,15 +30,16 @@ interface CallContextState {
setActiveCallRoomId: (roomId: string | null) => void;
viewedCallRoomId: string | null;
setViewedCallRoomId: (roomId: string | null) => void;
hangUp: (room: string) => void;
hangUp: () => void;
activeClientWidgetApi: ClientWidgetApi | null;
activeClientWidget: SmallWidget | null;
registerActiveClientWidgetApi: (
roomId: string | null,
clientWidgetApi: ClientWidgetApi | null,
clientWidget: SmallWidget
clientWidget: SmallWidget,
activeClientIframeRef: HTMLIFrameElement
) => void;
sendWidgetAction: <T = unknown>(
sendWidgetAction: <T extends IWidgetApiRequestData = IWidgetApiRequestData>(
action: WidgetApiToWidgetAction | string,
data: T
) => Promise<void>;
@ -60,7 +61,6 @@ interface CallProviderProps {
const DEFAULT_AUDIO_ENABLED = true;
const DEFAULT_VIDEO_ENABLED = false;
const DEFAULT_CHAT_OPENED = false;
const DEFAULT_CALL_ACTIVE = false;
export function CallProvider({ children }: CallProviderProps) {
const [activeCallRoomId, setActiveCallRoomIdState] = useState<string | null>(null);
@ -69,11 +69,12 @@ export function CallProvider({ children }: CallProviderProps) {
const [activeClientWidgetApi, setActiveClientWidgetApiState] = useState<ClientWidgetApi | null>(null);
const [activeClientWidget, setActiveClientWidget] = useState<SmallWidget | null>(null);
const [activeClientWidgetApiRoomId, setActiveClientWidgetApiRoomId] = useState<string | null>(null);
const [activeClientWidgetIframeRef, setActiveClientWidgetIframeRef] = useState<HTMLIFrameElement | null>(null)
const [isAudioEnabled, setIsAudioEnabledState] = useState<boolean>(DEFAULT_AUDIO_ENABLED);
const [isVideoEnabled, setIsVideoEnabledState] = useState<boolean>(DEFAULT_VIDEO_ENABLED);
const [isChatOpen, setIsChatOpenState] = useState<boolean>(DEFAULT_CHAT_OPENED);
const [isActiveCallReady, setIsActiveCallReady] = useState<boolean>(DEFAULT_CALL_ACTIVE);
const [isActiveCallReady, setIsActiveCallReady] = useState<boolean>(false);
const { roomIdOrAlias: viewedRoomId } = useParams<{ roomIdOrAlias: string }>();
@ -97,11 +98,13 @@ export function CallProvider({ children }: CallProviderProps) {
(
clientWidgetApi: ClientWidgetApi | null,
clientWidget: SmallWidget | null,
roomId: string | null
roomId: string | null,
clientWidgetIframeRef: HTMLIFrameElement | null
) => {
setActiveClientWidgetApiState(clientWidgetApi);
setActiveClientWidget(clientWidget);
setActiveClientWidgetApiRoomId(roomId);
setActiveClientWidgetIframeRef(clientWidgetIframeRef)
},
[]
);
@ -110,17 +113,19 @@ export function CallProvider({ children }: CallProviderProps) {
(
roomId: string | null,
clientWidgetApi: ClientWidgetApi | null,
clientWidget: SmallWidget | null
clientWidget: SmallWidget | null,
clientWidgetIframeRef: HTMLIFrameElement | null
) => {
if (activeClientWidgetApi && activeClientWidgetApi !== clientWidgetApi) {
logger.debug(`CallContext: Cleaning up listeners for previous clientWidgetApi instance.`);
}
if (roomId && clientWidgetApi) {
logger.debug(`CallContext: Registering active clientWidgetApi for room ${roomId}.`);
setActiveClientWidgetApi(clientWidgetApi, clientWidget, roomId);
setActiveClientWidgetApi(clientWidgetApi, clientWidget, roomId, clientWidgetIframeRef);
} else if (roomId === activeClientWidgetApiRoomId || roomId === null) {
setActiveClientWidgetApi(null, null, null);
setActiveClientWidgetApi(null, null, null, null);
}
},
[activeClientWidgetApi, activeClientWidgetApiRoomId, setActiveClientWidgetApi]
@ -128,7 +133,7 @@ export function CallProvider({ children }: CallProviderProps) {
const hangUp = useCallback(
() => {
setActiveClientWidgetApi(null, null, null);
setActiveClientWidgetApi(null, null, null, null);
setActiveCallRoomIdState(null);
activeClientWidgetApi?.transport.send(`${WIDGET_HANGUP_ACTION}`, {});
setIsActiveCallReady(false);
@ -143,7 +148,7 @@ export function CallProvider({ children }: CallProviderProps) {
const sendWidgetAction = useCallback(
async <T = unknown,>(action: WidgetApiToWidgetAction | string, data: T): Promise<void> => {
async <T extends IWidgetApiRequestData = IWidgetApiRequestData,>(action: WidgetApiToWidgetAction | string, data: T): Promise<void> => {
if (!activeClientWidgetApi) {
logger.warn(
`CallContext: Cannot send action '${action}', no active API clientWidgetApi registered.`
@ -163,6 +168,8 @@ export function CallProvider({ children }: CallProviderProps) {
data
);
await activeClientWidgetApi.transport.send(action as WidgetApiAction, data);
return Promise.resolve()
},
[activeClientWidgetApi, activeCallRoomId, activeClientWidgetApiRoomId]
);
@ -211,15 +218,14 @@ export function CallProvider({ children }: CallProviderProps) {
return;
}
const api = activeClientWidgetApi;
if (!api) {
if (!activeClientWidgetApi) {
return;
}
const handleHangup = (ev: CustomEvent) => {
ev.preventDefault();
if (isActiveCallReady && ev.detail.widgetId === activeClientWidgetApi?.widget.id) {
activeClientWidgetApi?.transport.reply(ev.detail, {});
if (isActiveCallReady && ev.detail.widgetId === activeClientWidgetApi.widget.id) {
activeClientWidgetApi.transport.reply(ev.detail, {});
}
logger.debug(
`CallContext: Received hangup action from widget in room ${activeCallRoomId}.`,
@ -251,33 +257,39 @@ export function CallProvider({ children }: CallProviderProps) {
const handleOnScreenStateUpdate = (ev: CustomEvent) => {
ev.preventDefault();
api.transport.reply(ev.detail, {});
activeClientWidgetApi.transport.reply(ev.detail, {});
};
const handleOnTileLayout = (ev: CustomEvent) => {
ev.preventDefault();
api.transport.reply(ev.detail, {});
activeClientWidgetApi.transport.reply(ev.detail, {});
};
const handleJoin = (ev: CustomEvent) => {
ev.preventDefault();
api.transport.reply(ev.detail, {});
activeClientWidgetApi.transport.reply(ev.detail, {});
const iframeDoc =
api.iframe?.contentDocument ||
api.iframe?.contentWindow.document;
const observer = new MutationObserver(() => {
const button = iframeDoc.querySelector('[data-testid="incall_leave"]');
if (button) {
button.addEventListener('click', () => {
hangUp()
});
}
observer.disconnect();
});
logger.debug('Join Call');
observer.observe(iframeDoc, { childList: true, subtree: true });
activeClientWidgetIframeRef?.contentWindow?.document ||
activeClientWidgetIframeRef?.contentDocument;
if(iframeDoc){
const observer = new MutationObserver(() => {
const button = iframeDoc.querySelector('[data-testid="incall_leave"]');
if (button) {
button.addEventListener('click', () => {
hangUp()
});
}
observer.disconnect();
});
logger.debug('Join Call');
observer.observe(iframeDoc, { childList: true, subtree: true });
}
setIsActiveCallReady(true);
};
@ -291,13 +303,14 @@ export function CallProvider({ children }: CallProviderProps) {
video_enabled: isVideoEnabled,
});
api.on(`action:${WIDGET_HANGUP_ACTION}`, handleHangup);
api.on(`action:${WIDGET_MEDIA_STATE_UPDATE_ACTION}`, handleMediaStateUpdate);
api.on(`action:${WIDGET_TILE_UPDATE}`, handleOnTileLayout);
api.on(`action:${WIDGET_ON_SCREEN_ACTION}`, handleOnScreenStateUpdate);
api.on(`action:${WIDGET_JOIN_ACTION}`, handleJoin);
activeClientWidgetApi.on(`action:${WIDGET_HANGUP_ACTION}`, handleHangup);
activeClientWidgetApi.on(`action:${WIDGET_MEDIA_STATE_UPDATE_ACTION}`, handleMediaStateUpdate);
activeClientWidgetApi.on(`action:${WIDGET_TILE_UPDATE}`, handleOnTileLayout);
activeClientWidgetApi.on(`action:${WIDGET_ON_SCREEN_ACTION}`, handleOnScreenStateUpdate);
activeClientWidgetApi.on(`action:${WIDGET_JOIN_ACTION}`, handleJoin);
}, [
activeClientWidgetIframeRef,
activeClientWidgetApi,
activeCallRoomId,
activeClientWidgetApiRoomId,

View file

@ -1,8 +1,7 @@
import React, { createContext, ReactNode, useCallback, useEffect, useMemo, useRef, useState } from 'react';
import React, { createContext, ReactNode, useCallback, useEffect, useMemo, useRef } from 'react';
import { logger } from 'matrix-js-sdk/lib/logger';
import { ClientWidgetApi } from 'matrix-widget-api';
import { Box } from 'folds';
import { useParams } from 'react-router-dom';
import { useCallState } from './CallProvider';
import {
createVirtualWidget,
@ -19,7 +18,7 @@ interface PersistentCallContainerProps {
children: ReactNode;
}
export const CallRefContext = createContext(null);
export const CallRefContext = createContext<React.MutableRefObject<HTMLIFrameElement | null> | null>(null);
export function PersistentCallContainer({ children }: PersistentCallContainerProps) {
const callIframeRef = useRef<HTMLIFrameElement | null>(null);
@ -44,10 +43,10 @@ export function PersistentCallContainer({ children }: PersistentCallContainerPro
const setupWidget = useCallback(
(
widgetApiRef: { current: ClientWidgetApi },
smallWidgetRef: { current: SmallWidget },
iframeRef: { current: { src: string } },
skipLobby: { toString: () => any },
widgetApiRef: React.MutableRefObject<ClientWidgetApi | null>,
smallWidgetRef: React.MutableRefObject<SmallWidget | null>,
iframeRef: React.MutableRefObject<HTMLIFrameElement | null>,
skipLobby: boolean,
themeKind: ThemeKind | null
) => {
if (mx?.getUserId()) {
@ -112,7 +111,7 @@ export function PersistentCallContainer({ children }: PersistentCallContainerPro
const widgetApiInstance = smallWidget.startMessaging(iframeElement);
widgetApiRef.current = widgetApiInstance;
registerActiveClientWidgetApi(roomIdToSet, widgetApiRef.current, smallWidget);
registerActiveClientWidgetApi(roomIdToSet, widgetApiRef.current, smallWidget, iframeElement);
widgetApiInstance.once('ready', () => {
logger.info(`PersistentCallContainer: Widget for ${roomIdToSet} is ready.`);