From 9b407d58a045df2e03350d0741dfd0a623e9d3d5 Mon Sep 17 00:00:00 2001 From: Torjus Date: Thu, 2 Aug 2018 12:18:07 +0200 Subject: [PATCH 1/4] Store selected user for filmstrip in store --- app/lib/components/Filmstrip.jsx | 41 ++++++++++++++++++-------------- app/lib/redux/reducers/room.js | 6 ++++- app/lib/redux/stateActions.js | 7 +++++- 3 files changed, 34 insertions(+), 20 deletions(-) diff --git a/app/lib/components/Filmstrip.jsx b/app/lib/components/Filmstrip.jsx index 54a46e1..9588442 100644 --- a/app/lib/components/Filmstrip.jsx +++ b/app/lib/components/Filmstrip.jsx @@ -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,14 @@ class Filmstrip extends Component } state = { - selectedPeerName : null, - lastSpeaker : null, - width : 400 + 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. getActivePeerName = () => - this.state.selectedPeerName || this.state.lastSpeaker; + this.props.selectedPeerName || this.state.lastSpeaker; isSharingCamera = (peerName) => this.props.peers[peerName] && this.props.peers[peerName].consumers.some((consumer) => @@ -94,10 +94,8 @@ class Filmstrip extends Component handleSelectPeer = (selectedPeerName) => { - this.setState((oldState) => ({ - selectedPeerName : oldState.selectedPeerName === selectedPeerName ? - null : selectedPeerName - })); + this.props.setSelectedPeer(this.props.selectedPeerName === selectedPeerName ? + null : selectedPeerName); }; render() @@ -132,7 +130,7 @@ class Filmstrip extends Component key={peerName} onClick={() => this.handleSelectPeer(peerName)} className={classnames('film', { - selected : this.state.selectedPeerName === peerName, + selected : this.props.selectedPeerName === peerName, active : this.state.lastSpeaker === peerName })} > @@ -156,17 +154,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) => - ({ - activeSpeakerName : state.room.activeSpeakerName, - peers : state.peers, - consumers : state.consumers, - myName : state.me.name - }); +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); diff --git a/app/lib/redux/reducers/room.js b/app/lib/redux/reducers/room.js index 4a787de..0856029 100644 --- a/app/lib/redux/reducers/room.js +++ b/app/lib/redux/reducers/room.js @@ -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,9 @@ const room = (state = initialState, action) => case 'SET_DISPLAY_MODE': return { ...state, mode: action.payload.mode }; + case 'SET_SELECTED_PEER': + return { ...state, selectedPeerName: action.payload.selectedPeerName }; + default: return state; } diff --git a/app/lib/redux/stateActions.js b/app/lib/redux/stateActions.js index 008d308..1d8d09f 100644 --- a/app/lib/redux/stateActions.js +++ b/app/lib/redux/stateActions.js @@ -472,4 +472,9 @@ export const setPeerPicture = (peerName, picture) => export const loggedIn = () => ({ type : 'LOGGED_IN' - }); \ No newline at end of file + }); + +export const setSelectedPeer = (selectedPeerName) => ({ + type : 'SET_SELECTED_PEER', + payload : { selectedPeerName } +}); From 9e23683f0bec4feea08d30f64428fd303177aab3 Mon Sep 17 00:00:00 2001 From: Torjus Date: Thu, 2 Aug 2018 12:44:28 +0200 Subject: [PATCH 2/4] Support selecting Peers from ParticipantList --- app/lib/components/Filmstrip.jsx | 8 +- .../ParticipantList/ParticipantList.jsx | 78 +++++++------------ app/lib/redux/reducers/room.js | 11 ++- app/stylus/components/ParticipantList.styl | 7 +- 4 files changed, 43 insertions(+), 61 deletions(-) diff --git a/app/lib/components/Filmstrip.jsx b/app/lib/components/Filmstrip.jsx index 9588442..86a3332 100644 --- a/app/lib/components/Filmstrip.jsx +++ b/app/lib/components/Filmstrip.jsx @@ -92,12 +92,6 @@ class Filmstrip extends Component } } - handleSelectPeer = (selectedPeerName) => - { - this.props.setSelectedPeer(this.props.selectedPeerName === selectedPeerName ? - null : selectedPeerName); - }; - render() { const { peers, advancedMode } = this.props; @@ -128,7 +122,7 @@ class Filmstrip extends Component {Object.keys(peers).map((peerName) => (
this.handleSelectPeer(peerName)} + onClick={() => this.props.setSelectedPeer(peerName)} className={classnames('film', { selected : this.props.selectedPeerName === peerName, active : this.state.lastSpeaker === peerName diff --git a/app/lib/components/ParticipantList/ParticipantList.jsx b/app/lib/components/ParticipantList/ParticipantList.jsx index a212509..cf38181 100644 --- a/app/lib/components/ParticipantList/ParticipantList.jsx +++ b/app/lib/components/ParticipantList/ParticipantList.jsx @@ -1,48 +1,35 @@ 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'; -class ParticipantList extends React.Component -{ - constructor(props) - { - super(props); - } - - render() - { - const { - advancedMode, - peers - } = this.props; - - return ( -
-
    - { - peers.map((peer) => - { - return ( -
  • - -
  • - ); - }) - } -
-
- ); - } -} +const ParticipantList = ({ advancedMode, peers, setSelectedPeer, selectedPeerName }) => ( +
+
    + {peers.map((peer) => ( +
  • setSelectedPeer(peer.name)} + > + +
  • + ))} +
+
+); ParticipantList.propTypes = { - advancedMode : PropTypes.bool, - peers : PropTypes.arrayOf(appPropTypes.Peer).isRequired + advancedMode : PropTypes.bool, + peers : PropTypes.arrayOf(appPropTypes.Peer).isRequired, + setSelectedPeer : PropTypes.func.isRequired, + selectedPeerName : PropTypes.string }; const mapStateToProps = (state) => @@ -50,26 +37,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( diff --git a/app/lib/redux/reducers/room.js b/app/lib/redux/reducers/room.js index 0856029..19872ec 100644 --- a/app/lib/redux/reducers/room.js +++ b/app/lib/redux/reducers/room.js @@ -72,7 +72,16 @@ const room = (state = initialState, action) => return { ...state, mode: action.payload.mode }; case 'SET_SELECTED_PEER': - return { ...state, selectedPeerName: action.payload.selectedPeerName }; + { + const { selectedPeerName } = action.payload; + + return { + ...state, + + selectedPeerName : state.selectedPeerName === selectedPeerName ? + null : selectedPeerName + }; + } default: return state; diff --git a/app/stylus/components/ParticipantList.styl b/app/stylus/components/ParticipantList.styl index 5b2d1f6..31c9951 100644 --- a/app/stylus/components/ParticipantList.styl +++ b/app/stylus/components/ParticipantList.styl @@ -7,9 +7,14 @@ > .list-item { padding: 0.5vmin; - border-bottom: 1px solid #ddd; + border-bottom: 1px solid #CBCBCB; width: 100%; overflow: hidden; + cursor: pointer; + + &.selected { + border-bottom-color: #377EFF; + } } } } From c2494724239eea94cf9210e06b97ec8871bbe493 Mon Sep 17 00:00:00 2001 From: Torjus Date: Thu, 2 Aug 2018 13:00:27 +0200 Subject: [PATCH 3/4] Merge develop --- app/lib/components/ParticipantList/ParticipantList.jsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/lib/components/ParticipantList/ParticipantList.jsx b/app/lib/components/ParticipantList/ParticipantList.jsx index cf38181..5f56983 100644 --- a/app/lib/components/ParticipantList/ParticipantList.jsx +++ b/app/lib/components/ParticipantList/ParticipantList.jsx @@ -5,10 +5,13 @@ import * as appPropTypes from '../appPropTypes'; import * as stateActions from '../../redux/stateActions'; import PropTypes from 'prop-types'; import ListPeer from './ListPeer'; +import ListMe from './ListMe'; const ParticipantList = ({ advancedMode, peers, setSelectedPeer, selectedPeerName }) => (
    + + {peers.map((peer) => (
  • Date: Thu, 2 Aug 2018 13:01:35 +0200 Subject: [PATCH 4/4] Select random peer if no peer has spoken yet --- app/lib/components/Filmstrip.jsx | 22 ++++++++++- app/lib/components/ParticipantList/ListMe.jsx | 38 +++++++++++++++++++ app/stylus/components/ParticipantList.styl | 6 +++ 3 files changed, 64 insertions(+), 2 deletions(-) create mode 100644 app/lib/components/ParticipantList/ListMe.jsx diff --git a/app/lib/components/Filmstrip.jsx b/app/lib/components/Filmstrip.jsx index 86a3332..5a86b69 100644 --- a/app/lib/components/Filmstrip.jsx +++ b/app/lib/components/Filmstrip.jsx @@ -21,9 +21,27 @@ class Filmstrip extends Component }; // 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.props.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) => diff --git a/app/lib/components/ParticipantList/ListMe.jsx b/app/lib/components/ParticipantList/ListMe.jsx new file mode 100644 index 0000000..6b86025 --- /dev/null +++ b/app/lib/components/ParticipantList/ListMe.jsx @@ -0,0 +1,38 @@ +import React from 'react'; +import { connect } from 'react-redux'; +import { Me } from '../appPropTypes'; + +const ListMe = ({ me }) => +{ + const picture = me.picture || 'resources/images/avatar-empty.jpeg'; + + return ( +
  • +
    + + +
    + {me.displayName} +
    + +
    + {me.raisedHand && ( +
    + )} +
    +
    +
  • + ); +}; + +ListMe.propTypes = { + me : Me.isRequired +}; + +const mapStateToProps = (state) => ({ + me : state.me +}); + +export default connect( + mapStateToProps +)(ListMe); \ No newline at end of file diff --git a/app/stylus/components/ParticipantList.styl b/app/stylus/components/ParticipantList.styl index 31c9951..6dd24cc 100644 --- a/app/stylus/components/ParticipantList.styl +++ b/app/stylus/components/ParticipantList.styl @@ -12,6 +12,10 @@ overflow: hidden; cursor: pointer; + &.me { + cursor: auto; + } + &.selected { border-bottom-color: #377EFF; } @@ -21,6 +25,8 @@ [data-component='ListPeer'] { display: flex; + align-items: center; + > .indicators { left: 0; top: 0;