Merge pull request #57 from havfo/feat/user-state

Feat/user state
master
Håvar Aambø Fosstveit 2018-08-02 14:17:57 +02:00 committed by GitHub
commit 6cec6e5155
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 101 additions and 81 deletions

View File

@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
import ResizeObserver from 'resize-observer-polyfill'; import ResizeObserver from 'resize-observer-polyfill';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import classnames from 'classnames'; import classnames from 'classnames';
import * as stateActions from '../redux/stateActions';
import Peer from './Peer'; import Peer from './Peer';
class Filmstrip extends Component class Filmstrip extends Component
@ -15,15 +16,32 @@ class Filmstrip extends Component
} }
state = { state = {
selectedPeerName : null, lastSpeaker : null,
lastSpeaker : null, width : 400
width : 400
}; };
// Find the name of the peer which is currently speaking. This is either // 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 = () => 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] && isSharingCamera = (peerName) => this.props.peers[peerName] &&
this.props.peers[peerName].consumers.some((consumer) => 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() render()
{ {
const { peers, advancedMode } = this.props; const { peers, advancedMode } = this.props;
@ -130,9 +140,9 @@ class Filmstrip extends Component
{Object.keys(peers).map((peerName) => ( {Object.keys(peers).map((peerName) => (
<div <div
key={peerName} key={peerName}
onClick={() => this.handleSelectPeer(peerName)} onClick={() => this.props.setSelectedPeer(peerName)}
className={classnames('film', { className={classnames('film', {
selected : this.state.selectedPeerName === peerName, selected : this.props.selectedPeerName === peerName,
active : this.state.lastSpeaker === peerName active : this.state.lastSpeaker === peerName
})} })}
> >
@ -156,17 +166,24 @@ Filmstrip.propTypes = {
advancedMode : PropTypes.bool, advancedMode : PropTypes.bool,
peers : PropTypes.object.isRequired, peers : PropTypes.object.isRequired,
consumers : 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,
activeSpeakerName : state.room.activeSpeakerName, selectedPeerName : state.room.selectedPeerName,
peers : state.peers, peers : state.peers,
consumers : state.consumers, consumers : state.consumers,
myName : state.me.name myName : state.me.name
}); });
const mapDispatchToProps = {
setSelectedPeer : stateActions.setSelectedPeer
};
export default connect( export default connect(
mapStateToProps mapStateToProps,
mapDispatchToProps
)(Filmstrip); )(Filmstrip);

View File

@ -7,7 +7,7 @@ const ListMe = ({ me }) =>
const picture = me.picture || 'resources/images/avatar-empty.jpeg'; const picture = me.picture || 'resources/images/avatar-empty.jpeg';
return ( return (
<li className='list-item'> <li className='list-item me'>
<div data-component='ListPeer'> <div data-component='ListPeer'>
<img className='avatar' src={picture} /> <img className='avatar' src={picture} />

View File

@ -1,51 +1,38 @@
import React from 'react'; import React from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import classNames from 'classnames';
import * as appPropTypes from '../appPropTypes'; import * as appPropTypes from '../appPropTypes';
import * as requestActions from '../../redux/requestActions';
import * as stateActions from '../../redux/stateActions'; import * as stateActions from '../../redux/stateActions';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import ListPeer from './ListPeer'; import ListPeer from './ListPeer';
import ListMe from './ListMe'; import ListMe from './ListMe';
class ParticipantList extends React.Component const ParticipantList = ({ advancedMode, peers, setSelectedPeer, selectedPeerName }) => (
{ <div data-component='ParticipantList'>
constructor(props) <ul className='list'>
{ <ListMe />
super(props);
}
render() {peers.map((peer) => (
{ <li
const { key={peer.name}
advancedMode, className={classNames('list-item', {
peers selected : peer.name === selectedPeerName
} = this.props; })}
onClick={() => setSelectedPeer(peer.name)}
return ( >
<div data-component='ParticipantList'> <ListPeer name={peer.name} advancedMode={advancedMode} />
<ul className='list'> </li>
<ListMe /> ))}
</ul>
{ </div>
peers.map((peer) => );
{
return (
<li key={peer.name} className='list-item'>
<ListPeer name={peer.name} advancedMode={advancedMode} />
</li>
);
})
}
</ul>
</div>
);
}
}
ParticipantList.propTypes = ParticipantList.propTypes =
{ {
advancedMode : PropTypes.bool, 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) => const mapStateToProps = (state) =>
@ -53,26 +40,13 @@ const mapStateToProps = (state) =>
const peersArray = Object.values(state.peers); const peersArray = Object.values(state.peers);
return { return {
peers : peersArray peers : peersArray,
selectedPeerName : state.room.selectedPeerName
}; };
}; };
const mapDispatchToProps = (dispatch) => const mapDispatchToProps = {
{ setSelectedPeer : stateActions.setSelectedPeer
return {
handleChangeWebcam : (device) =>
{
dispatch(requestActions.changeWebcam(device.value));
},
handleChangeAudioDevice : (device) =>
{
dispatch(requestActions.changeAudioDevice(device.value));
},
onToggleAdvancedMode : () =>
{
dispatch(stateActions.toggleAdvancedMode());
}
};
}; };
const ParticipantListContainer = connect( const ParticipantListContainer = connect(

View File

@ -7,7 +7,8 @@ const initialState =
advancedMode : false, advancedMode : false,
fullScreenConsumer : null, // ConsumerID fullScreenConsumer : null, // ConsumerID
toolbarsVisible : true, toolbarsVisible : true,
mode : 'democratic' mode : 'democratic',
selectedPeerName : null
}; };
const room = (state = initialState, action) => const room = (state = initialState, action) =>
@ -70,6 +71,18 @@ const room = (state = initialState, action) =>
case 'SET_DISPLAY_MODE': case 'SET_DISPLAY_MODE':
return { ...state, mode: action.payload.mode }; return { ...state, mode: action.payload.mode };
case 'SET_SELECTED_PEER':
{
const { selectedPeerName } = action.payload;
return {
...state,
selectedPeerName : state.selectedPeerName === selectedPeerName ?
null : selectedPeerName
};
}
default: default:
return state; return state;
} }

View File

@ -472,4 +472,9 @@ export const setPeerPicture = (peerName, picture) =>
export const loggedIn = () => export const loggedIn = () =>
({ ({
type : 'LOGGED_IN' type : 'LOGGED_IN'
}); });
export const setSelectedPeer = (selectedPeerName) => ({
type : 'SET_SELECTED_PEER',
payload : { selectedPeerName }
});

View File

@ -7,15 +7,26 @@
> .list-item { > .list-item {
padding: 0.5vmin; padding: 0.5vmin;
border-bottom: 1px solid #ddd; border-bottom: 1px solid #CBCBCB;
width: 100%; width: 100%;
overflow: hidden; overflow: hidden;
cursor: pointer;
&.me {
cursor: auto;
}
&.selected {
border-bottom-color: #377EFF;
}
} }
} }
} }
[data-component='ListPeer'] { [data-component='ListPeer'] {
display: flex; display: flex;
align-items: center;
> .indicators { > .indicators {
left: 0; left: 0;
top: 0; top: 0;