ソースを参照

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年前
コミット
4b7a6741fa
コミッターのメールアドレスに関連付けられたアカウントが存在しません

+ 3
- 2
modules/API/API.js ファイルの表示

@@ -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 ファイルの表示

@@ -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 ファイルの表示

@@ -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 ファイルの表示

@@ -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 ファイルの表示

@@ -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 ファイルの表示

@@ -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 ファイルの表示

@@ -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 ファイルの表示

@@ -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 ファイルの表示

@@ -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 ファイルの表示

@@ -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 ファイルの表示

@@ -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 ファイルの表示

@@ -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 ファイルの表示

@@ -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 ファイルの表示

@@ -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 ファイルの表示

@@ -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 ファイルの表示

@@ -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 ファイルの表示

@@ -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),

読み込み中…
キャンセル
保存