mirror of https://github.com/jitsi/jitsi-meet
Use the new abstractions, which already take care of the rendering part.pull/2860/head
parent
b634f6b200
commit
01cb4ac7c8
@ -0,0 +1,145 @@ |
||||
// @flow
|
||||
|
||||
// XXX: AlwaysOnTop imports the button directly in order to avoid bringing in
|
||||
// other components that use lib-jitsi-meet, which always on top does not
|
||||
// import.
|
||||
import AbstractAudioMuteButton |
||||
from '../toolbox/components/buttons/AbstractAudioMuteButton'; |
||||
import type { Props } from '../toolbox/components/buttons/AbstractButton'; |
||||
|
||||
const { api } = window.alwaysOnTop; |
||||
|
||||
type State = { |
||||
|
||||
/** |
||||
* Whether audio is available is not. |
||||
*/ |
||||
audioAvailable: boolean, |
||||
|
||||
/** |
||||
* Whether audio is muted or not. |
||||
*/ |
||||
audioMuted: boolean |
||||
}; |
||||
|
||||
/** |
||||
* Stateless hangup button for the Always-on-Top windows. |
||||
*/ |
||||
export default class AudioMuteButton |
||||
extends AbstractAudioMuteButton<Props, State> { |
||||
|
||||
/** |
||||
* Initializes a new {@code AudioMuteButton} instance. |
||||
* |
||||
* @param {Props} props - The React {@code Component} props to initialize |
||||
* the new {@code AudioMuteButton} instance with. |
||||
*/ |
||||
constructor(props: Props) { |
||||
super(props); |
||||
|
||||
this.state = { |
||||
audioAvailable: false, |
||||
audioMuted: true |
||||
}; |
||||
|
||||
// Bind event handlers so they are only bound once per instance.
|
||||
this._audioAvailabilityListener |
||||
= this._audioAvailabilityListener.bind(this); |
||||
this._audioMutedListener = this._audioMutedListener.bind(this); |
||||
} |
||||
|
||||
/** |
||||
* Sets mouse move listener and initial toolbar timeout. |
||||
* |
||||
* @inheritdoc |
||||
* @returns {void} |
||||
*/ |
||||
componentDidMount() { |
||||
api.on('audioAvailabilityChanged', this._audioAvailabilityListener); |
||||
api.on('audioMuteStatusChanged', this._audioMutedListener); |
||||
|
||||
Promise.all([ |
||||
api.isAudioAvailable(), |
||||
api.isAudioMuted() |
||||
]) |
||||
.then(values => { |
||||
const [ audioAvailable, audioMuted ] = values; |
||||
|
||||
this.setState({ |
||||
audioAvailable, |
||||
audioMuted |
||||
}); |
||||
}) |
||||
.catch(console.error); |
||||
} |
||||
|
||||
/** |
||||
* Removes all listeners. |
||||
* |
||||
* @inheritdoc |
||||
* @returns {void} |
||||
*/ |
||||
componentWillUnmount() { |
||||
api.removeListener('audioAvailabilityChanged', |
||||
this._audioAvailabilityListener); |
||||
api.removeListener('audioMuteStatusChanged', |
||||
this._audioMutedListener); |
||||
} |
||||
|
||||
/** |
||||
* Indicates whether this button is disabled or not. |
||||
* |
||||
* @override |
||||
* @private |
||||
* @returns {boolean} |
||||
*/ |
||||
_isDisabled() { |
||||
return !this.state.audioAvailable; |
||||
} |
||||
|
||||
/** |
||||
* Indicates if audio is currently muted ot nor. |
||||
* |
||||
* @override |
||||
* @private |
||||
* @returns {boolean} |
||||
*/ |
||||
_isAudioMuted() { |
||||
return this.state.audioMuted; |
||||
} |
||||
|
||||
/** |
||||
* Changes the muted state. |
||||
* |
||||
* @param {boolean} audioMuted - Whether audio should be muted or not. |
||||
* @private |
||||
* @returns {void} |
||||
*/ |
||||
_setAudioMuted(audioMuted: boolean) { // eslint-disable-line no-unused-vars
|
||||
this.state.audioAvailable && api.executeCommand('toggleAudio'); |
||||
} |
||||
|
||||
_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 }); |
||||
} |
||||
} |
||||
@ -0,0 +1,38 @@ |
||||
// @flow
|
||||
|
||||
// XXX: AlwaysOnTop imports the button directly in order to avoid bringing in
|
||||
// other components that use lib-jitsi-meet, which always on top does not
|
||||
// import.
|
||||
import AbstractHangupButton |
||||
from '../toolbox/components/buttons/AbstractHangupButton'; |
||||
import type { Props } from '../toolbox/components/buttons/AbstractButton'; |
||||
|
||||
const { api } = window.alwaysOnTop; |
||||
|
||||
/** |
||||
* Stateless hangup button for the Always-on-Top windows. |
||||
*/ |
||||
export default class HangupButton extends AbstractHangupButton<Props, *> { |
||||
/** |
||||
* Helper function to perform the actual hangup action. |
||||
* |
||||
* @override |
||||
* @private |
||||
* @returns {void} |
||||
*/ |
||||
_doHangup() { |
||||
api.executeCommand('hangup'); |
||||
window.close(); |
||||
} |
||||
|
||||
/** |
||||
* Indicates whether this button is disabled or not. |
||||
* |
||||
* @override |
||||
* @private |
||||
* @returns {boolean} |
||||
*/ |
||||
_isDisabled() { |
||||
return false; |
||||
} |
||||
} |
||||
@ -0,0 +1,60 @@ |
||||
// @flow
|
||||
|
||||
import React, { Component } from 'react'; |
||||
|
||||
import AudioMuteButton from './AudioMuteButton'; |
||||
import HangupButton from './HangupButton'; |
||||
import VideoMuteButton from './VideoMuteButton'; |
||||
|
||||
/** |
||||
* The type of the React {@code Component} props of {@link Toolbar}. |
||||
*/ |
||||
type Props = { |
||||
|
||||
/** |
||||
* Additional CSS class names to add to the root of the toolbar. |
||||
*/ |
||||
className: string, |
||||
|
||||
/** |
||||
* Callback invoked when no longer moused over the toolbar. |
||||
*/ |
||||
onMouseOut: Function, |
||||
|
||||
/** |
||||
* Callback invoked when the mouse has moved over the toolbar. |
||||
*/ |
||||
onMouseOver: Function |
||||
}; |
||||
|
||||
/** |
||||
* Represents the toolbar in the Always On Top window. |
||||
* |
||||
* @extends Component |
||||
*/ |
||||
export default class Toolbar extends Component<Props> { |
||||
/** |
||||
* Implements React's {@link Component#render()}. |
||||
* |
||||
* @inheritdoc |
||||
* @returns {ReactElement} |
||||
*/ |
||||
render() { |
||||
const { |
||||
className = '', |
||||
onMouseOut, |
||||
onMouseOver |
||||
} = this.props; |
||||
|
||||
return ( |
||||
<div |
||||
className = { `always-on-top-toolbox ${className}` } |
||||
onMouseOut = { onMouseOut } |
||||
onMouseOver = { onMouseOver }> |
||||
<AudioMuteButton /> |
||||
<HangupButton /> |
||||
<VideoMuteButton /> |
||||
</div> |
||||
); |
||||
} |
||||
} |
||||
@ -1,159 +0,0 @@ |
||||
// @flow
|
||||
|
||||
import React, { Component } from 'react'; |
||||
|
||||
// FIXME: AlwaysOnTop imports the button directly in order to avoid bringing in
|
||||
// other components that use lib-jitsi-meet, which always on top does not
|
||||
// import.
|
||||
import ToolbarButton from '../toolbox/components/ToolbarButton'; |
||||
|
||||
const { api } = window.alwaysOnTop; |
||||
|
||||
/** |
||||
* The type of the React {@code Component} props of {@link ToolboxAlwaysOnTop}. |
||||
*/ |
||||
type Props = { |
||||
|
||||
/** |
||||
* Whether or not microphone access is available. |
||||
*/ |
||||
audioAvailable: boolean, |
||||
|
||||
/** |
||||
* Whether or not the user is currently audio muted. |
||||
*/ |
||||
audioMuted: boolean, |
||||
|
||||
/** |
||||
* Additional CSS class names to add to the root of the toolbar. |
||||
*/ |
||||
className: string, |
||||
|
||||
/** |
||||
* Callback invoked when no longer moused over the toolbar. |
||||
*/ |
||||
onMouseOut: Function, |
||||
|
||||
/** |
||||
* Callback invoked when the mouse has moved over the toolbar. |
||||
*/ |
||||
onMouseOver: Function, |
||||
|
||||
/** |
||||
* Whether or not camera access is available. |
||||
*/ |
||||
videoAvailable: boolean, |
||||
|
||||
/** |
||||
* Whether or not the user is currently video muted. |
||||
*/ |
||||
videoMuted: boolean |
||||
}; |
||||
|
||||
/** |
||||
* Represents the toolbar in the Always On Top window. |
||||
* |
||||
* @extends Component |
||||
*/ |
||||
export default class ToolboxAlwaysOnTop extends Component<Props> { |
||||
/** |
||||
* Initializes a new {@code ToolboxAlwaysOnTop} instance. |
||||
* |
||||
* @param {Props} props - The read-only properties with which the new |
||||
* instance is to be initialized. |
||||
*/ |
||||
constructor(props: Props) { |
||||
super(props); |
||||
|
||||
// Bind event handlers so they are only bound once per instance.
|
||||
this._onToolbarHangup = this._onToolbarHangup.bind(this); |
||||
this._onToolbarToggleAudio = this._onToolbarToggleAudio.bind(this); |
||||
this._onToolbarToggleVideo = this._onToolbarToggleVideo.bind(this); |
||||
} |
||||
|
||||
/** |
||||
* Implements React's {@link Component#render()}. |
||||
* |
||||
* @inheritdoc |
||||
* @returns {ReactElement} |
||||
*/ |
||||
render() { |
||||
const { |
||||
audioAvailable, |
||||
audioMuted, |
||||
className = '', |
||||
onMouseOut, |
||||
onMouseOver, |
||||
videoAvailable, |
||||
videoMuted |
||||
} = this.props; |
||||
|
||||
const videoMuteIcon = `${videoMuted || !videoAvailable |
||||
? 'icon-camera-disabled toggled' : 'icon-camera'} ${ |
||||
videoAvailable ? '' : 'disabled'}`;
|
||||
const audioMuteIcon = `${audioMuted || !audioAvailable |
||||
? 'icon-mic-disabled toggled' : 'icon-microphone'} ${ |
||||
audioAvailable ? '' : 'disabled'}`;
|
||||
|
||||
return ( |
||||
<div |
||||
className = { `always-on-top-toolbox ${className}` } |
||||
onMouseOut = { onMouseOut } |
||||
onMouseOver = { onMouseOver }> |
||||
<ToolbarButton |
||||
accessibilityLabel = 'Audio mute' |
||||
iconName = { audioMuteIcon } |
||||
onClick = { this._onToolbarToggleAudio } /> |
||||
<ToolbarButton |
||||
accessibilityLabel = 'Hangup' |
||||
iconName = 'icon-hangup' |
||||
onClick = { this._onToolbarHangup } /> |
||||
<ToolbarButton |
||||
accessibilityLabel = 'Video mute' |
||||
iconName = { videoMuteIcon } |
||||
onClick = { this._onToolbarToggleVideo } /> |
||||
</div> |
||||
); |
||||
} |
||||
|
||||
_onToolbarHangup: () => void; |
||||
|
||||
/** |
||||
* Ends the conference call and closes the always on top window. |
||||
* |
||||
* @private |
||||
* @returns {void} |
||||
*/ |
||||
_onToolbarHangup() { |
||||
api.executeCommand('hangup'); |
||||
window.close(); |
||||
} |
||||
|
||||
_onToolbarToggleAudio: () => void; |
||||
|
||||
/** |
||||
* Toggles audio mute if audio is avaiable. |
||||
* |
||||
* @private |
||||
* @returns {void} |
||||
*/ |
||||
_onToolbarToggleAudio() { |
||||
if (this.props.audioAvailable) { |
||||
api.executeCommand('toggleAudio'); |
||||
} |
||||
} |
||||
|
||||
_onToolbarToggleVideo: () => void; |
||||
|
||||
/** |
||||
* Toggles video mute if video is avaiable. |
||||
* |
||||
* @private |
||||
* @returns {void} |
||||
*/ |
||||
_onToolbarToggleVideo() { |
||||
if (this.props.videoAvailable) { |
||||
api.executeCommand('toggleVideo'); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,145 @@ |
||||
// @flow
|
||||
|
||||
// XXX: AlwaysOnTop imports the button directly in order to avoid bringing in
|
||||
// other components that use lib-jitsi-meet, which always on top does not
|
||||
// import.
|
||||
import AbstractVideoMuteButton |
||||
from '../toolbox/components/buttons/AbstractVideoMuteButton'; |
||||
import type { Props } from '../toolbox/components/buttons/AbstractButton'; |
||||
|
||||
const { api } = window.alwaysOnTop; |
||||
|
||||
type State = { |
||||
|
||||
/** |
||||
* Whether video is available is not. |
||||
*/ |
||||
videoAvailable: boolean, |
||||
|
||||
/** |
||||
* Whether video is muted or not. |
||||
*/ |
||||
videoMuted: boolean |
||||
}; |
||||
|
||||
/** |
||||
* Stateless hangup button for the Always-on-Top windows. |
||||
*/ |
||||
export default class VideoMuteButton |
||||
extends AbstractVideoMuteButton<Props, State> { |
||||
|
||||
/** |
||||
* 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(values => { |
||||
const [ videoAvailable, videoMuted ] = values; |
||||
|
||||
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 |
||||
* @private |
||||
* @returns {boolean} |
||||
*/ |
||||
_isDisabled() { |
||||
return !this.state.videoAvailable; |
||||
} |
||||
|
||||
/** |
||||
* Indicates if video is currently muted ot nor. |
||||
* |
||||
* @override |
||||
* @private |
||||
* @returns {boolean} |
||||
*/ |
||||
_isVideoMuted() { |
||||
return this.state.videoMuted; |
||||
} |
||||
|
||||
/** |
||||
* Changes the muted state. |
||||
* |
||||
* @param {boolean} videoMuted - Whether video should be muted or not. |
||||
* @private |
||||
* @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 }); |
||||
} |
||||
} |
||||
Loading…
Reference in new issue