2024-12-11 09:36:59 +00:00
|
|
|
/*
|
|
|
|
|
Copyright 2022-2024 New Vector Ltd.
|
|
|
|
|
|
2025-02-18 17:59:58 +00:00
|
|
|
SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
2024-12-11 09:36:59 +00:00
|
|
|
Please see LICENSE in the repository root for full details.
|
|
|
|
|
*/
|
|
|
|
|
|
2025-10-22 12:53:22 +02:00
|
|
|
import {
|
|
|
|
|
type ChangeEvent,
|
|
|
|
|
type FC,
|
|
|
|
|
useCallback,
|
|
|
|
|
useEffect,
|
|
|
|
|
useMemo,
|
|
|
|
|
useState,
|
|
|
|
|
} from "react";
|
2024-12-11 09:36:59 +00:00
|
|
|
import { useTranslation } from "react-i18next";
|
2025-10-22 12:53:22 +02:00
|
|
|
import {
|
|
|
|
|
UNSTABLE_MSC4354_STICKY_EVENTS,
|
|
|
|
|
type MatrixClient,
|
|
|
|
|
} from "matrix-js-sdk";
|
|
|
|
|
import { logger } from "matrix-js-sdk/lib/logger";
|
2024-12-11 09:36:59 +00:00
|
|
|
|
|
|
|
|
import { FieldRow, InputField } from "../input/Input";
|
|
|
|
|
import {
|
|
|
|
|
useSetting,
|
|
|
|
|
duplicateTiles as duplicateTilesSetting,
|
2024-12-11 05:23:42 -05:00
|
|
|
debugTileLayout as debugTileLayoutSetting,
|
2025-01-06 09:47:39 +00:00
|
|
|
showConnectionStats as showConnectionStatsSetting,
|
2025-10-03 14:43:22 -04:00
|
|
|
multiSfu as multiSfuSetting,
|
2025-05-13 21:11:12 +02:00
|
|
|
muteAllAudio as muteAllAudioSetting,
|
2025-05-15 20:46:39 +02:00
|
|
|
alwaysShowIphoneEarpiece as alwaysShowIphoneEarpieceSetting,
|
2025-10-22 12:53:22 +02:00
|
|
|
preferStickyEvents as preferStickyEventsSetting,
|
2024-12-11 09:36:59 +00:00
|
|
|
} from "./settings";
|
2025-02-10 17:22:19 +00:00
|
|
|
import type { Room as LivekitRoom } from "livekit-client";
|
|
|
|
|
import styles from "./DeveloperSettingsTab.module.css";
|
2025-03-27 20:35:31 +00:00
|
|
|
import { useUrlParams } from "../UrlParams";
|
2025-10-22 12:53:22 +02:00
|
|
|
|
2024-12-11 09:36:59 +00:00
|
|
|
interface Props {
|
|
|
|
|
client: MatrixClient;
|
2025-09-22 14:18:23 +02:00
|
|
|
livekitRooms?: { room: LivekitRoom; url: string; isLocal?: boolean }[];
|
2024-12-11 09:36:59 +00:00
|
|
|
}
|
|
|
|
|
|
2025-09-22 14:18:23 +02:00
|
|
|
export const DeveloperSettingsTab: FC<Props> = ({ client, livekitRooms }) => {
|
2024-12-11 09:36:59 +00:00
|
|
|
const { t } = useTranslation();
|
|
|
|
|
const [duplicateTiles, setDuplicateTiles] = useSetting(duplicateTilesSetting);
|
2024-12-11 05:23:42 -05:00
|
|
|
const [debugTileLayout, setDebugTileLayout] = useSetting(
|
|
|
|
|
debugTileLayoutSetting,
|
|
|
|
|
);
|
2024-12-11 09:36:59 +00:00
|
|
|
|
2025-10-22 12:53:22 +02:00
|
|
|
const [stickyEventsSupported, setStickyEventsSupported] = useState(false);
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
client
|
|
|
|
|
.doesServerSupportUnstableFeature(UNSTABLE_MSC4354_STICKY_EVENTS)
|
|
|
|
|
.then((result) => {
|
|
|
|
|
setStickyEventsSupported(result);
|
|
|
|
|
})
|
|
|
|
|
.catch((ex) => {
|
|
|
|
|
logger.warn("Failed to check if sticky events are supported", ex);
|
|
|
|
|
});
|
|
|
|
|
}, [client]);
|
|
|
|
|
|
|
|
|
|
const [preferStickyEvents, setPreferStickyEvents] = useSetting(
|
|
|
|
|
preferStickyEventsSetting,
|
2025-01-06 09:47:39 +00:00
|
|
|
);
|
|
|
|
|
|
2025-10-22 12:53:22 +02:00
|
|
|
const [showConnectionStats, setShowConnectionStats] = useSetting(
|
|
|
|
|
showConnectionStatsSetting,
|
2025-03-07 17:27:04 +01:00
|
|
|
);
|
|
|
|
|
|
2025-05-15 20:46:39 +02:00
|
|
|
const [alwaysShowIphoneEarpiece, setAlwaysShowIphoneEarpiece] = useSetting(
|
|
|
|
|
alwaysShowIphoneEarpieceSetting,
|
|
|
|
|
);
|
2025-10-22 14:13:31 +02:00
|
|
|
|
2025-10-03 14:43:22 -04:00
|
|
|
const [multiSfu, setMultiSfu] = useSetting(multiSfuSetting);
|
2025-05-13 21:11:12 +02:00
|
|
|
|
|
|
|
|
const [muteAllAudio, setMuteAllAudio] = useSetting(muteAllAudioSetting);
|
|
|
|
|
|
2025-03-27 20:35:31 +00:00
|
|
|
const urlParams = useUrlParams();
|
|
|
|
|
|
2025-09-22 14:18:23 +02:00
|
|
|
const localSfuUrl = useMemo((): URL | null => {
|
|
|
|
|
const localRoom = livekitRooms?.find((r) => r.isLocal)?.room;
|
|
|
|
|
if (localRoom?.engine.client.ws?.url) {
|
2025-02-10 17:22:19 +00:00
|
|
|
// strip the URL params
|
2025-09-22 14:18:23 +02:00
|
|
|
const url = new URL(localRoom.engine.client.ws.url);
|
2025-02-10 17:22:19 +00:00
|
|
|
url.search = "";
|
|
|
|
|
return url;
|
|
|
|
|
}
|
|
|
|
|
return null;
|
2025-09-22 14:18:23 +02:00
|
|
|
}, [livekitRooms]);
|
2025-02-10 17:22:19 +00:00
|
|
|
|
2024-12-11 09:36:59 +00:00
|
|
|
return (
|
|
|
|
|
<>
|
|
|
|
|
<p>
|
|
|
|
|
{t("developer_mode.hostname", {
|
|
|
|
|
hostname: window.location.hostname || "unknown",
|
|
|
|
|
})}
|
|
|
|
|
</p>
|
|
|
|
|
<p>
|
|
|
|
|
{t("version", {
|
|
|
|
|
productName: import.meta.env.VITE_PRODUCT_NAME || "Element Call",
|
|
|
|
|
version: import.meta.env.VITE_APP_VERSION || "dev",
|
|
|
|
|
})}
|
|
|
|
|
</p>
|
|
|
|
|
<p>
|
|
|
|
|
{t("developer_mode.crypto_version", {
|
|
|
|
|
version: client.getCrypto()?.getVersion() || "unknown",
|
|
|
|
|
})}
|
|
|
|
|
</p>
|
|
|
|
|
<p>
|
|
|
|
|
{t("developer_mode.matrix_id", {
|
|
|
|
|
id: client.getUserId() || "unknown",
|
|
|
|
|
})}
|
|
|
|
|
</p>
|
|
|
|
|
<p>
|
|
|
|
|
{t("developer_mode.device_id", {
|
|
|
|
|
id: client.getDeviceId() || "unknown",
|
|
|
|
|
})}
|
|
|
|
|
</p>
|
|
|
|
|
<FieldRow>
|
|
|
|
|
<InputField
|
|
|
|
|
id="duplicateTiles"
|
|
|
|
|
type="number"
|
|
|
|
|
label={t("developer_mode.duplicate_tiles_label")}
|
|
|
|
|
value={duplicateTiles.toString()}
|
|
|
|
|
min={0}
|
|
|
|
|
onChange={useCallback(
|
|
|
|
|
(event: ChangeEvent<HTMLInputElement>): void => {
|
|
|
|
|
const value = event.target.valueAsNumber;
|
|
|
|
|
if (value < 0) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
setDuplicateTiles(Number.isNaN(value) ? 0 : value);
|
|
|
|
|
},
|
|
|
|
|
[setDuplicateTiles],
|
|
|
|
|
)}
|
|
|
|
|
/>
|
|
|
|
|
</FieldRow>
|
2024-12-11 05:23:42 -05:00
|
|
|
<FieldRow>
|
|
|
|
|
<InputField
|
|
|
|
|
id="debugTileLayout"
|
|
|
|
|
type="checkbox"
|
|
|
|
|
checked={debugTileLayout}
|
|
|
|
|
label={t("developer_mode.debug_tile_layout_label")}
|
|
|
|
|
onChange={(event: ChangeEvent<HTMLInputElement>): void =>
|
|
|
|
|
setDebugTileLayout(event.target.checked)
|
|
|
|
|
}
|
|
|
|
|
/>
|
|
|
|
|
</FieldRow>
|
2025-01-06 09:47:39 +00:00
|
|
|
<FieldRow>
|
|
|
|
|
<InputField
|
2025-10-22 12:53:22 +02:00
|
|
|
id="preferStickyEvents"
|
2025-01-06 09:47:39 +00:00
|
|
|
type="checkbox"
|
2025-10-22 12:53:22 +02:00
|
|
|
label={t("developer_mode.prefer_sticky_events.label")}
|
|
|
|
|
disabled={!stickyEventsSupported}
|
|
|
|
|
description={t("developer_mode.prefer_sticky_events.description")}
|
|
|
|
|
checked={!!preferStickyEvents}
|
2025-01-06 09:47:39 +00:00
|
|
|
onChange={useCallback(
|
|
|
|
|
(event: ChangeEvent<HTMLInputElement>): void => {
|
2025-10-22 12:53:22 +02:00
|
|
|
setPreferStickyEvents(event.target.checked);
|
2025-01-06 09:47:39 +00:00
|
|
|
},
|
2025-10-22 12:53:22 +02:00
|
|
|
[setPreferStickyEvents],
|
2025-01-06 09:47:39 +00:00
|
|
|
)}
|
|
|
|
|
/>
|
|
|
|
|
</FieldRow>
|
2025-03-07 17:27:04 +01:00
|
|
|
<FieldRow>
|
|
|
|
|
<InputField
|
2025-10-22 12:53:22 +02:00
|
|
|
id="showConnectionStats"
|
2025-03-07 17:27:04 +01:00
|
|
|
type="checkbox"
|
2025-10-22 12:53:22 +02:00
|
|
|
label={t("developer_mode.show_connection_stats")}
|
|
|
|
|
checked={!!showConnectionStats}
|
2025-03-07 17:27:04 +01:00
|
|
|
onChange={useCallback(
|
|
|
|
|
(event: ChangeEvent<HTMLInputElement>): void => {
|
2025-10-22 12:53:22 +02:00
|
|
|
setShowConnectionStats(event.target.checked);
|
2025-03-07 17:27:04 +01:00
|
|
|
},
|
2025-10-22 12:53:22 +02:00
|
|
|
[setShowConnectionStats],
|
2025-03-07 17:27:04 +01:00
|
|
|
)}
|
|
|
|
|
/>
|
|
|
|
|
</FieldRow>
|
2025-10-03 14:43:22 -04:00
|
|
|
<FieldRow>
|
|
|
|
|
<InputField
|
|
|
|
|
id="multiSfu"
|
|
|
|
|
type="checkbox"
|
|
|
|
|
label={t("developer_mode.multi_sfu")}
|
2025-10-22 12:53:22 +02:00
|
|
|
// If using sticky events we implicitly prefer use multi-sfu
|
|
|
|
|
checked={multiSfu || preferStickyEvents}
|
|
|
|
|
disabled={preferStickyEvents}
|
2025-10-03 14:43:22 -04:00
|
|
|
onChange={useCallback(
|
|
|
|
|
(event: ChangeEvent<HTMLInputElement>): void => {
|
|
|
|
|
setMultiSfu(event.target.checked);
|
|
|
|
|
},
|
|
|
|
|
[setMultiSfu],
|
|
|
|
|
)}
|
|
|
|
|
/>
|
|
|
|
|
</FieldRow>
|
2025-05-13 21:11:12 +02:00
|
|
|
<FieldRow>
|
|
|
|
|
<InputField
|
|
|
|
|
id="muteAllAudio"
|
|
|
|
|
type="checkbox"
|
|
|
|
|
label={t("developer_mode.mute_all_audio")}
|
|
|
|
|
checked={muteAllAudio}
|
|
|
|
|
onChange={useCallback(
|
|
|
|
|
(event: ChangeEvent<HTMLInputElement>): void => {
|
|
|
|
|
setMuteAllAudio(event.target.checked);
|
|
|
|
|
},
|
|
|
|
|
[setMuteAllAudio],
|
|
|
|
|
)}
|
|
|
|
|
/>
|
2025-05-15 20:46:39 +02:00
|
|
|
</FieldRow>{" "}
|
|
|
|
|
<FieldRow>
|
|
|
|
|
<InputField
|
|
|
|
|
id="alwaysShowIphoneEarpiece"
|
|
|
|
|
type="checkbox"
|
|
|
|
|
label={t("developer_mode.always_show_iphone_earpiece")}
|
|
|
|
|
checked={alwaysShowIphoneEarpiece}
|
|
|
|
|
onChange={useCallback(
|
|
|
|
|
(event: ChangeEvent<HTMLInputElement>): void => {
|
|
|
|
|
setAlwaysShowIphoneEarpiece(event.target.checked);
|
|
|
|
|
},
|
|
|
|
|
[setAlwaysShowIphoneEarpiece],
|
|
|
|
|
)}
|
|
|
|
|
/>{" "}
|
2025-05-13 21:11:12 +02:00
|
|
|
</FieldRow>
|
2025-09-22 14:18:23 +02:00
|
|
|
{livekitRooms?.map((livekitRoom) => (
|
2025-02-10 17:22:19 +00:00
|
|
|
<>
|
2025-09-22 14:18:23 +02:00
|
|
|
<h3>
|
2025-02-10 17:22:19 +00:00
|
|
|
{t("developer_mode.livekit_sfu", {
|
2025-09-22 14:18:23 +02:00
|
|
|
url: livekitRoom.url || "unknown",
|
2025-02-10 17:22:19 +00:00
|
|
|
})}
|
2025-09-22 14:18:23 +02:00
|
|
|
</h3>
|
|
|
|
|
{livekitRoom.isLocal && <p>ws-url: {localSfuUrl?.href}</p>}
|
|
|
|
|
<p>
|
|
|
|
|
{t("developer_mode.livekit_server_info")}(
|
|
|
|
|
{livekitRoom.isLocal ? "local" : "remote"})
|
2025-02-10 17:22:19 +00:00
|
|
|
</p>
|
|
|
|
|
<pre className={styles.pre}>
|
2025-09-22 14:18:23 +02:00
|
|
|
{livekitRoom.room.serverInfo
|
|
|
|
|
? JSON.stringify(livekitRoom.room.serverInfo, null, 2)
|
2025-02-10 17:22:19 +00:00
|
|
|
: "undefined"}
|
2025-09-22 14:18:23 +02:00
|
|
|
{livekitRoom.room.metadata}
|
2025-02-10 17:22:19 +00:00
|
|
|
</pre>
|
|
|
|
|
</>
|
2025-09-22 14:18:23 +02:00
|
|
|
))}
|
2025-03-27 20:35:31 +00:00
|
|
|
<p>{t("developer_mode.environment_variables")}</p>
|
|
|
|
|
<pre>{JSON.stringify(import.meta.env, null, 2)}</pre>
|
|
|
|
|
<p>{t("developer_mode.url_params")}</p>
|
|
|
|
|
<pre>{JSON.stringify(urlParams, null, 2)}</pre>
|
2024-12-11 09:36:59 +00:00
|
|
|
</>
|
|
|
|
|
);
|
|
|
|
|
};
|