From fa94a62d9d4439021de8ba5822e01c115b7c4107 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5var=20Aamb=C3=B8=20Fosstveit?= Date: Thu, 21 Jun 2018 15:25:40 +0200 Subject: [PATCH 1/2] Placed icon and begun work with code. --- app/lib/RoomClient.js | 8 +- app/lib/components/FullView.jsx | 90 +++++++++ app/lib/components/Me.jsx | 90 +++++---- app/lib/components/Peer.jsx | 131 ++++++++---- .../images/icon_fullscreen_black.svg | 4 + .../images/icon_fullscreen_exit_black.svg | 4 + app/stylus/components/Me.styl | 162 +++++++++------ app/stylus/components/Peer.styl | 188 ++++++++++-------- app/stylus/components/Room.styl | 2 - 9 files changed, 447 insertions(+), 232 deletions(-) create mode 100644 app/lib/components/FullView.jsx create mode 100644 app/resources/images/icon_fullscreen_black.svg create mode 100644 app/resources/images/icon_fullscreen_exit_black.svg diff --git a/app/lib/RoomClient.js b/app/lib/RoomClient.js index 6969735..fb6ed29 100644 --- a/app/lib/RoomClient.js +++ b/app/lib/RoomClient.js @@ -604,7 +604,7 @@ export default class RoomClient { for (const consumer of peer.consumers) { - if (consumer.kind !== 'audio') + if (consumer.appData.source !== 'mic') continue; consumer.pause('mute-audio'); @@ -640,7 +640,7 @@ export default class RoomClient { for (const consumer of peer.consumers) { - if (consumer.kind !== 'audio' || !consumer.supported) + if (consumer.appData.source !== 'mic' || !consumer.supported) continue; consumer.resume(); @@ -676,7 +676,7 @@ export default class RoomClient { for (const consumer of peer.consumers) { - if (consumer.kind !== 'video') + if (consumer.appData.source !== 'webcam') continue; consumer.pause('pause-video'); @@ -712,7 +712,7 @@ export default class RoomClient { for (const consumer of peer.consumers) { - if (consumer.kind !== 'video' || !consumer.supported) + if (consumer.appData.source !== 'webcam' || !consumer.supported) continue; consumer.resume(); diff --git a/app/lib/components/FullView.jsx b/app/lib/components/FullView.jsx new file mode 100644 index 0000000..fec212c --- /dev/null +++ b/app/lib/components/FullView.jsx @@ -0,0 +1,90 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import classnames from 'classnames'; +import Spinner from 'react-spinner'; + +export default class FullView extends React.Component +{ + constructor(props) + { + super(props); + + // Latest received video track. + // @type {MediaStreamTrack} + this._videoTrack = null; + } + + render() + { + const { + videoVisible, + videoProfile + } = this.props; + + return ( +
+
+ ); + } + + componentDidMount() + { + const { videoTrack } = this.props; + + this._setTracks(videoTrack); + } + + componentWillReceiveProps(nextProps) + { + const { videoTrack } = nextProps; + + this._setTracks(videoTrack); + } + + _setTracks(videoTrack) + { + if (this._videoTrack === videoTrack) + return; + + this._videoTrack = videoTrack; + + const { video } = this.refs; + + if (videoTrack) + { + const stream = new MediaStream; + + if (videoTrack) + stream.addTrack(videoTrack); + + video.srcObject = stream; + } + else + { + video.srcObject = null; + } + } +} + +FullView.propTypes = +{ + videoTrack : PropTypes.any, + videoVisible : PropTypes.bool, + videoProfile : PropTypes.string +}; diff --git a/app/lib/components/Me.jsx b/app/lib/components/Me.jsx index ad3259f..4fc985d 100644 --- a/app/lib/components/Me.jsx +++ b/app/lib/components/Me.jsx @@ -78,6 +78,11 @@ class Me extends React.Component if (!me.displayNameSet) tip = 'Click on your name to change it'; + const style = + { + 'width' : screenProducer ? '40vmin' : '' + }; + return (
- {connected ? -
-
- { - micState === 'on' ? onMuteMic() : onUnmuteMic(); - }} - /> +
+ {connected ? +
+
+ { + micState === 'on' ? onMuteMic() : onUnmuteMic(); + }} + /> -
- { - webcamState === 'on' ? onDisableWebcam() : onEnableWebcam(); - }} - /> -
- :null - } +
+ { + webcamState === 'on' ? onDisableWebcam() : onEnableWebcam(); + }} + /> +
+ :null + } - onChangeDisplayName(displayName)} - /> - - {screenProducer ? - onChangeDisplayName(displayName)} /> +
+ + {screenProducer ? +
+ +
:null } diff --git a/app/lib/components/Peer.jsx b/app/lib/components/Peer.jsx index e9567b2..e28dab9 100644 --- a/app/lib/components/Peer.jsx +++ b/app/lib/components/Peer.jsx @@ -4,6 +4,7 @@ import PropTypes from 'prop-types'; import classnames from 'classnames'; import * as appPropTypes from './appPropTypes'; import * as requestActions from '../redux/requestActions'; +import * as stateActions from '../redux/stateActions'; import PeerView from './PeerView'; import ScreenView from './ScreenView'; @@ -19,6 +20,9 @@ const Peer = (props) => onUnmuteMic, onDisableWebcam, onEnableWebcam, + onDisableScreen, + onEnableScreen, + toggleConsumerFullscreen, style } = props; @@ -57,35 +61,6 @@ const Peer = (props) => screen : screenConsumer })} > -
-
- { - e.stopPropagation(); - micEnabled ? onMuteMic(peer.name) : onUnmuteMic(peer.name); - }} - /> - -
- { - e.stopPropagation(); - videoVisible ? - onDisableWebcam(peer.name) : onEnableWebcam(peer.name); - }} - /> -
- {videoVisible && !webcamConsumer.supported ?

incompatible video

@@ -94,6 +69,43 @@ const Peer = (props) => }
+
+
+ { + e.stopPropagation(); + micEnabled ? onMuteMic(peer.name) : onUnmuteMic(peer.name); + }} + /> + +
+ { + e.stopPropagation(); + videoVisible ? + onDisableWebcam(peer.name) : onEnableWebcam(peer.name); + }} + /> + +
+ { + e.stopPropagation(); + toggleConsumerFullscreen(webcamConsumer); + }} + /> +
{screenConsumer ?
+
+
+ { + e.stopPropagation(); + screenVisible ? + onDisableScreen(peer.name) : onEnableScreen(peer.name); + }} + /> + +
+ { + e.stopPropagation(); + toggleConsumerFullscreen(screenConsumer); + }} + /> +
Peer.propTypes = { - advancedMode : PropTypes.bool, - peer : appPropTypes.Peer.isRequired, - micConsumer : appPropTypes.Consumer, - webcamConsumer : appPropTypes.Consumer, - screenConsumer : appPropTypes.Consumer, - onMuteMic : PropTypes.func.isRequired, - onUnmuteMic : PropTypes.func.isRequired, - onEnableWebcam : PropTypes.func.isRequired, - onDisableWebcam : PropTypes.func.isRequired, - streamDimensions : PropTypes.object, - style : PropTypes.object + advancedMode : PropTypes.bool, + peer : appPropTypes.Peer.isRequired, + micConsumer : appPropTypes.Consumer, + webcamConsumer : appPropTypes.Consumer, + screenConsumer : appPropTypes.Consumer, + onMuteMic : PropTypes.func.isRequired, + onUnmuteMic : PropTypes.func.isRequired, + onEnableWebcam : PropTypes.func.isRequired, + onDisableWebcam : PropTypes.func.isRequired, + streamDimensions : PropTypes.object, + style : PropTypes.object, + onEnableScreen : PropTypes.func.isRequired, + onDisableScreen : PropTypes.func.isRequired, + toggleConsumerFullscreen : PropTypes.func.isRequired }; const mapStateToProps = (state, { name }) => @@ -176,6 +215,18 @@ const mapDispatchToProps = (dispatch) => onDisableWebcam : (peerName) => { dispatch(requestActions.pausePeerVideo(peerName)); + }, + onEnableScreen : (peerName) => + { + dispatch(requestActions.resumePeerScreen(peerName)); + }, + onDisableScreen : (peerName) => + { + dispatch(requestActions.pausePeerScreen(peerName)); + }, + toggleConsumerFullscreen : (consumer) => + { + dispatch(stateActions.toggleConsumerFullscreen(consumer)); } }; }; diff --git a/app/resources/images/icon_fullscreen_black.svg b/app/resources/images/icon_fullscreen_black.svg new file mode 100644 index 0000000..0a13c87 --- /dev/null +++ b/app/resources/images/icon_fullscreen_black.svg @@ -0,0 +1,4 @@ + + + + diff --git a/app/resources/images/icon_fullscreen_exit_black.svg b/app/resources/images/icon_fullscreen_exit_black.svg new file mode 100644 index 0000000..a5bab63 --- /dev/null +++ b/app/resources/images/icon_fullscreen_exit_black.svg @@ -0,0 +1,4 @@ + + + + diff --git a/app/stylus/components/Me.styl b/app/stylus/components/Me.styl index aefbd0d..91d9b8b 100644 --- a/app/stylus/components/Me.styl +++ b/app/stylus/components/Me.styl @@ -1,87 +1,123 @@ [data-component='Me'] { + flex: 100 100 auto; position: relative; - height: 100%; - width: 100%; + height: 15vmin; + width: 20vmin; + flex-direction: row; + display: flex; - > .controls { - position: absolute; - z-index: 10 - top: 0; - left: 0; - right: 0; - display: flex; - flex-direction:; row; - justify-content: flex-end; - align-items: center; - padding: 0.4vmin; + > .view-container { + position: relative; + height: 100%; + width: 100%; - > .button { - flex: 0 0 auto; - margin: 0.2vmin; - border-radius: 2px; - background-position: center; - background-size: 75%; - background-repeat: no-repeat; - background-color: rgba(#000, 0.5); - cursor: pointer; - transition-property: opacity, background-color; - transition-duration: 0.15s; + &.webcam { + order: 2; + } - +desktop() { - width: 24px; - height: 24px; - opacity: 0.85; + &.screen { + order: 1; + } - &:hover { - opacity: 1; - } - } + > .controls { + position: absolute; + z-index: 10; + right: 0; + top: 0; + display: flex; + flex-direction:; row; + justify-content: flex-start; + align-items: center; + padding: 0.4vmin; - +mobile() { - width: 22px; - height: 22px; - } + > .button { + flex: 0 0 auto; + margin: 0.2vmin; + border-radius: 2px; + background-position: center; + background-size: 75%; + background-repeat: no-repeat; + background-color: rgba(#000, 0.5); + cursor: pointer; + transition-property: opacity, background-color; + transition-duration: 0.15s; - &.unsupported { - pointer-events: none; - } + +desktop() { + width: 24px; + height: 24px; + opacity: 0.85; - &.disabled { - pointer-events: none; - opacity: 0.5; - } - - &.on { - background-color: rgba(#fff, 0.7); - } - - &.mic { - &.on { - background-image: url('/resources/images/icon_mic_black_on.svg'); + &:hover { + opacity: 1; + } } - &.off { - background-image: url('/resources/images/icon_mic_white_off.svg'); - background-color: rgba(#d42241, 0.7); + +mobile() { + width: 22px; + height: 22px; } &.unsupported { - background-image: url('/resources/images/icon_mic_white_unsupported.svg'); + pointer-events: none; + } + + &.disabled { + pointer-events: none; + opacity: 0.5; } - } - &.webcam { &.on { - background-image: url('/resources/images/icon_webcam_black_on.svg'); + background-color: rgba(#fff, 0.7); } - &.off { - background-image: url('/resources/images/icon_remote_webcam_white_off.svg'); - background-color: rgba(#d42241, 0.7); + &.mic { + &.on { + background-image: url('/resources/images/icon_mic_black_on.svg'); + } + + &.off { + background-image: url('/resources/images/icon_remote_mic_white_off.svg'); + background-color: rgba(#d42241, 0.7); + } + + &.unsupported { + background-image: url('/resources/images/icon_mic_white_unsupported.svg'); + } } - &.unsupported { - background-image: url('/resources/images/icon_webcam_white_unsupported.svg'); + &.webcam { + &.on { + background-image: url('/resources/images/icon_webcam_black_on.svg'); + } + + &.off { + background-image: url('/resources/images/icon_remote_webcam_white_off.svg'); + background-color: rgba(#d42241, 0.7); + } + + &.unsupported { + background-image: url('/resources/images/icon_webcam_white_unsupported.svg'); + } + } + + &.screen { + &.on { + background-image: url('/resources/images/share-screen-black.svg'); + } + + &.off { + background-image: url('/resources/images/no-share-screen-white.svg'); + background-color: rgba(#d42241, 0.7); + } + + &.unsupported { + background-image: url('/resources/images/no-share-screen-white.svg'); + } + } + + &.fullscreen { + background-image: url('/resources/images/icon_fullscreen_black.svg'); + background-color: rgba(#fff, 0.7); } } } diff --git a/app/stylus/components/Peer.styl b/app/stylus/components/Peer.styl index efeef3a..a95884e 100644 --- a/app/stylus/components/Peer.styl +++ b/app/stylus/components/Peer.styl @@ -13,89 +13,6 @@ &:not(.screen) { } - > .controls { - position: absolute; - z-index: 10; - right: 0; - top: 0; - display: flex; - flex-direction:; row; - justify-content: flex-start; - align-items: center; - padding: 0.4vmin; - - > .button { - flex: 0 0 auto; - margin: 0.2vmin; - border-radius: 2px; - background-position: center; - background-size: 75%; - background-repeat: no-repeat; - background-color: rgba(#000, 0.5); - cursor: pointer; - transition-property: opacity, background-color; - transition-duration: 0.15s; - - +desktop() { - width: 24px; - height: 24px; - opacity: 0.85; - - &:hover { - opacity: 1; - } - } - - +mobile() { - width: 22px; - height: 22px; - } - - &.unsupported { - pointer-events: none; - } - - &.disabled { - pointer-events: none; - opacity: 0.5; - } - - &.on { - background-color: rgba(#fff, 0.7); - } - - &.mic { - &.on { - background-image: url('/resources/images/icon_mic_black_on.svg'); - } - - &.off { - background-image: url('/resources/images/icon_remote_mic_white_off.svg'); - background-color: rgba(#d42241, 0.7); - } - - &.unsupported { - background-image: url('/resources/images/icon_mic_white_unsupported.svg'); - } - } - - &.webcam { - &.on { - background-image: url('/resources/images/icon_webcam_black_on.svg'); - } - - &.off { - background-image: url('/resources/images/icon_remote_webcam_white_off.svg'); - background-color: rgba(#d42241, 0.7); - } - - &.unsupported { - background-image: url('/resources/images/icon_webcam_white_unsupported.svg'); - } - } - } - } - +mobile() { display: flex; flex-direction: column; @@ -104,6 +21,8 @@ } > .view-container { + position: relative; + &.webcam { order: 2; } @@ -111,6 +30,109 @@ &.screen { order: 1; } + + > .controls { + position: absolute; + z-index: 10; + right: 0; + top: 0; + display: flex; + flex-direction:; row; + justify-content: flex-start; + align-items: center; + padding: 0.4vmin; + + > .button { + flex: 0 0 auto; + margin: 0.2vmin; + border-radius: 2px; + background-position: center; + background-size: 75%; + background-repeat: no-repeat; + background-color: rgba(#000, 0.5); + cursor: pointer; + transition-property: opacity, background-color; + transition-duration: 0.15s; + + +desktop() { + width: 24px; + height: 24px; + opacity: 0.85; + + &:hover { + opacity: 1; + } + } + + +mobile() { + width: 22px; + height: 22px; + } + + &.unsupported { + pointer-events: none; + } + + &.disabled { + pointer-events: none; + opacity: 0.5; + } + + &.on { + background-color: rgba(#fff, 0.7); + } + + &.mic { + &.on { + background-image: url('/resources/images/icon_mic_black_on.svg'); + } + + &.off { + background-image: url('/resources/images/icon_remote_mic_white_off.svg'); + background-color: rgba(#d42241, 0.7); + } + + &.unsupported { + background-image: url('/resources/images/icon_mic_white_unsupported.svg'); + } + } + + &.webcam { + &.on { + background-image: url('/resources/images/icon_webcam_black_on.svg'); + } + + &.off { + background-image: url('/resources/images/icon_remote_webcam_white_off.svg'); + background-color: rgba(#d42241, 0.7); + } + + &.unsupported { + background-image: url('/resources/images/icon_webcam_white_unsupported.svg'); + } + } + + &.screen { + &.on { + background-image: url('/resources/images/share-screen-black.svg'); + } + + &.off { + background-image: url('/resources/images/no-share-screen-white.svg'); + background-color: rgba(#d42241, 0.7); + } + + &.unsupported { + background-image: url('/resources/images/no-share-screen-white.svg'); + } + } + + &.fullscreen { + background-image: url('/resources/images/icon_fullscreen_black.svg'); + background-color: rgba(#fff, 0.7); + } + } + } } .incompatible-video { diff --git a/app/stylus/components/Room.styl b/app/stylus/components/Room.styl index aa62aa0..e766650 100644 --- a/app/stylus/components/Room.styl +++ b/app/stylus/components/Room.styl @@ -153,8 +153,6 @@ } +desktop() { - height: 200px; - width: 235px; bottom: 20px; left: 20px; border: 1px solid rgba(#fff, 0.15); From 3b03b24cc4480ca9450e10c6f25d05df09b391c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5var=20Aamb=C3=B8=20Fosstveit?= Date: Fri, 22 Jun 2018 11:45:02 +0200 Subject: [PATCH 2/2] Working fullscreen view --- app/lib/components/FullScreenView.jsx | 91 +++++++++++++++++++ app/lib/components/FullView.jsx | 2 +- app/lib/components/Me.jsx | 6 -- app/lib/components/Peer.jsx | 3 +- app/lib/components/Peers.jsx | 13 +-- app/lib/components/Room.jsx | 2 + app/lib/redux/reducers/room.js | 19 ++-- app/lib/redux/stateActions.js | 8 ++ app/stylus/components/Chat.styl | 2 +- app/stylus/components/FullScreenView.styl | 75 ++++++++++++++++ app/stylus/components/FullView.styl | 105 ++++++++++++++++++++++ app/stylus/components/Me.styl | 6 +- app/stylus/index.styl | 2 + 13 files changed, 311 insertions(+), 23 deletions(-) create mode 100644 app/lib/components/FullScreenView.jsx create mode 100644 app/stylus/components/FullScreenView.styl create mode 100644 app/stylus/components/FullView.styl diff --git a/app/lib/components/FullScreenView.jsx b/app/lib/components/FullScreenView.jsx new file mode 100644 index 0000000..6192eee --- /dev/null +++ b/app/lib/components/FullScreenView.jsx @@ -0,0 +1,91 @@ +import React from 'react'; +import { connect } from 'react-redux'; +import PropTypes from 'prop-types'; +import classnames from 'classnames'; +import * as appPropTypes from './appPropTypes'; +import * as stateActions from '../redux/stateActions'; +import FullView from './FullView'; + +const FullScreenView = (props) => +{ + const { + advancedMode, + consumer, + toggleConsumerFullscreen + } = props; + + if (!consumer) + return null; + + const consumerVisible = ( + Boolean(consumer) && + !consumer.locallyPaused && + !consumer.remotelyPaused + ); + + let consumerProfile; + + if (consumer) + consumerProfile = consumer.profile; + + return ( +
+ {consumerVisible && !consumer.supported ? +
+

incompatible video

+
+ :null + } + +
+
+ { + e.stopPropagation(); + toggleConsumerFullscreen(consumer); + }} + /> +
+ + +
+ ); +}; + +FullScreenView.propTypes = +{ + advancedMode : PropTypes.bool, + consumer : appPropTypes.Consumer, + toggleConsumerFullscreen : PropTypes.func.isRequired +}; + +const mapStateToProps = (state) => +{ + return { + consumer : state.consumers[state.room.fullScreenConsumer] + }; +}; + +const mapDispatchToProps = (dispatch) => +{ + return { + toggleConsumerFullscreen : (consumer) => + { + if (consumer) + dispatch(stateActions.toggleConsumerFullscreen(consumer.id)); + } + }; +}; + +const FullScreenViewContainer = connect( + mapStateToProps, + mapDispatchToProps +)(FullScreenView); + +export default FullScreenViewContainer; diff --git a/app/lib/components/FullView.jsx b/app/lib/components/FullView.jsx index fec212c..3edc64a 100644 --- a/app/lib/components/FullView.jsx +++ b/app/lib/components/FullView.jsx @@ -22,7 +22,7 @@ export default class FullView extends React.Component } = this.props; return ( -
+