feat(rn,security) add security dialog
This commit is contained in:
parent
524af5ca67
commit
bf3726cb93
|
@ -226,7 +226,7 @@
|
|||
"liveStreamingDisabledBecauseOfActiveRecordingTooltip": "Not possible while recording is active",
|
||||
"liveStreamingDisabledTooltip": "Start live stream disabled.",
|
||||
"lockMessage": "Failed to lock the conference.",
|
||||
"lockRoom": "Add meeting $t(lockRoomPasswordUppercase)",
|
||||
"lockRoom": "Add meeting $t(lockRoomPassword)",
|
||||
"lockTitle": "Lock failed",
|
||||
"logoutQuestion": "Are you sure you want to logout and stop the conference?",
|
||||
"login": "Login",
|
||||
|
@ -525,7 +525,7 @@
|
|||
"oldElectronClientDescription2": "latest build",
|
||||
"oldElectronClientDescription3": " now!"
|
||||
},
|
||||
"passwordSetRemotely": "set by another participant",
|
||||
"passwordSetRemotely": "Set by another participant",
|
||||
"passwordDigitsOnly": "Up to {{number}} digits",
|
||||
"poweredby": "powered by",
|
||||
"prejoin": {
|
||||
|
|
|
@ -38,7 +38,7 @@ import {
|
|||
resizeLargeVideo,
|
||||
selectParticipantInLargeVideo
|
||||
} from '../../react/features/large-video/actions';
|
||||
import { toggleLobbyMode } from '../../react/features/lobby/actions.web';
|
||||
import { toggleLobbyMode } from '../../react/features/lobby/actions';
|
||||
import { RECORDING_TYPES } from '../../react/features/recording/constants';
|
||||
import { getActiveSession } from '../../react/features/recording/functions';
|
||||
import { toggleTileView, setTileView } from '../../react/features/video-layout';
|
||||
|
|
|
@ -116,6 +116,24 @@ const brandedDialogText = {
|
|||
textAlign: 'center'
|
||||
};
|
||||
|
||||
const brandedDialogLabelStyle = {
|
||||
color: schemeColor('text'),
|
||||
flexShrink: 1,
|
||||
fontSize: MD_FONT_SIZE,
|
||||
opacity: 0.90
|
||||
};
|
||||
|
||||
const brandedDialogItemContainerStyle = {
|
||||
alignItems: 'center',
|
||||
flexDirection: 'row',
|
||||
height: MD_ITEM_HEIGHT
|
||||
};
|
||||
|
||||
const brandedDialogIconStyle = {
|
||||
color: schemeColor('icon'),
|
||||
fontSize: 24
|
||||
};
|
||||
|
||||
export const inputDialog = {
|
||||
bottomField: {
|
||||
marginBottom: 0
|
||||
|
@ -145,28 +163,22 @@ ColorSchemeRegistry.register('BottomSheet', {
|
|||
* Style for the {@code Icon} element in a generic item of the menu.
|
||||
*/
|
||||
iconStyle: {
|
||||
color: schemeColor('icon'),
|
||||
fontSize: 24
|
||||
...brandedDialogIconStyle
|
||||
},
|
||||
|
||||
/**
|
||||
* Style for the label in a generic item rendered in the menu.
|
||||
*/
|
||||
labelStyle: {
|
||||
color: schemeColor('text'),
|
||||
flexShrink: 1,
|
||||
fontSize: MD_FONT_SIZE,
|
||||
marginLeft: 32,
|
||||
opacity: 0.90
|
||||
...brandedDialogLabelStyle,
|
||||
marginLeft: 32
|
||||
},
|
||||
|
||||
/**
|
||||
* Container style for a generic item rendered in the menu.
|
||||
*/
|
||||
style: {
|
||||
alignItems: 'center',
|
||||
flexDirection: 'row',
|
||||
height: MD_ITEM_HEIGHT
|
||||
...brandedDialogItemContainerStyle
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -258,3 +270,28 @@ ColorSchemeRegistry.register('Dialog', {
|
|||
borderTopWidth: 1
|
||||
}
|
||||
});
|
||||
|
||||
ColorSchemeRegistry.register('SecurityDialog', {
|
||||
/**
|
||||
* Field on an input dialog.
|
||||
*/
|
||||
field: {
|
||||
borderBottomWidth: 1,
|
||||
borderColor: schemeColor('border'),
|
||||
color: schemeColor('text'),
|
||||
fontSize: 14,
|
||||
paddingBottom: 8
|
||||
},
|
||||
|
||||
text: {
|
||||
color: schemeColor('text'),
|
||||
fontSize: 14,
|
||||
marginTop: 8
|
||||
},
|
||||
|
||||
title: {
|
||||
color: schemeColor('text'),
|
||||
fontSize: 18,
|
||||
fontWeight: 'bold'
|
||||
}
|
||||
});
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
// @flow
|
||||
|
||||
import { type Dispatch } from 'redux';
|
||||
|
||||
import {
|
||||
getCurrentConference
|
||||
} from '../base/conference';
|
||||
|
||||
/**
|
||||
* Action to toggle lobby mode on or off.
|
||||
*
|
||||
* @param {boolean} enabled - The desired (new) state of the lobby mode.
|
||||
* @returns {Function}
|
||||
*/
|
||||
export function toggleLobbyMode(enabled: boolean) {
|
||||
return async (dispatch: Dispatch<any>, getState: Function) => {
|
||||
const conference = getCurrentConference(getState);
|
||||
|
||||
if (enabled) {
|
||||
conference.enableLobby();
|
||||
} else {
|
||||
conference.disableLobby();
|
||||
}
|
||||
};
|
||||
}
|
|
@ -11,6 +11,7 @@ import {
|
|||
} from '../base/conference';
|
||||
import { hideDialog, openDialog } from '../base/dialog';
|
||||
import { getLocalParticipant } from '../base/participants';
|
||||
export * from './actions.any';
|
||||
|
||||
import {
|
||||
KNOCKING_PARTICIPANT_ARRIVED_OR_UPDATED,
|
||||
|
@ -198,20 +199,3 @@ export function startKnocking() {
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Action to toggle lobby mode on or off.
|
||||
*
|
||||
* @param {boolean} enabled - The desired (new) state of the lobby mode.
|
||||
* @returns {Function}
|
||||
*/
|
||||
export function toggleLobbyMode(enabled: boolean) {
|
||||
return async (dispatch: Dispatch<any>, getState: Function) => {
|
||||
const conference = getCurrentConference(getState);
|
||||
|
||||
if (enabled) {
|
||||
conference.enableLobby();
|
||||
} else {
|
||||
conference.disableLobby();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,78 +0,0 @@
|
|||
// @flow
|
||||
|
||||
import { getCurrentConference } from '../../../base/conference';
|
||||
import { translate } from '../../../base/i18n';
|
||||
import { IconMeetingUnlocked, IconMeetingLocked } from '../../../base/icons';
|
||||
import { isLocalParticipantModerator } from '../../../base/participants';
|
||||
import { connect } from '../../../base/redux';
|
||||
import AbstractButton, { type Props as AbstractProps } from '../../../base/toolbox/components/AbstractButton';
|
||||
import { showDisableLobbyModeDialog, showEnableLobbyModeDialog } from '../../actions.native';
|
||||
|
||||
type Props = AbstractProps & {
|
||||
|
||||
/**
|
||||
* The Redux Dispatch function.
|
||||
*/
|
||||
dispatch: Function,
|
||||
|
||||
/**
|
||||
* True if the lobby mode is currently enabled for this conference.
|
||||
*/
|
||||
lobbyEnabled: boolean
|
||||
};
|
||||
|
||||
/**
|
||||
* Component to render the lobby mode initiator button.
|
||||
*/
|
||||
class LobbyModeButton extends AbstractButton<Props, any> {
|
||||
accessibilityLabel = 'toolbar.accessibilityLabel.lobbyButton';
|
||||
icon = IconMeetingUnlocked;
|
||||
label = 'toolbar.lobbyButtonEnable';
|
||||
toggledLabel = 'toolbar.lobbyButtonDisable'
|
||||
toggledIcon = IconMeetingLocked;
|
||||
|
||||
/**
|
||||
* Callback for the click event of the button.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
_handleClick() {
|
||||
const { dispatch } = this.props;
|
||||
|
||||
if (this._isToggled()) {
|
||||
dispatch(showDisableLobbyModeDialog());
|
||||
} else {
|
||||
dispatch(showEnableLobbyModeDialog());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to define the button state.
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
_isToggled() {
|
||||
return this.props.lobbyEnabled;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps part of the Redux store to the props of this component.
|
||||
*
|
||||
* @param {Object} state - The Redux state.
|
||||
* @param {Props} ownProps - The own props of the component.
|
||||
* @returns {Props}
|
||||
*/
|
||||
export function _mapStateToProps(state: Object): $Shape<Props> {
|
||||
const conference = getCurrentConference(state);
|
||||
const { lobbyEnabled } = state['features/lobby'];
|
||||
const { hideLobbyButton } = state['features/base/config'];
|
||||
const lobbySupported = conference && conference.isLobbySupported();
|
||||
|
||||
return {
|
||||
lobbyEnabled,
|
||||
visible: lobbySupported && isLocalParticipantModerator(state) && !hideLobbyButton
|
||||
};
|
||||
}
|
||||
|
||||
export default translate(connect(_mapStateToProps)(LobbyModeButton));
|
|
@ -0,0 +1,58 @@
|
|||
// @flow
|
||||
|
||||
import React from 'react';
|
||||
import { Switch, View } from 'react-native';
|
||||
|
||||
import { translate } from '../../../base/i18n';
|
||||
import { connect } from '../../../base/redux';
|
||||
|
||||
import styles, {
|
||||
ENABLED_THUMB_COLOR,
|
||||
ENABLED_TRACK_COLOR,
|
||||
DISABLED_THUMB_COLOR
|
||||
} from './styles';
|
||||
|
||||
/**
|
||||
* The type of the React {@code Component} props of {@link LobbyModeSwitch}.
|
||||
*/
|
||||
type Props = {
|
||||
|
||||
/**
|
||||
* True if the lobby mode is currently enabled for this conference.
|
||||
*/
|
||||
lobbyEnabled: boolean,
|
||||
|
||||
/**
|
||||
* Callback to be invoked when handling enable-disable lobby mode switch.
|
||||
*/
|
||||
onToggleLobbyMode: Function
|
||||
};
|
||||
|
||||
/**
|
||||
* Component meant to Enable/Disable lobby mode.
|
||||
*
|
||||
* @returns {React$Element<any>}
|
||||
*/
|
||||
function LobbyModeSwitch(
|
||||
{
|
||||
lobbyEnabled,
|
||||
onToggleLobbyMode
|
||||
}: Props) {
|
||||
|
||||
return (
|
||||
<View style = { styles.lobbySwitchContainer }>
|
||||
<Switch
|
||||
onValueChange = { onToggleLobbyMode }
|
||||
style = { styles.lobbySwitchIcon }
|
||||
thumbColor = {
|
||||
lobbyEnabled
|
||||
? ENABLED_THUMB_COLOR
|
||||
: DISABLED_THUMB_COLOR
|
||||
}
|
||||
trackColor = {{ true: ENABLED_TRACK_COLOR }}
|
||||
value = { lobbyEnabled } />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
export default translate(connect()(LobbyModeSwitch));
|
|
@ -3,5 +3,4 @@
|
|||
export { default as DisableLobbyModeDialog } from './DisableLobbyModeDialog';
|
||||
export { default as EnableLobbyModeDialog } from './EnableLobbyModeDialog';
|
||||
export { default as KnockingParticipantList } from './KnockingParticipantList';
|
||||
export { default as LobbyModeButton } from './LobbyModeButton';
|
||||
export { default as LobbyScreen } from './LobbyScreen';
|
||||
|
|
|
@ -4,6 +4,10 @@ import { ColorPalette } from '../../../base/styles';
|
|||
|
||||
const SECONDARY_COLOR = '#B8C7E0';
|
||||
|
||||
export const ENABLED_THUMB_COLOR = ColorPalette.blueHighlight;
|
||||
export const ENABLED_TRACK_COLOR = ColorPalette.blue;
|
||||
export const DISABLED_THUMB_COLOR = ColorPalette.darkGrey;
|
||||
|
||||
export default {
|
||||
button: {
|
||||
alignItems: 'center',
|
||||
|
@ -138,5 +142,14 @@ export default {
|
|||
|
||||
knockingParticipantListText: {
|
||||
color: 'white'
|
||||
},
|
||||
|
||||
lobbySwitchContainer: {
|
||||
flexDirection: 'column',
|
||||
marginTop: 16
|
||||
},
|
||||
|
||||
lobbySwitchIcon: {
|
||||
alignSelf: 'flex-end'
|
||||
}
|
||||
};
|
||||
|
|
|
@ -12,34 +12,12 @@ import {
|
|||
setPassword
|
||||
} from '../base/conference';
|
||||
import { hideDialog, openDialog } from '../base/dialog';
|
||||
import { SecurityDialog } from '../security/components/security-dialog';
|
||||
|
||||
import { PasswordRequiredPrompt, RoomLockPrompt } from './components';
|
||||
import { PasswordRequiredPrompt } from './components';
|
||||
|
||||
declare var APP: Object;
|
||||
|
||||
/**
|
||||
* Begins a (user) request to lock a specific conference/room.
|
||||
*
|
||||
* @param {JitsiConference|undefined} conference - The JitsiConference to lock
|
||||
* if specified or undefined if the current JitsiConference is to be locked.
|
||||
* @returns {Function}
|
||||
*/
|
||||
export function beginRoomLockRequest(conference: ?Object) {
|
||||
return (dispatch: Function, getState: Function) => {
|
||||
if (typeof conference === 'undefined') {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
conference = getState()['features/base/conference'].conference;
|
||||
}
|
||||
if (conference) {
|
||||
const passwordNumberOfDigits = getState()['features/base/config'].roomPasswordNumberOfDigits;
|
||||
|
||||
dispatch(openDialog(RoomLockPrompt, {
|
||||
conference,
|
||||
passwordNumberOfDigits }));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels a prompt for a password to join a specific conference/room.
|
||||
*
|
||||
|
@ -99,7 +77,7 @@ export function endRoomLockRequest(
|
|||
= password
|
||||
? dispatch(setPassword(conference, conference.lock, password))
|
||||
: Promise.resolve();
|
||||
const endRoomLockRequest_ = () => dispatch(hideDialog(RoomLockPrompt));
|
||||
const endRoomLockRequest_ = () => dispatch(hideDialog(SecurityDialog));
|
||||
|
||||
setPassword_.then(endRoomLockRequest_, endRoomLockRequest_);
|
||||
};
|
||||
|
@ -137,3 +115,5 @@ export function unlockRoom() {
|
|||
));
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,101 +0,0 @@
|
|||
// @flow
|
||||
|
||||
import { MEETING_PASSWORD_ENABLED, getFeatureFlag } from '../../base/flags';
|
||||
import { translate } from '../../base/i18n';
|
||||
import { IconRoomLock, IconRoomUnlock } from '../../base/icons';
|
||||
import { isLocalParticipantModerator } from '../../base/participants';
|
||||
import { connect } from '../../base/redux';
|
||||
import { AbstractButton, type AbstractButtonProps } from '../../base/toolbox/components';
|
||||
import { beginRoomLockRequest, unlockRoom } from '../actions';
|
||||
|
||||
type Props = AbstractButtonProps & {
|
||||
|
||||
/**
|
||||
* Whether the current local participant is a moderator, therefore is
|
||||
* allowed to lock or unlock the conference.
|
||||
*/
|
||||
_localParticipantModerator: boolean,
|
||||
|
||||
/**
|
||||
* Whether the current conference is locked or not.
|
||||
*/
|
||||
_locked: boolean,
|
||||
|
||||
/**
|
||||
* The redux {@code dispatch} function.
|
||||
*/
|
||||
dispatch: Function
|
||||
};
|
||||
|
||||
/**
|
||||
* An implementation of a button for locking / unlocking a room.
|
||||
*/
|
||||
class RoomLockButton extends AbstractButton<Props, *> {
|
||||
accessibilityLabel = 'toolbar.accessibilityLabel.lockRoom';
|
||||
icon = IconRoomLock;
|
||||
label = 'dialog.lockRoom';
|
||||
toggledIcon = IconRoomUnlock;
|
||||
toggledLabel = 'dialog.unlockRoom';
|
||||
|
||||
/**
|
||||
* Handles clicking / pressing the button.
|
||||
*
|
||||
* @override
|
||||
* @protected
|
||||
* @returns {void}
|
||||
*/
|
||||
_handleClick() {
|
||||
const { dispatch, _locked } = this.props;
|
||||
|
||||
if (_locked) {
|
||||
dispatch(unlockRoom());
|
||||
} else {
|
||||
dispatch(beginRoomLockRequest());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether this button is disabled or not.
|
||||
*
|
||||
* @override
|
||||
* @protected
|
||||
* @returns {boolean}
|
||||
*/
|
||||
_isDisabled() {
|
||||
return !this.props._localParticipantModerator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether this button is in toggled state or not.
|
||||
*
|
||||
* @override
|
||||
* @protected
|
||||
* @returns {boolean}
|
||||
*/
|
||||
_isToggled() {
|
||||
return this.props._locked;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps (parts of) the redux state to the associated props for the
|
||||
* {@code RoomLockButton} component.
|
||||
*
|
||||
* @param {Object} state - The Redux state.
|
||||
* @param {Object} ownProps - The properties explicitly passed to the component instance.
|
||||
* @private
|
||||
* @returns {Props}
|
||||
*/
|
||||
function _mapStateToProps(state, ownProps): Object {
|
||||
const { conference, locked } = state['features/base/conference'];
|
||||
const enabled = getFeatureFlag(state, MEETING_PASSWORD_ENABLED, true);
|
||||
const { visible = enabled } = ownProps;
|
||||
|
||||
return {
|
||||
_localParticipantModerator: Boolean(conference && isLocalParticipantModerator(state)),
|
||||
_locked: Boolean(conference && locked),
|
||||
visible
|
||||
};
|
||||
}
|
||||
|
||||
export default translate(connect(_mapStateToProps)(RoomLockButton));
|
|
@ -1,140 +0,0 @@
|
|||
// @flow
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import type { Dispatch } from 'redux';
|
||||
|
||||
import { InputDialog } from '../../base/dialog';
|
||||
import { connect } from '../../base/redux';
|
||||
import { endRoomLockRequest } from '../actions';
|
||||
|
||||
/**
|
||||
* The style of the {@link TextInput} rendered by {@code RoomLockPrompt}. As it
|
||||
* requests the entry of a password, {@code TextInput} automatically correcting
|
||||
* the entry of the password is a pain to deal with as a user.
|
||||
*/
|
||||
const _TEXT_INPUT_PROPS = {
|
||||
autoCapitalize: 'none',
|
||||
autoCorrect: false
|
||||
};
|
||||
|
||||
/**
|
||||
* The type of the React {@code Component} props of {@link RoomLockPrompt}.
|
||||
*/
|
||||
type Props = {
|
||||
|
||||
/**
|
||||
* The JitsiConference which requires a password.
|
||||
*/
|
||||
conference: Object,
|
||||
|
||||
/**
|
||||
* The number of digits to be used in the password.
|
||||
*/
|
||||
passwordNumberOfDigits: ?number,
|
||||
|
||||
/**
|
||||
* Redux store dispatch function.
|
||||
*/
|
||||
dispatch: Dispatch<any>
|
||||
};
|
||||
|
||||
/**
|
||||
* Implements a React Component which prompts the user for a password to lock a
|
||||
* conference/room.
|
||||
*/
|
||||
class RoomLockPrompt extends Component<Props> {
|
||||
/**
|
||||
* Initializes a new RoomLockPrompt instance.
|
||||
*
|
||||
* @param {Props} props - The read-only properties with which the new
|
||||
* instance is to be initialized.
|
||||
*/
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
// Bind event handlers so they are only bound once per instance.
|
||||
this._onCancel = this._onCancel.bind(this);
|
||||
this._onSubmit = this._onSubmit.bind(this);
|
||||
this._validateInput = this._validateInput.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#render()}.
|
||||
*
|
||||
* @inheritdoc
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
let textInputProps = _TEXT_INPUT_PROPS;
|
||||
|
||||
if (this.props.passwordNumberOfDigits) {
|
||||
textInputProps = {
|
||||
...textInputProps,
|
||||
keyboardType: 'number-pad',
|
||||
maxLength: this.props.passwordNumberOfDigits
|
||||
};
|
||||
}
|
||||
|
||||
return (
|
||||
<InputDialog
|
||||
contentKey = 'security.about'
|
||||
onCancel = { this._onCancel }
|
||||
onSubmit = { this._onSubmit }
|
||||
textInputProps = { textInputProps }
|
||||
validateInput = { this._validateInput } />
|
||||
);
|
||||
}
|
||||
|
||||
_onCancel: () => boolean;
|
||||
|
||||
/**
|
||||
* Notifies this prompt that it has been dismissed by cancel.
|
||||
*
|
||||
* @private
|
||||
* @returns {boolean} True to hide this dialog/prompt; otherwise, false.
|
||||
*/
|
||||
_onCancel() {
|
||||
// An undefined password is understood to cancel the request to lock the
|
||||
// conference/room.
|
||||
return this._onSubmit(undefined);
|
||||
}
|
||||
|
||||
_onSubmit: (?string) => boolean;
|
||||
|
||||
/**
|
||||
* Notifies this prompt that it has been dismissed by submitting a specific
|
||||
* value.
|
||||
*
|
||||
* @param {string|undefined} value - The submitted value.
|
||||
* @private
|
||||
* @returns {boolean} False because we do not want to hide this
|
||||
* dialog/prompt as the hiding will be handled inside endRoomLockRequest
|
||||
* after setting the password is resolved.
|
||||
*/
|
||||
_onSubmit(value: ?string) {
|
||||
this.props.dispatch(endRoomLockRequest(this.props.conference, value));
|
||||
|
||||
return false; // Do not hide.
|
||||
}
|
||||
|
||||
_validateInput: (string) => boolean;
|
||||
|
||||
/**
|
||||
* Verifies input in case only digits are required.
|
||||
*
|
||||
* @param {string|undefined} value - The submitted value.
|
||||
* @private
|
||||
* @returns {boolean} False when the value is not valid and True otherwise.
|
||||
*/
|
||||
_validateInput(value: string) {
|
||||
|
||||
// we want only digits, but both number-pad and numeric add ',' and '.' as symbols
|
||||
if (this.props.passwordNumberOfDigits && value.length > 0 && !/^\d+$/.test(value)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
export default connect()(RoomLockPrompt);
|
|
@ -0,0 +1,83 @@
|
|||
// @flow
|
||||
|
||||
import React from 'react';
|
||||
import { Switch, Text, View } from 'react-native';
|
||||
|
||||
import { translate } from '../../base/i18n';
|
||||
import { connect } from '../../base/redux';
|
||||
import { LOCKED_REMOTELY } from '../constants';
|
||||
|
||||
import styles, {
|
||||
DISABLED_THUMB_COLOR,
|
||||
ENABLED_THUMB_COLOR, ENABLED_TRACK_COLOR
|
||||
} from './styles';
|
||||
|
||||
/**
|
||||
* The type of the React {@code Component} props of {@link RoomLockSwitch}.
|
||||
*/
|
||||
type Props = {
|
||||
|
||||
/**
|
||||
* Checks if the room is locked based on defined room lock constants.
|
||||
*/
|
||||
locked: string,
|
||||
|
||||
/**
|
||||
* Whether the switch is disabled.
|
||||
*/
|
||||
disabled: boolean,
|
||||
|
||||
/**
|
||||
* Callback to be invoked when the user toggles room lock.
|
||||
*/
|
||||
onToggleRoomLock: Function,
|
||||
|
||||
/**
|
||||
* Control for room lock.
|
||||
*/
|
||||
toggleRoomLock: boolean,
|
||||
|
||||
/**
|
||||
* Invoked to obtain translated strings.
|
||||
*/
|
||||
t: Function
|
||||
};
|
||||
|
||||
/**
|
||||
* Component meant to Add/Remove meeting password.
|
||||
*
|
||||
* @returns {React$Element<any>}
|
||||
*/
|
||||
function RoomLockSwitch(
|
||||
{
|
||||
locked,
|
||||
disabled,
|
||||
onToggleRoomLock,
|
||||
toggleRoomLock,
|
||||
t
|
||||
}: Props) {
|
||||
|
||||
return (
|
||||
<View style = { styles.roomLockSwitchContainer }>
|
||||
<Text>
|
||||
{
|
||||
locked === LOCKED_REMOTELY
|
||||
&& t('passwordSetRemotely')
|
||||
}
|
||||
</Text>
|
||||
<Switch
|
||||
disabled = { disabled }
|
||||
onValueChange = { onToggleRoomLock }
|
||||
thumbColor = {
|
||||
toggleRoomLock
|
||||
? ENABLED_THUMB_COLOR
|
||||
: DISABLED_THUMB_COLOR
|
||||
}
|
||||
trackColor = {{ true: ENABLED_TRACK_COLOR }}
|
||||
value = { toggleRoomLock } />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
export default translate(connect()(RoomLockSwitch));
|
|
@ -1,3 +1 @@
|
|||
export { default as PasswordRequiredPrompt } from './PasswordRequiredPrompt';
|
||||
export { default as RoomLockButton } from './RoomLockButton';
|
||||
export { default as RoomLockPrompt } from './RoomLockPrompt';
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
// @flow
|
||||
|
||||
import { ColorPalette } from '../../base/styles';
|
||||
|
||||
export const ENABLED_THUMB_COLOR = ColorPalette.blueHighlight;
|
||||
export const ENABLED_TRACK_COLOR = ColorPalette.blue;
|
||||
export const DISABLED_THUMB_COLOR = ColorPalette.darkGrey;
|
||||
|
||||
export default {
|
||||
roomLockSwitchContainer: {
|
||||
alignItems: 'center',
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
marginTop: 16
|
||||
}
|
||||
};
|
|
@ -16,7 +16,7 @@ import {
|
|||
} from '../notifications';
|
||||
|
||||
import { _openPasswordRequiredPrompt } from './actions';
|
||||
import { PasswordRequiredPrompt, RoomLockPrompt } from './components';
|
||||
import { PasswordRequiredPrompt } from './components';
|
||||
import { LOCKED_REMOTELY } from './constants';
|
||||
import logger from './logger';
|
||||
|
||||
|
@ -85,7 +85,6 @@ MiddlewareRegistry.register(store => next => action => {
|
|||
*/
|
||||
function _conferenceJoined({ dispatch }, next, action) {
|
||||
dispatch(hideDialog(PasswordRequiredPrompt));
|
||||
dispatch(hideDialog(RoomLockPrompt));
|
||||
|
||||
return next(action);
|
||||
}
|
||||
|
@ -116,7 +115,6 @@ function _conferenceFailed({ dispatch }, next, action) {
|
|||
}
|
||||
} else {
|
||||
dispatch(hideDialog(PasswordRequiredPrompt));
|
||||
dispatch(hideDialog(RoomLockPrompt));
|
||||
}
|
||||
|
||||
return next(action);
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
// @flow
|
||||
|
||||
import type { Dispatch } from 'redux';
|
||||
|
||||
import { createToolbarEvent, sendAnalytics } from '../../../analytics';
|
||||
import { translate } from '../../../base/i18n';
|
||||
import { IconSecurityOff, IconSecurityOn } from '../../../base/icons';
|
||||
|
@ -16,10 +18,9 @@ type Props = AbstractButtonProps & {
|
|||
_locked: boolean,
|
||||
|
||||
/**
|
||||
* On click handler that opens the security dialog.
|
||||
* The redux {@code dispatch} function.
|
||||
*/
|
||||
onClick: Function
|
||||
|
||||
dispatch: Dispatch<any>
|
||||
};
|
||||
|
||||
|
||||
|
@ -40,7 +41,7 @@ class SecurityDialogButton extends AbstractButton<Props, *> {
|
|||
*/
|
||||
_handleClick() {
|
||||
sendAnalytics(createToolbarEvent('toggle.security', { enable: !this.props._locked }));
|
||||
this.props.onClick();
|
||||
this.props.dispatch(toggleSecurityDialog());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -69,14 +70,4 @@ function mapStateToProps(state: Object) {
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps dispatching of some action to React component props.
|
||||
*
|
||||
* @param {Function} dispatch - Redux action dispatcher.
|
||||
* @returns {Props}
|
||||
*/
|
||||
const mapDispatchToProps = {
|
||||
onClick: () => toggleSecurityDialog()
|
||||
};
|
||||
|
||||
export default translate(connect(mapStateToProps, mapDispatchToProps)(SecurityDialogButton));
|
||||
export default translate(connect(mapStateToProps)(SecurityDialogButton));
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
export * from './native';
|
|
@ -0,0 +1 @@
|
|||
export * from './web';
|
|
@ -1,4 +1 @@
|
|||
// @flow
|
||||
|
||||
export { default as SecurityDialog } from './SecurityDialog';
|
||||
export { default as SecurityDialogButton } from './SecurityDialogButton';
|
||||
export * from './_';
|
||||
|
|
|
@ -0,0 +1,444 @@
|
|||
// @flow
|
||||
|
||||
import React, { PureComponent } from 'react';
|
||||
import {
|
||||
KeyboardAvoidingView,
|
||||
Platform,
|
||||
Text,
|
||||
TextInput,
|
||||
View
|
||||
} from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
import type { Dispatch } from 'redux';
|
||||
|
||||
import { ColorSchemeRegistry } from '../../../../base/color-scheme';
|
||||
import {
|
||||
FIELD_UNDERLINE,
|
||||
CustomSubmitDialog
|
||||
} from '../../../../base/dialog';
|
||||
import { getFeatureFlag, MEETING_PASSWORD_ENABLED } from '../../../../base/flags';
|
||||
import { translate } from '../../../../base/i18n';
|
||||
import { isLocalParticipantModerator } from '../../../../base/participants';
|
||||
import { StyleType } from '../../../../base/styles';
|
||||
import { toggleLobbyMode } from '../../../../lobby/actions.any';
|
||||
import LobbyModeSwitch
|
||||
from '../../../../lobby/components/native/LobbyModeSwitch';
|
||||
import { LOCKED_LOCALLY } from '../../../../room-lock';
|
||||
import {
|
||||
endRoomLockRequest,
|
||||
unlockRoom
|
||||
} from '../../../../room-lock/actions';
|
||||
import RoomLockSwitch from '../../../../room-lock/components/RoomLockSwitch';
|
||||
|
||||
/**
|
||||
* The style of the {@link TextInput} rendered by {@code SecurityDialog}. As it
|
||||
* requests the entry of a password, {@code TextInput} automatically correcting
|
||||
* the entry of the password is a pain to deal with as a user.
|
||||
*/
|
||||
const _TEXT_INPUT_PROPS = {
|
||||
autoCapitalize: 'none',
|
||||
autoCorrect: false
|
||||
};
|
||||
|
||||
/**
|
||||
* The type of the React {@code Component} props of {@link SecurityDialog}.
|
||||
*/
|
||||
type Props = {
|
||||
|
||||
/**
|
||||
* The JitsiConference which requires a password.
|
||||
*/
|
||||
_conference: Object,
|
||||
|
||||
/**
|
||||
* The color-schemed stylesheet of the feature.
|
||||
*/
|
||||
_dialogStyles: StyleType,
|
||||
|
||||
/**
|
||||
* Whether the local user is the moderator.
|
||||
*/
|
||||
_isModerator: boolean,
|
||||
|
||||
/**
|
||||
* State of the lobby mode.
|
||||
*/
|
||||
_lobbyEnabled: boolean,
|
||||
|
||||
/**
|
||||
* Whether the lobby mode switch is available or not.
|
||||
*/
|
||||
_lobbyModeSwitchVisible: boolean,
|
||||
|
||||
/**
|
||||
* The value for how the conference is locked (or undefined if not locked)
|
||||
* as defined by room-lock constants.
|
||||
*/
|
||||
_locked: string,
|
||||
|
||||
/**
|
||||
* Checks if the conference room is locked or not.
|
||||
*/
|
||||
_lockedConference: boolean,
|
||||
|
||||
/**
|
||||
* The current known password for the JitsiConference.
|
||||
*/
|
||||
_password: string,
|
||||
|
||||
/**
|
||||
* Number of digits used in the room-lock password.
|
||||
*/
|
||||
_passwordNumberOfDigits: number,
|
||||
|
||||
/**
|
||||
* Whether the room lock switch is available or not.
|
||||
*/
|
||||
_roomLockSwitchVisible: boolean,
|
||||
|
||||
/**
|
||||
* The color-schemed stylesheet of the security dialog feature.
|
||||
*/
|
||||
_securityDialogStyles: StyleType,
|
||||
|
||||
/**
|
||||
* Redux store dispatch function.
|
||||
*/
|
||||
dispatch: Dispatch<any>,
|
||||
|
||||
/**
|
||||
* Invoked to obtain translated strings.
|
||||
*/
|
||||
t: Function
|
||||
};
|
||||
|
||||
/**
|
||||
* The type of the React {@code Component} state of {@link SecurityDialog}.
|
||||
*/
|
||||
type State = {
|
||||
|
||||
/**
|
||||
* Password added by the participant for room lock.
|
||||
*/
|
||||
passwordInputValue: string,
|
||||
|
||||
/**
|
||||
* Shows an input or a message.
|
||||
*/
|
||||
showElement: boolean
|
||||
};
|
||||
|
||||
/**
|
||||
* Component that renders the security options dialog.
|
||||
*
|
||||
* @returns {React$Element<any>}
|
||||
*/
|
||||
class SecurityDialog extends PureComponent<Props, State> {
|
||||
|
||||
/**
|
||||
* Instantiates a new {@code SecurityDialog}.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
passwordInputValue: '',
|
||||
showElement: props._locked === LOCKED_LOCALLY || false
|
||||
};
|
||||
|
||||
this._onChangeText = this._onChangeText.bind(this);
|
||||
this._onSubmit = this._onSubmit.bind(this);
|
||||
this._onToggleLobbyMode = this._onToggleLobbyMode.bind(this);
|
||||
this._onToggleRoomLock = this._onToggleRoomLock.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements {@code SecurityDialog.render}.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
render() {
|
||||
return (
|
||||
<CustomSubmitDialog
|
||||
onSubmit = { this._onSubmit }>
|
||||
<KeyboardAvoidingView
|
||||
behavior =
|
||||
{
|
||||
Platform.OS === 'ios'
|
||||
? 'padding' : 'height'
|
||||
}
|
||||
enabled = { true }>
|
||||
{ this._renderLobbyMode() }
|
||||
{ this._renderRoomLock() }
|
||||
</KeyboardAvoidingView>
|
||||
</CustomSubmitDialog>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders lobby mode.
|
||||
*
|
||||
* @returns {ReactElement}
|
||||
* @private
|
||||
*/
|
||||
_renderLobbyMode() {
|
||||
const {
|
||||
_lobbyEnabled,
|
||||
_lobbyModeSwitchVisible,
|
||||
_securityDialogStyles,
|
||||
t
|
||||
} = this.props;
|
||||
|
||||
if (!_lobbyModeSwitchVisible) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<View>
|
||||
<Text style = { _securityDialogStyles.title } >
|
||||
{ t('lobby.dialogTitle') }
|
||||
</Text>
|
||||
<Text style = { _securityDialogStyles.text } >
|
||||
{ t('lobby.enableDialogText') }
|
||||
</Text>
|
||||
<LobbyModeSwitch
|
||||
lobbyEnabled = { _lobbyEnabled }
|
||||
onToggleLobbyMode = { this._onToggleLobbyMode } />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders room lock.
|
||||
*
|
||||
* @returns {ReactElement}
|
||||
* @private
|
||||
*/
|
||||
_renderRoomLock() {
|
||||
const {
|
||||
_isModerator,
|
||||
_locked,
|
||||
_lockedConference,
|
||||
_roomLockSwitchVisible,
|
||||
_securityDialogStyles,
|
||||
t
|
||||
} = this.props;
|
||||
const { showElement } = this.state;
|
||||
|
||||
if (!_roomLockSwitchVisible) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<View>
|
||||
<Text style = { _securityDialogStyles.title } >
|
||||
{ t('dialog.lockRoom') }
|
||||
</Text>
|
||||
<Text style = { _securityDialogStyles.text } >
|
||||
{ t('security.about') }
|
||||
</Text>
|
||||
<RoomLockSwitch
|
||||
disabled = { !_isModerator }
|
||||
locked = { _locked }
|
||||
onToggleRoomLock = { this._onToggleRoomLock }
|
||||
toggleRoomLock = { showElement || _lockedConference } />
|
||||
{ this._renderRoomLockMessage() }
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders room lock text input/message.
|
||||
*
|
||||
* @returns {ReactElement}
|
||||
* @private
|
||||
*/
|
||||
_renderRoomLockMessage() {
|
||||
let textInputProps = _TEXT_INPUT_PROPS;
|
||||
const {
|
||||
_isModerator,
|
||||
_locked,
|
||||
_password,
|
||||
_passwordNumberOfDigits,
|
||||
_securityDialogStyles,
|
||||
t
|
||||
} = this.props;
|
||||
const { passwordInputValue, showElement } = this.state;
|
||||
|
||||
if (_passwordNumberOfDigits) {
|
||||
textInputProps = {
|
||||
...textInputProps,
|
||||
keyboardType: 'numeric',
|
||||
maxLength: _passwordNumberOfDigits
|
||||
};
|
||||
}
|
||||
|
||||
if (!_isModerator) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (showElement) {
|
||||
if (typeof _locked === 'undefined') {
|
||||
return (
|
||||
<TextInput
|
||||
onChangeText = { this._onChangeText }
|
||||
placeholder = { t('lobby.passwordField') }
|
||||
style = { _securityDialogStyles.field }
|
||||
underlineColorAndroid = { FIELD_UNDERLINE }
|
||||
value = { passwordInputValue }
|
||||
{ ...textInputProps } />
|
||||
);
|
||||
} else if (_locked) {
|
||||
if (_locked === LOCKED_LOCALLY && typeof _password !== 'undefined') {
|
||||
return (
|
||||
<TextInput
|
||||
onChangeText = { this._onChangeText }
|
||||
placeholder = { _password }
|
||||
style = { _securityDialogStyles.field }
|
||||
underlineColorAndroid = { FIELD_UNDERLINE }
|
||||
value = { passwordInputValue }
|
||||
{ ...textInputProps } />
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_onToggleLobbyMode: () => void;
|
||||
|
||||
/**
|
||||
* Handles the enable-disable lobby mode switch.
|
||||
*
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
_onToggleLobbyMode() {
|
||||
const { _lobbyEnabled, dispatch } = this.props;
|
||||
|
||||
if (_lobbyEnabled) {
|
||||
dispatch(toggleLobbyMode(false));
|
||||
} else {
|
||||
dispatch(toggleLobbyMode(true));
|
||||
}
|
||||
}
|
||||
|
||||
_onToggleRoomLock: () => void;
|
||||
|
||||
/**
|
||||
* Callback to be invoked when room lock button is pressed.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
_onToggleRoomLock() {
|
||||
const { _isModerator, _locked, dispatch } = this.props;
|
||||
const { showElement } = this.state;
|
||||
|
||||
this.setState({
|
||||
showElement: !showElement
|
||||
});
|
||||
|
||||
if (_locked && _isModerator) {
|
||||
dispatch(unlockRoom());
|
||||
|
||||
this.setState({
|
||||
showElement: false
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies input in case only digits are required.
|
||||
*
|
||||
* @param {string} passwordInputValue - The value of the password
|
||||
* text input.
|
||||
* @private
|
||||
* @returns {boolean} False when the value is not valid and True otherwise.
|
||||
*/
|
||||
_validateInputValue(passwordInputValue: string) {
|
||||
const { _passwordNumberOfDigits } = this.props;
|
||||
|
||||
// we want only digits,
|
||||
// but both number-pad and numeric add ',' and '.' as symbols
|
||||
if (_passwordNumberOfDigits
|
||||
&& passwordInputValue.length > 0
|
||||
&& !/^\d+$/.test(passwordInputValue)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
_onChangeText: string => void;
|
||||
|
||||
/**
|
||||
* Callback to be invoked when the text in the field changes.
|
||||
*
|
||||
* @param {string} passwordInputValue - The value of password input.
|
||||
* @returns {void}
|
||||
*/
|
||||
_onChangeText(passwordInputValue) {
|
||||
if (!this._validateInputValue(passwordInputValue)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.setState({
|
||||
passwordInputValue
|
||||
});
|
||||
}
|
||||
|
||||
_onSubmit: () => boolean;
|
||||
|
||||
/**
|
||||
* Submits value typed in text input.
|
||||
*
|
||||
* @returns {boolean} False because we do not want to hide this
|
||||
* dialog/prompt as the hiding will be handled inside endRoomLockRequest
|
||||
* after setting the password is resolved.
|
||||
*/
|
||||
_onSubmit() {
|
||||
const {
|
||||
_conference,
|
||||
dispatch
|
||||
} = this.props;
|
||||
const { passwordInputValue } = this.state;
|
||||
|
||||
dispatch(endRoomLockRequest(_conference, passwordInputValue));
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps part of the Redux state to the props of this component.
|
||||
*
|
||||
* @param {Object} state - The Redux state.
|
||||
* @returns {Props}
|
||||
*/
|
||||
function _mapStateToProps(state: Object): Object {
|
||||
const { conference, locked, password } = state['features/base/conference'];
|
||||
const { hideLobbyButton } = state['features/base/config'];
|
||||
const { lobbyEnabled } = state['features/lobby'];
|
||||
const { roomPasswordNumberOfDigits } = state['features/base/config'];
|
||||
const lobbySupported = conference && conference.isLobbySupported();
|
||||
const visible = getFeatureFlag(state, MEETING_PASSWORD_ENABLED, true);
|
||||
|
||||
return {
|
||||
_conference: conference,
|
||||
_dialogStyles: ColorSchemeRegistry.get(state, 'Dialog'),
|
||||
_isModerator: isLocalParticipantModerator(state),
|
||||
_lobbyEnabled: lobbyEnabled,
|
||||
_lobbyModeSwitchVisible:
|
||||
lobbySupported && isLocalParticipantModerator(state) && !hideLobbyButton,
|
||||
_locked: locked,
|
||||
_lockedConference: Boolean(conference && locked),
|
||||
_password: password,
|
||||
_passwordNumberOfDigits: roomPasswordNumberOfDigits,
|
||||
_roomLockSwitchVisible: visible,
|
||||
_securityDialogStyles: ColorSchemeRegistry.get(state, 'SecurityDialog')
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
export default translate(connect(_mapStateToProps)(SecurityDialog));
|
|
@ -0,0 +1,4 @@
|
|||
// @flow
|
||||
|
||||
export { default as SecurityDialog } from './SecurityDialog';
|
||||
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
import React, { Component } from 'react';
|
||||
|
||||
import { translate } from '../../../base/i18n';
|
||||
import { LOCKED_LOCALLY } from '../../../room-lock';
|
||||
import { translate } from '../../../../base/i18n';
|
||||
import { LOCKED_LOCALLY } from '../../../../room-lock';
|
||||
|
||||
/**
|
||||
* The type of the React {@code Component} props of {@link PasswordForm}.
|
|
@ -3,8 +3,8 @@
|
|||
|
||||
import React, { useRef } from 'react';
|
||||
|
||||
import { translate } from '../../../base/i18n';
|
||||
import { copyText } from '../../../base/util';
|
||||
import { translate } from '../../../../base/i18n';
|
||||
import { copyText } from '../../../../base/util';
|
||||
|
||||
import PasswordForm from './PasswordForm';
|
||||
|
|
@ -2,13 +2,13 @@
|
|||
|
||||
import React, { useState, useEffect } from 'react';
|
||||
|
||||
import { setPassword as setPass } from '../../../base/conference';
|
||||
import { Dialog } from '../../../base/dialog';
|
||||
import { translate } from '../../../base/i18n';
|
||||
import { isLocalParticipantModerator } from '../../../base/participants';
|
||||
import { connect } from '../../../base/redux';
|
||||
import { E2EESection } from '../../../e2ee/components';
|
||||
import { LobbySection } from '../../../lobby';
|
||||
import { setPassword as setPass } from '../../../../base/conference';
|
||||
import { Dialog } from '../../../../base/dialog';
|
||||
import { translate } from '../../../../base/i18n';
|
||||
import { isLocalParticipantModerator } from '../../../../base/participants';
|
||||
import { connect } from '../../../../base/redux';
|
||||
import { E2EESection } from '../../../../e2ee/components';
|
||||
import { LobbySection } from '../../../../lobby';
|
||||
|
||||
import PasswordSection from './PasswordSection';
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
// @flow
|
||||
|
||||
export { default as SecurityDialog } from './SecurityDialog';
|
|
@ -11,10 +11,9 @@ import { connect } from '../../../base/redux';
|
|||
import { StyleType } from '../../../base/styles';
|
||||
import { SharedDocumentButton } from '../../../etherpad';
|
||||
import { InviteButton } from '../../../invite';
|
||||
import { LobbyModeButton } from '../../../lobby/components/native';
|
||||
import { AudioRouteButton } from '../../../mobile/audio-mode';
|
||||
import { LiveStreamButton, RecordButton } from '../../../recording';
|
||||
import { RoomLockButton } from '../../../room-lock';
|
||||
import SecurityDialogButton from '../../../security/components/security-dialog/SecurityDialogButton';
|
||||
import { SharedVideoButton } from '../../../shared-video/components';
|
||||
import { ClosedCaptionButton } from '../../../subtitles';
|
||||
import { TileViewButton } from '../../../video-layout';
|
||||
|
@ -140,7 +139,7 @@ class OverflowMenu extends PureComponent<Props, State> {
|
|||
{!toolbarButtons.has('invite') && <InviteButton { ...buttonProps } />}
|
||||
<AudioOnlyButton { ...buttonProps } />
|
||||
{!toolbarButtons.has('raisehand') && <RaiseHandButton { ...buttonProps } />}
|
||||
<LobbyModeButton { ...buttonProps } />
|
||||
<SecurityDialogButton { ...buttonProps } />
|
||||
<ScreenSharingButton { ...buttonProps } />
|
||||
<MoreOptionsButton { ...moreOptionsButtonProps } />
|
||||
<Collapsible collapsed = { !showMore }>
|
||||
|
@ -149,7 +148,6 @@ class OverflowMenu extends PureComponent<Props, State> {
|
|||
<RecordButton { ...buttonProps } />
|
||||
<LiveStreamButton { ...buttonProps } />
|
||||
<SharedVideoButton { ...buttonProps } />
|
||||
<RoomLockButton { ...buttonProps } />
|
||||
<ClosedCaptionButton { ...buttonProps } />
|
||||
<SharedDocumentButton { ...buttonProps } />
|
||||
<MuteEveryoneButton { ...buttonProps } />
|
||||
|
|
|
@ -47,7 +47,7 @@ import {
|
|||
LiveStreamButton,
|
||||
RecordButton
|
||||
} from '../../../recording';
|
||||
import { SecurityDialogButton } from '../../../security';
|
||||
import SecurityDialogButton from '../../../security/components/security-dialog/SecurityDialogButton';
|
||||
import {
|
||||
SETTINGS_TABS,
|
||||
SettingsButton,
|
||||
|
|
Loading…
Reference in New Issue