mirror of
https://github.com/vector-im/element-call.git
synced 2026-09-22 22:29:30 +00:00
`LobbyView` took `onEnter`, `enterLabel` and `waitingForInvite`, which cannot express a declined, banned or invite-only room, so each of those ended at a full-screen error and took the camera preview with it. It now takes a `LobbyJoinState`, one of seven kinds, and renders both the button and a message under the preview from it. `KnockLobbyView` passes through what the loader offers, which is a single `lobby` state in place of `canKnock` and `waitForInvite`, so a decline, a ban, or a room that takes neither joins nor knocks keeps the user in the lobby. Waiting says what it is waiting for and offers a way to withdraw the request. The loader drives that state from the lobby's own callbacks rather than from the load promise, so a refused request leaves the user where they were, and every membership listener it adds is dropped when the effect is cleaned up. What it knows of a room nobody has joined is a `PreJoinRoomInfo`, built from a summary or from a `Room`, so a ban Element Call finds at load time is a lobby state as well. Denied and banned reuse the translated `group_call_loader.*` copy, so four strings are new. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
105 lines
2.9 KiB
TypeScript
105 lines
2.9 KiB
TypeScript
/*
|
|
Copyright 2026 Element Creations Ltd.
|
|
|
|
SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
|
Please see LICENSE in the repository root for full details.
|
|
*/
|
|
|
|
import { describe, expect, it } from "vitest";
|
|
import {
|
|
EventType,
|
|
MatrixEvent,
|
|
type Room,
|
|
type RoomState,
|
|
type RoomSummary,
|
|
} from "matrix-js-sdk";
|
|
|
|
import { E2eeType } from "../e2ee/e2eeType";
|
|
import { mockMatrixRoom } from "../utils/test";
|
|
import {
|
|
preJoinRoomInfoFromRoom,
|
|
preJoinRoomInfoFromSummary,
|
|
} from "./preJoinRoomInfo";
|
|
|
|
const roomId = "!call:example.org";
|
|
|
|
const summary = (extra: Partial<RoomSummary> = {}): RoomSummary =>
|
|
({
|
|
room_id: roomId,
|
|
name: "Weekly sync",
|
|
canonical_alias: "#sync:example.org",
|
|
avatar_url: "mxc://example.org/avatar",
|
|
world_readable: false,
|
|
guest_can_join: false,
|
|
num_joined_members: 3,
|
|
...extra,
|
|
}) as RoomSummary;
|
|
|
|
const room = (extra: { encryption?: string } = {}): Room =>
|
|
mockMatrixRoom({
|
|
roomId,
|
|
name: "Weekly sync",
|
|
getCanonicalAlias: () => "#sync:example.org",
|
|
getMxcAvatarUrl: () => "mxc://example.org/avatar",
|
|
currentState: {
|
|
getStateEvents: (type: string) =>
|
|
type === EventType.RoomEncryption && extra.encryption !== undefined
|
|
? new MatrixEvent({
|
|
type: EventType.RoomEncryption,
|
|
state_key: "",
|
|
content: { algorithm: extra.encryption },
|
|
})
|
|
: null,
|
|
} as unknown as RoomState,
|
|
});
|
|
|
|
describe("preJoinRoomInfoFromSummary", () => {
|
|
it("reads the stable encryption field", () => {
|
|
expect(
|
|
preJoinRoomInfoFromSummary(
|
|
summary({ encryption: "m.megolm.v1.aes-sha2" } as Partial<RoomSummary>),
|
|
),
|
|
).toEqual({
|
|
roomId,
|
|
roomName: "Weekly sync",
|
|
roomAlias: "#sync:example.org",
|
|
roomAvatar: "mxc://example.org/avatar",
|
|
e2eeSystem: { kind: E2eeType.PER_PARTICIPANT },
|
|
});
|
|
});
|
|
|
|
it("falls back to the unstable encryption field", () => {
|
|
expect(
|
|
preJoinRoomInfoFromSummary(
|
|
summary({ "im.nheko.summary.encryption": "m.megolm.v1.aes-sha2" }),
|
|
).e2eeSystem,
|
|
).toEqual({ kind: E2eeType.PER_PARTICIPANT });
|
|
});
|
|
|
|
it("is unencrypted when neither field is set", () => {
|
|
expect(preJoinRoomInfoFromSummary(summary()).e2eeSystem).toEqual({
|
|
kind: E2eeType.NONE,
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("preJoinRoomInfoFromRoom", () => {
|
|
it("reads the encryption state event", () => {
|
|
expect(
|
|
preJoinRoomInfoFromRoom(room({ encryption: "m.megolm.v1.aes-sha2" })),
|
|
).toEqual({
|
|
roomId,
|
|
roomName: "Weekly sync",
|
|
roomAlias: "#sync:example.org",
|
|
roomAvatar: "mxc://example.org/avatar",
|
|
e2eeSystem: { kind: E2eeType.PER_PARTICIPANT },
|
|
});
|
|
});
|
|
|
|
it("is unencrypted with no encryption state event", () => {
|
|
expect(preJoinRoomInfoFromRoom(room()).e2eeSystem).toEqual({
|
|
kind: E2eeType.NONE,
|
|
});
|
|
});
|
|
});
|