diff --git a/react/features/invite/components/InfoDialogButton.web.js b/react/features/invite/components/InfoDialogButton.web.js
index 1b6c4eadf..dd0f6febb 100644
--- a/react/features/invite/components/InfoDialogButton.web.js
+++ b/react/features/invite/components/InfoDialogButton.web.js
@@ -1,9 +1,18 @@
+import InlineDialog from '@atlaskit/inline-dialog';
+import PropTypes from 'prop-types';
import React, { Component } from 'react';
+import { connect } from 'react-redux';
-import { ToolbarButtonWithDialog } from '../../toolbox';
+import { ToolbarButton, TOOLTIP_TO_POPUP_POSITION } from '../../toolbox';
+
+import { setInfoDialogVisibility } from '../actions';
import InfoDialog from './InfoDialog';
+declare var interfaceConfig: Object;
+
+const { INITIAL_TOOLBAR_TIMEOUT } = interfaceConfig;
+
/**
* A configuration object to describe how {@code ToolbarButton} should render
* the button.
@@ -25,6 +34,103 @@ const DEFAULT_BUTTON_CONFIGURATION = {
* @extends Component
*/
class InfoDialogButton extends Component {
+ /**
+ * {@code InfoDialogButton} component's property types.
+ *
+ * @static
+ */
+ static propTypes = {
+ /**
+ * Whether or not {@code InfoDialog} should be displayed.
+ */
+ _showDialog: PropTypes.bool,
+
+ /**
+ * Whether or not the toolbox, in which this component exists, are
+ * visible.
+ */
+ _toolboxVisible: PropTypes.bool,
+
+ /**
+ * Invoked to toggle display of the info dialog
+ */
+ dispatch: PropTypes.func,
+
+ /**
+ * From which side tooltips should display. Will be re-used for
+ * displaying the inline dialog for video quality adjustment.
+ */
+ tooltipPosition: PropTypes.string
+ };
+
+ /**
+ * Initializes new {@code ToolbarButtonWithDialog} instance.
+ *
+ * @param {Object} props - The read-only properties with which the new
+ * instance is to be initialized.
+ */
+ constructor(props) {
+ super(props);
+
+ /**
+ * The timeout to automatically hide the {@code InfoDialog} if it has
+ * not been interacted with.
+ *
+ * @type {timeoutID}
+ */
+ this._autoHideDialogTimeout = null;
+
+ this.state = {
+ /**
+ * Whether or not the dialog has been interacted with somehow, such
+ * as clicking or toggle display. A value of true will prevent the
+ * dialog from being automatically hidden.
+ */
+ hasInteractedWithDialog: false
+ };
+
+ // Bind event handlers so they are only bound once for every instance.
+ this._onDialogClose = this._onDialogClose.bind(this);
+ this._onDialogMouseOver = this._onDialogMouseOver.bind(this);
+ this._onDialogToggle = this._onDialogToggle.bind(this);
+ }
+
+ /**
+ * Set a timeout to automatically hide the {@code InfoDialog}.
+ *
+ * @inheritdoc
+ */
+ componentDidMount() {
+ this._autoHideDialogTimeout = setTimeout(() => {
+ this._maybeHideDialog();
+ }, INITIAL_TOOLBAR_TIMEOUT);
+ }
+
+ /**
+ * Update the state when the {@code InfoDialog} visibility has been updated.
+ *
+ * @inheritdoc
+ */
+ componentWillReceiveProps(nextProps) {
+ if (!this.state.hasInteractedWithDialog
+ && (nextProps._showDialog !== this.props._showDialog)) {
+ this.setState({ hasInteractedWithDialog: true });
+ }
+
+ if (!nextProps._toolboxVisible && this.props._toolboxVisible) {
+ this._onDialogClose();
+ }
+ }
+
+ /**
+ * Clear the timeout to automatically show the {@code InfoDialog}.
+ *
+ * @inheritdoc
+ */
+ componentWillUnmount() {
+ clearTimeout(this._autoHideDialogTimeout);
+ }
+
/**
* Implements React's {@link Component#render()}.
*
@@ -32,13 +138,96 @@ class InfoDialogButton extends Component {
* @returns {ReactElement}
*/
render() {
+ const { _showDialog, _toolboxVisible, tooltipPosition } = this.props;
+ const buttonConfiguration = {
+ ...DEFAULT_BUTTON_CONFIGURATION,
+ classNames: [
+ ...DEFAULT_BUTTON_CONFIGURATION.classNames,
+ _showDialog ? 'toggled button-active' : ''
+ ]
+ };
+
return (
-
+ }
+ isOpen = { _toolboxVisible && _showDialog }
+ onClose = { this._onDialogClose }
+ onContentClick = { this._onDialogInteract }
+ position = { TOOLTIP_TO_POPUP_POSITION[tooltipPosition] }>
+
+
);
}
+
+ /**
+ * Callback invoked after a timeout to trigger hiding of the
+ * {@code InfoDialog} if there has been no interaction with the dialog
+ * and the dialog is currently showing.
+ *
+ * @private
+ * @returns {void}
+ */
+ _maybeHideDialog() {
+ if (!this.state.hasInteractedWithDialog && this.props._showDialog) {
+ this._onDialogToggle();
+ }
+ }
+
+ /**
+ * Hides {@code InfoDialog}.
+ *
+ * @private
+ * @returns {void}
+ */
+ _onDialogClose() {
+ this.props.dispatch(setInfoDialogVisibility(false));
+ }
+
+ /**
+ * Updates the internal state to mark the {@code InfoDialog} as having been
+ * interacted with.
+ *
+ * @private
+ * @returns {void}
+ */
+ _onDialogMouseOver() {
+ if (!this.state.hasInteractedWithDialog) {
+ this.setState({ hasInteractedWithDialog: true });
+ }
+ }
+
+ /**
+ * Toggles the display of {@code InfoDialog}.
+ *
+ * @private
+ * @returns {void}
+ */
+ _onDialogToggle() {
+ this.props.dispatch(setInfoDialogVisibility(!this.props._showDialog));
+ }
}
-export default InfoDialogButton;
+/**
+ * Maps (parts of) the Redux state to the associated {@code InfoDialogButton}
+ * component's props.
+ *
+ * @param {Object} state - The Redux state.
+ * @private
+ * @returns {{
+ * _showDialog: boolean,
+ * _toolboxVisible: boolean
+ * }}
+ */
+function _mapStateToProps(state) {
+ return {
+ _showDialog: state['features/invite'].infoDialogVisible,
+ _toolboxVisible: state['features/toolbox'].visible
+ };
+}
+
+export default connect(_mapStateToProps)(InfoDialogButton);
diff --git a/react/features/invite/reducer.js b/react/features/invite/reducer.js
index 5323903c5..215c80bd6 100644
--- a/react/features/invite/reducer.js
+++ b/react/features/invite/reducer.js
@@ -1,16 +1,27 @@
import { ReducerRegistry } from '../base/redux';
import {
+ SET_INFO_DIALOG_VISIBILITY,
UPDATE_DIAL_IN_NUMBERS_FAILED,
UPDATE_DIAL_IN_NUMBERS_SUCCESS
} from './actionTypes';
const DEFAULT_STATE = {
+
+ // By default show the info dialog when joining the conference.
+ infoDialogVisible: true,
+
numbersEnabled: true
};
ReducerRegistry.register('features/invite', (state = DEFAULT_STATE, action) => {
switch (action.type) {
+ case SET_INFO_DIALOG_VISIBILITY:
+ return {
+ ...state,
+ infoDialogVisible: action.visible
+ };
+
case UPDATE_DIAL_IN_NUMBERS_FAILED:
return {
...state,
diff --git a/react/features/toolbox/components/ToolbarButton.web.js b/react/features/toolbox/components/ToolbarButton.web.js
index 0b4753e1d..3ce6bf59d 100644
--- a/react/features/toolbox/components/ToolbarButton.web.js
+++ b/react/features/toolbox/components/ToolbarButton.web.js
@@ -7,23 +7,12 @@ import React, { Component } from 'react';
import { translate } from '../../base/i18n';
+import { TOOLTIP_TO_POPUP_POSITION } from '../constants';
import { isButtonEnabled } from '../functions';
import StatelessToolbarButton from './StatelessToolbarButton';
declare var APP: Object;
-/**
- * Mapping of tooltip positions to equivalent {@code AKInlineDialog} positions.
- *
- * @private
- */
-const TOOLTIP_TO_POPUP_POSITION = {
- bottom: 'bottom center',
- left: 'left middle',
- top: 'top center',
- right: 'right middle'
-};
-
/**
* Represents a button in Toolbar on React.
*
diff --git a/react/features/toolbox/components/ToolbarButtonWithDialog.web.js b/react/features/toolbox/components/ToolbarButtonWithDialog.web.js
index a3e45982e..41234f2a1 100644
--- a/react/features/toolbox/components/ToolbarButtonWithDialog.web.js
+++ b/react/features/toolbox/components/ToolbarButtonWithDialog.web.js
@@ -3,21 +3,9 @@ import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
+import { TOOLTIP_TO_POPUP_POSITION } from '../constants';
import ToolbarButton from './ToolbarButton';
-/**
- * Maps AtlasKit {@code Tooltip} positions to equivalent {@code InlineDialog}
- * positions. The {@code InlineDialog} will appear from the the same side of
- * the button as the tooltip.
- *
- */
-const TOOLTIP_TO_DIALOG_POSITION = {
- bottom: 'bottom center',
- left: 'left middle',
- right: 'right middle',
- top: 'top center'
-};
-
/**
* React {@code Component} for displaying a button which will open an inline
* dialog.
@@ -113,7 +101,7 @@ class ToolbarButtonWithDialog extends Component {
content = { }
isOpen = { _visible && this.state.showDialog }
onClose = { this._onDialogClose }
- position = { TOOLTIP_TO_DIALOG_POSITION[tooltipPosition] }>
+ position = { TOOLTIP_TO_POPUP_POSITION[tooltipPosition] }>