Sfoglia il codice sorgente

fix(thumbnail): Optimize status bar moderator icon (#5076)

* fix(thumbnail): Optimize status bar moderator icon

Moved all moderator functionality to react to optimize the number of
status bar updates.

* fix(RemoteVideoMenuTriggerButton): Use nullish coalescing

Co-Authored-By: Saúl Ibarra Corretgé <saghul@jitsi.org>

* ref(StatusBar): rename to StatusIndicators

* fix(RemoteVideoMenu): isModerator value.

* fix(notification): mobile.

Co-authored-by: Saúl Ibarra Corretgé <s@saghul.net>
master
Hristo Terezov 5 anni fa
parent
commit
bbf1927c70
Nessun account collegato all'indirizzo email del committer

+ 0
- 23
conference.js Vedi File

435
      * the tracks won't exist).
435
      * the tracks won't exist).
436
      */
436
      */
437
     _localTracksInitialized: false,
437
     _localTracksInitialized: false,
438
-    isModerator: false,
439
     isSharingScreen: false,
438
     isSharingScreen: false,
440
 
439
 
441
     /**
440
     /**
926
         this.muteVideo(!this.isLocalVideoMuted(), showUI);
925
         this.muteVideo(!this.isLocalVideoMuted(), showUI);
927
     },
926
     },
928
 
927
 
929
-    /**
930
-     * Retrieve list of conference participants (without local user).
931
-     * @returns {JitsiParticipant[]}
932
-     */
933
-    listMembers() {
934
-        return room.getParticipants();
935
-    },
936
-
937
     /**
928
     /**
938
      * Retrieve list of ids of conference participants (without local user).
929
      * Retrieve list of ids of conference participants (without local user).
939
      * @returns {string[]}
930
      * @returns {string[]}
1894
 
1885
 
1895
             logger.log(`USER ${id} connnected:`, user);
1886
             logger.log(`USER ${id} connnected:`, user);
1896
             APP.UI.addUser(user);
1887
             APP.UI.addUser(user);
1897
-
1898
-            // check the roles for the new user and reflect them
1899
-            APP.UI.updateUserRole(user);
1900
         });
1888
         });
1901
 
1889
 
1902
         room.on(JitsiConferenceEvents.USER_LEFT, (id, user) => {
1890
         room.on(JitsiConferenceEvents.USER_LEFT, (id, user) => {
1927
                 logger.info(`My role changed, new role: ${role}`);
1915
                 logger.info(`My role changed, new role: ${role}`);
1928
 
1916
 
1929
                 APP.store.dispatch(localParticipantRoleChanged(role));
1917
                 APP.store.dispatch(localParticipantRoleChanged(role));
1930
-
1931
-                if (this.isModerator !== room.isModerator()) {
1932
-                    this.isModerator = room.isModerator();
1933
-                    APP.UI.updateLocalRole(room.isModerator());
1934
-                }
1935
             } else {
1918
             } else {
1936
                 APP.store.dispatch(participantRoleChanged(id, role));
1919
                 APP.store.dispatch(participantRoleChanged(id, role));
1937
-
1938
-                const user = room.getParticipantById(id);
1939
-
1940
-                if (user) {
1941
-                    APP.UI.updateUserRole(user);
1942
-                }
1943
             }
1920
             }
1944
         });
1921
         });
1945
 
1922
 

+ 0
- 42
modules/UI/UI.js Vedi File

126
     const { getState } = APP.store;
126
     const { getState } = APP.store;
127
     const { id, name } = getLocalParticipant(getState);
127
     const { id, name } = getLocalParticipant(getState);
128
 
128
 
129
-    // Update default button states before showing the toolbar
130
-    // if local role changes buttons state will be again updated.
131
-    UI.updateLocalRole(APP.conference.isModerator);
132
-
133
     UI.showToolbar();
129
     UI.showToolbar();
134
 
130
 
135
     const displayName = config.displayJids ? id : name;
131
     const displayName = config.displayJids ? id : name;
279
 UI.onPeerVideoTypeChanged
275
 UI.onPeerVideoTypeChanged
280
     = (id, newVideoType) => VideoLayout.onVideoTypeChanged(id, newVideoType);
276
     = (id, newVideoType) => VideoLayout.onVideoTypeChanged(id, newVideoType);
281
 
277
 
282
-/**
283
- * Update local user role and show notification if user is moderator.
284
- * @param {boolean} isModerator if local user is moderator or not
285
- */
286
-UI.updateLocalRole = isModerator => {
287
-    VideoLayout.showModeratorIndicator();
288
-
289
-    if (isModerator && !interfaceConfig.DISABLE_FOCUS_INDICATOR) {
290
-        messageHandler.participantNotification(
291
-            null, 'notify.me', 'connected', 'notify.moderator');
292
-    }
293
-};
294
-
295
-/**
296
- * Check the role for the user and reflect it in the UI, moderator ui indication
297
- * and notifies user who is the moderator
298
- * @param user to check for moderator
299
- */
300
-UI.updateUserRole = user => {
301
-    VideoLayout.showModeratorIndicator();
302
-
303
-    // We don't need to show moderator notifications when the focus (moderator)
304
-    // indicator is disabled.
305
-    if (!user.isModerator() || interfaceConfig.DISABLE_FOCUS_INDICATOR) {
306
-        return;
307
-    }
308
-
309
-    const displayName = user.getDisplayName();
310
-
311
-    messageHandler.participantNotification(
312
-        displayName,
313
-        'notify.somebody',
314
-        'connected',
315
-        'notify.grantedTo',
316
-        { to: displayName
317
-            ? UIUtil.escapeHtml(displayName) : '$t(notify.somebody)' });
318
-};
319
-
320
 /**
278
 /**
321
  * Updates the user status.
279
  * Updates the user status.
322
  *
280
  *

+ 1
- 2
modules/UI/videolayout/RemoteVideo.js Vedi File

129
         this._setThumbnailSize();
129
         this._setThumbnailSize();
130
         this.initBrowserSpecificProperties();
130
         this.initBrowserSpecificProperties();
131
         this.updateRemoteVideoMenu();
131
         this.updateRemoteVideoMenu();
132
+        this.updateStatusBar();
132
         this.addAudioLevelIndicator();
133
         this.addAudioLevelIndicator();
133
         this.addPresenceLabel();
134
         this.addPresenceLabel();
134
 
135
 
187
         // hide volume when in silent mode
188
         // hide volume when in silent mode
188
         const onVolumeChange
189
         const onVolumeChange
189
             = APP.store.getState()['features/base/config'].startSilent ? undefined : this._setAudioVolume;
190
             = APP.store.getState()['features/base/config'].startSilent ? undefined : this._setAudioVolume;
190
-        const { isModerator } = APP.conference;
191
         const participantID = this.id;
191
         const participantID = this.id;
192
         const currentLayout = getCurrentLayout(APP.store.getState());
192
         const currentLayout = getCurrentLayout(APP.store.getState());
193
         let remoteMenuPosition;
193
         let remoteMenuPosition;
207
                         <RemoteVideoMenuTriggerButton
207
                         <RemoteVideoMenuTriggerButton
208
                             initialVolumeValue = { initialVolumeValue }
208
                             initialVolumeValue = { initialVolumeValue }
209
                             isAudioMuted = { this.isAudioMuted }
209
                             isAudioMuted = { this.isAudioMuted }
210
-                            isModerator = { isModerator }
211
                             menuPosition = { remoteMenuPosition }
210
                             menuPosition = { remoteMenuPosition }
212
                             onMenuDisplay
211
                             onMenuDisplay
213
                                 = {this._onRemoteVideoMenuDisplay.bind(this)}
212
                                 = {this._onRemoteVideoMenuDisplay.bind(this)}

+ 9
- 47
modules/UI/videolayout/SmallVideo.js Vedi File

18
 import { ConnectionIndicator } from '../../../react/features/connection-indicator';
18
 import { ConnectionIndicator } from '../../../react/features/connection-indicator';
19
 import { DisplayName } from '../../../react/features/display-name';
19
 import { DisplayName } from '../../../react/features/display-name';
20
 import {
20
 import {
21
-    AudioMutedIndicator,
22
     DominantSpeakerIndicator,
21
     DominantSpeakerIndicator,
23
-    ModeratorIndicator,
24
     RaisedHandIndicator,
22
     RaisedHandIndicator,
25
-    VideoMutedIndicator
23
+    StatusIndicators
26
 } from '../../../react/features/filmstrip';
24
 } from '../../../react/features/filmstrip';
27
 import {
25
 import {
28
     LAYOUTS,
26
     LAYOUTS,
84
      * Constructor.
82
      * Constructor.
85
      */
83
      */
86
     constructor(VideoLayout) {
84
     constructor(VideoLayout) {
87
-        this._isModerator = false;
88
         this.isAudioMuted = false;
85
         this.isAudioMuted = false;
89
         this.hasAvatar = false;
86
         this.hasAvatar = false;
90
         this.isVideoMuted = false;
87
         this.isVideoMuted = false;
286
             return;
283
             return;
287
         }
284
         }
288
 
285
 
289
-        const currentLayout = getCurrentLayout(APP.store.getState());
290
-        let tooltipPosition;
291
-
292
-        if (currentLayout === LAYOUTS.TILE_VIEW) {
293
-            tooltipPosition = 'right';
294
-        } else if (currentLayout === LAYOUTS.VERTICAL_FILMSTRIP_VIEW) {
295
-            tooltipPosition = 'left';
296
-        } else {
297
-            tooltipPosition = 'top';
298
-        }
299
-
300
         ReactDOM.render(
286
         ReactDOM.render(
301
-            <I18nextProvider i18n = { i18next }>
302
-                <div>
303
-                    { this.isAudioMuted
304
-                        ? <AudioMutedIndicator
305
-                            tooltipPosition = { tooltipPosition } />
306
-                        : null }
307
-                    { this.isVideoMuted
308
-                        ? <VideoMutedIndicator
309
-                            tooltipPosition = { tooltipPosition } />
310
-                        : null }
311
-                    { this._isModerator && !interfaceConfig.DISABLE_FOCUS_INDICATOR
312
-                        ? <ModeratorIndicator
313
-                            tooltipPosition = { tooltipPosition } />
314
-                        : null }
315
-                </div>
316
-            </I18nextProvider>,
287
+            <Provider store = { APP.store }>
288
+                <I18nextProvider i18n = { i18next }>
289
+                    <StatusIndicators
290
+                        showAudioMutedIndicator = { this.isAudioMuted }
291
+                        showVideoMutedIndicator = { this.isVideoMuted }
292
+                        participantID = { this.id } />
293
+                </I18nextProvider>
294
+            </Provider>,
317
             statusBarContainer);
295
             statusBarContainer);
318
     }
