From cd4c940107c6ed68f47bf6fde21d090701a784d9 Mon Sep 17 00:00:00 2001 From: hmuresan Date: Thu, 23 Sep 2021 17:39:05 +0300 Subject: [PATCH] fix(toolbar) Fix toolbar always visible; refactors - deprecate `INITIAL_TOOLBAR_TIMEOUT`, `TOOLBAR_ALWAYS_VISIBLE`, `TOOLBAR_TIMEOUT` --- config.js | 13 ++ interface_config.js | 16 +- react/features/base/config/configWhitelist.js | 1 + react/features/base/config/reducer.js | 22 +++ react/features/toolbox/actionTypes.js | 21 --- react/features/toolbox/actions.any.js | 38 ++--- react/features/toolbox/actions.native.js | 20 ++- react/features/toolbox/actions.web.js | 58 +++---- react/features/toolbox/constants.js | 2 + react/features/toolbox/functions.native.js | 6 +- react/features/toolbox/functions.web.js | 17 +- react/features/toolbox/reducer.js | 159 +++++------------- 12 files changed, 170 insertions(+), 203 deletions(-) diff --git a/config.js b/config.js index 1695557e7..061012a26 100644 --- a/config.js +++ b/config.js @@ -545,6 +545,19 @@ var config = { // '__end' // ], + // Holds values related to toolbar visibility control. + // toolbarConfig: { + // // Moved from interfaceConfig.INITIAL_TOOLBAR_TIMEOUT + // // The initial numer of miliseconds for the toolbar buttons to be visible on screen. + // initialTimeout: 20000, + // // Moved from interfaceConfig.TOOLBAR_TIMEOUT + // // Number of miliseconds for the toolbar buttons to be visible on screen. + // timeout: 4000, + // // Moved from interfaceConfig.TOOLBAR_ALWAYS_VISIBLE + // // Whether toolbar should be always visible or should hide after x miliseconds. + // alwaysVisible: false + // }, + // Toolbar buttons which have their click event exposed through the API on // `toolbarButtonClicked` event instead of executing the normal click routine. // buttonsWithNotifyClick: [ diff --git a/interface_config.js b/interface_config.js index 2ccbd8148..cbef738fc 100644 --- a/interface_config.js +++ b/interface_config.js @@ -97,7 +97,11 @@ var interfaceConfig = { */ HIDE_INVITE_MORE_HEADER: false, - INITIAL_TOOLBAR_TIMEOUT: 20000, + /** + * DEPRECATED! Moved to config.js as `toolbarConfig.initialTimeout`. + */ + // INITIAL_TOOLBAR_TIMEOUT: 20000, + JITSI_WATERMARK_LINK: 'https://jitsi.org', LANG_DETECTION: true, // Allow i18n to detect the system language @@ -183,7 +187,10 @@ var interfaceConfig = { */ SUPPORT_URL: 'https://community.jitsi.org/', - TOOLBAR_ALWAYS_VISIBLE: false, + /** + * DEPRECATED! Moved to config.js as `toolbarConfig.alwaysVisible`. + */ + // TOOLBAR_ALWAYS_VISIBLE: false, /** * DEPRECATED! @@ -191,7 +198,10 @@ var interfaceConfig = { */ // TOOLBAR_BUTTONS: [], - TOOLBAR_TIMEOUT: 4000, + /** + * DEPRECATED! Moved to config.js as `toolbarConfig.timeout`. + */ + // TOOLBAR_TIMEOUT: 4000, // Browsers, in addition to those which do not fully support WebRTC, that // are not supported and should show the unsupported browser page. diff --git a/react/features/base/config/configWhitelist.js b/react/features/base/config/configWhitelist.js index fa65bed93..71ac52b5a 100644 --- a/react/features/base/config/configWhitelist.js +++ b/react/features/base/config/configWhitelist.js @@ -188,6 +188,7 @@ export default [ 'subject', 'testing', 'toolbarButtons', + 'toolbarConfig', 'useHostPageLocalStorage', 'useTurnUdp', 'videoQuality.persist', diff --git a/react/features/base/config/reducer.js b/react/features/base/config/reducer.js index a22edffa2..0a7ac85f0 100644 --- a/react/features/base/config/reducer.js +++ b/react/features/base/config/reducer.js @@ -227,6 +227,28 @@ function _translateLegacyConfig(oldValue: Object) { newValue.toolbarButtons = interfaceConfig.TOOLBAR_BUTTONS; } + if (!oldValue.toolbarConfig) { + oldValue.toolbarConfig = {}; + } + + if (typeof oldValue.toolbarConfig.alwaysVisible !== 'boolean' + && typeof interfaceConfig === 'object' + && typeof interfaceConfig.TOOLBAR_ALWAYS_VISIBLE === 'boolean') { + newValue.toolbarConfig.alwaysVisible = interfaceConfig.TOOLBAR_ALWAYS_VISIBLE; + } + + if (typeof oldValue.toolbarConfig.initialTimeout !== 'number' + && typeof interfaceConfig === 'object' + && typeof interfaceConfig.INITIAL_TOOLBAR_TIMEOUT === 'number') { + newValue.toolbarConfig.initialTimeout = interfaceConfig.INITIAL_TOOLBAR_TIMEOUT; + } + + if (typeof oldValue.toolbarConfig.timeout !== 'number' + && typeof interfaceConfig === 'object' + && typeof interfaceConfig.TOOLBAR_TIMEOUT === 'number') { + newValue.toolbarConfig.timeout = interfaceConfig.TOOLBAR_TIMEOUT; + } + const filteredConferenceInfo = Object.keys(CONFERENCE_HEADER_MAPPING).filter(key => oldValue[key]); if (filteredConferenceInfo.length) { diff --git a/react/features/toolbox/actionTypes.js b/react/features/toolbox/actionTypes.js index e01f0ff1d..4f23c8d9b 100644 --- a/react/features/toolbox/actionTypes.js +++ b/react/features/toolbox/actionTypes.js @@ -55,16 +55,6 @@ export const SET_OVERFLOW_MENU_VISIBLE = 'SET_OVERFLOW_MENU_VISIBLE'; */ export const SET_TOOLBAR_HOVERED = 'SET_TOOLBAR_HOVERED'; -/** - * The type of the action which sets the permanent visibility of the Toolbox. - * - * { - * type: SET_TOOLBOX_ALWAYS_VISIBLE, - * alwaysVisible: boolean - * } - */ -export const SET_TOOLBOX_ALWAYS_VISIBLE = 'SET_TOOLBOX_ALWAYS_VISIBLE'; - /** * The type of the (redux) action which enables/disables the Toolbox. * @@ -87,17 +77,6 @@ export const SET_TOOLBOX_ENABLED = 'SET_TOOLBOX_ENABLED'; */ export const SET_TOOLBOX_TIMEOUT = 'SET_TOOLBOX_TIMEOUT'; -/** - * The type of the action which sets the delay in milliseconds after which - * the Toolbox visibility is to be changed. - * - * { - * type: SET_TOOLBOX_TIMEOUT_MS, - * timeoutMS: number - * } - */ -export const SET_TOOLBOX_TIMEOUT_MS = 'SET_TOOLBOX_TIMEOUT_MS'; - /** * The type of the (redux) action which shows/hides the Toolbox. * diff --git a/react/features/toolbox/actions.any.js b/react/features/toolbox/actions.any.js index 5191c47d6..007177172 100644 --- a/react/features/toolbox/actions.any.js +++ b/react/features/toolbox/actions.any.js @@ -1,27 +1,12 @@ // @flow +import type { Dispatch } from 'redux'; + import { - SET_TOOLBOX_ALWAYS_VISIBLE, SET_TOOLBOX_ENABLED, SET_TOOLBOX_VISIBLE } from './actionTypes'; -/** - * Signals that always visible toolbars value should be changed. - * - * @param {boolean} alwaysVisible - Value to be set in redux store. - * @returns {{ - * type: SET_TOOLBOX_ALWAYS_VISIBLE, - * alwaysVisible: boolean - * }} - */ -export function setToolboxAlwaysVisible(alwaysVisible: boolean): Object { - return { - type: SET_TOOLBOX_ALWAYS_VISIBLE, - alwaysVisible - }; -} - /** * Enables/disables the toolbox. * @@ -42,14 +27,19 @@ export function setToolboxEnabled(enabled: boolean): Object { * Shows/hides the toolbox. * * @param {boolean} visible - True to show the toolbox or false to hide it. - * @returns {{ - * type: SET_TOOLBOX_VISIBLE, - * visible: boolean - * }} + * @returns {Function} */ export function setToolboxVisible(visible: boolean): Object { - return { - type: SET_TOOLBOX_VISIBLE, - visible + return (dispatch: Dispatch, getState: Function) => { + const { toolbarConfig: { alwaysVisible } } = getState()['features/base/config']; + + if (!visible && alwaysVisible) { + return; + } + + dispatch({ + type: SET_TOOLBOX_VISIBLE, + visible + }); }; } diff --git a/react/features/toolbox/actions.native.js b/react/features/toolbox/actions.native.js index 00ea1b2f7..0bc714c08 100644 --- a/react/features/toolbox/actions.native.js +++ b/react/features/toolbox/actions.native.js @@ -1,5 +1,7 @@ // @flow +import type { Dispatch } from 'redux'; + import { TOGGLE_TOOLBOX_VISIBLE } from './actionTypes'; export * from './actions.any'; @@ -7,12 +9,20 @@ export * from './actions.any'; /** * Action to toggle the toolbox visibility. * - * @returns {{ - * type: TOGGLE_TOOLBOX_VISIBLE - * }} + * @returns {Function} */ export function toggleToolboxVisible() { - return { - type: TOGGLE_TOOLBOX_VISIBLE + return (dispatch: Dispatch, getState: Function) => { + const state = getState(); + const { toolbarConfig: { alwaysVisible } } = state['features/base/config']; + const { visible } = state['features/toolbox']; + + if (visible && alwaysVisible) { + return; + } + + dispatch({ + type: TOGGLE_TOOLBOX_VISIBLE + }); }; } diff --git a/react/features/toolbox/actions.web.js b/react/features/toolbox/actions.web.js index 192080e62..bf148d412 100644 --- a/react/features/toolbox/actions.web.js +++ b/react/features/toolbox/actions.web.js @@ -2,6 +2,7 @@ import type { Dispatch } from 'redux'; +import { overwriteConfig } from '../base/config'; import { isLayoutTileView } from '../video-layout'; import { @@ -11,12 +12,10 @@ import { SET_OVERFLOW_DRAWER, SET_OVERFLOW_MENU_VISIBLE, SET_TOOLBAR_HOVERED, - SET_TOOLBOX_TIMEOUT, - SET_TOOLBOX_TIMEOUT_MS + SET_TOOLBOX_TIMEOUT } from './actionTypes'; -import { setToolboxVisible } from './actions.any'; - -declare var interfaceConfig: Object; +import { setToolboxVisible } from './actions'; +import { getToolbarTimeout } from './functions'; export * from './actions.any'; @@ -28,7 +27,9 @@ export * from './actions.any'; */ export function dockToolbox(dock: boolean): Function { return (dispatch: Dispatch, getState: Function) => { - const { timeoutMS, visible } = getState()['features/toolbox']; + const state = getState(); + const { visible } = state['features/toolbox']; + const toolbarTimeout = getToolbarTimeout(state); if (dock) { // First make sure the toolbox is shown. @@ -39,7 +40,7 @@ export function dockToolbox(dock: boolean): Function { dispatch( setToolboxTimeout( () => dispatch(hideToolbox()), - timeoutMS)); + toolbarTimeout)); } else { dispatch(showToolbox()); } @@ -73,11 +74,9 @@ export function fullScreenChanged(fullScreen: boolean) { export function hideToolbox(force: boolean = false): Function { return (dispatch: Dispatch, getState: Function) => { const state = getState(); - const { - alwaysVisible, - hovered, - timeoutMS - } = state['features/toolbox']; + const { toolbarConfig: { alwaysVisible } } = state['features/base/config']; + const { hovered } = state['features/toolbox']; + const toolbarTimeout = getToolbarTimeout(state); if (alwaysVisible) { return; @@ -95,7 +94,7 @@ export function hideToolbox(force: boolean = false): Function { dispatch( setToolboxTimeout( () => dispatch(hideToolbox()), - timeoutMS)); + toolbarTimeout)); } else { dispatch(setToolboxVisible(false)); } @@ -128,9 +127,13 @@ export function showToolbox(timeout: number = 0): Object { return (dispatch: Dispatch, getState: Function) => { const state = getState(); const { - alwaysVisible, + toolbarConfig: { initialTimeout, alwaysVisible }, + toolbarConfig + } = state['features/base/config']; + const toolbarTimeout = getToolbarTimeout(state); + + const { enabled, - timeoutMS, visible, overflowDrawer } = state['features/toolbox']; @@ -143,11 +146,17 @@ export function showToolbox(timeout: number = 0): Object { // If the Toolbox is always visible, there's no need for a timeout // to toggle its visibility. if (!alwaysVisible) { + if (typeof initialTimeout === 'number') { + // reset `initialTimeout` once it is consumed once + dispatch(overwriteConfig({ toolbarConfig: { + ...toolbarConfig, + initialTimeout: null + } })); + } dispatch( setToolboxTimeout( () => dispatch(hideToolbox()), - timeout || timeoutMS)); - dispatch(setToolboxTimeoutMS(interfaceConfig.TOOLBAR_TIMEOUT)); + timeout || initialTimeout || toolbarTimeout)); } } }; @@ -250,18 +259,3 @@ export function setToolboxTimeout(handler: Function, timeoutMS: number): Object }; } -/** - * Dispatches an action which sets new toolbox timeout value. - * - * @param {number} timeoutMS - Delay. - * @returns {{ - * type: SET_TOOLBOX_TIMEOUT_MS, - * timeoutMS: number - * }} - */ -export function setToolboxTimeoutMS(timeoutMS: number): Object { - return { - type: SET_TOOLBOX_TIMEOUT_MS, - timeoutMS - }; -} diff --git a/react/features/toolbox/constants.js b/react/features/toolbox/constants.js index 7ef06c6b3..5a58bcd8f 100644 --- a/react/features/toolbox/constants.js +++ b/react/features/toolbox/constants.js @@ -29,3 +29,5 @@ export const THRESHOLDS = [ ]; export const NOT_APPLICABLE = 'N/A'; + +export const TOOLBAR_TIMEOUT = 4000; diff --git a/react/features/toolbox/functions.native.js b/react/features/toolbox/functions.native.js index 194ec89f9..50f8619c6 100644 --- a/react/features/toolbox/functions.native.js +++ b/react/features/toolbox/functions.native.js @@ -60,12 +60,14 @@ export function getMovableButtons(width: number): Set { */ export function isToolboxVisible(stateful: Object | Function) { const state = toState(stateful); - const { alwaysVisible, enabled, visible } = state['features/toolbox']; + const { toolbarConfig: { alwaysVisible } } = state['features/base/config']; + const { enabled, visible } = state['features/toolbox']; const participantCount = getParticipantCountWithFake(state); const alwaysVisibleFlag = getFeatureFlag(state, TOOLBOX_ALWAYS_VISIBLE, false); const enabledFlag = getFeatureFlag(state, TOOLBOX_ENABLED, true); - return enabledFlag && enabled && (alwaysVisible || visible || participantCount === 1 || alwaysVisibleFlag); + return enabledFlag && enabled + && (alwaysVisible || visible || participantCount === 1 || alwaysVisibleFlag); } /** diff --git a/react/features/toolbox/functions.web.js b/react/features/toolbox/functions.web.js index 23b5961c1..81c20c77c 100644 --- a/react/features/toolbox/functions.web.js +++ b/react/features/toolbox/functions.web.js @@ -3,6 +3,8 @@ import { getToolbarButtons } from '../base/config'; import { hasAvailableDevices } from '../base/devices'; +import { TOOLBAR_TIMEOUT } from './constants'; + /** * Helper for getting the height of the toolbox. * @@ -37,9 +39,8 @@ export function isButtonEnabled(name: string, state: Object) { * otherwise. */ export function isToolboxVisible(state: Object) { - const { iAmSipGateway } = state['features/base/config']; + const { iAmSipGateway, toolbarConfig: { alwaysVisible } } = state['features/base/config']; const { - alwaysVisible, timeoutID, visible } = state['features/toolbox']; @@ -101,3 +102,15 @@ export function showOverflowDrawer(state: Object) { export function isToolboxEnabled(state: Object) { return state['features/toolbox'].enabled; } + +/** + * Returns the toolbar timeout from config or the default value. + * + * @param {Object} state - The state from the Redux store. + * @returns {number} - Toolbar timeout in miliseconds. + */ +export function getToolbarTimeout(state: Object) { + const { toolbarConfig: { timeout } } = state['features/base/config']; + + return timeout || TOOLBAR_TIMEOUT; +} diff --git a/react/features/toolbox/reducer.js b/react/features/toolbox/reducer.js index a7740554d..d7641824a 100644 --- a/react/features/toolbox/reducer.js +++ b/react/features/toolbox/reducer.js @@ -8,121 +8,66 @@ import { SET_OVERFLOW_DRAWER, SET_OVERFLOW_MENU_VISIBLE, SET_TOOLBAR_HOVERED, - SET_TOOLBOX_ALWAYS_VISIBLE, SET_TOOLBOX_ENABLED, SET_TOOLBOX_TIMEOUT, - SET_TOOLBOX_TIMEOUT_MS, SET_TOOLBOX_VISIBLE, TOGGLE_TOOLBOX_VISIBLE } from './actionTypes'; -declare var interfaceConfig: Object; - /** - * Returns initial state for toolbox's part of Redux store. - * - * @private - * @returns {{ - * alwaysVisible: boolean, - * enabled: boolean, - * hovered: boolean, - * overflowDrawer: boolean, - * overflowMenuVisible: boolean, - * timeoutID: number, - * timeoutMS: number, - * visible: boolean - * }} + * Initial state of toolbox's part of Redux store. */ -function _getInitialState() { - // Does the toolbar eventually fade out, or is it always visible? - let alwaysVisible = false; +const INITIAL_STATE = { - // Toolbar (initial) visibility. - let visible = false; + /** + * The indicator which determines whether the Toolbox is enabled. + * + * @type {boolean} + */ + enabled: true, - // Default toolbox timeout for mobile app. - let timeoutMS = 5000; + /** + * The indicator which determines whether a Toolbar in the Toolbox is + * hovered. + * + * @type {boolean} + */ + hovered: false, - if (typeof interfaceConfig !== 'undefined') { - if (interfaceConfig.INITIAL_TOOLBAR_TIMEOUT) { - timeoutMS = interfaceConfig.INITIAL_TOOLBAR_TIMEOUT; - } - if (typeof interfaceConfig.TOOLBAR_ALWAYS_VISIBLE !== 'undefined') { - alwaysVisible = interfaceConfig.TOOLBAR_ALWAYS_VISIBLE; - } - } + /** + * The indicator which determines whether the overflow menu(s) are to be displayed as drawers. + * + * @type {boolean} + */ + overflowDrawer: false, - // When the toolbar is always visible, it must initially be visible too. - if (alwaysVisible === true) { - visible = true; - } + /** + * The indicator which determines whether the OverflowMenu is visible. + * + * @type {boolean} + */ + overflowMenuVisible: false, - return { - /** - * The indicator which determines whether the Toolbox should always be - * visible. When false, the toolbar will fade out after timeoutMS. - * - * @type {boolean} - */ - alwaysVisible, + /** + * A number, non-zero value which identifies the timer created by a call + * to setTimeout(). + * + * @type {number|null} + */ + timeoutID: null, - /** - * The indicator which determines whether the Toolbox is enabled. - * - * @type {boolean} - */ - enabled: true, - /** - * The indicator which determines whether a Toolbar in the Toolbox is - * hovered. - * - * @type {boolean} - */ - hovered: false, - - /** - * The indicator which determines whether the overflow menu(s) are to be displayed as drawers. - * - * @type {boolean} - */ - overflowDrawer: false, - - /** - * The indicator which determines whether the OverflowMenu is visible. - * - * @type {boolean} - */ - overflowMenuVisible: false, - - /** - * A number, non-zero value which identifies the timer created by a call - * to setTimeout() with timeoutMS. - * - * @type {number|null} - */ - timeoutID: null, - - /** - * The delay in milliseconds before timeoutID executes (after its - * initialization). - * - * @type {number} - */ - timeoutMS, - - /** - * The indicator that determines whether the Toolbox is visible. - * - * @type {boolean} - */ - visible - }; -} + /** + * The indicator that determines whether the Toolbox is visible. + * + * @type {boolean} + */ + visible: false +}; ReducerRegistry.register( 'features/toolbox', - (state: Object = _getInitialState(), action: Object) => { + (state: Object = INITIAL_STATE, action: Object) => { switch (action.type) { case CLEAR_TOOLBOX_TIMEOUT: return { @@ -154,13 +99,6 @@ ReducerRegistry.register( hovered: action.hovered }; - case SET_TOOLBOX_ALWAYS_VISIBLE: - return { - ...state, - alwaysVisible: action.alwaysVisible, - visible: action.alwaysVisible === true ? true : state.visible - }; - case SET_TOOLBOX_ENABLED: return { ...state, @@ -170,21 +108,14 @@ ReducerRegistry.register( case SET_TOOLBOX_TIMEOUT: return { ...state, - timeoutID: action.timeoutID, - timeoutMS: action.timeoutMS - }; - - case SET_TOOLBOX_TIMEOUT_MS: - return { - ...state, - timeoutMS: action.timeoutMS + timeoutID: action.timeoutID }; case SET_TOOLBOX_VISIBLE: - return set(state, 'visible', state.alwaysVisible || action.visible); + return set(state, 'visible', action.visible); case TOGGLE_TOOLBOX_VISIBLE: - return set(state, 'visible', state.alwaysVisible || !state.visible); + return set(state, 'visible', !state.visible); } return state;