element-call/src/room/PTTCallView.jsx

165 lines
5.4 KiB
React
Raw Normal View History

2022-04-22 18:05:48 -07:00
import React from "react";
import { useModalTriggerState } from "../Modal";
import { SettingsModal } from "../settings/SettingsModal";
import { InviteModal } from "./InviteModal";
2022-04-28 17:44:50 -07:00
import { HangupButton, InviteButton, SettingsButton } from "../button";
2022-04-22 18:05:48 -07:00
import { Header, LeftNav, RightNav, RoomSetupHeaderInfo } from "../Header";
import styles from "./PTTCallView.module.css";
import { Facepile } from "../Facepile";
import { PTTButton } from "./PTTButton";
import { PTTFeed } from "./PTTFeed";
import { useMediaHandler } from "../settings/useMediaHandler";
2022-04-27 17:19:58 -07:00
import useMeasure from "react-use-measure";
import { ResizeObserver } from "@juggle/resize-observer";
2022-04-28 17:44:50 -07:00
import { usePTT } from "./usePTT";
import { Timer } from "./Timer";
import { Toggle } from "../input/Toggle";
import { getAvatarUrl } from "../matrix-utils";
import { ReactComponent as AudioIcon } from "../icons/Audio.svg";
2022-04-22 18:05:48 -07:00
export function PTTCallView({
client,
2022-04-28 17:44:50 -07:00
roomId,
2022-04-22 18:05:48 -07:00
roomName,
2022-04-28 17:44:50 -07:00
groupCall,
participants,
2022-04-22 18:05:48 -07:00
userMediaFeeds,
onLeave,
setShowInspector,
showInspector,
}) {
const { modalState: inviteModalState, modalProps: inviteModalProps } =
useModalTriggerState();
const { modalState: settingsModalState, modalProps: settingsModalProps } =
useModalTriggerState();
2022-04-27 17:19:58 -07:00
const [containerRef, bounds] = useMeasure({ polyfill: ResizeObserver });
const facepileSize = bounds.width < 800 ? "sm" : "md";
2022-04-28 17:44:50 -07:00
const pttButtonSize = 232;
const pttBorderWidth = 6;
const { audioOutput } = useMediaHandler();
const {
pttButtonHeld,
isAdmin,
talkOverEnabled,
setTalkOverEnabled,
activeSpeakerUserId,
startTalking,
stopTalking,
2022-04-28 17:44:50 -07:00
} = usePTT(client, groupCall, userMediaFeeds);
const activeSpeakerIsLocalUser =
activeSpeakerUserId && client.getUserId() === activeSpeakerUserId;
const showTalkOverError =
pttButtonHeld && !activeSpeakerIsLocalUser && !talkOverEnabled;
const activeSpeakerUser = activeSpeakerUserId
? client.getUser(activeSpeakerUserId)
: null;
const activeSpeakerAvatarUrl = activeSpeakerUser
? getAvatarUrl(
client,
activeSpeakerUser.avatarUrl,
pttButtonSize - pttBorderWidth * 2
)
: null;
const activeSpeakerDisplayName = activeSpeakerUser
? activeSpeakerUser.displayName
: "";
2022-04-22 18:05:48 -07:00
return (
2022-04-27 17:19:58 -07:00
<div className={styles.pttCallView} ref={containerRef}>
2022-04-22 18:05:48 -07:00
<Header className={styles.header}>
<LeftNav>
<RoomSetupHeaderInfo roomName={roomName} onPress={onLeave} />
</LeftNav>
2022-04-27 16:47:23 -07:00
<RightNav />
2022-04-22 18:05:48 -07:00
</Header>
<div className={styles.center}>
2022-04-27 16:47:23 -07:00
<div className={styles.participants}>
<p>{`${participants.length} ${
participants.length > 1 ? "people" : "person"
} connected`}</p>
<Facepile
2022-04-27 17:19:58 -07:00
size={facepileSize}
2022-04-27 16:47:23 -07:00
max={8}
className={styles.facepile}
client={client}
participants={participants}
/>
</div>
2022-04-27 17:19:58 -07:00
<div className={styles.footer}>
<SettingsButton onPress={() => settingsModalState.open()} />
<HangupButton onPress={onLeave} />
<InviteButton onPress={() => inviteModalState.open()} />
2022-04-27 16:47:23 -07:00
</div>
2022-04-27 17:19:58 -07:00
2022-04-27 16:47:23 -07:00
<div className={styles.pttButtonContainer}>
2022-04-28 17:44:50 -07:00
{activeSpeakerUserId ? (
<div className={styles.talkingInfo}>
<h2>
{!activeSpeakerIsLocalUser && (
<AudioIcon className={styles.speakerIcon} />
)}
{activeSpeakerIsLocalUser
? "Talking..."
: `${activeSpeakerDisplayName} is talking...`}
</h2>
<Timer value={activeSpeakerUserId} />
</div>
) : (
<div className={styles.talkingInfo} />
)}
2022-04-27 16:47:23 -07:00
<PTTButton
2022-04-28 17:44:50 -07:00
showTalkOverError={showTalkOverError}
activeSpeakerUserId={activeSpeakerUserId}
activeSpeakerDisplayName={activeSpeakerDisplayName}
activeSpeakerAvatarUrl={activeSpeakerAvatarUrl}
activeSpeakerIsLocalUser={activeSpeakerIsLocalUser}
size={pttButtonSize}
startTalking={startTalking}
stopTalking={stopTalking}
2022-04-22 18:05:48 -07:00
/>
2022-04-28 17:44:50 -07:00
<p className={styles.actionTip}>
{showTalkOverError
? "You can't talk at the same time"
: pttButtonHeld
? "Release spacebar key to stop"
: talkOverEnabled &&
activeSpeakerUserId &&
!activeSpeakerIsLocalUser
? `Press and hold spacebar to talk over ${activeSpeakerDisplayName}`
: "Press and hold spacebar to talk"}
</p>
2022-04-27 16:47:23 -07:00
{userMediaFeeds.map((callFeed) => (
<PTTFeed
key={callFeed.userId}
callFeed={callFeed}
audioOutputDevice={audioOutput}
/>
))}
2022-04-28 17:44:50 -07:00
{isAdmin && (
<Toggle
isSelected={talkOverEnabled}
onChange={setTalkOverEnabled}
label="Talk over speaker"
id="talkOverEnabled"
/>
)}
2022-04-27 16:47:23 -07:00
</div>
2022-04-22 18:05:48 -07:00
</div>
{settingsModalState.isOpen && (
<SettingsModal
{...settingsModalProps}
setShowInspector={setShowInspector}
showInspector={showInspector}
/>
)}
{inviteModalState.isOpen && (
<InviteModal roomId={roomId} {...inviteModalProps} />
)}
</div>
);
}