diff --git a/src/app/plugins/call/CallControl.ts b/src/app/plugins/call/CallControl.ts index 3098c4261..f829fd8d4 100644 --- a/src/app/plugins/call/CallControl.ts +++ b/src/app/plugins/call/CallControl.ts @@ -330,10 +330,32 @@ export class CallControl extends EventEmitter implements CallControlState { } } + // [Gitea #43] Set once the fork reports io.lotus.controls_state: from then on + // layout / settings / reactions go over the widget API and screenshare + + // layout state come from that report, not from EC's DOM. Older forks never + // send it and keep the DOM path below. + private forkControls = false; + + /** [Gitea #43] The fork's `io.lotus.controls_state` report. */ + public onControlsState(data: unknown) { + if (typeof data !== 'object' || data === null) return; + const { screensharing, layout } = data as { screensharing?: unknown; layout?: unknown }; + this.forkControls = true; + this.applyControls( + typeof screensharing === 'boolean' ? screensharing : this.screenshare, + layout === 'spotlight' || layout === 'grid' ? layout === 'spotlight' : this.spotlight, + ); + } + private onControlMutation() { - const wasScreensharing = this.screenshare; + if (this.forkControls) return; const screenshare: boolean = this.screenshareButton?.getAttribute('data-kind') === 'primary'; const spotlight: boolean = this.spotlightButton?.checked ?? false; + this.applyControls(screenshare, spotlight); + } + + private applyControls(screenshare: boolean, spotlight: boolean) { + const wasScreensharing = this.screenshare; // C-M6: when a screenshare stops, clear the screenshare-audio mute so a // later screenshare doesn't start pre-muted. @@ -436,6 +458,12 @@ export class CallControl extends EventEmitter implements CallControlState { } public toggleSpotlight() { + if (this.forkControls) { + this.sendForkAction('io.lotus.set_layout', { + layout: this.spotlight ? 'grid' : 'spotlight', + }); + return; + } if (this.spotlight) { this.gridButton?.click(); return; @@ -444,13 +472,26 @@ export class CallControl extends EventEmitter implements CallControlState { } public toggleReactions() { + if (this.forkControls) { + this.sendForkAction('io.lotus.toggle_reactions', {}); + return; + } this.reactionsButton?.click(); } public toggleSettings() { + if (this.forkControls) { + // Same as clicking EC's settings button: opens the modal. + this.sendForkAction('io.lotus.open_settings', { open: true }); + return; + } this.settingsButton?.click(); } + private sendForkAction(action: string, data: Record): void { + this.call.transport.send(action, data).catch(() => undefined); + } + /** * Focus a specific participant's camera tile in Element Call. * diff --git a/src/app/plugins/call/CallEmbed.ts b/src/app/plugins/call/CallEmbed.ts index 66f0617f4..07fb8ef1a 100644 --- a/src/app/plugins/call/CallEmbed.ts +++ b/src/app/plugins/call/CallEmbed.ts @@ -417,6 +417,13 @@ export class CallEmbed { } }), ); + // [Gitea #43] Screenshare + layout state from the fork; also switches the + // call bar's layout / settings / reactions buttons to widget actions. + this.disposables.push( + this.listenAction('io.lotus.controls_state', (evt) => { + this.control.onControlsState((evt.detail as { data?: unknown } | undefined)?.data); + }), + ); this.disposables.push( this.listenAction('io.lotus.call_state', (evt) => { const data = (evt.detail as { data?: { participants?: unknown } } | undefined)?.data;