296
     }
319
 
297
 
320
-    /**
321
-     * Adds the element indicating the moderator(owner) of the conference.
322
-     */
323
-    addModeratorIndicator() {
324
-        this._isModerator = true;
325
-        this.updateStatusBar();
326
-    }
327
-
328
     /**
298
     /**
329
      * Adds the element indicating the audio level of the participant.
299
      * Adds the element indicating the audio level of the participant.
330
      *
300
      *
380
         return this.container.querySelector('.audioindicator-container');
350
         return this.container.querySelector('.audioindicator-container');
381
     }
351
     }
382
 
352
 
383
-    /**
384
-     * Removes the element indicating the moderator(owner) of the conference.
385
-     */
386
-    removeModeratorIndicator() {
387
-        this._isModerator = false;
388
-        this.updateStatusBar();
389
-    }
390
-
391
     /**
353
     /**
392
      * This is an especially interesting function. A naive reader might think that
354
      * This is an especially interesting function. A naive reader might think that
393
      * it returns this SmallVideo's "video" element. But it is much more exciting.
355
      * it returns this SmallVideo's "video" element. But it is much more exciting.

+ 4
- 34
modules/UI/videolayout/VideoLayout.js Vedi File

174
 
174
 
175
         // Make sure track's muted state is reflected
175
         // Make sure track's muted state is reflected
176
         if (stream.getType() === 'audio') {
176
         if (stream.getType() === 'audio') {
177
-            this.onAudioMute(stream.getParticipantId(), stream.isMuted());
177
+            this.onAudioMute(id, stream.isMuted());
178
         } else {
178
         } else {
179
-            this.onVideoMute(stream.getParticipantId(), stream.isMuted());
179
+            this.onVideoMute(id, stream.isMuted());
180
         }
180
         }
181
     },
181
     },
182
 
182
 
204
     updateMutedForNoTracks(participantId, mediaType) {
204
     updateMutedForNoTracks(participantId, mediaType) {
205
         const participant = APP.conference.getParticipantById(participantId);
205
         const participant = APP.conference.getParticipantById(participantId);
206
 
206
 
207
-        if (participant
208
-                && !participant.getTracksByMediaType(mediaType).length) {
207
+        if (participant && !participant.getTracksByMediaType(mediaType).length) {
209
             if (mediaType === 'audio') {
208
             if (mediaType === 'audio') {
210
                 APP.UI.setAudioMuted(participantId, true);
209
                 APP.UI.setAudioMuted(participantId, true);
211
             } else if (mediaType === 'video') {
210
             } else if (mediaType === 'video') {
328
         this._updateLargeVideoIfDisplayed(resourceJid, true);
327
         this._updateLargeVideoIfDisplayed(resourceJid, true);
329
     },
328
     },
330
 
329
 
331
-    /**
332
-     * Shows a visual indicator for the moderator of the conference.
333
-     * On local or remote participants.
334
-     */
335
-    showModeratorIndicator() {
336
-        const isModerator = APP.conference.isModerator;
337
-
338
-        if (isModerator) {
339
-            localVideoThumbnail.addModeratorIndicator();
340
-        } else {
341
-            localVideoThumbnail.removeModeratorIndicator();
342
-        }
343
-
344
-        APP.conference.listMembers().forEach(member => {
345
-            const id = member.getId();
346
-            const remoteVideo = remoteVideos[id];
347
-
348
-            if (!remoteVideo) {
349
-                return;
350
-            }
351
-
352
-            if (member.isModerator()) {
353
-                remoteVideo.addModeratorIndicator();
354
-            }
355
-
356
-            remoteVideo.updateRemoteVideoMenu();
357
-        });
358
-    },
359
-
360
     /**
330
     /**
361
      * On audio muted event.
331
      * On audio muted event.
362
      */
