Added user interface for lastN (only peers in lastN are visible, others stay in HiddenPeers component)
parent
d7ce8253e2
commit
ed5ef29fba
|
|
@ -6,6 +6,7 @@ import debounce from 'lodash/debounce';
|
|||
import classnames from 'classnames';
|
||||
import * as stateActions from '../redux/stateActions';
|
||||
import Peer from './Peer';
|
||||
import HiddenPeers from './HiddenPeers';
|
||||
|
||||
class Filmstrip extends Component
|
||||
{
|
||||
|
|
@ -113,7 +114,7 @@ class Filmstrip extends Component
|
|||
|
||||
render()
|
||||
{
|
||||
const { peers, advancedMode } = this.props;
|
||||
const { peers, advancedMode, lastN, lastNLength } = this.props;
|
||||
|
||||
const activePeerName = this.getActivePeerName();
|
||||
|
||||
|
|
@ -138,25 +139,40 @@ class Filmstrip extends Component
|
|||
|
||||
<div className='filmstrip'>
|
||||
<div className='filmstrip-content'>
|
||||
{Object.keys(peers).map((peerName) => (
|
||||
<div
|
||||
key={peerName}
|
||||
onClick={() => this.props.setSelectedPeer(peerName)}
|
||||
className={classnames('film', {
|
||||
selected : this.props.selectedPeerName === peerName,
|
||||
active : this.state.lastSpeaker === peerName
|
||||
})}
|
||||
>
|
||||
<div className='film-content'>
|
||||
<Peer
|
||||
advancedMode={advancedMode}
|
||||
name={peerName}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
{
|
||||
Object.keys(peers).map((peerName) =>
|
||||
{
|
||||
return (
|
||||
lastN.find((lastNElement) => lastNElement === peerName)?
|
||||
<div
|
||||
key={peerName}
|
||||
onClick={() => this.props.setSelectedPeer(peerName)}
|
||||
className={classnames('film', {
|
||||
selected : this.props.selectedPeerName === peerName,
|
||||
active : this.state.lastSpeaker === peerName
|
||||
})}
|
||||
>
|
||||
<div className='film-content'>
|
||||
<Peer
|
||||
advancedMode={advancedMode}
|
||||
name={peerName}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
:null
|
||||
);
|
||||
})
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<div className='hidden-peer-container'>
|
||||
{ (lastNLength<Object.keys(peers).length)?
|
||||
<HiddenPeers
|
||||
lastNLength={Object.keys(peers).length-lastNLength}
|
||||
/>:null
|
||||
}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -169,16 +185,25 @@ Filmstrip.propTypes = {
|
|||
consumers : PropTypes.object.isRequired,
|
||||
myName : PropTypes.string.isRequired,
|
||||
selectedPeerName : PropTypes.string,
|
||||
setSelectedPeer : PropTypes.func.isRequired
|
||||
setSelectedPeer : PropTypes.func.isRequired,
|
||||
lastNLength : PropTypes.number,
|
||||
lastN : PropTypes.array.isRequired
|
||||
};
|
||||
|
||||
const mapStateToProps = (state) => ({
|
||||
activeSpeakerName : state.room.activeSpeakerName,
|
||||
selectedPeerName : state.room.selectedPeerName,
|
||||
peers : state.peers,
|
||||
consumers : state.consumers,
|
||||
myName : state.me.name
|
||||
});
|
||||
const mapStateToProps = (state) =>
|
||||
{
|
||||
const lastNLength = state.room.lastN ? state.room.lastN.length : 0;
|
||||
|
||||
return {
|
||||
activeSpeakerName : state.room.activeSpeakerName,
|
||||
selectedPeerName : state.room.selectedPeerName,
|
||||
peers : state.peers,
|
||||
consumers : state.consumers,
|
||||
myName : state.me.name,
|
||||
lastN : state.room.lastN,
|
||||
lastNLength
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = {
|
||||
setSelectedPeer : stateActions.setSelectedPeer
|
||||
|
|
|
|||
|
|
@ -0,0 +1,71 @@
|
|||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import PropTypes from 'prop-types';
|
||||
import * as stateActions from '../redux/stateActions';
|
||||
|
||||
class HiddenPeers extends Component
|
||||
{
|
||||
state = {
|
||||
controlsVisible : false
|
||||
};
|
||||
|
||||
handleMouseOver = () =>
|
||||
{
|
||||
this.setState({
|
||||
controlsVisible : true
|
||||
});
|
||||
};
|
||||
|
||||
handleMouseOut = () =>
|
||||
{
|
||||
this.setState({
|
||||
controlsVisible : false
|
||||
});
|
||||
};
|
||||
|
||||
render()
|
||||
{
|
||||
const {
|
||||
lastNLength,
|
||||
openUsersTab
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<div
|
||||
data-component='HiddenPeers'
|
||||
onMouseOver={this.handleMouseOver}
|
||||
onMouseOut={this.handleMouseOut}
|
||||
>
|
||||
<div data-component='HiddenPeersView'>
|
||||
<div className='view-container' onClick={() => openUsersTab()}>
|
||||
<p>+{lastNLength} <br /> participant(s)</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
HiddenPeers.propTypes =
|
||||
{
|
||||
lastNLength : 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;
|
||||
|
|
@ -6,6 +6,7 @@ import debounce from 'lodash/debounce';
|
|||
import * as appPropTypes from './appPropTypes';
|
||||
import { Appear } from './transitions';
|
||||
import Peer from './Peer';
|
||||
import HiddenPeers from './HiddenPeers';
|
||||
import ResizeObserver from 'resize-observer-polyfill';
|
||||
|
||||
const RATIO = 1.334;
|
||||
|
|
@ -91,7 +92,9 @@ class Peers extends React.Component
|
|||
const {
|
||||
advancedMode,
|
||||
activeSpeakerName,
|
||||
peers
|
||||
peers,
|
||||
lastN,
|
||||
lastNLength
|
||||
} = this.props;
|
||||
|
||||
const style =
|
||||
|
|
@ -106,22 +109,32 @@ class Peers extends React.Component
|
|||
peers.map((peer) =>
|
||||
{
|
||||
return (
|
||||
<Appear key={peer.name} duration={1000}>
|
||||
<div
|
||||
className={classnames('peer-container', {
|
||||
'active-speaker' : peer.name === activeSpeakerName
|
||||
})}
|
||||
>
|
||||
<Peer
|
||||
advancedMode={advancedMode}
|
||||
name={peer.name}
|
||||
style={style}
|
||||
/>
|
||||
</div>
|
||||
</Appear>
|
||||
(lastN.find(function(lastNElement)
|
||||
{ return lastNElement == peer.name; }))?
|
||||
<Appear key={peer.name} duration={1000}>
|
||||
<div
|
||||
className={classnames('peer-container', {
|
||||
'active-speaker' : peer.name === activeSpeakerName
|
||||
})}
|
||||
>
|
||||
<Peer
|
||||
advancedMode={advancedMode}
|
||||
name={peer.name}
|
||||
style={style}
|
||||
/>
|
||||
</div>
|
||||
</Appear>
|
||||
:null
|
||||
);
|
||||
})
|
||||
}
|
||||
<div className='hidden-peer-container'>
|
||||
{ (lastNLength<peers.length)?
|
||||
<HiddenPeers
|
||||
lastNLength={peers.length-lastNLength}
|
||||
/>:null
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -132,20 +145,25 @@ Peers.propTypes =
|
|||
advancedMode : PropTypes.bool,
|
||||
peers : PropTypes.arrayOf(appPropTypes.Peer).isRequired,
|
||||
boxes : PropTypes.number,
|
||||
activeSpeakerName : PropTypes.string
|
||||
activeSpeakerName : PropTypes.string,
|
||||
lastNLength : PropTypes.number,
|
||||
lastN : PropTypes.array.isRequired
|
||||
};
|
||||
|
||||
const mapStateToProps = (state) =>
|
||||
{
|
||||
const peers = Object.values(state.peers);
|
||||
|
||||
const boxes = peers.length + Object.values(state.consumers)
|
||||
const lastN = state.room.lastN;
|
||||
const lastNLength = lastN ? state.room.lastN.length : 0;
|
||||
const boxes = lastNLength + Object.values(state.consumers)
|
||||
.filter((consumer) => consumer.source === 'screen').length;
|
||||
|
||||
return {
|
||||
peers,
|
||||
boxes,
|
||||
activeSpeakerName : state.room.activeSpeakerName
|
||||
activeSpeakerName : state.room.activeSpeakerName,
|
||||
lastN,
|
||||
lastNLength
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ const initialState =
|
|||
toolbarsVisible : true,
|
||||
mode : 'democratic',
|
||||
selectedPeerName : null,
|
||||
lastN : null
|
||||
lastN : []
|
||||
};
|
||||
|
||||
const room = (state = initialState, action) =>
|
||||
|
|
|
|||
|
|
@ -19,6 +19,22 @@ const toolarea = (state = initialState, action) =>
|
|||
return { ...state, toolAreaOpen, unreadMessages, unreadFiles };
|
||||
}
|
||||
|
||||
case 'OPEN_TOOL_AREA':
|
||||
{
|
||||
const toolAreaOpen = true;
|
||||
const unreadMessages = state.currentToolTab === 'chat' ? 0 : state.unreadMessages;
|
||||
const unreadFiles = state.currentToolTab === 'files' ? 0 : state.unreadFiles;
|
||||
|
||||
return { ...state, toolAreaOpen, unreadMessages, unreadFiles };
|
||||
}
|
||||
|
||||
case 'CLOSE_TOOL_AREA':
|
||||
{
|
||||
const toolAreaOpen = false;
|
||||
|
||||
return { ...state, toolAreaOpen };
|
||||
}
|
||||
|
||||
case 'SET_TOOL_TAB':
|
||||
{
|
||||
const { toolTab } = action.payload;
|
||||
|
|
|
|||
|
|
@ -161,6 +161,20 @@ export const toggleToolArea = () =>
|
|||
};
|
||||
};
|
||||
|
||||
export const openToolArea = () =>
|
||||
{
|
||||
return {
|
||||
type : 'OPEN_TOOL_AREA'
|
||||
};
|
||||
};
|
||||
|
||||
export const closeToolArea = () =>
|
||||
{
|
||||
return {
|
||||
type : 'CLOSE_TOOL_AREA'
|
||||
};
|
||||
};
|
||||
|
||||
export const setToolTab = (toolTab) =>
|
||||
{
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,65 @@
|
|||
[data-component='HiddenPeersView'] {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
> .info {
|
||||
$backgroundTint = #000;
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
top: 0.6vmin;
|
||||
left: 0.6vmin;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
}
|
||||
> .view-container {
|
||||
width: 12vmin;
|
||||
height: 9vmin;
|
||||
position: absolute;
|
||||
bottom: 3%;
|
||||
right: 3%;
|
||||
color: #aaa;
|
||||
background-image: url('/resources/images/buddy.svg');
|
||||
background-color: rgba(#2a4b58, 1);
|
||||
background-position: bottom;
|
||||
background-size: auto 85%;
|
||||
background-repeat: no-repeat;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
line-height: 1.8vmin;
|
||||
font-size: 1.7vmin;
|
||||
}
|
||||
.view-container>p{
|
||||
transform: translate(0%,50%);
|
||||
}
|
||||
.view-container,
|
||||
.view-container::before,
|
||||
.view-container::after {
|
||||
/* Add shadow to distinguish sheets from one another */
|
||||
box-shadow: 2px 1px 1px rgba(0,0,0,0.15);
|
||||
}
|
||||
.view-container::before,
|
||||
.view-container::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #2a4b58;
|
||||
}
|
||||
/* Second sheet of paper */
|
||||
.view-container::before {
|
||||
left: .7vmin;
|
||||
top: .7vmin;
|
||||
z-index: -1;
|
||||
}
|
||||
/* Third sheet of paper */
|
||||
.view-container::after {
|
||||
left: 1.4vmin;
|
||||
top: 1.4vmin;
|
||||
z-index: -2;
|
||||
}
|
||||
}
|
||||
|
|
@ -47,6 +47,7 @@ body {
|
|||
@import './components/Peers';
|
||||
@import './components/Peer';
|
||||
@import './components/PeerView';
|
||||
@import './components/HiddenPeersView';
|
||||
@import './components/ScreenView';
|
||||
@import './components/Notifications';
|
||||
@import './components/Chat';
|
||||
|
|
|
|||
Loading…
Reference in New Issue