chore(deps): update dependency element-call from 0.19.1 to v0.20.1 (#2992)

* chore(deps): update dependency @element-hq/element-call-embedded from 0.19.1 to v0.20.1

* fix reaction button click

* fix call settings button query

* fix screenshare and spotlight button state update

* fix incomming call text alignment

* prevent displaying call notification for voice rooms

* disable mic/video icon when toggle in progress

* update matrix-js-sdk

---------

Co-authored-by: Ajay Bura <32841439+ajbura@users.noreply.github.com>
This commit is contained in:
Krishan
2026-06-20 21:20:25 +10:00
committed by GitHub
parent 762e99a907
commit e37971456a
9 changed files with 129 additions and 58 deletions
+21 -17
View File
@@ -43,7 +43,7 @@
"jotai": "2.6.0", "jotai": "2.6.0",
"linkify-react": "4.3.2", "linkify-react": "4.3.2",
"linkifyjs": "4.3.2", "linkifyjs": "4.3.2",
"matrix-js-sdk": "41.5.0", "matrix-js-sdk": "41.7.0",
"matrix-widget-api": "1.16.1", "matrix-widget-api": "1.16.1",
"millify": "6.1.0", "millify": "6.1.0",
"pdfjs-dist": "4.2.67", "pdfjs-dist": "4.2.67",
@@ -66,7 +66,7 @@
"ua-parser-js": "1.0.35" "ua-parser-js": "1.0.35"
}, },
"devDependencies": { "devDependencies": {
"@element-hq/element-call-embedded": "0.19.1", "@element-hq/element-call-embedded": "0.20.1",
"@esbuild-plugins/node-globals-polyfill": "0.2.3", "@esbuild-plugins/node-globals-polyfill": "0.2.3",
"@rollup/plugin-inject": "5.0.3", "@rollup/plugin-inject": "5.0.3",
"@rollup/plugin-wasm": "6.1.1", "@rollup/plugin-wasm": "6.1.1",
@@ -1774,9 +1774,9 @@
} }
}, },
"node_modules/@element-hq/element-call-embedded": { "node_modules/@element-hq/element-call-embedded": {
"version": "0.19.1", "version": "0.20.1",
"resolved": "https://registry.npmjs.org/@element-hq/element-call-embedded/-/element-call-embedded-0.19.1.tgz", "resolved": "https://registry.npmjs.org/@element-hq/element-call-embedded/-/element-call-embedded-0.20.1.tgz",
"integrity": "sha512-RDZY3P3LTx10ACaGhzkwh2+boNB3x54zHF/7v/cCyoQlAVfEYMhgMEb4CRTwJFwwYFe1r++6Higa0A0G5XxZ8Q==", "integrity": "sha512-ODg2r7UmR8UjRpapLKbn6v1PS8fu/r58zdbvXMYaAlUEAC2f6L/9Moc9S4noG1+ARgWxY+m2vLmNDK9G9uFZYQ==",
"dev": true "dev": true
}, },
"node_modules/@emotion/hash": { "node_modules/@emotion/hash": {
@@ -2386,9 +2386,9 @@
} }
}, },
"node_modules/@matrix-org/matrix-sdk-crypto-wasm": { "node_modules/@matrix-org/matrix-sdk-crypto-wasm": {
"version": "18.3.0", "version": "18.3.1",
"resolved": "https://registry.npmjs.org/@matrix-org/matrix-sdk-crypto-wasm/-/matrix-sdk-crypto-wasm-18.3.0.tgz", "resolved": "https://registry.npmjs.org/@matrix-org/matrix-sdk-crypto-wasm/-/matrix-sdk-crypto-wasm-18.3.1.tgz",
"integrity": "sha512-9a4feyt8QLysARu7PHKaRWT+wcCd+IYH074LXp9QK5WqfN4zUXueRhiSSMNT18Bm+8q3sBR/4zxDxOSDR0M8Kg==", "integrity": "sha512-VRjWhE1UgHnPpJ3b9B5+8z71ZC/HICFngPPFIN6ktzmUBKI5RusPujzbAQUoB3CgZ0yU58L99AfSQS4YTztSWw==",
"license": "Apache-2.0", "license": "Apache-2.0",
"engines": { "engines": {
"node": ">= 18" "node": ">= 18"
@@ -6216,12 +6216,16 @@
"optional": true "optional": true
}, },
"node_modules/content-type": { "node_modules/content-type": {
"version": "1.0.5", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.0.0.tgz",
"integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", "integrity": "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">= 0.6" "node": ">=18"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/express"
} }
}, },
"node_modules/conventional-commit-types": { "node_modules/conventional-commit-types": {
@@ -10106,16 +10110,16 @@
"license": "Apache-2.0" "license": "Apache-2.0"
}, },
"node_modules/matrix-js-sdk": { "node_modules/matrix-js-sdk": {
"version": "41.5.0", "version": "41.7.0",
"resolved": "https://registry.npmjs.org/matrix-js-sdk/-/matrix-js-sdk-41.5.0.tgz", "resolved": "https://registry.npmjs.org/matrix-js-sdk/-/matrix-js-sdk-41.7.0.tgz",
"integrity": "sha512-CK3h+qQJ4wkVEUgEWc5MdLjccXyiFqncCC53P+auqOhnX2U6tAFsRfnbML1QQiKIsFMzqTrAnF/4a5LUUOIeXg==", "integrity": "sha512-MP0xNv/VVRbshq00TE6EVo77IIXsQk0KjiVtgKV0t9j/V77a6Klt00QrrO0XykkTUsNC0+mQeBMxnx75rZO86Q==",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.12.5", "@babel/runtime": "^7.12.5",
"@matrix-org/matrix-sdk-crypto-wasm": "^18.2.0", "@matrix-org/matrix-sdk-crypto-wasm": "^18.3.1",
"another-json": "^0.2.0", "another-json": "^0.2.0",
"bs58": "^6.0.0", "bs58": "^6.0.0",
"content-type": "^1.0.4", "content-type": "^2.0.0",
"jwt-decode": "^4.0.0", "jwt-decode": "^4.0.0",
"loglevel": "^1.9.2", "loglevel": "^1.9.2",
"matrix-events-sdk": "0.0.1", "matrix-events-sdk": "0.0.1",
+2 -2
View File
@@ -67,7 +67,7 @@
"jotai": "2.6.0", "jotai": "2.6.0",
"linkify-react": "4.3.2", "linkify-react": "4.3.2",
"linkifyjs": "4.3.2", "linkifyjs": "4.3.2",
"matrix-js-sdk": "41.5.0", "matrix-js-sdk": "41.7.0",
"matrix-widget-api": "1.16.1", "matrix-widget-api": "1.16.1",
"millify": "6.1.0", "millify": "6.1.0",
"pdfjs-dist": "4.2.67", "pdfjs-dist": "4.2.67",
@@ -90,7 +90,7 @@
"ua-parser-js": "1.0.35" "ua-parser-js": "1.0.35"
}, },
"devDependencies": { "devDependencies": {
"@element-hq/element-call-embedded": "0.19.1", "@element-hq/element-call-embedded": "0.20.1",
"@esbuild-plugins/node-globals-polyfill": "0.2.3", "@esbuild-plugins/node-globals-polyfill": "0.2.3",
"@rollup/plugin-inject": "5.0.3", "@rollup/plugin-inject": "5.0.3",
"@rollup/plugin-wasm": "6.1.1", "@rollup/plugin-wasm": "6.1.1",
+5 -2
View File
@@ -148,11 +148,13 @@ function IncomingCall({ dm, info, onIgnore, onAnswer, onReject }: IncomingCallPr
/> />
</Avatar> </Avatar>
</Box> </Box>
<Box grow="Yes" direction="Column" gap="100"> <Box grow="Yes" direction="Column" gap="100" alignItems="Center">
<Text size="H3" align="Center" truncate> <Text size="H3" align="Center" truncate>
{roomName} {roomName}
</Text> </Text>
<Text size="T300">Incoming Call</Text> <Text size="T300" align="Center">
Incoming Call
</Text>
</Box> </Box>
</Box> </Box>
{!livekitSupported && ( {!livekitSupported && (
@@ -237,6 +239,7 @@ function IncomingCallListener({ callEmbed, joined }: IncomingCallListenerProps)
// only process rtc notification reference events. // only process rtc notification reference events.
// we do not want to wait to decrypt all events. // we do not want to wait to decrypt all events.
if (event.getRelation()?.rel_type !== RelationType.Reference) return; if (event.getRelation()?.rel_type !== RelationType.Reference) return;
if (room?.isCallRoom()) return;
if (event.isEncrypted()) { if (event.isEncrypted()) {
if (!event.isBeingDecrypted()) { if (!event.isBeingDecrypted()) {
+15 -6
View File
@@ -12,6 +12,9 @@ type MicrophoneButtonProps = {
disabled?: boolean; disabled?: boolean;
}; };
function MicrophoneButton({ enabled, onToggle, disabled }: MicrophoneButtonProps) { function MicrophoneButton({ enabled, onToggle, disabled }: MicrophoneButtonProps) {
const [micState, toggleMic] = useAsyncCallback(onToggle);
const loading = micState.status === AsyncStatus.Loading;
return ( return (
<TooltipProvider <TooltipProvider
position="Top" position="Top"
@@ -28,9 +31,9 @@ function MicrophoneButton({ enabled, onToggle, disabled }: MicrophoneButtonProps
fill="Soft" fill="Soft"
radii="300" radii="300"
size="300" size="300"
onClick={() => onToggle()} onClick={toggleMic}
outlined outlined
disabled={disabled} disabled={disabled || loading}
> >
<Icon size="100" src={enabled ? Icons.Mic : Icons.MicMute} filled={!enabled} /> <Icon size="100" src={enabled ? Icons.Mic : Icons.MicMute} filled={!enabled} />
</IconButton> </IconButton>
@@ -82,6 +85,9 @@ type VideoButtonProps = {
disabled?: boolean; disabled?: boolean;
}; };
function VideoButton({ enabled, onToggle, disabled }: VideoButtonProps) { function VideoButton({ enabled, onToggle, disabled }: VideoButtonProps) {
const [videoState, toggleVideo] = useAsyncCallback(onToggle);
const loading = videoState.status === AsyncStatus.Loading;
return ( return (
<TooltipProvider <TooltipProvider
position="Top" position="Top"
@@ -98,9 +104,9 @@ function VideoButton({ enabled, onToggle, disabled }: VideoButtonProps) {
fill="Soft" fill="Soft"
radii="300" radii="300"
size="300" size="300"
onClick={() => onToggle()} onClick={toggleVideo}
outlined outlined
disabled={disabled} disabled={disabled || loading}
> >
<Icon <Icon
size="100" size="100"
@@ -158,6 +164,9 @@ export function CallControl({
const { microphone, video, sound, screenshare } = useCallControlState(callEmbed.control); const { microphone, video, sound, screenshare } = useCallControlState(callEmbed.control);
const setCallEmbed = useSetAtom(callEmbedAtom); const setCallEmbed = useSetAtom(callEmbedAtom);
const handleMicrophoneToggle = useCallback(() => callEmbed.control.toggleMicrophone(), [callEmbed]);
const handleVideoToggle = useCallback(() => callEmbed.control.toggleVideo(), [callEmbed]);
const [hangupState, hangup] = useAsyncCallback( const [hangupState, hangup] = useAsyncCallback(
useCallback(() => callEmbed.hangup(), [callEmbed]) useCallback(() => callEmbed.hangup(), [callEmbed])
); );
@@ -177,7 +186,7 @@ export function CallControl({
<Box alignItems="Inherit" gap="200"> <Box alignItems="Inherit" gap="200">
<MicrophoneButton <MicrophoneButton
enabled={microphone} enabled={microphone}
onToggle={() => callEmbed.control.toggleMicrophone()} onToggle={handleMicrophoneToggle}
disabled={!callJoined} disabled={!callJoined}
/> />
<SoundButton <SoundButton
@@ -188,7 +197,7 @@ export function CallControl({
{!compact && <StatusDivider />} {!compact && <StatusDivider />}
<VideoButton <VideoButton
enabled={video} enabled={video}
onToggle={() => callEmbed.control.toggleVideo()} onToggle={handleVideoToggle}
disabled={!callJoined} disabled={!callJoined}
/> />
{!compact && ( {!compact && (
+5 -2
View File
@@ -71,6 +71,9 @@ export function CallControls({ callEmbed }: CallControlsProps) {
setCords(undefined); setCords(undefined);
}; };
const handleMicrophoneToggle = useCallback(() => callEmbed.control.toggleMicrophone(), [callEmbed]);
const handleVideoToggle = useCallback(() => callEmbed.control.toggleVideo(), [callEmbed]);
const [hangupState, hangup] = useAsyncCallback( const [hangupState, hangup] = useAsyncCallback(
useCallback(() => callEmbed.hangup(), [callEmbed]) useCallback(() => callEmbed.hangup(), [callEmbed])
); );
@@ -96,13 +99,13 @@ export function CallControls({ callEmbed }: CallControlsProps) {
<Box shrink="No" alignItems="Inherit" justifyContent="Inherit" gap="200"> <Box shrink="No" alignItems="Inherit" justifyContent="Inherit" gap="200">
<MicrophoneButton <MicrophoneButton
enabled={microphone} enabled={microphone}
onToggle={() => callEmbed.control.toggleMicrophone()} onToggle={handleMicrophoneToggle}
/> />
<SoundButton enabled={sound} onToggle={() => callEmbed.control.toggleSound()} /> <SoundButton enabled={sound} onToggle={() => callEmbed.control.toggleSound()} />
</Box> </Box>
{!compact && <ControlDivider />} {!compact && <ControlDivider />}
<Box shrink="No" alignItems="Inherit" justifyContent="Inherit" gap="200"> <Box shrink="No" alignItems="Inherit" justifyContent="Inherit" gap="200">
<VideoButton enabled={video} onToggle={() => callEmbed.control.toggleVideo()} /> <VideoButton enabled={video} onToggle={handleVideoToggle} />
<ScreenShareButton <ScreenShareButton
enabled={screenshare} enabled={screenshare}
onToggle={() => callEmbed.control.toggleScreenshare()} onToggle={() => callEmbed.control.toggleScreenshare()}
+13 -4
View File
@@ -3,6 +3,7 @@ import { Icon, IconButton, Icons, Line, Text, Tooltip, TooltipProvider } from 'f
import { useAtom } from 'jotai'; import { useAtom } from 'jotai';
import * as css from './styles.css'; import * as css from './styles.css';
import { callChatAtom } from '../../state/callEmbed'; import { callChatAtom } from '../../state/callEmbed';
import { AsyncStatus, useAsyncCallback } from '../../hooks/useAsyncCallback';
export function ControlDivider() { export function ControlDivider() {
return ( return (
@@ -12,9 +13,12 @@ export function ControlDivider() {
type MicrophoneButtonProps = { type MicrophoneButtonProps = {
enabled: boolean; enabled: boolean;
onToggle: () => void; onToggle: () => Promise<unknown>;
}; };
export function MicrophoneButton({ enabled, onToggle }: MicrophoneButtonProps) { export function MicrophoneButton({ enabled, onToggle }: MicrophoneButtonProps) {
const [micState, toggleMic] = useAsyncCallback(onToggle);
const loading = micState.status === AsyncStatus.Loading;
return ( return (
<TooltipProvider <TooltipProvider
position="Top" position="Top"
@@ -32,8 +36,9 @@ export function MicrophoneButton({ enabled, onToggle }: MicrophoneButtonProps) {
fill="Soft" fill="Soft"
radii="400" radii="400"
size="400" size="400"
onClick={() => onToggle()} onClick={toggleMic}
outlined outlined
disabled={loading}
> >
<Icon size="400" src={enabled ? Icons.Mic : Icons.MicMute} filled={!enabled} /> <Icon size="400" src={enabled ? Icons.Mic : Icons.MicMute} filled={!enabled} />
</IconButton> </IconButton>
@@ -80,9 +85,12 @@ export function SoundButton({ enabled, onToggle }: SoundButtonProps) {
type VideoButtonProps = { type VideoButtonProps = {
enabled: boolean; enabled: boolean;
onToggle: () => void; onToggle: () => Promise<unknown>;
}; };
export function VideoButton({ enabled, onToggle }: VideoButtonProps) { export function VideoButton({ enabled, onToggle }: VideoButtonProps) {
const [videoState, toggleVideo] = useAsyncCallback(onToggle);
const loading = videoState.status === AsyncStatus.Loading;
return ( return (
<TooltipProvider <TooltipProvider
position="Top" position="Top"
@@ -100,8 +108,9 @@ export function VideoButton({ enabled, onToggle }: VideoButtonProps) {
fill="Soft" fill="Soft"
radii="400" radii="400"
size="400" size="400"
onClick={() => onToggle()} onClick={toggleVideo}
outlined outlined
disabled={loading}
> >
<Icon <Icon
size="400" size="400"
+7 -3
View File
@@ -1,4 +1,4 @@
import React from 'react'; import React, { useCallback } from 'react';
import { Box, Button, Icon, Icons, Spinner, Text } from 'folds'; import { Box, Button, Icon, Icons, Spinner, Text } from 'folds';
import { SequenceCard } from '../../components/sequence-card'; import { SequenceCard } from '../../components/sequence-card';
import * as css from './styles.css'; import * as css from './styles.css';
@@ -26,6 +26,10 @@ export function PrescreenControls({ canJoin }: PrescreenControlsProps) {
const { microphone, video, sound, toggleMicrophone, toggleVideo, toggleSound } = const { microphone, video, sound, toggleMicrophone, toggleVideo, toggleSound } =
useCallPreferences(); useCallPreferences();
const handleMicrophoneToggle = useCallback(async () => toggleMicrophone(), [toggleMicrophone]);
const handleVideoToggle = useCallback(async () => toggleVideo(), [toggleVideo]);
return ( return (
<SequenceCard <SequenceCard
className={css.ControlCard} className={css.ControlCard}
@@ -37,12 +41,12 @@ export function PrescreenControls({ canJoin }: PrescreenControlsProps) {
wrap="Wrap" wrap="Wrap"
> >
<Box shrink="No" alignItems="Inherit" justifyContent="SpaceBetween" gap="200"> <Box shrink="No" alignItems="Inherit" justifyContent="SpaceBetween" gap="200">
<MicrophoneButton enabled={microphone} onToggle={toggleMicrophone} /> <MicrophoneButton enabled={microphone} onToggle={handleMicrophoneToggle} />
<SoundButton enabled={sound} onToggle={toggleSound} /> <SoundButton enabled={sound} onToggle={toggleSound} />
</Box> </Box>
<ControlDivider /> <ControlDivider />
<Box shrink="No" alignItems="Inherit" justifyContent="SpaceBetween" gap="200"> <Box shrink="No" alignItems="Inherit" justifyContent="SpaceBetween" gap="200">
<VideoButton enabled={video} onToggle={toggleVideo} /> <VideoButton enabled={video} onToggle={handleVideoToggle} />
<ChatButton /> <ChatButton />
</Box> </Box>
<Box grow="Yes" direction="Column"> <Box grow="Yes" direction="Column">
+57 -7
View File
@@ -14,8 +14,12 @@ export class CallControl extends EventEmitter implements CallControlState {
private iframe: HTMLIFrameElement; private iframe: HTMLIFrameElement;
private bodyMutationObserver: MutationObserver;
private controlMutationObserver: MutationObserver; private controlMutationObserver: MutationObserver;
private mediaStatePromiseResolver: undefined | (() => void);
private get document(): Document | undefined { private get document(): Document | undefined {
return this.iframe.contentDocument ?? this.iframe.contentWindow?.document; return this.iframe.contentDocument ?? this.iframe.contentWindow?.document;
} }
@@ -28,16 +32,25 @@ export class CallControl extends EventEmitter implements CallControlState {
return screenshareBtn ?? undefined; return screenshareBtn ?? undefined;
} }
private get settingsButton(): HTMLElement | undefined { private get leaveButton(): Element | undefined {
const leaveBtn = this.document?.querySelector('[data-testid="incall_leave"]'); const leaveBtn = this.document?.querySelector('[data-testid="incall_leave"]');
const settingsButton = leaveBtn?.previousElementSibling as HTMLElement | null; return leaveBtn ?? undefined;
}
return settingsButton ?? undefined; private get settingsButton(): HTMLElement | undefined {
const settingsButtonLeft = this.document?.querySelector(
'[data-testid="settings-bottom-left"]'
) as HTMLButtonElement | undefined;
const settingsButtonCenter = this.document?.querySelector(
'[data-testid="settings-bottom-center"]'
) as HTMLButtonElement | undefined;
return settingsButtonLeft ?? settingsButtonCenter ?? undefined;
} }
private get reactionsButton(): HTMLElement | undefined { private get reactionsButton(): HTMLElement | undefined {
const reactionsButton = this.settingsButton?.previousElementSibling as HTMLElement | null; const reactionsButton = this.leaveButton?.previousElementSibling as HTMLElement | null;
return reactionsButton ?? undefined; return reactionsButton ?? undefined;
} }
@@ -65,6 +78,7 @@ export class CallControl extends EventEmitter implements CallControlState {
this.call = call; this.call = call;
this.iframe = iframe; this.iframe = iframe;
this.bodyMutationObserver = new MutationObserver(this.onBodyMutation.bind(this));
this.controlMutationObserver = new MutationObserver(this.onControlMutation.bind(this)); this.controlMutationObserver = new MutationObserver(this.onControlMutation.bind(this));
} }
@@ -102,6 +116,30 @@ export class CallControl extends EventEmitter implements CallControlState {
} }
public startObserving() { public startObserving() {
if (!this.document) return;
this.bodyMutationObserver.observe(this.document.body, {
childList: true,
subtree: false, // only direct children of body
});
this.onBodyMutation();
}
private onBodyMutation() {
if (!this.document) return;
this.document.body.style.setProperty('background', 'none', 'important');
const controls = this.leaveButton?.parentElement?.parentElement;
if (controls) {
controls.style.setProperty('position', 'absolute');
controls.style.setProperty('visibility', 'hidden');
}
this.observeControls();
}
private observeControls() {
this.controlMutationObserver.disconnect(); this.controlMutationObserver.disconnect();
const screenshareBtn = this.screenshareButton; const screenshareBtn = this.screenshareButton;
@@ -125,8 +163,14 @@ export class CallControl extends EventEmitter implements CallControlState {
this.setSound(this.sound); this.setSound(this.sound);
} }
private setMediaState(state: ElementMediaStatePayload) { private async setMediaState(state: ElementMediaStatePayload) {
return this.call.transport.send(ElementWidgetActions.DeviceMute, state); const data = await this.call.transport.send(ElementWidgetActions.DeviceMute, state);
return new Promise<typeof data>(resolve => {
if (this.mediaStatePromiseResolver) {
this.mediaStatePromiseResolver();
}
this.mediaStatePromiseResolver = () => resolve(data);
});
} }
private setSound(sound: boolean): void { private setSound(sound: boolean): void {
@@ -157,9 +201,14 @@ export class CallControl extends EventEmitter implements CallControlState {
if (this.microphone && !this.sound) { if (this.microphone && !this.sound) {
this.toggleSound(); this.toggleSound();
} }
if (this.mediaStatePromiseResolver) {
this.mediaStatePromiseResolver();
this.mediaStatePromiseResolver = undefined;
}
} }
public onControlMutation() { private onControlMutation() {
const screenshare: boolean = this.screenshareButton?.getAttribute('data-kind') === 'primary'; const screenshare: boolean = this.screenshareButton?.getAttribute('data-kind') === 'primary';
const spotlight: boolean = this.spotlightButton?.checked ?? false; const spotlight: boolean = this.spotlightButton?.checked ?? false;
@@ -230,6 +279,7 @@ export class CallControl extends EventEmitter implements CallControlState {
} }
public dispose() { public dispose() {
this.bodyMutationObserver.disconnect();
this.controlMutationObserver.disconnect(); this.controlMutationObserver.disconnect();
} }
+4 -15
View File
@@ -172,6 +172,10 @@ export class CallEmbed {
const controlState = initialControlState ?? new CallControlState(true, false, true); const controlState = initialControlState ?? new CallControlState(true, false, true);
this.control = new CallControl(controlState, call, iframe); this.control = new CallControl(controlState, call, iframe);
this.control.startObserving();
iframe.onload = () => {
this.control.startObserving();
};
let initialMediaEvent = true; let initialMediaEvent = true;
this.disposables.push( this.disposables.push(
@@ -272,21 +276,6 @@ export class CallEmbed {
private onCallJoined(): void { private onCallJoined(): void {
this.joined = true; this.joined = true;
this.applyStyles();
this.control.startObserving();
}
private applyStyles(): void {
const doc = this.document;
if (!doc) return;
doc.body.style.setProperty('background', 'none', 'important');
const controls = doc.body.querySelector('[data-testid="incall_leave"]')?.parentElement
?.parentElement;
if (controls) {
controls.style.setProperty('position', 'absolute');
controls.style.setProperty('visibility', 'hidden');
}
} }
private onEvent(ev: MatrixEvent): void { private onEvent(ev: MatrixEvent): void {