commit
6cec6e5155
|
|
@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
|
|||
import ResizeObserver from 'resize-observer-polyfill';
|
||||
import { connect } from 'react-redux';
|
||||
import classnames from 'classnames';
|
||||
import * as stateActions from '../redux/stateActions';
|
||||
import Peer from './Peer';
|
||||
|
||||
class Filmstrip extends Component
|
||||
|
|
@ -15,15 +16,32 @@ class Filmstrip extends Component
|
|||
}
|
||||
|
||||
state = {
|
||||
selectedPeerName : null,
|
||||
lastSpeaker : null,
|
||||
width : 400
|
||||
};
|
||||
|
||||
// Find the name of the peer which is currently speaking. This is either
|
||||
// the latest active speaker, or the manually selected peer.
|
||||
// the latest active speaker, or the manually selected peer, or, if no
|
||||
// person has spoken yet, the first peer in the list of peers.
|
||||
getActivePeerName = () =>
|
||||
this.state.selectedPeerName || this.state.lastSpeaker;
|
||||
{
|
||||
if (this.props.selectedPeerName)
|
||||
{
|
||||
return this.props.selectedPeerName;
|
||||
}
|
||||
|
||||
if (this.state.lastSpeaker)
|
||||
{
|
||||
return this.state.lastSpeaker;
|
||||
}
|
||||
|
||||
const peerNames = Object.keys(this.props.peers);
|
||||
|
||||
if (peerNames.length > 0)
|
||||
{
|
||||
return peerNames[0];
|
||||
}
|
||||
};
|
||||
|
||||
isSharingCamera = (peerName) => this.props.peers[peerName] &&
|
||||
this.props.peers[peerName].consumers.some((consumer) =>
|
||||
|
|
@ -92,14 +110,6 @@ class Filmstrip extends Component
|
|||
}
|
||||
}
|
||||
|
||||
handleSelectPeer = (selectedPeerName) =>
|
||||
{
|
||||
this.setState((oldState) => ({
|
||||
selectedPeerName : oldState.selectedPeerName === selectedPeerName ?
|
||||
null : selectedPeerName
|
||||
}));
|
||||
};
|
||||
|
||||
render()
|
||||
{
|
||||
const { peers, advancedMode } = this.props;
|
||||
|
|
@ -130,9 +140,9 @@ class Filmstrip extends Component
|
|||
{Object.keys(peers).map((peerName) => (
|
||||
<div
|
||||
key={peerName}
|
||||
onClick={() => this.handleSelectPeer(peerName)}
|
||||
onClick={() => this.props.setSelectedPeer(peerName)}
|
||||
className={classnames('film', {
|
||||
selected : this.state.selectedPeerName === peerName,
|
||||
selected : this.props.selectedPeerName === peerName,
|
||||
active : this.state.lastSpeaker === peerName
|
||||
})}
|
||||
>
|
||||
|
|
@ -156,17 +166,24 @@ Filmstrip.propTypes = {
|
|||
advancedMode : PropTypes.bool,
|
||||
peers : PropTypes.object.isRequired,
|
||||
consumers : PropTypes.object.isRequired,
|
||||
myName : PropTypes.string.isRequired
|
||||
myName : PropTypes.string.isRequired,
|
||||
selectedPeerName : PropTypes.string,
|
||||
setSelectedPeer : PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
const mapStateToProps = (state) =>
|
||||
({
|
||||
const mapStateToProps = (state) => ({
|
||||
activeSpeakerName : state.room.activeSpeakerName,
|
||||
selectedPeerName : state.room.selectedPeerName,
|
||||
peers : state.peers,
|
||||
consumers : state.consumers,
|
||||
myName : state.me.name
|
||||
});
|
||||
});
|
||||
|
||||
const mapDispatchToProps = {
|
||||
setSelectedPeer : stateActions.setSelectedPeer
|
||||
};
|
||||
|
||||
export default connect(
|
||||
mapStateToProps
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(Filmstrip);
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ const ListMe = ({ me }) =>
|
|||
const picture = me.picture || 'resources/images/avatar-empty.jpeg';
|
||||
|
||||
return (
|
||||
<li className='list-item'>
|
||||
<li className='list-item me'>
|
||||
<div data-component='ListPeer'>
|
||||
<img className='avatar' src={picture} />
|
||||
|
||||
|
|
|
|||
|
|
@ -1,51 +1,38 @@
|
|||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import classNames from 'classnames';
|
||||
import * as appPropTypes from '../appPropTypes';
|
||||
import * as requestActions from '../../redux/requestActions';
|
||||
import * as stateActions from '../../redux/stateActions';
|
||||
import PropTypes from 'prop-types';
|
||||
import ListPeer from './ListPeer';
|
||||
import ListMe from './ListMe';
|
||||
|
||||
class ParticipantList extends React.Component
|
||||
{
|
||||
constructor(props)
|
||||
{
|
||||
super(props);
|
||||
}
|
||||
|
||||
render()
|
||||
{
|
||||
const {
|
||||
advancedMode,
|
||||
peers
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
const ParticipantList = ({ advancedMode, peers, setSelectedPeer, selectedPeerName }) => (
|
||||
<div data-component='ParticipantList'>
|
||||
<ul className='list'>
|
||||
<ListMe />
|
||||
|
||||
{
|
||||
peers.map((peer) =>
|
||||
{
|
||||
return (
|
||||
<li key={peer.name} className='list-item'>
|
||||
{peers.map((peer) => (
|
||||
<li
|
||||
key={peer.name}
|
||||
className={classNames('list-item', {
|
||||
selected : peer.name === selectedPeerName
|
||||
})}
|
||||
onClick={() => setSelectedPeer(peer.name)}
|
||||
>
|
||||
<ListPeer name={peer.name} advancedMode={advancedMode} />
|
||||
</li>
|
||||
);
|
||||
})
|
||||
}
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
ParticipantList.propTypes =
|
||||
{
|
||||
advancedMode : PropTypes.bool,
|
||||
peers : PropTypes.arrayOf(appPropTypes.Peer).isRequired
|
||||
peers : PropTypes.arrayOf(appPropTypes.Peer).isRequired,
|
||||
setSelectedPeer : PropTypes.func.isRequired,
|
||||
selectedPeerName : PropTypes.string
|
||||
};
|
||||
|
||||
const mapStateToProps = (state) =>
|
||||
|
|
@ -53,26 +40,13 @@ const mapStateToProps = (state) =>
|
|||
const peersArray = Object.values(state.peers);
|
||||
|
||||
return {
|
||||
peers : peersArray
|
||||
peers : peersArray,
|
||||
selectedPeerName : state.room.selectedPeerName
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = (dispatch) =>
|
||||
{
|
||||
return {
|
||||
handleChangeWebcam : (device) =>
|
||||
{
|
||||
dispatch(requestActions.changeWebcam(device.value));
|
||||
},
|
||||
handleChangeAudioDevice : (device) =>
|
||||
{
|
||||
dispatch(requestActions.changeAudioDevice(device.value));
|
||||
},
|
||||
onToggleAdvancedMode : () =>
|
||||
{
|
||||
dispatch(stateActions.toggleAdvancedMode());
|
||||
}
|
||||
};
|
||||
const mapDispatchToProps = {
|
||||
setSelectedPeer : stateActions.setSelectedPeer
|
||||
};
|
||||
|
||||
const ParticipantListContainer = connect(
|
||||
|
|
|
|||
|
|
@ -7,7 +7,8 @@ const initialState =
|
|||
advancedMode : false,
|
||||
fullScreenConsumer : null, // ConsumerID
|
||||
toolbarsVisible : true,
|
||||
mode : 'democratic'
|
||||
mode : 'democratic',
|
||||
selectedPeerName : null
|
||||
};
|
||||
|
||||
const room = (state = initialState, action) =>
|
||||
|
|
@ -70,6 +71,18 @@ const room = (state = initialState, action) =>
|
|||
case 'SET_DISPLAY_MODE':
|
||||
return { ...state, mode: action.payload.mode };
|
||||
|
||||
case 'SET_SELECTED_PEER':
|
||||
{
|
||||
const { selectedPeerName } = action.payload;
|
||||
|
||||
return {
|
||||
...state,
|
||||
|
||||
selectedPeerName : state.selectedPeerName === selectedPeerName ?
|
||||
null : selectedPeerName
|
||||
};
|
||||
}
|
||||
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -473,3 +473,8 @@ export const loggedIn = () =>
|
|||
({
|
||||
type : 'LOGGED_IN'
|
||||
});
|
||||
|
||||
export const setSelectedPeer = (selectedPeerName) => ({
|
||||
type : 'SET_SELECTED_PEER',
|
||||
payload : { selectedPeerName }
|
||||
});
|
||||
|
|
|
|||
|
|
@ -7,15 +7,26 @@
|
|||
|
||||
> .list-item {
|
||||
padding: 0.5vmin;
|
||||
border-bottom: 1px solid #ddd;
|
||||
border-bottom: 1px solid #CBCBCB;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
|
||||
&.me {
|
||||
cursor: auto;
|
||||
}
|
||||
|
||||
&.selected {
|
||||
border-bottom-color: #377EFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[data-component='ListPeer'] {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
> .indicators {
|
||||
left: 0;
|
||||
top: 0;
|
||||
|
|
|
|||
Loading…
Reference in New Issue