Major cleanup. Moved a lot of CSS variables out too root of CSS for easier styling.
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import PropTypes from 'prop-types';
|
||||
import classnames from 'classnames';
|
||||
import * as stateActions from '../../redux/stateActions';
|
||||
|
||||
class HiddenPeers extends Component
|
||||
{
|
||||
constructor(props)
|
||||
{
|
||||
super(props);
|
||||
this.state = { className: '' };
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps)
|
||||
{
|
||||
const { hiddenPeersCount } = this.props;
|
||||
|
||||
if (hiddenPeersCount !== prevProps.hiddenPeersCount)
|
||||
{
|
||||
// eslint-disable-next-line react/no-did-update-set-state
|
||||
this.setState({ className: 'pulse' }, () =>
|
||||
{
|
||||
if (this.timeout)
|
||||
{
|
||||
clearTimeout(this.timeout);
|
||||
}
|
||||
|
||||
this.timeout = setTimeout(() =>
|
||||
{
|
||||
this.setState({ className: '' });
|
||||
}, 500);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
render()
|
||||
{
|
||||
const {
|
||||
hiddenPeersCount,
|
||||
openUsersTab
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<div data-component='HiddenPeers'>
|
||||
<div className={classnames('view-container', this.state.className)} onClick={() => openUsersTab()}>
|
||||
<p>+{hiddenPeersCount} <br /> participant
|
||||
{(hiddenPeersCount === 1) ? null : 's'}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
HiddenPeers.propTypes =
|
||||
{
|
||||
hiddenPeersCount : PropTypes.number,
|
||||
openUsersTab : PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
const mapDispatchToProps = (dispatch) =>
|
||||
{
|
||||
return {
|
||||
openUsersTab : () =>
|
||||
{
|
||||
dispatch(stateActions.openToolArea());
|
||||
dispatch(stateActions.setToolTab('users'));
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
const HiddenPeersContainer = connect(
|
||||
null,
|
||||
mapDispatchToProps
|
||||
)(HiddenPeers);
|
||||
|
||||
export default HiddenPeersContainer;
|
||||
@@ -0,0 +1,240 @@
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import ReactTooltip from 'react-tooltip';
|
||||
import PropTypes from 'prop-types';
|
||||
import classnames from 'classnames';
|
||||
import { getDeviceInfo } from 'mediasoup-client';
|
||||
import * as appPropTypes from '../appPropTypes';
|
||||
import { withRoomContext } from '../../RoomContext';
|
||||
import PeerView from '../VideoContainers/PeerView';
|
||||
import ScreenView from '../VideoContainers/ScreenView';
|
||||
|
||||
class Me extends React.Component
|
||||
{
|
||||
state = {
|
||||
controlsVisible : false
|
||||
};
|
||||
|
||||
handleMouseOver = () =>
|
||||
{
|
||||
this.setState({
|
||||
controlsVisible : true
|
||||
});
|
||||
};
|
||||
|
||||
handleMouseOut = () =>
|
||||
{
|
||||
this.setState({
|
||||
controlsVisible : false
|
||||
});
|
||||
};
|
||||
|
||||
constructor(props)
|
||||
{
|
||||
super(props);
|
||||
|
||||
this._mounted = false;
|
||||
this._rootNode = null;
|
||||
this._tooltip = true;
|
||||
|
||||
// TODO: Issue when using react-tooltip in Edge:
|
||||
// https://github.com/wwayne/react-tooltip/issues/328
|
||||
if (getDeviceInfo().flag === 'msedge')
|
||||
this._tooltip = false;
|
||||
}
|
||||
|
||||
render()
|
||||
{
|
||||
const {
|
||||
roomClient,
|
||||
connected,
|
||||
me,
|
||||
advancedMode,
|
||||
micProducer,
|
||||
webcamProducer,
|
||||
screenProducer
|
||||
} = this.props;
|
||||
|
||||
let micState;
|
||||
|
||||
if (!me.canSendMic)
|
||||
micState = 'unsupported';
|
||||
else if (!micProducer)
|
||||
micState = 'unsupported';
|
||||
else if (!micProducer.locallyPaused && !micProducer.remotelyPaused)
|
||||
micState = 'on';
|
||||
else
|
||||
micState = 'off';
|
||||
|
||||
let webcamState;
|
||||
|
||||
if (!me.canSendWebcam)
|
||||
webcamState = 'unsupported';
|
||||
else if (webcamProducer)
|
||||
webcamState = 'on';
|
||||
else
|
||||
webcamState = 'off';
|
||||
|
||||
const videoVisible = (
|
||||
Boolean(webcamProducer) &&
|
||||
!webcamProducer.locallyPaused &&
|
||||
!webcamProducer.remotelyPaused
|
||||
);
|
||||
|
||||
const screenVisible = (
|
||||
Boolean(screenProducer) &&
|
||||
!screenProducer.locallyPaused &&
|
||||
!screenProducer.remotelyPaused
|
||||
);
|
||||
|
||||
let tip;
|
||||
|
||||
if (!me.displayNameSet)
|
||||
tip = 'Click on your name to change it';
|
||||
|
||||
return (
|
||||
<div
|
||||
data-component='Me'
|
||||
ref={(node) => (this._rootNode = node)}
|
||||
data-tip={tip}
|
||||
data-tip-disable={!tip}
|
||||
data-type='dark'
|
||||
onMouseOver={this.handleMouseOver}
|
||||
onMouseOut={this.handleMouseOut}
|
||||
>
|
||||
<div className={classnames('view-container', 'webcam')}>
|
||||
<If condition={connected}>
|
||||
<div className={classnames('controls', 'visible')}>
|
||||
<div
|
||||
data-tip='keyboard shortcut: ‘m‘'
|
||||
data-type='dark'
|
||||
data-place='bottom'
|
||||
data-for='me'
|
||||
className={classnames('button', 'mic', micState, {
|
||||
disabled : me.audioInProgress,
|
||||
visible : micState == 'off' || this.state.controlsVisible
|
||||
})}
|
||||
onClick={() =>
|
||||
{
|
||||
micState === 'on' ?
|
||||
roomClient.muteMic() :
|
||||
roomClient.unmuteMic();
|
||||
}}
|
||||
/>
|
||||
<ReactTooltip
|
||||
id='me'
|
||||
effect='solid'
|
||||
/>
|
||||
<div
|
||||
className={classnames('button', 'webcam', webcamState, {
|
||||
disabled : me.webcamInProgress,
|
||||
visible : webcamState == 'off' || this.state.controlsVisible
|
||||
})}
|
||||
onClick={() =>
|
||||
{
|
||||
webcamState === 'on' ?
|
||||
roomClient.disableWebcam() :
|
||||
roomClient.enableWebcam();
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</If>
|
||||
|
||||
<PeerView
|
||||
isMe
|
||||
advancedMode={advancedMode}
|
||||
peer={me}
|
||||
audioTrack={micProducer ? micProducer.track : null}
|
||||
volume={micProducer ? micProducer.volume : null}
|
||||
videoTrack={webcamProducer ? webcamProducer.track : null}
|
||||
videoVisible={videoVisible}
|
||||
audioCodec={micProducer ? micProducer.codec : null}
|
||||
videoCodec={webcamProducer ? webcamProducer.codec : null}
|
||||
onChangeDisplayName={(displayName) =>
|
||||
{
|
||||
roomClient.changeDisplayName(displayName);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<If condition={screenProducer}>
|
||||
<div className={classnames('view-container', 'screen')}>
|
||||
<ScreenView
|
||||
isMe
|
||||
advancedMode={advancedMode}
|
||||
screenTrack={screenProducer ? screenProducer.track : null}
|
||||
screenVisible={screenVisible}
|
||||
screenCodec={screenProducer ? screenProducer.codec : null}
|
||||
/>
|
||||
</div>
|
||||
</If>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
componentDidMount()
|
||||
{
|
||||
this._mounted = true;
|
||||
|
||||
if (this._tooltip)
|
||||
{
|
||||
setTimeout(() =>
|
||||
{
|
||||
if (!this._mounted || this.props.me.displayNameSet)
|
||||
return;
|
||||
|
||||
ReactTooltip.show(this._rootNode);
|
||||
}, 4000);
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount()
|
||||
{
|
||||
this._mounted = false;
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps)
|
||||
{
|
||||
if (this._tooltip)
|
||||
{
|
||||
if (nextProps.me.displayNameSet)
|
||||
ReactTooltip.hide(this._rootNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Me.propTypes =
|
||||
{
|
||||
roomClient : PropTypes.any.isRequired,
|
||||
connected : PropTypes.bool.isRequired,
|
||||
advancedMode : PropTypes.bool,
|
||||
me : appPropTypes.Me.isRequired,
|
||||
micProducer : appPropTypes.Producer,
|
||||
webcamProducer : appPropTypes.Producer,
|
||||
screenProducer : appPropTypes.Producer
|
||||
};
|
||||
|
||||
const mapStateToProps = (state) =>
|
||||
{
|
||||
const producersArray = Object.values(state.producers);
|
||||
const micProducer =
|
||||
producersArray.find((producer) => producer.source === 'mic');
|
||||
const webcamProducer =
|
||||
producersArray.find((producer) => producer.source === 'webcam');
|
||||
const screenProducer =
|
||||
producersArray.find((producer) => producer.source === 'screen');
|
||||
|
||||
return {
|
||||
connected : state.room.state === 'connected',
|
||||
me : state.me,
|
||||
micProducer : micProducer,
|
||||
webcamProducer : webcamProducer,
|
||||
screenProducer : screenProducer
|
||||
};
|
||||
};
|
||||
|
||||
const MeContainer = withRoomContext(connect(
|
||||
mapStateToProps
|
||||
)(Me));
|
||||
|
||||
export default MeContainer;
|
||||
@@ -0,0 +1,266 @@
|
||||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import PropTypes from 'prop-types';
|
||||
import classnames from 'classnames';
|
||||
import * as appPropTypes from '../appPropTypes';
|
||||
import { withRoomContext } from '../../RoomContext';
|
||||
import * as stateActions from '../../redux/stateActions';
|
||||
import PeerView from '../VideoContainers/PeerView';
|
||||
import ScreenView from '../VideoContainers/ScreenView';
|
||||
|
||||
class Peer extends Component
|
||||
{
|
||||
state = {
|
||||
controlsVisible : false
|
||||
};
|
||||
|
||||
handleMouseOver = () =>
|
||||
{
|
||||
this.setState({
|
||||
controlsVisible : true
|
||||
});
|
||||
};
|
||||
|
||||
handleMouseOut = () =>
|
||||
{
|
||||
this.setState({
|
||||
controlsVisible : false
|
||||
});
|
||||
};
|
||||
|
||||
render()
|
||||
{
|
||||
const {
|
||||
roomClient,
|
||||
advancedMode,
|
||||
peer,
|
||||
micConsumer,
|
||||
webcamConsumer,
|
||||
screenConsumer,
|
||||
toggleConsumerFullscreen,
|
||||
toggleConsumerWindow,
|
||||
style,
|
||||
windowConsumer
|
||||
} = this.props;
|
||||
|
||||
const micEnabled = (
|
||||
Boolean(micConsumer) &&
|
||||
!micConsumer.locallyPaused &&
|
||||
!micConsumer.remotelyPaused
|
||||
);
|
||||
|
||||
const videoVisible = (
|
||||
Boolean(webcamConsumer) &&
|
||||
!webcamConsumer.locallyPaused &&
|
||||
!webcamConsumer.remotelyPaused
|
||||
);
|
||||
|
||||
const screenVisible = (
|
||||
Boolean(screenConsumer) &&
|
||||
!screenConsumer.locallyPaused &&
|
||||
!screenConsumer.remotelyPaused
|
||||
);
|
||||
|
||||
let videoProfile;
|
||||
|
||||
if (webcamConsumer)
|
||||
videoProfile = webcamConsumer.profile;
|
||||
|
||||
let screenProfile;
|
||||
|
||||
if (screenConsumer)
|
||||
screenProfile = screenConsumer.profile;
|
||||
|
||||
return (
|
||||
<div
|
||||
data-component='Peer'
|
||||
className={classnames({
|
||||
screen : screenConsumer
|
||||
})}
|
||||
onMouseOver={this.handleMouseOver}
|
||||
onMouseOut={this.handleMouseOut}
|
||||
>
|
||||
<If condition={videoVisible && !webcamConsumer.supported}>
|
||||
<div className='incompatible-video'>
|
||||
<p>incompatible video</p>
|
||||
</div>
|
||||
</If>
|
||||
|
||||
<If condition={!videoVisible}>
|
||||
<div className='paused-video'>
|
||||
<p>this video is paused</p>
|
||||
</div>
|
||||
</If>
|
||||
|
||||
<div className={classnames('view-container', 'webcam')} style={style}>
|
||||
<div className='indicators'>
|
||||
<If condition={peer.raiseHandState}>
|
||||
<div className={
|
||||
classnames(
|
||||
'icon', 'raise-hand', {
|
||||
on : peer.raiseHandState,
|
||||
off : !peer.raiseHandState
|
||||
}
|
||||
)
|
||||
}
|
||||
/>
|
||||
</If>
|
||||
</div>
|
||||
<div
|
||||
className={classnames('controls', {
|
||||
visible : this.state.controlsVisible
|
||||
})}
|
||||
>
|
||||
<div
|
||||
className={classnames('button', 'mic', {
|
||||
on : micEnabled,
|
||||
off : !micEnabled,
|
||||
disabled : peer.peerAudioInProgress
|
||||
})}
|
||||
onClick={(e) =>
|
||||
{
|
||||
e.stopPropagation();
|
||||
micEnabled ?
|
||||
roomClient.modifyPeerConsumer(peer.name, 'mic', true) :
|
||||
roomClient.modifyPeerConsumer(peer.name, 'mic', false);
|
||||
}}
|
||||
/>
|
||||
|
||||
<div
|
||||
className={classnames('button', 'newwindow', {
|
||||
disabled : !videoVisible ||
|
||||
(windowConsumer === webcamConsumer.id)
|
||||
})}
|
||||
onClick={(e) =>
|
||||
{
|
||||
e.stopPropagation();
|
||||
toggleConsumerWindow(webcamConsumer);
|
||||
}}
|
||||
/>
|
||||
|
||||
<div
|
||||
className={classnames('button', 'fullscreen', {
|
||||
disabled : !videoVisible
|
||||
})}
|
||||
onClick={(e) =>
|
||||
{
|
||||
e.stopPropagation();
|
||||
toggleConsumerFullscreen(webcamConsumer);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<PeerView
|
||||
advancedMode={advancedMode}
|
||||
peer={peer}
|
||||
volume={micConsumer ? micConsumer.volume : null}
|
||||
videoTrack={webcamConsumer ? webcamConsumer.track : null}
|
||||
videoVisible={videoVisible}
|
||||
videoProfile={videoProfile}
|
||||
audioCodec={micConsumer ? micConsumer.codec : null}
|
||||
videoCodec={webcamConsumer ? webcamConsumer.codec : null}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<If condition={screenConsumer}>
|
||||
<div className={classnames('view-container', 'screen')} style={style}>
|
||||
<div
|
||||
className={classnames('controls', {
|
||||
visible : this.state.controlsVisible
|
||||
})}
|
||||
>
|
||||
<div
|
||||
className={classnames('button', 'newwindow', {
|
||||
disabled : !screenVisible ||
|
||||
(windowConsumer === screenConsumer.id)
|
||||
})}
|
||||
onClick={(e) =>
|
||||
{
|
||||
e.stopPropagation();
|
||||
toggleConsumerWindow(screenConsumer);
|
||||
}}
|
||||
/>
|
||||
|
||||
<div
|
||||
className={classnames('button', 'fullscreen', {
|
||||
disabled : !screenVisible
|
||||
})}
|
||||
onClick={(e) =>
|
||||
{
|
||||
e.stopPropagation();
|
||||
toggleConsumerFullscreen(screenConsumer);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<ScreenView
|
||||
advancedMode={advancedMode}
|
||||
screenTrack={screenConsumer ? screenConsumer.track : null}
|
||||
screenVisible={screenVisible}
|
||||
screenProfile={screenProfile}
|
||||
screenCodec={screenConsumer ? screenConsumer.codec : null}
|
||||
/>
|
||||
</div>
|
||||
</If>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Peer.propTypes =
|
||||
{
|
||||
roomClient : PropTypes.any.isRequired,
|
||||
advancedMode : PropTypes.bool,
|
||||
peer : appPropTypes.Peer.isRequired,
|
||||
micConsumer : appPropTypes.Consumer,
|
||||
webcamConsumer : appPropTypes.Consumer,
|
||||
screenConsumer : appPropTypes.Consumer,
|
||||
windowConsumer : PropTypes.number,
|
||||
streamDimensions : PropTypes.object,
|
||||
style : PropTypes.object,
|
||||
toggleConsumerFullscreen : PropTypes.func.isRequired,
|
||||
toggleConsumerWindow : PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
const mapStateToProps = (state, { name }) =>
|
||||
{
|
||||
const peer = state.peers[name];
|
||||
const consumersArray = peer.consumers
|
||||
.map((consumerId) => state.consumers[consumerId]);
|
||||
const micConsumer =
|
||||
consumersArray.find((consumer) => consumer.source === 'mic');
|
||||
const webcamConsumer =
|
||||
consumersArray.find((consumer) => consumer.source === 'webcam');
|
||||
const screenConsumer =
|
||||
consumersArray.find((consumer) => consumer.source === 'screen');
|
||||
|
||||
return {
|
||||
peer,
|
||||
micConsumer,
|
||||
webcamConsumer,
|
||||
screenConsumer,
|
||||
windowConsumer : state.room.windowConsumer
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = (dispatch) =>
|
||||
{
|
||||
return {
|
||||
toggleConsumerFullscreen : (consumer) =>
|
||||
{
|
||||
if (consumer)
|
||||
dispatch(stateActions.toggleConsumerFullscreen(consumer.id));
|
||||
},
|
||||
toggleConsumerWindow : (consumer) =>
|
||||
{
|
||||
if (consumer)
|
||||
dispatch(stateActions.toggleConsumerWindow(consumer.id));
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
const PeerContainer = withRoomContext(connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(Peer));
|
||||
|
||||
export default PeerContainer;
|
||||
Reference in New Issue
Block a user