| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450 | 
							- // @flow
 - 
 - import React, { Component } from 'react';
 - 
 - import StatelessToolbar from '../toolbox/components/StatelessToolbar';
 - import StatelessToolbarButton
 -     from '../toolbox/components/StatelessToolbarButton';
 - 
 - const { api } = window.alwaysOnTop;
 - 
 - /**
 -  * Map with toolbar button descriptors.
 -  */
 - const TOOLBAR_BUTTONS = {
 -     /**
 -      * The descriptor of the camera toolbar button.
 -      */
 -     camera: {
 -         classNames: [ 'button', 'icon-camera' ],
 -         enabled: true,
 -         id: 'toolbar_button_camera',
 -         onClick() {
 -             api.executeCommand('toggleVideo');
 -         }
 -     },
 - 
 -     /**
 -      * The descriptor of the toolbar button which hangs up the call/conference.
 -      */
 -     hangup: {
 -         classNames: [ 'button', 'icon-hangup', 'button_hangup' ],
 -         enabled: true,
 -         id: 'toolbar_button_hangup',
 -         onClick() {
 -             api.executeCommand('hangup');
 -             window.close();
 -         }
 -     },
 - 
 -     /**
 -      * The descriptor of the microphone toolbar button.
 -      */
 -     microphone: {
 -         classNames: [ 'button', 'icon-microphone' ],
 -         enabled: true,
 -         id: 'toolbar_button_mute',
 -         onClick() {
 -             api.executeCommand('toggleAudio');
 -         }
 -     }
 - };
 - 
 - /**
 -  * The timeout in ms for hidding the toolbar.
 -  */
 - const TOOLBAR_TIMEOUT = 4000;
 - 
 - /**
 -  * The type of the React {@code Component} state of {@link FeedbackButton}.
 -  */
 - type State = {
 -     audioAvailable: boolean,
 -     audioMuted: boolean,
 -     avatarURL: string,
 -     displayName: string,
 -     isVideoDisplayed: boolean,
 -     videoAvailable: boolean,
 -     videoMuted: boolean,
 -     visible: boolean
 - };
 - 
 - /**
 -  * Represents the always on top page.
 -  *
 -  * @class AlwaysOnTop
 -  * @extends Component
 -  */
 - export default class AlwaysOnTop extends Component<*, State> {
 -     _hovered: boolean;
 - 
 -     /**
 -      * Initializes new AlwaysOnTop instance.
 -      *
 -      * @param {*} props - The read-only properties with which the new instance
 -      * is to be initialized.
 -      */
 -     constructor(props: *) {
 -         super(props);
 - 
 -         this.state = {
 -             visible: true,
 -             audioMuted: false,
 -             videoMuted: false,
 -             audioAvailable: false,
 -             videoAvailable: false,
 -             displayName: '',
 -             isVideoDisplayed: true,
 -             avatarURL: ''
 -         };
 - 
 -         // Bind event handlers so they are only bound once per instance.
 -         this._audioAvailabilityListener
 -             = this._audioAvailabilityListener.bind(this);
 -         this._audioMutedListener = this._audioMutedListener.bind(this);
 -         this._avatarChangedListener = this._avatarChangedListener.bind(this);
 -         this._largeVideoChangedListener
 -             = this._largeVideoChangedListener.bind(this);
 -         this._displayNameChangedListener
 -             = this._displayNameChangedListener.bind(this);
 -         this._mouseMove = this._mouseMove.bind(this);
 -         this._onMouseOut = this._onMouseOut.bind(this);
 -         this._onMouseOver = this._onMouseOver.bind(this);
 -         this._videoAvailabilityListener
 -             = this._videoAvailabilityListener.bind(this);
 -         this._videoMutedListener = this._videoMutedListener.bind(this);
 -     }
 - 
 -     _audioAvailabilityListener: ({ available: boolean }) => void;
 - 
 -     /**
 -      * Handles audio available api events.
 -      *
 -      * @param {{ available: boolean }} status - The new available status.
 -      * @returns {void}
 -      */
 -     _audioAvailabilityListener({ available }) {
 -         this.setState({ audioAvailable: available });
 -     }
 - 
 -     _audioMutedListener: ({ muted: boolean }) => void;
 - 
 -     /**
 -      * Handles audio muted api events.
 -      *
 -      * @param {{ muted: boolean }} status - The new muted status.
 -      * @returns {void}
 -      */
 -     _audioMutedListener({ muted }) {
 -         this.setState({ audioMuted: muted });
 -     }
 - 
 -     _avatarChangedListener: () => void;
 - 
 -     /**
 -      * Handles avatar changed api events.
 -      *
 -      * @returns {void}
 -      */
 -     _avatarChangedListener({ avatarURL, id }) {
 -         if (api._getOnStageParticipant() !== id) {
 -             return;
 -         }
 - 
 -         if (avatarURL !== this.state.avatarURL) {
 -             this.setState({ avatarURL });
 -         }
 -     }
 - 
 -     _displayNameChangedListener: () => void;
 - 
 -     /**
 -      * Handles display name changed api events.
 -      *
 -      * @returns {void}
 -      */
 -     _displayNameChangedListener({ formattedDisplayName, id }) {
 -         if (api._getOnStageParticipant() !== id) {
 -             return;
 -         }
 - 
 -         if (formattedDisplayName !== this.state.displayName) {
 -             this.setState({ displayName: formattedDisplayName });
 -         }
 -     }
 - 
 -     /**
 -      * Hides the toolbar after a timeout.
 -      *
 -      * @returns {void}
 -      */
 -     _hideToolbarAfterTimeout() {
 -         setTimeout(() => {
 -             if (this._hovered) {
 -                 this._hideToolbarAfterTimeout();
 - 
 -                 return;
 -             }
 -             this.setState({ visible: false });
 -         }, TOOLBAR_TIMEOUT);
 -     }
 - 
 -     _largeVideoChangedListener: () => void;
 - 
 -     /**
 -      * Handles large video changed api events.
 -      *
 -      * @returns {void}
 -      */
 -     _largeVideoChangedListener() {
 -         const userID = api._getOnStageParticipant();
 -         const displayName = api._getFormattedDisplayName(userID);
 -         const avatarURL = api.getAvatarURL(userID);
 -         const isVideoDisplayed = Boolean(api._getLargeVideo());
 - 
 -         this.setState({
 -             avatarURL,
 -             displayName,
 -             isVideoDisplayed
 -         });
 -     }
 - 
 -     _mouseMove: () => void;
 - 
 -     /**
 -      * Handles mouse move events.
 -      *
 -      * @returns {void}
 -      */
 -     _mouseMove() {
 -         if (!this.state.visible) {
 -             this.setState({ visible: true });
 -         }
 -     }
 - 
 -     _onMouseOut: () => void;
 - 
 -     /**
 -      * Toolbar mouse out handler.
 -      *
 -      * @returns {void}
 -      */
 -     _onMouseOut() {
 -         this._hovered = false;
 -     }
 - 
 -     _onMouseOver: () => void;
 - 
 -     /**
 -      * Toolbar mouse over handler.
 -      *
 -      * @returns {void}
 -      */
 -     _onMouseOver() {
 -         this._hovered = true;
 -     }
 - 
 -     _videoAvailabilityListener: ({ available: boolean }) => void;
 - 
 -     /**
 -      * Renders display name and avatar for the on stage participant.
 -      *
 -      * @returns {ReactElement}
 -      */
 -     _renderVideoNotAvailableScreen() {
 -         const { avatarURL, displayName, isVideoDisplayed } = this.state;
 - 
 -         if (isVideoDisplayed) {
 -             return null;
 -         }
 - 
 -         return (
 -             <div id = 'videoNotAvailableScreen'>
 -                 {
 -                     avatarURL
 -                         ? <div id = 'avatarContainer'>
 -                             <img
 -                                 id = 'avatar'
 -                                 src = { avatarURL } />
 -                         </div>
 -                         : null
 -                 }
 -                 <div
 -                     className = 'displayname'
 -                     id = 'displayname'>
 -                     { displayName }
 -                 </div>
 -             </div>
 -         );
 -     }
 - 
 -     /**
 -      * Handles audio available api events.
 -      *
 -      * @param {{ available: boolean }} status - The new available status.
 -      * @returns {void}
 -      */
 -     _videoAvailabilityListener({ available }) {
 -         this.setState({ videoAvailable: available });
 -     }
 - 
 -     _videoMutedListener: ({ muted: boolean }) => void;
 - 
 -     /**
 -      * Handles video muted api events.
 -      *
 -      * @param {{ muted: boolean }} status - The new muted status.
 -      * @returns {void}
 -      */
 -     _videoMutedListener({ muted }) {
 -         this.setState({ videoMuted: muted });
 -     }
 - 
 -     /**
 -      * Sets mouse move listener and initial toolbar timeout.
 -      *
 -      * @inheritdoc
 -      * @returns {void}
 -      */
 -     componentDidMount() {
 -         api.on('audioMuteStatusChanged', this._audioMutedListener);
 -         api.on('videoMuteStatusChanged', this._videoMutedListener);
 -         api.on('audioAvailabilityChanged', this._audioAvailabilityListener);
 -         api.on('videoAvailabilityChanged', this._videoAvailabilityListener);
 -         api.on('largeVideoChanged', this._largeVideoChangedListener);
 -         api.on('displayNameChange', this._displayNameChangedListener);
 -         api.on('avatarChanged', this._avatarChangedListener);
 - 
 -         this._largeVideoChangedListener();
 - 
 -         Promise.all([
 -             api.isAudioMuted(),
 -             api.isVideoMuted(),
 -             api.isAudioAvailable(),
 -             api.isVideoAvailable()
 -         ])
 -         .then(([
 -             audioMuted = false,
 -             videoMuted = false,
 -             audioAvailable = false,
 -             videoAvailable = false
 -         ]) =>
 -             this.setState({
 -                 audioMuted,
 -                 videoMuted,
 -                 audioAvailable,
 -                 videoAvailable
 -             })
 -         )
 -         .catch(console.error);
 - 
 -         window.addEventListener('mousemove', this._mouseMove);
 - 
 -         this._hideToolbarAfterTimeout();
 -     }
 - 
 -     /**
 -      * Removes all listeners.
 -      *
 -      * @inheritdoc
 -      * @returns {void}
 -      */
 -     componentWillUnmount() {
 -         api.removeListener('audioMuteStatusChanged',
 -             this._audioMutedListener);
 -         api.removeListener('videoMuteStatusChanged',
 -             this._videoMutedListener);
 -         api.removeListener('audioAvailabilityChanged',
 -             this._audioAvailabilityListener);
 -         api.removeListener('videoAvailabilityChanged',
 -             this._videoAvailabilityListener);
 -         api.removeListener('largeVideoChanged',
 -             this._largeVideoChangedListener);
 -         api.removeListener('displayNameChange',
 -             this._displayNameChangedListener);
 -         api.removeListener('avatarChanged', this._avatarChangedListener);
 -         window.removeEventListener('mousemove', this._mouseMove);
 -     }
 - 
 -     /**
 -      * Sets a timeout to hide the toolbar when the toolbar is shown.
 -      *
 -      * @inheritdoc
 -      * @returns {void}
 -      */
 -     componentWillUpdate(nextProps: *, nextState: State) {
 -         if (!this.state.visible && nextState.visible) {
 -             this._hideToolbarAfterTimeout();
 -         }
 -     }
 - 
 -     /**
 -      * Implements React's {@link Component#render()}.
 -      *
 -      * @inheritdoc
 -      * @returns {ReactElement}
 -      */
 -     render() {
 -         const className
 -             = `toolbar_primary always-on-top ${
 -                 this.state.visible ? 'fadeIn' : 'fadeOut'}`;
 - 
 -         return (
 -             <div id = 'alwaysOnTop'>
 -                 <StatelessToolbar
 -                     className = { className }
 -                     onMouseOut = { this._onMouseOut }
 -                     onMouseOver = { this._onMouseOver }>
 -                     {
 -                         Object.entries(TOOLBAR_BUTTONS).map(
 -                             ([ key, button ]) => {
 -                                 // XXX The following silences a couple of flow
 -                                 // errors:
 -                                 if (button === null
 -                                         || typeof button !== 'object') {
 -                                     return null;
 -                                 }
 - 
 -                                 const { onClick } = button;
 -                                 let enabled = false;
 -                                 let toggled = false;
 - 
 -                                 switch (key) {
 -                                 case 'microphone':
 -                                     enabled = this.state.audioAvailable;
 -                                     toggled = enabled
 -                                         ? this.state.audioMuted : true;
 -                                     break;
 -                                 case 'camera':
 -                                     enabled = this.state.videoAvailable;
 -                                     toggled = enabled
 -                                         ? this.state.videoMuted : true;
 -                                     break;
 -                                 default: // hangup button
 -                                     toggled = false;
 -                                     enabled = true;
 -                                 }
 - 
 -                                 const updatedButton = {
 -                                     ...button,
 -                                     enabled,
 -                                     toggled
 -                                 };
 - 
 -                                 return (
 -                                     <StatelessToolbarButton
 -                                         button = { updatedButton }
 -                                         key = { key }
 -                                         onClick = { onClick } />
 -                                 );
 -                             }
 -                         )
 -                     }
 -                 </StatelessToolbar>
 -                 {
 -                     this._renderVideoNotAvailableScreen()
 -                 }
 -             </div>
 -         );
 -     }
 - }
 
 
  |