mirror of
https://github.com/vector-im/element-call.git
synced 2026-09-10 21:55:19 +00:00
Talk to a component host in callbacks, not observables
The component exposed the internal HostBridge to hosts as-is, which carried the host's requests as rxjs observables. That made rxjs part of the public API of a package that bundles its own copy of it, so a host would build bridges with a different rxjs than the one Element Call consumed them with — and asked every host to learn rxjs to change the theme. A component host now implements plain async callbacks for what Element Call tells it (`ElementCallHostBridge`, all optional), and makes its own requests through an imperative handle on the component's `ref` (`ElementCallHandle`: setTheme, join, hangUp, setDeviceMute), each resolving once Element Call has acted and rejecting when nothing in Element Call can. `component/host.ts` adapts that to the HostBridge the rest of Element Call still speaks, with a bridge whose identity never changes, so a host re-creating its callbacks on render restarts nothing. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
d18e82c546
commit
8e8bc5ddde
@@ -11,12 +11,13 @@ import {
|
||||
type ReactNode,
|
||||
useCallback,
|
||||
useMemo,
|
||||
useRef,
|
||||
useState,
|
||||
} from "react";
|
||||
import { type MatrixClient } from "matrix-js-sdk";
|
||||
import { logger } from "matrix-js-sdk/lib/logger";
|
||||
|
||||
import { ElementCall } from "../index";
|
||||
import { ElementCall, type ElementCallHandle } from "../index";
|
||||
import { createDevHostBridge } from "./DevHostBridge";
|
||||
import { createSession, joinRoom } from "./session";
|
||||
import styles from "./Harness.module.css";
|
||||
@@ -102,6 +103,29 @@ const Pane: FC<{
|
||||
[log, session.label],
|
||||
);
|
||||
|
||||
// What the host asks of Element Call goes through the component's handle.
|
||||
// Worth saying out loud when a request is refused — asking to hang up when
|
||||
// there is no call, say — since that is the sort of thing the harness is for.
|
||||
const handle = useRef<ElementCallHandle>(null);
|
||||
const ask = (
|
||||
name: string,
|
||||
make: (handle: ElementCallHandle) => Promise<unknown>,
|
||||
): void => {
|
||||
if (handle.current === null) {
|
||||
log(session.label, `← ${name}: not mounted`);
|
||||
return;
|
||||
}
|
||||
log(session.label, `← ${name}`);
|
||||
make(handle.current).then(
|
||||
(reply) =>
|
||||
log(
|
||||
session.label,
|
||||
`→ ${name} acknowledged${reply === undefined ? "" : `: ${JSON.stringify(reply)}`}`,
|
||||
),
|
||||
(e: unknown) => log(session.label, `→ ${name} refused: ${e}`),
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<section className={styles.pane} data-testid="call-pane">
|
||||
<div className={styles.paneBar}>
|
||||
@@ -110,24 +134,42 @@ const Pane: FC<{
|
||||
<button onClick={(): void => setMounted((m) => !m)}>
|
||||
{mounted ? "Unmount" : "Mount"}
|
||||
</button>
|
||||
<button onClick={(): void => bridge.requestTheme("light")}>
|
||||
Light
|
||||
</button>
|
||||
<button onClick={(): void => bridge.requestTheme("dark")}>Dark</button>
|
||||
<button
|
||||
onClick={(): void =>
|
||||
bridge.requestDeviceMute({ audio_enabled: false })
|
||||
ask("setTheme(light)", async (h) => await h.setTheme("light"))
|
||||
}
|
||||
>
|
||||
Light
|
||||
</button>
|
||||
<button
|
||||
onClick={(): void =>
|
||||
ask("setTheme(dark)", async (h) => await h.setTheme("dark"))
|
||||
}
|
||||
>
|
||||
Dark
|
||||
</button>
|
||||
<button
|
||||
onClick={(): void =>
|
||||
ask(
|
||||
"setDeviceMute(audio: false)",
|
||||
async (h) => await h.setDeviceMute({ audio_enabled: false }),
|
||||
)
|
||||
}
|
||||
>
|
||||
Mute
|
||||
</button>
|
||||
<button onClick={(): void => bridge.requestHangUp()}>Hang up</button>
|
||||
<button
|
||||
onClick={(): void => ask("hangUp", async (h) => await h.hangUp())}
|
||||
>
|
||||
Hang up
|
||||
</button>
|
||||
</div>
|
||||
{/* Resizable, because how Element Call copes with the size it is given is
|
||||
one of the things we cannot find out from the standalone app */}
|
||||
<div className={styles.paneCall} data-testid="call-container">
|
||||
{mounted && (
|
||||
<ElementCall
|
||||
ref={handle}
|
||||
client={session.client}
|
||||
roomId={roomId}
|
||||
hostBridge={bridge}
|
||||
|
||||
Reference in New Issue
Block a user