Add a URL param for room ID
And consolidate our URL params logic
This commit is contained in:
parent
2a8cb3c4e2
commit
cf56b24dda
13 changed files with 166 additions and 67 deletions
|
@ -29,7 +29,11 @@ import { MatrixEvent } from "matrix-js-sdk/src/models/event";
|
||||||
import { logger } from "matrix-js-sdk/src/logger";
|
import { logger } from "matrix-js-sdk/src/logger";
|
||||||
|
|
||||||
import { ErrorView } from "./FullScreenView";
|
import { ErrorView } from "./FullScreenView";
|
||||||
import { initClient, initMatroskaClient, defaultHomeserver } from "./matrix-utils";
|
import {
|
||||||
|
initClient,
|
||||||
|
initMatroskaClient,
|
||||||
|
defaultHomeserver,
|
||||||
|
} from "./matrix-utils";
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface Window {
|
interface Window {
|
||||||
|
|
|
@ -5,7 +5,11 @@ import { MemoryStore } from "matrix-js-sdk/src/store/memory";
|
||||||
import { IndexedDBCryptoStore } from "matrix-js-sdk/src/crypto/store/indexeddb-crypto-store";
|
import { IndexedDBCryptoStore } from "matrix-js-sdk/src/crypto/store/indexeddb-crypto-store";
|
||||||
import { LocalStorageCryptoStore } from "matrix-js-sdk/src/crypto/store/localStorage-crypto-store";
|
import { LocalStorageCryptoStore } from "matrix-js-sdk/src/crypto/store/localStorage-crypto-store";
|
||||||
import { MemoryCryptoStore } from "matrix-js-sdk/src/crypto/store/memory-crypto-store";
|
import { MemoryCryptoStore } from "matrix-js-sdk/src/crypto/store/memory-crypto-store";
|
||||||
import { createClient, createRoomWidgetClient, MatrixClient } from "matrix-js-sdk/src/matrix";
|
import {
|
||||||
|
createClient,
|
||||||
|
createRoomWidgetClient,
|
||||||
|
MatrixClient,
|
||||||
|
} from "matrix-js-sdk/src/matrix";
|
||||||
import { ICreateClientOpts } from "matrix-js-sdk/src/matrix";
|
import { ICreateClientOpts } from "matrix-js-sdk/src/matrix";
|
||||||
import { ClientEvent } from "matrix-js-sdk/src/client";
|
import { ClientEvent } from "matrix-js-sdk/src/client";
|
||||||
import { EventType } from "matrix-js-sdk/src/@types/event";
|
import { EventType } from "matrix-js-sdk/src/@types/event";
|
||||||
|
@ -15,6 +19,7 @@ import { WidgetApi } from "matrix-widget-api";
|
||||||
import { logger } from "matrix-js-sdk/src/logger";
|
import { logger } from "matrix-js-sdk/src/logger";
|
||||||
|
|
||||||
import IndexedDBWorker from "./IndexedDBWorker?worker";
|
import IndexedDBWorker from "./IndexedDBWorker?worker";
|
||||||
|
import { getRoomParams } from "./room/useRoomParams";
|
||||||
|
|
||||||
export const defaultHomeserver =
|
export const defaultHomeserver =
|
||||||
(import.meta.env.VITE_DEFAULT_HOMESERVER as string) ??
|
(import.meta.env.VITE_DEFAULT_HOMESERVER as string) ??
|
||||||
|
@ -82,20 +87,20 @@ const SEND_RECV_TO_DEVICE = [
|
||||||
* @returns The MatrixClient instance
|
* @returns The MatrixClient instance
|
||||||
*/
|
*/
|
||||||
export async function initMatroskaClient(
|
export async function initMatroskaClient(
|
||||||
widgetId: string, parentUrl: string,
|
widgetId: string,
|
||||||
|
parentUrl: string
|
||||||
): Promise<MatrixClient> {
|
): Promise<MatrixClient> {
|
||||||
// In this mode, we use a special client which routes all requests through
|
// In this mode, we use a special client which routes all requests through
|
||||||
// the host application via the widget API
|
// the host application via the widget API
|
||||||
|
|
||||||
// The rest of the data we need is encoded in the fragment so as to avoid
|
const { roomId, userId, deviceId } = getRoomParams();
|
||||||
// leaking it to the server
|
if (!roomId) throw new Error("Room ID must be supplied");
|
||||||
const fragmentQueryStart = window.location.hash.indexOf("?");
|
if (!userId) throw new Error("User ID must be supplied");
|
||||||
const roomId = window.location.hash.substring(0, fragmentQueryStart);
|
if (!deviceId) throw new Error("Device ID must be supplied");
|
||||||
const fragmentQuery = new URLSearchParams(window.location.hash.substring(fragmentQueryStart));
|
|
||||||
|
|
||||||
// Since all data should be coming from the host application, there's no
|
// Since all data should be coming from the host application, there's no
|
||||||
// need to persist anything, and therefore we can use the default stores
|
// need to persist anything, and therefore we can use the default stores
|
||||||
// We don't even need to set up crypto!
|
// We don't even need to set up crypto
|
||||||
const client = createRoomWidgetClient(
|
const client = createRoomWidgetClient(
|
||||||
new WidgetApi(widgetId, new URL(parentUrl).origin),
|
new WidgetApi(widgetId, new URL(parentUrl).origin),
|
||||||
{
|
{
|
||||||
|
@ -103,14 +108,15 @@ export async function initMatroskaClient(
|
||||||
receiveState: SEND_RECV_STATE,
|
receiveState: SEND_RECV_STATE,
|
||||||
sendToDevice: SEND_RECV_TO_DEVICE,
|
sendToDevice: SEND_RECV_TO_DEVICE,
|
||||||
receiveToDevice: SEND_RECV_TO_DEVICE,
|
receiveToDevice: SEND_RECV_TO_DEVICE,
|
||||||
|
turnServers: true,
|
||||||
},
|
},
|
||||||
roomId,
|
roomId,
|
||||||
{
|
{
|
||||||
baseUrl: "",
|
baseUrl: "",
|
||||||
userId: fragmentQuery.get("userId"),
|
userId,
|
||||||
deviceId: fragmentQuery.get("deviceId"),
|
deviceId,
|
||||||
timelineSupport: true,
|
timelineSupport: true,
|
||||||
},
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
await client.startClient();
|
await client.startClient();
|
||||||
|
@ -192,16 +198,13 @@ export async function initClient(
|
||||||
storeOpts.cryptoStore = new MemoryCryptoStore();
|
storeOpts.cryptoStore = new MemoryCryptoStore();
|
||||||
}
|
}
|
||||||
|
|
||||||
// XXX: we read from the URL search params in RoomPage too:
|
// XXX: we read from the room params in RoomPage too:
|
||||||
// it would be much better to read them in one place and pass
|
// it would be much better to read them in one place and pass
|
||||||
// the values around, but we initialise the matrix client in
|
// the values around, but we initialise the matrix client in
|
||||||
// many different places so we'd have to pass it into all of
|
// many different places so we'd have to pass it into all of
|
||||||
// them.
|
// them.
|
||||||
const params = new URLSearchParams(window.location.search);
|
const { e2eEnabled } = getRoomParams();
|
||||||
// disable e2e only if enableE2e=false is given
|
if (!e2eEnabled) {
|
||||||
const enableE2e = params.get("enableE2e") !== "false";
|
|
||||||
|
|
||||||
if (!enableE2e) {
|
|
||||||
logger.info("Disabling E2E: group call signalling will NOT be encrypted.");
|
logger.info("Disabling E2E: group call signalling will NOT be encrypted.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -212,7 +215,7 @@ export async function initClient(
|
||||||
// Use a relatively low timeout for API calls: this is a realtime app
|
// Use a relatively low timeout for API calls: this is a realtime app
|
||||||
// so we don't want API calls taking ages, we'd rather they just fail.
|
// so we don't want API calls taking ages, we'd rather they just fail.
|
||||||
localTimeoutMs: 5000,
|
localTimeoutMs: 5000,
|
||||||
useE2eForGroupCall: enableE2e,
|
useE2eForGroupCall: e2eEnabled,
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -319,17 +322,17 @@ export async function createRoom(
|
||||||
return [fullAliasFromRoomName(name, client), result.room_id];
|
return [fullAliasFromRoomName(name, client), result.room_id];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getRoomUrl(roomId: string): string {
|
export function getRoomUrl(roomIdOrAlias: string): string {
|
||||||
if (roomId.startsWith("#")) {
|
if (roomIdOrAlias.startsWith("#")) {
|
||||||
const [localPart, host] = roomId.replace("#", "").split(":");
|
const [localPart, host] = roomIdOrAlias.replace("#", "").split(":");
|
||||||
|
|
||||||
if (host !== defaultHomeserverHost) {
|
if (host !== defaultHomeserverHost) {
|
||||||
return `${window.location.protocol}//${window.location.host}/room/${roomId}`;
|
return `${window.location.protocol}//${window.location.host}/room/${roomIdOrAlias}`;
|
||||||
} else {
|
} else {
|
||||||
return `${window.location.protocol}//${window.location.host}/${localPart}`;
|
return `${window.location.protocol}//${window.location.host}/${localPart}`;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return `${window.location.protocol}//${window.location.host}/room/${roomId}`;
|
return `${window.location.protocol}//${window.location.host}/room/#?roomId=${roomIdOrAlias}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,14 +21,14 @@ import { usePageTitle } from "../usePageTitle";
|
||||||
|
|
||||||
export function GroupCallLoader({
|
export function GroupCallLoader({
|
||||||
client,
|
client,
|
||||||
roomId,
|
roomIdOrAlias,
|
||||||
viaServers,
|
viaServers,
|
||||||
createPtt,
|
createPtt,
|
||||||
children,
|
children,
|
||||||
}) {
|
}) {
|
||||||
const { loading, error, groupCall } = useLoadGroupCall(
|
const { loading, error, groupCall } = useLoadGroupCall(
|
||||||
client,
|
client,
|
||||||
roomId,
|
roomIdOrAlias,
|
||||||
viaServers,
|
viaServers,
|
||||||
createPtt
|
createPtt
|
||||||
);
|
);
|
||||||
|
|
|
@ -31,7 +31,7 @@ export function GroupCallView({
|
||||||
client,
|
client,
|
||||||
isPasswordlessUser,
|
isPasswordlessUser,
|
||||||
isEmbedded,
|
isEmbedded,
|
||||||
roomId,
|
roomIdOrAlias,
|
||||||
groupCall,
|
groupCall,
|
||||||
}) {
|
}) {
|
||||||
const {
|
const {
|
||||||
|
@ -89,7 +89,7 @@ export function GroupCallView({
|
||||||
return (
|
return (
|
||||||
<PTTCallView
|
<PTTCallView
|
||||||
client={client}
|
client={client}
|
||||||
roomId={roomId}
|
roomIdOrAlias={roomIdOrAlias}
|
||||||
roomName={groupCall.room.name}
|
roomName={groupCall.room.name}
|
||||||
avatarUrl={avatarUrl}
|
avatarUrl={avatarUrl}
|
||||||
groupCall={groupCall}
|
groupCall={groupCall}
|
||||||
|
@ -117,7 +117,7 @@ export function GroupCallView({
|
||||||
isScreensharing={isScreensharing}
|
isScreensharing={isScreensharing}
|
||||||
localScreenshareFeed={localScreenshareFeed}
|
localScreenshareFeed={localScreenshareFeed}
|
||||||
screenshareFeeds={screenshareFeeds}
|
screenshareFeeds={screenshareFeeds}
|
||||||
roomId={roomId}
|
roomIdOrAlias={roomIdOrAlias}
|
||||||
unencryptedEventsFromUsers={unencryptedEventsFromUsers}
|
unencryptedEventsFromUsers={unencryptedEventsFromUsers}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
@ -153,7 +153,7 @@ export function GroupCallView({
|
||||||
localVideoMuted={localVideoMuted}
|
localVideoMuted={localVideoMuted}
|
||||||
toggleLocalVideoMuted={toggleLocalVideoMuted}
|
toggleLocalVideoMuted={toggleLocalVideoMuted}
|
||||||
toggleMicrophoneMuted={toggleMicrophoneMuted}
|
toggleMicrophoneMuted={toggleMicrophoneMuted}
|
||||||
roomId={roomId}
|
roomIdOrAlias={roomIdOrAlias}
|
||||||
isEmbedded={isEmbedded}
|
isEmbedded={isEmbedded}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
|
@ -65,7 +65,7 @@ export function InCallView({
|
||||||
toggleScreensharing,
|
toggleScreensharing,
|
||||||
isScreensharing,
|
isScreensharing,
|
||||||
screenshareFeeds,
|
screenshareFeeds,
|
||||||
roomId,
|
roomIdOrAlias,
|
||||||
unencryptedEventsFromUsers,
|
unencryptedEventsFromUsers,
|
||||||
}) {
|
}) {
|
||||||
usePreventScroll();
|
usePreventScroll();
|
||||||
|
@ -184,7 +184,7 @@ export function InCallView({
|
||||||
)}
|
)}
|
||||||
<OverflowMenu
|
<OverflowMenu
|
||||||
inCall
|
inCall
|
||||||
roomId={roomId}
|
roomIdOrAlias={roomIdOrAlias}
|
||||||
client={client}
|
client={client}
|
||||||
groupCall={groupCall}
|
groupCall={groupCall}
|
||||||
showInvite={true}
|
showInvite={true}
|
||||||
|
@ -201,7 +201,7 @@ export function InCallView({
|
||||||
{rageshakeRequestModalState.isOpen && (
|
{rageshakeRequestModalState.isOpen && (
|
||||||
<RageshakeRequestModal
|
<RageshakeRequestModal
|
||||||
{...rageshakeRequestModalProps}
|
{...rageshakeRequestModalProps}
|
||||||
roomId={roomId}
|
roomIdOrAlias={roomIdOrAlias}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -20,7 +20,7 @@ import { CopyButton } from "../button";
|
||||||
import { getRoomUrl } from "../matrix-utils";
|
import { getRoomUrl } from "../matrix-utils";
|
||||||
import styles from "./InviteModal.module.css";
|
import styles from "./InviteModal.module.css";
|
||||||
|
|
||||||
export function InviteModal({ roomId, ...rest }) {
|
export function InviteModal({ roomIdOrAlias, ...rest }) {
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
title="Invite People"
|
title="Invite People"
|
||||||
|
@ -30,7 +30,10 @@ export function InviteModal({ roomId, ...rest }) {
|
||||||
>
|
>
|
||||||
<ModalContent>
|
<ModalContent>
|
||||||
<p>Copy and share this meeting link</p>
|
<p>Copy and share this meeting link</p>
|
||||||
<CopyButton className={styles.copyButton} value={getRoomUrl(roomId)} />
|
<CopyButton
|
||||||
|
className={styles.copyButton}
|
||||||
|
value={getRoomUrl(roomIdOrAlias)}
|
||||||
|
/>
|
||||||
</ModalContent>
|
</ModalContent>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
|
|
|
@ -41,7 +41,7 @@ export function LobbyView({
|
||||||
localVideoMuted,
|
localVideoMuted,
|
||||||
toggleLocalVideoMuted,
|
toggleLocalVideoMuted,
|
||||||
toggleMicrophoneMuted,
|
toggleMicrophoneMuted,
|
||||||
roomId,
|
roomIdOrAlias,
|
||||||
isEmbedded,
|
isEmbedded,
|
||||||
}) {
|
}) {
|
||||||
const { stream } = useCallFeed(localCallFeed);
|
const { stream } = useCallFeed(localCallFeed);
|
||||||
|
@ -95,7 +95,7 @@ export function LobbyView({
|
||||||
<VideoPreview
|
<VideoPreview
|
||||||
state={state}
|
state={state}
|
||||||
client={client}
|
client={client}
|
||||||
roomId={roomId}
|
roomIdOrAlias={roomIdOrAlias}
|
||||||
microphoneMuted={microphoneMuted}
|
microphoneMuted={microphoneMuted}
|
||||||
localVideoMuted={localVideoMuted}
|
localVideoMuted={localVideoMuted}
|
||||||
toggleLocalVideoMuted={toggleLocalVideoMuted}
|
toggleLocalVideoMuted={toggleLocalVideoMuted}
|
||||||
|
@ -116,7 +116,7 @@ export function LobbyView({
|
||||||
<Body>Or</Body>
|
<Body>Or</Body>
|
||||||
<CopyButton
|
<CopyButton
|
||||||
variant="secondaryCopy"
|
variant="secondaryCopy"
|
||||||
value={getRoomUrl(roomId)}
|
value={getRoomUrl(roomIdOrAlias)}
|
||||||
className={styles.copyButton}
|
className={styles.copyButton}
|
||||||
copiedMessage="Call link copied"
|
copiedMessage="Call link copied"
|
||||||
>
|
>
|
||||||
|
|
|
@ -30,7 +30,7 @@ import { TooltipTrigger } from "../Tooltip";
|
||||||
import { FeedbackModal } from "./FeedbackModal";
|
import { FeedbackModal } from "./FeedbackModal";
|
||||||
|
|
||||||
export function OverflowMenu({
|
export function OverflowMenu({
|
||||||
roomId,
|
roomIdOrAlias,
|
||||||
inCall,
|
inCall,
|
||||||
groupCall,
|
groupCall,
|
||||||
showInvite,
|
showInvite,
|
||||||
|
@ -88,7 +88,7 @@ export function OverflowMenu({
|
||||||
</PopoverMenuTrigger>
|
</PopoverMenuTrigger>
|
||||||
{settingsModalState.isOpen && <SettingsModal {...settingsModalProps} />}
|
{settingsModalState.isOpen && <SettingsModal {...settingsModalProps} />}
|
||||||
{inviteModalState.isOpen && (
|
{inviteModalState.isOpen && (
|
||||||
<InviteModal roomId={roomId} {...inviteModalProps} />
|
<InviteModal roomIdOrAlias={roomIdOrAlias} {...inviteModalProps} />
|
||||||
)}
|
)}
|
||||||
{feedbackModalState.isOpen && (
|
{feedbackModalState.isOpen && (
|
||||||
<FeedbackModal
|
<FeedbackModal
|
||||||
|
|
|
@ -86,7 +86,7 @@ function getPromptText(
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
client: MatrixClient;
|
client: MatrixClient;
|
||||||
roomId: string;
|
roomIdOrAlias: string;
|
||||||
roomName: string;
|
roomName: string;
|
||||||
avatarUrl: string;
|
avatarUrl: string;
|
||||||
groupCall: GroupCall;
|
groupCall: GroupCall;
|
||||||
|
@ -98,7 +98,7 @@ interface Props {
|
||||||
|
|
||||||
export const PTTCallView: React.FC<Props> = ({
|
export const PTTCallView: React.FC<Props> = ({
|
||||||
client,
|
client,
|
||||||
roomId,
|
roomIdOrAlias,
|
||||||
roomName,
|
roomName,
|
||||||
avatarUrl,
|
avatarUrl,
|
||||||
groupCall,
|
groupCall,
|
||||||
|
@ -204,7 +204,7 @@ export const PTTCallView: React.FC<Props> = ({
|
||||||
<div className={styles.footer}>
|
<div className={styles.footer}>
|
||||||
<OverflowMenu
|
<OverflowMenu
|
||||||
inCall
|
inCall
|
||||||
roomId={roomId}
|
roomIdOrAlias={roomIdOrAlias}
|
||||||
client={client}
|
client={client}
|
||||||
groupCall={groupCall}
|
groupCall={groupCall}
|
||||||
showInvite={false}
|
showInvite={false}
|
||||||
|
@ -282,7 +282,7 @@ export const PTTCallView: React.FC<Props> = ({
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{inviteModalState.isOpen && showControls && (
|
{inviteModalState.isOpen && showControls && (
|
||||||
<InviteModal roomId={roomId} {...inviteModalProps} />
|
<InviteModal roomIdOrAlias={roomIdOrAlias} {...inviteModalProps} />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -21,7 +21,11 @@ import { FieldRow, ErrorMessage } from "../input/Input";
|
||||||
import { useSubmitRageshake } from "../settings/submit-rageshake";
|
import { useSubmitRageshake } from "../settings/submit-rageshake";
|
||||||
import { Body } from "../typography/Typography";
|
import { Body } from "../typography/Typography";
|
||||||
|
|
||||||
export function RageshakeRequestModal({ rageshakeRequestId, roomId, ...rest }) {
|
export function RageshakeRequestModal({
|
||||||
|
rageshakeRequestId,
|
||||||
|
roomIdOrAlias,
|
||||||
|
...rest
|
||||||
|
}) {
|
||||||
const { submitRageshake, sending, sent, error } = useSubmitRageshake();
|
const { submitRageshake, sending, sent, error } = useSubmitRageshake();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -43,7 +47,7 @@ export function RageshakeRequestModal({ rageshakeRequestId, roomId, ...rest }) {
|
||||||
submitRageshake({
|
submitRageshake({
|
||||||
sendLogs: true,
|
sendLogs: true,
|
||||||
rageshakeRequestId,
|
rageshakeRequestId,
|
||||||
roomId,
|
roomIdOrAlias, // Possibly not a room ID, but oh well
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
disabled={sending}
|
disabled={sending}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
Copyright 2021 New Vector Ltd
|
Copyright 2021-2022 New Vector Ltd
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -14,13 +14,13 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { useEffect, useMemo, useState } from "react";
|
import React, { FC, useEffect, useState } from "react";
|
||||||
import { useLocation, useParams } from "react-router-dom";
|
|
||||||
import { useClient } from "../ClientContext";
|
import { useClient } from "../ClientContext";
|
||||||
import { ErrorView, LoadingView } from "../FullScreenView";
|
import { ErrorView, LoadingView } from "../FullScreenView";
|
||||||
import { RoomAuthView } from "./RoomAuthView";
|
import { RoomAuthView } from "./RoomAuthView";
|
||||||
import { GroupCallLoader } from "./GroupCallLoader";
|
import { GroupCallLoader } from "./GroupCallLoader";
|
||||||
import { GroupCallView } from "./GroupCallView";
|
import { GroupCallView } from "./GroupCallView";
|
||||||
|
import { useRoomParams } from "./useRoomParams";
|
||||||
import { MediaHandlerProvider } from "../settings/useMediaHandler";
|
import { MediaHandlerProvider } from "../settings/useMediaHandler";
|
||||||
import { useRegisterPasswordlessUser } from "../auth/useRegisterPasswordlessUser";
|
import { useRegisterPasswordlessUser } from "../auth/useRegisterPasswordlessUser";
|
||||||
|
|
||||||
|
@ -28,20 +28,12 @@ export function RoomPage() {
|
||||||
const { loading, isAuthenticated, error, client, isPasswordlessUser } =
|
const { loading, isAuthenticated, error, client, isPasswordlessUser } =
|
||||||
useClient();
|
useClient();
|
||||||
|
|
||||||
const { roomId: maybeRoomId } = useParams();
|
const { roomAlias, roomId, viaServers, isEmbedded, isPtt, displayName } =
|
||||||
const { hash, search } = useLocation();
|
useRoomParams();
|
||||||
const [viaServers, isEmbedded, isPtt, displayName] = useMemo(() => {
|
const roomIdOrAlias = roomId ?? roomAlias;
|
||||||
const params = new URLSearchParams(search);
|
if (!roomIdOrAlias) throw new Error("No room specified");
|
||||||
return [
|
|
||||||
params.getAll("via"),
|
const { registerPasswordlessUser } = useRegisterPasswordlessUser();
|
||||||
params.has("embed"),
|
|
||||||
params.get("ptt") === "true",
|
|
||||||
params.get("displayName"),
|
|
||||||
];
|
|
||||||
}, [search]);
|
|
||||||
const roomId = (maybeRoomId || hash || "").toLowerCase();
|
|
||||||
const { registerPasswordlessUser, recaptchaId } =
|
|
||||||
useRegisterPasswordlessUser();
|
|
||||||
const [isRegistering, setIsRegistering] = useState(false);
|
const [isRegistering, setIsRegistering] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -76,14 +68,14 @@ export function RoomPage() {
|
||||||
<MediaHandlerProvider client={client}>
|
<MediaHandlerProvider client={client}>
|
||||||
<GroupCallLoader
|
<GroupCallLoader
|
||||||
client={client}
|
client={client}
|
||||||
roomId={roomId}
|
roomIdOrAlias={roomIdOrAlias}
|
||||||
viaServers={viaServers}
|
viaServers={viaServers}
|
||||||
createPtt={isPtt}
|
createPtt={isPtt}
|
||||||
>
|
>
|
||||||
{(groupCall) => (
|
{(groupCall) => (
|
||||||
<GroupCallView
|
<GroupCallView
|
||||||
client={client}
|
client={client}
|
||||||
roomId={roomId}
|
roomIdOrAlias={roomIdOrAlias}
|
||||||
groupCall={groupCall}
|
groupCall={groupCall}
|
||||||
isPasswordlessUser={isPasswordlessUser}
|
isPasswordlessUser={isPasswordlessUser}
|
||||||
isEmbedded={isEmbedded}
|
isEmbedded={isEmbedded}
|
||||||
|
|
|
@ -30,7 +30,7 @@ import { useModalTriggerState } from "../Modal";
|
||||||
export function VideoPreview({
|
export function VideoPreview({
|
||||||
client,
|
client,
|
||||||
state,
|
state,
|
||||||
roomId,
|
roomIdOrAlias,
|
||||||
microphoneMuted,
|
microphoneMuted,
|
||||||
localVideoMuted,
|
localVideoMuted,
|
||||||
toggleLocalVideoMuted,
|
toggleLocalVideoMuted,
|
||||||
|
@ -80,7 +80,7 @@ export function VideoPreview({
|
||||||
onPress={toggleLocalVideoMuted}
|
onPress={toggleLocalVideoMuted}
|
||||||
/>
|
/>
|
||||||
<OverflowMenu
|
<OverflowMenu
|
||||||
roomId={roomId}
|
roomIdOrAlias={roomIdOrAlias}
|
||||||
client={client}
|
client={client}
|
||||||
feedbackModalState={feedbackModalState}
|
feedbackModalState={feedbackModalState}
|
||||||
feedbackModalProps={feedbackModalProps}
|
feedbackModalProps={feedbackModalProps}
|
||||||
|
|
93
src/room/useRoomParams.ts
Normal file
93
src/room/useRoomParams.ts
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
/*
|
||||||
|
Copyright 2022 New Vector Ltd
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { useMemo } from "react";
|
||||||
|
import { useLocation } from "react-router-dom";
|
||||||
|
|
||||||
|
export interface RoomParams {
|
||||||
|
roomAlias: string | null;
|
||||||
|
roomId: string | null;
|
||||||
|
viaServers: string[];
|
||||||
|
// Whether the app is running in embedded mode, and should keep the user
|
||||||
|
// confined to the current room
|
||||||
|
isEmbedded: boolean;
|
||||||
|
// Whether to start a walkie-talkie call instead of a video call
|
||||||
|
isPtt: boolean;
|
||||||
|
// Whether to use end-to-end encryption
|
||||||
|
e2eEnabled: boolean;
|
||||||
|
// The user's ID (only used in Matroska mode)
|
||||||
|
userId: string | null;
|
||||||
|
// The display name to use for auto-registration
|
||||||
|
displayName: string | null;
|
||||||
|
// The device's ID (only used in Matroska mode)
|
||||||
|
deviceId: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the room parameters for the current URL.
|
||||||
|
* @param {string} query The URL query string
|
||||||
|
* @param {string} fragment The URL fragment string
|
||||||
|
* @returns {RoomParams} The room parameters encoded in the URL
|
||||||
|
*/
|
||||||
|
export const getRoomParams = (
|
||||||
|
query: string = window.location.search,
|
||||||
|
fragment: string = window.location.hash
|
||||||
|
): RoomParams => {
|
||||||
|
const fragmentQueryStart = fragment.indexOf("?");
|
||||||
|
const fragmentParams = new URLSearchParams(
|
||||||
|
fragmentQueryStart === -1 ? "" : fragment.substring(fragmentQueryStart)
|
||||||
|
);
|
||||||
|
const queryParams = new URLSearchParams(query);
|
||||||
|
|
||||||
|
// Normally, room params should be encoded in the fragment so as to avoid
|
||||||
|
// leaking them to the server. However, we also check the normal query
|
||||||
|
// string for backwards compatibility with versions that only used that.
|
||||||
|
const hasParam = (name: string): boolean =>
|
||||||
|
fragmentParams.has(name) || queryParams.has(name);
|
||||||
|
const getParam = (name: string): string | null =>
|
||||||
|
fragmentParams.get(name) ?? queryParams.get(name);
|
||||||
|
const getAllParams = (name: string): string[] => [
|
||||||
|
...fragmentParams.getAll(name),
|
||||||
|
...queryParams.getAll(name),
|
||||||
|
];
|
||||||
|
|
||||||
|
// The part of the fragment before the ?
|
||||||
|
const fragmentRoute =
|
||||||
|
fragmentQueryStart === -1
|
||||||
|
? fragment
|
||||||
|
: fragment.substring(0, fragmentQueryStart);
|
||||||
|
|
||||||
|
return {
|
||||||
|
roomAlias: fragmentRoute.length > 1 ? fragmentRoute : null,
|
||||||
|
roomId: getParam("roomId"),
|
||||||
|
viaServers: getAllParams("via"),
|
||||||
|
isEmbedded: hasParam("embed"),
|
||||||
|
isPtt: hasParam("ptt"),
|
||||||
|
e2eEnabled: getParam("enableE2e") !== "false", // Defaults to true
|
||||||
|
userId: getParam("userId"),
|
||||||
|
displayName: getParam("displayName"),
|
||||||
|
deviceId: getParam("deviceId"),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hook to simplify use of getRoomParams.
|
||||||
|
* @returns {RoomParams} The room parameters for the current URL
|
||||||
|
*/
|
||||||
|
export const useRoomParams = (): RoomParams => {
|
||||||
|
const { hash, search } = useLocation();
|
||||||
|
return useMemo(() => getRoomParams(search, hash), [search, hash]);
|
||||||
|
};
|
Loading…
Add table
Reference in a new issue