332
      */
371
             }
341
             }
372
 
342
 
373
             remoteVideo.showAudioIndicator(isMuted);
343
             remoteVideo.showAudioIndicator(isMuted);
374
-            remoteVideo.updateRemoteVideoMenu(isMuted);
344
+            remoteVideo.updateRemoteVideoMenu();
375
         }
345
         }
376
     },
346
     },
377
 
347
 

+ 112
- 0
react/features/filmstrip/components/web/StatusIndicators.js Vedi File

1
+/* @flow */
2
+
3
+import React, { Component } from 'react';
4
+
5
+import { getLocalParticipant, getParticipantById, PARTICIPANT_ROLE } from '../../../base/participants';
6
+import { connect } from '../../../base/redux';
7
+import { getCurrentLayout, LAYOUTS } from '../../../video-layout';
8
+
9
+import AudioMutedIndicator from './AudioMutedIndicator';
10
+import ModeratorIndicator from './ModeratorIndicator';
11
+import VideoMutedIndicator from './VideoMutedIndicator';
12
+
13
+declare var interfaceConfig: Object;
14
+
15
+/**
16
+ * The type of the React {@code Component} props of {@link StatusIndicators}.
17
+ */
18
+type Props = {
19
+
20
+    /**
21
+     * The current layout of the filmstrip.
22
+     */
23
+    _currentLayout: string,
24
+
25
+    /**
26
+     * Indicates if the moderator indicator should be visible or not.
27
+     */
28
+    _showModeratorIndicator: Boolean,
29
+
30
+    /**
31
+     * Indicates if the audio muted indicator should be visible or not.
32
+     */
33
+    showAudioMutedIndicator: Boolean,
34
+
35
+    /**
36
+     * Indicates if the video muted indicator should be visible or not.
37
+     */
38
+    showVideoMutedIndicator: Boolean,
39
+
40
+    /**
41
+     * The ID of the participant for which the status bar is rendered.
42
+     */
43
+    participantID: String
44
+};
45
+
46
+/**
47
+ * React {@code Component} for showing the status bar in a thumbnail.
48
+ *
49
+ * @extends Component
50
+ */
51
+class StatusIndicators extends Component<Props> {
52
+    /**
53
+     * Implements React's {@link Component#render()}.
54
+     *
55
+     * @inheritdoc
56
+     * @returns {ReactElement}
57
+     */
58
+    render() {
59
+        const {
60
+            _currentLayout,
61
+            _showModeratorIndicator,
62
+            showAudioMutedIndicator,
63
+            showVideoMutedIndicator
64
+        } = this.props;
65
+        let tooltipPosition;
66
+
67
+        switch (_currentLayout) {
68
+        case LAYOUTS.TILE_VIEW:
69
+            tooltipPosition = 'right';
70
+            break;
71
+        case LAYOUTS.VERTICAL_FILMSTRIP_VIEW:
72
+            tooltipPosition = 'left';
73
+            break;
74
+        default:
75
+            tooltipPosition = 'top';
76
+        }
77
+
78
+        return (
79
+            <div>
80
+                { showAudioMutedIndicator ? <AudioMutedIndicator tooltipPosition = { tooltipPosition } /> : null }
81
+                { showVideoMutedIndicator ? <VideoMutedIndicator tooltipPosition = { tooltipPosition } /> : null }
82
+                { _showModeratorIndicator ? <ModeratorIndicator tooltipPosition = { tooltipPosition } /> : null }
83
+            </div>
84
+        );
85
+    }
86
+}
87
+
88
+/**
89
+ * Maps (parts of) the Redux state to the associated {@code StatusIndicators}'s props.
90
+ *
91
+ * @param {Object} state - The Redux state.
92
+ * @param {Object} ownProps - The own props of the component.
93
+ * @private
94
+ * @returns {{
95
+ *     _currentLayout: string,
96
+ *     _showModeratorIndicator: boolean
97
+ * }}
98
+*/
99
+function _mapStateToProps(state, ownProps) {
100
+    const { participantID } = ownProps;
101
+
102
+    // Only the local participant won't have id for the time when the conference is not yet joined.
103
+    const participant = participantID ? getParticipantById(state, participantID) : getLocalParticipant(state);
104
+
105
+    return {
106
+        _currentLayout: getCurrentLayout(state),
107
+        _showModeratorIndicator:
108
+            !interfaceConfig.DISABLE_FOCUS_INDICATOR && participant && participant.role === PARTICIPANT_ROLE.MODERATOR
109
+    };
110
+}
111
+
112
+export default connect(_mapStateToProps)(StatusIndicators);

