Browse Source

feat(raised-hand) Change `raisedHand` to a timestamp instead of boole… (#10167)

- this was needed for sorting the raised hand participants in participants pane in
the order they raised their hand also for participants joining late
master
Horatiu Muresan 3 years ago
parent
commit
4b7a6741fa
No account linked to committer's email address

+ 3
- 2
modules/API/API.js View File

@@ -37,7 +37,8 @@ import {
37 37
     kickParticipant,
38 38
     raiseHand,
39 39
     isParticipantModerator,
40
-    isLocalParticipantModerator
40
+    isLocalParticipantModerator,
41
+    hasRaisedHand
41 42
 } from '../../react/features/base/participants';
42 43
 import { updateSettings } from '../../react/features/base/settings';
43 44
 import { isToggleCameraEnabled, toggleCamera } from '../../react/features/base/tracks';
@@ -281,7 +282,7 @@ function initCommands() {
281 282
             if (!localParticipant) {
282 283
                 return;
283 284
             }
284
-            const { raisedHand } = localParticipant;
285
+            const raisedHand = hasRaisedHand(localParticipant);
285 286
 
286 287
             sendAnalytics(createApiEvent('raise-hand.toggled'));
287 288
             APP.store.dispatch(raiseHand(!raisedHand));

+ 3
- 2
react/features/av-moderation/middleware.js View File

@@ -8,6 +8,7 @@ import { MEDIA_TYPE } from '../base/media';
8 8
 import {
9 9
     getLocalParticipant,
10 10
     getRemoteParticipants,
11
+    hasRaisedHand,
11 12
     isLocalParticipantModerator,
12 13
     isParticipantModerator,
13 14
     PARTICIPANT_UPDATED,
@@ -134,7 +135,7 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
134 135
             if (isLocalParticipantModerator(state)) {
135 136
 
136 137
                 // this is handled only by moderators
137
-                if (participant.raisedHand) {
138
+                if (hasRaisedHand(participant)) {
138 139
                     // if participant raises hand show notification
139 140
                     !isParticipantApproved(participant.id, MEDIA_TYPE.AUDIO)(state)
140 141
                     && dispatch(participantPendingAudio(participant));
@@ -148,7 +149,7 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
148 149
 
149 150
                 // this is the granted moderator case
150 151
                 getRemoteParticipants(state).forEach(p => {
151
-                    p.raisedHand && !isParticipantApproved(p.id, MEDIA_TYPE.AUDIO)(state)
152
+                    hasRaisedHand(p) && !isParticipantApproved(p.id, MEDIA_TYPE.AUDIO)(state)
152 153
                         && dispatch(participantPendingAudio(p));
153 154
                 });
154 155
             }

+ 2
- 2
react/features/base/participants/actions.js View File

@@ -564,13 +564,13 @@ export function setLoadableAvatarUrl(participantId, url) {
564 564
  * @param {boolean} enabled - Raise or lower hand.
565 565
  * @returns {{
566 566
  *     type: LOCAL_PARTICIPANT_RAISE_HAND,
567
- *     enabled: boolean
567
+ *     raisedHandTimestamp: number
568 568
  * }}
569 569
  */
570 570
 export function raiseHand(enabled) {
571 571
     return {
572 572
         type: LOCAL_PARTICIPANT_RAISE_HAND,
573
-        enabled
573
+        raisedHandTimestamp: enabled ? Date.now() : 0
574 574
     };
575 575
 }
576 576
 

+ 12
- 2
react/features/base/participants/functions.js View File

@@ -461,10 +461,20 @@ async function _getFirstLoadableAvatarUrl(participant, store) {
461 461
  * @param {(Function|Object)} stateful - The (whole) redux state, or redux's
462 462
  * {@code getState} function to be used to retrieve the state
463 463
  * features/base/participants.
464
- * @returns {Array<string>}
464
+ * @returns {Array<Object>}
465 465
  */
466
-export function getRaiseHandsQueue(stateful: Object | Function): Array<string> {
466
+export function getRaiseHandsQueue(stateful: Object | Function): Array<Object> {
467 467
     const { raisedHandsQueue } = toState(stateful)['features/base/participants'];
468 468
 
469 469
     return raisedHandsQueue;
470 470
 }
471
+
472
+/**
473
+ * Returns whether the given participant has his hand raised or not.
474
+ *
475
+ * @param {Object} participant - The participant.
476
+ * @returns {boolean} - Whether participant has raise hand or not.
477
+ */
478
+export function hasRaisedHand(participant: Object): boolean {
479
+    return Boolean(participant && participant.raisedHandTimestamp);
480
+}

+ 48
- 28
react/features/base/participants/middleware.js View File

@@ -94,7 +94,7 @@ MiddlewareRegistry.register(store => next => action => {
94 94
         const participant = getLocalParticipant(state);
95 95
         const isLocal = participant && participant.id === id;
96 96
 
97
-        if (isLocal && participant.raisedHand === undefined) {
97
+        if (isLocal && participant.raisedHandTimestamp === undefined) {
98 98
             // if local was undefined, let's leave it like that
99 99
             // avoids sending unnecessary presence updates
100 100
             break;
@@ -105,7 +105,7 @@ MiddlewareRegistry.register(store => next => action => {
105 105
                 conference,
106 106
                 id,
107 107
                 local: isLocal,
108
-                raisedHand: false
108
+                raisedHandTimestamp: 0
109 109
             }));
110 110
         }
111 111
 
@@ -127,14 +127,9 @@ MiddlewareRegistry.register(store => next => action => {
127 127
     }
128 128
 
129 129
     case LOCAL_PARTICIPANT_RAISE_HAND: {
130
-        const { enabled } = action;
130
+        const { raisedHandTimestamp } = action;
131 131
         const localId = getLocalParticipant(store.getState())?.id;
132 132
 
133
-        store.dispatch(raiseHandUpdateQueue({
134
-            id: localId,
135
-            raisedHand: enabled
136
-        }));
137
-
138 133
         store.dispatch(participantUpdated({
139 134
             // XXX Only the local participant is allowed to update without
140 135
             // stating the JitsiConference instance (i.e. participant property
@@ -144,11 +139,16 @@ MiddlewareRegistry.register(store => next => action => {
144 139
 
145 140
             id: localId,
146 141
             local: true,
147
-            raisedHand: enabled
142
+            raisedHandTimestamp
143
+        }));
144
+
145
+        store.dispatch(raiseHandUpdateQueue({
146
+            id: localId,
147
+            raisedHandTimestamp
148 148
         }));
149 149
 
150 150
         if (typeof APP !== 'undefined') {
151
-            APP.API.notifyRaiseHandUpdated(localId, enabled);
151
+            APP.API.notifyRaiseHandUpdated(localId, raisedHandTimestamp);
152 152
         }
153 153
 
154 154
         break;
@@ -177,16 +177,22 @@ MiddlewareRegistry.register(store => next => action => {
177 177
 
178 178
     case RAISE_HAND_UPDATED: {
179 179
         const { participant } = action;
180
-        const queue = getRaiseHandsQueue(store.getState());
180
+        let queue = getRaiseHandsQueue(store.getState());
181 181
 
182
-        if (participant.raisedHand) {
183
-            queue.push(participant.id);
184
-            action.queue = queue;
185
-        } else {
186
-            const filteredQueue = queue.filter(id => id !== participant.id);
182
+        if (participant.raisedHandTimestamp) {
183
+            queue.push({
184
+                id: participant.id,
185
+                raisedHandTimestamp: participant.raisedHandTimestamp
186
+            });
187 187
 
188
-            action.queue = filteredQueue;
188
+            // sort the queue before adding to store.
189
+            queue = queue.sort(({ raisedHandTimestamp: a }, { raisedHandTimestamp: b }) => a - b);
190
+        } else {
191
+            // no need to sort on remove value.
192
+            queue = queue.filter(({ id }) => id !== participant.id);
189 193
         }
194
+
195
+        action.queue = queue;
190 196
         break;
191 197
     }
192 198
 
@@ -287,7 +293,8 @@ StateListenerRegistry.register(
287 293
                         id: participant.getId(),
288 294
                         features: { 'screen-sharing': true }
289 295
                     })),
290
-                'raisedHand': (participant, value) => _raiseHandUpdated(store, conference, participant.getId(), value),
296
+                'raisedHand': (participant, value) =>
297
+                    _raiseHandUpdated(store, conference, participant.getId(), value),
291 298
                 'remoteControlSessionStatus': (participant, value) =>
292 299
                     store.dispatch(participantUpdated({
293 300
                         conference,
@@ -320,7 +327,7 @@ StateListenerRegistry.register(
320 327
 
321 328
             // We left the conference, the local participant must be updated.
322 329
             _e2eeUpdated(store, conference, localParticipantId, false);
323
-            _raiseHandUpdated(store, conference, localParticipantId, false);
330
+            _raiseHandUpdated(store, conference, localParticipantId, 0);
324 331
         }
325 332
     }
326 333
 );
@@ -451,18 +458,19 @@ function _maybePlaySounds({ getState, dispatch }, action) {
451 458
  */
452 459
 function _participantJoinedOrUpdated(store, next, action) {
453 460
     const { dispatch, getState } = store;
454
-    const { participant: { avatarURL, email, id, local, name, raisedHand } } = action;
461
+    const { participant: { avatarURL, email, id, local, name, raisedHandTimestamp } } = action;
455 462
 
456 463
     // Send an external update of the local participant's raised hand state
457 464
     // if a new raised hand state is defined in the action.
458
-    if (typeof raisedHand !== 'undefined') {
465
+    if (typeof raisedHandTimestamp !== 'undefined') {
459 466
 
460 467
         if (local) {
461 468
             const { conference } = getState()['features/base/conference'];
469
+            const rHand = parseInt(raisedHandTimestamp, 10);
462 470
 
463 471
             // Send raisedHand signalling only if there is a change
464
-            if (conference && raisedHand !== getLocalParticipant(getState()).raisedHand) {
465
-                conference.setLocalParticipantProperty('raisedHand', raisedHand);
472
+            if (conference && rHand !== getLocalParticipant(getState()).raisedHandTimestamp) {
473
+                conference.setLocalParticipantProperty('raisedHand', rHand);
466 474
             }
467 475
         }
468 476
     }
@@ -508,22 +516,34 @@ function _participantJoinedOrUpdated(store, next, action) {
508 516
  * @returns {void}
509 517
  */
510 518
 function _raiseHandUpdated({ dispatch, getState }, conference, participantId, newValue) {
511
-    const raisedHand = newValue === 'true';
519
+    let raisedHandTimestamp;
520
+
521
+    switch (newValue) {
522
+    case undefined:
523
+    case 'false':
524
+        raisedHandTimestamp = 0;
525
+        break;
526
+    case 'true':
527
+        raisedHandTimestamp = Date.now();
528
+        break;
529
+    default:
530
+        raisedHandTimestamp = parseInt(newValue, 10);
531
+    }
512 532
     const state = getState();
513 533
 
514 534
     dispatch(participantUpdated({
515 535
         conference,
516 536
         id: participantId,
517
-        raisedHand
537
+        raisedHandTimestamp
518 538
     }));
519 539
 
520 540
     dispatch(raiseHandUpdateQueue({
521 541
         id: participantId,
522
-        raisedHand
542
+        raisedHandTimestamp
523 543
     }));
524 544
 
525 545
     if (typeof APP !== 'undefined') {
526
-        APP.API.notifyRaiseHandUpdated(participantId, raisedHand);
546
+        APP.API.notifyRaiseHandUpdated(participantId, raisedHandTimestamp);
527 547
     }
528 548
 
529 549
     const isModerator = isLocalParticipantModerator(state);
@@ -540,7 +560,7 @@ function _raiseHandUpdated({ dispatch, getState }, conference, participantId, ne
540 560
         customActionHandler: () => dispatch(approveParticipant(participantId))
541 561
     } : {};
542 562
 
543
-    if (raisedHand) {
563
+    if (raisedHandTimestamp) {
544 564
         dispatch(showNotification({
545 565
             titleKey: 'notify.somebody',
546 566
             title: getParticipantDisplayName(state, participantId),

+ 2
- 2
react/features/filmstrip/components/AbstractRaisedHandIndicator.js View File

@@ -2,7 +2,7 @@
2 2
 
3 3
 import { Component } from 'react';
4 4
 
5
-import { getParticipantById } from '../../base/participants';
5
+import { getParticipantById, hasRaisedHand } from '../../base/participants';
6 6
 
7 7
 export type Props = {
8 8
 
@@ -57,6 +57,6 @@ export function _mapStateToProps(state: Object, ownProps: Props): Object {
57 57
     const participant = getParticipantById(state, ownProps.participantId);
58 58
 
59 59
     return {
60
-        _raisedHand: participant && participant.raisedHand
60
+        _raisedHand: hasRaisedHand(participant)
61 61
     };
62 62
 }

+ 2
- 1
react/features/participants-pane/components/native/LobbyParticipantItem.js View File

@@ -5,6 +5,7 @@ import { useTranslation } from 'react-i18next';
5 5
 import { Button } from 'react-native-paper';
6 6
 import { useDispatch } from 'react-redux';
7 7
 
8
+import { hasRaisedHand } from '../../../base/participants';
8 9
 import { approveKnockingParticipant } from '../../../lobby/actions.native';
9 10
 import { showContextMenuReject } from '../../actions.native';
10 11
 import { MEDIA_STATE } from '../../constants';
@@ -35,7 +36,7 @@ export const LobbyParticipantItem = ({ participant: p }: Props) => {
35 36
             onPress = { openContextMenuReject }
36 37
             participant = { p }
37 38
             participantID = { p.id }
38
-            raisedHand = { p.raisedHand }
39
+            raisedHand = { hasRaisedHand(p) }
39 40
             videoMediaState = { MEDIA_STATE.NONE }>
40 41
             <Button
41 42
                 children = { t('lobby.admit') }

+ 2
- 1
react/features/participants-pane/components/native/MeetingParticipantItem.js View File

@@ -7,6 +7,7 @@ import {
7 7
     getLocalParticipant,
8 8
     getParticipantByIdOrUndefined,
9 9
     getParticipantDisplayName,
10
+    hasRaisedHand,
10 11
     isParticipantModerator
11 12
 } from '../../../base/participants';
12 13
 import { connect } from '../../../base/redux';
@@ -190,7 +191,7 @@ function mapStateToProps(state, ownProps): Object {
190 191
         _local: Boolean(participant?.local),
191 192
         _localVideoOwner: Boolean(ownerId === localParticipantId),
192 193
         _participantID: participant?.id,
193
-        _raisedHand: Boolean(participant?.raisedHand),
194
+        _raisedHand: hasRaisedHand(participant),
194 195
         _videoMediaState: videoMediaState
195 196
     };
196 197
 }

+ 2
- 1
react/features/participants-pane/components/web/LobbyParticipantItem.js View File

@@ -3,6 +3,7 @@
3 3
 import React from 'react';
4 4
 import { useTranslation } from 'react-i18next';
5 5
 
6
+import { hasRaisedHand } from '../../../base/participants';
6 7
 import { ACTION_TRIGGER, MEDIA_STATE } from '../../constants';
7 8
 import { useLobbyActions } from '../../hooks';
8 9
 
@@ -45,7 +46,7 @@ export const LobbyParticipantItem = ({
45 46
             openDrawerForParticipant = { openDrawerForParticipant }
46 47
             overflowDrawer = { overflowDrawer }
47 48
             participantID = { id }
48
-            raisedHand = { p.raisedHand }
49
+            raisedHand = { hasRaisedHand(p) }
49 50
             videoMediaState = { MEDIA_STATE.NONE }
50 51
             youText = { t('chat.you') }>
51 52
             <ParticipantActionButton

+ 2
- 1
react/features/participants-pane/components/web/MeetingParticipantItem.js View File

@@ -9,6 +9,7 @@ import {
9 9
     getLocalParticipant,
10 10
     getParticipantByIdOrUndefined,
11 11
     getParticipantDisplayName,
12
+    hasRaisedHand,
12 13
     isParticipantModerator
13 14
 } from '../../../base/participants';
14 15
 import { connect } from '../../../base/redux';
@@ -307,7 +308,7 @@ function _mapStateToProps(state, ownProps): Object {
307 308
         _participant: participant,
308 309
         _participantID: participant?.id,
309 310
         _quickActionButtonType,
310
-        _raisedHand: Boolean(participant?.raisedHand),
311
+        _raisedHand: hasRaisedHand(participant),
311 312
         _videoMediaState
312 313
     };
313 314
 }

+ 3
- 7
react/features/participants-pane/functions.js View File

@@ -211,7 +211,7 @@ export function getSortedParticipantIds(stateful: Object | Function): Array<stri
211 211
     const { id } = getLocalParticipant(stateful);
212 212
     const remoteParticipants = getRemoteParticipantsSorted(stateful);
213 213
     const reorderedParticipants = new Set(remoteParticipants);
214
-    const raisedHandParticipants = getRaiseHandsQueue(stateful);
214
+    const raisedHandParticipants = getRaiseHandsQueue(stateful).map(({ id: particId }) => particId);
215 215
     const remoteRaisedHandParticipants = new Set(raisedHandParticipants || []);
216 216
     const dominantSpeaker = getDominantSpeakerParticipant(stateful);
217 217
 
@@ -219,15 +219,11 @@ export function getSortedParticipantIds(stateful: Object | Function): Array<stri
219 219
         // Avoid duplicates.
220 220
         if (reorderedParticipants.has(participant)) {
221 221
             reorderedParticipants.delete(participant);
222
-        } else {
223
-            remoteRaisedHandParticipants.delete(participant);
224 222
         }
225 223
     }
226 224
 
227
-    // Remove self.
228
-    remoteRaisedHandParticipants.delete(id);
229
-
230 225
     const dominant = [];
226
+    const local = remoteRaisedHandParticipants.has(id) ? [] : [ id ];
231 227
 
232 228
     // Remove dominant speaker.
233 229
     if (dominantSpeaker && dominantSpeaker.id !== id) {
@@ -239,7 +235,7 @@ export function getSortedParticipantIds(stateful: Object | Function): Array<stri
239 235
     // Move self and participants with raised hand to the top of the list.
240 236
     return [
241 237
         ...dominant,
242
-        id,
238
+        ...local,
243 239
         ...Array.from(remoteRaisedHandParticipants.keys()),
244 240
         ...Array.from(reorderedParticipants.keys())
245 241
     ];

+ 2
- 1
react/features/reactions/components/native/RaiseHandButton.js View File

@@ -12,6 +12,7 @@ import { ColorSchemeRegistry } from '../../../base/color-scheme';
12 12
 import { translate } from '../../../base/i18n';
13 13
 import {
14 14
     getLocalParticipant,
15
+    hasRaisedHand,
15 16
     raiseHand
16 17
 } from '../../../base/participants';
17 18
 import { connect } from '../../../base/redux';
@@ -157,7 +158,7 @@ function _mapStateToProps(state): Object {
157 158
 
158 159
     return {
159 160
         _localParticipant,
160
-        _raisedHand: _localParticipant.raisedHand,
161
+        _raisedHand: hasRaisedHand(_localParticipant),
161 162
         _styles: ColorSchemeRegistry.get(state, 'Toolbox').raiseHandButton
162 163
     };
163 164
 }

+ 2
- 2
react/features/reactions/components/native/ReactionsMenuButton.js View File

@@ -7,7 +7,7 @@ import { RAISE_HAND_ENABLED, getFeatureFlag } from '../../../base/flags';
7 7
 import { translate } from '../../../base/i18n';
8 8
 import { IconRaisedHand } from '../../../base/icons';
9 9
 import {
10
-    getLocalParticipant
10
+    getLocalParticipant, hasRaisedHand
11 11
 } from '../../../base/participants';
12 12
 import { connect } from '../../../base/redux';
13 13
 import { AbstractButton, type AbstractButtonProps } from '../../../base/toolbox/components';
@@ -81,7 +81,7 @@ function _mapStateToProps(state, ownProps): Object {
81 81
     const { visible = enabled } = ownProps;
82 82
 
83 83
     return {
84
-        _raisedHand: _localParticipant.raisedHand,
84
+        _raisedHand: hasRaisedHand(_localParticipant),
85 85
         _reactionsOpen: isDialogOpen(state, ReactionMenuDialog),
86 86
         visible
87 87
     };

+ 5
- 18
react/features/reactions/components/web/ReactionsMenu.js View File

@@ -10,7 +10,7 @@ import {
10 10
 } from '../../../analytics';
11 11
 import { isMobileBrowser } from '../../../base/environment/utils';
12 12
 import { translate } from '../../../base/i18n';
13
-import { getLocalParticipant, participantUpdated } from '../../../base/participants';
13
+import { getLocalParticipant, hasRaisedHand, raiseHand } from '../../../base/participants';
14 14
 import { connect } from '../../../base/redux';
15 15
 import { dockToolbox } from '../../../toolbox/actions.web';
16 16
 import { addReactionToBuffer } from '../../actions.any';
@@ -123,22 +123,9 @@ class ReactionsMenu extends Component<Props> {
123 123
      * @returns {void}
124 124
      */
125 125
     _doToggleRaiseHand() {
126
-        const { _localParticipantID, _raisedHand } = this.props;
127
-        const newRaisedStatus = !_raisedHand;
128
-
129
-        this.props.dispatch(participantUpdated({
130
-            // XXX Only the local participant is allowed to update without
131
-            // stating the JitsiConference instance (i.e. participant property
132
-            // `conference` for a remote participant) because the local
133
-            // participant is uniquely identified by the very fact that there is
134
-            // only one local participant.
135
-
136
-            id: _localParticipantID,
137
-            local: true,
138
-            raisedHand: newRaisedStatus
139
-        }));
140
-
141
-        APP.API.notifyRaiseHandUpdated(_localParticipantID, newRaisedStatus);
126
+        const { _raisedHand } = this.props;
127
+
128
+        this.props.dispatch(raiseHand(!_raisedHand));
142 129
     }
143 130
 
144 131
     /**
@@ -221,7 +208,7 @@ function mapStateToProps(state) {
221 208
     return {
222 209
         _localParticipantID: localParticipant.id,
223 210
         _isMobile: isMobileBrowser(),
224
-        _raisedHand: localParticipant.raisedHand
211
+        _raisedHand: hasRaisedHand(localParticipant)
225 212
     };
226 213
 }
227 214
 

+ 2
- 2
react/features/reactions/components/web/ReactionsMenuButton.js View File

@@ -5,7 +5,7 @@ import React from 'react';
5 5
 import { isMobileBrowser } from '../../../base/environment/utils';
6 6
 import { translate } from '../../../base/i18n';
7 7
 import { IconArrowUp, IconRaisedHand } from '../../../base/icons';
8
-import { getLocalParticipant } from '../../../base/participants';
8
+import { getLocalParticipant, hasRaisedHand } from '../../../base/participants';
9 9
 import { connect } from '../../../base/redux';
10 10
 import { ToolboxButtonWithIcon } from '../../../base/toolbox/components';
11 11
 import ToolbarButton from '../../../toolbox/components/web/ToolbarButton';
@@ -138,7 +138,7 @@ function mapStateToProps(state) {
138 138
         isOpen: getReactionsMenuVisibility(state),
139 139
         isMobile: isMobileBrowser(),
140 140
         reactionsQueue: getReactionsQueue(state),
141
-        raisedHand: localParticipant?.raisedHand
141
+        raisedHand: hasRaisedHand(localParticipant)
142 142
     };
143 143
 }
144 144
 

+ 2
- 1
react/features/toolbox/components/native/RaiseHandButton.js View File

@@ -11,6 +11,7 @@ import { translate } from '../../../base/i18n';
11 11
 import { IconRaisedHand } from '../../../base/icons';
12 12
 import {
13 13
     getLocalParticipant,
14
+    hasRaisedHand,
14 15
     raiseHand
15 16
 } from '../../../base/participants';
16 17
 import { connect } from '../../../base/redux';
@@ -97,7 +98,7 @@ function _mapStateToProps(state, ownProps): Object {
97 98
 
98 99
     return {
99 100
         _localParticipant,
100
-        _raisedHand: _localParticipant.raisedHand,
101
+        _raisedHand: hasRaisedHand(_localParticipant),
101 102
         visible
102 103
     };
103 104
 }

+ 4
- 6
react/features/toolbox/components/web/Toolbox.js View File

@@ -17,6 +17,7 @@ import { translate } from '../../../base/i18n';
17 17
 import JitsiMeetJS from '../../../base/lib-jitsi-meet';
18 18
 import {
19 19
     getLocalParticipant,
20
+    hasRaisedHand,
20 21
     haveParticipantWithScreenSharingFeature,
21 22
     raiseHand
22 23
 } from '../../../base/participants';
@@ -488,12 +489,9 @@ class Toolbox extends Component<Props> {
488 489
      * @returns {void}
489 490
      */
490 491
     _doToggleRaiseHand() {
491
-        const { _localParticipantID, _raisedHand } = this.props;
492
-        const newRaisedStatus = !_raisedHand;
492
+        const { _raisedHand } = this.props;
493 493
 
494
-        this.props.dispatch(raiseHand(newRaisedStatus));
495
-
496
-        APP.API.notifyRaiseHandUpdated(_localParticipantID, newRaisedStatus);
494
+        this.props.dispatch(raiseHand(!_raisedHand));
497 495
     }
498 496
 
499 497
     /**
@@ -1338,7 +1336,7 @@ function _mapStateToProps(state, ownProps) {
1338 1336
         _localVideo: localVideo,
1339 1337
         _overflowMenuVisible: overflowMenuVisible,
1340 1338
         _participantsPaneOpen: getParticipantsPaneOpen(state),
1341
-        _raisedHand: localParticipant?.raisedHand,
1339
+        _raisedHand: hasRaisedHand(localParticipant),
1342 1340
         _reactionsEnabled: isReactionsEnabled(state),
1343 1341
         _screenSharing: isScreenVideoShared(state),
1344 1342
         _tileViewEnabled: shouldDisplayTileView(state),

Loading…
Cancel
Save