feat(rn) add mute everyone / (else) capabilities
This commit is contained in:
parent
721848da3f
commit
71fb5aef6c
|
@ -0,0 +1,102 @@
|
|||
// @flow
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { Dialog } from '../../base/dialog';
|
||||
import { getLocalParticipant, getParticipantDisplayName } from '../../base/participants';
|
||||
import { muteAllParticipants } from '../actions';
|
||||
|
||||
import AbstractMuteRemoteParticipantDialog, {
|
||||
type Props as AbstractProps
|
||||
} from './AbstractMuteRemoteParticipantDialog';
|
||||
|
||||
/**
|
||||
* The type of the React {@code Component} props of
|
||||
* {@link AbstractMuteEveryoneDialog}.
|
||||
*/
|
||||
export type Props = AbstractProps & {
|
||||
|
||||
content: string,
|
||||
exclude: Array<string>,
|
||||
title: string
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* An abstract Component with the contents for a dialog that asks for confirmation
|
||||
* from the user before muting all remote participants.
|
||||
*
|
||||
* @extends AbstractMuteRemoteParticipantDialog
|
||||
*/
|
||||
export default class AbstractMuteEveryoneDialog<P: Props> extends AbstractMuteRemoteParticipantDialog<P> {
|
||||
static defaultProps = {
|
||||
exclude: [],
|
||||
muteLocal: false
|
||||
};
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#render()}.
|
||||
*
|
||||
* @inheritdoc
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
const { content, title } = this.props;
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
okKey = 'dialog.muteParticipantButton'
|
||||
onSubmit = { this._onSubmit }
|
||||
titleString = { title }
|
||||
width = 'small'>
|
||||
<div>
|
||||
{ content }
|
||||
</div>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
||||
_onSubmit: () => boolean;
|
||||
|
||||
/**
|
||||
* Callback to be invoked when the value of this dialog is submitted.
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
_onSubmit() {
|
||||
const {
|
||||
dispatch,
|
||||
exclude
|
||||
} = this.props;
|
||||
|
||||
dispatch(muteAllParticipants(exclude));
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps (parts of) the Redux state to the associated {@code AbstractMuteEveryoneDialog}'s props.
|
||||
*
|
||||
* @param {Object} state - The redux state.
|
||||
* @param {Object} ownProps - The properties explicitly passed to the component.
|
||||
* @returns {Props}
|
||||
*/
|
||||
export function abstractMapStateToProps(state: Object, ownProps: Props) {
|
||||
const { exclude, t } = ownProps;
|
||||
|
||||
const whom = exclude
|
||||
// eslint-disable-next-line no-confusing-arrow
|
||||
.map(id => id === getLocalParticipant(state).id
|
||||
? t('dialog.muteEveryoneSelf')
|
||||
: getParticipantDisplayName(state, id))
|
||||
.join(', ');
|
||||
|
||||
return whom.length ? {
|
||||
content: t('dialog.muteEveryoneElseDialog'),
|
||||
title: t('dialog.muteEveryoneElseTitle', { whom })
|
||||
} : {
|
||||
content: t('dialog.muteEveryoneDialog'),
|
||||
title: t('dialog.muteEveryoneTitle')
|
||||
};
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
// @flow
|
||||
|
||||
import { createToolbarEvent, sendAnalytics } from '../../analytics';
|
||||
import { openDialog } from '../../base/dialog';
|
||||
import { IconMuteEveryone } from '../../base/icons';
|
||||
import { AbstractButton, type AbstractButtonProps } from '../../base/toolbox/components';
|
||||
|
||||
import { MuteEveryoneDialog } from '.';
|
||||
|
||||
export type Props = AbstractButtonProps & {
|
||||
|
||||
/**
|
||||
* The redux {@code dispatch} function.
|
||||
*/
|
||||
dispatch: Function,
|
||||
|
||||
/**
|
||||
* The ID of the participant object that this button is supposed to keep unmuted.
|
||||
*/
|
||||
participantID: string,
|
||||
|
||||
/**
|
||||
* The function to be used to translate i18n labels.
|
||||
*/
|
||||
t: Function
|
||||
};
|
||||
|
||||
/**
|
||||
* An abstract remote video menu button which mutes all the other participants.
|
||||
*/
|
||||
export default class AbstractMuteEveryoneElseButton extends AbstractButton<Props, *> {
|
||||
accessibilityLabel = 'toolbar.accessibilityLabel.muteEveryoneElse';
|
||||
icon = IconMuteEveryone;
|
||||
label = 'videothumbnail.domuteOthers';
|
||||
|
||||
/**
|
||||
* Handles clicking / pressing the button, and opens a confirmation dialog.
|
||||
*
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
_handleClick() {
|
||||
const { dispatch, participantID } = this.props;
|
||||
|
||||
sendAnalytics(createToolbarEvent('mute.everyoneelse.pressed'));
|
||||
dispatch(openDialog(MuteEveryoneDialog, { exclude: [ participantID ] }));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
// @flow
|
||||
|
||||
import React from 'react';
|
||||
import { Text } from 'react-native';
|
||||
|
||||
import { ColorSchemeRegistry } from '../../../base/color-scheme';
|
||||
import { ConfirmDialog } from '../../../base/dialog';
|
||||
import { translate } from '../../../base/i18n';
|
||||
import { connect } from '../../../base/redux';
|
||||
import { StyleType } from '../../../base/styles';
|
||||
import AbstractMuteEveryoneDialog, {
|
||||
abstractMapStateToProps,
|
||||
type Props as AbstractProps } from '../AbstractMuteEveryoneDialog';
|
||||
|
||||
type Props = AbstractProps & {
|
||||
|
||||
/**
|
||||
* The color-schemed stylesheet of the base/dialog feature.
|
||||
*/
|
||||
_dialogStyles: StyleType
|
||||
}
|
||||
|
||||
/**
|
||||
* A React Component with the contents for a dialog that asks for confirmation
|
||||
* from the user before muting all remote participants.
|
||||
*
|
||||
* @extends AbstractMuteEveryoneDialog
|
||||
*/
|
||||
class MuteEveryoneDialog extends AbstractMuteEveryoneDialog<Props> {
|
||||
|
||||
/**
|
||||
* Implements {@code Component#render}.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
render() {
|
||||
return (
|
||||
<ConfirmDialog
|
||||
okKey = 'dialog.muteParticipantButton'
|
||||
onSubmit = { this._onSubmit } >
|
||||
<Text style = { this.props._dialogStyles.text }>
|
||||
{ `${this.props.title} \n\n ${this.props.content}` }
|
||||
</Text>
|
||||
</ConfirmDialog>
|
||||
);
|
||||
}
|
||||
|
||||
_onSubmit: () => boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps part of the Redux state to the props of this component.
|
||||
*
|
||||
* @param {Object} state - The Redux state.
|
||||
* @param {Props} ownProps - The own props of the component.
|
||||
* @returns {{
|
||||
* _dialogStyles: StyleType
|
||||
* }}
|
||||
*/
|
||||
function _mapStateToProps(state: Object, ownProps: Props) {
|
||||
return {
|
||||
...abstractMapStateToProps(state, ownProps),
|
||||
_dialogStyles: ColorSchemeRegistry.get(state, 'Dialog')
|
||||
};
|
||||
}
|
||||
|
||||
export default translate(connect(_mapStateToProps)(MuteEveryoneDialog));
|
|
@ -0,0 +1,20 @@
|
|||
// @flow
|
||||
|
||||
import { translate } from '../../../base/i18n';
|
||||
import { isLocalParticipantModerator } from '../../../base/participants';
|
||||
import { connect } from '../../../base/redux';
|
||||
import AbstractMuteEveryoneElseButton from '../AbstractMuteEveryoneElseButton';
|
||||
|
||||
/**
|
||||
* Maps part of the Redux state to the props of this component.
|
||||
*
|
||||
* @param {Object} state - The Redux state.
|
||||
* @returns {Props}
|
||||
*/
|
||||
function _mapStateToProps(state) {
|
||||
return {
|
||||
visible: isLocalParticipantModerator(state)
|
||||
};
|
||||
}
|
||||
|
||||
export default translate(connect(_mapStateToProps)(AbstractMuteEveryoneElseButton));
|
|
@ -16,6 +16,7 @@ import { hideRemoteVideoMenu } from '../../actions';
|
|||
import GrantModeratorButton from './GrantModeratorButton';
|
||||
import KickButton from './KickButton';
|
||||
import MuteButton from './MuteButton';
|
||||
import MuteEveryoneElseButton from './MuteEveryoneElseButton';
|
||||
import PinButton from './PinButton';
|
||||
import styles from './styles';
|
||||
|
||||
|
@ -104,6 +105,7 @@ class RemoteVideoMenu extends PureComponent<Props> {
|
|||
<GrantModeratorButton { ...buttonProps } />
|
||||
<PinButton { ...buttonProps } />
|
||||
<PrivateMessageButton { ...buttonProps } />
|
||||
<MuteEveryoneElseButton { ...buttonProps } />
|
||||
</BottomSheet>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,12 +1,7 @@
|
|||
// @flow
|
||||
|
||||
export {
|
||||
default as GrantModeratorDialog
|
||||
} from './GrantModeratorDialog';
|
||||
export {
|
||||
default as KickRemoteParticipantDialog
|
||||
} from './KickRemoteParticipantDialog';
|
||||
export {
|
||||
default as MuteRemoteParticipantDialog
|
||||
} from './MuteRemoteParticipantDialog';
|
||||
export { default as GrantModeratorDialog } from './GrantModeratorDialog';
|
||||
export { default as KickRemoteParticipantDialog } from './KickRemoteParticipantDialog';
|
||||
export { default as MuteEveryoneDialog } from './MuteEveryoneDialog';
|
||||
export { default as MuteRemoteParticipantDialog } from './MuteRemoteParticipantDialog';
|
||||
export { default as RemoteVideoMenu } from './RemoteVideoMenu';
|
||||
|
|
|
@ -5,53 +5,15 @@ import React from 'react';
|
|||
import { Dialog } from '../../../base/dialog';
|
||||
import { translate } from '../../../base/i18n';
|
||||
import { connect } from '../../../base/redux';
|
||||
import { muteAllParticipants } from '../../actions';
|
||||
import AbstractMuteRemoteParticipantDialog, {
|
||||
type Props as AbstractProps
|
||||
} from '../AbstractMuteRemoteParticipantDialog';
|
||||
|
||||
declare var APP: Object;
|
||||
|
||||
/**
|
||||
* The type of the React {@code Component} props of
|
||||
* {@link MuteEveryoneDialog}.
|
||||
*/
|
||||
type Props = AbstractProps & {
|
||||
|
||||
/**
|
||||
* The IDs of the remote participants to exclude from being muted.
|
||||
*/
|
||||
exclude: Array<string>
|
||||
};
|
||||
|
||||
/**
|
||||
* Translations needed for dialog rendering.
|
||||
*/
|
||||
type Translations = {
|
||||
|
||||
/**
|
||||
* Content text.
|
||||
*/
|
||||
content: string,
|
||||
|
||||
/**
|
||||
* Title text.
|
||||
*/
|
||||
title: string
|
||||
}
|
||||
import AbstractMuteEveryoneDialog, { abstractMapStateToProps, type Props } from '../AbstractMuteEveryoneDialog';
|
||||
|
||||
/**
|
||||
* A React Component with the contents for a dialog that asks for confirmation
|
||||
* from the user before muting a remote participant.
|
||||
* from the user before muting all remote participants.
|
||||
*
|
||||
* @extends Component
|
||||
* @extends AbstractMuteEveryoneDialog
|
||||
*/
|
||||
class MuteEveryoneDialog extends AbstractMuteRemoteParticipantDialog<Props> {
|
||||
static defaultProps = {
|
||||
exclude: [],
|
||||
muteLocal: false
|
||||
};
|
||||
|
||||
class MuteEveryoneDialog extends AbstractMuteEveryoneDialog<Props> {
|
||||
/**
|
||||
* Implements React's {@link Component#render()}.
|
||||
*
|
||||
|
@ -59,64 +21,20 @@ class MuteEveryoneDialog extends AbstractMuteRemoteParticipantDialog<Props> {
|
|||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
const { content, title } = this._getTranslations();
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
okKey = 'dialog.muteParticipantButton'
|
||||
onSubmit = { this._onSubmit }
|
||||
titleString = { title }
|
||||
titleString = { this.props.title }
|
||||
width = 'small'>
|
||||
<div>
|
||||
{ content }
|
||||
{ this.props.content }
|
||||
</div>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
||||
_onSubmit: () => boolean;
|
||||
|
||||
/**
|
||||
* Callback to be invoked when the value of this dialog is submitted.
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
_onSubmit() {
|
||||
const {
|
||||
dispatch,
|
||||
exclude
|
||||
} = this.props;
|
||||
|
||||
dispatch(muteAllParticipants(exclude));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to get translations depending on whether we have an exclusive
|
||||
* mute or not.
|
||||
*
|
||||
* @returns {Translations}
|
||||
* @private
|
||||
*/
|
||||
_getTranslations(): Translations {
|
||||
const { exclude, t } = this.props;
|
||||
const { conference } = APP;
|
||||
const whom = exclude
|
||||
// eslint-disable-next-line no-confusing-arrow
|
||||
.map(id => conference.isLocalId(id)
|
||||
? t('dialog.muteEveryoneSelf')
|
||||
: conference.getParticipantDisplayName(id))
|
||||
.join(', ');
|
||||
|
||||
return whom.length ? {
|
||||
content: t('dialog.muteEveryoneElseDialog'),
|
||||
title: t('dialog.muteEveryoneElseTitle', { whom })
|
||||
} : {
|
||||
content: t('dialog.muteEveryoneDialog'),
|
||||
title: t('dialog.muteEveryoneTitle')
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export default translate(connect()(MuteEveryoneDialog));
|
||||
export default translate(connect(abstractMapStateToProps)(MuteEveryoneDialog));
|
||||
|
|
|
@ -2,17 +2,13 @@
|
|||
|
||||
import React from 'react';
|
||||
|
||||
import { createToolbarEvent, sendAnalytics } from '../../../analytics';
|
||||
import { openDialog } from '../../../base/dialog';
|
||||
import { translate } from '../../../base/i18n';
|
||||
import { IconMuteEveryoneElse } from '../../../base/icons';
|
||||
import { connect } from '../../../base/redux';
|
||||
import AbstractMuteButton, {
|
||||
_mapStateToProps,
|
||||
import AbstractMuteEveryoneElseButton, {
|
||||
type Props
|
||||
} from '../AbstractMuteButton';
|
||||
} from '../AbstractMuteEveryoneElseButton';
|
||||
|
||||
import MuteEveryoneDialog from './MuteEveryoneDialog';
|
||||
import RemoteVideoMenuButton from './RemoteVideoMenuButton';
|
||||
|
||||
/**
|
||||
|
@ -20,9 +16,9 @@ import RemoteVideoMenuButton from './RemoteVideoMenuButton';
|
|||
* every participant in the conference except the one with the given
|
||||
* participantID
|
||||
*/
|
||||
class MuteEveryoneElseButton extends AbstractMuteButton {
|
||||
class MuteEveryoneElseButton extends AbstractMuteEveryoneElseButton {
|
||||
/**
|
||||
* Instantiates a new {@code MuteEveryoneElseButton}.
|
||||
* Instantiates a new {@code Component}.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
|
@ -53,19 +49,6 @@ class MuteEveryoneElseButton extends AbstractMuteButton {
|
|||
}
|
||||
|
||||
_handleClick: () => void;
|
||||
|
||||
/**
|
||||
* Handles clicking / pressing the button, and opens a confirmation dialog.
|
||||
*
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
_handleClick() {
|
||||
const { dispatch, participantID } = this.props;
|
||||
|
||||
sendAnalytics(createToolbarEvent('mute.everyoneelse.pressed'));
|
||||
dispatch(openDialog(MuteEveryoneDialog, { exclude: [ participantID ] }));
|
||||
}
|
||||
}
|
||||
|
||||
export default translate(connect(_mapStateToProps)(MuteEveryoneElseButton));
|
||||
export default translate(connect()(MuteEveryoneElseButton));
|
||||
|
|
|
@ -9,10 +9,11 @@ import { Popover } from '../../../base/popover';
|
|||
import { connect } from '../../../base/redux';
|
||||
import { isRemoteTrackMuted } from '../../../base/tracks';
|
||||
|
||||
import MuteEveryoneElseButton from './MuteEveryoneElseButton';
|
||||
|
||||
import {
|
||||
GrantModeratorButton,
|
||||
MuteButton,
|
||||
MuteEveryoneElseButton,
|
||||
KickButton,
|
||||
PrivateMessageMenuButton,
|
||||
RemoteControlButton,
|
||||
|
|
|
@ -1,26 +1,15 @@
|
|||
// @flow
|
||||
|
||||
export { default as GrantModeratorButton } from './GrantModeratorButton';
|
||||
export {
|
||||
default as GrantModeratorDialog
|
||||
} from './GrantModeratorDialog';
|
||||
export { default as GrantModeratorDialog } from './GrantModeratorDialog';
|
||||
export { default as KickButton } from './KickButton';
|
||||
export {
|
||||
default as KickRemoteParticipantDialog
|
||||
} from './KickRemoteParticipantDialog';
|
||||
export { default as KickRemoteParticipantDialog } from './KickRemoteParticipantDialog';
|
||||
export { default as MuteButton } from './MuteButton';
|
||||
export { default as MuteEveryoneElseButton } from './MuteEveryoneElseButton';
|
||||
export { default as MuteEveryoneDialog } from './MuteEveryoneDialog';
|
||||
export {
|
||||
default as MuteRemoteParticipantDialog
|
||||
} from './MuteRemoteParticipantDialog';
|
||||
export { default as MuteEveryoneElseButton } from './MuteEveryoneElseButton';
|
||||
export { default as MuteRemoteParticipantDialog } from './MuteRemoteParticipantDialog';
|
||||
export { default as PrivateMessageMenuButton } from './PrivateMessageMenuButton';
|
||||
export {
|
||||
REMOTE_CONTROL_MENU_STATES,
|
||||
default as RemoteControlButton
|
||||
} from './RemoteControlButton';
|
||||
export { REMOTE_CONTROL_MENU_STATES, default as RemoteControlButton } from './RemoteControlButton';
|
||||
export { default as RemoteVideoMenu } from './RemoteVideoMenu';
|
||||
export {
|
||||
default as RemoteVideoMenuTriggerButton
|
||||
} from './RemoteVideoMenuTriggerButton';
|
||||
export { default as RemoteVideoMenuTriggerButton } from './RemoteVideoMenuTriggerButton';
|
||||
export { default as VolumeSlider } from './VolumeSlider';
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
// @flow
|
||||
|
||||
import { createToolbarEvent, sendAnalytics } from '../../../analytics';
|
||||
import { openDialog } from '../../../base/dialog';
|
||||
import { translate } from '../../../base/i18n';
|
||||
import { IconMuteEveryone } from '../../../base/icons';
|
||||
import { getLocalParticipant, PARTICIPANT_ROLE } from '../../../base/participants';
|
||||
import { connect } from '../../../base/redux';
|
||||
import { AbstractButton, type AbstractButtonProps } from '../../../base/toolbox/components';
|
||||
import { MuteEveryoneDialog } from '../../../remote-video-menu';
|
||||
import { createToolbarEvent, sendAnalytics } from '../../analytics';
|
||||
import { openDialog } from '../../base/dialog';
|
||||
import { translate } from '../../base/i18n';
|
||||
import { IconMuteEveryone } from '../../base/icons';
|
||||
import { getLocalParticipant, PARTICIPANT_ROLE } from '../../base/participants';
|
||||
import { connect } from '../../base/redux';
|
||||
import { AbstractButton, type AbstractButtonProps } from '../../base/toolbox/components';
|
||||
import { MuteEveryoneDialog } from '../../remote-video-menu/components';
|
||||
|
||||
type Props = AbstractButtonProps & {
|
||||
|
|
@ -19,6 +19,7 @@ import { ClosedCaptionButton } from '../../../subtitles';
|
|||
import { TileViewButton } from '../../../video-layout';
|
||||
import { VideoShareButton } from '../../../youtube-player/components';
|
||||
import HelpButton from '../HelpButton';
|
||||
import MuteEveryoneButton from '../MuteEveryoneButton';
|
||||
|
||||
import AudioOnlyButton from './AudioOnlyButton';
|
||||
import MoreOptionsButton from './MoreOptionsButton';
|
||||
|
@ -143,6 +144,7 @@ class OverflowMenu extends PureComponent<Props, State> {
|
|||
<RoomLockButton { ...buttonProps } />
|
||||
<ClosedCaptionButton { ...buttonProps } />
|
||||
<SharedDocumentButton { ...buttonProps } />
|
||||
<MuteEveryoneButton { ...buttonProps } />
|
||||
<HelpButton { ...buttonProps } />
|
||||
</Collapsible>
|
||||
</BottomSheet>
|
||||
|
|
|
@ -79,9 +79,9 @@ import { isToolboxVisible } from '../../functions';
|
|||
import DownloadButton from '../DownloadButton';
|
||||
import HangupButton from '../HangupButton';
|
||||
import HelpButton from '../HelpButton';
|
||||
import MuteEveryoneButton from '../MuteEveryoneButton';
|
||||
|
||||
import AudioSettingsButton from './AudioSettingsButton';
|
||||
import MuteEveryoneButton from './MuteEveryoneButton';
|
||||
import OverflowMenuButton from './OverflowMenuButton';
|
||||
import OverflowMenuProfileItem from './OverflowMenuProfileItem';
|
||||
import ToolbarButton from './ToolbarButton';
|
||||
|
|
Loading…
Reference in New Issue