2022-05-04 17:09:48 +01:00
|
|
|
/*
|
|
|
|
Copyright 2022 Matrix.org Foundation C.I.C.
|
|
|
|
|
|
|
|
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.
|
|
|
|
*/
|
|
|
|
|
2022-05-31 10:43:05 -04:00
|
|
|
import React, { forwardRef } from "react";
|
2022-04-07 14:22:36 -07:00
|
|
|
import { animated } from "@react-spring/web";
|
|
|
|
import classNames from "classnames";
|
2022-10-10 09:19:10 -04:00
|
|
|
import { useTranslation } from "react-i18next";
|
2022-08-12 19:27:34 +02:00
|
|
|
|
2022-04-07 14:22:36 -07:00
|
|
|
import styles from "./VideoTile.module.css";
|
|
|
|
import { ReactComponent as MicMutedIcon } from "../icons/MicMuted.svg";
|
|
|
|
import { ReactComponent as VideoMutedIcon } from "../icons/VideoMuted.svg";
|
2022-08-07 19:09:45 +02:00
|
|
|
import { AudioButton, FullscreenButton } from "../button/Button";
|
2022-04-07 14:22:36 -07:00
|
|
|
|
2022-08-12 19:27:34 +02:00
|
|
|
interface Props {
|
|
|
|
name: string;
|
2022-10-21 17:24:56 +01:00
|
|
|
hasFeed: Boolean;
|
2022-08-12 19:27:34 +02:00
|
|
|
speaking?: boolean;
|
|
|
|
audioMuted?: boolean;
|
|
|
|
videoMuted?: boolean;
|
|
|
|
screenshare?: boolean;
|
|
|
|
avatar?: JSX.Element;
|
|
|
|
mediaRef?: React.RefObject<MediaElement>;
|
|
|
|
onOptionsPress?: () => void;
|
|
|
|
localVolume?: number;
|
2022-09-16 10:21:41 -04:00
|
|
|
maximised?: boolean;
|
2022-09-14 19:05:05 -04:00
|
|
|
fullscreen?: boolean;
|
2022-08-12 19:27:34 +02:00
|
|
|
onFullscreen?: () => void;
|
|
|
|
className?: string;
|
|
|
|
showOptions?: boolean;
|
|
|
|
isLocal?: boolean;
|
|
|
|
disableSpeakingIndicator?: boolean;
|
|
|
|
}
|
|
|
|
|
|
|
|
export const VideoTile = forwardRef<HTMLDivElement, Props>(
|
2022-05-31 10:43:05 -04:00
|
|
|
(
|
|
|
|
{
|
2022-08-12 19:27:34 +02:00
|
|
|
name,
|
2022-10-21 17:24:56 +01:00
|
|
|
hasFeed,
|
2022-05-31 10:43:05 -04:00
|
|
|
speaking,
|
|
|
|
audioMuted,
|
|
|
|
videoMuted,
|
|
|
|
screenshare,
|
|
|
|
avatar,
|
|
|
|
mediaRef,
|
2022-07-15 11:18:56 +02:00
|
|
|
onOptionsPress,
|
2022-08-02 14:30:12 +02:00
|
|
|
localVolume,
|
2022-09-14 19:05:05 -04:00
|
|
|
maximised,
|
|
|
|
fullscreen,
|
2022-08-07 19:09:45 +02:00
|
|
|
onFullscreen,
|
2022-08-12 19:27:34 +02:00
|
|
|
className,
|
|
|
|
showOptions,
|
|
|
|
isLocal,
|
|
|
|
// TODO: disableSpeakingIndicator is not used atm.
|
|
|
|
disableSpeakingIndicator,
|
2022-05-31 10:43:05 -04:00
|
|
|
...rest
|
|
|
|
},
|
|
|
|
ref
|
|
|
|
) => {
|
2022-10-10 09:19:10 -04:00
|
|
|
const { t } = useTranslation();
|
|
|
|
|
2022-09-22 17:35:23 -04:00
|
|
|
const toolbarButtons: JSX.Element[] = [];
|
2022-11-02 12:34:31 -04:00
|
|
|
if (hasFeed && !isLocal) {
|
2022-09-22 17:35:23 -04:00
|
|
|
toolbarButtons.push(
|
|
|
|
<AudioButton
|
2022-11-02 12:15:32 -04:00
|
|
|
key="localVolume"
|
2022-09-22 17:35:23 -04:00
|
|
|
className={styles.button}
|
|
|
|
volume={localVolume}
|
|
|
|
onPress={onOptionsPress}
|
|
|
|
/>
|
|
|
|
);
|
|
|
|
|
|
|
|
if (screenshare) {
|
|
|
|
toolbarButtons.push(
|
|
|
|
<FullscreenButton
|
2022-11-02 12:15:32 -04:00
|
|
|
key="fullscreen"
|
2022-09-22 17:35:23 -04:00
|
|
|
className={styles.button}
|
|
|
|
fullscreen={fullscreen}
|
|
|
|
onPress={onFullscreen}
|
|
|
|
/>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-21 17:24:56 +01:00
|
|
|
const caption = hasFeed ? name : t("{{name}} (Connecting...)", { name });
|
|
|
|
|
2022-05-31 10:43:05 -04:00
|
|
|
return (
|
|
|
|
<animated.div
|
|
|
|
className={classNames(styles.videoTile, className, {
|
|
|
|
[styles.isLocal]: isLocal,
|
|
|
|
[styles.speaking]: speaking,
|
|
|
|
[styles.muted]: audioMuted,
|
|
|
|
[styles.screenshare]: screenshare,
|
2022-09-14 19:05:05 -04:00
|
|
|
[styles.maximised]: maximised,
|
2022-05-31 10:43:05 -04:00
|
|
|
})}
|
|
|
|
ref={ref}
|
|
|
|
{...rest}
|
|
|
|
>
|
2022-09-23 00:29:29 -04:00
|
|
|
{toolbarButtons.length > 0 && !maximised && (
|
2022-09-22 17:35:23 -04:00
|
|
|
<div className={classNames(styles.toolbar)}>{toolbarButtons}</div>
|
2022-08-02 16:05:36 +02:00
|
|
|
)}
|
2022-08-12 10:33:59 +02:00
|
|
|
{videoMuted && (
|
2022-05-31 10:43:05 -04:00
|
|
|
<>
|
|
|
|
<div className={styles.videoMutedOverlay} />
|
|
|
|
{avatar}
|
|
|
|
</>
|
|
|
|
)}
|
2022-09-14 19:05:05 -04:00
|
|
|
{!maximised &&
|
|
|
|
(screenshare ? (
|
|
|
|
<div className={styles.presenterLabel}>
|
2022-10-10 09:19:10 -04:00
|
|
|
<span>{t("{{name}} is presenting", { name })}</span>
|
2022-09-14 19:05:05 -04:00
|
|
|
</div>
|
|
|
|
) : (
|
|
|
|
<div className={classNames(styles.infoBubble, styles.memberName)}>
|
|
|
|
{audioMuted && !videoMuted && <MicMutedIcon />}
|
|
|
|
{videoMuted && <VideoMutedIcon />}
|
2022-10-21 17:24:56 +01:00
|
|
|
<span title={caption}>{caption}</span>
|
2022-09-14 19:05:05 -04:00
|
|
|
</div>
|
|
|
|
))}
|
2022-05-31 10:43:05 -04:00
|
|
|
<video ref={mediaRef} playsInline disablePictureInPicture />
|
|
|
|
</animated.div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
);
|