Merge remote-tracking branch 'origin/livekit' into hs/reactions-viewcallmodel

This commit is contained in:
Half-Shot
2024-12-12 09:18:36 +00:00
155 changed files with 1772 additions and 996 deletions
+6
View File
@@ -37,6 +37,12 @@ module.exports = {
"@typescript-eslint/promise-function-async": "error", "@typescript-eslint/promise-function-async": "error",
"@typescript-eslint/require-await": "error", "@typescript-eslint/require-await": "error",
"@typescript-eslint/await-thenable": "error", "@typescript-eslint/await-thenable": "error",
// To help ensure that we get proper vite/rollup lazy loading (e.g. for matrix-js-sdk):
"@typescript-eslint/consistent-type-imports": [
"error",
{ fixStyle: "inline-type-imports" },
],
// To encourage good usage of RxJS:
"rxjs/no-exposed-subjects": "error", "rxjs/no-exposed-subjects": "error",
}, },
settings: { settings: {
+4
View File
@@ -17,5 +17,9 @@
}, },
"rageshake": { "rageshake": {
"submit_url": "https://element.io/bugreports/submit" "submit_url": "https://element.io/bugreports/submit"
},
"sentry": {
"environment": "netlify-pr-preview",
"DSN": "https://b1e328d49be3402ba96101338989fb35@sentry.tools.element.io/41"
} }
} }
+6 -8
View File
@@ -70,6 +70,7 @@
}, },
"developer_mode": { "developer_mode": {
"crypto_version": "Crypto version: {{version}}", "crypto_version": "Crypto version: {{version}}",
"debug_tile_layout_label": "Debug tile layout",
"device_id": "Device ID: {{id}}", "device_id": "Device ID: {{id}}",
"duplicate_tiles_label": "Number of additional tile copies per participant", "duplicate_tiles_label": "Number of additional tile copies per participant",
"hostname": "Hostname: {{hostname}}", "hostname": "Hostname: {{hostname}}",
@@ -147,11 +148,9 @@
"screenshare_button_label": "Share screen", "screenshare_button_label": "Share screen",
"settings": { "settings": {
"audio_tab": { "audio_tab": {
"effect_volume_description": "Volume for sound effects such as: joining or leaving a call, and reactions.", "effect_volume_description": "Adjust the volume at which reactions and hand raised effects play.",
"effect_volume_label": "Sound effect volume" "effect_volume_label": "Sound effect volume"
}, },
"developer_settings_label": "Developer Settings",
"developer_settings_label_description": "Expose developer settings in the settings window.",
"developer_tab_title": "Developer", "developer_tab_title": "Developer",
"feedback_tab_body": "If you are experiencing issues or simply would like to provide some feedback, please send us a short description below.", "feedback_tab_body": "If you are experiencing issues or simply would like to provide some feedback, please send us a short description below.",
"feedback_tab_description_label": "Your feedback", "feedback_tab_description_label": "Your feedback",
@@ -159,17 +158,16 @@
"feedback_tab_send_logs_label": "Include debug logs", "feedback_tab_send_logs_label": "Include debug logs",
"feedback_tab_thank_you": "Thanks, we received your feedback!", "feedback_tab_thank_you": "Thanks, we received your feedback!",
"feedback_tab_title": "Feedback", "feedback_tab_title": "Feedback",
"more_tab_title": "More",
"opt_in_description": "<0></0><1></1>You may withdraw consent by unchecking this box. If you are currently in a call, this setting will take effect at the end of the call.", "opt_in_description": "<0></0><1></1>You may withdraw consent by unchecking this box. If you are currently in a call, this setting will take effect at the end of the call.",
"preferences_tab": { "preferences_tab": {
"developer_mode_label": "Developer mode",
"developer_mode_label_description": "Enable developer mode and show developer settings tab.",
"reactions_play_sound_description": "Play a sound effect when anyone sends a reaction into a call.", "reactions_play_sound_description": "Play a sound effect when anyone sends a reaction into a call.",
"reactions_play_sound_label": "Play reaction sounds", "reactions_play_sound_label": "Play reaction sounds",
"reactions_show_description": "Show an animation when anyone sends a reaction.", "reactions_show_description": "Show an animation when anyone sends a reaction.",
"reactions_show_label": "Show reactions", "reactions_show_label": "Show reactions"
"reactions_title": "Reactions"
}, },
"preferences_tab_body": "Here you can configure extra options for an improved experience", "preferences_tab_body": "Here you can configure extra options for an improved experience.",
"preferences_tab_h4": "Preferences",
"preferences_tab_show_hand_raised_timer_description": "Show a timer when a participant raises their hand", "preferences_tab_show_hand_raised_timer_description": "Show a timer when a participant raises their hand",
"preferences_tab_show_hand_raised_timer_label": "Show hand raise duration", "preferences_tab_show_hand_raised_timer_label": "Show hand raise duration",
"speaker_device_selection_label": "Speaker" "speaker_device_selection_label": "Speaker"
+3 -3
View File
@@ -27,13 +27,13 @@
"@codecov/vite-plugin": "^1.3.0", "@codecov/vite-plugin": "^1.3.0",
"@fontsource/inconsolata": "^5.1.0", "@fontsource/inconsolata": "^5.1.0",
"@fontsource/inter": "^5.1.0", "@fontsource/inter": "^5.1.0",
"@formatjs/intl-durationformat": "^0.6.1", "@formatjs/intl-durationformat": "^0.7.0",
"@formatjs/intl-segmenter": "^11.7.3", "@formatjs/intl-segmenter": "^11.7.3",
"@livekit/components-core": "^0.11.0", "@livekit/components-core": "^0.11.0",
"@livekit/components-react": "^2.0.0", "@livekit/components-react": "^2.0.0",
"@opentelemetry/api": "^1.4.0", "@opentelemetry/api": "^1.4.0",
"@opentelemetry/core": "^1.25.1", "@opentelemetry/core": "^1.25.1",
"@opentelemetry/exporter-trace-otlp-http": "^0.55.0", "@opentelemetry/exporter-trace-otlp-http": "^0.56.0",
"@opentelemetry/resources": "^1.25.1", "@opentelemetry/resources": "^1.25.1",
"@opentelemetry/sdk-trace-base": "^1.25.1", "@opentelemetry/sdk-trace-base": "^1.25.1",
"@opentelemetry/sdk-trace-web": "^1.9.1", "@opentelemetry/sdk-trace-web": "^1.9.1",
@@ -113,7 +113,7 @@
"typescript-eslint-language-service": "^5.0.5", "typescript-eslint-language-service": "^5.0.5",
"unique-names-generator": "^4.6.0", "unique-names-generator": "^4.6.0",
"vaul": "^1.0.0", "vaul": "^1.0.0",
"vite": "^5.0.0", "vite": "^6.0.0",
"vite-plugin-compression2": "^1.3.1", "vite-plugin-compression2": "^1.3.1",
"vite-plugin-html-template": "^1.1.0", "vite-plugin-html-template": "^1.1.0",
"vite-plugin-svgr": "^4.0.0", "vite-plugin-svgr": "^4.0.0",
+1 -1
View File
@@ -7,7 +7,7 @@ Please see LICENSE in the repository root for full details.
import "matrix-js-sdk/src/@types/global"; import "matrix-js-sdk/src/@types/global";
import type { DurationFormat as PolyfillDurationFormat } from "@formatjs/intl-durationformat"; import type { DurationFormat as PolyfillDurationFormat } from "@formatjs/intl-durationformat";
import { Controls } from "../controls"; import { type Controls } from "../controls";
declare global { declare global {
interface Document { interface Document {
+1 -1
View File
@@ -7,7 +7,7 @@ Please see LICENSE in the repository root for full details.
import "i18next"; import "i18next";
// import all namespaces (for the default language, only) // import all namespaces (for the default language, only)
import app from "../../locales/en/app.json"; import type app from "../../locales/en/app.json";
declare module "i18next" { declare module "i18next" {
interface CustomTypeOptions { interface CustomTypeOptions {
+2 -2
View File
@@ -6,8 +6,8 @@ Please see LICENSE in the repository root for full details.
*/ */
import { import {
ElementCallReactionEventType, type ElementCallReactionEventType,
ECallReactionEventContent, type ECallReactionEventContent,
} from "../reactions"; } from "../reactions";
// Extend Matrix JS SDK types via Typescript declaration merging to support unspecced event fields and types // Extend Matrix JS SDK types via Typescript declaration merging to support unspecced event fields and types
+2 -2
View File
@@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { FC, Suspense, useEffect, useState } from "react"; import { type FC, Suspense, useEffect, useState } from "react";
import { import {
BrowserRouter as Router, BrowserRouter as Router,
Switch, Switch,
@@ -13,7 +13,7 @@ import {
useLocation, useLocation,
} from "react-router-dom"; } from "react-router-dom";
import * as Sentry from "@sentry/react"; import * as Sentry from "@sentry/react";
import { History } from "history"; import { type History } from "history";
import { TooltipProvider } from "@vector-im/compound-web"; import { TooltipProvider } from "@vector-im/compound-web";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
+2 -2
View File
@@ -7,8 +7,8 @@ Please see LICENSE in the repository root for full details.
import { afterEach, expect, test, vi } from "vitest"; import { afterEach, expect, test, vi } from "vitest";
import { render, screen } from "@testing-library/react"; import { render, screen } from "@testing-library/react";
import { MatrixClient } from "matrix-js-sdk/src/client"; import { type MatrixClient } from "matrix-js-sdk/src/client";
import { FC, PropsWithChildren } from "react"; import { type FC, type PropsWithChildren } from "react";
import { ClientContextProvider } from "./ClientContext"; import { ClientContextProvider } from "./ClientContext";
import { Avatar } from "./Avatar"; import { Avatar } from "./Avatar";
+8 -2
View File
@@ -5,9 +5,15 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { useMemo, FC, CSSProperties, useState, useEffect } from "react"; import {
useMemo,
type FC,
type CSSProperties,
useState,
useEffect,
} from "react";
import { Avatar as CompoundAvatar } from "@vector-im/compound-web"; import { Avatar as CompoundAvatar } from "@vector-im/compound-web";
import { MatrixClient } from "matrix-js-sdk/src/client"; import { type MatrixClient } from "matrix-js-sdk/src/client";
import { useClientState } from "./ClientContext"; import { useClientState } from "./ClientContext";
+2 -2
View File
@@ -6,7 +6,7 @@ Please see LICENSE in the repository root for full details.
*/ */
import { import {
FC, type FC,
useCallback, useCallback,
useEffect, useEffect,
useState, useState,
@@ -18,7 +18,7 @@ import {
import { useHistory } from "react-router-dom"; import { useHistory } from "react-router-dom";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { ISyncStateData, SyncState } from "matrix-js-sdk/src/sync"; import { type ISyncStateData, type SyncState } from "matrix-js-sdk/src/sync";
import { ClientEvent, type MatrixClient } from "matrix-js-sdk/src/client"; import { ClientEvent, type MatrixClient } from "matrix-js-sdk/src/client";
import type { WidgetApi } from "matrix-widget-api"; import type { WidgetApi } from "matrix-widget-api";
+2 -2
View File
@@ -6,11 +6,11 @@ Please see LICENSE in the repository root for full details.
*/ */
import classNames from "classnames"; import classNames from "classnames";
import { FC, HTMLAttributes, ReactNode } from "react"; import { type FC, type HTMLAttributes, type ReactNode } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import styles from "./DisconnectedBanner.module.css"; import styles from "./DisconnectedBanner.module.css";
import { ValidClientState, useClientState } from "./ClientContext"; import { type ValidClientState, useClientState } from "./ClientContext";
interface Props extends HTMLAttributes<HTMLElement> { interface Props extends HTMLAttributes<HTMLElement> {
children?: ReactNode; children?: ReactNode;
+1 -1
View File
@@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { FC, ReactNode, useCallback, useEffect } from "react"; import { type FC, type ReactNode, useCallback, useEffect } from "react";
import { useLocation } from "react-router-dom"; import { useLocation } from "react-router-dom";
import classNames from "classnames"; import classNames from "classnames";
import { Trans, useTranslation } from "react-i18next"; import { Trans, useTranslation } from "react-i18next";
+6 -1
View File
@@ -6,7 +6,12 @@ Please see LICENSE in the repository root for full details.
*/ */
import classNames from "classnames"; import classNames from "classnames";
import { FC, HTMLAttributes, ReactNode, forwardRef } from "react"; import {
type FC,
type HTMLAttributes,
type ReactNode,
forwardRef,
} from "react";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Heading, Text } from "@vector-im/compound-web"; import { Heading, Text } from "@vector-im/compound-web";
+1 -1
View File
@@ -7,7 +7,7 @@ Please see LICENSE in the repository root for full details.
import { expect, test } from "vitest"; import { expect, test } from "vitest";
import { render } from "@testing-library/react"; import { render } from "@testing-library/react";
import { ReactNode, useState } from "react"; import { type ReactNode, useState } from "react";
import { afterEach } from "node:test"; import { afterEach } from "node:test";
import userEvent from "@testing-library/user-event"; import userEvent from "@testing-library/user-event";
+1 -1
View File
@@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { FC, ReactNode, useCallback } from "react"; import { type FC, type ReactNode, useCallback } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { import {
Root as DialogRoot, Root as DialogRoot,
+1 -1
View File
@@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { FC, useEffect, useState } from "react"; import { type FC, useEffect, useState } from "react";
import { toDataURL } from "qrcode"; import { toDataURL } from "qrcode";
import classNames from "classnames"; import classNames from "classnames";
import { t } from "i18next"; import { t } from "i18next";
+1 -1
View File
@@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { FC, useCallback } from "react"; import { type FC, useCallback } from "react";
import { Root, Track, Range, Thumb } from "@radix-ui/react-slider"; import { Root, Track, Range, Thumb } from "@radix-ui/react-slider";
import classNames from "classnames"; import classNames from "classnames";
import { Tooltip } from "@vector-im/compound-web"; import { Tooltip } from "@vector-im/compound-web";
+3 -3
View File
@@ -6,9 +6,9 @@ Please see LICENSE in the repository root for full details.
*/ */
import { import {
ComponentType, type ComponentType,
FC, type FC,
SVGAttributes, type SVGAttributes,
useCallback, useCallback,
useEffect, useEffect,
} from "react"; } from "react";
+96 -1
View File
@@ -97,7 +97,102 @@ describe("UrlParams", () => {
}); });
it("respected in widget mode", () => { it("respected in widget mode", () => {
expect(getUrlParams("?preload=true&widgetId=12345").preload).toBe(true); expect(
getUrlParams(
"?preload=true&widgetId=12345&parentUrl=https%3A%2F%2Flocalhost%2Ffoo",
).preload,
).toBe(true);
});
});
describe("returnToLobby", () => {
it("is true in SPA mode", () => {
expect(getUrlParams("?returnToLobby=false").returnToLobby).toBe(true);
});
it("defaults to false in widget mode", () => {
expect(
getUrlParams("?widgetId=12345&parentUrl=https%3A%2F%2Flocalhost%2Ffoo")
.returnToLobby,
).toBe(false);
});
it("respected in widget mode", () => {
expect(
getUrlParams(
"?returnToLobby=true&widgetId=12345&parentUrl=https%3A%2F%2Flocalhost%2Ffoo",
).returnToLobby,
).toBe(true);
});
});
describe("userId", () => {
it("is ignored in SPA mode", () => {
expect(getUrlParams("?userId=asd").userId).toBe(null);
});
it("is parsed in widget mode", () => {
expect(
getUrlParams(
"?userId=asd&widgetId=12345&parentUrl=https%3A%2F%2Flocalhost%2Ffoo",
).userId,
).toBe("asd");
});
});
describe("deviceId", () => {
it("is ignored in SPA mode", () => {
expect(getUrlParams("?deviceId=asd").deviceId).toBe(null);
});
it("is parsed in widget mode", () => {
expect(
getUrlParams(
"?deviceId=asd&widgetId=12345&parentUrl=https%3A%2F%2Flocalhost%2Ffoo",
).deviceId,
).toBe("asd");
});
});
describe("baseUrl", () => {
it("is ignored in SPA mode", () => {
expect(getUrlParams("?baseUrl=asd").baseUrl).toBe(null);
});
it("is parsed in widget mode", () => {
expect(
getUrlParams(
"?baseUrl=asd&widgetId=12345&parentUrl=https%3A%2F%2Flocalhost%2Ffoo",
).baseUrl,
).toBe("asd");
});
});
describe("viaServers", () => {
it("is ignored in widget mode", () => {
expect(
getUrlParams(
"?viaServers=asd&widgetId=12345&parentUrl=https%3A%2F%2Flocalhost%2Ffoo",
).viaServers,
).toBe(null);
});
it("is parsed in SPA mode", () => {
expect(getUrlParams("?viaServers=asd").viaServers).toBe("asd");
});
});
describe("homeserver", () => {
it("is ignored in widget mode", () => {
expect(
getUrlParams(
"?homeserver=asd&widgetId=12345&parentUrl=https%3A%2F%2Flocalhost%2Ffoo",
).homeserver,
).toBe(null);
});
it("is parsed in SPA mode", () => {
expect(getUrlParams("?homeserver=asd").homeserver).toBe("asd");
}); });
}); });
}); });
+10 -9
View File
@@ -10,7 +10,7 @@ import { useLocation } from "react-router-dom";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import { Config } from "./config/Config"; import { Config } from "./config/Config";
import { EncryptionSystem } from "./e2ee/sharedKeyManagement"; import { type EncryptionSystem } from "./e2ee/sharedKeyManagement";
import { E2eeType } from "./e2ee/e2eeType"; import { E2eeType } from "./e2ee/e2eeType";
interface RoomIdentifier { interface RoomIdentifier {
@@ -212,11 +212,12 @@ export const getUrlParams = (
const fontScale = parseFloat(parser.getParam("fontScale") ?? ""); const fontScale = parseFloat(parser.getParam("fontScale") ?? "");
const widgetId = parser.getParam("widgetId"); const widgetId = parser.getParam("widgetId");
const isWidget = !!widgetId; const parentUrl = parser.getParam("parentUrl");
const isWidget = !!widgetId && !!parentUrl;
return { return {
widgetId, widgetId,
parentUrl: parser.getParam("parentUrl"), parentUrl,
// NB. we don't validate roomId here as we do in getRoomIdentifierFromUrl: // NB. we don't validate roomId here as we do in getRoomIdentifierFromUrl:
// what would we do if it were invalid? If the widget API says that's what // what would we do if it were invalid? If the widget API says that's what
@@ -232,10 +233,10 @@ export const getUrlParams = (
showControls: parser.getFlagParam("showControls", true), showControls: parser.getFlagParam("showControls", true),
hideScreensharing: parser.getFlagParam("hideScreensharing"), hideScreensharing: parser.getFlagParam("hideScreensharing"),
e2eEnabled: parser.getFlagParam("enableE2EE", true), e2eEnabled: parser.getFlagParam("enableE2EE", true),
userId: parser.getParam("userId"), userId: isWidget ? parser.getParam("userId") : null,
displayName: parser.getParam("displayName"), displayName: parser.getParam("displayName"),
deviceId: parser.getParam("deviceId"), deviceId: isWidget ? parser.getParam("deviceId") : null,
baseUrl: parser.getParam("baseUrl"), baseUrl: isWidget ? parser.getParam("baseUrl") : null,
lang: parser.getParam("lang"), lang: parser.getParam("lang"),
fonts: parser.getAllParams("font"), fonts: parser.getAllParams("font"),
fontScale: Number.isNaN(fontScale) ? null : fontScale, fontScale: Number.isNaN(fontScale) ? null : fontScale,
@@ -243,10 +244,10 @@ export const getUrlParams = (
allowIceFallback: parser.getFlagParam("allowIceFallback"), allowIceFallback: parser.getFlagParam("allowIceFallback"),
perParticipantE2EE: parser.getFlagParam("perParticipantE2EE"), perParticipantE2EE: parser.getFlagParam("perParticipantE2EE"),
skipLobby: parser.getFlagParam("skipLobby"), skipLobby: parser.getFlagParam("skipLobby"),
returnToLobby: parser.getFlagParam("returnToLobby"), returnToLobby: isWidget ? parser.getFlagParam("returnToLobby") : true,
theme: parser.getParam("theme"), theme: parser.getParam("theme"),
viaServers: parser.getParam("viaServers"), viaServers: !isWidget ? parser.getParam("viaServers") : null,
homeserver: parser.getParam("homeserver"), homeserver: !isWidget ? parser.getParam("homeserver") : null,
}; };
}; };
+1 -1
View File
@@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { FC, useMemo, useState } from "react"; import { type FC, useMemo, useState } from "react";
import { useLocation } from "react-router-dom"; import { useLocation } from "react-router-dom";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Menu, MenuItem } from "@vector-im/compound-web"; import { Menu, MenuItem } from "@vector-im/compound-web";
+1 -1
View File
@@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { FC, useCallback, useState } from "react"; import { type FC, useCallback, useState } from "react";
import { useHistory, useLocation } from "react-router-dom"; import { useHistory, useLocation } from "react-router-dom";
import { useClientLegacy } from "./ClientContext"; import { useClientLegacy } from "./ClientContext";
+1 -1
View File
@@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { FC } from "react"; import { type FC } from "react";
import { Trans } from "react-i18next"; import { Trans } from "react-i18next";
import { ExternalLink } from "../button/Link"; import { ExternalLink } from "../button/Link";
+6 -2
View File
@@ -5,9 +5,13 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import posthog, { CaptureOptions, PostHog, Properties } from "posthog-js"; import posthog, {
type CaptureOptions,
type PostHog,
type Properties,
} from "posthog-js";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import { MatrixClient } from "matrix-js-sdk/src/matrix"; import { type MatrixClient } from "matrix-js-sdk/src/matrix";
import { Buffer } from "buffer"; import { Buffer } from "buffer";
import { widget } from "../widget"; import { widget } from "../widget";
+3 -3
View File
@@ -5,12 +5,12 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { DisconnectReason } from "livekit-client"; import { type DisconnectReason } from "livekit-client";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import { MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc"; import { type MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc";
import { import {
IPosthogEvent, type IPosthogEvent,
PosthogAnalytics, PosthogAnalytics,
RegistrationType, RegistrationType,
} from "./PosthogAnalytics"; } from "./PosthogAnalytics";
+3 -3
View File
@@ -6,9 +6,9 @@ Please see LICENSE in the repository root for full details.
*/ */
import { import {
SpanProcessor, type SpanProcessor,
ReadableSpan, type ReadableSpan,
Span, type Span,
} from "@opentelemetry/sdk-trace-base"; } from "@opentelemetry/sdk-trace-base";
import { hrTimeToMilliseconds } from "@opentelemetry/core"; import { hrTimeToMilliseconds } from "@opentelemetry/core";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
+4 -4
View File
@@ -5,12 +5,12 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { AttributeValue, Attributes } from "@opentelemetry/api"; import { type AttributeValue, type Attributes } from "@opentelemetry/api";
import { hrTimeToMicroseconds } from "@opentelemetry/core"; import { hrTimeToMicroseconds } from "@opentelemetry/core";
import { import {
SpanProcessor, type SpanProcessor,
ReadableSpan, type ReadableSpan,
Span, type Span,
} from "@opentelemetry/sdk-trace-base"; } from "@opentelemetry/sdk-trace-base";
const dumpAttributes = ( const dumpAttributes = (
+1 -1
View File
@@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { FC, FormEvent, useCallback, useRef, useState } from "react"; import { type FC, type FormEvent, useCallback, useRef, useState } from "react";
import { useHistory, useLocation } from "react-router-dom"; import { useHistory, useLocation } from "react-router-dom";
import { Trans, useTranslation } from "react-i18next"; import { Trans, useTranslation } from "react-i18next";
import { Button } from "@vector-im/compound-web"; import { Button } from "@vector-im/compound-web";
+3 -3
View File
@@ -6,9 +6,9 @@ Please see LICENSE in the repository root for full details.
*/ */
import { import {
ChangeEvent, type ChangeEvent,
FC, type FC,
FormEvent, type FormEvent,
useCallback, useCallback,
useEffect, useEffect,
useRef, useRef,
+3 -3
View File
@@ -9,12 +9,12 @@ import { useCallback } from "react";
import { InteractiveAuth } from "matrix-js-sdk/src/interactive-auth"; import { InteractiveAuth } from "matrix-js-sdk/src/interactive-auth";
import { import {
createClient, createClient,
LoginResponse, type LoginResponse,
MatrixClient, type MatrixClient,
} from "matrix-js-sdk/src/matrix"; } from "matrix-js-sdk/src/matrix";
import { initClient } from "../utils/matrix"; import { initClient } from "../utils/matrix";
import { Session } from "../ClientContext"; import { type Session } from "../ClientContext";
/** /**
* This provides the login method to login using user credentials. * This provides the login method to login using user credentials.
* @param oldClient If there is an already authenticated client it should be passed to this hook * @param oldClient If there is an already authenticated client it should be passed to this hook
+3 -3
View File
@@ -9,13 +9,13 @@ import { useState, useEffect, useCallback, useRef } from "react";
import { InteractiveAuth } from "matrix-js-sdk/src/interactive-auth"; import { InteractiveAuth } from "matrix-js-sdk/src/interactive-auth";
import { import {
createClient, createClient,
MatrixClient, type MatrixClient,
RegisterResponse, type RegisterResponse,
} from "matrix-js-sdk/src/matrix"; } from "matrix-js-sdk/src/matrix";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import { initClient } from "../utils/matrix"; import { initClient } from "../utils/matrix";
import { Session } from "../ClientContext"; import { type Session } from "../ClientContext";
import { Config } from "../config/Config"; import { Config } from "../config/Config";
import { widget } from "../widget"; import { widget } from "../widget";
+1 -1
View File
@@ -4,7 +4,7 @@ Copyright 2022-2024 New Vector Ltd.
SPDX-License-Identifier: AGPL-3.0-only SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { ComponentPropsWithoutRef, FC } from "react"; import { type ComponentPropsWithoutRef, type FC } from "react";
import classNames from "classnames"; import classNames from "classnames";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Button as CpdButton, Tooltip } from "@vector-im/compound-web"; import { Button as CpdButton, Tooltip } from "@vector-im/compound-web";
+1 -1
View File
@@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { ComponentPropsWithoutRef, FC } from "react"; import { type ComponentPropsWithoutRef, type FC } from "react";
import { Button } from "@vector-im/compound-web"; import { Button } from "@vector-im/compound-web";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { UserAddIcon } from "@vector-im/compound-design-tokens/assets/web/icons"; import { UserAddIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
+3 -3
View File
@@ -6,15 +6,15 @@ Please see LICENSE in the repository root for full details.
*/ */
import { import {
ComponentPropsWithoutRef, type ComponentPropsWithoutRef,
forwardRef, forwardRef,
MouseEvent, type MouseEvent,
useCallback, useCallback,
useMemo, useMemo,
} from "react"; } from "react";
import { Link as CpdLink } from "@vector-im/compound-web"; import { Link as CpdLink } from "@vector-im/compound-web";
import { useHistory } from "react-router-dom"; import { useHistory } from "react-router-dom";
import { createPath, LocationDescriptor, Path } from "history"; import { createPath, type LocationDescriptor, type Path } from "history";
import classNames from "classnames"; import classNames from "classnames";
import { useLatest } from "../useLatest"; import { useLatest } from "../useLatest";
+2 -2
View File
@@ -5,9 +5,9 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { ComponentPropsWithoutRef, forwardRef } from "react"; import { type ComponentPropsWithoutRef, forwardRef } from "react";
import { Button } from "@vector-im/compound-web"; import { Button } from "@vector-im/compound-web";
import { LocationDescriptor } from "history"; import { type LocationDescriptor } from "history";
import { useLink } from "./Link"; import { useLink } from "./Link";
+1 -1
View File
@@ -9,7 +9,7 @@ import { act, render } from "@testing-library/react";
import { expect, test } from "vitest"; import { expect, test } from "vitest";
import { TooltipProvider } from "@vector-im/compound-web"; import { TooltipProvider } from "@vector-im/compound-web";
import { userEvent } from "@testing-library/user-event"; import { userEvent } from "@testing-library/user-event";
import { ReactNode } from "react"; import { type ReactNode } from "react";
import { MockRoom } from "../utils/testReactions"; import { MockRoom } from "../utils/testReactions";
import { ReactionToggleButton } from "./ReactionToggleButton"; import { ReactionToggleButton } from "./ReactionToggleButton";
+8 -4
View File
@@ -13,9 +13,9 @@ import {
ReactionSolidIcon, ReactionSolidIcon,
} from "@vector-im/compound-design-tokens/assets/web/icons"; } from "@vector-im/compound-design-tokens/assets/web/icons";
import { import {
ComponentPropsWithoutRef, type ComponentPropsWithoutRef,
FC, type FC,
ReactNode, type ReactNode,
useCallback, useCallback,
useEffect, useEffect,
useMemo, useMemo,
@@ -29,7 +29,11 @@ import { map } from "rxjs";
import { useReactions } from "../useReactions"; import { useReactions } from "../useReactions";
import styles from "./ReactionToggleButton.module.css"; import styles from "./ReactionToggleButton.module.css";
import { ReactionOption, ReactionSet, ReactionsRowSize } from "../reactions"; import {
type ReactionOption,
ReactionSet,
ReactionsRowSize,
} from "../reactions";
import { Modal } from "../Modal"; import { Modal } from "../Modal";
import { CallViewModel } from "../state/CallViewModel"; import { CallViewModel } from "../state/CallViewModel";
+2 -2
View File
@@ -10,8 +10,8 @@ import { merge } from "lodash-es";
import { getUrlParams } from "../UrlParams"; import { getUrlParams } from "../UrlParams";
import { import {
DEFAULT_CONFIG, DEFAULT_CONFIG,
ConfigOptions, type ConfigOptions,
ResolvedConfigOptions, type ResolvedConfigOptions,
} from "./ConfigOptions"; } from "./ConfigOptions";
export class Config { export class Config {
+1 -1
View File
@@ -7,7 +7,7 @@ Please see LICENSE in the repository root for full details.
import { describe, expect, test, vi } from "vitest"; import { describe, expect, test, vi } from "vitest";
import { import {
MatrixRTCSession, type MatrixRTCSession,
MatrixRTCSessionEvent, MatrixRTCSessionEvent,
} from "matrix-js-sdk/src/matrixrtc"; } from "matrix-js-sdk/src/matrixrtc";
import { KeyProviderEvent } from "livekit-client"; import { KeyProviderEvent } from "livekit-client";
+1 -1
View File
@@ -8,7 +8,7 @@ Please see LICENSE in the repository root for full details.
import { BaseKeyProvider, createKeyMaterialFromBuffer } from "livekit-client"; import { BaseKeyProvider, createKeyMaterialFromBuffer } from "livekit-client";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import { import {
MatrixRTCSession, type MatrixRTCSession,
MatrixRTCSessionEvent, MatrixRTCSessionEvent,
} from "matrix-js-sdk/src/matrixrtc/MatrixRTCSession"; } from "matrix-js-sdk/src/matrixrtc/MatrixRTCSession";
+1 -1
View File
@@ -8,7 +8,7 @@ Please see LICENSE in the repository root for full details.
import { useEffect, useMemo } from "react"; import { useEffect, useMemo } from "react";
import { setLocalStorageItem, useLocalStorage } from "../useLocalStorage"; import { setLocalStorageItem, useLocalStorage } from "../useLocalStorage";
import { UrlParams, getUrlParams, useUrlParams } from "../UrlParams"; import { type UrlParams, getUrlParams, useUrlParams } from "../UrlParams";
import { E2eeType } from "./e2eeType"; import { E2eeType } from "./e2eeType";
import { useClient } from "../ClientContext"; import { useClient } from "../ClientContext";
+1 -1
View File
@@ -6,7 +6,7 @@ Please see LICENSE in the repository root for full details.
*/ */
import classNames from "classnames"; import classNames from "classnames";
import { FormEventHandler, forwardRef, ReactNode } from "react"; import { type FormEventHandler, forwardRef, type ReactNode } from "react";
import styles from "./Form.module.css"; import styles from "./Form.module.css";
+4 -4
View File
@@ -5,11 +5,11 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { BehaviorSubject, Observable } from "rxjs"; import { type BehaviorSubject, type Observable } from "rxjs";
import { ComponentType } from "react"; import { type ComponentType } from "react";
import { LayoutProps } from "./Grid"; import { type LayoutProps } from "./Grid";
import { TileViewModel } from "../state/TileViewModel"; import { type TileViewModel } from "../state/TileViewModel";
export interface Bounds { export interface Bounds {
width: number; width: number;
+12 -12
View File
@@ -6,21 +6,21 @@ Please see LICENSE in the repository root for full details.
*/ */
import { import {
SpringRef, type SpringRef,
TransitionFn, type TransitionFn,
animated, type animated,
useTransition, useTransition,
} from "@react-spring/web"; } from "@react-spring/web";
import { EventTypes, Handler, useScroll } from "@use-gesture/react"; import { type EventTypes, type Handler, useScroll } from "@use-gesture/react";
import { import {
CSSProperties, type CSSProperties,
ComponentProps, type ComponentProps,
ComponentType, type ComponentType,
Dispatch, type Dispatch,
FC, type FC,
LegacyRef, type LegacyRef,
ReactNode, type ReactNode,
SetStateAction, type SetStateAction,
createContext, createContext,
forwardRef, forwardRef,
memo, memo,
+4 -4
View File
@@ -5,15 +5,15 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { CSSProperties, forwardRef, useCallback, useMemo } from "react"; import { type CSSProperties, forwardRef, useCallback, useMemo } from "react";
import { distinctUntilChanged } from "rxjs"; import { distinctUntilChanged } from "rxjs";
import { useObservableEagerState } from "observable-hooks"; import { useObservableEagerState } from "observable-hooks";
import { GridLayout as GridLayoutModel } from "../state/CallViewModel"; import { type GridLayout as GridLayoutModel } from "../state/CallViewModel";
import styles from "./GridLayout.module.css"; import styles from "./GridLayout.module.css";
import { useInitial } from "../useInitial"; import { useInitial } from "../useInitial";
import { CallLayout, arrangeTiles } from "./CallLayout"; import { type CallLayout, arrangeTiles } from "./CallLayout";
import { DragCallback, useUpdateLayout } from "./Grid"; import { type DragCallback, useUpdateLayout } from "./Grid";
interface GridCSSProperties extends CSSProperties { interface GridCSSProperties extends CSSProperties {
"--gap": string; "--gap": string;
+3 -3
View File
@@ -9,10 +9,10 @@ import { forwardRef, useCallback, useMemo } from "react";
import { useObservableEagerState } from "observable-hooks"; import { useObservableEagerState } from "observable-hooks";
import classNames from "classnames"; import classNames from "classnames";
import { OneOnOneLayout as OneOnOneLayoutModel } from "../state/CallViewModel"; import { type OneOnOneLayout as OneOnOneLayoutModel } from "../state/CallViewModel";
import { CallLayout, arrangeTiles } from "./CallLayout"; import { type CallLayout, arrangeTiles } from "./CallLayout";
import styles from "./OneOnOneLayout.module.css"; import styles from "./OneOnOneLayout.module.css";
import { DragCallback, useUpdateLayout } from "./Grid"; import { type DragCallback, useUpdateLayout } from "./Grid";
/** /**
* An implementation of the "one-on-one" layout, in which the remote participant * An implementation of the "one-on-one" layout, in which the remote participant
+3 -3
View File
@@ -8,9 +8,9 @@ Please see LICENSE in the repository root for full details.
import { forwardRef, useCallback } from "react"; import { forwardRef, useCallback } from "react";
import { useObservableEagerState } from "observable-hooks"; import { useObservableEagerState } from "observable-hooks";
import { SpotlightExpandedLayout as SpotlightExpandedLayoutModel } from "../state/CallViewModel"; import { type SpotlightExpandedLayout as SpotlightExpandedLayoutModel } from "../state/CallViewModel";
import { CallLayout } from "./CallLayout"; import { type CallLayout } from "./CallLayout";
import { DragCallback, useUpdateLayout } from "./Grid"; import { type DragCallback, useUpdateLayout } from "./Grid";
import styles from "./SpotlightExpandedLayout.module.css"; import styles from "./SpotlightExpandedLayout.module.css";
/** /**
+2 -2
View File
@@ -9,8 +9,8 @@ import { forwardRef } from "react";
import { useObservableEagerState } from "observable-hooks"; import { useObservableEagerState } from "observable-hooks";
import classNames from "classnames"; import classNames from "classnames";
import { CallLayout } from "./CallLayout"; import { type CallLayout } from "./CallLayout";
import { SpotlightLandscapeLayout as SpotlightLandscapeLayoutModel } from "../state/CallViewModel"; import { type SpotlightLandscapeLayout as SpotlightLandscapeLayoutModel } from "../state/CallViewModel";
import styles from "./SpotlightLandscapeLayout.module.css"; import styles from "./SpotlightLandscapeLayout.module.css";
import { useUpdateLayout } from "./Grid"; import { useUpdateLayout } from "./Grid";
+3 -3
View File
@@ -5,12 +5,12 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { CSSProperties, forwardRef } from "react"; import { type CSSProperties, forwardRef } from "react";
import { useObservableEagerState } from "observable-hooks"; import { useObservableEagerState } from "observable-hooks";
import classNames from "classnames"; import classNames from "classnames";
import { CallLayout, arrangeTiles } from "./CallLayout"; import { type CallLayout, arrangeTiles } from "./CallLayout";
import { SpotlightPortraitLayout as SpotlightPortraitLayoutModel } from "../state/CallViewModel"; import { type SpotlightPortraitLayout as SpotlightPortraitLayoutModel } from "../state/CallViewModel";
import styles from "./SpotlightPortraitLayout.module.css"; import styles from "./SpotlightPortraitLayout.module.css";
import { useUpdateLayout } from "./Grid"; import { useUpdateLayout } from "./Grid";
+4 -4
View File
@@ -5,12 +5,12 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { ComponentType, memo, RefObject, useRef } from "react"; import { type ComponentType, memo, type RefObject, useRef } from "react";
import { EventTypes, Handler, useDrag } from "@use-gesture/react"; import { type EventTypes, type Handler, useDrag } from "@use-gesture/react";
import { SpringValue } from "@react-spring/web"; import { type SpringValue } from "@react-spring/web";
import classNames from "classnames"; import classNames from "classnames";
import { TileProps } from "./Grid"; import { type TileProps } from "./Grid";
import styles from "./TileWrapper.module.css"; import styles from "./TileWrapper.module.css";
interface Props<M, R extends HTMLElement> { interface Props<M, R extends HTMLElement> {
+3 -3
View File
@@ -5,13 +5,13 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { render, RenderResult } from "@testing-library/react"; import { render, type RenderResult } from "@testing-library/react";
import { MatrixClient } from "matrix-js-sdk/src/matrix"; import { type MatrixClient } from "matrix-js-sdk/src/matrix";
import { MemoryRouter } from "react-router-dom"; import { MemoryRouter } from "react-router-dom";
import { describe, expect, it } from "vitest"; import { describe, expect, it } from "vitest";
import { CallList } from "../../src/home/CallList"; import { CallList } from "../../src/home/CallList";
import { GroupCallRoom } from "../../src/home/useGroupCallRooms"; import { type GroupCallRoom } from "../../src/home/useGroupCallRooms";
describe("CallList", () => { describe("CallList", () => {
const renderComponent = (rooms: GroupCallRoom[]): RenderResult => { const renderComponent = (rooms: GroupCallRoom[]): RenderResult => {
+5 -5
View File
@@ -6,10 +6,10 @@ Please see LICENSE in the repository root for full details.
*/ */
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import { MatrixClient } from "matrix-js-sdk/src/client"; import { type MatrixClient } from "matrix-js-sdk/src/client";
import { RoomMember } from "matrix-js-sdk/src/models/room-member"; import { type RoomMember } from "matrix-js-sdk/src/models/room-member";
import { Room } from "matrix-js-sdk/src/models/room"; import { type Room } from "matrix-js-sdk/src/models/room";
import { FC, useCallback, MouseEvent, useState } from "react"; import { type FC, useCallback, type MouseEvent, useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { IconButton, Text } from "@vector-im/compound-web"; import { IconButton, Text } from "@vector-im/compound-web";
import { CloseIcon } from "@vector-im/compound-design-tokens/assets/web/icons"; import { CloseIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
@@ -18,7 +18,7 @@ import classNames from "classnames";
import { Avatar, Size } from "../Avatar"; import { Avatar, Size } from "../Avatar";
import styles from "./CallList.module.css"; import styles from "./CallList.module.css";
import { getRelativeRoomUrl } from "../utils/matrix"; import { getRelativeRoomUrl } from "../utils/matrix";
import { GroupCallRoom } from "./useGroupCallRooms"; import { type GroupCallRoom } from "./useGroupCallRooms";
import { useRoomEncryptionSystem } from "../e2ee/sharedKeyManagement"; import { useRoomEncryptionSystem } from "../e2ee/sharedKeyManagement";
interface CallListProps { interface CallListProps {
+1 -1
View File
@@ -6,7 +6,7 @@ Please see LICENSE in the repository root for full details.
*/ */
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { FC } from "react"; import { type FC } from "react";
import { useClientState } from "../ClientContext"; import { useClientState } from "../ClientContext";
import { ErrorView, LoadingView } from "../FullScreenView"; import { ErrorView, LoadingView } from "../FullScreenView";
+1 -1
View File
@@ -6,7 +6,7 @@ Please see LICENSE in the repository root for full details.
*/ */
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { FC, MouseEvent } from "react"; import { type FC, type MouseEvent } from "react";
import { Button } from "@vector-im/compound-web"; import { Button } from "@vector-im/compound-web";
import { Modal } from "../Modal"; import { Modal } from "../Modal";
+8 -2
View File
@@ -5,9 +5,15 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { useState, useCallback, FormEvent, FormEventHandler, FC } from "react"; import {
useState,
useCallback,
type FormEvent,
type FormEventHandler,
type FC,
} from "react";
import { useHistory } from "react-router-dom"; import { useHistory } from "react-router-dom";
import { MatrixClient } from "matrix-js-sdk/src/client"; import { type MatrixClient } from "matrix-js-sdk/src/client";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Heading, Text } from "@vector-im/compound-web"; import { Heading, Text } from "@vector-im/compound-web";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
+1 -1
View File
@@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { FC, useCallback, useState, FormEventHandler } from "react"; import { type FC, useCallback, useState, type FormEventHandler } from "react";
import { useHistory } from "react-router-dom"; import { useHistory } from "react-router-dom";
import { randomString } from "matrix-js-sdk/src/randomstring"; import { randomString } from "matrix-js-sdk/src/randomstring";
import { Trans, useTranslation } from "react-i18next"; import { Trans, useTranslation } from "react-i18next";
+4 -4
View File
@@ -5,12 +5,12 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { MatrixClient } from "matrix-js-sdk/src/client"; import { type MatrixClient } from "matrix-js-sdk/src/client";
import { Room, RoomEvent } from "matrix-js-sdk/src/models/room"; import { type Room, RoomEvent } from "matrix-js-sdk/src/models/room";
import { RoomMember } from "matrix-js-sdk/src/models/room-member"; import { type RoomMember } from "matrix-js-sdk/src/models/room-member";
import { useState, useEffect } from "react"; import { useState, useEffect } from "react";
import { EventTimeline, EventType, JoinRule } from "matrix-js-sdk/src/matrix"; import { EventTimeline, EventType, JoinRule } from "matrix-js-sdk/src/matrix";
import { MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc/MatrixRTCSession"; import { type MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc/MatrixRTCSession";
import { MatrixRTCSessionManagerEvents } from "matrix-js-sdk/src/matrixrtc/MatrixRTCSessionManager"; import { MatrixRTCSessionManagerEvents } from "matrix-js-sdk/src/matrixrtc/MatrixRTCSessionManager";
import { KnownMembership } from "matrix-js-sdk/src/types"; import { KnownMembership } from "matrix-js-sdk/src/types";
+3 -3
View File
@@ -6,13 +6,13 @@ Please see LICENSE in the repository root for full details.
*/ */
import { import {
AllHTMLAttributes, type AllHTMLAttributes,
useEffect, useEffect,
useCallback, useCallback,
useState, useState,
ChangeEvent, type ChangeEvent,
useRef, useRef,
FC, type FC,
} from "react"; } from "react";
import classNames from "classnames"; import classNames from "classnames";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
+4 -4
View File
@@ -6,11 +6,11 @@ Please see LICENSE in the repository root for full details.
*/ */
import { import {
ChangeEvent, type ChangeEvent,
FC, type FC,
ForwardedRef, type ForwardedRef,
forwardRef, forwardRef,
ReactNode, type ReactNode,
useId, useId,
} from "react"; } from "react";
import classNames from "classnames"; import classNames from "classnames";
+3 -3
View File
@@ -6,7 +6,7 @@ Please see LICENSE in the repository root for full details.
*/ */
import { import {
FC, type FC,
createContext, createContext,
useCallback, useCallback,
useContext, useContext,
@@ -16,7 +16,7 @@ import {
useState, useState,
} from "react"; } from "react";
import { createMediaDeviceObserver } from "@livekit/components-core"; import { createMediaDeviceObserver } from "@livekit/components-core";
import { Observable } from "rxjs"; import { type Observable } from "rxjs";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import { import {
@@ -24,7 +24,7 @@ import {
audioInput as audioInputSetting, audioInput as audioInputSetting,
audioOutput as audioOutputSetting, audioOutput as audioOutputSetting,
videoInput as videoInputSetting, videoInput as videoInputSetting,
Setting, type Setting,
} from "../settings/settings"; } from "../settings/settings";
import { isFirefox } from "../Platform"; import { isFirefox } from "../Platform";
+3 -3
View File
@@ -5,11 +5,11 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { IOpenIDToken, MatrixClient } from "matrix-js-sdk/src/matrix"; import { type IOpenIDToken, type MatrixClient } from "matrix-js-sdk/src/matrix";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import { MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc/MatrixRTCSession"; import { type MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc/MatrixRTCSession";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { LivekitFocus } from "matrix-js-sdk/src/matrixrtc/LivekitFocus"; import { type LivekitFocus } from "matrix-js-sdk/src/matrixrtc/LivekitFocus";
import { useActiveLivekitFocus } from "../room/useActiveFocus"; import { useActiveLivekitFocus } from "../room/useActiveFocus";
+3 -3
View File
@@ -8,10 +8,10 @@ Please see LICENSE in the repository root for full details.
import { import {
AudioPresets, AudioPresets,
DefaultReconnectPolicy, DefaultReconnectPolicy,
RoomOptions, type RoomOptions,
ScreenSharePresets, ScreenSharePresets,
TrackPublishDefaults, type TrackPublishDefaults,
VideoPreset, type VideoPreset,
VideoPresets, VideoPresets,
} from "livekit-client"; } from "livekit-client";
+4 -4
View File
@@ -6,10 +6,10 @@ Please see LICENSE in the repository root for full details.
*/ */
import { import {
AudioCaptureOptions, type AudioCaptureOptions,
ConnectionState, ConnectionState,
LocalTrack, type LocalTrack,
Room, type Room,
RoomEvent, RoomEvent,
Track, Track,
} from "livekit-client"; } from "livekit-client";
@@ -17,7 +17,7 @@ import { useCallback, useEffect, useRef, useState } from "react";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import * as Sentry from "@sentry/react"; import * as Sentry from "@sentry/react";
import { SFUConfig, sfuConfigEquals } from "./openIDSFU"; import { type SFUConfig, sfuConfigEquals } from "./openIDSFU";
import { PosthogAnalytics } from "../analytics/PosthogAnalytics"; import { PosthogAnalytics } from "../analytics/PosthogAnalytics";
declare global { declare global {
+9 -9
View File
@@ -7,32 +7,32 @@ Please see LICENSE in the repository root for full details.
import { import {
ConnectionState, ConnectionState,
E2EEOptions, type E2EEOptions,
ExternalE2EEKeyProvider, ExternalE2EEKeyProvider,
Room, Room,
RoomOptions, type RoomOptions,
Track, Track,
} from "livekit-client"; } from "livekit-client";
import { useEffect, useMemo, useRef } from "react"; import { useEffect, useMemo, useRef } from "react";
import E2EEWorker from "livekit-client/e2ee-worker?worker"; import E2EEWorker from "livekit-client/e2ee-worker?worker";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import { MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc/MatrixRTCSession"; import { type MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc/MatrixRTCSession";
import { defaultLiveKitOptions } from "./options"; import { defaultLiveKitOptions } from "./options";
import { SFUConfig } from "./openIDSFU"; import { type SFUConfig } from "./openIDSFU";
import { MuteStates } from "../room/MuteStates"; import { type MuteStates } from "../room/MuteStates";
import { import {
MediaDevice, type MediaDevice,
MediaDevices, type MediaDevices,
useMediaDevices, useMediaDevices,
} from "./MediaDevicesContext"; } from "./MediaDevicesContext";
import { import {
ECConnectionState, type ECConnectionState,
useECConnectionState, useECConnectionState,
} from "./useECConnectionState"; } from "./useECConnectionState";
import { MatrixKeyProvider } from "../e2ee/matrixKeyProvider"; import { MatrixKeyProvider } from "../e2ee/matrixKeyProvider";
import { E2eeType } from "../e2ee/e2eeType"; import { E2eeType } from "../e2ee/e2eeType";
import { EncryptionSystem } from "../e2ee/sharedKeyManagement"; import { type EncryptionSystem } from "../e2ee/sharedKeyManagement";
interface UseLivekitResult { interface UseLivekitResult {
livekitRoom?: Room; livekitRoom?: Room;
+5 -5
View File
@@ -5,17 +5,17 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { Span } from "@opentelemetry/api"; import { type Span } from "@opentelemetry/api";
import { MatrixCall } from "matrix-js-sdk/src/matrix"; import { type MatrixCall } from "matrix-js-sdk/src/matrix";
import { CallEvent } from "matrix-js-sdk/src/webrtc/call"; import { CallEvent } from "matrix-js-sdk/src/webrtc/call";
import { import {
TransceiverStats, type TransceiverStats,
CallFeedStats, type CallFeedStats,
} from "matrix-js-sdk/src/webrtc/stats/statsReport"; } from "matrix-js-sdk/src/webrtc/stats/statsReport";
import { ObjectFlattener } from "./ObjectFlattener"; import { ObjectFlattener } from "./ObjectFlattener";
import { ElementCallOpenTelemetry } from "./otel"; import { ElementCallOpenTelemetry } from "./otel";
import { OTelCallAbstractMediaStreamSpan } from "./OTelCallAbstractMediaStreamSpan"; import { type OTelCallAbstractMediaStreamSpan } from "./OTelCallAbstractMediaStreamSpan";
import { OTelCallTransceiverMediaStreamSpan } from "./OTelCallTransceiverMediaStreamSpan"; import { OTelCallTransceiverMediaStreamSpan } from "./OTelCallTransceiverMediaStreamSpan";
import { OTelCallFeedMediaStreamSpan } from "./OTelCallFeedMediaStreamSpan"; import { OTelCallFeedMediaStreamSpan } from "./OTelCallFeedMediaStreamSpan";
+3 -3
View File
@@ -5,10 +5,10 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import opentelemetry, { Span } from "@opentelemetry/api"; import opentelemetry, { type Span } from "@opentelemetry/api";
import { TrackStats } from "matrix-js-sdk/src/webrtc/stats/statsReport"; import { type TrackStats } from "matrix-js-sdk/src/webrtc/stats/statsReport";
import { ElementCallOpenTelemetry } from "./otel"; import { type ElementCallOpenTelemetry } from "./otel";
import { OTelCallMediaStreamTrackSpan } from "./OTelCallMediaStreamTrackSpan"; import { OTelCallMediaStreamTrackSpan } from "./OTelCallMediaStreamTrackSpan";
type TrackId = string; type TrackId = string;
+4 -4
View File
@@ -5,13 +5,13 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { Span } from "@opentelemetry/api"; import { type Span } from "@opentelemetry/api";
import { import {
CallFeedStats, type CallFeedStats,
TrackStats, type TrackStats,
} from "matrix-js-sdk/src/webrtc/stats/statsReport"; } from "matrix-js-sdk/src/webrtc/stats/statsReport";
import { ElementCallOpenTelemetry } from "./otel"; import { type ElementCallOpenTelemetry } from "./otel";
import { OTelCallAbstractMediaStreamSpan } from "./OTelCallAbstractMediaStreamSpan"; import { OTelCallAbstractMediaStreamSpan } from "./OTelCallAbstractMediaStreamSpan";
export class OTelCallFeedMediaStreamSpan extends OTelCallAbstractMediaStreamSpan { export class OTelCallFeedMediaStreamSpan extends OTelCallAbstractMediaStreamSpan {
+3 -3
View File
@@ -5,10 +5,10 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { TrackStats } from "matrix-js-sdk/src/webrtc/stats/statsReport"; import { type TrackStats } from "matrix-js-sdk/src/webrtc/stats/statsReport";
import opentelemetry, { Span } from "@opentelemetry/api"; import opentelemetry, { type Span } from "@opentelemetry/api";
import { ElementCallOpenTelemetry } from "./otel"; import { type ElementCallOpenTelemetry } from "./otel";
export class OTelCallMediaStreamTrackSpan { export class OTelCallMediaStreamTrackSpan {
private readonly span: Span; private readonly span: Span;
@@ -5,13 +5,13 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { Span } from "@opentelemetry/api"; import { type Span } from "@opentelemetry/api";
import { import {
TrackStats, type TrackStats,
TransceiverStats, type TransceiverStats,
} from "matrix-js-sdk/src/webrtc/stats/statsReport"; } from "matrix-js-sdk/src/webrtc/stats/statsReport";
import { ElementCallOpenTelemetry } from "./otel"; import { type ElementCallOpenTelemetry } from "./otel";
import { OTelCallAbstractMediaStreamSpan } from "./OTelCallAbstractMediaStreamSpan"; import { OTelCallAbstractMediaStreamSpan } from "./OTelCallAbstractMediaStreamSpan";
export class OTelCallTransceiverMediaStreamSpan extends OTelCallAbstractMediaStreamSpan { export class OTelCallTransceiverMediaStreamSpan extends OTelCallAbstractMediaStreamSpan {
+20 -16
View File
@@ -5,31 +5,35 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import opentelemetry, { Span, Attributes, Context } from "@opentelemetry/api"; import opentelemetry, {
type Span,
type Attributes,
type Context,
} from "@opentelemetry/api";
import { import {
GroupCall, type GroupCall,
MatrixClient, type MatrixClient,
MatrixEvent, type MatrixEvent,
RoomMember, type RoomMember,
} from "matrix-js-sdk/src/matrix"; } from "matrix-js-sdk/src/matrix";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import { import {
CallError, type CallError,
CallState, type CallState,
MatrixCall, type MatrixCall,
VoipEvent, type VoipEvent,
} from "matrix-js-sdk/src/webrtc/call"; } from "matrix-js-sdk/src/webrtc/call";
import { import {
CallsByUserAndDevice, type CallsByUserAndDevice,
GroupCallError, type GroupCallError,
GroupCallEvent, GroupCallEvent,
GroupCallStatsReport, type GroupCallStatsReport,
} from "matrix-js-sdk/src/webrtc/groupCall"; } from "matrix-js-sdk/src/webrtc/groupCall";
import { import {
ConnectionStatsReport, type ConnectionStatsReport,
ByteSentStatsReport, type ByteSentStatsReport,
SummaryStatsReport, type SummaryStatsReport,
CallFeedReport, type CallFeedReport,
} from "matrix-js-sdk/src/webrtc/stats/statsReport"; } from "matrix-js-sdk/src/webrtc/stats/statsReport";
import { ElementCallOpenTelemetry } from "./otel"; import { ElementCallOpenTelemetry } from "./otel";
+4 -4
View File
@@ -5,11 +5,11 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { GroupCallStatsReport } from "matrix-js-sdk/src/webrtc/groupCall"; import { type GroupCallStatsReport } from "matrix-js-sdk/src/webrtc/groupCall";
import { import {
AudioConcealment, type AudioConcealment,
ByteSentStatsReport, type ByteSentStatsReport,
ConnectionStatsReport, type ConnectionStatsReport,
} from "matrix-js-sdk/src/webrtc/stats/statsReport"; } from "matrix-js-sdk/src/webrtc/stats/statsReport";
import { describe, expect, it } from "vitest"; import { describe, expect, it } from "vitest";
+6 -6
View File
@@ -4,13 +4,13 @@ Copyright 2023, 2024 New Vector Ltd.
SPDX-License-Identifier: AGPL-3.0-only SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { Attributes } from "@opentelemetry/api"; import { type Attributes } from "@opentelemetry/api";
import { VoipEvent } from "matrix-js-sdk/src/webrtc/call"; import { type VoipEvent } from "matrix-js-sdk/src/webrtc/call";
import { GroupCallStatsReport } from "matrix-js-sdk/src/webrtc/groupCall"; import { type GroupCallStatsReport } from "matrix-js-sdk/src/webrtc/groupCall";
import { import {
ByteSentStatsReport, type ByteSentStatsReport,
ConnectionStatsReport, type ConnectionStatsReport,
SummaryStatsReport, type SummaryStatsReport,
} from "matrix-js-sdk/src/webrtc/stats/statsReport"; } from "matrix-js-sdk/src/webrtc/stats/statsReport";
export class ObjectFlattener { export class ObjectFlattener {
+1 -1
View File
@@ -8,7 +8,7 @@ Please see LICENSE in the repository root for full details.
import { SimpleSpanProcessor } from "@opentelemetry/sdk-trace-base"; import { SimpleSpanProcessor } from "@opentelemetry/sdk-trace-base";
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http"; import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
import { WebTracerProvider } from "@opentelemetry/sdk-trace-web"; import { WebTracerProvider } from "@opentelemetry/sdk-trace-web";
import opentelemetry, { Tracer } from "@opentelemetry/api"; import opentelemetry, { type Tracer } from "@opentelemetry/api";
import { Resource } from "@opentelemetry/resources"; import { Resource } from "@opentelemetry/resources";
import { SemanticResourceAttributes } from "@opentelemetry/semantic-conventions"; import { SemanticResourceAttributes } from "@opentelemetry/semantic-conventions";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
+4 -4
View File
@@ -5,10 +5,10 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { MatrixClient } from "matrix-js-sdk/src/client"; import { type MatrixClient } from "matrix-js-sdk/src/client";
import { MatrixEvent } from "matrix-js-sdk/src/models/event"; import { type MatrixEvent } from "matrix-js-sdk/src/models/event";
import { User, UserEvent } from "matrix-js-sdk/src/models/user"; import { type User, UserEvent } from "matrix-js-sdk/src/models/user";
import { FileType } from "matrix-js-sdk/src/http-api"; import { type FileType } from "matrix-js-sdk/src/http-api";
import { useState, useCallback, useEffect } from "react"; import { useState, useCallback, useEffect } from "react";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
+2 -2
View File
@@ -6,8 +6,8 @@ Please see LICENSE in the repository root for full details.
*/ */
import { import {
MouseEventHandler, type MouseEventHandler,
ReactNode, type ReactNode,
useCallback, useCallback,
useEffect, useEffect,
useState, useState,
+1 -1
View File
@@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { PropsWithChildren, ReactNode } from "react"; import { type PropsWithChildren, type ReactNode } from "react";
import classNames from "classnames"; import classNames from "classnames";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
+1 -1
View File
@@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { RelationType } from "matrix-js-sdk/src/types"; import { type RelationType } from "matrix-js-sdk/src/types";
import catSoundOgg from "../sound/reactions/cat.ogg?url"; import catSoundOgg from "../sound/reactions/cat.ogg?url";
import catSoundMp3 from "../sound/reactions/cat.mp3?url"; import catSoundMp3 from "../sound/reactions/cat.mp3?url";
+7 -1
View File
@@ -5,7 +5,13 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { FC, MouseEvent, useCallback, useMemo, useState } from "react"; import {
type FC,
type MouseEvent,
useCallback,
useMemo,
useState,
} from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Button, Text } from "@vector-im/compound-web"; import { Button, Text } from "@vector-im/compound-web";
import { PopOutIcon } from "@vector-im/compound-design-tokens/assets/web/icons"; import { PopOutIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
+8 -2
View File
@@ -5,8 +5,14 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { FC, FormEventHandler, ReactNode, useCallback, useState } from "react"; import {
import { MatrixClient } from "matrix-js-sdk/src/client"; type FC,
type FormEventHandler,
type ReactNode,
useCallback,
useState,
} from "react";
import { type MatrixClient } from "matrix-js-sdk/src/client";
import { Trans, useTranslation } from "react-i18next"; import { Trans, useTranslation } from "react-i18next";
import { useHistory } from "react-router-dom"; import { useHistory } from "react-router-dom";
import { Button, Heading, Text } from "@vector-im/compound-web"; import { Button, Heading, Text } from "@vector-im/compound-web";
+2 -2
View File
@@ -10,13 +10,13 @@ import {
afterAll, afterAll,
beforeEach, beforeEach,
expect, expect,
MockedFunction, type MockedFunction,
test, test,
vitest, vitest,
} from "vitest"; } from "vitest";
import { afterEach } from "node:test"; import { afterEach } from "node:test";
import { act } from "react"; import { act } from "react";
import { CallMembership } from "matrix-js-sdk/src/matrixrtc"; import { type CallMembership } from "matrix-js-sdk/src/matrixrtc";
import { mockRtcMembership } from "../utils/test"; import { mockRtcMembership } from "../utils/test";
import { import {
+6 -6
View File
@@ -5,10 +5,10 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { ReactNode, useEffect } from "react"; import { type ReactNode, useEffect } from "react";
import { filter, interval, throttle } from "rxjs"; import { filter, interval, throttle } from "rxjs";
import { CallViewModel } from "../state/CallViewModel"; import { type CallViewModel } from "../state/CallViewModel";
import joinCallSoundMp3 from "../sound/join_call.mp3"; import joinCallSoundMp3 from "../sound/join_call.mp3";
import joinCallSoundOgg from "../sound/join_call.ogg"; import joinCallSoundOgg from "../sound/join_call.ogg";
import leftCallSoundMp3 from "../sound/left_call.mp3"; import leftCallSoundMp3 from "../sound/left_call.mp3";
@@ -24,7 +24,7 @@ import { useLatest } from "../useLatest";
export const MAX_PARTICIPANT_COUNT_FOR_SOUND = 8; export const MAX_PARTICIPANT_COUNT_FOR_SOUND = 8;
export const THROTTLE_SOUND_EFFECT_MS = 500; export const THROTTLE_SOUND_EFFECT_MS = 500;
const sounds = prefetchSounds({ export const callEventAudioSounds = prefetchSounds({
join: { join: {
mp3: joinCallSoundMp3, mp3: joinCallSoundMp3,
ogg: joinCallSoundOgg, ogg: joinCallSoundOgg,
@@ -45,7 +45,7 @@ export function CallEventAudioRenderer({
vm: CallViewModel; vm: CallViewModel;
}): ReactNode { }): ReactNode {
const audioEngineCtx = useAudioContext({ const audioEngineCtx = useAudioContext({
sounds, sounds: callEventAudioSounds,
latencyHint: "interactive", latencyHint: "interactive",
}); });
const audioEngineRef = useLatest(audioEngineCtx); const audioEngineRef = useLatest(audioEngineCtx);
@@ -60,7 +60,7 @@ export function CallEventAudioRenderer({
throttle(() => interval(THROTTLE_SOUND_EFFECT_MS)), throttle(() => interval(THROTTLE_SOUND_EFFECT_MS)),
) )
.subscribe(() => { .subscribe(() => {
audioEngineRef.current?.playSound("join"); void audioEngineRef.current?.playSound("join");
}); });
const leftSub = vm.memberChanges const leftSub = vm.memberChanges
@@ -72,7 +72,7 @@ export function CallEventAudioRenderer({
throttle(() => interval(THROTTLE_SOUND_EFFECT_MS)), throttle(() => interval(THROTTLE_SOUND_EFFECT_MS)),
) )
.subscribe(() => { .subscribe(() => {
audioEngineRef.current?.playSound("left"); void audioEngineRef.current?.playSound("left");
}); });
const handRaisedSub = vm.handRaised.subscribe(() => { const handRaisedSub = vm.handRaised.subscribe(() => {
+1 -1
View File
@@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { FC } from "react"; import { type FC } from "react";
import { Tooltip } from "@vector-im/compound-web"; import { Tooltip } from "@vector-im/compound-web";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { import {
+153
View File
@@ -0,0 +1,153 @@
/*
Copyright 2024 New Vector Ltd.
SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details.
*/
import { beforeEach, expect, type MockedFunction, test, vitest } from "vitest";
import { render } from "@testing-library/react";
import { type MatrixClient } from "matrix-js-sdk/src/client";
import { type MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc";
import { of } from "rxjs";
import { JoinRule, type RoomState } from "matrix-js-sdk/src/matrix";
import { Router } from "react-router-dom";
import { createBrowserHistory } from "history";
import userEvent from "@testing-library/user-event";
import { type MuteStates } from "./MuteStates";
import { prefetchSounds } from "../soundUtils";
import { useAudioContext } from "../useAudioContext";
import { ActiveCall } from "./InCallView";
import {
mockMatrixRoom,
mockMatrixRoomMember,
mockRtcMembership,
MockRTCSession,
} from "../utils/test";
import { GroupCallView } from "./GroupCallView";
import { leaveRTCSession } from "../rtcSessionHelpers";
import { type WidgetHelpers } from "../widget";
import { LazyEventEmitter } from "../LazyEventEmitter";
vitest.mock("../soundUtils");
vitest.mock("../useAudioContext");
vitest.mock("./InCallView");
vitest.mock("../rtcSessionHelpers", async (importOriginal) => {
// TODO: perhaps there is a more elegant way to manage the type import here?
// eslint-disable-next-line @typescript-eslint/consistent-type-imports
const orig = await importOriginal<typeof import("../rtcSessionHelpers")>();
vitest.spyOn(orig, "leaveRTCSession");
return orig;
});
let playSound: MockedFunction<
NonNullable<ReturnType<typeof useAudioContext>>["playSound"]
>;
const localRtcMember = mockRtcMembership("@carol:example.org", "CCCC");
const carol = mockMatrixRoomMember(localRtcMember);
const roomMembers = new Map([carol].map((p) => [p.userId, p]));
const roomId = "!foo:bar";
const soundPromise = Promise.resolve(true);
beforeEach(() => {
(prefetchSounds as MockedFunction<typeof prefetchSounds>).mockResolvedValue({
sound: new ArrayBuffer(0),
});
playSound = vitest.fn().mockReturnValue(soundPromise);
(useAudioContext as MockedFunction<typeof useAudioContext>).mockReturnValue({
playSound,
});
// A trivial implementation of Active call to ensure we are testing GroupCallView exclusively here.
(ActiveCall as MockedFunction<typeof ActiveCall>).mockImplementation(
({ onLeave }) => {
return (
<div>
<button onClick={() => onLeave()}>Leave</button>
</div>
);
},
);
});
function createGroupCallView(widget: WidgetHelpers | null): {
rtcSession: MockRTCSession;
getByText: ReturnType<typeof render>["getByText"];
} {
const history = createBrowserHistory();
const client = {
getUser: () => null,
getUserId: () => localRtcMember.sender,
getDeviceId: () => localRtcMember.deviceId,
getRoom: (rId) => (rId === roomId ? room : null),
} as Partial<MatrixClient> as MatrixClient;
const room = mockMatrixRoom({
client,
roomId,
getMember: (userId) => roomMembers.get(userId) ?? null,
getMxcAvatarUrl: () => null,
getCanonicalAlias: () => null,
currentState: {
getJoinRule: () => JoinRule.Invite,
} as Partial<RoomState> as RoomState,
});
const rtcSession = new MockRTCSession(
room,
localRtcMember,
[],
).withMemberships(of([]));
const muteState = {
audio: { enabled: false },
video: { enabled: false },
} as MuteStates;
const { getByText } = render(
<Router history={history}>
<GroupCallView
client={client}
isPasswordlessUser={false}
confineToRoom={false}
preload={false}
skipLobby={false}
hideHeader={true}
rtcSession={rtcSession as unknown as MatrixRTCSession}
muteStates={muteState}
widget={widget}
/>
</Router>,
);
return {
getByText,
rtcSession,
};
}
test("will play a leave sound asynchronously in SPA mode", async () => {
const user = userEvent.setup();
const { getByText, rtcSession } = createGroupCallView(null);
const leaveButton = getByText("Leave");
await user.click(leaveButton);
expect(playSound).toHaveBeenCalledWith("left");
expect(leaveRTCSession).toHaveBeenCalledWith(rtcSession, undefined);
expect(rtcSession.leaveRoomSession).toHaveBeenCalledOnce();
});
test("will play a leave sound synchronously in widget mode", async () => {
const user = userEvent.setup();
const widget = {
api: {
setAlwaysOnScreen: async () => Promise.resolve(true),
} as Partial<WidgetHelpers["api"]>,
lazyActions: new LazyEventEmitter(),
};
const { getByText, rtcSession } = createGroupCallView(
widget as WidgetHelpers,
);
const leaveButton = getByText("Leave");
await user.click(leaveButton);
expect(playSound).toHaveBeenCalledWith("left");
expect(leaveRTCSession).toHaveBeenCalledWith(rtcSession, soundPromise);
expect(rtcSession.leaveRoomSession).toHaveBeenCalledOnce();
});
+67 -29
View File
@@ -5,31 +5,45 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { FC, useCallback, useEffect, useMemo, useRef, useState } from "react"; import {
type FC,
useCallback,
useEffect,
useMemo,
useRef,
useState,
} from "react";
import { useHistory } from "react-router-dom"; import { useHistory } from "react-router-dom";
import { MatrixClient } from "matrix-js-sdk/src/client"; import { type MatrixClient } from "matrix-js-sdk/src/client";
import { import {
Room, Room,
isE2EESupported as isE2EESupportedBrowser, isE2EESupported as isE2EESupportedBrowser,
} from "livekit-client"; } from "livekit-client";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import { MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc/MatrixRTCSession"; import { type MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc/MatrixRTCSession";
import { JoinRule } from "matrix-js-sdk/src/matrix"; import { JoinRule } from "matrix-js-sdk/src/matrix";
import { Heading, Text } from "@vector-im/compound-web"; import { Heading, Text } from "@vector-im/compound-web";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import type { IWidgetApiRequest } from "matrix-widget-api"; import type { IWidgetApiRequest } from "matrix-widget-api";
import { widget, ElementWidgetActions, JoinCallData } from "../widget"; import {
ElementWidgetActions,
type JoinCallData,
type WidgetHelpers,
} from "../widget";
import { FullScreenView } from "../FullScreenView"; import { FullScreenView } from "../FullScreenView";
import { LobbyView } from "./LobbyView"; import { LobbyView } from "./LobbyView";
import { MatrixInfo } from "./VideoPreview"; import { type MatrixInfo } from "./VideoPreview";
import { CallEndedView } from "./CallEndedView"; import { CallEndedView } from "./CallEndedView";
import { PosthogAnalytics } from "../analytics/PosthogAnalytics"; import { PosthogAnalytics } from "../analytics/PosthogAnalytics";
import { useProfile } from "../profile/useProfile"; import { useProfile } from "../profile/useProfile";
import { findDeviceByName } from "../utils/media"; import { findDeviceByName } from "../utils/media";
import { ActiveCall } from "./InCallView"; import { ActiveCall } from "./InCallView";
import { MUTE_PARTICIPANT_COUNT, MuteStates } from "./MuteStates"; import { MUTE_PARTICIPANT_COUNT, type MuteStates } from "./MuteStates";
import { useMediaDevices, MediaDevices } from "../livekit/MediaDevicesContext"; import {
useMediaDevices,
type MediaDevices,
} from "../livekit/MediaDevicesContext";
import { useMatrixRTCSessionMemberships } from "../useMatrixRTCSessionMemberships"; import { useMatrixRTCSessionMemberships } from "../useMatrixRTCSessionMemberships";
import { enterRTCSession, leaveRTCSession } from "../rtcSessionHelpers"; import { enterRTCSession, leaveRTCSession } from "../rtcSessionHelpers";
import { useMatrixRTCSessionJoinState } from "../useMatrixRTCSessionJoinState"; import { useMatrixRTCSessionJoinState } from "../useMatrixRTCSessionJoinState";
@@ -42,6 +56,9 @@ import { useUrlParams } from "../UrlParams";
import { E2eeType } from "../e2ee/e2eeType"; import { E2eeType } from "../e2ee/e2eeType";
import { Link } from "../button/Link"; import { Link } from "../button/Link";
import { ReactionsProvider } from "../useReactions"; import { ReactionsProvider } from "../useReactions";
import { useAudioContext } from "../useAudioContext";
import { callEventAudioSounds } from "./CallEventAudioRenderer";
import { useLatest } from "../useLatest";
declare global { declare global {
interface Window { interface Window {
@@ -58,6 +75,7 @@ interface Props {
hideHeader: boolean; hideHeader: boolean;
rtcSession: MatrixRTCSession; rtcSession: MatrixRTCSession;
muteStates: MuteStates; muteStates: MuteStates;
widget: WidgetHelpers | null;
} }
export const GroupCallView: FC<Props> = ({ export const GroupCallView: FC<Props> = ({
@@ -69,10 +87,16 @@ export const GroupCallView: FC<Props> = ({
hideHeader, hideHeader,
rtcSession, rtcSession,
muteStates, muteStates,
widget,
}) => { }) => {
const memberships = useMatrixRTCSessionMemberships(rtcSession); const memberships = useMatrixRTCSessionMemberships(rtcSession);
const isJoined = useMatrixRTCSessionJoinState(rtcSession); const isJoined = useMatrixRTCSessionJoinState(rtcSession);
const leaveSoundContext = useLatest(
useAudioContext({
sounds: callEventAudioSounds,
latencyHint: "interactive",
}),
);
// This should use `useEffectEvent` (only available in experimental versions) // This should use `useEffectEvent` (only available in experimental versions)
useEffect(() => { useEffect(() => {
if (memberships.length >= MUTE_PARTICIPANT_COUNT) if (memberships.length >= MUTE_PARTICIPANT_COUNT)
@@ -186,14 +210,14 @@ export const GroupCallView: FC<Props> = ({
ev.detail.data as unknown as JoinCallData, ev.detail.data as unknown as JoinCallData,
); );
await enterRTCSession(rtcSession, perParticipantE2EE); await enterRTCSession(rtcSession, perParticipantE2EE);
widget!.api.transport.reply(ev.detail, {}); widget.api.transport.reply(ev.detail, {});
})().catch((e) => { })().catch((e) => {
logger.error("Error joining RTC session", e); logger.error("Error joining RTC session", e);
}); });
}; };
widget.lazyActions.on(ElementWidgetActions.JoinCall, onJoin); widget.lazyActions.on(ElementWidgetActions.JoinCall, onJoin);
return (): void => { return (): void => {
widget!.lazyActions.off(ElementWidgetActions.JoinCall, onJoin); widget.lazyActions.off(ElementWidgetActions.JoinCall, onJoin);
}; };
} else { } else {
// No lobby and no preload: we enter the rtc session right away // No lobby and no preload: we enter the rtc session right away
@@ -207,7 +231,7 @@ export const GroupCallView: FC<Props> = ({
void enterRTCSession(rtcSession, perParticipantE2EE); void enterRTCSession(rtcSession, perParticipantE2EE);
} }
} }
}, [rtcSession, preload, skipLobby, perParticipantE2EE]); }, [widget, rtcSession, preload, skipLobby, perParticipantE2EE]);
const [left, setLeft] = useState(false); const [left, setLeft] = useState(false);
const [leaveError, setLeaveError] = useState<Error | undefined>(undefined); const [leaveError, setLeaveError] = useState<Error | undefined>(undefined);
@@ -215,12 +239,12 @@ export const GroupCallView: FC<Props> = ({
const onLeave = useCallback( const onLeave = useCallback(
(leaveError?: Error): void => { (leaveError?: Error): void => {
setLeaveError(leaveError); const audioPromise = leaveSoundContext.current?.playSound("left");
setLeft(true);
// In embedded/widget mode the iFrame will be killed right after the call ended prohibiting the posthog event from getting sent, // In embedded/widget mode the iFrame will be killed right after the call ended prohibiting the posthog event from getting sent,
// therefore we want the event to be sent instantly without getting queued/batched. // therefore we want the event to be sent instantly without getting queued/batched.
const sendInstantly = !!widget; const sendInstantly = !!widget;
setLeaveError(leaveError);
setLeft(true);
PosthogAnalytics.instance.eventCallEnded.track( PosthogAnalytics.instance.eventCallEnded.track(
rtcSession.room.roomId, rtcSession.room.roomId,
rtcSession.memberships.length, rtcSession.memberships.length,
@@ -228,8 +252,12 @@ export const GroupCallView: FC<Props> = ({
rtcSession, rtcSession,
); );
// Only sends matrix leave event. The Livekit session will disconnect once the ActiveCall-view unmounts. leaveRTCSession(
leaveRTCSession(rtcSession) rtcSession,
// Wait for the sound in widget mode (it's not long)
sendInstantly && audioPromise ? audioPromise : undefined,
)
// Only sends matrix leave event. The Livekit session will disconnect once the ActiveCall-view unmounts.
.then(() => { .then(() => {
if ( if (
!isPasswordlessUser && !isPasswordlessUser &&
@@ -243,18 +271,25 @@ export const GroupCallView: FC<Props> = ({
logger.error("Error leaving RTC session", e); logger.error("Error leaving RTC session", e);
}); });
}, },
[rtcSession, isPasswordlessUser, confineToRoom, history], [
widget,
rtcSession,
isPasswordlessUser,
confineToRoom,
leaveSoundContext,
history,
],
); );
useEffect(() => { useEffect(() => {
if (widget && isJoined) { if (widget && isJoined) {
// set widget to sticky once joined. // set widget to sticky once joined.
widget!.api.setAlwaysOnScreen(true).catch((e) => { widget.api.setAlwaysOnScreen(true).catch((e) => {
logger.error("Error calling setAlwaysOnScreen(true)", e); logger.error("Error calling setAlwaysOnScreen(true)", e);
}); });
const onHangup = (ev: CustomEvent<IWidgetApiRequest>): void => { const onHangup = (ev: CustomEvent<IWidgetApiRequest>): void => {
widget!.api.transport.reply(ev.detail, {}); widget.api.transport.reply(ev.detail, {});
// Only sends matrix leave event. The Livekit session will disconnect once the ActiveCall-view unmounts. // Only sends matrix leave event. The Livekit session will disconnect once the ActiveCall-view unmounts.
leaveRTCSession(rtcSession).catch((e) => { leaveRTCSession(rtcSession).catch((e) => {
logger.error("Failed to leave RTC session", e); logger.error("Failed to leave RTC session", e);
@@ -262,10 +297,10 @@ export const GroupCallView: FC<Props> = ({
}; };
widget.lazyActions.once(ElementWidgetActions.HangupCall, onHangup); widget.lazyActions.once(ElementWidgetActions.HangupCall, onHangup);
return (): void => { return (): void => {
widget!.lazyActions.off(ElementWidgetActions.HangupCall, onHangup); widget.lazyActions.off(ElementWidgetActions.HangupCall, onHangup);
}; };
} }
}, [isJoined, rtcSession]); }, [widget, isJoined, rtcSession]);
const onReconnect = useCallback(() => { const onReconnect = useCallback(() => {
setLeft(false); setLeft(false);
@@ -360,14 +395,17 @@ export const GroupCallView: FC<Props> = ({
leaveError leaveError
) { ) {
return ( return (
<CallEndedView <>
endedCallId={rtcSession.room.roomId} <CallEndedView
client={client} endedCallId={rtcSession.room.roomId}
isPasswordlessUser={isPasswordlessUser} client={client}
confineToRoom={confineToRoom} isPasswordlessUser={isPasswordlessUser}
leaveError={leaveError} confineToRoom={confineToRoom}
reconnect={onReconnect} leaveError={leaveError}
/> reconnect={onReconnect}
/>
;
</>
); );
} else { } else {
// If the user is a regular user, we'll have sent them back to the homepage, // If the user is a regular user, we'll have sent them back to the homepage,
+30 -16
View File
@@ -10,13 +10,13 @@ import {
RoomContext, RoomContext,
useLocalParticipant, useLocalParticipant,
} from "@livekit/components-react"; } from "@livekit/components-react";
import { ConnectionState, Room } from "livekit-client"; import { ConnectionState, type Room } from "livekit-client";
import { MatrixClient } from "matrix-js-sdk/src/client"; import { type MatrixClient } from "matrix-js-sdk/src/client";
import { import {
FC, type FC,
PointerEvent, type PointerEvent,
PropsWithoutRef, type PropsWithoutRef,
TouchEvent, type TouchEvent,
forwardRef, forwardRef,
useCallback, useCallback,
useEffect, useEffect,
@@ -25,7 +25,7 @@ import {
useState, useState,
} from "react"; } from "react";
import useMeasure from "react-use-measure"; import useMeasure from "react-use-measure";
import { MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc/MatrixRTCSession"; import { type MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc/MatrixRTCSession";
import classNames from "classnames"; import classNames from "classnames";
import { BehaviorSubject, map } from "rxjs"; import { BehaviorSubject, map } from "rxjs";
import { useObservable, useObservableEagerState } from "observable-hooks"; import { useObservable, useObservableEagerState } from "observable-hooks";
@@ -49,28 +49,32 @@ import { useCallViewKeyboardShortcuts } from "../useCallViewKeyboardShortcuts";
import { ElementWidgetActions, widget } from "../widget"; import { ElementWidgetActions, widget } from "../widget";
import styles from "./InCallView.module.css"; import styles from "./InCallView.module.css";
import { GridTile } from "../tile/GridTile"; import { GridTile } from "../tile/GridTile";
import { OTelGroupCallMembership } from "../otel/OTelGroupCallMembership"; import { type OTelGroupCallMembership } from "../otel/OTelGroupCallMembership";
import { SettingsModal, defaultSettingsTab } from "../settings/SettingsModal"; import { SettingsModal, defaultSettingsTab } from "../settings/SettingsModal";
import { useRageshakeRequestModal } from "../settings/submit-rageshake"; import { useRageshakeRequestModal } from "../settings/submit-rageshake";
import { RageshakeRequestModal } from "./RageshakeRequestModal"; import { RageshakeRequestModal } from "./RageshakeRequestModal";
import { useLiveKit } from "../livekit/useLiveKit"; import { useLiveKit } from "../livekit/useLiveKit";
import { useWakeLock } from "../useWakeLock"; import { useWakeLock } from "../useWakeLock";
import { useMergedRefs } from "../useMergedRefs"; import { useMergedRefs } from "../useMergedRefs";
import { MuteStates } from "./MuteStates"; import { type MuteStates } from "./MuteStates";
import { MatrixInfo } from "./VideoPreview"; import { type MatrixInfo } from "./VideoPreview";
import { InviteButton } from "../button/InviteButton"; import { InviteButton } from "../button/InviteButton";
import { LayoutToggle } from "./LayoutToggle"; import { LayoutToggle } from "./LayoutToggle";
import { ECConnectionState } from "../livekit/useECConnectionState"; import { type ECConnectionState } from "../livekit/useECConnectionState";
import { useOpenIDSFU } from "../livekit/openIDSFU"; import { useOpenIDSFU } from "../livekit/openIDSFU";
import { CallViewModel, GridMode, Layout } from "../state/CallViewModel"; import {
import { Grid, TileProps } from "../grid/Grid"; CallViewModel,
type GridMode,
type Layout,
} from "../state/CallViewModel";
import { Grid, type TileProps } from "../grid/Grid";
import { useInitial } from "../useInitial"; import { useInitial } from "../useInitial";
import { SpotlightTile } from "../tile/SpotlightTile"; import { SpotlightTile } from "../tile/SpotlightTile";
import { EncryptionSystem } from "../e2ee/sharedKeyManagement"; import { type EncryptionSystem } from "../e2ee/sharedKeyManagement";
import { E2eeType } from "../e2ee/e2eeType"; import { E2eeType } from "../e2ee/e2eeType";
import { makeGridLayout } from "../grid/GridLayout"; import { makeGridLayout } from "../grid/GridLayout";
import { import {
CallLayoutOutputs, type CallLayoutOutputs,
defaultPipAlignment, defaultPipAlignment,
defaultSpotlightAlignment, defaultSpotlightAlignment,
} from "../grid/CallLayout"; } from "../grid/CallLayout";
@@ -78,12 +82,16 @@ import { makeOneOnOneLayout } from "../grid/OneOnOneLayout";
import { makeSpotlightExpandedLayout } from "../grid/SpotlightExpandedLayout"; import { makeSpotlightExpandedLayout } from "../grid/SpotlightExpandedLayout";
import { makeSpotlightLandscapeLayout } from "../grid/SpotlightLandscapeLayout"; import { makeSpotlightLandscapeLayout } from "../grid/SpotlightLandscapeLayout";
import { makeSpotlightPortraitLayout } from "../grid/SpotlightPortraitLayout"; import { makeSpotlightPortraitLayout } from "../grid/SpotlightPortraitLayout";
import { GridTileViewModel, TileViewModel } from "../state/TileViewModel"; import { GridTileViewModel, type TileViewModel } from "../state/TileViewModel";
import { ReactionsProvider, useReactions } from "../useReactions"; import { ReactionsProvider, useReactions } from "../useReactions";
import { ReactionsAudioRenderer } from "./ReactionAudioRenderer"; import { ReactionsAudioRenderer } from "./ReactionAudioRenderer";
import { useSwitchCamera } from "./useSwitchCamera"; import { useSwitchCamera } from "./useSwitchCamera";
import { ReactionsOverlay } from "./ReactionsOverlay"; import { ReactionsOverlay } from "./ReactionsOverlay";
import { CallEventAudioRenderer } from "./CallEventAudioRenderer"; import { CallEventAudioRenderer } from "./CallEventAudioRenderer";
import {
debugTileLayout as debugTileLayoutSetting,
useSetting,
} from "../settings/settings";
const canScreenshare = "getDisplayMedia" in (navigator.mediaDevices ?? {}); const canScreenshare = "getDisplayMedia" in (navigator.mediaDevices ?? {});
@@ -224,6 +232,8 @@ export const InCallView: FC<InCallViewProps> = ({
const windowMode = useObservableEagerState(vm.windowMode); const windowMode = useObservableEagerState(vm.windowMode);
const layout = useObservableEagerState(vm.layout); const layout = useObservableEagerState(vm.layout);
const tileStoreGeneration = useObservableEagerState(vm.tileStoreGeneration);
const [debugTileLayout] = useSetting(debugTileLayoutSetting);
const gridMode = useObservableEagerState(vm.gridMode); const gridMode = useObservableEagerState(vm.gridMode);
const showHeader = useObservableEagerState(vm.showHeader); const showHeader = useObservableEagerState(vm.showHeader);
const showFooter = useObservableEagerState(vm.showFooter); const showFooter = useObservableEagerState(vm.showFooter);
@@ -587,6 +597,10 @@ export const InCallView: FC<InCallViewProps> = ({
height={11} height={11}
aria-label={import.meta.env.VITE_PRODUCT_NAME || "Element Call"} aria-label={import.meta.env.VITE_PRODUCT_NAME || "Element Call"}
/> />
{/* Don't mind this odd placement, it's just a little debug label */}
{debugTileLayout
? `Tiles generation: ${tileStoreGeneration}`
: undefined}
</div> </div>
)} )}
{showControls && <div className={styles.buttons}>{buttons}</div>} {showControls && <div className={styles.buttons}>{buttons}</div>}
+1 -1
View File
@@ -7,7 +7,7 @@ Please see LICENSE in the repository root for full details.
import { render, screen } from "@testing-library/react"; import { render, screen } from "@testing-library/react";
import { expect, test, vi } from "vitest"; import { expect, test, vi } from "vitest";
import { Room } from "matrix-js-sdk/src/matrix"; import { type Room } from "matrix-js-sdk/src/matrix";
import { axe } from "vitest-axe"; import { axe } from "vitest-axe";
import { BrowserRouter } from "react-router-dom"; import { BrowserRouter } from "react-router-dom";
import userEvent from "@testing-library/user-event"; import userEvent from "@testing-library/user-event";
+8 -2
View File
@@ -5,9 +5,15 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { FC, MouseEvent, useCallback, useMemo, useState } from "react"; import {
type FC,
type MouseEvent,
useCallback,
useMemo,
useState,
} from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Room } from "matrix-js-sdk/src/matrix"; import { type Room } from "matrix-js-sdk/src/matrix";
import { Button, Text } from "@vector-im/compound-web"; import { Button, Text } from "@vector-im/compound-web";
import { import {
LinkIcon, LinkIcon,
+1 -1
View File
@@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { ChangeEvent, FC, TouchEvent, useCallback } from "react"; import { type ChangeEvent, type FC, type TouchEvent, useCallback } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Tooltip } from "@vector-im/compound-web"; import { Tooltip } from "@vector-im/compound-web";
import { import {
+5 -5
View File
@@ -5,15 +5,15 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { FC, useCallback, useMemo, useState } from "react"; import { type FC, useCallback, useMemo, useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { MatrixClient } from "matrix-js-sdk/src/matrix"; import { type MatrixClient } from "matrix-js-sdk/src/matrix";
import { Button } from "@vector-im/compound-web"; import { Button } from "@vector-im/compound-web";
import classNames from "classnames"; import classNames from "classnames";
import { useHistory } from "react-router-dom"; import { useHistory } from "react-router-dom";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import { usePreviewTracks } from "@livekit/components-react"; import { usePreviewTracks } from "@livekit/components-react";
import { LocalVideoTrack, Track } from "livekit-client"; import { type LocalVideoTrack, Track } from "livekit-client";
import { useObservable } from "observable-hooks"; import { useObservable } from "observable-hooks";
import { map } from "rxjs"; import { map } from "rxjs";
@@ -21,8 +21,8 @@ import inCallStyles from "./InCallView.module.css";
import styles from "./LobbyView.module.css"; import styles from "./LobbyView.module.css";
import { Header, LeftNav, RightNav, RoomHeaderInfo } from "../Header"; import { Header, LeftNav, RightNav, RoomHeaderInfo } from "../Header";
import { useLocationNavigation } from "../useLocationNavigation"; import { useLocationNavigation } from "../useLocationNavigation";
import { MatrixInfo, VideoPreview } from "./VideoPreview"; import { type MatrixInfo, VideoPreview } from "./VideoPreview";
import { MuteStates } from "./MuteStates"; import { type MuteStates } from "./MuteStates";
import { InviteButton } from "../button/InviteButton"; import { InviteButton } from "../button/InviteButton";
import { import {
EndCallButton, EndCallButton,
+3 -3
View File
@@ -6,15 +6,15 @@ Please see LICENSE in the repository root for full details.
*/ */
import { afterAll, afterEach, describe, expect, it, vi } from "vitest"; import { afterAll, afterEach, describe, expect, it, vi } from "vitest";
import React, { ReactNode } from "react"; import React, { type ReactNode } from "react";
import { beforeEach } from "vitest"; import { beforeEach } from "vitest";
import { render, screen } from "@testing-library/react"; import { render, screen } from "@testing-library/react";
import { MemoryRouter } from "react-router-dom"; import { MemoryRouter } from "react-router-dom";
import { useMuteStates } from "./MuteStates"; import { useMuteStates } from "./MuteStates";
import { import {
MediaDevice, type MediaDevice,
MediaDevices, type MediaDevices,
MediaDevicesContext, MediaDevicesContext,
} from "../livekit/MediaDevicesContext"; } from "../livekit/MediaDevicesContext";
import { mockConfig } from "../utils/test"; import { mockConfig } from "../utils/test";
+7 -4
View File
@@ -6,16 +6,19 @@ Please see LICENSE in the repository root for full details.
*/ */
import { import {
Dispatch, type Dispatch,
SetStateAction, type SetStateAction,
useCallback, useCallback,
useEffect, useEffect,
useMemo, useMemo,
} from "react"; } from "react";
import { IWidgetApiRequest } from "matrix-widget-api"; import { type IWidgetApiRequest } from "matrix-widget-api";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import { MediaDevice, useMediaDevices } from "../livekit/MediaDevicesContext"; import {
type MediaDevice,
useMediaDevices,
} from "../livekit/MediaDevicesContext";
import { useReactiveState } from "../useReactiveState"; import { useReactiveState } from "../useReactiveState";
import { ElementWidgetActions, widget } from "../widget"; import { ElementWidgetActions, widget } from "../widget";
import { Config } from "../config/Config"; import { Config } from "../config/Config";
+2 -2
View File
@@ -5,11 +5,11 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { FC, useEffect } from "react"; import { type FC, useEffect } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Button, Text } from "@vector-im/compound-web"; import { Button, Text } from "@vector-im/compound-web";
import { Modal, Props as ModalProps } from "../Modal"; import { Modal, type Props as ModalProps } from "../Modal";
import { FieldRow, ErrorMessage } from "../input/Input"; import { FieldRow, ErrorMessage } from "../input/Input";
import { useSubmitRageshake } from "../settings/submit-rageshake"; import { useSubmitRageshake } from "../settings/submit-rageshake";
+3 -3
View File
@@ -12,11 +12,11 @@ import {
expect, expect,
test, test,
vitest, vitest,
MockedFunction, type MockedFunction,
Mock, type Mock,
} from "vitest"; } from "vitest";
import { TooltipProvider } from "@vector-im/compound-web"; import { TooltipProvider } from "@vector-im/compound-web";
import { act, ReactNode } from "react"; import { act, type ReactNode } from "react";
import { afterEach } from "node:test"; import { afterEach } from "node:test";
import { ReactionsAudioRenderer } from "./ReactionAudioRenderer"; import { ReactionsAudioRenderer } from "./ReactionAudioRenderer";
+1 -1
View File
@@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { ReactNode, useEffect, useState } from "react"; import { type ReactNode, useEffect, useState } from "react";
import { playReactionsSound, useSetting } from "../settings/settings"; import { playReactionsSound, useSetting } from "../settings/settings";
import { GenericReaction, ReactionSet } from "../reactions"; import { GenericReaction, ReactionSet } from "../reactions";
+2 -2
View File
@@ -5,11 +5,11 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { ReactNode } from "react"; import { type ReactNode } from "react";
import { useObservableState } from "observable-hooks";
import styles from "./ReactionsOverlay.module.css"; import styles from "./ReactionsOverlay.module.css";
import { CallViewModel } from "../state/CallViewModel"; import { CallViewModel } from "../state/CallViewModel";
import { useObservableState } from "observable-hooks";
export function ReactionsOverlay({ vm }: { vm: CallViewModel }): ReactNode { export function ReactionsOverlay({ vm }: { vm: CallViewModel }): ReactNode {
const reactionsIcons = useObservableState(vm.visibleReactions); const reactionsIcons = useObservableState(vm.visibleReactions);
+1 -1
View File
@@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { FC, useCallback, useState } from "react"; import { type FC, useCallback, useState } from "react";
import { useLocation } from "react-router-dom"; import { useLocation } from "react-router-dom";
import { Trans, useTranslation } from "react-i18next"; import { Trans, useTranslation } from "react-i18next";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
+3 -2
View File
@@ -5,11 +5,11 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { FC, useEffect, useState, ReactNode, useRef } from "react"; import { type FC, useEffect, useState, type ReactNode, useRef } from "react";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { CheckIcon } from "@vector-im/compound-design-tokens/assets/web/icons"; import { CheckIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
import { MatrixError } from "matrix-js-sdk/src/http-api"; import { type MatrixError } from "matrix-js-sdk/src/http-api";
import { Heading, Text } from "@vector-im/compound-web"; import { Heading, Text } from "@vector-im/compound-web";
import { useClientLegacy } from "../ClientContext"; import { useClientLegacy } from "../ClientContext";
@@ -98,6 +98,7 @@ export const RoomPage: FC = () => {
case "loaded": case "loaded":
return ( return (
<GroupCallView <GroupCallView
widget={widget}
client={client!} client={client!}
rtcSession={groupCallState.rtcSession} rtcSession={groupCallState.rtcSession}
isPasswordlessUser={passwordlessUser} isPasswordlessUser={passwordlessUser}
+4 -4
View File
@@ -5,15 +5,15 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { useEffect, useRef, FC, ReactNode } from "react"; import { useEffect, useRef, type FC, type ReactNode } from "react";
import useMeasure from "react-use-measure"; import useMeasure from "react-use-measure";
import { facingModeFromLocalTrack, LocalVideoTrack } from "livekit-client"; import { facingModeFromLocalTrack, type LocalVideoTrack } from "livekit-client";
import classNames from "classnames"; import classNames from "classnames";
import { Avatar } from "../Avatar"; import { Avatar } from "../Avatar";
import styles from "./VideoPreview.module.css"; import styles from "./VideoPreview.module.css";
import { MuteStates } from "./MuteStates"; import { type MuteStates } from "./MuteStates";
import { EncryptionSystem } from "../e2ee/sharedKeyManagement"; import { type EncryptionSystem } from "../e2ee/sharedKeyManagement";
export type MatrixInfo = { export type MatrixInfo = {
userId: string; userId: string;
+2 -2
View File
@@ -5,8 +5,8 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { vi, Mocked, test, expect } from "vitest"; import { vi, type Mocked, test, expect } from "vitest";
import { RoomState } from "matrix-js-sdk/src/models/room-state"; import { type RoomState } from "matrix-js-sdk/src/models/room-state";
import { PosthogAnalytics } from "../../src/analytics/PosthogAnalytics"; import { PosthogAnalytics } from "../../src/analytics/PosthogAnalytics";
import { checkForParallelCalls } from "../../src/room/checkForParallelCalls"; import { checkForParallelCalls } from "../../src/room/checkForParallelCalls";

Some files were not shown because too many files have changed in this diff Show More