+ 2
- 2
react/features/filmstrip/components/web/index.js Vedi File

1
 // @flow
1
 // @flow
2
 
2
 
3
 export { default as AudioMutedIndicator } from './AudioMutedIndicator';
3
 export { default as AudioMutedIndicator } from './AudioMutedIndicator';
4
-export { default as DominantSpeakerIndicator }
5
-    from './DominantSpeakerIndicator';
4
+export { default as DominantSpeakerIndicator } from './DominantSpeakerIndicator';
6
 export { default as Filmstrip } from './Filmstrip';
5
 export { default as Filmstrip } from './Filmstrip';
7
 export { default as ModeratorIndicator } from './ModeratorIndicator';
6
 export { default as ModeratorIndicator } from './ModeratorIndicator';
8
 export { default as RaisedHandIndicator } from './RaisedHandIndicator';
7
 export { default as RaisedHandIndicator } from './RaisedHandIndicator';
8
+export { default as StatusIndicators } from './StatusIndicators';
9
 export { default as VideoMutedIndicator } from './VideoMutedIndicator';
9
 export { default as VideoMutedIndicator } from './VideoMutedIndicator';

+ 43
- 3
react/features/notifications/middleware.js Vedi File

4
 import {
4
 import {
5
     PARTICIPANT_JOINED,
5
     PARTICIPANT_JOINED,
6
     PARTICIPANT_LEFT,
6
     PARTICIPANT_LEFT,
7
+    PARTICIPANT_ROLE,
8
+    PARTICIPANT_UPDATED,
7
     getParticipantById,
9
     getParticipantById,
8
     getParticipantDisplayName
10
     getParticipantDisplayName
9
 } from '../base/participants';
11
 } from '../base/participants';
