mirror of
https://github.com/vector-im/element-call.git
synced 2026-09-13 21:59:30 +00:00
Say outright whether the profile is ours to change
Whether to offer the profile settings was inferred from whether the host could close Element Call. For a component with no host bridge — the default — nothing could, so an embedded Element Call let the user edit the profile of an account that belongs to the host application. `HostBridge.supportsProfileChanges` states it directly: true standalone, where Element Call signed the user in itself; false for a widget's host and for anything embedding the component (which sets it itself, since the client it hands over is its own). The profile tab and the profile shortcut follow that. What a host's ability to close us still decides — what to show after the call ends — is a question about who owns our lifetime, and stays keyed on `close`. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
f0359259f9
commit
7cd21476f7
@@ -247,6 +247,11 @@ describe("createWidgetHostBridge", () => {
|
||||
});
|
||||
});
|
||||
|
||||
test("does not offer profile changes, since the host signed the user in", () => {
|
||||
const bridge = createWidgetHostBridge(mockWidget({}));
|
||||
expect(bridge.supportsProfileChanges).toBe(false);
|
||||
});
|
||||
|
||||
describe("supportsReactions", () => {
|
||||
const capabilities = [
|
||||
"org.matrix.msc2762.send.event:m.reaction",
|
||||
@@ -278,6 +283,10 @@ describe("nullHostBridge", () => {
|
||||
expect(nullHostBridge.close).toBeUndefined();
|
||||
});
|
||||
|
||||
test("supports profile changes, since Element Call signed the user in itself", () => {
|
||||
expect(nullHostBridge.supportsProfileChanges).toBe(true);
|
||||
});
|
||||
|
||||
test("offers no media download, so Element Call uses its own client", () => {
|
||||
expect(nullHostBridge.downloadMedia).toBeUndefined();
|
||||
});
|
||||
|
||||
+15
-1
@@ -96,8 +96,16 @@ export interface HostBridge {
|
||||
/** The host wants to change, or read back, the device mute state. */
|
||||
deviceMute$: Observable<HostRequest<DeviceMuteRequest, DeviceMuteState>>;
|
||||
|
||||
// What the host is capable of.
|
||||
// What the host is, and is capable of.
|
||||
|
||||
/**
|
||||
* Whether Element Call may offer to change the user's profile — their
|
||||
* display name and avatar. Only when the account is Element Call's own,
|
||||
* which is to say standalone: a widget's host and an application embedding
|
||||
* Element Call both signed the user in themselves, so the profile is theirs
|
||||
* to manage and Element Call must not offer to edit it.
|
||||
*/
|
||||
readonly supportsProfileChanges: boolean;
|
||||
/** Whether the host permits Element Call to send and receive reactions. */
|
||||
readonly supportsReactions: boolean;
|
||||
/**
|
||||
@@ -122,6 +130,9 @@ export const nullHostBridge: HostBridge = {
|
||||
join$: NEVER,
|
||||
hangUp$: NEVER,
|
||||
deviceMute$: NEVER,
|
||||
// Standalone, the account is Element Call's own: it signed the user in, so
|
||||
// it may offer to change the profile.
|
||||
supportsProfileChanges: true,
|
||||
// Standalone Element Call reaches the homeserver itself, so nothing is
|
||||
// withholding these from it.
|
||||
supportsReactions: true,
|
||||
@@ -176,6 +187,9 @@ export function createWidgetHostBridge(widget: WidgetHelpers): HostBridge {
|
||||
join$: requests(ElementWidgetActions.JoinCall),
|
||||
hangUp$: requests(ElementWidgetActions.HangupCall),
|
||||
deviceMute$: requests(ElementWidgetActions.DeviceMute),
|
||||
// The client we are a widget of signed the user in, so the profile is its
|
||||
// to manage
|
||||
supportsProfileChanges: false,
|
||||
// Element Call needs the host's permission to send reactions on its behalf.
|
||||
// Read on access rather than up front: the widget API negotiates its
|
||||
// capabilities asynchronously, and the bridge is built before that settles.
|
||||
|
||||
@@ -116,10 +116,8 @@ export const GroupCallView: FC<Props> = ({
|
||||
const hostBridge = useHostBridge();
|
||||
// A host that can close us is a host that decides when we stop existing, so
|
||||
// we neither show our own post-call screens nor assume we have time to
|
||||
// finish what we are doing.
|
||||
// TODO: this reads a capability as a proxy for who owns our lifetime. Worth
|
||||
// finding a more direct way to express it — see the guidance in UrlParams.ts
|
||||
// on naming behaviours rather than situations.
|
||||
// finish what we are doing. (Whose account the user's is, by contrast, is
|
||||
// stated outright: see `HostBridge.supportsProfileChanges`.)
|
||||
const hostControlsLifetime = hostBridge.close !== undefined;
|
||||
|
||||
const muteAllAudio = useBehavior(muteAllAudio$);
|
||||
|
||||
@@ -329,11 +329,8 @@ export const InCallView: FC<InCallViewProps> = ({
|
||||
|
||||
const openProfile = useMemo(
|
||||
() =>
|
||||
// A host that can dismiss us is a host that owns the user's account, so
|
||||
// their profile is not ours to edit.
|
||||
// TODO: another use of the close capability as a proxy — see the note in
|
||||
// GroupCallView.
|
||||
hostBridge.close === undefined
|
||||
// The profile is only ours to edit when the account is ours
|
||||
hostBridge.supportsProfileChanges
|
||||
? (): void => {
|
||||
setSettingsTab("profile");
|
||||
setSettingsOpen(true);
|
||||
|
||||
@@ -235,9 +235,8 @@ export const SettingsModal: FC<Props> = ({
|
||||
};
|
||||
|
||||
const tabs = [audioTab, videoTab];
|
||||
// A host that can dismiss us is a host that owns the user's account, so their
|
||||
// profile is not ours to edit.
|
||||
if (hostBridge.close === undefined) tabs.push(profileTab);
|
||||
// The profile is only ours to edit when the account is ours
|
||||
if (hostBridge.supportsProfileChanges) tabs.push(profileTab);
|
||||
tabs.push(preferencesTab);
|
||||
if (isRageshakeAvailable || import.meta.env.VITE_PACKAGE === "full") {
|
||||
// for full package we want to show the analytics consent checkbox
|
||||
|
||||
Reference in New Issue
Block a user