From ef2d8a41053910d1bfecb4f189620d65ba782ed9 Mon Sep 17 00:00:00 2001 From: Torjus Date: Thu, 19 Jul 2018 13:47:14 +0200 Subject: [PATCH 01/14] Add basic skeleton for a Filmstrip view --- app/lib/components/Filmstrip/index.jsx | 75 ++++++++++++++++++++++++++ app/lib/components/Peers.jsx | 10 ++-- app/lib/components/Room.jsx | 10 ++-- 3 files changed, 85 insertions(+), 10 deletions(-) create mode 100644 app/lib/components/Filmstrip/index.jsx diff --git a/app/lib/components/Filmstrip/index.jsx b/app/lib/components/Filmstrip/index.jsx new file mode 100644 index 0000000..9266368 --- /dev/null +++ b/app/lib/components/Filmstrip/index.jsx @@ -0,0 +1,75 @@ +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; +import { connect } from 'react-redux'; +import * as appPropTypes from '../appPropTypes'; +import Peer from '../Peer'; + +class Filmstrip extends Component +{ + state = { + selectedPeerName : null + }; + + handleSelectPeer = (selectedPeerName) => + { + this.setState({ + selectedPeerName + }); + }; + + render() + { + const { activeSpeakerName, peers, advancedMode } = this.props; + + // Find the name of the peer which is currently speaking. This is either + // the latest active speaker, or the manually selected peer. + const activePeerName = this.state.selectedPeerName || activeSpeakerName; + + // Find the remainding peer names, which will be shown in the filmstrip. + const remaindingPeerNames = Object.keys(peers).filter((peerName) => + peerName !== activePeerName); + + return ( +
+ {peers[activePeerName] && ( +
+ +
+ )} + +
+ {remaindingPeerNames.map((peerName) => ( +
this.handleSelectPeer(peerName)} + > + +
+ ))} +
+
+ ); + } +} + +Filmstrip.propTypes = { + activeSpeakerName : PropTypes.string, + advancedMode : PropTypes.bool, + peers : appPropTypes.peers +}; + +const mapStateToProps = (state) => + ({ + activeSpeakerName : state.room.activeSpeakerName, + peers : state.peers + }); + +export default connect( + mapStateToProps +)(Filmstrip); diff --git a/app/lib/components/Peers.jsx b/app/lib/components/Peers.jsx index fccebb8..b219db5 100644 --- a/app/lib/components/Peers.jsx +++ b/app/lib/components/Peers.jsx @@ -82,8 +82,7 @@ class Peers extends React.Component const { advancedMode, activeSpeakerName, - peers, - toolAreaOpen + peers } = this.props; const style = @@ -108,7 +107,6 @@ class Peers extends React.Component advancedMode={advancedMode} name={peer.name} style={style} - toolAreaOpen={toolAreaOpen} /> @@ -125,8 +123,7 @@ Peers.propTypes = advancedMode : PropTypes.bool, peers : PropTypes.arrayOf(appPropTypes.Peer).isRequired, boxes : PropTypes.number, - activeSpeakerName : PropTypes.string, - toolAreaOpen : PropTypes.bool + activeSpeakerName : PropTypes.string }; const mapStateToProps = (state) => @@ -139,8 +136,7 @@ const mapStateToProps = (state) => return { peers, boxes, - activeSpeakerName : state.room.activeSpeakerName, - toolAreaOpen : state.toolarea.toolAreaOpen + activeSpeakerName : state.room.activeSpeakerName }; }; diff --git a/app/lib/components/Room.jsx b/app/lib/components/Room.jsx index 7202c90..0e81374 100644 --- a/app/lib/components/Room.jsx +++ b/app/lib/components/Room.jsx @@ -17,6 +17,7 @@ import FullScreenView from './FullScreenView'; import Draggable from 'react-draggable'; import { idle } from '../utils'; import Sidebar from './Sidebar'; +import Filmstrip from './Filmstrip'; // Hide toolbars after 10 seconds of inactivity. const TIMEOUT = 10 * 1000; @@ -121,9 +122,12 @@ class Room extends React.Component - + + {false && ( + + )}
Date: Thu, 19 Jul 2018 15:07:33 +0200 Subject: [PATCH 02/14] Add some very basic styling to the Filmstrip --- app/lib/components/Filmstrip/index.jsx | 24 ++++++++++--------- app/stylus/components/Filmstrip.styl | 32 ++++++++++++++++++++++++++ app/stylus/components/Peer.styl | 4 +++- app/stylus/index.styl | 1 + 4 files changed, 49 insertions(+), 12 deletions(-) create mode 100644 app/stylus/components/Filmstrip.styl diff --git a/app/lib/components/Filmstrip/index.jsx b/app/lib/components/Filmstrip/index.jsx index 9266368..baa5f75 100644 --- a/app/lib/components/Filmstrip/index.jsx +++ b/app/lib/components/Filmstrip/index.jsx @@ -1,6 +1,7 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { connect } from 'react-redux'; +import classnames from 'classnames'; import * as appPropTypes from '../appPropTypes'; import Peer from '../Peer'; @@ -12,9 +13,10 @@ class Filmstrip extends Component handleSelectPeer = (selectedPeerName) => { - this.setState({ - selectedPeerName - }); + this.setState((oldState) => ({ + selectedPeerName : oldState.selectedPeerName === selectedPeerName ? + null : selectedPeerName + })); }; render() @@ -25,14 +27,10 @@ class Filmstrip extends Component // the latest active speaker, or the manually selected peer. const activePeerName = this.state.selectedPeerName || activeSpeakerName; - // Find the remainding peer names, which will be shown in the filmstrip. - const remaindingPeerNames = Object.keys(peers).filter((peerName) => - peerName !== activePeerName); - return ( -
+
{peers[activePeerName] && ( -
+
)} -
- {remaindingPeerNames.map((peerName) => ( +
+ {Object.keys(peers).map((peerName) => (
this.handleSelectPeer(peerName)} + className={classnames('film', { + selected : this.state.selectedPeerName === peerName, + active : activeSpeakerName === peerName + })} > .active-peer { + width: 95vmin; + padding: 10vmin 1vmin 1vmin 1vmin; + } + + > .filmstrip { + display: flex; + padding: 0.5vmin; + cursor: pointer; + + > .film { + height: 15vmin; + max-width: 15vmin * (2 * 4 / 3); + margin: 1vmin; + + &.active { + border: 5px solid white; + } + + &.selected { + border: 5px solid pink; + } + } + } +} \ No newline at end of file diff --git a/app/stylus/components/Peer.styl b/app/stylus/components/Peer.styl index 5a9e762..7d26715 100644 --- a/app/stylus/components/Peer.styl +++ b/app/stylus/components/Peer.styl @@ -22,13 +22,15 @@ > .view-container { position: relative; - + flex-grow: 1; + &.webcam { order: 2; } &.screen { order: 1; + max-width: 50%; } > .controls { diff --git a/app/stylus/index.styl b/app/stylus/index.styl index 94e08b8..5e67e46 100644 --- a/app/stylus/index.styl +++ b/app/stylus/index.styl @@ -50,6 +50,7 @@ body { @import './components/ParticipantList'; @import './components/FullScreenView'; @import './components/FullView'; + @import './components/Filmstrip'; } // Hack to detect in JS the current media query From c03d55b18113bc3ac26e55a505191ba26c441af4 Mon Sep 17 00:00:00 2001 From: Torjus Date: Thu, 19 Jul 2018 15:13:25 +0200 Subject: [PATCH 03/14] Do not use separate directory for Filmstrip --- app/lib/components/{Filmstrip/index.jsx => Filmstrip.jsx} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename app/lib/components/{Filmstrip/index.jsx => Filmstrip.jsx} (95%) diff --git a/app/lib/components/Filmstrip/index.jsx b/app/lib/components/Filmstrip.jsx similarity index 95% rename from app/lib/components/Filmstrip/index.jsx rename to app/lib/components/Filmstrip.jsx index baa5f75..e0a16e9 100644 --- a/app/lib/components/Filmstrip/index.jsx +++ b/app/lib/components/Filmstrip.jsx @@ -2,8 +2,8 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { connect } from 'react-redux'; import classnames from 'classnames'; -import * as appPropTypes from '../appPropTypes'; -import Peer from '../Peer'; +import * as appPropTypes from './appPropTypes'; +import Peer from './Peer'; class Filmstrip extends Component { From 076441e2b5521a3309c79f7388f88176412a97af Mon Sep 17 00:00:00 2001 From: Torjus Date: Thu, 19 Jul 2018 16:29:11 +0200 Subject: [PATCH 04/14] Continue improving Filmstrip styling --- app/stylus/components/Filmstrip.styl | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/app/stylus/components/Filmstrip.styl b/app/stylus/components/Filmstrip.styl index fd59280..051249c 100644 --- a/app/stylus/components/Filmstrip.styl +++ b/app/stylus/components/Filmstrip.styl @@ -8,6 +8,11 @@ > .active-peer { width: 95vmin; padding: 10vmin 1vmin 1vmin 1vmin; + + > [data-component='Peer'] { + border: 5px solid rgba(255, 255, 255, 0.15); + box-shadow: 0px 5px 12px 2px rgba(17, 17, 17, 0.5); + } } > .filmstrip { @@ -17,15 +22,25 @@ > .film { height: 15vmin; - max-width: 15vmin * (2 * 4 / 3); margin: 1vmin; + border: 1px solid rgba(255, 255, 255, 0.15); + box-shadow: 0px 5px 12px 2px rgba(17, 17, 17, 0.5); + + > [data-component='Peer'] { + max-width: 15vmin * (4 / 3); + + &.screen { + max-width: 15vmin * (2 * 4 / 3); + border: 0; + } + } &.active { - border: 5px solid white; + border-color: #FFF; } &.selected { - border: 5px solid pink; + border-color: #377EFF; } } } From f6aee44df670555f5d01dc3a655b14db29d33f84 Mon Sep 17 00:00:00 2001 From: Torjus Date: Fri, 20 Jul 2018 09:52:16 +0200 Subject: [PATCH 05/14] Add overlay to the Filmstrip and scrollbar for horizontal overflow --- app/lib/components/Filmstrip.jsx | 10 ++++--- app/stylus/components/Filmstrip.styl | 44 ++++++++++++++++++---------- 2 files changed, 34 insertions(+), 20 deletions(-) diff --git a/app/lib/components/Filmstrip.jsx b/app/lib/components/Filmstrip.jsx index e0a16e9..f1607fd 100644 --- a/app/lib/components/Filmstrip.jsx +++ b/app/lib/components/Filmstrip.jsx @@ -48,10 +48,12 @@ class Filmstrip extends Component active : activeSpeakerName === peerName })} > - +
+ +
))}
diff --git a/app/stylus/components/Filmstrip.styl b/app/stylus/components/Filmstrip.styl index 051249c..1b1d590 100644 --- a/app/stylus/components/Filmstrip.styl +++ b/app/stylus/components/Filmstrip.styl @@ -17,30 +17,42 @@ > .filmstrip { display: flex; - padding: 0.5vmin; - cursor: pointer; + background: rgba(0, 0, 0 , 0.5); + width: 100%; + overflow-x: auto; + padding: 1vmin 0; > .film { height: 15vmin; - margin: 1vmin; - border: 1px solid rgba(255, 255, 255, 0.15); - box-shadow: 0px 5px 12px 2px rgba(17, 17, 17, 0.5); + flex-shrink: 0; + padding-left: 1vmin; - > [data-component='Peer'] { - max-width: 15vmin * (4 / 3); + &:last-child { + padding-right: 1vmin; + } - &.screen { - max-width: 15vmin * (2 * 4 / 3); - border: 0; + > .film-content { + height: 100%; + width: 100%; + border: 1px solid rgba(255,255,255,0.15); + + > [data-component='Peer'] { + max-width: 15vmin * (4 / 3); + cursor: pointer; + + &.screen { + max-width: 15vmin * (2 * 4 / 3); + border: 0; + } } - } - &.active { - border-color: #FFF; - } + &.active { + border-color: #FFF; + } - &.selected { - border-color: #377EFF; + &.selected { + border-color: #377EFF; + } } } } From d4e65e0c1bb49f9a4524da4862b4289df3695624 Mon Sep 17 00:00:00 2001 From: Torjus Date: Fri, 20 Jul 2018 09:55:26 +0200 Subject: [PATCH 06/14] Fix Filmstrip border colors --- app/stylus/components/Filmstrip.styl | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/stylus/components/Filmstrip.styl b/app/stylus/components/Filmstrip.styl index 1b1d590..d5a3e80 100644 --- a/app/stylus/components/Filmstrip.styl +++ b/app/stylus/components/Filmstrip.styl @@ -45,12 +45,16 @@ border: 0; } } + } - &.active { + &.active { + > .film-content { border-color: #FFF; } + } - &.selected { + &.selected { + > .film-content { border-color: #377EFF; } } From 0c3eb4f154ca26fdfb121ece4e0899c5f9673228 Mon Sep 17 00:00:00 2001 From: Torjus Date: Fri, 20 Jul 2018 10:16:32 +0200 Subject: [PATCH 07/14] Make Settings inputs controlled --- app/lib/components/Settings.jsx | 37 +++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/app/lib/components/Settings.jsx b/app/lib/components/Settings.jsx index 0f4c3b6..ba6db42 100644 --- a/app/lib/components/Settings.jsx +++ b/app/lib/components/Settings.jsx @@ -8,18 +8,34 @@ import Dropdown from 'react-dropdown'; class Settings extends React.Component { - constructor(props) + state = { + selectedCamera: null, + selectedAudioDevice: null + }; + + handleChangeWebcam = (webcam) => { - super(props); + this.props.handleChangeWebcam(webcam); + + this.setState({ + selectedCamera: webcam + }); } - render() + handleChangeAudioDevice = (device) => { + this.props.handleChangeAudioDevice(device); + + this.setState({ + selectedAudioDevice: device + }); + } + + render() + { const { room, me, - handleChangeWebcam, - handleChangeAudioDevice, onToggleAdvancedMode } = this.props; @@ -55,21 +71,24 @@ class Settings extends React.Component - Advanced mode +
); From bab4f420fd7a17176db1eb4417f848ba01c33997 Mon Sep 17 00:00:00 2001 From: Torjus Date: Fri, 20 Jul 2018 10:49:03 +0200 Subject: [PATCH 08/14] Add mode switch (democratic, filmstrip) to settings --- app/lib/components/Filmstrip.jsx | 3 +- app/lib/components/Peers.jsx | 16 ++++++--- app/lib/components/Room.jsx | 12 +++---- app/lib/components/Settings.jsx | 62 ++++++++++++++++++++------------ app/lib/redux/reducers/room.js | 7 +++- app/lib/redux/stateActions.js | 6 ++++ 6 files changed, 70 insertions(+), 36 deletions(-) diff --git a/app/lib/components/Filmstrip.jsx b/app/lib/components/Filmstrip.jsx index f1607fd..5e2f870 100644 --- a/app/lib/components/Filmstrip.jsx +++ b/app/lib/components/Filmstrip.jsx @@ -2,7 +2,6 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { connect } from 'react-redux'; import classnames from 'classnames'; -import * as appPropTypes from './appPropTypes'; import Peer from './Peer'; class Filmstrip extends Component @@ -65,7 +64,7 @@ class Filmstrip extends Component Filmstrip.propTypes = { activeSpeakerName : PropTypes.string, advancedMode : PropTypes.bool, - peers : appPropTypes.peers + peers : PropTypes.object.isRequired }; const mapStateToProps = (state) => diff --git a/app/lib/components/Peers.jsx b/app/lib/components/Peers.jsx index b219db5..de8cbbc 100644 --- a/app/lib/components/Peers.jsx +++ b/app/lib/components/Peers.jsx @@ -14,14 +14,22 @@ class Peers extends React.Component constructor(props) { super(props); + this.state = { peerWidth : 400, peerHeight : 300 }; + + this.peersRef = React.createRef(); } updateDimensions = () => { + if (!this.peersRef.current) + { + return; + } + const n = this.props.boxes; if (n === 0) @@ -29,8 +37,8 @@ class Peers extends React.Component return; } - const width = this.refs.peers.clientWidth; - const height = this.refs.peers.clientHeight; + const width = this.peersRef.current.clientWidth; + const height = this.peersRef.current.clientHeight; let x, y, space; @@ -64,7 +72,7 @@ class Peers extends React.Component window.addEventListener('resize', this.updateDimensions); const observer = new ResizeObserver(this.updateDimensions); - observer.observe(this.refs.peers); + observer.observe(this.peersRef.current); } componentWillUnmount() @@ -92,7 +100,7 @@ class Peers extends React.Component }; return ( -
+
{ peers.map((peer) => { diff --git a/app/lib/components/Room.jsx b/app/lib/components/Room.jsx index 0e81374..6aeb26e 100644 --- a/app/lib/components/Room.jsx +++ b/app/lib/components/Room.jsx @@ -65,6 +65,11 @@ class Room extends React.Component onRoomLinkCopy } = this.props; + const View = { + filmstrip : Filmstrip, + democratic : Peers + }[room.mode]; + return (
@@ -122,12 +127,7 @@ class Room extends React.Component
- - {false && ( - - )} +
{ - this.props.handleChangeWebcam(webcam); + this.props.handleChangeWebcam(webcam.value); this.setState({ - selectedCamera: webcam + selectedCamera : webcam }); } handleChangeAudioDevice = (device) => { - this.props.handleChangeAudioDevice(device); + this.props.handleChangeAudioDevice(device.value); this.setState({ - selectedAudioDevice: device + selectedAudioDevice : device }); } + handleChangeMode = (mode) => + { + this.setState({ + selectedMode : mode + }); + + this.props.handleChangeMode(mode.value); + }; + render() { const { @@ -75,6 +93,7 @@ class Settings extends React.Component onChange={this.handleChangeWebcam} placeholder={webcamText} /> + + + +
); @@ -101,7 +127,8 @@ Settings.propTypes = room : appPropTypes.Room.isRequired, handleChangeWebcam : PropTypes.func.isRequired, handleChangeAudioDevice : PropTypes.func.isRequired, - onToggleAdvancedMode : PropTypes.func.isRequired + onToggleAdvancedMode : PropTypes.func.isRequired, + handleChangeMode : PropTypes.func.isRequired }; const mapStateToProps = (state) => @@ -112,22 +139,11 @@ const mapStateToProps = (state) => }; }; -const mapDispatchToProps = (dispatch) => -{ - return { - handleChangeWebcam : (device) => - { - dispatch(requestActions.changeWebcam(device.value)); - }, - handleChangeAudioDevice : (device) => - { - dispatch(requestActions.changeAudioDevice(device.value)); - }, - onToggleAdvancedMode : () => - { - dispatch(stateActions.toggleAdvancedMode()); - } - }; +const mapDispatchToProps = { + handleChangeWebcam : requestActions.changeWebcam, + handleChangeAudioDevice : requestActions.changeAudioDevice, + onToggleAdvancedMode : stateActions.toggleAdvancedMode, + handleChangeMode : stateActions.setDisplayMode }; const SettingsContainer = connect( diff --git a/app/lib/redux/reducers/room.js b/app/lib/redux/reducers/room.js index e92196b..4a787de 100644 --- a/app/lib/redux/reducers/room.js +++ b/app/lib/redux/reducers/room.js @@ -6,7 +6,8 @@ const initialState = showSettings : false, advancedMode : false, fullScreenConsumer : null, // ConsumerID - toolbarsVisible : true + toolbarsVisible : true, + mode : 'democratic' }; const room = (state = initialState, action) => @@ -65,6 +66,10 @@ const room = (state = initialState, action) => return { ...state, toolbarsVisible }; } + + case 'SET_DISPLAY_MODE': + return { ...state, mode: action.payload.mode }; + default: return state; } diff --git a/app/lib/redux/stateActions.js b/app/lib/redux/stateActions.js index 9dcbb41..2c51b02 100644 --- a/app/lib/redux/stateActions.js +++ b/app/lib/redux/stateActions.js @@ -93,6 +93,12 @@ export const toggleAdvancedMode = () => }; }; +export const setDisplayMode = (mode) => + ({ + type : 'SET_DISPLAY_MODE', + payload : { mode } + }); + export const setAudioOnlyState = (enabled) => { return { From b9f4b6a812f09bfe894272df449226ad0a4905af Mon Sep 17 00:00:00 2001 From: Torjus Date: Fri, 20 Jul 2018 10:53:11 +0200 Subject: [PATCH 09/14] Ensure Filmstrip is always at the bottom of the page --- app/stylus/components/Filmstrip.styl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/stylus/components/Filmstrip.styl b/app/stylus/components/Filmstrip.styl index d5a3e80..d6edfc6 100644 --- a/app/stylus/components/Filmstrip.styl +++ b/app/stylus/components/Filmstrip.styl @@ -1,7 +1,6 @@ [data-component='Filmstrip'] { display: flex; flex-direction: column; - justify-content: space-between; align-items: center; height: 100%; @@ -21,6 +20,7 @@ width: 100%; overflow-x: auto; padding: 1vmin 0; + margin-top: auto; > .film { height: 15vmin; From e49cdcf88ebad57a85fb65158ee30dbaf790f310 Mon Sep 17 00:00:00 2001 From: Torjus Date: Fri, 20 Jul 2018 11:10:24 +0200 Subject: [PATCH 10/14] Move Me to the top of the screen to accomodate for the Filmstrip view --- app/stylus/components/Room.styl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/stylus/components/Room.styl b/app/stylus/components/Room.styl index 55dbe71..dcc62d5 100644 --- a/app/stylus/components/Room.styl +++ b/app/stylus/components/Room.styl @@ -153,13 +153,13 @@ } +desktop() { - bottom: 20px; + top: 20px; left: 20px; border: 1px solid rgba(#fff, 0.15); } +mobile() { - bottom: 10px; + top: 10px; left: 10px; border: 1px solid rgba(#fff, 0.25); } From e4f29b298ba0fa84bc3aabcf13e61fc9235caa6a Mon Sep 17 00:00:00 2001 From: Torjus Date: Fri, 20 Jul 2018 16:44:21 +0200 Subject: [PATCH 11/14] Force Filmstrip video to take as much space as possible --- app/lib/components/Filmstrip.jsx | 144 +++++++++++++++++++++------ app/stylus/components/Filmstrip.styl | 35 ++++--- 2 files changed, 135 insertions(+), 44 deletions(-) diff --git a/app/lib/components/Filmstrip.jsx b/app/lib/components/Filmstrip.jsx index 5e2f870..01552e4 100644 --- a/app/lib/components/Filmstrip.jsx +++ b/app/lib/components/Filmstrip.jsx @@ -1,15 +1,92 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; +import ResizeObserver from 'resize-observer-polyfill'; import { connect } from 'react-redux'; import classnames from 'classnames'; import Peer from './Peer'; class Filmstrip extends Component { + constructor(props) + { + super(props); + + this.activePeerContainer = React.createRef(); + } + state = { - selectedPeerName : null + selectedPeerName : 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.props.activeSpeakerName; + + isSharingCamera = (peerName) => this.props.peers[peerName] && + this.props.peers[peerName].consumers.some((consumer) => + this.props.consumers[consumer].source === 'screen'); + + getRatio = () => + { + let ratio = 4 / 3; + + if (this.isSharingCamera(this.getActivePeerName())) + { + ratio *= 2; + } + + return ratio; + }; + + updateDimensions = () => + { + const container = this.activePeerContainer.current; + + if (container) + { + const ratio = this.getRatio(); + + let width = container.clientWidth; + + if (width / ratio > container.clientHeight) + { + width = container.clientHeight * ratio; + } + + this.setState({ + width + }); + } + }; + + componentDidMount() + { + this.updateDimensions(); + } + + componentDidMount() + { + window.addEventListener('resize', this.updateDimensions); + const observer = new ResizeObserver(this.updateDimensions); + + observer.observe(this.activePeerContainer.current); + } + + componentWillUnmount() + { + window.removeEventListener('resize', this.updateDimensions); + } + + componentDidUpdate(prevProps) + { + if (prevProps !== this.props) + { + this.updateDimensions(); + } + } + handleSelectPeer = (selectedPeerName) => { this.setState((oldState) => ({ @@ -22,39 +99,44 @@ class Filmstrip extends Component { const { activeSpeakerName, peers, advancedMode } = this.props; - // Find the name of the peer which is currently speaking. This is either - // the latest active speaker, or the manually selected peer. - const activePeerName = this.state.selectedPeerName || activeSpeakerName; + const activePeerName = this.getActivePeerName(); return (
- {peers[activePeerName] && ( -
- -
- )} +
+ {peers[activePeerName] && ( +
+ +
+ )} +
- {Object.keys(peers).map((peerName) => ( -
this.handleSelectPeer(peerName)} - className={classnames('film', { - selected : this.state.selectedPeerName === peerName, - active : activeSpeakerName === peerName - })} - > -
- +
+ {Object.keys(peers).map((peerName) => ( +
this.handleSelectPeer(peerName)} + className={classnames('film', { + selected : this.state.selectedPeerName === peerName, + active : activeSpeakerName === peerName + })} + > +
+ +
-
- ))} + ))} +
); @@ -64,13 +146,15 @@ class Filmstrip extends Component Filmstrip.propTypes = { activeSpeakerName : PropTypes.string, advancedMode : PropTypes.bool, - peers : PropTypes.object.isRequired + peers : PropTypes.object.isRequired, + consumers : PropTypes.object.isRequired }; const mapStateToProps = (state) => ({ activeSpeakerName : state.room.activeSpeakerName, - peers : state.peers + peers : state.peers, + consumers : state.consumers }); export default connect( diff --git a/app/stylus/components/Filmstrip.styl b/app/stylus/components/Filmstrip.styl index d6edfc6..529f11b 100644 --- a/app/stylus/components/Filmstrip.styl +++ b/app/stylus/components/Filmstrip.styl @@ -4,13 +4,20 @@ align-items: center; height: 100%; - > .active-peer { - width: 95vmin; - padding: 10vmin 1vmin 1vmin 1vmin; + > .active-peer-container { + width: 100%; + height: 80vh; + display: flex; + justify-content: center; - > [data-component='Peer'] { - border: 5px solid rgba(255, 255, 255, 0.15); - box-shadow: 0px 5px 12px 2px rgba(17, 17, 17, 0.5); + > .active-peer { + width: 100%; + padding: 5vmin 1vmin 1vmin 1vmin; + + > [data-component='Peer'] { + border: 5px solid rgba(255, 255, 255, 0.15); + box-shadow: 0px 5px 12px 2px rgba(17, 17, 17, 0.5); + } } } @@ -19,16 +26,16 @@ background: rgba(0, 0, 0 , 0.5); width: 100%; overflow-x: auto; - padding: 1vmin 0; - margin-top: auto; + height: 20vh; + align-items: center; > .film { - height: 15vmin; - flex-shrink: 0; - padding-left: 1vmin; + height: 18vh; + flex-shrink: 0; + padding-left: 1vh; &:last-child { - padding-right: 1vmin; + padding-right: 1vh; } > .film-content { @@ -37,11 +44,11 @@ border: 1px solid rgba(255,255,255,0.15); > [data-component='Peer'] { - max-width: 15vmin * (4 / 3); + max-width: 17vh * (4 / 3); cursor: pointer; &.screen { - max-width: 15vmin * (2 * 4 / 3); + max-width: 17vh * (2 * 4 / 3); border: 0; } } From 86f0d56f00c545b95bbe0a3e73110cd6271a1741 Mon Sep 17 00:00:00 2001 From: Torjus Date: Fri, 20 Jul 2018 16:51:48 +0200 Subject: [PATCH 12/14] Center films in filmstrip --- app/stylus/components/Filmstrip.styl | 57 ++++++++++++++++------------ 1 file changed, 32 insertions(+), 25 deletions(-) diff --git a/app/stylus/components/Filmstrip.styl b/app/stylus/components/Filmstrip.styl index 529f11b..5b6bb1f 100644 --- a/app/stylus/components/Filmstrip.styl +++ b/app/stylus/components/Filmstrip.styl @@ -29,40 +29,47 @@ height: 20vh; align-items: center; - > .film { - height: 18vh; - flex-shrink: 0; - padding-left: 1vh; + > .filmstrip-content { + margin: 0 auto; + display: flex; + height: 100%; + align-items: center; - &:last-child { - padding-right: 1vh; - } + > .film { + height: 18vh; + flex-shrink: 0; + padding-left: 1vh; - > .film-content { - height: 100%; - width: 100%; - border: 1px solid rgba(255,255,255,0.15); + &:last-child { + padding-right: 1vh; + } - > [data-component='Peer'] { - max-width: 17vh * (4 / 3); - cursor: pointer; + > .film-content { + height: 100%; + width: 100%; + border: 1px solid rgba(255,255,255,0.15); - &.screen { - max-width: 17vh * (2 * 4 / 3); - border: 0; + > [data-component='Peer'] { + max-width: 18vh * (4 / 3); + cursor: pointer; + + &.screen { + max-width: 18vh * (2 * 4 / 3); + border: 0; + } } } - } - &.active { - > .film-content { - border-color: #FFF; + &.active { + > .film-content { + border-color: #FFF; + } } - } - &.selected { - > .film-content { - border-color: #377EFF; + &.selected { + > .film-content { + border-color: #377EFF; + } } } } From 32366163db75b49d4df59efb292bdba28f322409 Mon Sep 17 00:00:00 2001 From: Torjus Date: Mon, 23 Jul 2018 09:27:01 +0200 Subject: [PATCH 13/14] Never clear big film in Filmstrip view --- app/lib/components/Filmstrip.jsx | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/app/lib/components/Filmstrip.jsx b/app/lib/components/Filmstrip.jsx index 01552e4..54a46e1 100644 --- a/app/lib/components/Filmstrip.jsx +++ b/app/lib/components/Filmstrip.jsx @@ -16,13 +16,14 @@ 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. getActivePeerName = () => - this.state.selectedPeerName || this.props.activeSpeakerName; + this.state.selectedPeerName || this.state.lastSpeaker; isSharingCamera = (peerName) => this.props.peers[peerName] && this.props.peers[peerName].consumers.some((consumer) => @@ -61,17 +62,13 @@ class Filmstrip extends Component } }; - componentDidMount() - { - this.updateDimensions(); - } - componentDidMount() { window.addEventListener('resize', this.updateDimensions); const observer = new ResizeObserver(this.updateDimensions); observer.observe(this.activePeerContainer.current); + this.updateDimensions(); } componentWillUnmount() @@ -84,6 +81,14 @@ class Filmstrip extends Component if (prevProps !== this.props) { this.updateDimensions(); + + if (this.props.activeSpeakerName !== this.props.myName) + { + // eslint-disable-next-line react/no-did-update-set-state + this.setState({ + lastSpeaker : this.props.activeSpeakerName + }); + } } } @@ -97,7 +102,7 @@ class Filmstrip extends Component render() { - const { activeSpeakerName, peers, advancedMode } = this.props; + const { peers, advancedMode } = this.props; const activePeerName = this.getActivePeerName(); @@ -107,7 +112,10 @@ class Filmstrip extends Component {peers[activePeerName] && (
this.handleSelectPeer(peerName)} className={classnames('film', { selected : this.state.selectedPeerName === peerName, - active : activeSpeakerName === peerName + active : this.state.lastSpeaker === peerName })} >
@@ -147,14 +155,16 @@ Filmstrip.propTypes = { activeSpeakerName : PropTypes.string, advancedMode : PropTypes.bool, peers : PropTypes.object.isRequired, - consumers : PropTypes.object.isRequired + consumers : PropTypes.object.isRequired, + myName : PropTypes.string.isRequired }; const mapStateToProps = (state) => ({ activeSpeakerName : state.room.activeSpeakerName, peers : state.peers, - consumers : state.consumers + consumers : state.consumers, + myName : state.me.name }); export default connect( From 7239dffad5daecd09960dcddc3d94042314c35e4 Mon Sep 17 00:00:00 2001 From: Torjus Date: Mon, 23 Jul 2018 09:29:11 +0200 Subject: [PATCH 14/14] Always vertically center the big film in Filmstrip view --- app/stylus/components/Filmstrip.styl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/stylus/components/Filmstrip.styl b/app/stylus/components/Filmstrip.styl index 5b6bb1f..65b94ef 100644 --- a/app/stylus/components/Filmstrip.styl +++ b/app/stylus/components/Filmstrip.styl @@ -9,10 +9,11 @@ height: 80vh; display: flex; justify-content: center; + align-items: center; > .active-peer { width: 100%; - padding: 5vmin 1vmin 1vmin 1vmin; + padding: 1vmin; > [data-component='Peer'] { border: 5px solid rgba(255, 255, 255, 0.15);