29
     switch (action.type) {
31
     switch (action.type) {
30
     case PARTICIPANT_JOINED: {
32
     case PARTICIPANT_JOINED: {
31
         const result = next(action);
33
         const result = next(action);
32
-
33
         const { participant: p } = action;
34
         const { participant: p } = action;
35
+        const { dispatch, getState } = store;
34
 
36
 
35
         if (!p.local && !joinLeaveNotificationsDisabled()) {
37
         if (!p.local && !joinLeaveNotificationsDisabled()) {
36
-            store.dispatch(showParticipantJoinedNotification(
37
-                getParticipantDisplayName(store.getState, p.id)
38
+            dispatch(showParticipantJoinedNotification(
39
+                getParticipantDisplayName(getState, p.id)
38
             ));
40
             ));
39
         }
41
         }
40
 
42
 
43
+        if (typeof interfaceConfig === 'object'
44
+                && !interfaceConfig.DISABLE_FOCUS_INDICATOR && p.role === PARTICIPANT_ROLE.MODERATOR) {
45
+            // Do not show the notification for mobile and also when the focus indicator is disabled.
46
+            const displayName = getParticipantDisplayName(getState, p.id);
47
+
48
+            dispatch(showNotification({
49
+                descriptionArguments: { to: displayName || '$t(notify.somebody)' },
50
+                descriptionKey: 'notify.grantedTo',
51
+                titleKey: 'notify.somebody',
52
+                title: displayName
53
+            },
54
+            NOTIFICATION_TIMEOUT));
55
+        }
56
+
41
         return result;
57
         return result;
42
     }
58
     }
43
     case PARTICIPANT_LEFT: {
59
     case PARTICIPANT_LEFT: {
60
 
76
 
61
         return next(action);
77
         return next(action);
62
     }
78
     }
79
+    case PARTICIPANT_UPDATED: {
80
+        if (typeof interfaceConfig === 'undefined' || interfaceConfig.DISABLE_FOCUS_INDICATOR) {
81
+            // Do not show the notification for mobile and also when the focus indicator is disabled.
82
+            return next(action);
83
+        }
84
+
85
+        const { id, role } = action.participant;
86
+        const state = store.getState();
87
+        const { role: oldRole } = getParticipantById(state, id);
88
+
89
+        if (oldRole !== role && role === PARTICIPANT_ROLE.MODERATOR) {
90
+            const displayName = getParticipantDisplayName(state, id);
91
+
92
+            store.dispatch(showNotification({
93
+                descriptionArguments: { to: displayName || '$t(notify.somebody)' },
94
+                descriptionKey: 'notify.grantedTo',
95
+                titleKey: 'notify.somebody',
96
+                title: displayName
97
+            },
98
+            NOTIFICATION_TIMEOUT));
99
+        }
100
+
101
+        return next(action);
102
+    }
63
     }
103
     }
