diff --git a/app/src/components/Containers/Me.js b/app/src/components/Containers/Me.js index 5c0ba90..0128be2 100644 --- a/app/src/components/Containers/Me.js +++ b/app/src/components/Containers/Me.js @@ -9,10 +9,6 @@ import { getDeviceInfo } from 'mediasoup-client'; import * as appPropTypes from '../appPropTypes'; import PeerView from '../VideoContainers/PeerView'; import ScreenView from '../VideoContainers/ScreenView'; -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'; const styles = () => ({ @@ -36,53 +32,6 @@ const styles = () => { order : 1 } - }, - controls : - { - position : 'absolute', - right : 0, - top : 0, - display : 'flex', - flexDirection : 'row', - padding : '0.4vmin', - zIndex : 20, - opacity : 0, - transition : 'opacity 0.3s', - '&.visible' : - { - opacity : 1 - } - }, - button : - { - flex : '0 0 auto', - margin : '0.2vmin', - borderRadius : 2, - opacity : 0.85, - width : 'var(--media-control-button-size)', - height : 'var(--media-control-button-size)', - backgroundColor : 'var(--media-control-button-color)', - '&:hover' : - { - opacity : 1 - }, - '&.unsupported' : - { - pointerEvents : 'none' - }, - '&.disabled' : - { - pointerEvents : 'none', - backgroundColor : 'var(--media-control-botton-disabled)' - }, - '&.on' : - { - backgroundColor : 'var(--media-control-botton-on)' - }, - '&.off' : - { - backgroundColor : 'var(--media-control-botton-off)' - } } }); @@ -124,8 +73,8 @@ class Me extends React.PureComponent { const { roomClient, - connected, me, + style, advancedMode, micProducer, webcamProducer, @@ -133,26 +82,6 @@ class Me extends React.PureComponent classes } = this.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'; - const videoVisible = ( Boolean(webcamProducer) && !webcamProducer.locallyPaused && @@ -180,57 +109,7 @@ class Me extends React.PureComponent onMouseOver={this.handleMouseOver} onMouseOut={this.handleMouseOut} > -
- { connected ? -
-
- { - micState === 'on' ? - roomClient.muteMic() : - roomClient.unmuteMic(); - }} - > - { micState === 'on' ? - - : - - } -
- -
- { - webcamState === 'on' ? - roomClient.disableWebcam() : - roomClient.enableWebcam(); - }} - > - { webcamState === 'on' ? - - : - - } -
-
- :null - } - +
{ screenProducer ? -
+
+const styles = (theme) => ({ root : { @@ -24,6 +26,10 @@ const styles = () => flex : '100 100 auto', position : 'relative' }, + fab : + { + margin : theme.spacing.unit + }, viewContainer : { position : 'relative', @@ -40,56 +46,23 @@ const styles = () => }, controls : { - position : 'absolute', - right : 0, - top : 0, - display : 'flex', - flexDirection : 'row', - justifyContent : 'flex-start', - alignItems : 'center', - padding : '0.4vmin', - zIndex : 20, - opacity : 0, - transition : 'opacity 0.3s', - '&.visible' : + position : 'absolute', + width : '100%', + height : '100%', + backgroundColor : 'rgba(0, 0, 0, 0.3)', + display : 'flex', + flexDirection : 'row', + justifyContent : 'center', + alignItems : 'center', + padding : '0.4vmin', + zIndex : 20, + opacity : 0, + transition : 'opacity 0.3s', + '&:hover' : { opacity : 1 } }, - button : - { - flex : '0 0 auto', - margin : '0.2vmin', - borderRadius : 2, - opacity : 0.85, - width : 'var(--media-control-button-size)', - height : 'var(--media-control-button-size)', - backgroundColor : 'var(--media-control-button-color)', - cursor : 'pointer', - transitionProperty : 'opacity, background-color', - transitionDuration : '0.15s', - '&:hover' : - { - opacity : 1 - }, - '&.unsupported' : - { - pointerEvents : 'none' - }, - '&.disabled' : - { - pointerEvents : 'none', - backgroundColor : 'var(--media-control-botton-disabled)' - }, - '&.on' : - { - backgroundColor : 'var(--media-control-botton-on)' - }, - '&.off' : - { - backgroundColor : 'var(--media-control-botton-off)' - } - }, pausedVideo : { position : 'absolute', @@ -136,207 +109,186 @@ const styles = () => } }); -class Peer extends React.PureComponent +const Peer = (props) => { - state = { - controlsVisible : false - }; + const { + roomClient, + advancedMode, + peer, + micConsumer, + webcamConsumer, + screenConsumer, + toggleConsumerFullscreen, + toggleConsumerWindow, + style, + windowConsumer, + classes, + theme + } = props; - handleMouseOver = () => - { - this.setState({ - controlsVisible : true - }); - }; + const micEnabled = ( + Boolean(micConsumer) && + !micConsumer.locallyPaused && + !micConsumer.remotelyPaused + ); - handleMouseOut = () => - { - this.setState({ - controlsVisible : false - }); - }; + const videoVisible = ( + Boolean(webcamConsumer) && + !webcamConsumer.locallyPaused && + !webcamConsumer.remotelyPaused + ); - render() - { - const { - roomClient, - advancedMode, - peer, - micConsumer, - webcamConsumer, - screenConsumer, - toggleConsumerFullscreen, - toggleConsumerWindow, - style, - windowConsumer, - classes - } = this.props; + const screenVisible = ( + Boolean(screenConsumer) && + !screenConsumer.locallyPaused && + !screenConsumer.remotelyPaused + ); - const micEnabled = ( - Boolean(micConsumer) && - !micConsumer.locallyPaused && - !micConsumer.remotelyPaused - ); + let videoProfile; - const videoVisible = ( - Boolean(webcamConsumer) && - !webcamConsumer.locallyPaused && - !webcamConsumer.remotelyPaused - ); + if (webcamConsumer) + videoProfile = webcamConsumer.profile; - const screenVisible = ( - Boolean(screenConsumer) && - !screenConsumer.locallyPaused && - !screenConsumer.remotelyPaused - ); + let screenProfile; - let videoProfile; + if (screenConsumer) + screenProfile = screenConsumer.profile; - if (webcamConsumer) - videoProfile = webcamConsumer.profile; + const smallScreen = useMediaQuery(theme.breakpoints.down('sm')); - let screenProfile; + return ( +
+ { videoVisible && !webcamConsumer.supported ? +
+

incompatible video

+
+ :null + } - if (screenConsumer) - screenProfile = screenConsumer.profile; + { !videoVisible ? +
+

this video is paused

+
+ :null + } - return ( -
- { videoVisible && !webcamConsumer.supported ? -
-

incompatible video

-
- :null - } - - { !videoVisible ? -
-

this video is paused

-
- :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');