Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Element Call: fix widget shown while its still loading (waitForIframeLoad=false) #12292

Merged
merged 9 commits into from
Mar 12, 2024
13 changes: 6 additions & 7 deletions src/components/views/elements/AppTile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -249,8 +249,9 @@ export default class AppTile extends React.Component<IProps, IState> {
private getNewState(newProps: IProps): IState {
return {
initialising: true, // True while we are mangling the widget URL
// True while the iframe content is loading
loading: this.props.waitForIframeLoad && !PersistedElement.isMounted(this.persistKey),
// Don't show loading at all if the widget is ready once the IFrame is loaded (waitForIframeLoad = true).
// We only need the loading screen if the widget sends a contentLoaded event (waitForIframeLoad = false).
loading: !this.props.waitForIframeLoad && !PersistedElement.isMounted(this.persistKey),
// Assume that widget has permission to load if we are the user who
// added it to the room, or if explicitly granted by the user
hasPermissionToLoad: this.hasPermissionToLoad(newProps),
Expand Down Expand Up @@ -312,7 +313,6 @@ export default class AppTile extends React.Component<IProps, IState> {
if (this.props.room) {
this.context.on(RoomEvent.MyMembership, this.onMyMembership);
}

this.allowedWidgetsWatchRef = SettingsStore.watchSetting("allowedWidgets", null, this.onAllowedWidgetsChange);
// Widget action listeners
this.dispatcherRef = dis.register(this.onAction);
Expand Down Expand Up @@ -352,15 +352,15 @@ export default class AppTile extends React.Component<IProps, IState> {
}

private setupSgListeners(): void {
this.sgWidget?.on("preparing", this.onWidgetPreparing);
this.sgWidget?.on("ready", this.onWidgetReady);
this.sgWidget?.on("error:preparing", this.updateRequiresClient);
// emits when the capabilities have been set up or changed
this.sgWidget?.on("capabilitiesNotified", this.updateRequiresClient);
}

private stopSgListeners(): void {
if (!this.sgWidget) return;
this.sgWidget.off("preparing", this.onWidgetPreparing);
this.sgWidget?.off("ready", this.onWidgetReady);
this.sgWidget.off("error:preparing", this.updateRequiresClient);
this.sgWidget.off("capabilitiesNotified", this.updateRequiresClient);
}
Expand Down Expand Up @@ -446,8 +446,7 @@ export default class AppTile extends React.Component<IProps, IState> {

this.sgWidget?.stopMessaging({ forceDestroy: true });
}

private onWidgetPreparing = (): void => {
private onWidgetReady = (): void => {
this.setState({ loading: false });
};

Expand Down
2 changes: 1 addition & 1 deletion src/models/Call.ts
Original file line number Diff line number Diff line change
Expand Up @@ -758,7 +758,7 @@ export class ElementCall extends Call {
name: "Element Call",
type: WidgetType.CALL.preferred,
url: url.toString(),
// waitForIframeLoad: false,
waitForIframeLoad: false,
data: ElementCall.getWidgetData(
client,
roomId,
Expand Down
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Those snaps are now updated since we dont show the loading view for IFrames that have waitForIframeLoad=true (That are considered ready once the IFrame is ready.)

It would be possible to use the "preparing" event to show a spinner in the waitForIframeLoad=true cases. But to me it looks like this is how it was intended to be. (I dont see why waitForIFrame would have been used in getNewState otherwise)

Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ exports[`AppTile destroys non-persisted right panel widget on room change 1`] =
id="1"
>
<div
class="mx_AppTileBody mx_AppTileBody--large mx_AppTileBody--loading"
class="mx_AppTileBody mx_AppTileBody--large"
>
<div
class="mx_AppTileBody_fadeInSpinner"
Expand Down Expand Up @@ -412,7 +412,7 @@ exports[`AppTile preserves non-persisted widget on container move 1`] = `
</span>
</div>
<div
class="mx_AppTileBody mx_AppTileBody--large mx_AppTileBody--loading"
class="mx_AppTileBody mx_AppTileBody--large"
>
<div
class="mx_AppTileBody_fadeInSpinner"
Expand Down
5 changes: 2 additions & 3 deletions test/test-utils/call.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,8 @@ export class MockedCall extends Call {
url: "https://example.org",
name: "Group call",
creatorUserId: "@alice:example.org",
// waitForIframeLoad = false, makes the widget API wait for the 'contentLoaded' event instead.
// This is how the EC is designed, but for backwards compatibility (full mesh) we currently need to use waitForIframeLoad = true
// waitForIframeLoad: false
// waitForIframeLoad = false, makes the widget API wait for the 'contentLoaded' event.
waitForIframeLoad: false,
},
room.client,
);
Expand Down
Loading