64
 
104
 
65
     return next(action);
105
     return next(action);

+ 28
- 8
react/features/remote-video-menu/components/web/RemoteVideoMenuTriggerButton.js Vedi File

3
 import React, { Component } from 'react';
3
 import React, { Component } from 'react';
4
 
4
 
5
 import { Icon, IconMenuThumb } from '../../../base/icons';
5
 import { Icon, IconMenuThumb } from '../../../base/icons';
6
+import { getLocalParticipant, PARTICIPANT_ROLE } from '../../../base/participants';
6
 import { Popover } from '../../../base/popover';
7
 import { Popover } from '../../../base/popover';
8
+import { connect } from '../../../base/redux';
7
 
9
 
8
 import {
10
 import {
9
     MuteButton,
11
     MuteButton,
23
  */
25
  */
24
 type Props = {
26
 type Props = {
25
 
27
 
28
+    /**
29
+     * Whether or not the participant is a conference moderator.
30
+     */
31
+    _isModerator: boolean,
32
+
26
     /**
33
     /**
27
      * A value between 0 and 1 indicating the volume of the participant's
34
      * A value between 0 and 1 indicating the volume of the participant's
28
      * audio element.
35
      * audio element.
34
      */
41
      */
35
     isAudioMuted: boolean,
42
     isAudioMuted: boolean,
36
 
43
 
37
-    /**
38
-     * Whether or not the participant is a conference moderator.
39
-     */
40
-    isModerator: boolean,
41
-
42
     /**
44
     /**
43
      * Callback to invoke when the popover has been displayed.
45
      * Callback to invoke when the popover has been displayed.
44
      */
46
      */
154
      */
156
      */
155
     _renderRemoteVideoMenu() {
157
     _renderRemoteVideoMenu() {
156
         const {
158
         const {
159
+            _isModerator,
157
             initialVolumeValue,
160
             initialVolumeValue,
158
             isAudioMuted,
161
             isAudioMuted,
159
-            isModerator,
160
             onRemoteControlToggle,
162
             onRemoteControlToggle,
161
             onVolumeChange,
163
             onVolumeChange,
162
             remoteControlState,
164
             remoteControlState,
165
 
167
 
166
         const buttons = [];
168
         const buttons = [];
167
 
169
 
168
-        if (isModerator) {
170
+        if (_isModerator) {
169
             buttons.push(
171
             buttons.push(
170
                 <MuteButton
172
                 <MuteButton
171
                     isAudioMuted = { isAudioMuted }
173
                     isAudioMuted = { isAudioMuted }
216
     }
218
     }
217
 }
219
 }
218
 
220
 
219
-export default RemoteVideoMenuTriggerButton;
221
+/**
222
+ * Maps (parts of) the Redux state to the associated {@code RemoteVideoMenuTriggerButton}'s props.
223
+ *
224
+ * @param {Object} state - The Redux state.
225
+ * @param {Object} ownProps - The own props of the component.
226
+ * @private
227
+ * @returns {{
228
+ *     _isModerator: boolean
229
+ * }}
230
+ */
231
+function _mapStateToProps(state) {
232
+    const participant = getLocalParticipant(state);
233
+
234
+    return {
235
+        _isModerator: Boolean(participant?.role === PARTICIPANT_ROLE.MODERATOR)
236
+    };
237
+}
238
+
239
+export default connect(_mapStateToProps)(RemoteVideoMenuTriggerButton);

Loading…
Annulla
Salva