diff --git a/conference.js b/conference.js
index 3a45895f6..d73fef644 100644
--- a/conference.js
+++ b/conference.js
@@ -1263,21 +1263,24 @@ export default {
* @returns {void}
*/
_displayAudioOnlyTooltip(featureName) {
+ let buttonName = null;
let tooltipElementId = null;
switch (featureName) {
case 'screenShare':
- tooltipElementId = '#screenshareWhileAudioOnly';
+ buttonName = 'desktop';
+ tooltipElementId = 'screenshareWhileAudioOnly';
break;
case 'videoMute':
- tooltipElementId = '#unmuteWhileAudioOnly';
+ buttonName = 'camera';
+ tooltipElementId = 'unmuteWhileAudioOnly';
break;
}
if (tooltipElementId) {
APP.UI.showToolbar(6000);
APP.UI.showCustomToolbarPopup(
- tooltipElementId, true, 5000);
+ buttonName, tooltipElementId, true, 5000);
}
},
@@ -1697,7 +1700,8 @@ export default {
room.on(ConferenceEvents.TALK_WHILE_MUTED, () => {
APP.UI.showToolbar(6000);
- APP.UI.showCustomToolbarPopup('#talkWhileMutedPopup', true, 5000);
+ APP.UI.showCustomToolbarPopup(
+ 'microphone', 'talkWhileMutedPopup', true, 5000);
});
room.on(
diff --git a/css/_toolbars.scss b/css/_toolbars.scss
index 7dcefd3a5..44dcf763a 100644
--- a/css/_toolbars.scss
+++ b/css/_toolbars.scss
@@ -130,11 +130,11 @@
@include transform(translateX(-50%));
- .button:first-child {
+ > div:first-child .button {
border-bottom-left-radius: 3px;
border-top-left-radius: 3px;
}
- .button:last-child {
+ > div:last-child .button {
border-bottom-right-radius: 3px;
border-top-right-radius: 3px;
}
diff --git a/lang/main.json b/lang/main.json
index 02bd3957e..9ff05492b 100644
--- a/lang/main.json
+++ b/lang/main.json
@@ -114,8 +114,8 @@
"login": "Login",
"logout": "Logout",
"dialpad": "Open / Close dialpad",
- "sharedVideoMutedPopup": "Your shared video has been muted so
that you can talk to the other participants.",
- "micMutedPopup": "Your microphone has been muted so that you
would fully enjoy your shared video.",
+ "sharedVideoMutedPopup": "Your shared video has been muted so that you can talk to the other participants.",
+ "micMutedPopup": "Your microphone has been muted so that you would fully enjoy your shared video.",
"talkWhileMutedPopup": "Trying to speak? You are muted.",
"unableToUnmutePopup": "You cannot un-mute while the shared video is on.",
"cameraDisabled": "Camera is not available",
diff --git a/modules/UI/UI.js b/modules/UI/UI.js
index a5346db67..9e998ff35 100644
--- a/modules/UI/UI.js
+++ b/modules/UI/UI.js
@@ -30,7 +30,9 @@ import {
import { openDisplayNamePrompt } from '../../react/features/display-name';
import {
checkAutoEnableDesktopSharing,
+ clearButtonPopup,
dockToolbox,
+ setButtonPopupTimeout,
setToolbarButton,
showDialPadButton,
showEtherpadButton,
@@ -609,13 +611,21 @@ UI.inputDisplayNameHandler = function (newDisplayName) {
/**
* Show custom popup/tooltip for a specified button.
- * @param popupSelectorID the selector id of the popup to show
- * @param show true or false/show or hide the popup
- * @param timeout the time to show the popup
+ *
+ * @param {string} buttonName - The name of the button as specified in the
+ * button configurations for the toolbar.
+ * @param {string} popupSelectorID - The id of the popup to show as specified in
+ * the button configurations for the toolbar.
+ * @param {boolean} show - True or false/show or hide the popup
+ * @param {number} timeout - The time to show the popup
+ * @returns {void}
*/
-UI.showCustomToolbarPopup = function (popupSelectorID, show, timeout) {
- eventEmitter.emit(UIEvents.SHOW_CUSTOM_TOOLBAR_BUTTON_POPUP,
- popupSelectorID, show, timeout);
+UI.showCustomToolbarPopup = function (buttonName, popupID, show, timeout) {
+ const action = show
+ ? setButtonPopupTimeout(buttonName, popupID, timeout)
+ : clearButtonPopup(buttonName);
+
+ APP.store.dispatch(action);
};
/**
diff --git a/modules/UI/recording/Recording.js b/modules/UI/recording/Recording.js
index 1524189b5..99295d9bc 100644
--- a/modules/UI/recording/Recording.js
+++ b/modules/UI/recording/Recording.js
@@ -18,7 +18,6 @@ const logger = require("jitsi-meet-logger").getLogger(__filename);
import UIEvents from "../../../service/UI/UIEvents";
import UIUtil from '../util/UIUtil';
-import { setTooltip } from '../util/Tooltip';
import VideoLayout from '../videolayout/VideoLayout';
import { setToolboxEnabled } from '../../../react/features/toolbox';
@@ -324,8 +323,6 @@ var Recording = {
initRecordingButton() {
const selector = $('#toolbar_button_record');
- setTooltip(selector, 'liveStreaming.buttonTooltip', 'right');
-
selector.addClass(this.baseClass);
selector.attr("data-i18n", "[content]" + this.recordingButtonTooltip);
APP.translation.translateElement(selector);
diff --git a/modules/UI/shared_video/SharedVideo.js b/modules/UI/shared_video/SharedVideo.js
index 4fb98bd28..e9a34e1ed 100644
--- a/modules/UI/shared_video/SharedVideo.js
+++ b/modules/UI/shared_video/SharedVideo.js
@@ -558,7 +558,8 @@ export default class SharedVideoManager {
if(show)
this.showSharedVideoMutedPopup(false);
- APP.UI.showCustomToolbarPopup('#micMutedPopup', show, 5000);
+ APP.UI.showCustomToolbarPopup(
+ 'microphone', 'micMutedPopup', show, 5000);
}
/**
@@ -571,7 +572,8 @@ export default class SharedVideoManager {
if(show)
this.showMicMutedPopup(false);
- APP.UI.showCustomToolbarPopup('#sharedVideoMutedPopup', show, 5000);
+ APP.UI.showCustomToolbarPopup(
+ 'sharedvideo', 'sharedVideoMutedPopup', show, 5000);
}
}
diff --git a/react/features/toolbox/actions.web.js b/react/features/toolbox/actions.web.js
index c7b61e993..54d58473b 100644
--- a/react/features/toolbox/actions.web.js
+++ b/react/features/toolbox/actions.web.js
@@ -20,6 +20,7 @@ import {
} from './actions.native';
import { SET_DEFAULT_TOOLBOX_BUTTONS } from './actionTypes';
import {
+ getButton,
getDefaultToolboxButtons,
isButtonEnabled
} from './functions';
@@ -48,6 +49,23 @@ export function checkAutoEnableDesktopSharing(): Function {
};
}
+/**
+ * Dispatches an action to hide any popups displayed by the associated button.
+ *
+ * @param {string} buttonName - The name of the button as specified in the
+ * button configurations for the toolbar.
+ * @returns {Function}
+ */
+export function clearButtonPopup(buttonName) {
+ return (dispatch, getState) => {
+ _clearPopupTimeout(buttonName, getState());
+
+ dispatch(setToolbarButton(buttonName, {
+ popupDisplay: null
+ }));
+ };
+}
+
/**
* Docks/undocks the Toolbox.
*
@@ -195,6 +213,34 @@ export function hideToolbox(force: boolean = false): Function {
};
}
+/**
+ * Dispatches an action to show the popup associated with a button. Sets a
+ * timeout to be fired which will dismiss the popup.
+ *
+ * @param {string} buttonName - The name of the button as specified in the
+ * button configurations for the toolbar.
+ * @param {string} popupName - The id of the popup to show as specified in
+ * the button configurations for the toolbar.
+ * @param {number} timeout - The time in milliseconds to show the popup.
+ * @returns {Function}
+ */
+export function setButtonPopupTimeout(buttonName, popupName, timeout) {
+ return (dispatch, getState) => {
+ _clearPopupTimeout(buttonName, getState());
+
+ const newTimeoutId = setTimeout(() => {
+ dispatch(clearButtonPopup(buttonName));
+ }, timeout);
+
+ dispatch(setToolbarButton(buttonName, {
+ popupDisplay: {
+ popupID: popupName,
+ timeoutID: newTimeoutId
+ }
+ }));
+ };
+}
+
/**
* Sets the default toolbar buttons of the Toolbox.
*
@@ -387,3 +433,20 @@ export function toggleSideToolbarContainer(containerId: string): Function {
}
};
}
+
+/**
+ * Clears the timeout set for hiding a button popup.
+ *
+ * @param {string} buttonName - The name of the button as specified in the
+ * button configurations for the toolbar.
+ * @param {Object} state - The redux state in which the button is expected to
+ * be defined.
+ * @private
+ * @returns {void}
+ */
+function _clearPopupTimeout(buttonName, state) {
+ const { popupDisplay } = getButton(buttonName, state);
+ const { timeoutID } = popupDisplay || {};
+
+ clearTimeout(timeoutID);
+}
diff --git a/react/features/toolbox/components/ToolbarButton.web.js b/react/features/toolbox/components/ToolbarButton.web.js
index 763a4013d..897cbfdb3 100644
--- a/react/features/toolbox/components/ToolbarButton.web.js
+++ b/react/features/toolbox/components/ToolbarButton.web.js
@@ -1,5 +1,6 @@
/* @flow */
+import AKInlineDialog from '@atlaskit/inline-dialog';
import { Tooltip } from '@atlaskit/tooltip';
import React, { Component } from 'react';
@@ -11,6 +12,18 @@ 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.
*
@@ -127,26 +140,39 @@ class ToolbarButton extends Component {
*/
render(): ReactElement<*> {
const { button, t, tooltipPosition } = this.props;
- const popups = button.popups || [];
-
const props = {
...this.props,
onClick: this._onClick,
createRefToButton: this._createRefToButton
};
- return (
+ const buttonComponent = ( // eslint-disable-line no-extra-parens