From 0f97d655d2a6a5345958d1231c54ef0718c458a6 Mon Sep 17 00:00:00 2001 From: Robin Date: Sun, 17 Sep 2023 17:48:03 -0400 Subject: [PATCH 1/9] Add a prompt to launch Element X on mobile This shows a bottom sheet on mobile asking the user whether they want to open the call in Element X, as soon as the page is loaded. --- public/locales/en-GB/app.json | 4 ++ src/UrlParams.ts | 16 ++++++ src/room/AppSelectionModal.module.css | 33 ++++++++++++ src/room/AppSelectionModal.tsx | 77 +++++++++++++++++++++++++++ src/room/RoomPage.tsx | 53 ++++++++++-------- 5 files changed, 161 insertions(+), 22 deletions(-) create mode 100644 src/room/AppSelectionModal.module.css create mode 100644 src/room/AppSelectionModal.tsx diff --git a/public/locales/en-GB/app.json b/public/locales/en-GB/app.json index f6a7ed65..d9132962 100644 --- a/public/locales/en-GB/app.json +++ b/public/locales/en-GB/app.json @@ -27,6 +27,7 @@ "Close": "Close", "Confirm password": "Confirm password", "Connectivity to the server has been lost.": "Connectivity to the server has been lost.", + "Continue in browser": "Continue in browser", "Copied!": "Copied!", "Copy": "Copy", "Copy and share this call link": "Copy and share this call link", @@ -70,9 +71,11 @@ "Not encrypted": "Not encrypted", "Not now, return to home screen": "Not now, return to home screen", "Not registered yet? <2>Create an account": "Not registered yet? <2>Create an account", + "Open in the app": "Open in the app", "Password": "Password", "Passwords must match": "Passwords must match", "Profile": "Profile", + "Ready to join?": "Ready to join?", "Recaptcha dismissed": "Recaptcha dismissed", "Recaptcha not loaded": "Recaptcha not loaded", "Reconnect": "Reconnect", @@ -82,6 +85,7 @@ "Retry sending logs": "Retry sending logs", "Return to home screen": "Return to home screen", "Select an option": "Select an option", + "Select app": "Select app", "Send debug logs": "Send debug logs", "Sending debug logs…": "Sending debug logs…", "Sending…": "Sending…", diff --git a/src/UrlParams.ts b/src/UrlParams.ts index e6f0cd05..a4b67299 100644 --- a/src/UrlParams.ts +++ b/src/UrlParams.ts @@ -94,6 +94,22 @@ interface UrlParams { password: string | null; } +export function editFragmentQuery( + hash: string, + edit: (params: URLSearchParams) => URLSearchParams +): string { + const fragmentQueryStart = hash.indexOf("?"); + const fragmentParams = edit( + new URLSearchParams( + fragmentQueryStart === -1 ? "" : hash.substring(fragmentQueryStart) + ) + ); + return `${hash.substring( + 0, + fragmentQueryStart + )}?${fragmentParams.toString()}`; +} + /** * Gets the app parameters for the current URL. * @param ignoreRoomAlias If true, does not try to parse a room alias from the URL diff --git a/src/room/AppSelectionModal.module.css b/src/room/AppSelectionModal.module.css new file mode 100644 index 00000000..773df4fd --- /dev/null +++ b/src/room/AppSelectionModal.module.css @@ -0,0 +1,33 @@ +/* +Copyright 2023 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. +*/ + +.modal p { + text-align: center; + margin-block-end: var(--cpd-space-8x); +} + +.modal button, +.modal a { + width: 100%; +} + +.modal button { + margin-block-end: var(--cpd-space-6x); +} + +.modal a { + box-sizing: border-box; +} diff --git a/src/room/AppSelectionModal.tsx b/src/room/AppSelectionModal.tsx new file mode 100644 index 00000000..7d5a1a47 --- /dev/null +++ b/src/room/AppSelectionModal.tsx @@ -0,0 +1,77 @@ +/* +Copyright 2023 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 { FC, MouseEvent, useCallback, useMemo, useState } from "react"; +import { useTranslation } from "react-i18next"; +import { Button, Text } from "@vector-im/compound-web"; +import { ReactComponent as PopOutIcon } from "@vector-im/compound-design-tokens/icons/pop-out.svg"; + +import { Modal } from "../NewModal"; +import { useRoomSharedKey } from "../e2ee/sharedKeyManagement"; +import { getRoomUrl } from "../matrix-utils"; +import styles from "./AppSelectionModal.module.css"; +import { editFragmentQuery } from "../UrlParams"; + +interface Props { + roomId: string | null; +} + +export const AppSelectionModal: FC = ({ roomId }) => { + const { t } = useTranslation(); + + const [open, setOpen] = useState(true); + const onBrowserClick = useCallback( + (e: MouseEvent) => { + e.preventDefault(); + e.stopPropagation(); + setOpen(false); + }, + [setOpen] + ); + + const roomSharedKey = useRoomSharedKey(roomId ?? ""); + const appUrl = useMemo(() => { + // If the room ID is not known, fall back to the URL of the current page + const url = new URL( + roomId === null + ? window.location.href + : getRoomUrl(roomId, roomSharedKey ?? undefined) + ); + // Edit the URL so that it opens in embedded mode + url.hash = editFragmentQuery(url.hash, (params) => { + params.set("isEmbedded", ""); + return params; + }); + + const result = new URL("element://call"); + result.searchParams.set("url", url.toString()); + return result.toString(); + }, [roomId, roomSharedKey]); + + return ( + + + {t("Ready to join?")} + + + + + ); +}; diff --git a/src/room/RoomPage.tsx b/src/room/RoomPage.tsx index 50156e70..b9e9a8a5 100644 --- a/src/room/RoomPage.tsx +++ b/src/room/RoomPage.tsx @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { FC, useEffect, useState, useCallback } from "react"; +import { FC, useEffect, useState, useCallback, ReactNode } from "react"; import { MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc/MatrixRTCSession"; import { useClientLegacy } from "../ClientContext"; @@ -26,6 +26,8 @@ import { useUrlParams } from "../UrlParams"; import { useRegisterPasswordlessUser } from "../auth/useRegisterPasswordlessUser"; import { useOptInAnalytics } from "../settings/useSetting"; import { HomePage } from "../home/HomePage"; +import { platform } from "../Platform"; +import { AppSelectionModal } from "./AppSelectionModal"; export const RoomPage: FC = () => { const { @@ -86,30 +88,37 @@ export const RoomPage: FC = () => { [client, passwordlessUser, isEmbedded, preload, hideHeader] ); + let content: ReactNode; if (loading || isRegistering) { - return ; - } - - if (error) { - return ; - } - - if (!client) { - return ; - } - - if (!roomIdOrAlias) { - return ; + content = ; + } else if (error) { + content = ; + } else if (!client) { + content = ; + } else if (!roomIdOrAlias) { + // TODO: This doesn't belong here, the app routes need to be reworked + content = ; + } else { + content = ( + + {groupCallView} + + ); } return ( - - {groupCallView} - + <> + {content} + {/* On mobile, show a prompt to launch the mobile app. If in embedded mode, + that means we *are* in the mobile app and should show no further prompt. */} + {(platform === "android" || platform === "ios") && !isEmbedded && ( + + )} + ); }; From db0d3b1ee9c4dd910191819eda5ccd62d7a1a831 Mon Sep 17 00:00:00 2001 From: Robin Date: Mon, 18 Sep 2023 10:42:07 -0400 Subject: [PATCH 2/9] Fix the feedback screen looking broken on mobile --- src/room/CallEndedView.module.css | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/room/CallEndedView.module.css b/src/room/CallEndedView.module.css index 9952a784..12409d4e 100644 --- a/src/room/CallEndedView.module.css +++ b/src/room/CallEndedView.module.css @@ -17,7 +17,8 @@ limitations under the License. .headline { text-align: center; margin-bottom: 60px; - white-space: pre; + white-space: pre-wrap; + overflow-wrap: break-word; } .callEndedContent { @@ -66,6 +67,7 @@ limitations under the License. flex: 1; flex-direction: column; align-items: center; + padding-inline: var(--inline-content-inset); } .logo { From 1e9e0963562d0bdfe16cbbd802c79281e9cfcc7f Mon Sep 17 00:00:00 2001 From: Robin Date: Mon, 18 Sep 2023 11:06:06 -0400 Subject: [PATCH 3/9] Fully remove walkie-talkie mode --- public/locales/en-GB/app.json | 10 +--- src/UrlParams.ts | 5 -- src/home/CallTypeDropdown.module.css | 19 ------- src/home/CallTypeDropdown.tsx | 85 ---------------------------- src/home/HomePage.tsx | 5 +- src/home/RegisteredView.tsx | 33 ++++------- src/home/UnauthenticatedView.tsx | 30 +++------- src/matrix-utils.ts | 9 +-- src/room/GroupCallLoader.tsx | 9 +-- src/room/RoomPage.tsx | 2 - src/room/useLoadGroupCall.ts | 6 +- 11 files changed, 29 insertions(+), 184 deletions(-) delete mode 100644 src/home/CallTypeDropdown.module.css delete mode 100644 src/home/CallTypeDropdown.tsx diff --git a/public/locales/en-GB/app.json b/public/locales/en-GB/app.json index f6a7ed65..84798e1e 100644 --- a/public/locales/en-GB/app.json +++ b/public/locales/en-GB/app.json @@ -22,7 +22,6 @@ "By clicking \"Join call now\", you agree to our <2>End User Licensing Agreement (EULA)": "By clicking \"Join call now\", you agree to our <2>End User Licensing Agreement (EULA)", "By participating in this beta, you consent to the collection of anonymous data, which we use to improve the product. You can find more information about which data we track in our <2>Privacy Policy and our <5>Cookie Policy.": "By participating in this beta, you consent to the collection of anonymous data, which we use to improve the product. You can find more information about which data we track in our <2>Privacy Policy and our <5>Cookie Policy.", "Call link copied": "Call link copied", - "Call type menu": "Call type menu", "Camera": "Camera", "Close": "Close", "Confirm password": "Confirm password", @@ -66,6 +65,7 @@ "Microphone off": "Microphone off", "Microphone on": "Microphone on", "More": "More", + "Name of call": "Name of call", "No": "No", "Not encrypted": "Not encrypted", "Not now, return to home screen": "Not now, return to home screen", @@ -96,6 +96,7 @@ "Sign out": "Sign out", "Speaker": "Speaker", "Spotlight": "Spotlight", + "Start new call": "Start new call", "Submit": "Submit", "Submit feedback": "Submit feedback", "Submitting…": "Submitting…", @@ -108,16 +109,11 @@ "Username": "Username", "Version: {{version}}": "Version: {{version}}", "Video": "Video", - "Video call": "Video call", - "Video call name": "Video call name", "Video off": "Video off", "Video on": "Video on", "Waiting for other participants…": "Waiting for other participants…", - "Walkie-talkie call": "Walkie-talkie call", - "Walkie-talkie call name": "Walkie-talkie call name", "Yes, join call": "Yes, join call", "You": "You", "You were disconnected from the call": "You were disconnected from the call", - "Your feedback": "Your feedback", - "Your recent calls": "Your recent calls" + "Your feedback": "Your feedback" } diff --git a/src/UrlParams.ts b/src/UrlParams.ts index e6f0cd05..6a2ea501 100644 --- a/src/UrlParams.ts +++ b/src/UrlParams.ts @@ -43,10 +43,6 @@ interface UrlParams { * Whether to hide the screen-sharing button. */ hideScreensharing: boolean; - /** - * Whether to start a walkie-talkie call instead of a video call. - */ - isPtt: boolean; /** * Whether to use end-to-end encryption. */ @@ -179,7 +175,6 @@ export const getUrlParams = ( preload: hasParam("preload"), hideHeader: hasParam("hideHeader"), hideScreensharing: hasParam("hideScreensharing"), - isPtt: hasParam("ptt"), e2eEnabled: getParam("enableE2e") !== "false", // Defaults to true userId: getParam("userId"), displayName: getParam("displayName"), diff --git a/src/home/CallTypeDropdown.module.css b/src/home/CallTypeDropdown.module.css deleted file mode 100644 index 6641fea0..00000000 --- a/src/home/CallTypeDropdown.module.css +++ /dev/null @@ -1,19 +0,0 @@ -/* -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. -*/ - -.label { - margin-bottom: 0; -} diff --git a/src/home/CallTypeDropdown.tsx b/src/home/CallTypeDropdown.tsx deleted file mode 100644 index f24d3d48..00000000 --- a/src/home/CallTypeDropdown.tsx +++ /dev/null @@ -1,85 +0,0 @@ -/* -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 { FC } from "react"; -import { Item } from "@react-stately/collections"; -import { useTranslation } from "react-i18next"; - -import { Headline } from "../typography/Typography"; -import { Button } from "../button"; -import { PopoverMenuTrigger } from "../popover/PopoverMenu"; -import { ReactComponent as VideoIcon } from "../icons/Video.svg"; -import { ReactComponent as MicIcon } from "../icons/Mic.svg"; -import { ReactComponent as CheckIcon } from "../icons/Check.svg"; -import styles from "./CallTypeDropdown.module.css"; -import commonStyles from "./common.module.css"; -import menuStyles from "../Menu.module.css"; -import { Menu } from "../Menu"; - -export enum CallType { - Video = "video", - Radio = "radio", -} - -interface Props { - callType: CallType; - setCallType: (value: CallType) => void; -} - -export const CallTypeDropdown: FC = ({ callType, setCallType }) => { - const { t } = useTranslation(); - - const onAction = (key: React.Key) => { - setCallType(key.toString() as CallType); - }; - - const onClose = () => {}; - - return ( - - - {(props: JSX.IntrinsicAttributes) => ( - - - - {t("Video call")} - {callType === CallType.Video && ( - - )} - - - - {t("Walkie-talkie call")} - {callType === CallType.Radio && ( - - )} - - - )} - - ); -}; diff --git a/src/home/HomePage.tsx b/src/home/HomePage.tsx index 018e0512..a78cb8bd 100644 --- a/src/home/HomePage.tsx +++ b/src/home/HomePage.tsx @@ -34,10 +34,7 @@ export function HomePage() { return ; } else { return clientState.authenticated ? ( - + ) : ( ); diff --git a/src/home/RegisteredView.tsx b/src/home/RegisteredView.tsx index 0f8cc93c..87c0a417 100644 --- a/src/home/RegisteredView.tsx +++ b/src/home/RegisteredView.tsx @@ -19,6 +19,7 @@ import { useHistory } from "react-router-dom"; import { MatrixClient } from "matrix-js-sdk/src/client"; import { randomString } from "matrix-js-sdk/src/randomstring"; import { useTranslation } from "react-i18next"; +import { Heading } from "@vector-im/compound-web"; import { createRoom, @@ -35,9 +36,8 @@ import { CallList } from "./CallList"; import { UserMenuContainer } from "../UserMenuContainer"; import { useModalTriggerState } from "../Modal"; import { JoinExistingCallModal } from "./JoinExistingCallModal"; -import { Caption, Title } from "../typography/Typography"; +import { Caption } from "../typography/Typography"; import { Form } from "../form/Form"; -import { CallType, CallTypeDropdown } from "./CallTypeDropdown"; import { useEnableE2EE, useOptInAnalytics } from "../settings/useSetting"; import { AnalyticsNotice } from "../analytics/AnalyticsNotice"; import { E2EEBanner } from "../E2EEBanner"; @@ -46,11 +46,9 @@ import { getRoomSharedKeyLocalStorageKey } from "../e2ee/sharedKeyManagement"; interface Props { client: MatrixClient; - isPasswordlessUser: boolean; } -export function RegisteredView({ client, isPasswordlessUser }: Props) { - const [callType, setCallType] = useState(CallType.Video); +export function RegisteredView({ client }: Props) { const [loading, setLoading] = useState(false); const [error, setError] = useState(); const [optInAnalytics] = useOptInAnalytics(); @@ -68,14 +66,13 @@ export function RegisteredView({ client, isPasswordlessUser }: Props) { typeof roomNameData === "string" ? sanitiseRoomNameInput(roomNameData) : ""; - const ptt = callType === CallType.Radio; async function submit() { setError(undefined); setLoading(true); const roomId = ( - await createRoom(client, roomName, ptt, e2eeEnabled ?? false) + await createRoom(client, roomName, e2eeEnabled ?? false) )[1]; if (e2eeEnabled) { @@ -101,7 +98,7 @@ export function RegisteredView({ client, isPasswordlessUser }: Props) { } }); }, - [client, history, modalState, callType, e2eeEnabled] + [client, history, modalState, e2eeEnabled] ); const recentRooms = useGroupCallRooms(client); @@ -111,11 +108,6 @@ export function RegisteredView({ client, isPasswordlessUser }: Props) { history.push(`/${existingAlias}`); }, [history, existingAlias]); - const callNameLabel = - callType === CallType.Video - ? t("Video call name") - : t("Walkie-talkie call name"); - return ( <>
@@ -129,14 +121,16 @@ export function RegisteredView({ client, isPasswordlessUser }: Props) {
- + + {t("Start new call")} +
{recentRooms.length > 0 && ( - <> - - {t("Your recent calls")} - - - + )}
diff --git a/src/home/UnauthenticatedView.tsx b/src/home/UnauthenticatedView.tsx index 721c56d1..fb3a3445 100644 --- a/src/home/UnauthenticatedView.tsx +++ b/src/home/UnauthenticatedView.tsx @@ -18,6 +18,7 @@ import { FC, useCallback, useState, FormEventHandler } from "react"; import { useHistory } from "react-router-dom"; import { randomString } from "matrix-js-sdk/src/randomstring"; import { Trans, useTranslation } from "react-i18next"; +import { Heading } from "@vector-im/compound-web"; import { useClient } from "../ClientContext"; import { Header, HeaderLogo, LeftNav, RightNav } from "../Header"; @@ -35,7 +36,6 @@ import { JoinExistingCallModal } from "./JoinExistingCallModal"; import { useRecaptcha } from "../auth/useRecaptcha"; import { Body, Caption, Link } from "../typography/Typography"; import { Form } from "../form/Form"; -import { CallType, CallTypeDropdown } from "./CallTypeDropdown"; import styles from "./UnauthenticatedView.module.css"; import commonStyles from "./common.module.css"; import { generateRandomName } from "../auth/generateRandomName"; @@ -48,7 +48,6 @@ import { setLocalStorageItem } from "../useLocalStorage"; export const UnauthenticatedView: FC = () => { const { setClient } = useClient(); - const [callType, setCallType] = useState(CallType.Video); const [loading, setLoading] = useState(false); const [error, setError] = useState(); const [optInAnalytics] = useOptInAnalytics(); @@ -68,7 +67,6 @@ export const UnauthenticatedView: FC = () => { const data = new FormData(e.target as HTMLFormElement); const roomName = sanitiseRoomNameInput(data.get("callName") as string); const displayName = data.get("displayName") as string; - const ptt = callType === CallType.Radio; async function submit() { setError(undefined); @@ -86,7 +84,7 @@ export const UnauthenticatedView: FC = () => { let roomId: string; try { roomId = ( - await createRoom(client, roomName, ptt, e2eeEnabled ?? false) + await createRoom(client, roomName, e2eeEnabled ?? false) )[1]; if (e2eeEnabled) { @@ -133,23 +131,9 @@ export const UnauthenticatedView: FC = () => { reset(); }); }, - [ - register, - reset, - execute, - history, - callType, - modalState, - setClient, - e2eeEnabled, - ] + [register, reset, execute, history, modalState, setClient, e2eeEnabled] ); - const callNameLabel = - callType === CallType.Video - ? t("Video call name") - : t("Walkie-talkie call name"); - return ( <>
@@ -163,14 +147,16 @@ export const UnauthenticatedView: FC = () => {
- + + {t("Start new call")} + { logger.log(`Creating room for group call`); @@ -327,14 +326,12 @@ export async function createRoom( const result = await createPromise; - logger.log( - `Creating ${ptt ? "PTT" : "video"} group call in ${result.room_id}` - ); + logger.log(`Creating group call in ${result.room_id}`); await client.createGroupCall( result.room_id, - ptt ? GroupCallType.Voice : GroupCallType.Video, - ptt, + GroupCallType.Video, + false, GroupCallIntent.Room, true ); diff --git a/src/room/GroupCallLoader.tsx b/src/room/GroupCallLoader.tsx index 78fa780c..5f71f203 100644 --- a/src/room/GroupCallLoader.tsx +++ b/src/room/GroupCallLoader.tsx @@ -27,7 +27,6 @@ interface Props { roomIdOrAlias: string; viaServers: string[]; children: (rtcSession: MatrixRTCSession) => ReactNode; - createPtt: boolean; } export function GroupCallLoader({ @@ -35,15 +34,9 @@ export function GroupCallLoader({ roomIdOrAlias, viaServers, children, - createPtt, }: Props): JSX.Element { const { t } = useTranslation(); - const groupCallState = useLoadGroupCall( - client, - roomIdOrAlias, - viaServers, - createPtt - ); + const groupCallState = useLoadGroupCall(client, roomIdOrAlias, viaServers); switch (groupCallState.kind) { case "loading": diff --git a/src/room/RoomPage.tsx b/src/room/RoomPage.tsx index 50156e70..c7eed871 100644 --- a/src/room/RoomPage.tsx +++ b/src/room/RoomPage.tsx @@ -35,7 +35,6 @@ export const RoomPage: FC = () => { isEmbedded, preload, hideHeader, - isPtt, displayName, } = useUrlParams(); const roomIdOrAlias = roomId ?? roomAlias; @@ -107,7 +106,6 @@ export const RoomPage: FC = () => { client={client} roomIdOrAlias={roomIdOrAlias} viaServers={viaServers} - createPtt={isPtt} > {groupCallView} diff --git a/src/room/useLoadGroupCall.ts b/src/room/useLoadGroupCall.ts index 9218bf32..e6f79ced 100644 --- a/src/room/useLoadGroupCall.ts +++ b/src/room/useLoadGroupCall.ts @@ -56,8 +56,7 @@ export interface GroupCallLoadState { export const useLoadGroupCall = ( client: MatrixClient, roomIdOrAlias: string, - viaServers: string[], - createPtt: boolean + viaServers: string[] ): GroupCallStatus => { const { t } = useTranslation(); const [state, setState] = useState({ kind: "loading" }); @@ -101,7 +100,6 @@ export const useLoadGroupCall = ( const [, roomId] = await createRoom( client, roomNameFromRoomId(roomIdOrAlias), - createPtt, e2eeEnabled ?? false ); @@ -151,7 +149,7 @@ export const useLoadGroupCall = ( .then(fetchOrCreateGroupCall) .then((rtcSession) => setState({ kind: "loaded", rtcSession })) .catch((error) => setState({ kind: "failed", error })); - }, [client, roomIdOrAlias, viaServers, createPtt, t, e2eeEnabled]); + }, [client, roomIdOrAlias, viaServers, t, e2eeEnabled]); return state; }; From 282c345ad352ff3938ce0faedbcb2357af8c26d0 Mon Sep 17 00:00:00 2001 From: Robin Date: Mon, 18 Sep 2023 11:17:15 -0400 Subject: [PATCH 4/9] Invert the microphone and video button states MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit … so that they use the 'on' state when muted, and announce the action that they take rather than the current state, as suggested in internal design guidance. --- public/locales/en-GB/app.json | 6 ++++-- src/button/Button.tsx | 8 ++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/public/locales/en-GB/app.json b/public/locales/en-GB/app.json index f6a7ed65..c1cc75a9 100644 --- a/public/locales/en-GB/app.json +++ b/public/locales/en-GB/app.json @@ -66,6 +66,7 @@ "Microphone off": "Microphone off", "Microphone on": "Microphone on", "More": "More", + "Mute microphone": "Mute microphone", "No": "No", "Not encrypted": "Not encrypted", "Not now, return to home screen": "Not now, return to home screen", @@ -96,6 +97,8 @@ "Sign out": "Sign out", "Speaker": "Speaker", "Spotlight": "Spotlight", + "Start video": "Start video", + "Stop video": "Stop video", "Submit": "Submit", "Submit feedback": "Submit feedback", "Submitting…": "Submitting…", @@ -104,14 +107,13 @@ "Thanks!": "Thanks!", "This call already exists, would you like to join?": "This call already exists, would you like to join?", "This site is protected by ReCAPTCHA and the Google <2>Privacy Policy and <6>Terms of Service apply.<9>By clicking \"Register\", you agree to our <12>End User Licensing Agreement (EULA)": "This site is protected by ReCAPTCHA and the Google <2>Privacy Policy and <6>Terms of Service apply.<9>By clicking \"Register\", you agree to our <12>End User Licensing Agreement (EULA)", + "Unmute microphone": "Unmute microphone", "User menu": "User menu", "Username": "Username", "Version: {{version}}": "Version: {{version}}", "Video": "Video", "Video call": "Video call", "Video call name": "Video call name", - "Video off": "Video off", - "Video on": "Video on", "Waiting for other participants…": "Waiting for other participants…", "Walkie-talkie call": "Walkie-talkie call", "Walkie-talkie call name": "Walkie-talkie call name", diff --git a/src/button/Button.tsx b/src/button/Button.tsx index 2b8049e5..3d269dc2 100644 --- a/src/button/Button.tsx +++ b/src/button/Button.tsx @@ -145,11 +145,11 @@ export function MicButton({ }) { const { t } = useTranslation(); const Icon = muted ? MicOffSolidIcon : MicOnSolidIcon; - const label = muted ? t("Microphone off") : t("Microphone on"); + const label = muted ? t("Unmute microphone") : t("Mute microphone"); return ( - @@ -166,11 +166,11 @@ export function VideoButton({ }) { const { t } = useTranslation(); const Icon = muted ? VideoCallOffIcon : VideoCallIcon; - const label = muted ? t("Video off") : t("Video on"); + const label = muted ? t("Start video") : t("Stop video"); return ( - From b5ccff483dbdeb02feb4aa8dea2bb731065b2e86 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 18 Sep 2023 15:31:31 +0000 Subject: [PATCH 5/9] Update dependency @use-gesture/react to v10.3.0 --- yarn.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/yarn.lock b/yarn.lock index 4ed74726..551d2f9d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5114,17 +5114,17 @@ "@typescript-eslint/types" "6.1.0" eslint-visitor-keys "^3.4.1" -"@use-gesture/core@10.2.27": - version "10.2.27" - resolved "https://registry.yarnpkg.com/@use-gesture/core/-/core-10.2.27.tgz#0f24b17c036cd828ba07e3451ff45e2df959c6f5" - integrity sha512-V4XV7hn9GAD2MYu8yBBVi5iuWBsAMfjPRMsEVzoTNGYH72tf0kFP+OKqGKc8YJFQIJx6yj+AOqxmEHOmx2/MEA== +"@use-gesture/core@10.3.0": + version "10.3.0" + resolved "https://registry.yarnpkg.com/@use-gesture/core/-/core-10.3.0.tgz#9afd3777a45b2a08990a5dcfcf8d9ddd55b00db9" + integrity sha512-rh+6MND31zfHcy9VU3dOZCqGY511lvGcfyJenN4cWZe0u1BH6brBpBddLVXhF2r4BMqWbvxfsbL7D287thJU2A== "@use-gesture/react@^10.2.11": - version "10.2.27" - resolved "https://registry.yarnpkg.com/@use-gesture/react/-/react-10.2.27.tgz#7fbd50d14449ec5bc49c9b6cfef8a2845f5e0608" - integrity sha512-7E5vnWCxeslWlxwZ8uKIcnUZVMTRMZ8cvSnLLKF1NkyNb3PnNiAzoXM4G1vTKJKRhgOTeI6wK1YsEpwo9ABV5w== + version "10.3.0" + resolved "https://registry.yarnpkg.com/@use-gesture/react/-/react-10.3.0.tgz#180534c821fd635c2853cbcfa813f92c94f27e3f" + integrity sha512-3zc+Ve99z4usVP6l9knYVbVnZgfqhKah7sIG+PS2w+vpig2v2OLct05vs+ZXMzwxdNCMka8B+8WlOo0z6Pn6DA== dependencies: - "@use-gesture/core" "10.2.27" + "@use-gesture/core" "10.3.0" "@vector-im/compound-design-tokens@^0.0.5": version "0.0.5" From 7e963b9a0eab7f1541cab7067fe0ee8aed7858f6 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 18 Sep 2023 15:31:46 +0000 Subject: [PATCH 6/9] Update dependency babel-loader to v8.3.0 --- yarn.lock | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/yarn.lock b/yarn.lock index 4ed74726..96ae94d6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4768,11 +4768,16 @@ "@types/tough-cookie" "*" parse5 "^7.0.0" -"@types/json-schema@*", "@types/json-schema@^7.0.12", "@types/json-schema@^7.0.4", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.8": +"@types/json-schema@*", "@types/json-schema@^7.0.12", "@types/json-schema@^7.0.4", "@types/json-schema@^7.0.8": version "7.0.12" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.12.tgz#d70faba7039d5fca54c83c7dbab41051d2b6f6cb" integrity sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA== +"@types/json-schema@^7.0.5": + version "7.0.13" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.13.tgz#02c24f4363176d2d18fc8b70b9f3c54aba178a85" + integrity sha512-RbSSoHliUbnXj3ny0CNFOoxrIDV6SUGyStHsvDqosw6CkdPV8TtWGlfecuK4ToyMEAql6pzNxgCFKanovUzlgQ== + "@types/json5@^0.0.29": version "0.0.29" resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" @@ -6003,7 +6008,7 @@ babel-jest@^29.2.2: graceful-fs "^4.2.9" slash "^3.0.0" -babel-loader@^8.0.0: +babel-loader@^8.0.0, babel-loader@^8.2.3: version "8.3.0" resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.3.0.tgz#124936e841ba4fe8176786d6ff28add1f134d6a8" integrity sha512-H8SvsMF+m9t15HNLMipppzkC+Y2Yq+v3SonZyU70RBL/h1gxPkH08Ot8pEE9Z4Kd+czyWJClmFS8qzIP9OZ04Q== @@ -6013,16 +6018,6 @@ babel-loader@^8.0.0: make-dir "^3.1.0" schema-utils "^2.6.5" -babel-loader@^8.2.3: - version "8.2.5" - resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.2.5.tgz#d45f585e654d5a5d90f5350a779d7647c5ed512e" - integrity sha512-OSiFfH89LrEMiWd4pLNqGz4CwJDtbs2ZVc+iGu2HrkRfPxId9F2anQj38IxWpmRfsUY0aBZYi1EFcd3mhtRMLQ== - dependencies: - find-cache-dir "^3.3.1" - loader-utils "^2.0.0" - make-dir "^3.1.0" - schema-utils "^2.6.5" - babel-plugin-add-react-displayname@^0.0.5: version "0.0.5" resolved "https://registry.yarnpkg.com/babel-plugin-add-react-displayname/-/babel-plugin-add-react-displayname-0.0.5.tgz#339d4cddb7b65fd62d1df9db9fe04de134122bd5" From 7b9f70027aaaafb4b7ccde8dbbb1fecafe9103cd Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 18 Sep 2023 15:42:52 +0000 Subject: [PATCH 7/9] Update dependency @types/node to v18.17.17 --- yarn.lock | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/yarn.lock b/yarn.lock index fee7aaed..1c5f247a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4614,9 +4614,9 @@ integrity sha512-Mnq3O9Xz52exs3mlxMcQuA7/9VFe/dXcrgAyfjLkABIqxXKOgBRjyazTxUbjsxDa4BP7hhPliyjVTP9RDP14xg== "@types/node@^18.13.0": - version "18.13.0" - resolved "https://registry.yarnpkg.com/@types/node/-/node-18.13.0.tgz#0400d1e6ce87e9d3032c19eb6c58205b0d3f7850" - integrity sha512-gC3TazRzGoOnoKAhUx+Q0t8S9Tzs74z7m0ipwGpSqQrleP14hKxP4/JUeEQcD3W1/aIpnWl8pHowI7WokuZpXg== + version "18.17.17" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.17.17.tgz#53cc07ce582c9d7c5850702a3c2cb0af0d7b0ca1" + integrity sha512-cOxcXsQ2sxiwkykdJqvyFS+MLQPLvIdwh5l6gNg8qF6s+C7XSkEWOZjK+XhUZd+mYvHV/180g2cnCcIl4l06Pw== "@types/normalize-package-data@^2.4.0": version "2.4.1" @@ -4649,9 +4649,9 @@ integrity sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w== "@types/q@^1.5.1": - version "1.5.5" - resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.5.tgz#75a2a8e7d8ab4b230414505d92335d1dcb53a6df" - integrity sha512-L28j2FcJfSZOnL1WBjDYp2vUHCeIFlyYI/53EwD/rKUBQ7MtUUfbQWiyKJGpcnv4/WgrhWsFKrcPstcAt/J0tQ== + version "1.5.6" + resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.6.tgz#a6edffe8283910e46dc7a573621f928e6b47fa56" + integrity sha512-IKjZ8RjTSwD4/YG+2gtj7BPFRB/lNbWKTiSj3M7U/TD2B7HfYCxvp2Zz6xA2WIY7pAuL1QOUPw8gQRbUrrq4fQ== "@types/qs@^6.9.5": version "6.9.8" @@ -4659,9 +4659,9 @@ integrity sha512-u95svzDlTysU5xecFNTgfFG5RUWu1A9P0VzgpcIiGZA9iraHOdSzcxMxQ55DyeRaGCSxQi7LxXDI4rzq/MYfdg== "@types/react-dom@^18.0.0": - version "18.0.7" - resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.0.7.tgz#ee7cf8ec4e6977e3f0a7b1d38bd89c75aa2aec28" - integrity sha512-HaXc+BbqAZE1RdsK3tC8SbkFy6UL2xF76lT9rQs5JkPrJg3rWA3Ou/Lhw3YJQzEDkBpmJ79nBsfnd05WrBd2QQ== + version "18.2.7" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.2.7.tgz#67222a08c0a6ae0a0da33c3532348277c70abb63" + integrity sha512-GRaAEriuT4zp9N4p1i8BDBYmEyfo+xQ3yHjJU4eiK5NDa1RmUZG+unZABUTK4/Ox/M+GaHwb6Ow8rUITrtjszA== dependencies: "@types/react" "*" From 662a85c16a60a0ac230b7beec211039ac903a690 Mon Sep 17 00:00:00 2001 From: Robin Date: Mon, 18 Sep 2023 11:46:16 -0400 Subject: [PATCH 8/9] Add a clarifying comment --- src/room/AppSelectionModal.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/room/AppSelectionModal.tsx b/src/room/AppSelectionModal.tsx index 7d5a1a47..feeb009d 100644 --- a/src/room/AppSelectionModal.tsx +++ b/src/room/AppSelectionModal.tsx @@ -50,7 +50,10 @@ export const AppSelectionModal: FC = ({ roomId }) => { ? window.location.href : getRoomUrl(roomId, roomSharedKey ?? undefined) ); - // Edit the URL so that it opens in embedded mode + // Edit the URL so that it opens in embedded mode. We do this for two + // reasons: It causes the mobile app to limit the user to only visiting the + // room in question, and it prevents this app selection prompt from being + // shown a second time. url.hash = editFragmentQuery(url.hash, (params) => { params.set("isEmbedded", ""); return params; From 1ecc8e3b22d50f3a3c86be74e450efac16d97014 Mon Sep 17 00:00:00 2001 From: Robin Date: Mon, 18 Sep 2023 11:56:24 -0400 Subject: [PATCH 9/9] Fix bad import --- src/Modal.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Modal.tsx b/src/Modal.tsx index ea8aff70..9fe68122 100644 --- a/src/Modal.tsx +++ b/src/Modal.tsx @@ -31,7 +31,7 @@ import { ReactComponent as CloseIcon } from "@vector-im/compound-design-tokens/i import classNames from "classnames"; import { Heading } from "@vector-im/compound-web"; -import styles from "./NewModal.module.css"; +import styles from "./Modal.module.css"; import { useMediaQuery } from "./useMediaQuery"; import { Glass } from "./Glass";