Added support for locking rooms
This commit is contained in:
+80
-13
@@ -990,10 +990,22 @@ export default class RoomClient
|
||||
this._signalingSocket.on('connect', () =>
|
||||
{
|
||||
logger.debug('signaling Peer "connect" event');
|
||||
});
|
||||
|
||||
this._signalingSocket.on('room-ready', () =>
|
||||
{
|
||||
logger.debug('signaling Peer "room-ready" event');
|
||||
|
||||
this._joinRoom({ displayName, device });
|
||||
});
|
||||
|
||||
this._signalingSocket.on('room-locked', () =>
|
||||
{
|
||||
logger.debug('signaling Peer "room-locked" event');
|
||||
|
||||
store.dispatch(stateActions.setRoomLockedOut());
|
||||
});
|
||||
|
||||
this._signalingSocket.on('disconnect', () =>
|
||||
{
|
||||
logger.warn('signaling Peer "disconnect" event');
|
||||
@@ -1024,10 +1036,34 @@ export default class RoomClient
|
||||
this._room.receiveNotification(notification);
|
||||
});
|
||||
|
||||
this._signalingSocket.on('active-speaker', (data) =>
|
||||
this._signalingSocket.on('lock-room', ({ peerName }) =>
|
||||
{
|
||||
const { peerName } = data;
|
||||
store.dispatch(
|
||||
stateActions.setRoomLocked());
|
||||
|
||||
const peer = this._room.getPeerByName(peerName);
|
||||
|
||||
if (peer)
|
||||
{
|
||||
this.notify(`${peer.appData.displayName} locked the room.`);
|
||||
}
|
||||
});
|
||||
|
||||
this._signalingSocket.on('unlock-room', ({ peerName }) =>
|
||||
{
|
||||
store.dispatch(
|
||||
stateActions.setRoomUnLocked());
|
||||
|
||||
const peer = this._room.getPeerByName(peerName);
|
||||
|
||||
if (peer)
|
||||
{
|
||||
this.notify(`${peer.appData.displayName} unlocked the room.`);
|
||||
}
|
||||
});
|
||||
|
||||
this._signalingSocket.on('active-speaker', ({ peerName }) =>
|
||||
{
|
||||
store.dispatch(
|
||||
stateActions.setRoomActiveSpeaker(peerName));
|
||||
|
||||
@@ -1035,11 +1071,8 @@ export default class RoomClient
|
||||
this._spotlights.handleActiveSpeaker(peerName);
|
||||
});
|
||||
|
||||
this._signalingSocket.on('display-name-changed', (data) =>
|
||||
this._signalingSocket.on('display-name-changed', ({ peerName, displayName: name }) =>
|
||||
{
|
||||
// eslint-disable-next-line no-shadow
|
||||
const { peerName, displayName } = data;
|
||||
|
||||
// NOTE: Hack, we shouldn't do this, but this is just a demo.
|
||||
const peer = this._room.getPeerByName(peerName);
|
||||
|
||||
@@ -1050,20 +1083,18 @@ export default class RoomClient
|
||||
return;
|
||||
}
|
||||
|
||||
const oldDisplayName = peer.appData.displayName;
|
||||
const oldDisplayName = peer.appData.name;
|
||||
|
||||
peer.appData.displayName = displayName;
|
||||
peer.appData.displayName = name;
|
||||
|
||||
store.dispatch(
|
||||
stateActions.setPeerDisplayName(displayName, peerName));
|
||||
stateActions.setPeerDisplayName(name, peerName));
|
||||
|
||||
this.notify(`${oldDisplayName} changed their display name to ${displayName}.`);
|
||||
this.notify(`${oldDisplayName} changed their display name to ${name}.`);
|
||||
});
|
||||
|
||||
this._signalingSocket.on('profile-picture-changed', (data) =>
|
||||
this._signalingSocket.on('profile-picture-changed', ({ peerName, picture }) =>
|
||||
{
|
||||
const { peerName, picture } = data;
|
||||
|
||||
store.dispatch(stateActions.setPeerPicture(peerName, picture));
|
||||
});
|
||||
|
||||
@@ -1292,6 +1323,42 @@ export default class RoomClient
|
||||
}
|
||||
}
|
||||
|
||||
async lockRoom()
|
||||
{
|
||||
logger.debug('lockRoom()');
|
||||
|
||||
try
|
||||
{
|
||||
await this.sendRequest('lock-room');
|
||||
|
||||
store.dispatch(
|
||||
stateActions.setRoomLocked());
|
||||
this.notify('You locked the room.');
|
||||
}
|
||||
catch (error)
|
||||
{
|
||||
logger.error('lockRoom() | failed: %o', error);
|
||||
}
|
||||
}
|
||||
|
||||
async unlockRoom()
|
||||
{
|
||||
logger.debug('unlockRoom()');
|
||||
|
||||
try
|
||||
{
|
||||
await this.sendRequest('unlock-room');
|
||||
|
||||
store.dispatch(
|
||||
stateActions.setRoomUnLocked());
|
||||
this.notify('You unlocked the room.');
|
||||
}
|
||||
catch (error)
|
||||
{
|
||||
logger.error('unlockRoom() | failed: %o', error);
|
||||
}
|
||||
}
|
||||
|
||||
async _setMicProducer()
|
||||
{
|
||||
if (!this._room.canSend('audio'))
|
||||
|
||||
@@ -59,11 +59,13 @@ class Sidebar extends Component
|
||||
roomClient,
|
||||
toolbarsVisible,
|
||||
me,
|
||||
screenProducer
|
||||
screenProducer,
|
||||
locked
|
||||
} = this.props;
|
||||
|
||||
let screenState;
|
||||
let screenTip;
|
||||
let lockState = 'unlocked';
|
||||
|
||||
if (me.needExtension)
|
||||
{
|
||||
@@ -86,6 +88,11 @@ class Sidebar extends Component
|
||||
screenTip = 'Start screen sharing';
|
||||
}
|
||||
|
||||
if (locked)
|
||||
{
|
||||
lockState = 'locked';
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classnames('sidebar room-controls', {
|
||||
@@ -161,6 +168,25 @@ class Sidebar extends Component
|
||||
</Otherwise>
|
||||
</Choose>
|
||||
</If>
|
||||
<div
|
||||
className={classnames('button', 'lock', lockState, {
|
||||
on : locked
|
||||
})}
|
||||
data-tip={`Room is ${lockState}`}
|
||||
data-place='right'
|
||||
data-type='dark'
|
||||
onClick={() =>
|
||||
{
|
||||
if (locked)
|
||||
{
|
||||
roomClient.unlockRoom();
|
||||
}
|
||||
else
|
||||
{
|
||||
roomClient.lockRoom();
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
className={classnames('button', 'raise-hand', {
|
||||
on : me.raiseHand,
|
||||
@@ -188,7 +214,8 @@ Sidebar.propTypes = {
|
||||
roomClient : PropTypes.any.isRequired,
|
||||
toolbarsVisible : PropTypes.bool.isRequired,
|
||||
me : appPropTypes.Me.isRequired,
|
||||
screenProducer : appPropTypes.Producer
|
||||
screenProducer : appPropTypes.Producer,
|
||||
locked : PropTypes.bool.isRequired
|
||||
};
|
||||
|
||||
const mapStateToProps = (state) =>
|
||||
@@ -196,7 +223,8 @@ const mapStateToProps = (state) =>
|
||||
toolbarsVisible : state.room.toolbarsVisible,
|
||||
screenProducer : Object.values(state.producers)
|
||||
.find((producer) => producer.source === 'screen'),
|
||||
me : state.me
|
||||
me : state.me,
|
||||
locked : state.room.locked
|
||||
});
|
||||
|
||||
export default withRoomContext(connect(
|
||||
|
||||
+102
-85
@@ -73,97 +73,114 @@ class Room extends React.Component
|
||||
democratic : Peers
|
||||
}[room.mode];
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<Appear duration={300}>
|
||||
<div data-component='Room'>
|
||||
<CookieConsent>
|
||||
This website uses cookies to enhance the user experience.
|
||||
</CookieConsent>
|
||||
|
||||
<FullScreenView advancedMode={room.advancedMode} />
|
||||
|
||||
<VideoWindow advancedMode={room.advancedMode} />
|
||||
|
||||
<div className='room-wrapper'>
|
||||
<div data-component='Logo' />
|
||||
<AudioPeers />
|
||||
|
||||
<Notifications />
|
||||
|
||||
<If condition={room.advancedMode}>
|
||||
<div className='state' data-tip='Server status'>
|
||||
<div className={classnames('icon', room.state)} />
|
||||
<p className={classnames('text', room.state)}>{room.state}</p>
|
||||
</div>
|
||||
</If>
|
||||
|
||||
<div
|
||||
className={classnames('room-link-wrapper room-controls', {
|
||||
'visible' : this.props.room.toolbarsVisible
|
||||
})}
|
||||
>
|
||||
<div className='room-link'>
|
||||
<CopyToClipboard
|
||||
text={room.url}
|
||||
onCopy={onRoomLinkCopy}
|
||||
>
|
||||
<a
|
||||
className='link'
|
||||
href={room.url}
|
||||
target='_blank'
|
||||
data-tip='Click to copy room link'
|
||||
rel='noopener noreferrer'
|
||||
onClick={(event) =>
|
||||
{
|
||||
// If this is a 'Open in new window/tab' don't prevent
|
||||
// click default action.
|
||||
if (
|
||||
event.ctrlKey || event.shiftKey || event.metaKey ||
|
||||
// Middle click (IE > 9 and everyone else).
|
||||
(event.button && event.button === 1)
|
||||
)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
event.preventDefault();
|
||||
}}
|
||||
>
|
||||
invitation link
|
||||
</a>
|
||||
</CopyToClipboard>
|
||||
</div>
|
||||
if (room.lockedOut)
|
||||
{
|
||||
return (
|
||||
<Fragment>
|
||||
<Appear duration={300}>
|
||||
<div data-component='Room'>
|
||||
<div className='locked-out'>
|
||||
This room is locked at the moment, try again later.
|
||||
</div>
|
||||
|
||||
<View advancedMode={room.advancedMode} />
|
||||
|
||||
<Draggable handle='.me-container' bounds='body' cancel='.display-name'>
|
||||
</div>
|
||||
</Appear>
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
return (
|
||||
<Fragment>
|
||||
<Appear duration={300}>
|
||||
<div data-component='Room'>
|
||||
<CookieConsent>
|
||||
This website uses cookies to enhance the user experience.
|
||||
</CookieConsent>
|
||||
|
||||
<FullScreenView advancedMode={room.advancedMode} />
|
||||
|
||||
<VideoWindow advancedMode={room.advancedMode} />
|
||||
|
||||
<div className='room-wrapper'>
|
||||
<div data-component='Logo' />
|
||||
<AudioPeers />
|
||||
|
||||
<Notifications />
|
||||
|
||||
<If condition={room.advancedMode}>
|
||||
<div className='state' data-tip='Server status'>
|
||||
<div className={classnames('icon', room.state)} />
|
||||
<p className={classnames('text', room.state)}>{room.state}</p>
|
||||
</div>
|
||||
</If>
|
||||
|
||||
<div
|
||||
className={classnames('me-container', {
|
||||
'active-speaker' : amActiveSpeaker
|
||||
className={classnames('room-link-wrapper room-controls', {
|
||||
'visible' : this.props.room.toolbarsVisible
|
||||
})}
|
||||
>
|
||||
<Me
|
||||
advancedMode={room.advancedMode}
|
||||
/>
|
||||
<div className='room-link'>
|
||||
<CopyToClipboard
|
||||
text={room.url}
|
||||
onCopy={onRoomLinkCopy}
|
||||
>
|
||||
<a
|
||||
className='link'
|
||||
href={room.url}
|
||||
target='_blank'
|
||||
data-tip='Click to copy room link'
|
||||
rel='noopener noreferrer'
|
||||
onClick={(event) =>
|
||||
{
|
||||
// If this is a 'Open in new window/tab' don't prevent
|
||||
// click default action.
|
||||
if (
|
||||
event.ctrlKey || event.shiftKey || event.metaKey ||
|
||||
// Middle click (IE > 9 and everyone else).
|
||||
(event.button && event.button === 1)
|
||||
)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
event.preventDefault();
|
||||
}}
|
||||
>
|
||||
invitation link
|
||||
</a>
|
||||
</CopyToClipboard>
|
||||
</div>
|
||||
</div>
|
||||
</Draggable>
|
||||
|
||||
<Sidebar />
|
||||
|
||||
<ReactTooltip
|
||||
effect='solid'
|
||||
delayShow={100}
|
||||
delayHide={100}
|
||||
/>
|
||||
|
||||
<View advancedMode={room.advancedMode} />
|
||||
|
||||
<Draggable handle='.me-container' bounds='body' cancel='.display-name'>
|
||||
<div
|
||||
className={classnames('me-container', {
|
||||
'active-speaker' : amActiveSpeaker
|
||||
})}
|
||||
>
|
||||
<Me
|
||||
advancedMode={room.advancedMode}
|
||||
/>
|
||||
</div>
|
||||
</Draggable>
|
||||
|
||||
<Sidebar />
|
||||
|
||||
<ReactTooltip
|
||||
effect='solid'
|
||||
delayShow={100}
|
||||
delayHide={100}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<ToolArea />
|
||||
</div>
|
||||
|
||||
<ToolArea />
|
||||
</div>
|
||||
</Appear>
|
||||
</Fragment>
|
||||
);
|
||||
</Appear>
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@ const initialState =
|
||||
{
|
||||
url : null,
|
||||
state : 'new', // new/connecting/connected/disconnected/closed,
|
||||
locked : false,
|
||||
lockedOut : false,
|
||||
activeSpeakerName : null,
|
||||
torrentSupport : false,
|
||||
showSettings : false,
|
||||
@@ -35,6 +37,21 @@ const room = (state = initialState, action) =>
|
||||
return { ...state, state: roomState, activeSpeakerName: null };
|
||||
}
|
||||
|
||||
case 'SET_ROOM_LOCKED':
|
||||
{
|
||||
return { ...state, locked: true };
|
||||
}
|
||||
|
||||
case 'SET_ROOM_UNLOCKED':
|
||||
{
|
||||
return { ...state, locked: false };
|
||||
}
|
||||
|
||||
case 'SET_ROOM_LOCKED_OUT':
|
||||
{
|
||||
return { ...state, lockedOut: true };
|
||||
}
|
||||
|
||||
case 'SET_ROOM_ACTIVE_SPEAKER':
|
||||
{
|
||||
const { peerName } = action.payload;
|
||||
|
||||
@@ -22,6 +22,27 @@ export const setRoomActiveSpeaker = (peerName) =>
|
||||
};
|
||||
};
|
||||
|
||||
export const setRoomLocked = () =>
|
||||
{
|
||||
return {
|
||||
type : 'SET_ROOM_LOCKED'
|
||||
};
|
||||
};
|
||||
|
||||
export const setRoomUnLocked = () =>
|
||||
{
|
||||
return {
|
||||
type : 'SET_ROOM_UNLOCKED'
|
||||
};
|
||||
};
|
||||
|
||||
export const setRoomLockedOut = () =>
|
||||
{
|
||||
return {
|
||||
type : 'SET_ROOM_LOCKED_OUT'
|
||||
};
|
||||
};
|
||||
|
||||
export const setMe = ({ peerName, displayName, displayNameSet, device, loginEnabled }) =>
|
||||
{
|
||||
return {
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24px" height="24px">
|
||||
<path d="M 12 1 C 8.6761905 1 6 3.6761905 6 7 L 6 8 C 4.9 8 4 8.9 4 10 L 4 20 C 4 21.1 4.9 22 6 22 L 18 22 C 19.1 22 20 21.1 20 20 L 20 10 C 20 8.9 19.1 8 18 8 L 18 7 C 18 3.6761905 15.32381 1 12 1 z M 12 3 C 14.27619 3 16 4.7238095 16 7 L 16 8 L 8 8 L 8 7 C 8 4.7238095 9.7238095 3 12 3 z M 12 13 C 13.1 13 14 13.9 14 15 C 14 16.1 13.1 17 12 17 C 10.9 17 10 16.1 10 15 C 10 13.9 10.9 13 12 13 z" fill="#FFFFFF"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 535 B |
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24px" height="24px">
|
||||
<path style="line-height:normal;text-indent:0;text-align:start;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000;text-transform:none;block-progression:tb;isolation:auto;mix-blend-mode:normal" d="M 12 1 C 9.1277778 1 6.7189086 3.0461453 6.1230469 5.7871094 L 8.078125 6.2128906 C 8.4822632 4.3538547 10.072222 3 12 3 C 14.27619 3 16 4.7238095 16 7 L 16 8 L 6 8 C 4.9 8 4 8.9 4 10 L 4 20 C 4 21.1 4.9 22 6 22 L 18 22 C 19.1 22 20 21.1 20 20 L 20 10 C 20 8.9 19.1 8 18 8 L 18 7 C 18 3.6761905 15.32381 1 12 1 z M 12 13 C 13.1 13 14 13.9 14 15 C 14 16.1 13.1 17 12 17 C 10.9 17 10 16.1 10 15 C 10 13.9 10.9 13 12 13 z" font-weight="400" font-family="sans-serif" white-space="normal" overflow="visible" fill="#FFFFFF"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 867 B |
@@ -1,6 +1,20 @@
|
||||
[data-component='Room'] {
|
||||
AppearFadeIn(300ms);
|
||||
|
||||
> .locked-out {
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translateX(-50%) translateY(-50%);
|
||||
width: 30vw;
|
||||
text-align: center;
|
||||
font-family: 'Roboto';
|
||||
font-size: 2.5em;
|
||||
box-shadow: 0px 5px 12px 2px rgba(17, 17, 17, 0.5);
|
||||
background-color: #fff;
|
||||
padding: 2vmin;
|
||||
}
|
||||
|
||||
> .room-wrapper {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
|
||||
@@ -96,6 +96,16 @@
|
||||
}
|
||||
}
|
||||
|
||||
&.lock {
|
||||
&.locked {
|
||||
background-image: url('/resources/images/icon_locked_white.svg');
|
||||
}
|
||||
|
||||
&.unlocked {
|
||||
background-image: url('/resources/images/icon_unlocked_white.svg');
|
||||
}
|
||||
}
|
||||
|
||||
&.raise-hand {
|
||||
background-image: url('/resources/images/icon-hand-white.svg');
|
||||
|
||||
|
||||
Reference in New Issue
Block a user