@@ -226,6 +238,13 @@ const mapDispatchToProps = (dispatch) =>
{
dispatch(requestActions.restartIce());
},
+ onToggleHand : (enable) =>
+ {
+ if (enable)
+ dispatch(requestActions.raiseHand());
+ else
+ dispatch(requestActions.lowerHand());
+ },
onLeaveMeeting : () =>
{
dispatch(requestActions.leaveRoom());
diff --git a/app/lib/redux/STATE.md b/app/lib/redux/STATE.md
index c05ffc2..cd3de86 100644
--- a/app/lib/redux/STATE.md
+++ b/app/lib/redux/STATE.md
@@ -51,10 +51,11 @@
{
'alice' :
{
- name : 'alice',
- displayName : 'Alice Thomsom',
- device : { flag: 'chrome', name: 'Chrome', version: '58' },
- consumers : [ 5551, 5552 ]
+ name : 'alice',
+ displayName : 'Alice Thomsom',
+ raiseHandState : false,
+ device : { flag: 'chrome', name: 'Chrome', version: '58' },
+ consumers : [ 5551, 5552 ]
}
},
consumers :
diff --git a/app/lib/redux/reducers/me.js b/app/lib/redux/reducers/me.js
index dd6b41c..8f15038 100644
--- a/app/lib/redux/reducers/me.js
+++ b/app/lib/redux/reducers/me.js
@@ -13,6 +13,8 @@ const initialState =
screenShareInProgress : false,
audioOnly : false,
audioOnlyInProgress : false,
+ raiseHand : false,
+ raiseHandInProgress : false,
restartIceInProgress : false
};
@@ -33,11 +35,11 @@ const me = (state = initialState, action) =>
return { ...state, canSendMic, canSendWebcam };
}
-
+
case 'SET_SCREEN_CAPABILITIES':
{
const { canShareScreen, needExtension } = action.payload;
-
+
return { ...state, canShareScreen, needExtension };
}
@@ -87,6 +89,20 @@ const me = (state = initialState, action) =>
return { ...state, audioOnlyInProgress: flag };
}
+ case 'SET_MY_RAISE_HAND_STATE':
+ {
+ const { flag } = action.payload;
+
+ return { ...state, raiseHand: flag };
+ }
+
+ case 'SET_MY_RAISE_HAND_STATE_IN_PROGRESS':
+ {
+ const { flag } = action.payload;
+
+ return { ...state, raiseHandInProgress: flag };
+ }
+
case 'SET_RESTART_ICE_IN_PROGRESS':
{
const { flag } = action.payload;
diff --git a/app/lib/redux/reducers/peers.js b/app/lib/redux/reducers/peers.js
index 59761e2..8ff36bd 100644
--- a/app/lib/redux/reducers/peers.js
+++ b/app/lib/redux/reducers/peers.js
@@ -34,6 +34,19 @@ const peers = (state = initialState, action) =>
return { ...state, [newPeer.name]: newPeer };
}
+ case 'SET_PEER_RAISE_HAND_STATE':
+ {
+ const { peerName, raiseHandState } = action.payload;
+ const peer = state[peerName];
+
+ if (!peer)
+ throw new Error('no Peer found');
+
+ const newPeer = { ...peer, raiseHandState };
+
+ return { ...state, [newPeer.name]: newPeer };
+ }
+
case 'ADD_CONSUMER':
{
const { consumer, peerName } = action.payload;
diff --git a/app/lib/redux/requestActions.js b/app/lib/redux/requestActions.js
index 1c3b304..e13203b 100644
--- a/app/lib/redux/requestActions.js
+++ b/app/lib/redux/requestActions.js
@@ -78,6 +78,20 @@ export const disableAudioOnly = () =>
};
};
+export const raiseHand = () =>
+{
+ return {
+ type : 'RAISE_HAND'
+ };
+};
+
+export const lowerHand = () =>
+{
+ return {
+ type : 'LOWER_HAND'
+ };
+};
+
export const restartIce = () =>
{
return {
diff --git a/app/lib/redux/roomClientMiddleware.js b/app/lib/redux/roomClientMiddleware.js
index fed0951..971985a 100644
--- a/app/lib/redux/roomClientMiddleware.js
+++ b/app/lib/redux/roomClientMiddleware.js
@@ -102,6 +102,20 @@ export default ({ dispatch, getState }) => (next) =>
break;
}
+ case 'RAISE_HAND':
+ {
+ client.sendRaiseHandState(true);
+
+ break;
+ }
+
+ case 'LOWER_HAND':
+ {
+ client.sendRaiseHandState(false);
+
+ break;
+ }
+
case 'RESTART_ICE':
{
client.restartIce();
diff --git a/app/lib/redux/stateActions.js b/app/lib/redux/stateActions.js
index bab6033..21bb7c3 100644
--- a/app/lib/redux/stateActions.js
+++ b/app/lib/redux/stateActions.js
@@ -86,6 +86,30 @@ export const setAudioOnlyInProgress = (flag) =>
};
};
+export const setMyRaiseHandState = (flag) =>
+{
+ return {
+ type : 'SET_MY_RAISE_HAND_STATE',
+ payload : { flag }
+ };
+};
+
+export const setMyRaiseHandStateInProgress = (flag) =>
+{
+ return {
+ type : 'SET_MY_RAISE_HAND_STATE_IN_PROGRESS',
+ payload : { flag }
+ };
+};
+
+export const setPeerRaiseHandState = (peerName, raiseHandState) =>
+{
+ return {
+ type : 'SET_PEER_RAISE_HAND_STATE',
+ payload : { peerName, raiseHandState }
+ };
+};
+
export const setRestartIceInProgress = (flag) =>
{
return {
diff --git a/app/resources/images/icon-hand-black.svg b/app/resources/images/icon-hand-black.svg
new file mode 100644
index 0000000..8f0f065
--- /dev/null
+++ b/app/resources/images/icon-hand-black.svg
@@ -0,0 +1,26 @@
+
+
+
diff --git a/app/resources/images/icon-hand-white.svg b/app/resources/images/icon-hand-white.svg
new file mode 100644
index 0000000..0e2f05f
--- /dev/null
+++ b/app/resources/images/icon-hand-white.svg
@@ -0,0 +1,26 @@
+
+
+
diff --git a/app/resources/images/icon_remote_raise_hand.svg b/app/resources/images/icon_remote_raise_hand.svg
new file mode 100644
index 0000000..0e2f05f
--- /dev/null
+++ b/app/resources/images/icon_remote_raise_hand.svg
@@ -0,0 +1,26 @@
+
+
+
diff --git a/app/stylus/components/Peer.styl b/app/stylus/components/Peer.styl
index 8426b0f..3c32d99 100644
--- a/app/stylus/components/Peer.styl
+++ b/app/stylus/components/Peer.styl
@@ -38,6 +38,10 @@
opacity: 0.85;
}
+ &.raise-hand {
+ background-image: url('/resources/images/icon_remote_raise_hand.svg');
+ }
+
&.mic-off {
background-image: url('/resources/images/icon_remote_mic_white_off.svg');
}
diff --git a/app/stylus/components/Room.styl b/app/stylus/components/Room.styl
index fcc1471..6685afd 100644
--- a/app/stylus/components/Room.styl
+++ b/app/stylus/components/Room.styl
@@ -250,6 +250,13 @@
background-image: url('/resources/images/share-screen-extension.svg');
}
}
+ &.raise-hand {
+ background-image: url('/resources/images/icon-hand-white.svg');
+
+ &.on {
+ background-image: url('/resources/images/icon-hand-black.svg');
+ }
+ }
&.leave-meeting {
background-image: url('/resources/images/leave-meeting.svg');
diff --git a/server/lib/Room.js b/server/lib/Room.js
index a2bad3f..4a72188 100644
--- a/server/lib/Room.js
+++ b/server/lib/Room.js
@@ -260,6 +260,27 @@ class Room extends EventEmitter
break;
}
+ case 'raisehand-message':
+ {
+ accept();
+
+ const { raiseHandState } = request.data;
+ const { mediaPeer } = protooPeer.data;
+
+ mediaPeer.appData.raiseHand = request.data.raiseHandState;
+
+ // Spread to others via protoo.
+ this._protooRoom.spread(
+ 'raisehand-message',
+ {
+ peerName : protooPeer.id,
+ raiseHandState : raiseHandState
+ },
+ [ protooPeer ]);
+
+ break;
+ }
+
default:
{
logger.error('unknown request.method "%s"', request.method);