123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444 |
- // @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));
|