Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,10 @@ test.describe("Room list", () => {
.click();
await page.getByRole("menuitem", { name: "New video room" }).click();
await page.getByRole("textbox", { name: "Name" }).fill("video room");
// Make it public to avoid any crypto setup toasts
await page.getByRole("button", { name: "Room visibility" }).click();
await page.getByRole("option", { name: "Public room" }).click();
await page.getByRole("textbox", { name: "Room address" }).fill("video-room");
await page.getByRole("button", { name: "Create video room" }).click();

const roomListView = getRoomList(page);
Expand Down
28 changes: 14 additions & 14 deletions apps/web/playwright/e2e/voip/element-call.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -216,9 +216,9 @@ test.describe("Element Call", () => {
});
});

[true, false].forEach((skipLobbyToggle) => {
[true, false].forEach((joinWithVideo) => {
test(
`should be able to join a call via incoming video call toast (skipLobby=${skipLobbyToggle})`,
`should be able to join a call via incoming video call toast (joinWithVideo=${joinWithVideo})`,
{ tag: ["@screenshot"] },
async ({ page, user, bot, room, app }) => {
await app.viewRoomById(room.roomId);
Expand All @@ -230,7 +230,7 @@ test.describe("Element Call", () => {
const toast = page.locator(".mx_Toast_toast");
const button = toast.getByRole("button", { name: "Join" });

if (skipLobbyToggle) {
if (joinWithVideo) {
await toast.getByRole("switch").check();
await expect(toast).toMatchScreenshot(`incoming-call-group-video-toast-checked.png`);
} else {
Expand All @@ -246,8 +246,8 @@ test.describe("Element Call", () => {
const hash = new URLSearchParams(url.hash.slice(1));
assertCommonCallParameters(url.searchParams, hash, user, room);

expect(hash.get("intent")).toEqual("join_existing");
expect(hash.get("skipLobby")).toEqual(skipLobbyToggle.toString());
expect(hash.get("intent")).toEqual(joinWithVideo ? "join_existing" : "join_existing_voice");
expect(hash.get("skipLobby")).toEqual("true");
},
);
});
Expand Down Expand Up @@ -275,7 +275,7 @@ test.describe("Element Call", () => {
const hash = new URLSearchParams(url.hash.slice(1));
assertCommonCallParameters(url.searchParams, hash, user, room);

expect(hash.get("intent")).toEqual("join_existing");
expect(hash.get("intent")).toEqual("join_existing_voice");
expect(hash.get("skipLobby")).toEqual("true");
},
);
Expand Down Expand Up @@ -349,24 +349,24 @@ test.describe("Element Call", () => {
expect(hash.get("skipLobby")).toEqual(null);
});

[true, false].forEach((skipLobbyToggle) => {
[true, false].forEach((joinWithVideo) => {
test(
`should be able to join a call via incoming call toast (skipLobby=${skipLobbyToggle})`,
`should be able to join a call via incoming call toast (joinWithVideo=${joinWithVideo})`,
{ tag: ["@screenshot"] },
async ({ page, user, bot, room, app }) => {
await app.viewRoomById(room.roomId);
await expect(page.getByText("Bob joined the room")).toBeVisible();
// Fake a start of a call
await sendRTCState(bot, room.roomId, "ring", "video");
const toast = page.locator(".mx_Toast_toast");
const button = toast.getByRole("button", { name: "Accept" });
if (skipLobbyToggle) {
const button = toast.getByRole("button", { name: "Join" });
if (joinWithVideo) {
await toast.getByRole("switch").check();
} else {
await toast.getByRole("switch").uncheck();
}
await expect(toast).toMatchScreenshot(
`incoming-call-dm-video-toast-${skipLobbyToggle ? "checked" : "unchecked"}.png`,
`incoming-call-dm-video-toast-${joinWithVideo ? "checked" : "unchecked"}.png`,
{
// Hide UserId
css: `
Expand All @@ -385,8 +385,8 @@ test.describe("Element Call", () => {
const hash = new URLSearchParams(url.hash.slice(1));
assertCommonCallParameters(url.searchParams, hash, user, room);

expect(hash.get("intent")).toEqual("join_existing_dm");
expect(hash.get("skipLobby")).toEqual(skipLobbyToggle.toString());
expect(hash.get("intent")).toEqual(joinWithVideo ? "join_existing_dm" : "join_existing_dm_voice");
expect(hash.get("skipLobby")).toEqual("true");
},
);
});
Expand All @@ -400,7 +400,7 @@ test.describe("Element Call", () => {
// Fake a start of a call
await sendRTCState(bot, room.roomId, "ring", "audio");
const toast = page.locator(".mx_Toast_toast");
const button = toast.getByRole("button", { name: "Accept" });
const button = toast.getByRole("button", { name: "Join" });

await expect(toast).toMatchScreenshot(`incoming-call-dm-voice-toast.png`, {
// Hide UserId
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
41 changes: 14 additions & 27 deletions apps/web/res/css/structures/_ToastContainer.pcss
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,16 @@ Please see LICENSE files in the repository root for full details.
z-index: 101;
padding: 4px;
display: grid;
grid-template-rows: 1fr 14px 6px;
grid-template-rows: 1fr 28px 8px;

&.mx_ToastContainer_stacked::before {
content: "";
margin: 0 4px;
grid-row: 2 / 4;
margin: 0 6px;
grid-row: 2 / -1;
grid-column: 1;
background-color: $system;
box-shadow: 0px 4px 20px rgb(0, 0, 0, 0.5);
border-radius: 8px;
border-radius: var(--cpd-space-6x);
}

.mx_Toast_toast {
Expand All @@ -32,45 +32,32 @@ Please see LICENSE files in the repository root for full details.
color: $primary-content;
box-shadow: 0px 4px 24px rgb(0, 0, 0, 0.1);
border: var(--cpd-border-width-1) solid var(--cpd-color-border-interactive-secondary);
border-radius: 12px;
border-radius: calc(var(--cpd-space-6x) - var(--cpd-border-width-1));
overflow: hidden;
display: grid;
grid-template-columns: 22px 1fr;
column-gap: 8px;
grid-template-columns: 20px 1fr auto;
column-gap: var(--cpd-space-2x);
row-gap: 4px;
align-items: center;
padding: var(--cpd-space-3x);
padding: calc(var(--cpd-space-5x) - var(--cpd-border-width-1));

&.mx_Toast_hasIcon {
svg {
width: 22px;
height: 22px;
width: 20px;
height: 20px;
grid-column: 1;
}

.mx_Toast_title {
grid-column: 2;
}

.mx_Toast_body {
grid-column: 2 / 4;
}

.mx_Toast_closebutton {
grid-column: 3;
}
}
&:not(.mx_Toast_hasIcon) {
padding-left: 12px;

.mx_Toast_title {
grid-column: 1 / -1;
}
}

.mx_Toast_title,
.mx_Toast_description {
padding-right: 8px;
&:not(.mx_Toast_hasIcon) .mx_Toast_title {
grid-column: 1 / -1;
}

.mx_Toast_title {
Expand All @@ -89,14 +76,14 @@ Please see LICENSE files in the repository root for full details.
}

.mx_Toast_body {
grid-column: 1 / 3;
grid-column: 1 / -1;
grid-row: 2;
}

.mx_Toast_buttons {
display: flex;
justify-content: flex-end;
column-gap: 5px;
column-gap: var(--cpd-space-2x);

.mx_AccessibleButton {
min-width: 96px;
Expand Down
71 changes: 31 additions & 40 deletions apps/web/res/css/views/toasts/_IncomingCallToast.pcss
Original file line number Diff line number Diff line change
Expand Up @@ -9,64 +9,55 @@ Please see LICENSE files in the repository root for full details.
.mx_IncomingCallToast {
position: relative;
display: flex;
flex-direction: row;
flex-direction: column;
pointer-events: initial; /* restore pointer events so the user can accept/decline */

$closeButtonSize: var(--cpd-space-4x);

.mx_IncomingCallToast_content {
display: flex;
flex-direction: column;
gap: var(--cpd-space-4x);
padding: var(--cpd-space-3x);
width: 100%;
overflow: hidden;

.mx_IncomingCallToast_message {
font-size: var(--cpd-font-size-body-lg);
line-height: var(--cpd-font-size-heading-sm);
width: calc(100% - $closeButtonSize - 2 * var(--cpd-space-1x));
font-weight: var(--cpd-font-weight-semibold);
}

.mx_IncomingCallToast_buttons {
display: flex;
.mx_IncomingCallToast_title {
display: grid;
grid-template-columns: auto 1fr auto;
align-items: center;
gap: var(--cpd-space-2x);
}

.mx_IncomingCallToast_actionButton {
position: relative;
h2 {
margin: 0;
}

align-self: flex-end;
.mx_IncomingCallToast_expandButton {
padding: var(--cpd-space-1x);
color: var(--cpd-color-icon-secondary);
transition: color 0.1s;

box-sizing: border-box;
min-width: 120px;
&:hover {
color: var(--cpd-color-icon-primary);
}

padding: var(--cpd-space-1x) 0;
padding-right: var(--cpd-space-4x);
line-height: var(--cpd-space-6x);
& > svg {
display: block;
}
}
}
}

.mx_IncomingCallToast_closeButton {
position: absolute;

right: 0;

display: flex;
height: $closeButtonSize;
width: $closeButtonSize;
.mx_IncomingCallToast_avatars {
display: inline-block;
vertical-align: top;
}

svg {
height: inherit;
width: inherit;
color: $secondary-content;
.mx_IncomingCallToast_buttons {
display: flex;
gap: var(--cpd-space-2x);
padding-block-start: var(--cpd-space-2x);
}
}
.mx_IncomingCallToast_toggleWithLabel {
display: flex;
span {
flex-grow: 1;

.mx_IncomingCallToast_actionButton {
box-sizing: border-box;
min-width: 131px;
}
}
}
7 changes: 3 additions & 4 deletions apps/web/src/components/views/rooms/LiveContentSummary.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,16 @@

import React, { type FC } from "react";
import classNames from "classnames";
import { GroupIcon, VideoCallSolidIcon, VoiceCallSolidIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
import { GroupIcon, VideoCallSolidIcon } from "@vector-im/compound-design-tokens/assets/web/icons";

import { _t } from "../../../languageHandler";

export enum LiveContentType {
Video,
Voice,
}

interface Props {
type: LiveContentType;

Check warning on line 20 in apps/web/src/components/views/rooms/LiveContentSummary.tsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'type' PropType is defined but prop is never used

See more on https://sonarcloud.io/project/issues?id=element-web&issues=AZ1kfHBjt5DCDkqYAXj2&open=AZ1kfHBjt5DCDkqYAXj2&pullRequest=33043
text: string;
active: boolean;
participantCount: number;
Expand All @@ -27,14 +26,14 @@
/**
* Summary line used to call out live, interactive content such as calls.
*/
export const LiveContentSummary: FC<Props> = ({ type, text, active, participantCount }) => (
export const LiveContentSummary: FC<Props> = ({ text, active, participantCount }) => (
<span className="mx_LiveContentSummary">
<span
className={classNames("mx_LiveContentSummary_text", {
mx_LiveContentSummary_text_active: active,
})}
>
{type === LiveContentType.Video ? <VideoCallSolidIcon /> : <VoiceCallSolidIcon />}
<VideoCallSolidIcon />
{text}
</span>
{participantCount > 0 && (
Expand Down
12 changes: 2 additions & 10 deletions apps/web/src/hooks/useCall.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,7 @@ export const useParticipantCount = (call: Call | null): number => {
}, [participants]);
};

export const useParticipatingMembers = (call: Call): RoomMember[] => {
export const useParticipatingMembers = (call: Call | null): RoomMember[] => {
const participants = useParticipants(call);

return useMemo(() => {
const members: RoomMember[] = [];
for (const [member, devices] of participants) {
// Repeat the member for as many devices as they're using
for (let i = 0; i < devices.size; i++) members.push(member);
}
return members;
}, [participants]);
return useMemo(() => [...participants.keys()], [participants]);
};
Loading
Loading