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
This commit is contained in:
parent
a91b2c91dd
commit
700e809439
|
@ -28,6 +28,11 @@ type Props = {
|
|||
*/
|
||||
_audioMediaState: MediaState,
|
||||
|
||||
/**
|
||||
* Whether or not to disable the moderator indicator.
|
||||
*/
|
||||
_disableModeratorIndicator: boolean,
|
||||
|
||||
/**
|
||||
* The display name of the participant.
|
||||
*/
|
||||
|
@ -131,6 +136,7 @@ class MeetingParticipantItem extends PureComponent<Props> {
|
|||
render() {
|
||||
const {
|
||||
_audioMediaState,
|
||||
_disableModeratorIndicator,
|
||||
_displayName,
|
||||
_isModerator,
|
||||
_local,
|
||||
|
@ -142,6 +148,7 @@ class MeetingParticipantItem extends PureComponent<Props> {
|
|||
return (
|
||||
<ParticipantItem
|
||||
audioMediaState = { _audioMediaState }
|
||||
disableModeratorIndicator = { _disableModeratorIndicator }
|
||||
displayName = { _displayName }
|
||||
isKnockingParticipant = { false }
|
||||
isModerator = { _isModerator }
|
||||
|
@ -171,9 +178,11 @@ function mapStateToProps(state, ownProps): Object {
|
|||
const _isVideoMuted = isParticipantVideoMuted(participant, state);
|
||||
const audioMediaState = getParticipantAudioMediaState(participant, _isAudioMuted, state);
|
||||
const videoMediaState = getParticipantVideoMediaState(participant, _isVideoMuted, state);
|
||||
const { disableModeratorIndicator } = state['features/base/config'];
|
||||
|
||||
return {
|
||||
_audioMediaState: audioMediaState,
|
||||
_disableModeratorIndicator: disableModeratorIndicator,
|
||||
_displayName: getParticipantDisplayName(state, participant?.id),
|
||||
_isAudioMuted,
|
||||
_isFakeParticipant: Boolean(participant?.isFakeParticipant),
|
||||
|
|
|
@ -24,6 +24,11 @@ type Props = {
|
|||
*/
|
||||
children?: Node,
|
||||
|
||||
/**
|
||||
* Whether or not to disable the moderator indicator.
|
||||
*/
|
||||
disableModeratorIndicator?: boolean,
|
||||
|
||||
/**
|
||||
* The name of the participant. Used for showing lobby names.
|
||||
*/
|
||||
|
@ -73,6 +78,7 @@ type Props = {
|
|||
function ParticipantItem({
|
||||
children,
|
||||
displayName,
|
||||
disableModeratorIndicator,
|
||||
isKnockingParticipant,
|
||||
isModerator,
|
||||
local,
|
||||
|
@ -101,7 +107,9 @@ function ParticipantItem({
|
|||
</Text>
|
||||
{ local ? <Text style = { styles.isLocal }>({t('chat.you')})</Text> : null }
|
||||
</View>
|
||||
{isModerator && <Text style = { styles.moderatorLabel }>{t('videothumbnail.moderator')}</Text>}
|
||||
{isModerator && !disableModeratorIndicator
|
||||
&& <Text style = { styles.moderatorLabel }>{t('videothumbnail.moderator')}</Text>
|
||||
}
|
||||
</View>
|
||||
{
|
||||
!isKnockingParticipant
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
import { withStyles } from '@material-ui/core/styles';
|
||||
import React, { Component } from 'react';
|
||||
|
||||
import { approveParticipant } from '../../../av-moderation/actions';
|
||||
import { Avatar } from '../../../base/avatar';
|
||||
import { isToolbarButtonEnabled } from '../../../base/config/functions.web';
|
||||
import { openDialog } from '../../../base/dialog';
|
||||
|
@ -12,10 +13,12 @@ import {
|
|||
IconCrown,
|
||||
IconMessage,
|
||||
IconMicDisabled,
|
||||
IconMicrophone,
|
||||
IconMuteEveryoneElse,
|
||||
IconShareVideo,
|
||||
IconVideoOff
|
||||
} from '../../../base/icons';
|
||||
import { MEDIA_TYPE } from '../../../base/media';
|
||||
import {
|
||||
getLocalParticipant,
|
||||
getParticipantByIdOrUndefined,
|
||||
|
@ -31,7 +34,7 @@ import { Drawer, DrawerPortal } from '../../../toolbox/components/web';
|
|||
import { GrantModeratorDialog, KickRemoteParticipantDialog, MuteEveryoneDialog } from '../../../video-menu';
|
||||
import { VolumeSlider } from '../../../video-menu/components/web';
|
||||
import MuteRemoteParticipantsVideoDialog from '../../../video-menu/components/web/MuteRemoteParticipantsVideoDialog';
|
||||
import { getComputedOuterHeight } from '../../functions';
|
||||
import { getComputedOuterHeight, isForceMuted } from '../../functions';
|
||||
|
||||
import {
|
||||
ContextMenu,
|
||||
|
@ -43,6 +46,11 @@ import {
|
|||
|
||||
type Props = {
|
||||
|
||||
/**
|
||||
* Whether or not the participant is audio force muted.
|
||||
*/
|
||||
_isAudioForceMuted: boolean,
|
||||
|
||||
/**
|
||||
* True if the local participant is moderator and false otherwise.
|
||||
*/
|
||||
|
@ -68,6 +76,11 @@ type Props = {
|
|||
*/
|
||||
_isParticipantAudioMuted: boolean,
|
||||
|
||||
/**
|
||||
* Whether or not the participant is video force muted.
|
||||
*/
|
||||
_isVideoForceMuted: boolean,
|
||||
|
||||
/**
|
||||
* Shared video local participant owner.
|
||||
*/
|
||||
|
@ -206,6 +219,7 @@ class MeetingParticipantContextMenu extends Component<Props, State> {
|
|||
this._onSendPrivateMessage = this._onSendPrivateMessage.bind(this);
|
||||
this._position = this._position.bind(this);
|
||||
this._onVolumeChange = this._onVolumeChange.bind(this);
|
||||
this._onAskToUnmute = this._onAskToUnmute.bind(this);
|
||||
}
|
||||
|
||||
_getCurrentParticipantId: () => string;
|
||||
|
@ -344,6 +358,20 @@ class MeetingParticipantContextMenu extends Component<Props, State> {
|
|||
dispatch(setVolume(id, value));
|
||||
}
|
||||
|
||||
_onAskToUnmute: () => void;
|
||||
|
||||
/**
|
||||
* Handles click on ask to unmute.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
_onAskToUnmute() {
|
||||
const { _participant, dispatch } = this.props;
|
||||
const { id } = _participant;
|
||||
|
||||
dispatch(approveParticipant(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements React Component's componentDidMount.
|
||||
*
|
||||
|
@ -373,11 +401,13 @@ class MeetingParticipantContextMenu extends Component<Props, State> {
|
|||
*/
|
||||
render() {
|
||||
const {
|
||||
_isAudioForceMuted,
|
||||
_isLocalModerator,
|
||||
_isChatButtonEnabled,
|
||||
_isParticipantModerator,
|
||||
_isParticipantVideoMuted,
|
||||
_isParticipantAudioMuted,
|
||||
_isVideoForceMuted,
|
||||
_localVideoOwner,
|
||||
_participant,
|
||||
_volume = 1,
|
||||
|
@ -416,6 +446,16 @@ class MeetingParticipantContextMenu extends Component<Props, State> {
|
|||
{_isLocalModerator && (
|
||||
<ContextMenuItemGroup>
|
||||
<>
|
||||
{overflowDrawer && (_isAudioForceMuted || _isVideoForceMuted)
|
||||
&& <ContextMenuItem onClick = { this._onAskToUnmute }>
|
||||
<ContextMenuIcon src = { IconMicrophone } />
|
||||
<span>
|
||||
{t(_isAudioForceMuted
|
||||
? 'participantsPane.actions.askUnmute'
|
||||
: 'participantsPane.actions.allowVideo')}
|
||||
</span>
|
||||
</ContextMenuItem>
|
||||
}
|
||||
{
|
||||
!_isParticipantAudioMuted && overflowDrawer
|
||||
&& <ContextMenuItem onClick = { muteAudio(_participant) }>
|
||||
|
@ -542,11 +582,13 @@ function _mapStateToProps(state, ownProps): Object {
|
|||
const isLocal = participant?.local ?? true;
|
||||
|
||||
return {
|
||||
_isAudioForceMuted: isForceMuted(participant, MEDIA_TYPE.AUDIO, state),
|
||||
_isLocalModerator,
|
||||
_isChatButtonEnabled,
|
||||
_isParticipantModerator,
|
||||
_isParticipantVideoMuted,
|
||||
_isParticipantAudioMuted,
|
||||
_isVideoForceMuted: isForceMuted(participant, MEDIA_TYPE.VIDEO, state),
|
||||
_localVideoOwner: Boolean(ownerId === localParticipantId),
|
||||
_participant: participant,
|
||||
_volume: isLocal ? undefined : id ? participantsVolume[id] : undefined
|
||||
|
|
|
@ -42,10 +42,9 @@ type Props = {
|
|||
_audioTrack: ?Object,
|
||||
|
||||
/**
|
||||
* Media state for video.
|
||||
* Whether or not to disable the moderator indicator.
|
||||
*/
|
||||
_videoMediaState: MediaState,
|
||||
|
||||
_disableModeratorIndicator: boolean,
|
||||
|
||||
/**
|
||||
* The display name of the participant.
|
||||
|
@ -85,6 +84,11 @@ type Props = {
|
|||
*/
|
||||
_raisedHand: boolean,
|
||||
|
||||
/**
|
||||
* Media state for video.
|
||||
*/
|
||||
_videoMediaState: MediaState,
|
||||
|
||||
/**
|
||||
* The translated ask unmute text for the qiuck action buttons.
|
||||
*/
|
||||
|
@ -156,7 +160,7 @@ type Props = {
|
|||
function MeetingParticipantItem({
|
||||
_audioMediaState,
|
||||
_audioTrack,
|
||||
_videoMediaState,
|
||||
_disableModeratorIndicator,
|
||||
_displayName,
|
||||
_local,
|
||||
_localVideoOwner,
|
||||
|
@ -164,6 +168,7 @@ function MeetingParticipantItem({
|
|||
_participantID,
|
||||
_quickActionButtonType,
|
||||
_raisedHand,
|
||||
_videoMediaState,
|
||||
askUnmuteText,
|
||||
isHighlighted,
|
||||
muteAudio,
|
||||
|
@ -219,6 +224,7 @@ function MeetingParticipantItem({
|
|||
<ParticipantItem
|
||||
actionsTrigger = { ACTION_TRIGGER.HOVER }
|
||||
audioMediaState = { audioMediaState }
|
||||
disableModeratorIndicator = { _disableModeratorIndicator }
|
||||
displayName = { _displayName }
|
||||
isHighlighted = { isHighlighted }
|
||||
isModerator = { isParticipantModerator(_participant) }
|
||||
|
@ -279,17 +285,20 @@ function _mapStateToProps(state, ownProps): Object {
|
|||
const _audioTrack = participantID === localParticipantId
|
||||
? getLocalAudioTrack(tracks) : getTrackByMediaTypeAndParticipant(tracks, MEDIA_TYPE.AUDIO, participantID);
|
||||
|
||||
const { disableModeratorIndicator } = state['features/base/config'];
|
||||
|
||||
return {
|
||||
_audioMediaState,
|
||||
_audioTrack,
|
||||
_videoMediaState,
|
||||
_disableModeratorIndicator: disableModeratorIndicator,
|
||||
_displayName: getParticipantDisplayName(state, participant?.id),
|
||||
_local: Boolean(participant?.local),
|
||||
_localVideoOwner: Boolean(ownerId === localParticipantId),
|
||||
_participant: participant,
|
||||
_participantID: participant?.id,
|
||||
_quickActionButtonType,
|
||||
_raisedHand: Boolean(participant?.raisedHand)
|
||||
_raisedHand: Boolean(participant?.raisedHand),
|
||||
_videoMediaState
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -51,6 +51,11 @@ type Props = {
|
|||
*/
|
||||
children: Node,
|
||||
|
||||
/**
|
||||
* Whether or not to disable the moderator indicator.
|
||||
*/
|
||||
disableModeratorIndicator: boolean,
|
||||
|
||||
/**
|
||||
* The name of the participant. Used for showing lobby names.
|
||||
*/
|
||||
|
@ -119,20 +124,21 @@ type Props = {
|
|||
* @returns {ReactNode}
|
||||
*/
|
||||
function ParticipantItem({
|
||||
children,
|
||||
isHighlighted,
|
||||
isModerator,
|
||||
onLeave,
|
||||
actionsTrigger = ACTION_TRIGGER.HOVER,
|
||||
audioMediaState = MEDIA_STATE.NONE,
|
||||
videoMediaState = MEDIA_STATE.NONE,
|
||||
children,
|
||||
disableModeratorIndicator,
|
||||
displayName,
|
||||
participantID,
|
||||
isHighlighted,
|
||||
isModerator,
|
||||
local,
|
||||
onLeave,
|
||||
openDrawerForParticipant,
|
||||
overflowDrawer,
|
||||
participantID,
|
||||
raisedHand,
|
||||
t,
|
||||
videoMediaState = MEDIA_STATE.NONE,
|
||||
youText
|
||||
}: Props) {
|
||||
const ParticipantActions = Actions[actionsTrigger];
|
||||
|
@ -162,7 +168,7 @@ function ParticipantItem({
|
|||
</ParticipantName>
|
||||
{ local ? <span> ({ youText })</span> : null }
|
||||
</ParticipantNameContainer>
|
||||
{isModerator && <ModeratorLabel>
|
||||
{isModerator && !disableModeratorIndicator && <ModeratorLabel>
|
||||
{t('videothumbnail.moderator')}
|
||||
</ModeratorLabel>}
|
||||
</ParticipantDetailsContainer>
|
||||
|
|
Loading…
Reference in New Issue