diff --git a/lang/main.json b/lang/main.json
index de572067e..bdb6b4344 100644
--- a/lang/main.json
+++ b/lang/main.json
@@ -264,7 +264,7 @@
"removeSharedVideoMsg": "Are you sure you would like to remove your shared video?",
"alreadySharedVideoMsg": "Another member is already sharing video. This conference allows only one shared video at a time.",
"WaitingForHost": "Waiting for the host ...",
- "WaitForHostMsg": "The conference '__room__' has not yet started. If you are the host then please authenticate. Otherwise, please wait for the host to arrive.",
+ "WaitForHostMsg": "The conference __room__ has not yet started. If you are the host then please authenticate. Otherwise, please wait for the host to arrive.",
"IamHost": "I am the host",
"Cancel": "Cancel",
"Submit": "Submit",
diff --git a/modules/UI/authentication/AuthHandler.js b/modules/UI/authentication/AuthHandler.js
index fd9c1b664..6510a58f3 100644
--- a/modules/UI/authentication/AuthHandler.js
+++ b/modules/UI/authentication/AuthHandler.js
@@ -139,38 +139,41 @@ function initJWTTokenListener(room) {
* @param {JitsiConference} room
* @param {string} [lockPassword] password to use if the conference is locked
*/
-function doXmppAuth (room, lockPassword) {
- const loginDialog = LoginDialog.showAuthDialog(function (id, password) {
- const authConnection = room.createAuthenticationConnection();
-
- authConnection.authenticateAndUpgradeRole({
+function doXmppAuth(room, lockPassword) {
+ const loginDialog = LoginDialog.showAuthDialog(
+ /* successCallback */ (id, password) => {
+ room.authenticateAndUpgradeRole({
id,
password,
roomPassword: lockPassword,
- onLoginSuccessful: () => { /* Called when XMPP login succeeds */
+
+ /** Called when the XMPP login succeeds. */
+ onLoginSuccessful() {
loginDialog.displayConnectionStatus(
'connection.FETCH_SESSION_ID');
}
})
- .then(() => {
- loginDialog.displayConnectionStatus(
- 'connection.GOT_SESSION_ID');
- loginDialog.close();
- })
- .catch(error => {
- logger.error('authenticateAndUpgradeRole failed', error);
- if (error.authenticationError) {
- loginDialog.displayError(
- 'connection.GET_SESSION_ID_ERROR', {
- msg: error.authenticationError
- });
- } else {
- loginDialog.displayError(error.connectionError);
- }
- });
- }, function () {
- loginDialog.close();
- });
+ .then(
+ /* onFulfilled */ () => {
+ loginDialog.displayConnectionStatus(
+ 'connection.GOT_SESSION_ID');
+ loginDialog.close();
+ },
+ /* onRejected */ error => {
+ logger.error('authenticateAndUpgradeRole failed', error);
+
+ const { authenticationError, connectionError } = error;
+
+ if (authenticationError) {
+ loginDialog.displayError(
+ 'connection.GET_SESSION_ID_ERROR',
+ { msg: authenticationError });
+ } else if (connectionError) {
+ loginDialog.displayError(connectionError);
+ }
+ });
+ },
+ /* cancelCallback */ () => loginDialog.close());
}
/**
diff --git a/modules/UI/authentication/LoginDialog.js b/modules/UI/authentication/LoginDialog.js
index 1e1426214..63fabb327 100644
--- a/modules/UI/authentication/LoginDialog.js
+++ b/modules/UI/authentication/LoginDialog.js
@@ -1,4 +1,5 @@
/* global $, APP, config, JitsiMeetJS */
+
import { toJid } from '../../../react/features/base/connection';
const ConnectionErrors = JitsiMeetJS.errors.connection;
@@ -196,34 +197,38 @@ export default {
},
/**
- * Show notification that authentication is required
- * to create the conference, so he should authenticate or wait for a host.
- * @param {string} roomName name of the conference
- * @param {function} onAuthNow callback to invoke if
- * user want to authenticate.
+ * Shows a notification that authentication is required to create the
+ * conference, so the local participant should authenticate or wait for a
+ * host.
+ *
+ * @param {string} room - The name of the conference.
+ * @param {function} onAuthNow - The callback to invoke if the local
+ * participant wants to authenticate.
* @returns dialog
*/
- showAuthRequiredDialog: function (roomName, onAuthNow) {
- var msg = APP.translation.generateTranslationHTML(
- "dialog.WaitForHostMsg", {room: roomName}
+ showAuthRequiredDialog(room, onAuthNow) {
+ const msg = APP.translation.generateTranslationHTML(
+ '[html]dialog.WaitForHostMsg',
+ { room }
);
-
- var buttonTxt = APP.translation.generateTranslationHTML(
- "dialog.IamHost"
+ const buttonTxt = APP.translation.generateTranslationHTML(
+ 'dialog.IamHost'
);
- var buttons = [{title: buttonTxt, value: "authNow"}];
+ const buttons = [{
+ title: buttonTxt,
+ value: 'authNow'
+ }];
return APP.UI.messageHandler.openDialog(
- "dialog.WaitingForHost",
+ 'dialog.WaitingForHost',
msg,
true,
buttons,
- function (e, submitValue) {
-
- // Do not close the dialog yet
+ (e, submitValue) => {
+ // Do not close the dialog yet.
e.preventDefault();
- // Open login popup
+ // Open login popup.
if (submitValue === 'authNow') {
onAuthNow();
}
diff --git a/react/features/app/components/App.native.js b/react/features/app/components/App.native.js
index 6a5ac264f..30d544a68 100644
--- a/react/features/app/components/App.native.js
+++ b/react/features/app/components/App.native.js
@@ -4,6 +4,7 @@ import React from 'react';
import { Linking } from 'react-native';
import '../../analytics';
+import '../../authentication';
import { Platform } from '../../base/react';
import '../../mobile/audio-mode';
import '../../mobile/background';
@@ -15,7 +16,6 @@ import '../../mobile/proximity';
import '../../mobile/wake-lock';
import { AbstractApp } from './AbstractApp';
-import '../../authentication';
/**
* Root application component.
diff --git a/react/features/authentication/actionTypes.js b/react/features/authentication/actionTypes.js
index db93e681e..2d2aa9f18 100644
--- a/react/features/authentication/actionTypes.js
+++ b/react/features/authentication/actionTypes.js
@@ -28,48 +28,41 @@ export const CANCEL_WAIT_FOR_OWNER = Symbol('CANCEL_WAIT_FOR_OWNER');
*/
export const STOP_WAIT_FOR_OWNER = Symbol('STOP_WAIT_FOR_OWNER');
+/**
+ * The type of (redux) action which informs that the authentication and role
+ * upgrade process has finished either with success or with a specific error.
+ * If error is undefined, then the process succeeded;
+ * otherwise, it failed. Refer to
+ * {@link JitsiConference#authenticateAndUpgradeRole} in lib-jitsi-meet for the
+ * error details.
+ *
+ * {
+ * type: UPGRADE_ROLE_FINISHED,
+ * error: Object
+ * }
+ */
+export const UPGRADE_ROLE_FINISHED = Symbol('UPGRADE_ROLE_FINISHED');
+
/**
* The type of (redux) action which signals that the process of authenticating
- * and upgrading the current conference user's role has been started.
+ * and upgrading the local participant's role has been started.
*
* {
* type: UPGRADE_ROLE_STARTED,
- * authConnection: JitsiAuthConnection
+ * thenableWithCancel: Object
* }
*/
export const UPGRADE_ROLE_STARTED = Symbol('UPGRADE_ROLE_STARTED');
-/**
- * The type of (redux) action which informs that the authentication and role
- * upgrade process has been completed successfully.
- *
- * {
- * type: UPGRADE_ROLE_SUCCESS
- * }
- */
-export const UPGRADE_ROLE_SUCCESS = Symbol('UPGRADE_ROLE_SUCCESS');
-
-/**
- * The type of (redux) action which informs that the authentication and role
- * upgrade process has failed with an error. Check the docs of
- * {@link JitsiAuthConnection} for more details about the error structure.
- *
- * {
- * type: UPGRADE_ROLE_SUCCESS,
- * error: Object
- * }
- */
-export const UPGRADE_ROLE_FAILED = Symbol('UPGRADE_ROLE_FAILED');
-
/**
* The type of (redux) action that sets delayed handler which will check if
* the conference has been created and it's now possible to join from anonymous
* connection.
*
* {
- * type: WAIT_FOR_OWNER,
- * handler: Function,
- * timeoutMs: number
+ * type: WAIT_FOR_OWNER,
+ * handler: Function,
+ * timeoutMs: number
* }
*/
export const WAIT_FOR_OWNER = Symbol('WAIT_FOR_OWNER');
diff --git a/react/features/authentication/actions.js b/react/features/authentication/actions.js
index 1f6f8bac1..694178378 100644
--- a/react/features/authentication/actions.js
+++ b/react/features/authentication/actions.js
@@ -1,53 +1,57 @@
-import { openDialog } from '../base/dialog/actions';
-import { checkIfCanJoin } from '../base/conference/actions';
+/* @flow */
+
+import { checkIfCanJoin } from '../base/conference';
+import { openDialog } from '../base/dialog';
+
import {
CANCEL_LOGIN,
CANCEL_WAIT_FOR_OWNER,
STOP_WAIT_FOR_OWNER,
- UPGRADE_ROLE_FAILED,
+ UPGRADE_ROLE_FINISHED,
UPGRADE_ROLE_STARTED,
- UPGRADE_ROLE_SUCCESS,
WAIT_FOR_OWNER
} from './actionTypes';
import { LoginDialog, WaitForOwnerDialog } from './components';
+const logger = require('jitsi-meet-logger').getLogger(__filename);
+
/**
- * Instantiates new {@link JitsiAuthConnection} and uses it to authenticate and
- * upgrade role of the current conference user to moderator which will allow to
- * create and join new conference on XMPP password + guest access configuration.
- * See {@link LoginDialog} description for more info.
+ * Initiates authenticating and upgrading the role of the local participant to
+ * moderator which will allow to create and join a new conference on an XMPP
+ * password + guest access configuration. Refer to {@link LoginDialog} for more
+ * info.
*
- * @param {string} id - XMPP user's id eg. user@domain.com.
- * @param {string} userPassword - The user's password.
- * @param {JitsiConference} conference - The conference for which user's role
- * will be upgraded.
- * @returns {function({dispatch: Function, getState: Function})}
+ * @param {string} id - The XMPP user's ID (e.g. user@domain.com).
+ * @param {string} password - The XMPP user's password.
+ * @param {JitsiConference} conference - The conference for which the local
+ * participant's role will be upgraded.
+ * @returns {function({ dispatch: Dispatch, getState: Function })}
*/
-export function authenticateAndUpgradeRole(id, userPassword, conference) {
- return (dispatch, getState) => {
- const authConnection = conference.createAuthenticationConnection();
-
- dispatch(_upgradeRoleStarted(authConnection));
-
+export function authenticateAndUpgradeRole(
+ id: string,
+ password: string,
+ conference: Object) {
+ return (dispatch: Dispatch, getState: Function) => {
const { password: roomPassword }
= getState()['features/base/conference'];
+ const process
+ = conference.authenticateAndUpgradeRole({
+ id,
+ password,
+ roomPassword
+ });
- authConnection.authenticateAndUpgradeRole({
- id,
- password: userPassword,
- roomPassword
- })
- .then(() => {
- dispatch(_upgradeRoleSuccess());
- })
- .catch(error => {
- // Lack of error means the operation was canceled, so no need to log
- // that on error level.
- if (error.error) {
- console.error('upgradeRoleFailed', error);
- }
- dispatch(_upgradeRoleFailed(error));
- });
+ dispatch(_upgradeRoleStarted(process));
+ process.then(
+ /* onFulfilled */ () => dispatch(_upgradeRoleFinished()),
+ /* onRejected */ error => {
+ // The lack of an error signals a cancellation.
+ if (error.authenticationError || error.connectionError) {
+ logger.error('authenticateAndUpgradeRole failed', error);
+ }
+
+ dispatch(_upgradeRoleFinished(error));
+ });
};
}
@@ -55,7 +59,7 @@ export function authenticateAndUpgradeRole(id, userPassword, conference) {
* Cancels {@ink LoginDialog}.
*
* @returns {{
- * type: CANCEL_LOGIN
+ * type: CANCEL_LOGIN
* }}
*/
export function cancelLogin() {
@@ -68,7 +72,7 @@ export function cancelLogin() {
* Cancels {@link WaitForOwnerDialog}. Will navigate back to the welcome page.
*
* @returns {{
- * type: CANCEL_WAIT_FOR_OWNER
+ * type: CANCEL_WAIT_FOR_OWNER
* }}
*/
export function cancelWaitForOwner() {
@@ -78,118 +82,77 @@ export function cancelWaitForOwner() {
}
/**
- * Stops waiting for conference owner and clears any pending timeout.
+ * Opens {@link LoginDialog} which will ask to enter username and password
+ * for the current conference.
+ *
+ * @protected
+ * @returns {Action}
+ */
+export function _openLoginDialog() {
+ return openDialog(LoginDialog);
+}
+
+/**
+ * Opens {@link WaitForOnwerDialog}.
+ *
+ * @protected
+ * @returns {Action}
+ */
+export function _openWaitForOwnerDialog() {
+ return openDialog(WaitForOwnerDialog);
+}
+
+/**
+ * Stops waiting for the conference owner.
*
* @returns {{
- * type: STOP_WAIT_FOR_OWNER
+ * type: STOP_WAIT_FOR_OWNER
* }}
*/
-export function clearWaitForOwnerTimeout() {
+export function stopWaitForOwner() {
return {
type: STOP_WAIT_FOR_OWNER
};
}
/**
- * Sets a delayed "wait for owner" handler function.
- *
- * @param {Function} handler - The "wait for owner" handler function.
- * @param {number} waitMs - The delay in milliseconds.
+ * Signals that the process of authenticating and upgrading the local
+ * participant's role has finished either with success or with a specific error.
*
+ * @param {Object} error - If undefined, then the process of
+ * authenticating and upgrading the local participant's role has succeeded;
+ * otherwise, it has failed with the specified error. Refer to
+ * {@link JitsiConference#authenticateAndUpgradeRole} in lib-jitsi-meet for the
+ * error details.
* @private
* @returns {{
- * type: WAIT_FOR_OWNER,
- * handler: Function,
- * timeoutMs: number
+ * type: UPGRADE_ROLE_FINISHED,
+ * error: Object
* }}
*/
-function _setWaitForOwnerTimeout(handler, waitMs) {
+function _upgradeRoleFinished(error) {
return {
- type: WAIT_FOR_OWNER,
- handler,
- timeoutMs: waitMs
- };
-}
-
-/**
- * Displays {@link LoginDialog} which will ask to enter username and password
- * for the current conference.
- *
- * @protected
- * @returns {{
- * type: OPEN_DIALOG,
- * component: LoginDialog,
- * props: React.PropTypes
- * }}
- */
-export function _showLoginDialog() {
- return openDialog(LoginDialog, { });
-}
-
-/**
- * Displays {@link WaitForOnwerDialog}.
- *
- * @protected
- * @returns {{
- * type: OPEN_DIALOG,
- * component: WaitForOwnerDialog,
- * props: React.PropTypes
- * }}
- */
-export function _showWaitForOwnerDialog() {
- return openDialog(WaitForOwnerDialog, { });
-}
-
-/**
- * Emits an error which occurred during {@link authenticateAndUpgradeRole}.
- *
- * @param {Object} error - Check the docs of {@link JitsiAuthConnection} in
- * lib-jitsi-meet for more details about the error's structure.
- *
- * @private
- * @returns {{
- * type: UPGRADE_ROLE_FAILED,
- * error: Object
- * }}
- */
-function _upgradeRoleFailed(error) {
- return {
- type: UPGRADE_ROLE_FAILED,
+ type: UPGRADE_ROLE_FINISHED,
error
};
}
/**
- * Signals that the role upgrade process has been started using given
- * {@link JitsiAuthConnection} instance.
- *
- * @param {JitsiAuthConnection} authenticationConnection - The authentication
- * connection instance that can be used to cancel the process.
+ * Signals that a process of authenticating and upgrading the local
+ * participant's role has started.
*
+ * @param {Object} thenableWithCancel - The process of authenticating and
+ * upgrading the local participant's role.
* @private
* @returns {{
- * type: UPGRADE_ROLE_STARTED,
- * authConnection: JitsiAuthConnection
+ * type: UPGRADE_ROLE_STARTED,
+ * thenableWithCancel: Object
* }}
*/
-function _upgradeRoleStarted(authenticationConnection) {
+function _upgradeRoleStarted(thenableWithCancel) {
return {
type: UPGRADE_ROLE_STARTED,
- authConnection: authenticationConnection
- };
-}
-
-/**
- * Signals that the role upgrade process has been completed successfully.
- *
- * @private
- * @returns {{
- * type: UPGRADE_ROLE_SUCCESS
- * }}
- */
-function _upgradeRoleSuccess() {
- return {
- type: UPGRADE_ROLE_SUCCESS
+ thenableWithCancel
};
}
@@ -198,13 +161,13 @@ function _upgradeRoleSuccess() {
* start the process of "waiting for the owner" by periodically trying to join
* the room every five seconds.
*
- * @returns {function({ dispatch: Function})}
+ * @returns {function({ dispatch: Dispatch })}
*/
export function waitForOwner() {
- return dispatch => {
- dispatch(
- _setWaitForOwnerTimeout(
- () => dispatch(checkIfCanJoin()),
- 5000));
- };
+ return (dispatch: Dispatch) =>
+ dispatch({
+ type: WAIT_FOR_OWNER,
+ handler: () => dispatch(checkIfCanJoin()),
+ timeoutMs: 5000
+ });
}
diff --git a/react/features/authentication/components/LoginDialog.native.js b/react/features/authentication/components/LoginDialog.native.js
index 9a4f0652d..4252d0498 100644
--- a/react/features/authentication/components/LoginDialog.native.js
+++ b/react/features/authentication/components/LoginDialog.native.js
@@ -1,22 +1,14 @@
+import PropTypes from 'prop-types';
import React, { Component } from 'react';
+import { Text, TextInput, View } from 'react-native';
import { connect as reduxConnect } from 'react-redux';
-import {
- Button,
- Modal,
- Text,
- TextInput,
- View
-} from 'react-native';
-import {
- authenticateAndUpgradeRole,
- cancelLogin
-} from '../actions';
-import {
- connect,
- toJid
-} from '../../base/connection';
+
+import { connect, toJid } from '../../base/connection';
+import { Dialog } from '../../base/dialog';
import { translate } from '../../base/i18n';
import { JitsiConnectionErrors } from '../../base/lib-jitsi-meet';
+
+import { authenticateAndUpgradeRole, cancelLogin } from '../actions';
import styles from './styles';
/**
@@ -36,15 +28,15 @@ import styles from './styles';
* yet, Jicofo will not allow to start new conference. This will trigger
* 'CONFERENCE_FAILED' action with JitsiConferenceErrors.AUTHENTICATION_REQUIRED
* error and 'authRequired' value of 'features/base/conference' will hold
- * the {@link JitsiConference} instance. If user decides to authenticate a new
- * {@link JitsiAuthConnection} will be created from which separate XMPP
- * connection is established and authentication is performed. In case it
- * succeeds Jicofo will assign new session ID which then can be used from
- * the anonymous domain connection to create and join the room. This part is
- * done by {@link JitsiAuthConnection} from lib-jitsi-meet.
+ * the {@link JitsiConference} instance. If user decides to authenticate, a
+ * new/separate XMPP connection is established and authentication is performed.
+ * In case it succeeds, Jicofo will assign new session ID which then can be used
+ * from the anonymous domain connection to create and join the room. This part
+ * is done by {@link JitsiConference#authenticateAndUpgradeRole} in
+ * lib-jitsi-meet.
*
- * See https://github.com/jitsi/jicofo#secure-domain for configuration
- * parameters description.
+ * See {@link https://github.com/jitsi/jicofo#secure-domain} for a description
+ * of the configuration parameters.
*/
class LoginDialog extends Component {
/**
@@ -57,37 +49,37 @@ class LoginDialog extends Component {
* {@link JitsiConference} that needs authentication - will hold a valid
* value in XMPP login + guest access mode.
*/
- conference: React.PropTypes.object,
+ _conference: PropTypes.object,
/**
*
*/
- configHosts: React.PropTypes.object,
+ _configHosts: PropTypes.object,
/**
* Indicates if the dialog should display "connecting" status message.
*/
- connecting: React.PropTypes.bool,
-
- /**
- * Redux store dispatch method.
- */
- dispatch: React.PropTypes.func,
+ _connecting: PropTypes.bool,
/**
* The error which occurred during login/authentication.
*/
- error: React.PropTypes.string,
+ _error: PropTypes.string,
/**
* Any extra details about the error provided by lib-jitsi-meet.
*/
- errorDetails: React.PropTypes.string,
+ _errorDetails: PropTypes.string,
+
+ /**
+ * Redux store dispatch method.
+ */
+ dispatch: PropTypes.func,
/**
* Invoked to obtain translated strings.
*/
- t: React.PropTypes.func
+ t: PropTypes.func
};
/**
@@ -99,16 +91,16 @@ class LoginDialog extends Component {
constructor(props) {
super(props);
- // Bind event handlers so they are only bound once for every instance.
- this._onCancel = this._onCancel.bind(this);
- this._onLogin = this._onLogin.bind(this);
- this._onUsernameChange = this._onUsernameChange.bind(this);
- this._onPasswordChange = this._onPasswordChange.bind(this);
-
this.state = {
username: '',
password: ''
};
+
+ // Bind event handlers so they are only bound once per instance.
+ this._onCancel = this._onCancel.bind(this);
+ this._onLogin = this._onLogin.bind(this);
+ this._onPasswordChange = this._onPasswordChange.bind(this);
+ this._onUsernameChange = this._onUsernameChange.bind(this);
}
/**
@@ -119,56 +111,51 @@ class LoginDialog extends Component {
*/
render() {
const {
- error,
- errorDetails,
- connecting,
+ _connecting: connecting,
+ _error: error,
+ _errorDetails: errorDetails,
t
} = this.props;
let messageKey = '';
- const messageOptions = { };
+ const messageOptions = {};
if (error === JitsiConnectionErrors.PASSWORD_REQUIRED) {
messageKey = 'dialog.incorrectPassword';
} else if (error) {
messageKey = 'dialog.connectErrorWithMsg';
-
messageOptions.msg = `${error} ${errorDetails}`;
}
return (
-
-
- Username:
+
+
);
}
@@ -216,9 +203,9 @@ class LoginDialog extends Component {
* @returns {void}
*/
_onLogin() {
- const conference = this.props.conference;
+ const { _conference: conference } = this.props;
const { username, password } = this.state;
- const jid = toJid(username, this.props.configHosts);
+ const jid = toJid(username, this.props._configHosts);
// If there's a conference it means that the connection has succeeded,
// but authentication is required in order to join the room.
@@ -238,42 +225,45 @@ class LoginDialog extends Component {
* @param {Object} state - The Redux state.
* @private
* @returns {{
- * configHosts: Object,
- * connecting: boolean,
- * error: string,
- * errorDetails: string,
- * conference: JitsiConference
+ * _conference: JitsiConference,
+ * _configHosts: Object,
+ * _connecting: boolean,
+ * _error: string,
+ * _errorDetails: string
* }}
*/
function _mapStateToProps(state) {
+ const {
+ upgradeRoleError,
+ upgradeRoleInProgress
+ } = state['features/authentication'];
+ const { authRequired } = state['features/base/conference'];
const { hosts: configHosts } = state['features/base/config'];
const {
connecting,
error: connectionError,
errorMessage: connectionErrorMessage
} = state['features/base/connection'];
- const {
- authRequired
- } = state['features/base/conference'];
- const {
- upgradeRoleError,
- upgradeRoleInProgress
- } = state['features/authentication'];
- const error
- = connectionError
- || (upgradeRoleError
- && (upgradeRoleError.connectionError
- || upgradeRoleError.authenticationError));
+ let error;
+ let errorDetails;
+
+ if (connectionError) {
+ error = connectionError;
+ errorDetails = connectionErrorMessage;
+ } else if (upgradeRoleError) {
+ error
+ = upgradeRoleError.connectionError
+ || upgradeRoleError.authenticationError;
+ errorDetails = upgradeRoleError.message;
+ }
return {
- configHosts,
- connecting: Boolean(connecting) || Boolean(upgradeRoleInProgress),
- error,
- errorDetails:
- (connectionError && connectionErrorMessage)
- || (upgradeRoleError && upgradeRoleError.message),
- conference: authRequired
+ _conference: authRequired,
+ _configHosts: configHosts,
+ _connecting: Boolean(connecting) || Boolean(upgradeRoleInProgress),
+ _error: error,
+ _errorDetails: errorDetails
};
}
diff --git a/react/features/authentication/components/WaitForOwnerDialog.native.js b/react/features/authentication/components/WaitForOwnerDialog.native.js
index 0fc62105a..a1fe6d9a1 100644
--- a/react/features/authentication/components/WaitForOwnerDialog.native.js
+++ b/react/features/authentication/components/WaitForOwnerDialog.native.js
@@ -1,9 +1,12 @@
+import PropTypes from 'prop-types';
import React, { Component } from 'react';
+import { Text } from 'react-native';
import { connect } from 'react-redux';
-import { Button, Modal, Text, View } from 'react-native';
+import { Dialog } from '../../base/dialog';
import { translate } from '../../base/i18n';
-import { _showLoginDialog, cancelWaitForOwner } from '../actions';
+
+import { cancelWaitForOwner, _openLoginDialog } from '../actions';
import styles from './styles';
/**
@@ -19,20 +22,20 @@ class WaitForOwnerDialog extends Component {
* @static
*/
static propTypes = {
- /**
- * Redux store dispatch function.
- */
- dispatch: React.PropTypes.func,
-
/**
* The name of the conference room (without the domain part).
*/
- roomName: React.PropTypes.string,
+ _room: PropTypes.string,
+
+ /**
+ * Redux store dispatch function.
+ */
+ dispatch: PropTypes.func,
/**
* Invoked to obtain translated strings.
*/
- t: React.PropTypes.func
+ t: PropTypes.func
};
/**
@@ -44,8 +47,9 @@ class WaitForOwnerDialog extends Component {
constructor(props) {
super(props);
- this._onLogin = this._onLogin.bind(this);
+ // Bind event handlers so they are only bound once per instance.
this._onCancel = this._onCancel.bind(this);
+ this._onLogin = this._onLogin.bind(this);
}
/**
@@ -56,43 +60,25 @@ class WaitForOwnerDialog extends Component {
*/
render() {
const {
- roomName,
+ _room: room,
t
} = this.props;
return (
-
-
-
- { t(
- 'dialog.WaitForHostMsg',
- { room: roomName })
- }
-
-
-
-
-
+
);
}
- /**
- * Called when the OK button is clicked.
- *
- * @private
- * @returns {void}
- */
- _onLogin() {
- this.props.dispatch(_showLoginDialog());
- }
-
/**
* Called when the cancel button is clicked.
*
@@ -102,6 +88,33 @@ class WaitForOwnerDialog extends Component {
_onCancel() {
this.props.dispatch(cancelWaitForOwner());
}
+
+ /**
+ * Called when the OK button is clicked.
+ *
+ * @private
+ * @returns {void}
+ */
+ _onLogin() {
+ this.props.dispatch(_openLoginDialog());
+ }
+
+ /**
+ * Renders a specific string which may contain HTML.
+ *
+ * @param {string} html - The string which may contain HTML to
+ * render.
+ * @returns {string}
+ */
+ _renderHTML(html) {
+ if (typeof html === 'string') {
+ // TODO Limited styling may easily be provided by utilizing Text
+ // with style.
+ return html.replace(/<\\?b>/gi, '');
+ }
+
+ return html;
+ }
}
/**
@@ -111,7 +124,7 @@ class WaitForOwnerDialog extends Component {
* @param {Object} state - The Redux state.
* @private
* @returns {{
- * roomName: string
+ * _room: string
* }}
*/
function _mapStateToProps(state) {
@@ -120,7 +133,7 @@ function _mapStateToProps(state) {
} = state['features/base/conference'];
return {
- roomName: authRequired && authRequired.getName()
+ _room: authRequired && authRequired.getName()
};
}
diff --git a/react/features/authentication/components/styles.js b/react/features/authentication/components/styles.js
index 26b6a5ef2..54b70ef64 100644
--- a/react/features/authentication/components/styles.js
+++ b/react/features/authentication/components/styles.js
@@ -1,23 +1,55 @@
-import {
- ColorPalette,
- createStyleSheet
-} from '../../base/styles';
+import { BoxModel, createStyleSheet } from '../../base/styles';
+
+/**
+ * The style common to LoginDialog and WaitForOwnerDialog.
+ */
+const dialog = {
+ marginBottom: BoxModel.margin,
+ marginTop: BoxModel.margin
+};
+
+/**
+ * The style common to Text rendered by LoginDialog and
+ * WaitForOwnerDialog.
+ */
+const text = {
+};
/**
* The styles of the authentication feature.
*/
export default createStyleSheet({
- outerArea: {
- flex: 1
+ /**
+ * The style of LoginDialog.
+ */
+ loginDialog: {
+ ...dialog,
+ flex: 0,
+ flexDirection: 'column'
},
- dialogBox: {
- marginLeft: '10%',
- marginRight: '10%',
- marginTop: '10%',
- backgroundColor: ColorPalette.white
+
+ /**
+ * The style of Text rendered by LoginDialog.
+ */
+ loginDialogText: {
+ ...text
},
- textInput: {
- height: 25,
- fontSize: 16
+
+ /**
+ * The style of TextInput rendered by LoginDialog.
+ */
+ loginDialogTextInput: {
+ // XXX Matches react-native-prompt's dialogInput because base/dialog's
+ // Dialog is implemented using react-native-prompt.
+ fontSize: 18,
+ height: 50
+ },
+
+ /**
+ * The style of WaitForOwnerDialog.
+ */
+ waitForOwnerDialog: {
+ ...dialog,
+ ...text
}
});
diff --git a/react/features/authentication/functions.js b/react/features/authentication/functions.js
deleted file mode 100644
index f25a6a61e..000000000
--- a/react/features/authentication/functions.js
+++ /dev/null
@@ -1,74 +0,0 @@
-import {
- LoginDialog,
- WaitForOwnerDialog
-} from './components/index';
-import { hideDialog } from '../base/dialog/actions';
-
-/**
- * Will clear the wait for conference owner timeout handler if any is currently
- * set.
- *
- * @param {Object} store - The Redux store instance.
- * @returns {void}
- */
-export function clearExistingWaitForOwnerTimeout(store) {
- const { waitForOwnerTimeoutID }
- = store.getState()['features/authentication'];
-
- if (waitForOwnerTimeoutID) {
- clearTimeout(waitForOwnerTimeoutID);
- }
-}
-
-/**
- * Checks if {@link LoginDialog} is currently open.
- *
- * @param {Object|Function} getStateOrState - The Redux store instance or
- * store's get state method.
- * @returns {boolean}
- */
-export function isLoginDialogOpened(getStateOrState) {
- const state
- = typeof getStateOrState === 'function'
- ? getStateOrState() : getStateOrState;
- const dialogState = state['features/base/dialog'];
-
- return dialogState.component && dialogState.component === LoginDialog;
-}
-
-/**
- * Hides {@link LoginDialog} if it's currently displayed.
- *
- * @param {Object} store - The Redux store instance.
- * @returns {void}
- */
-export function hideLoginDialog({ dispatch, getState }) {
- if (isLoginDialogOpened(getState)) {
- dispatch(hideDialog());
- }
-}
-
-/**
- * Checks if {@link WaitForOwnerDialog} is currently open.
- *
- * @param {Object} store - The Redux store instance.
- * @returns {boolean}
- */
-export function isWaitForOwnerDialogOpened({ getState }) {
- const dialogState = getState()['features/base/dialog'];
-
- return dialogState.component
- && dialogState.component === WaitForOwnerDialog;
-}
-
-/**
- * Checks if the cyclic "wait for conference owner" task is currently scheduled.
- *
- * @param {Object} store - The Redux store instance.
- * @returns {boolean}
- */
-export function isWaitingForOwner({ getState }) {
- const { waitForOwnerTimeoutID } = getState()['features/authentication'];
-
- return Boolean(waitForOwnerTimeoutID);
-}
diff --git a/react/features/authentication/index.js b/react/features/authentication/index.js
index 88b1e84c2..a29aa08e0 100644
--- a/react/features/authentication/index.js
+++ b/react/features/authentication/index.js
@@ -1,7 +1,6 @@
export * from './actions';
export * from './actionTypes';
-export * from './functions';
+export * from './components';
import './middleware';
-
import './reducer';
diff --git a/react/features/authentication/middleware.js b/react/features/authentication/middleware.js
index 570a76ebc..26df0832c 100644
--- a/react/features/authentication/middleware.js
+++ b/react/features/authentication/middleware.js
@@ -1,40 +1,33 @@
+import { appNavigate } from '../app';
+import {
+ CONFERENCE_FAILED,
+ CONFERENCE_JOINED,
+ CONFERENCE_LEFT
+} from '../base/conference';
+import { CONNECTION_ESTABLISHED, CONNECTION_FAILED } from '../base/connection';
+import { hideDialog, isDialogOpen } from '../base/dialog';
+import {
+ JitsiConferenceErrors,
+ JitsiConnectionErrors
+} from '../base/lib-jitsi-meet';
import { MiddlewareRegistry } from '../base/redux';
import {
- clearWaitForOwnerTimeout,
- _showLoginDialog,
- _showWaitForOwnerDialog,
+ _openLoginDialog,
+ _openWaitForOwnerDialog,
+ stopWaitForOwner,
waitForOwner
} from './actions';
-import { appNavigate } from '../app/actions';
import {
CANCEL_LOGIN,
CANCEL_WAIT_FOR_OWNER,
STOP_WAIT_FOR_OWNER,
WAIT_FOR_OWNER
} from './actionTypes';
-import {
- CONFERENCE_FAILED,
- CONFERENCE_JOINED,
- CONFERENCE_LEFT
-} from '../base/conference/actionTypes';
-import { hideDialog } from '../base/dialog/actions';
-import { CONNECTION_ESTABLISHED } from '../base/connection/actionTypes';
-import { CONNECTION_FAILED } from '../base/connection';
-import {
- clearExistingWaitForOwnerTimeout,
- hideLoginDialog,
- isLoginDialogOpened,
- isWaitForOwnerDialogOpened,
- isWaitingForOwner
-} from './functions';
-import {
- JitsiConferenceErrors,
- JitsiConnectionErrors
-} from '../base/lib-jitsi-meet';
+import { LoginDialog, WaitForOwnerDialog } from './components';
/**
- * Middleware that captures connection or conference failed errors and controlls
+ * Middleware that captures connection or conference failed errors and controls
* {@link WaitForOwnerDialog} and {@link LoginDialog}.
*
* FIXME Some of the complexity was introduced by the lack of dialog stacking.
@@ -44,93 +37,121 @@ import {
*/
MiddlewareRegistry.register(store => next => action => {
switch (action.type) {
- case CONNECTION_FAILED: {
- if (action.error === JitsiConnectionErrors.PASSWORD_REQUIRED) {
- store.dispatch(_showLoginDialog());
- }
- break;
- }
- case CONNECTION_ESTABLISHED: {
- hideLoginDialog(store);
- break;
- }
- case CONFERENCE_FAILED: {
- if (action.error === JitsiConferenceErrors.AUTHENTICATION_REQUIRED) {
- store.dispatch(waitForOwner());
- } else {
- store.dispatch(clearWaitForOwnerTimeout());
- }
- break;
- }
- case CONFERENCE_JOINED: {
- if (isWaitingForOwner(store)) {
- store.dispatch(clearWaitForOwnerTimeout());
- }
- hideLoginDialog(store);
- break;
- }
- case CONFERENCE_LEFT: {
- store.dispatch(clearWaitForOwnerTimeout());
- break;
- }
- case WAIT_FOR_OWNER: {
- clearExistingWaitForOwnerTimeout(store);
- const { handler, timeoutMs } = action;
- const newTimeoutId = setTimeout(handler, timeoutMs);
-
- action.waitForOwnerTimeoutID = newTimeoutId;
-
- // The WAIT_FOR_OWNER action is cyclic and we don't want to hide
- // the login dialog every few seconds...
- if (!isLoginDialogOpened(store.getState())) {
- store.dispatch(_showWaitForOwnerDialog());
- }
- break;
- }
- case STOP_WAIT_FOR_OWNER: {
- clearExistingWaitForOwnerTimeout(store);
- if (isWaitForOwnerDialogOpened(store)) {
- store.dispatch(hideDialog());
- }
- break;
- }
case CANCEL_LOGIN: {
const { upgradeRoleInProgress }
= store.getState()['features/authentication'];
- if (upgradeRoleInProgress) {
- upgradeRoleInProgress.cancel();
- }
-
- const waitingForOwner = isWaitingForOwner(store);
+ upgradeRoleInProgress && upgradeRoleInProgress.cancel();
// The LoginDialog can be opened on top of "wait for owner". The app
- // should navigate only if LoginDialog was open without
- // the WaitForOwnerDialog.
- if (!isWaitForOwnerDialogOpened(store) && !waitingForOwner) {
- // Go back to app entry point
- hideLoginDialog(store);
+ // should navigate only if LoginDialog was open without the
+ // WaitForOwnerDialog.
+ if (!isDialogOpen(store, WaitForOwnerDialog)) {
+ if (_isWaitingForOwner(store)) {
+ // Instead of hiding show the new one.
+ const result = next(action);
+
+ store.dispatch(_openWaitForOwnerDialog());
+
+ return result;
+ }
+
+ // Go back to the app's entry point.
+ _hideLoginDialog(store);
store.dispatch(appNavigate(undefined));
- } else if (!isWaitForOwnerDialogOpened(store) && waitingForOwner) {
- // Instead of hiding show the new one.
- const result = next(action);
-
- store.dispatch(_showWaitForOwnerDialog());
-
- return result;
}
break;
}
+
case CANCEL_WAIT_FOR_OWNER: {
const result = next(action);
- store.dispatch(clearWaitForOwnerTimeout());
+ store.dispatch(stopWaitForOwner());
store.dispatch(appNavigate(undefined));
return result;
}
+ case CONFERENCE_FAILED:
+ if (action.error === JitsiConferenceErrors.AUTHENTICATION_REQUIRED) {
+ store.dispatch(waitForOwner());
+ } else {
+ store.dispatch(stopWaitForOwner());
+ }
+ break;
+
+ case CONFERENCE_JOINED:
+ if (_isWaitingForOwner(store)) {
+ store.dispatch(stopWaitForOwner());
+ }
+ _hideLoginDialog(store);
+ break;
+
+ case CONFERENCE_LEFT:
+ store.dispatch(stopWaitForOwner());
+ break;
+
+ case CONNECTION_ESTABLISHED:
+ _hideLoginDialog(store);
+ break;
+
+ case CONNECTION_FAILED:
+ action.error === JitsiConnectionErrors.PASSWORD_REQUIRED
+ && store.dispatch(_openLoginDialog());
+ break;
+
+ case STOP_WAIT_FOR_OWNER:
+ _clearExistingWaitForOwnerTimeout(store);
+ store.dispatch(hideDialog(WaitForOwnerDialog));
+ break;
+
+ case WAIT_FOR_OWNER: {
+ _clearExistingWaitForOwnerTimeout(store);
+
+ const { handler, timeoutMs } = action;
+
+ action.waitForOwnerTimeoutID = setTimeout(handler, timeoutMs);
+
+ // The WAIT_FOR_OWNER action is cyclic and we don't want to hide the
+ // login dialog every few seconds...
+ isDialogOpen(store, LoginDialog)
+ || store.dispatch(_openWaitForOwnerDialog());
+ break;
+ }
}
return next(action);
});
+
+/**
+ * Will clear the wait for conference owner timeout handler if any is currently
+ * set.
+ *
+ * @param {Object} store - The redux store.
+ * @returns {void}
+ */
+function _clearExistingWaitForOwnerTimeout({ getState }) {
+ const { waitForOwnerTimeoutID } = getState()['features/authentication'];
+
+ waitForOwnerTimeoutID && clearTimeout(waitForOwnerTimeoutID);
+}
+
+/**
+ * Hides {@link LoginDialog} if it's currently displayed.
+ *
+ * @param {Object} store - The redux store.
+ * @returns {void}
+ */
+function _hideLoginDialog({ dispatch }) {
+ dispatch(hideDialog(LoginDialog));
+}
+
+/**
+ * Checks if the cyclic "wait for conference owner" task is currently scheduled.
+ *
+ * @param {Object} store - The redux store.
+ * @returns {boolean}
+ */
+function _isWaitingForOwner({ getState }) {
+ return Boolean(getState()['features/authentication'].waitForOwnerTimeoutID);
+}
diff --git a/react/features/authentication/reducer.js b/react/features/authentication/reducer.js
index f54a34c93..573f0cbe3 100644
--- a/react/features/authentication/reducer.js
+++ b/react/features/authentication/reducer.js
@@ -1,43 +1,39 @@
-import { assign } from '../base/redux/functions';
-import { ReducerRegistry } from '../base/redux';
+/* @flow */
+
+import { assign, ReducerRegistry } from '../base/redux';
import {
CANCEL_LOGIN,
STOP_WAIT_FOR_OWNER,
- UPGRADE_ROLE_FAILED, UPGRADE_ROLE_STARTED, UPGRADE_ROLE_SUCCESS,
+ UPGRADE_ROLE_FINISHED,
+ UPGRADE_ROLE_STARTED,
WAIT_FOR_OWNER
} from './actionTypes';
-ReducerRegistry.register('features/authentication', (state = { }, action) => {
+ReducerRegistry.register('features/authentication', (state = {}, action) => {
switch (action.type) {
- case WAIT_FOR_OWNER:
- return assign(state, {
- waitForOwnerTimeoutID: action.waitForOwnerTimeoutID
- });
- case UPGRADE_ROLE_STARTED:
- return assign(state, {
- upgradeRoleError: undefined,
- upgradeRoleInProgress: action.authConnection
- });
- case UPGRADE_ROLE_SUCCESS:
- return assign(state, {
- upgradeRoleError: undefined,
- upgradeRoleInProgress: undefined
- });
- case UPGRADE_ROLE_FAILED:
- return assign(state, {
- upgradeRoleError: action.error,
- upgradeRoleInProgress: undefined
- });
case CANCEL_LOGIN:
return assign(state, {
upgradeRoleError: undefined,
upgradeRoleInProgress: undefined
});
+
case STOP_WAIT_FOR_OWNER:
return assign(state, {
- waitForOwnerTimeoutID: undefined,
- upgradeRoleError: undefined
+ upgradeRoleError: undefined,
+ waitForOwnerTimeoutID: undefined
+ });
+
+ case UPGRADE_ROLE_FINISHED:
+ case UPGRADE_ROLE_STARTED:
+ return assign(state, {
+ upgradeRoleError: action.error,
+ upgradeRoleInProgress: action.thenableWithCancel
+ });
+
+ case WAIT_FOR_OWNER:
+ return assign(state, {
+ waitForOwnerTimeoutID: action.waitForOwnerTimeoutID
});
}
diff --git a/react/features/base/conference/actions.js b/react/features/base/conference/actions.js
index 8ddf2cc47..f5f9b1ee0 100644
--- a/react/features/base/conference/actions.js
+++ b/react/features/base/conference/actions.js
@@ -298,12 +298,10 @@ export function createConference() {
*/
export function checkIfCanJoin() {
return (dispatch, getState) => {
- const { password, authRequired }
+ const { authRequired, password }
= getState()['features/base/conference'];
- if (authRequired) {
- authRequired.join(password);
- }
+ authRequired && authRequired.join(password);
};
}
diff --git a/react/features/base/connection/actions.native.js b/react/features/base/connection/actions.native.js
index 1b078e80b..9e1a3f66b 100644
--- a/react/features/base/connection/actions.native.js
+++ b/react/features/base/connection/actions.native.js
@@ -18,12 +18,11 @@ import {
/**
* Opens new connection.
*
- * @param {string} [username] - The XMPP user id eg. user@server.com.
- * @param {string} [password] - The user's password.
- *
+ * @param {string} [id] - The XMPP user's ID (e.g. user@server.com).
+ * @param {string} [password] - The XMPP user's password.
* @returns {Function}
*/
-export function connect(username: ?string, password: ?string) {
+export function connect(id: ?string, password: ?string) {
return (dispatch: Dispatch<*>, getState: Function) => {
const state = getState();
const options = _constructOptions(state);
@@ -47,7 +46,7 @@ export function connect(username: ?string, password: ?string) {
_onConnectionFailed);
connection.connect({
- id: username,
+ id,
password
});
diff --git a/react/features/base/connection/functions.js b/react/features/base/connection/functions.js
index 458cfbd75..40196d915 100644
--- a/react/features/base/connection/functions.js
+++ b/react/features/base/connection/functions.js
@@ -53,24 +53,14 @@ export function getURLWithoutParams(url: URL): URL {
}
/**
- * Convert provided id to jid if it's not jid yet.
+ * Converts a specific id to jid if it's not jid yet.
*
* @param {string} id - User id or jid.
- * @param {Object} configHosts - The 'hosts' part of the config object.
- * @returns {string} jid - A string in the form of user@server.com.
+ * @param {Object} configHosts - The hosts part of the config
+ * object.
+ * @returns {string} A string in the form of a JID (i.e.
+ * user@server.com).
*/
-export function toJid(id: string, configHosts: Object): string {
- if (id.indexOf('@') >= 0) {
- return id;
- }
-
- let jid = id.concat('@');
-
- if (configHosts.authdomain) {
- jid += configHosts.authdomain;
- } else {
- jid += configHosts.domain;
- }
-
- return jid;
+export function toJid(id: string, { authdomain, domain }: Object): string {
+ return id.indexOf('@') >= 0 ? id : `${id}@${authdomain || domain}`;
}