// Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 import classNames from 'classnames/bind'; import React, { useContext, useEffect, useState } from 'react'; import { FormattedMessage, useIntl } from 'react-intl'; import { useHistory } from 'react-router-dom'; import ChimeSdkWrapper from '../chime/ChimeSdkWrapper'; import routes from '../constants/routes.json'; import getChimeContext from '../context/getChimeContext'; import getUIStateContext from '../context/getUIStateContext'; import ClassMode from '../enums/ClassMode'; import ViewMode from '../enums/ViewMode'; import styles from './Controls.css'; import Tooltip from './Tooltip'; import MessageTopic from '../enums/MessageTopic'; const cx = classNames.bind(styles); enum VideoStatus { Disabled, Loading, Enabled } type Props = { viewMode: ViewMode; onClickShareButton: () => void; }; export default function Controls(props: Props) { const { viewMode, onClickShareButton } = props; const chime: ChimeSdkWrapper | null = useContext(getChimeContext()); const [state] = useContext(getUIStateContext()); const history = useHistory(); const [muted, setMuted] = useState(false); const [focus, setFocus] = useState(false); const [videoStatus, setVideoStatus] = useState(VideoStatus.Disabled); const intl = useIntl(); useEffect(() => { const callback = (localMuted: boolean) => { setMuted(localMuted); }; chime?.audioVideo?.realtimeSubscribeToMuteAndUnmuteLocalAudio(callback); return () => { if (chime && chime?.audioVideo) { chime?.audioVideo?.realtimeUnsubscribeToMuteAndUnmuteLocalAudio( callback ); } }; }, []); return ( <div className={cx('controls', { roomMode: viewMode === ViewMode.Room, screenShareMode: viewMode === ViewMode.ScreenShare, videoEnabled: videoStatus === VideoStatus.Enabled, audioMuted: muted })} > <div className={cx('micMuted')}> <FormattedMessage id="Controls.micMutedInScreenViewMode" /> </div> {state.classMode === ClassMode.Teacher && viewMode === ViewMode.Room && ( <Tooltip tooltip={ focus ? intl.formatMessage({ id: 'Controls.turnOffFocusTooltip' }) : intl.formatMessage({ id: 'Controls.turnOnFocusTooltip' }) } > <button type="button" className={cx('focusButton', { enabled: focus })} onClick={() => { const newFocusState = !focus; chime?.sendMessage(MessageTopic.Focus, { focus: newFocusState }); chime?.sendMessage( MessageTopic.Chat, newFocusState ? intl.formatMessage({ id: 'Controls.focusOnMessage' }) : intl.formatMessage({ id: 'Controls.focusOffMessage' }) ); setFocus(newFocusState); }} > {focus ? ( <i className="fas fa-street-view" /> ) : ( <i className="fas fa-street-view" /> )} </button> </Tooltip> )} <Tooltip tooltip={ muted ? intl.formatMessage({ id: 'Controls.unmuteTooltip' }) : intl.formatMessage({ id: 'Controls.muteTooltip' }) } > <button type="button" className={cx('muteButton', { enabled: !muted })} onClick={async () => { if (muted) { chime?.audioVideo?.realtimeUnmuteLocalAudio(); } else { chime?.audioVideo?.realtimeMuteLocalAudio(); } // Adds a slight delay to close the tooltip before rendering the updated text in it await new Promise(resolve => setTimeout(resolve, 10)); }} > {muted ? ( <i className="fas fa-microphone-slash" /> ) : ( <i className="fas fa-microphone" /> )} </button> </Tooltip> <Tooltip tooltip={ videoStatus === VideoStatus.Disabled ? intl.formatMessage({ id: 'Controls.turnOnVideoTooltip' }) : intl.formatMessage({ id: 'Controls.turnOffVideoTooltip' }) } > <button type="button" className={cx('videoButton', { enabled: videoStatus === VideoStatus.Enabled })} onClick={async () => { // Adds a slight delay to close the tooltip before rendering the updated text in it await new Promise(resolve => setTimeout(resolve, 10)); if (videoStatus === VideoStatus.Disabled) { setVideoStatus(VideoStatus.Loading); try { if (!chime?.currentVideoInputDevice) { throw new Error('currentVideoInputDevice does not exist'); } await chime?.chooseVideoInputDevice( chime?.currentVideoInputDevice ); chime?.audioVideo?.startLocalVideoTile(); setVideoStatus(VideoStatus.Enabled); } catch (error) { // eslint-disable-next-line console.error(error); setVideoStatus(VideoStatus.Disabled); } } else if (videoStatus === VideoStatus.Enabled) { setVideoStatus(VideoStatus.Loading); chime?.audioVideo?.stopLocalVideoTile(); setVideoStatus(VideoStatus.Disabled); } }} > {videoStatus === VideoStatus.Enabled ? ( <i className="fas fa-video" /> ) : ( <i className="fas fa-video-slash" /> )} </button> </Tooltip> {state.classMode === ClassMode.Teacher && viewMode !== ViewMode.ScreenShare && ( <Tooltip tooltip={intl.formatMessage({ id: 'Controls.shareScreenTooltip' })} > <button type="button" className={cx('shareButton')} onClick={() => { onClickShareButton(); }} > <i className="fas fa-desktop" /> </button> </Tooltip> )} {viewMode !== ViewMode.ScreenShare && ( <Tooltip tooltip={ state.classMode === ClassMode.Teacher ? intl.formatMessage({ id: 'Controls.endClassroomTooltip' }) : intl.formatMessage({ id: 'Controls.leaveClassroomTooltip' }) } > <button type="button" className={cx('endButton')} onClick={() => { chime?.leaveRoom(state.classMode === ClassMode.Teacher); history.push(routes.HOME); }} > <i className="fas fa-times" /> </button> </Tooltip> )} </div> ); }