浏览代码

fix(av-moderation) Improve advanced moderation (#10004)

* fix(av-moderation) Improve advanced moderation

Hide moderator label on disasbleModeratorIndicator
 - On disasbleModeratorIndicator config hide moderator label from participants pane

Add Ask to Unmute button to mobile web

* Fix lint error
master
robertpin 4 年前
父节点
当前提交
700e809439
没有帐户链接到提交者的电子邮件

+ 9
- 0
react/features/participants-pane/components/native/MeetingParticipantItem.js 查看文件

28
      */
28
      */
29
     _audioMediaState: MediaState,
29
     _audioMediaState: MediaState,
30
 
30
 
31
+    /**
32
+     * Whether or not to disable the moderator indicator.
33
+     */
34
+    _disableModeratorIndicator: boolean,
35
+
31
     /**
36
     /**
32
      * The display name of the participant.
37
      * The display name of the participant.
33
      */
38
      */
131
     render() {
136
     render() {
132
         const {
137
         const {
133
             _audioMediaState,
138
             _audioMediaState,
139
+            _disableModeratorIndicator,
134
             _displayName,
140
             _displayName,
135
             _isModerator,
141
             _isModerator,
136
             _local,
142
             _local,
142
         return (
148
         return (
143
             <ParticipantItem
149
             <ParticipantItem
144
                 audioMediaState = { _audioMediaState }
150
                 audioMediaState = { _audioMediaState }
151
+                disableModeratorIndicator = { _disableModeratorIndicator }
145
                 displayName = { _displayName }
152
                 displayName = { _displayName }
146
                 isKnockingParticipant = { false }
153
                 isKnockingParticipant = { false }
147
                 isModerator = { _isModerator }
154
                 isModerator = { _isModerator }
171
     const _isVideoMuted = isParticipantVideoMuted(participant, state);
178
     const _isVideoMuted = isParticipantVideoMuted(participant, state);
172
     const audioMediaState = getParticipantAudioMediaState(participant, _isAudioMuted, state);
179
     const audioMediaState = getParticipantAudioMediaState(participant, _isAudioMuted, state);
173
     const videoMediaState = getParticipantVideoMediaState(participant, _isVideoMuted, state);
180
     const videoMediaState = getParticipantVideoMediaState(participant, _isVideoMuted, state);
181
+    const { disableModeratorIndicator } = state['features/base/config'];
174
 
182
 
175
     return {
183
     return {
176
         _audioMediaState: audioMediaState,
184
         _audioMediaState: audioMediaState,
185
+        _disableModeratorIndicator: disableModeratorIndicator,
177
         _displayName: getParticipantDisplayName(state, participant?.id),
186
         _displayName: getParticipantDisplayName(state, participant?.id),
178
         _isAudioMuted,
187
         _isAudioMuted,
179
         _isFakeParticipant: Boolean(participant?.isFakeParticipant),
188
         _isFakeParticipant: Boolean(participant?.isFakeParticipant),

+ 9
- 1
react/features/participants-pane/components/native/ParticipantItem.js 查看文件

24
      */
24
      */
25
     children?: Node,
25
     children?: Node,
26
 
26
 
27
+    /**
28
+     * Whether or not to disable the moderator indicator.
29
+     */
30
+    disableModeratorIndicator?: boolean,
31
+
27
     /**
32
     /**
28
      * The name of the participant. Used for showing lobby names.
33
      * The name of the participant. Used for showing lobby names.
29
      */
34
      */
73
 function ParticipantItem({
78
 function ParticipantItem({
74
     children,
79
     children,
75
     displayName,
80
     displayName,
81
+    disableModeratorIndicator,
76
     isKnockingParticipant,
82
     isKnockingParticipant,
77
     isModerator,
83
     isModerator,
78
     local,
84
     local,
101
                         </Text>
107
                         </Text>
102
                         { local ? <Text style = { styles.isLocal }>({t('chat.you')})</Text> : null }
108
                         { local ? <Text style = { styles.isLocal }>({t('chat.you')})</Text> : null }
103
                     </View>
109
                     </View>
104
-                    {isModerator && <Text style = { styles.moderatorLabel }>{t('videothumbnail.moderator')}</Text>}
110
+                    {isModerator && !disableModeratorIndicator
111
+                        && <Text style = { styles.moderatorLabel }>{t('videothumbnail.moderator')}</Text>
112
+                    }
105
                 </View>
113
                 </View>
106
                 {
114
                 {
107
                     !isKnockingParticipant
115
                     !isKnockingParticipant

+ 43
- 1
react/features/participants-pane/components/web/MeetingParticipantContextMenu.js 查看文件

2
 import { withStyles } from '@material-ui/core/styles';
2
 import { withStyles } from '@material-ui/core/styles';
3
 import React, { Component } from 'react';
3
 import React, { Component } from 'react';
4
 
4
 
5
+import { approveParticipant } from '../../../av-moderation/actions';
5
 import { Avatar } from '../../../base/avatar';
6
 import { Avatar } from '../../../base/avatar';
6
 import { isToolbarButtonEnabled } from '../../../base/config/functions.web';
7
 import { isToolbarButtonEnabled } from '../../../base/config/functions.web';
7
 import { openDialog } from '../../../base/dialog';
8
 import { openDialog } from '../../../base/dialog';
12
     IconCrown,
13
     IconCrown,
13
     IconMessage,
14
     IconMessage,
14
     IconMicDisabled,
15
     IconMicDisabled,
16
+    IconMicrophone,
15
     IconMuteEveryoneElse,
17
     IconMuteEveryoneElse,
16
     IconShareVideo,
18
     IconShareVideo,
17
     IconVideoOff
19
     IconVideoOff
18
 } from '../../../base/icons';
20
 } from '../../../base/icons';
21
+import { MEDIA_TYPE } from '../../../base/media';
19
 import {
22
 import {
20
     getLocalParticipant,
23
     getLocalParticipant,
21
     getParticipantByIdOrUndefined,
24
     getParticipantByIdOrUndefined,
31
 import { GrantModeratorDialog, KickRemoteParticipantDialog, MuteEveryoneDialog } from '../../../video-menu';
34
 import { GrantModeratorDialog, KickRemoteParticipantDialog, MuteEveryoneDialog } from '../../../video-menu';
32
 import { VolumeSlider } from '../../../video-menu/components/web';
35
 import { VolumeSlider } from '../../../video-menu/components/web';
33
 import MuteRemoteParticipantsVideoDialog from '../../../video-menu/components/web/MuteRemoteParticipantsVideoDialog';
36
 import MuteRemoteParticipantsVideoDialog from '../../../video-menu/components/web/MuteRemoteParticipantsVideoDialog';
34
-import { getComputedOuterHeight } from '../../functions';
37
+import { getComputedOuterHeight, isForceMuted } from '../../functions';
35
 
38
 
36
 import {
39
 import {
37
     ContextMenu,
40
     ContextMenu,
43
 
46
 
44
 type Props = {
47
 type Props = {
45
 
48
 
49
+    /**
50
+     * Whether or not the participant is audio force muted.
51
+     */
52
+    _isAudioForceMuted: boolean,
53
+
46
     /**
54
     /**
47
      * True if the local participant is moderator and false otherwise.
55
      * True if the local participant is moderator and false otherwise.
48
      */
56
      */
68
      */
76
      */
69
     _isParticipantAudioMuted: boolean,
77
     _isParticipantAudioMuted: boolean,
70
 
78
 
79
+    /**
80
+     * Whether or not the participant is video force muted.
81
+     */
82
+    _isVideoForceMuted: boolean,
83
+
71
     /**
84
     /**
72
      * Shared video local participant owner.
85
      * Shared video local participant owner.
73
      */
86
      */
206
         this._onSendPrivateMessage = this._onSendPrivateMessage.bind(this);
219
         this._onSendPrivateMessage = this._onSendPrivateMessage.bind(this);
207
         this._position = this._position.bind(this);
220
         this._position = this._position.bind(this);
208
         this._onVolumeChange = this._onVolumeChange.bind(this);
221
         this._onVolumeChange = this._onVolumeChange.bind(this);
222
+        this._onAskToUnmute = this._onAskToUnmute.bind(this);
209
     }
223
     }
210
 
224
 
211
     _getCurrentParticipantId: () => string;
225
     _getCurrentParticipantId: () => string;
344
         dispatch(setVolume(id, value));
358
         dispatch(setVolume(id, value));
345
     }
359
     }
346
 
360
 
361
+    _onAskToUnmute: () => void;
362
+
363
+    /**
364
+     * Handles click on ask to unmute.
365
+     *
366
+     * @returns {void}
367
+     */
368
+    _onAskToUnmute() {
369
+        const { _participant, dispatch } = this.props;
370
+        const { id } = _participant;
371
+
372
+        dispatch(approveParticipant(id));
373
+    }
374
+
347
     /**
375
     /**
348
      * Implements React Component's componentDidMount.
376
      * Implements React Component's componentDidMount.
349
      *
377
      *
373
      */
401
      */
374
     render() {
402
     render() {
375
         const {
403
         const {
404
+            _isAudioForceMuted,
376
             _isLocalModerator,
405
             _isLocalModerator,
377
             _isChatButtonEnabled,
406
             _isChatButtonEnabled,
378
             _isParticipantModerator,
407
             _isParticipantModerator,
379
             _isParticipantVideoMuted,
408
             _isParticipantVideoMuted,
380
             _isParticipantAudioMuted,
409
             _isParticipantAudioMuted,
410
+            _isVideoForceMuted,
381
             _localVideoOwner,
411
             _localVideoOwner,
382
             _participant,
412
             _participant,
383
             _volume = 1,
413
             _volume = 1,
416
                     {_isLocalModerator && (
446
                     {_isLocalModerator && (
417
                         <ContextMenuItemGroup>
447
                         <ContextMenuItemGroup>
418
                             <>
448
                             <>
449
+                                {overflowDrawer && (_isAudioForceMuted || _isVideoForceMuted)
450
+                                        && <ContextMenuItem onClick = { this._onAskToUnmute }>
451
+                                            <ContextMenuIcon src = { IconMicrophone } />
452
+                                            <span>
453
+                                                {t(_isAudioForceMuted
454
+                                                    ? 'participantsPane.actions.askUnmute'
455
+                                                    : 'participantsPane.actions.allowVideo')}
456
+                                            </span>
457
+                                        </ContextMenuItem>
458
+                                }
419
                                 {
459
                                 {
420
                                     !_isParticipantAudioMuted && overflowDrawer
460
                                     !_isParticipantAudioMuted && overflowDrawer
421
                                     && <ContextMenuItem onClick = { muteAudio(_participant) }>
461
                                     && <ContextMenuItem onClick = { muteAudio(_participant) }>
542
     const isLocal = participant?.local ?? true;
582
     const isLocal = participant?.local ?? true;
543
 
583
 
544
     return {
584
     return {
585
+        _isAudioForceMuted: isForceMuted(participant, MEDIA_TYPE.AUDIO, state),
545
         _isLocalModerator,
586
         _isLocalModerator,
546
         _isChatButtonEnabled,
587
         _isChatButtonEnabled,
547
         _isParticipantModerator,
588
         _isParticipantModerator,
548
         _isParticipantVideoMuted,
589
         _isParticipantVideoMuted,
549
         _isParticipantAudioMuted,
590
         _isParticipantAudioMuted,
591
+        _isVideoForceMuted: isForceMuted(participant, MEDIA_TYPE.VIDEO, state),
550
         _localVideoOwner: Boolean(ownerId === localParticipantId),
592
         _localVideoOwner: Boolean(ownerId === localParticipantId),
551
         _participant: participant,
593
         _participant: participant,
552
         _volume: isLocal ? undefined : id ? participantsVolume[id] : undefined
594
         _volume: isLocal ? undefined : id ? participantsVolume[id] : undefined

+ 15
- 6
react/features/participants-pane/components/web/MeetingParticipantItem.js 查看文件

42
     _audioTrack: ?Object,
42
     _audioTrack: ?Object,
43
 
43
 
44
     /**
44
     /**
45
-     * Media state for video.
45
+     * Whether or not to disable the moderator indicator.
46
      */
46
      */
47
-    _videoMediaState: MediaState,
48
-
47
+    _disableModeratorIndicator: boolean,
49
 
48
 
50
     /**
49
     /**
51
      * The display name of the participant.
50
      * The display name of the participant.
85
      */
84
      */
86
     _raisedHand: boolean,
85
     _raisedHand: boolean,
87
 
86
 
87
+    /**
88
+     * Media state for video.
89
+     */
90
+    _videoMediaState: MediaState,
91
+
88
     /**
92
     /**
89
      * The translated ask unmute text for the qiuck action buttons.
93
      * The translated ask unmute text for the qiuck action buttons.
90
      */
94
      */
156
 function MeetingParticipantItem({
160
 function MeetingParticipantItem({
157
     _audioMediaState,
161
     _audioMediaState,
158
     _audioTrack,
162
     _audioTrack,
159
-    _videoMediaState,
163
+    _disableModeratorIndicator,
160
     _displayName,
164
     _displayName,
161
     _local,
165
     _local,
162
     _localVideoOwner,
166
     _localVideoOwner,
164
     _participantID,
168
     _participantID,
165
     _quickActionButtonType,
169
     _quickActionButtonType,
166
     _raisedHand,
170
     _raisedHand,
171
+    _videoMediaState,
167
     askUnmuteText,
172
     askUnmuteText,
168
     isHighlighted,
173
     isHighlighted,
169
     muteAudio,
174
     muteAudio,
219
         <ParticipantItem
224
         <ParticipantItem
220
             actionsTrigger = { ACTION_TRIGGER.HOVER }
225
             actionsTrigger = { ACTION_TRIGGER.HOVER }
221
             audioMediaState = { audioMediaState }
226
             audioMediaState = { audioMediaState }
227
+            disableModeratorIndicator = { _disableModeratorIndicator }
222
             displayName = { _displayName }
228
             displayName = { _displayName }
223
             isHighlighted = { isHighlighted }
229
             isHighlighted = { isHighlighted }
224
             isModerator = { isParticipantModerator(_participant) }
230
             isModerator = { isParticipantModerator(_participant) }
279
     const _audioTrack = participantID === localParticipantId
285
     const _audioTrack = participantID === localParticipantId
280
         ? getLocalAudioTrack(tracks) : getTrackByMediaTypeAndParticipant(tracks, MEDIA_TYPE.AUDIO, participantID);
286
         ? getLocalAudioTrack(tracks) : getTrackByMediaTypeAndParticipant(tracks, MEDIA_TYPE.AUDIO, participantID);
281
 
287
 
288
+    const { disableModeratorIndicator } = state['features/base/config'];
289
+
282
     return {
290
     return {
283
         _audioMediaState,
291
         _audioMediaState,
284
         _audioTrack,
292
         _audioTrack,
285
-        _videoMediaState,
293
+        _disableModeratorIndicator: disableModeratorIndicator,
286
         _displayName: getParticipantDisplayName(state, participant?.id),
294
         _displayName: getParticipantDisplayName(state, participant?.id),
287
         _local: Boolean(participant?.local),
295
         _local: Boolean(participant?.local),
288
         _localVideoOwner: Boolean(ownerId === localParticipantId),
296
         _localVideoOwner: Boolean(ownerId === localParticipantId),
289
         _participant: participant,
297
         _participant: participant,
290
         _participantID: participant?.id,
298
         _participantID: participant?.id,
291
         _quickActionButtonType,
299
         _quickActionButtonType,
292
-        _raisedHand: Boolean(participant?.raisedHand)
300
+        _raisedHand: Boolean(participant?.raisedHand),
301
+        _videoMediaState
293
     };
302
     };
294
 }
303
 }
295
 
304
 

+ 13
- 7
react/features/participants-pane/components/web/ParticipantItem.js 查看文件

51
      */
51
      */
52
     children: Node,
52
     children: Node,
53
 
53
 
54
+    /**
55
+     * Whether or not to disable the moderator indicator.
56
+     */
57
+    disableModeratorIndicator: boolean,
58
+
54
     /**
59
     /**
55
      * The name of the participant. Used for showing lobby names.
60
      * The name of the participant. Used for showing lobby names.
56
      */
61
      */
119
  * @returns {ReactNode}
124
  * @returns {ReactNode}
120
  */
125
  */
121
 function ParticipantItem({
126
 function ParticipantItem({
122
-    children,
123
-    isHighlighted,
124
-    isModerator,
125
-    onLeave,
126
     actionsTrigger = ACTION_TRIGGER.HOVER,
127
     actionsTrigger = ACTION_TRIGGER.HOVER,
127
     audioMediaState = MEDIA_STATE.NONE,
128
     audioMediaState = MEDIA_STATE.NONE,
128
-    videoMediaState = MEDIA_STATE.NONE,
129
+    children,
130
+    disableModeratorIndicator,
129
     displayName,
131
     displayName,
130
-    participantID,
132
+    isHighlighted,
133
+    isModerator,
131
     local,
134
     local,
135
+    onLeave,
132
     openDrawerForParticipant,
136
     openDrawerForParticipant,
133
     overflowDrawer,
137
     overflowDrawer,
138
+    participantID,
134
     raisedHand,
139
     raisedHand,
135
     t,
140
     t,
141
+    videoMediaState = MEDIA_STATE.NONE,
136
     youText
142
     youText
137
 }: Props) {
143
 }: Props) {
138
     const ParticipantActions = Actions[actionsTrigger];
144
     const ParticipantActions = Actions[actionsTrigger];
162
                         </ParticipantName>
168
                         </ParticipantName>
163
                         { local ? <span>&nbsp;({ youText })</span> : null }
169
                         { local ? <span>&nbsp;({ youText })</span> : null }
164
                     </ParticipantNameContainer>
170
                     </ParticipantNameContainer>
165
-                    {isModerator && <ModeratorLabel>
171
+                    {isModerator && !disableModeratorIndicator && <ModeratorLabel>
166
                         {t('videothumbnail.moderator')}
172
                         {t('videothumbnail.moderator')}
167
                     </ModeratorLabel>}
173
                     </ModeratorLabel>}
168
                 </ParticipantDetailsContainer>
174
                 </ParticipantDetailsContainer>

正在加载...
取消
保存