// @flow // We need to reference these files directly to avoid loading things that are not available // in this environment (e.g. JitsiMeetJS or interfaceConfig) import AbstractVideoMuteButton from '../base/toolbox/components/AbstractVideoMuteButton'; import type { Props } from '../base/toolbox/components/AbstractButton'; const { api } = window.alwaysOnTop; /** * The type of the React {@code Component} state of {@link VideoMuteButton}. */ type State = { /** * Whether video is available is not. */ videoAvailable: boolean, /** * Whether video is muted or not. */ videoMuted: boolean }; /** * Stateless "mute/unmute video" button for the Always-on-Top windows. */ export default class VideoMuteButton extends AbstractVideoMuteButton { accessibilityLabel = 'Video mute'; /** * Initializes a new {@code VideoMuteButton} instance. * * @param {Props} props - The React {@code Component} props to initialize * the new {@code VideoMuteButton} instance with. */ constructor(props: Props) { super(props); this.state = { videoAvailable: false, videoMuted: true }; // Bind event handlers so they are only bound once per instance. this._videoAvailabilityListener = this._videoAvailabilityListener.bind(this); this._videoMutedListener = this._videoMutedListener.bind(this); } /** * Sets mouse move listener and initial toolbar timeout. * * @inheritdoc * @returns {void} */ componentDidMount() { api.on('videoAvailabilityChanged', this._videoAvailabilityListener); api.on('videoMuteStatusChanged', this._videoMutedListener); Promise.all([ api.isVideoAvailable(), api.isVideoMuted() ]) .then(([ videoAvailable, videoMuted ]) => this.setState({ videoAvailable, videoMuted })) .catch(console.error); } /** * Removes all listeners. * * @inheritdoc * @returns {void} */ componentWillUnmount() { api.removeListener( 'videoAvailabilityChanged', this._videoAvailabilityListener); api.removeListener( 'videoMuteStatusChanged', this._videoMutedListener); } /** * Indicates whether this button is disabled or not. * * @override * @protected * @returns {boolean} */ _isDisabled() { return !this.state.videoAvailable; } /** * Indicates if video is currently muted ot nor. * * @override * @protected * @returns {boolean} */ _isVideoMuted() { return this.state.videoMuted; } /** * Changes the muted state. * * @override * @param {boolean} videoMuted - Whether video should be muted or not. * @protected * @returns {void} */ _setVideoMuted(videoMuted: boolean) { // eslint-disable-line no-unused-vars this.state.videoAvailable && api.executeCommand('toggleVideo'); } _videoAvailabilityListener: ({ available: boolean }) => void; /** * Handles video 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 }); } }