+ { videoVisible && !webcamConsumer.supported ?
+
+ :null
+ }
- if (screenConsumer)
- screenProfile = screenConsumer.profile;
+ { !videoVisible ?
+
+ :null
+ }
- return (
-
- { videoVisible && !webcamConsumer.supported ?
-
- :null
- }
-
- { !videoVisible ?
-
- :null
- }
-
-
-
+
+
+ {
+ micEnabled ?
+ roomClient.modifyPeerConsumer(peer.name, 'mic', true) :
+ roomClient.modifyPeerConsumer(peer.name, 'mic', false);
+ }}
>
-
- {
- e.stopPropagation();
- micEnabled ?
- roomClient.modifyPeerConsumer(peer.name, 'mic', true) :
- roomClient.modifyPeerConsumer(peer.name, 'mic', false);
- }}
- >
- { micEnabled ?
-
- :
-
- }
-
+ { micEnabled ?
+
+ :
+
+ }
+
-
+ { !smallScreen ?
+
{
- e.stopPropagation();
toggleConsumerWindow(webcamConsumer);
}}
>
-
+
+ :null
+ }
-
- {
- e.stopPropagation();
- toggleConsumerFullscreen(webcamConsumer);
- }}
- >
-
-
-
-
-
+
+ {
+ toggleConsumerFullscreen(webcamConsumer);
+ }}
+ >
+
+
- { screenConsumer ?
-
-
-
+
+ { screenConsumer ?
+
+
+ { !smallScreen ?
+
{
- e.stopPropagation();
toggleConsumerWindow(screenConsumer);
}}
>
-
+
+ :null
+ }
-
- {
- e.stopPropagation();
- toggleConsumerFullscreen(screenConsumer);
- }}
- >
-
-
-
-
+
+ {
+ toggleConsumerFullscreen(screenConsumer);
+ }}
+ >
+
+
- :null
- }
-
- );
- }
-}
+
+
+ :null
+ }
+
+ );
+};
Peer.propTypes =
{
@@ -351,7 +303,8 @@ Peer.propTypes =
style : PropTypes.object,
toggleConsumerFullscreen : PropTypes.func.isRequired,
toggleConsumerWindow : PropTypes.func.isRequired,
- classes : PropTypes.object
+ classes : PropTypes.object.isRequired,
+ theme : PropTypes.object.isRequired
};
const mapStateToProps = (state, { name }) =>
@@ -394,4 +347,4 @@ const mapDispatchToProps = (dispatch) =>
export default withRoomContext(connect(
mapStateToProps,
mapDispatchToProps
-)(withStyles(styles)(Peer)));
+)(withStyles(styles, { withTheme: true })(Peer)));
diff --git a/app/src/components/Controls/Sidebar.js b/app/src/components/Controls/Sidebar.js
index c2bbbe7..d163552 100644
--- a/app/src/components/Controls/Sidebar.js
+++ b/app/src/components/Controls/Sidebar.js
@@ -2,34 +2,49 @@ import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { withStyles } from '@material-ui/core/styles';
+import { unstable_useMediaQuery as useMediaQuery } from '@material-ui/core/useMediaQuery';
import classnames from 'classnames';
import * as appPropTypes from '../appPropTypes';
import { withRoomContext } from '../../RoomContext';
import Fab from '@material-ui/core/Fab';
-import Avatar from '@material-ui/core/Avatar';
+// import Avatar from '@material-ui/core/Avatar';
+import MicIcon from '@material-ui/icons/Mic';
+import MicOffIcon from '@material-ui/icons/MicOff';
+import VideoIcon from '@material-ui/icons/Videocam';
+import VideoOffIcon from '@material-ui/icons/VideocamOff';
import ScreenIcon from '@material-ui/icons/ScreenShare';
import ScreenOffIcon from '@material-ui/icons/StopScreenShare';
import ExtensionIcon from '@material-ui/icons/Extension';
import LockIcon from '@material-ui/icons/Lock';
import LockOpenIcon from '@material-ui/icons/LockOpen';
-import HandOff from '../../images/icon-hand-black.svg';
-import HandOn from '../../images/icon-hand-white.svg';
+// import HandOff from '../../images/icon-hand-black.svg';
+// import HandOn from '../../images/icon-hand-white.svg';
import LeaveIcon from '@material-ui/icons/Cancel';
const styles = (theme) =>
({
root :
{
- position : 'fixed',
- zIndex : 500,
- top : '50%',
- transform : 'translate(0%, -50%)',
- display : 'flex',
- flexDirection : 'column',
- justifyContent : 'center',
- alignItems : 'center',
- left : '1.0em',
- width : '2.6em'
+ position : 'fixed',
+ zIndex : 500,
+ display : 'flex',
+ [theme.breakpoints.up('md')] :
+ {
+ top : '50%',
+ transform : 'translate(0%, -50%)',
+ flexDirection : 'column',
+ justifyContent : 'center',
+ alignItems : 'center',
+ left : '1.0em',
+ width : '2.6em'
+ },
+ [theme.breakpoints.down('sm')] :
+ {
+ flexDirection : 'row',
+ bottom : '0.5em',
+ left : '50%',
+ transform : 'translate(-50%, -0%)'
+ }
},
fab :
{
@@ -47,150 +62,218 @@ const styles = (theme) =>
}
});
-class Sidebar extends React.PureComponent
+const Sidebar = (props) =>
{
- render()
+ const {
+ roomClient,
+ toolbarsVisible,
+ me,
+ micProducer,
+ webcamProducer,
+ screenProducer,
+ locked,
+ classes,
+ theme
+ } = props;
+
+ let micState;
+
+ if (!me.canSendMic)
+ micState = 'unsupported';
+ else if (!micProducer)
+ micState = 'unsupported';
+ else if (!micProducer.locallyPaused && !micProducer.remotelyPaused)
+ micState = 'on';
+ else
+ micState = 'off';
+
+ let webcamState;
+
+ if (!me.canSendWebcam)
+ webcamState = 'unsupported';
+ else if (webcamProducer)
+ webcamState = 'on';
+ else
+ webcamState = 'off';
+
+ let screenState;
+
+ if (me.needExtension)
{
- const {
- roomClient,
- toolbarsVisible,
- me,
- screenProducer,
- locked,
- classes
- } = this.props;
-
- let screenState;
-
- if (me.needExtension)
- {
- screenState = 'need-extension';
- }
- else if (!me.canShareScreen)
- {
- screenState = 'unsupported';
- }
- else if (screenProducer)
- {
- screenState = 'on';
- }
- else
- {
- screenState = 'off';
- }
-
- return (
-
-
- {
- switch (screenState)
- {
- case 'on':
- {
- roomClient.disableScreenSharing();
- break;
- }
- case 'off':
- {
- roomClient.enableScreenSharing();
- break;
- }
- case 'need-extension':
- {
- roomClient.installExtension();
- break;
- }
- default:
- {
- break;
- }
- }
- }}
- >
- { screenState === 'on' || screenState === 'unsupported' ?
-
- :null
- }
- { screenState === 'off' ?
-
- :null
- }
- { screenState === 'need-extension' ?
-
- :null
- }
-
-
-
- {
- if (locked)
- {
- roomClient.unlockRoom();
- }
- else
- {
- roomClient.lockRoom();
- }
- }}
- >
- { locked ?
-
- :
-
- }
-
-
-
roomClient.sendRaiseHandState(!me.raiseHand)}
- >
-
-
-
-
roomClient.close()}
- >
-
-
-
- );
+ screenState = 'need-extension';
}
-}
+ else if (!me.canShareScreen)
+ {
+ screenState = 'unsupported';
+ }
+ else if (screenProducer)
+ {
+ screenState = 'on';
+ }
+ else
+ {
+ screenState = 'off';
+ }
+
+ const smallScreen = useMediaQuery(theme.breakpoints.down('sm'));
+
+ return (
+
+
+ {
+ micState === 'on' ?
+ roomClient.muteMic() :
+ roomClient.unmuteMic();
+ }}
+ >
+ { micState === 'on' ?
+
+ :
+
+ }
+
+
+ {
+ webcamState === 'on' ?
+ roomClient.disableWebcam() :
+ roomClient.enableWebcam();
+ }}
+ >
+ { webcamState === 'on' ?
+
+ :
+
+ }
+
+
+ {
+ switch (screenState)
+ {
+ case 'on':
+ {
+ roomClient.disableScreenSharing();
+ break;
+ }
+ case 'off':
+ {
+ roomClient.enableScreenSharing();
+ break;
+ }
+ case 'need-extension':
+ {
+ roomClient.installExtension();
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ }}
+ >
+ { screenState === 'on' || screenState === 'unsupported' ?
+
+ :null
+ }
+ { screenState === 'off' ?
+
+ :null
+ }
+ { screenState === 'need-extension' ?
+
+ :null
+ }
+
+
+
+ {
+ if (locked)
+ {
+ roomClient.unlockRoom();
+ }
+ else
+ {
+ roomClient.lockRoom();
+ }
+ }}
+ >
+ { locked ?
+
+ :
+
+ }
+
+
+ { /*
roomClient.sendRaiseHandState(!me.raiseHand)}
+ >
+
+ */ }
+
+
roomClient.close()}
+ >
+
+
+
+ );
+};
Sidebar.propTypes =
{
roomClient : PropTypes.any.isRequired,
toolbarsVisible : PropTypes.bool.isRequired,
me : appPropTypes.Me.isRequired,
+ micProducer : appPropTypes.Producer,
+ webcamProducer : appPropTypes.Producer,
screenProducer : appPropTypes.Producer,
locked : PropTypes.bool.isRequired,
- classes : PropTypes.object.isRequired
+ classes : PropTypes.object.isRequired,
+ theme : PropTypes.object.isRequired
};
const mapStateToProps = (state) =>
({
toolbarsVisible : state.room.toolbarsVisible,
- screenProducer : Object.values(state.producers)
+ micProducer : Object.values(state.producers)
+ .find((producer) => producer.source === 'mic'),
+ webcamProducer : Object.values(state.producers)
+ .find((producer) => producer.source === 'webcam'),
+ screenProducer : Object.values(state.producers)
.find((producer) => producer.source === 'screen'),
me : state.me,
locked : state.room.locked
@@ -198,4 +281,4 @@ const mapStateToProps = (state) =>
export default withRoomContext(connect(
mapStateToProps
-)(withStyles(styles)(Sidebar)));
+)(withStyles(styles, { withTheme: true })(Sidebar)));
diff --git a/app/src/components/MeetingViews/Democratic.js b/app/src/components/MeetingViews/Democratic.js
index ec2b44c..84efee3 100644
--- a/app/src/components/MeetingViews/Democratic.js
+++ b/app/src/components/MeetingViews/Democratic.js
@@ -5,11 +5,12 @@ import classnames from 'classnames';
import debounce from 'lodash/debounce';
import { withStyles } from '@material-ui/core/styles';
import Peer from '../Containers/Peer';
+import Me from '../Containers/Me';
import HiddenPeers from '../Containers/HiddenPeers';
import ResizeObserver from 'resize-observer-polyfill';
const RATIO = 1.334;
-const PADDING = 100;
+const PADDING = 60;
const styles = () =>
({
@@ -23,7 +24,7 @@ const styles = () =>
justifyContent : 'center',
alignItems : 'center',
alignContent : 'center',
- paddingTop : 70,
+ paddingTop : 30,
paddingBottom : 30
},
peerContainer :
@@ -126,6 +127,7 @@ class Democratic extends React.PureComponent
const {
advancedMode,
activeSpeakerName,
+ amActiveSpeaker,
peers,
spotlights,
spotlightsLength,
@@ -140,6 +142,16 @@ class Democratic extends React.PureComponent
return (
+
+
+
{ Object.keys(peers).map((peerName) =>
{
if (spotlights.find((spotlightsElement) => spotlightsElement === peerName))
@@ -181,6 +193,7 @@ Democratic.propTypes =
advancedMode : PropTypes.bool,
peers : PropTypes.object.isRequired,
boxes : PropTypes.number,
+ amActiveSpeaker : PropTypes.bool.isRequired,
activeSpeakerName : PropTypes.string,
selectedPeerName : PropTypes.string,
spotlightsLength : PropTypes.number,
@@ -193,13 +206,15 @@ const mapStateToProps = (state) =>
const spotlights = state.room.spotlights;
const spotlightsLength = spotlights ? state.room.spotlights.length : 0;
const boxes = spotlightsLength + Object.values(state.consumers)
- .filter((consumer) => consumer.source === 'screen').length;
+ .filter((consumer) => consumer.source === 'screen').length + Object.values(state.producers)
+ .filter((producer) => producer.source === 'screen').length + 1;
return {
peers : state.peers,
boxes,
activeSpeakerName : state.room.activeSpeakerName,
selectedPeerName : state.room.selectedPeerName,
+ amActiveSpeaker : state.me.name === state.room.activeSpeakerName,
spotlights,
spotlightsLength
};
diff --git a/app/src/components/Room.js b/app/src/components/Room.js
index 0c3604d..b1dd671 100644
--- a/app/src/components/Room.js
+++ b/app/src/components/Room.js
@@ -2,11 +2,11 @@ import React from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import * as appPropTypes from './appPropTypes';
-import classnames from 'classnames';
+// import classnames from 'classnames';
import { withRoomContext } from '../RoomContext';
import { withStyles } from '@material-ui/core/styles';
import * as stateActions from '../actions/stateActions';
-import Draggable from 'react-draggable';
+// import Draggable from 'react-draggable';
import { idle } from '../utils';
import FullScreen from './FullScreen';
import CookieConsent from 'react-cookie-consent';
@@ -26,7 +26,7 @@ import Notifications from './Notifications/Notifications';
import MeetingDrawer from './MeetingDrawer/MeetingDrawer';
import Democratic from './MeetingViews/Democratic';
import Filmstrip from './MeetingViews/Filmstrip';
-import Me from './Containers/Me';
+// import Me from './Containers/Me';
import AudioPeers from './PeerAudio/AudioPeers';
import FullScreenView from './VideoContainers/FullScreenView';
import VideoWindow from './VideoWindow/VideoWindow';
@@ -68,7 +68,12 @@ const styles = (theme) =>
},
logo :
{
- marginLeft : 20
+ display : 'none',
+ marginLeft : 20,
+ [theme.breakpoints.up('sm')] :
+ {
+ display : 'block'
+ }
},
show :
{
@@ -126,8 +131,8 @@ const styles = (theme) =>
boxShadow : 'var(--me-shadow)',
transitionProperty : 'border-color',
transitionDuration : '0.15s',
- top : '8%',
- left : '1%',
+ top : '5em',
+ left : '1em',
border : 'var(--me-border)',
'&.active-speaker' :
{
@@ -215,7 +220,7 @@ class Room extends React.PureComponent
roomClient,
room,
me,
- amActiveSpeaker,
+ // amActiveSpeaker,
setSettingsOpen,
toolAreaOpen,
toggleToolArea,
@@ -337,7 +342,8 @@ class Room extends React.PureComponent
{
+ onClick={() =>
+{
me.loggedIn ? roomClient.logout() : roomClient.login();
}}
>
@@ -367,6 +373,7 @@ class Room extends React.PureComponent
+ { /*
+ */ }
@@ -393,7 +401,7 @@ Room.propTypes =
roomClient : PropTypes.object.isRequired,
room : appPropTypes.Room.isRequired,
me : appPropTypes.Me.isRequired,
- amActiveSpeaker : PropTypes.bool.isRequired,
+ // amActiveSpeaker : PropTypes.bool.isRequired,
toolAreaOpen : PropTypes.bool.isRequired,
screenProducer : appPropTypes.Producer,
setToolbarsVisible : PropTypes.func.isRequired,
@@ -411,13 +419,13 @@ const mapStateToProps = (state) =>
producersArray.find((producer) => producer.source === 'screen');
return {
- room : state.room,
- me : state.me,
- amActiveSpeaker : state.me.name === state.room.activeSpeakerName,
- screenProducer : screenProducer,
- toolAreaOpen : state.toolarea.toolAreaOpen,
- unread : state.toolarea.unreadMessages +
+ room : state.room,
+ me : state.me,
+ screenProducer : screenProducer,
+ toolAreaOpen : state.toolarea.toolAreaOpen,
+ unread : state.toolarea.unreadMessages +
state.toolarea.unreadFiles
+ // amActiveSpeaker : state.me.name === state.room.activeSpeakerName,
};
};
diff --git a/app/src/index.css b/app/src/index.css
index 7eb8228..7624529 100644
--- a/app/src/index.css
+++ b/app/src/index.css
@@ -1,17 +1,6 @@
:root {
--background-color: rgba(114, 119, 143, 1.0);
- --media-control-button-color: rgba(255, 255, 255, 0.85);
- --media-control-botton-on: rgba(255, 255, 255, 0.7);
- --media-control-botton-off: rgba(212, 34, 65, 0.7);
- --media-control-botton-disabled: rgba(255, 255, 255, 0.5);
- --media-control-button-size: 1.5em;
-
- --me-shadow: 0px 1px 5px 0px rgba(0, 0, 0, 0.2), 0px 2px 2px 0px rgba(0, 0, 0, 0.14), 0px 3px 1px -2px rgba(0, 0, 0, 0.12);
- --me-border: 1px solid rgba(255, 255, 255, 0.15);
- --me-width: 20vmin;
- --me-height: 15vmin;
-
--peer-shadow: 0px 1px 5px 0px rgba(0, 0, 0, 0.2), 0px 2px 2px 0px rgba(0, 0, 0, 0.14), 0px 3px 1px -2px rgba(0, 0, 0, 0.12);
--peer-border: 1px solid rgba(255, 255, 255, 0.15);
--peer-empty-avatar: url('./images/buddy.svg');