Inform user that their camera is starting in Lobby (#2869)

* Inform user that their camera is starting

Instead of just showing a grey box.

* Review feedback

* Show spinner from design suggestion

* useMemo

* Lint

* Lint

* Feedback from review

* Use colour that actually exists

* Refactor into Avatar superclass

* .

* Remove size limit behaviour

* Add VideoPreview tests
This commit is contained in:
Hugh Nimmo-Smith
2024-12-18 15:31:45 +00:00
committed by GitHub
parent 19d0f84f02
commit ba5da7e9af
8 changed files with 189 additions and 12 deletions

View File

@@ -5,12 +5,13 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details.
*/
import { useEffect, useRef, type FC, type ReactNode } from "react";
import { useEffect, useMemo, useRef, type FC, type ReactNode } from "react";
import useMeasure from "react-use-measure";
import { facingModeFromLocalTrack, type LocalVideoTrack } from "livekit-client";
import classNames from "classnames";
import { useTranslation } from "react-i18next";
import { Avatar } from "../Avatar";
import { TileAvatar } from "../tile/TileAvatar";
import styles from "./VideoPreview.module.css";
import { type MuteStates } from "./MuteStates";
import { type EncryptionSystem } from "../e2ee/sharedKeyManagement";
@@ -39,6 +40,7 @@ export const VideoPreview: FC<Props> = ({
videoTrack,
children,
}) => {
const { t } = useTranslation();
const [previewRef, previewBounds] = useMeasure();
const videoEl = useRef<HTMLVideoElement | null>(null);
@@ -53,6 +55,11 @@ export const VideoPreview: FC<Props> = ({
};
}, [videoTrack]);
const cameraIsStarting = useMemo(
() => muteStates.video.enabled && !videoTrack,
[muteStates.video.enabled, videoTrack],
);
return (
<div className={classNames(styles.preview)} ref={previewRef}>
<video
@@ -69,15 +76,23 @@ export const VideoPreview: FC<Props> = ({
tabIndex={-1}
disablePictureInPicture
/>
{!muteStates.video.enabled && (
<div className={styles.avatarContainer}>
<Avatar
id={matrixInfo.userId}
name={matrixInfo.displayName}
size={Math.min(previewBounds.width, previewBounds.height) / 2}
src={matrixInfo.avatarUrl}
/>
</div>
{(!muteStates.video.enabled || cameraIsStarting) && (
<>
<div className={styles.avatarContainer}>
{cameraIsStarting && (
<div className={styles.cameraStarting} role="status">
{t("video_tile.camera_starting")}
</div>
)}
<TileAvatar
id={matrixInfo.userId}
name={matrixInfo.displayName}
size={Math.min(previewBounds.width, previewBounds.height) / 2}
src={matrixInfo.avatarUrl}
loading={cameraIsStarting}
/>
</div>
</>
)}
<div className={styles.buttonBar}>{children}</div>
</div>