fix(toolbar) Fix toolbar always visible; refactors

- deprecate `INITIAL_TOOLBAR_TIMEOUT`, `TOOLBAR_ALWAYS_VISIBLE`, `TOOLBAR_TIMEOUT`
This commit is contained in:
hmuresan 2021-09-23 17:39:05 +03:00 committed by Horatiu Muresan
parent e9f3625ffa
commit cd4c940107
12 changed files with 170 additions and 203 deletions

View File

@ -545,6 +545,19 @@ var config = {
// '__end' // '__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 // Toolbar buttons which have their click event exposed through the API on
// `toolbarButtonClicked` event instead of executing the normal click routine. // `toolbarButtonClicked` event instead of executing the normal click routine.
// buttonsWithNotifyClick: [ // buttonsWithNotifyClick: [

View File

@ -97,7 +97,11 @@ var interfaceConfig = {
*/ */
HIDE_INVITE_MORE_HEADER: false, 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', JITSI_WATERMARK_LINK: 'https://jitsi.org',
LANG_DETECTION: true, // Allow i18n to detect the system language LANG_DETECTION: true, // Allow i18n to detect the system language
@ -183,7 +187,10 @@ var interfaceConfig = {
*/ */
SUPPORT_URL: 'https://community.jitsi.org/', SUPPORT_URL: 'https://community.jitsi.org/',
TOOLBAR_ALWAYS_VISIBLE: false, /**
* DEPRECATED! Moved to config.js as `toolbarConfig.alwaysVisible`.
*/
// TOOLBAR_ALWAYS_VISIBLE: false,
/** /**
* DEPRECATED! * DEPRECATED!
@ -191,7 +198,10 @@ var interfaceConfig = {
*/ */
// TOOLBAR_BUTTONS: [], // 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 // Browsers, in addition to those which do not fully support WebRTC, that
// are not supported and should show the unsupported browser page. // are not supported and should show the unsupported browser page.

View File

@ -188,6 +188,7 @@ export default [
'subject', 'subject',
'testing', 'testing',
'toolbarButtons', 'toolbarButtons',
'toolbarConfig',
'useHostPageLocalStorage', 'useHostPageLocalStorage',
'useTurnUdp', 'useTurnUdp',
'videoQuality.persist', 'videoQuality.persist',

View File

@ -227,6 +227,28 @@ function _translateLegacyConfig(oldValue: Object) {
newValue.toolbarButtons = interfaceConfig.TOOLBAR_BUTTONS; 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]); const filteredConferenceInfo = Object.keys(CONFERENCE_HEADER_MAPPING).filter(key => oldValue[key]);
if (filteredConferenceInfo.length) { if (filteredConferenceInfo.length) {

View File

@ -55,16 +55,6 @@ export const SET_OVERFLOW_MENU_VISIBLE = 'SET_OVERFLOW_MENU_VISIBLE';
*/ */
export const SET_TOOLBAR_HOVERED = 'SET_TOOLBAR_HOVERED'; 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. * 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'; 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. * The type of the (redux) action which shows/hides the Toolbox.
* *

View File

@ -1,27 +1,12 @@
// @flow // @flow
import type { Dispatch } from 'redux';
import { import {
SET_TOOLBOX_ALWAYS_VISIBLE,
SET_TOOLBOX_ENABLED, SET_TOOLBOX_ENABLED,
SET_TOOLBOX_VISIBLE SET_TOOLBOX_VISIBLE
} from './actionTypes'; } 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. * Enables/disables the toolbox.
* *
@ -42,14 +27,19 @@ export function setToolboxEnabled(enabled: boolean): Object {
* Shows/hides the toolbox. * Shows/hides the toolbox.
* *
* @param {boolean} visible - True to show the toolbox or false to hide it. * @param {boolean} visible - True to show the toolbox or false to hide it.
* @returns {{ * @returns {Function}
* type: SET_TOOLBOX_VISIBLE,
* visible: boolean
* }}
*/ */
export function setToolboxVisible(visible: boolean): Object { export function setToolboxVisible(visible: boolean): Object {
return { return (dispatch: Dispatch<any>, getState: Function) => {
type: SET_TOOLBOX_VISIBLE, const { toolbarConfig: { alwaysVisible } } = getState()['features/base/config'];
visible
if (!visible && alwaysVisible) {
return;
}
dispatch({
type: SET_TOOLBOX_VISIBLE,
visible
});
}; };
} }

View File

@ -1,5 +1,7 @@
// @flow // @flow
import type { Dispatch } from 'redux';
import { TOGGLE_TOOLBOX_VISIBLE } from './actionTypes'; import { TOGGLE_TOOLBOX_VISIBLE } from './actionTypes';
export * from './actions.any'; export * from './actions.any';
@ -7,12 +9,20 @@ export * from './actions.any';
/** /**
* Action to toggle the toolbox visibility. * Action to toggle the toolbox visibility.
* *
* @returns {{ * @returns {Function}
* type: TOGGLE_TOOLBOX_VISIBLE
* }}
*/ */
export function toggleToolboxVisible() { export function toggleToolboxVisible() {
return { return (dispatch: Dispatch<any>, getState: Function) => {
type: TOGGLE_TOOLBOX_VISIBLE const state = getState();
const { toolbarConfig: { alwaysVisible } } = state['features/base/config'];
const { visible } = state['features/toolbox'];
if (visible && alwaysVisible) {
return;
}
dispatch({
type: TOGGLE_TOOLBOX_VISIBLE
});
}; };
} }

View File

@ -2,6 +2,7 @@
import type { Dispatch } from 'redux'; import type { Dispatch } from 'redux';
import { overwriteConfig } from '../base/config';
import { isLayoutTileView } from '../video-layout'; import { isLayoutTileView } from '../video-layout';
import { import {
@ -11,12 +12,10 @@ import {
SET_OVERFLOW_DRAWER, SET_OVERFLOW_DRAWER,
SET_OVERFLOW_MENU_VISIBLE, SET_OVERFLOW_MENU_VISIBLE,
SET_TOOLBAR_HOVERED, SET_TOOLBAR_HOVERED,
SET_TOOLBOX_TIMEOUT, SET_TOOLBOX_TIMEOUT
SET_TOOLBOX_TIMEOUT_MS
} from './actionTypes'; } from './actionTypes';
import { setToolboxVisible } from './actions.any'; import { setToolboxVisible } from './actions';
import { getToolbarTimeout } from './functions';
declare var interfaceConfig: Object;
export * from './actions.any'; export * from './actions.any';
@ -28,7 +27,9 @@ export * from './actions.any';
*/ */
export function dockToolbox(dock: boolean): Function { export function dockToolbox(dock: boolean): Function {
return (dispatch: Dispatch<any>, getState: Function) => { return (dispatch: Dispatch<any>, getState: Function) => {
const { timeoutMS, visible } = getState()['features/toolbox']; const state = getState();
const { visible } = state['features/toolbox'];
const toolbarTimeout = getToolbarTimeout(state);
if (dock) { if (dock) {
// First make sure the toolbox is shown. // First make sure the toolbox is shown.
@ -39,7 +40,7 @@ export function dockToolbox(dock: boolean): Function {
dispatch( dispatch(
setToolboxTimeout( setToolboxTimeout(
() => dispatch(hideToolbox()), () => dispatch(hideToolbox()),
timeoutMS)); toolbarTimeout));
} else { } else {
dispatch(showToolbox()); dispatch(showToolbox());
} }
@ -73,11 +74,9 @@ export function fullScreenChanged(fullScreen: boolean) {
export function hideToolbox(force: boolean = false): Function { export function hideToolbox(force: boolean = false): Function {
return (dispatch: Dispatch<any>, getState: Function) => { return (dispatch: Dispatch<any>, getState: Function) => {
const state = getState(); const state = getState();
const { const { toolbarConfig: { alwaysVisible } } = state['features/base/config'];
alwaysVisible, const { hovered } = state['features/toolbox'];
hovered, const toolbarTimeout = getToolbarTimeout(state);
timeoutMS
} = state['features/toolbox'];
if (alwaysVisible) { if (alwaysVisible) {
return; return;
@ -95,7 +94,7 @@ export function hideToolbox(force: boolean = false): Function {
dispatch( dispatch(
setToolboxTimeout( setToolboxTimeout(
() => dispatch(hideToolbox()), () => dispatch(hideToolbox()),
timeoutMS)); toolbarTimeout));
} else { } else {
dispatch(setToolboxVisible(false)); dispatch(setToolboxVisible(false));
} }
@ -128,9 +127,13 @@ export function showToolbox(timeout: number = 0): Object {
return (dispatch: Dispatch<any>, getState: Function) => { return (dispatch: Dispatch<any>, getState: Function) => {
const state = getState(); const state = getState();
const { const {
alwaysVisible, toolbarConfig: { initialTimeout, alwaysVisible },
toolbarConfig
} = state['features/base/config'];
const toolbarTimeout = getToolbarTimeout(state);
const {
enabled, enabled,
timeoutMS,
visible, visible,
overflowDrawer overflowDrawer
} = state['features/toolbox']; } = 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 // If the Toolbox is always visible, there's no need for a timeout
// to toggle its visibility. // to toggle its visibility.
if (!alwaysVisible) { if (!alwaysVisible) {
if (typeof initialTimeout === 'number') {
// reset `initialTimeout` once it is consumed once
dispatch(overwriteConfig({ toolbarConfig: {
...toolbarConfig,
initialTimeout: null
} }));
}
dispatch( dispatch(
setToolboxTimeout( setToolboxTimeout(
() => dispatch(hideToolbox()), () => dispatch(hideToolbox()),
timeout || timeoutMS)); timeout || initialTimeout || toolbarTimeout));
dispatch(setToolboxTimeoutMS(interfaceConfig.TOOLBAR_TIMEOUT));
} }
} }
}; };
@ -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
};
}

View File

@ -29,3 +29,5 @@ export const THRESHOLDS = [
]; ];
export const NOT_APPLICABLE = 'N/A'; export const NOT_APPLICABLE = 'N/A';
export const TOOLBAR_TIMEOUT = 4000;

View File

@ -60,12 +60,14 @@ export function getMovableButtons(width: number): Set<string> {
*/ */
export function isToolboxVisible(stateful: Object | Function) { export function isToolboxVisible(stateful: Object | Function) {
const state = toState(stateful); 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 participantCount = getParticipantCountWithFake(state);
const alwaysVisibleFlag = getFeatureFlag(state, TOOLBOX_ALWAYS_VISIBLE, false); const alwaysVisibleFlag = getFeatureFlag(state, TOOLBOX_ALWAYS_VISIBLE, false);
const enabledFlag = getFeatureFlag(state, TOOLBOX_ENABLED, true); const enabledFlag = getFeatureFlag(state, TOOLBOX_ENABLED, true);
return enabledFlag && enabled && (alwaysVisible || visible || participantCount === 1 || alwaysVisibleFlag); return enabledFlag && enabled
&& (alwaysVisible || visible || participantCount === 1 || alwaysVisibleFlag);
} }
/** /**

View File

@ -3,6 +3,8 @@
import { getToolbarButtons } from '../base/config'; import { getToolbarButtons } from '../base/config';
import { hasAvailableDevices } from '../base/devices'; import { hasAvailableDevices } from '../base/devices';
import { TOOLBAR_TIMEOUT } from './constants';
/** /**
* Helper for getting the height of the toolbox. * Helper for getting the height of the toolbox.
* *
@ -37,9 +39,8 @@ export function isButtonEnabled(name: string, state: Object) {
* otherwise. * otherwise.
*/ */
export function isToolboxVisible(state: Object) { export function isToolboxVisible(state: Object) {
const { iAmSipGateway } = state['features/base/config']; const { iAmSipGateway, toolbarConfig: { alwaysVisible } } = state['features/base/config'];
const { const {
alwaysVisible,
timeoutID, timeoutID,
visible visible
} = state['features/toolbox']; } = state['features/toolbox'];
@ -101,3 +102,15 @@ export function showOverflowDrawer(state: Object) {
export function isToolboxEnabled(state: Object) { export function isToolboxEnabled(state: Object) {
return state['features/toolbox'].enabled; 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;
}

View File

@ -8,121 +8,66 @@ import {
SET_OVERFLOW_DRAWER, SET_OVERFLOW_DRAWER,
SET_OVERFLOW_MENU_VISIBLE, SET_OVERFLOW_MENU_VISIBLE,
SET_TOOLBAR_HOVERED, SET_TOOLBAR_HOVERED,
SET_TOOLBOX_ALWAYS_VISIBLE,
SET_TOOLBOX_ENABLED, SET_TOOLBOX_ENABLED,
SET_TOOLBOX_TIMEOUT, SET_TOOLBOX_TIMEOUT,
SET_TOOLBOX_TIMEOUT_MS,
SET_TOOLBOX_VISIBLE, SET_TOOLBOX_VISIBLE,
TOGGLE_TOOLBOX_VISIBLE TOGGLE_TOOLBOX_VISIBLE
} from './actionTypes'; } from './actionTypes';
declare var interfaceConfig: Object;
/** /**
* Returns initial state for toolbox's part of Redux store. * Initial state of toolbox's part of Redux store.
*
* @private
* @returns {{
* alwaysVisible: boolean,
* enabled: boolean,
* hovered: boolean,
* overflowDrawer: boolean,
* overflowMenuVisible: boolean,
* timeoutID: number,
* timeoutMS: number,
* visible: boolean
* }}
*/ */
function _getInitialState() { const INITIAL_STATE = {
// Does the toolbar eventually fade out, or is it always visible?
let alwaysVisible = false;
// 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) { * The indicator which determines whether the overflow menu(s) are to be displayed as drawers.
timeoutMS = interfaceConfig.INITIAL_TOOLBAR_TIMEOUT; *
} * @type {boolean}
if (typeof interfaceConfig.TOOLBAR_ALWAYS_VISIBLE !== 'undefined') { */
alwaysVisible = interfaceConfig.TOOLBAR_ALWAYS_VISIBLE; overflowDrawer: false,
}
}
// When the toolbar is always visible, it must initially be visible too. /**
if (alwaysVisible === true) { * The indicator which determines whether the OverflowMenu is visible.
visible = true; *
} * @type {boolean}
*/
overflowMenuVisible: false,
return { /**
/** * A number, non-zero value which identifies the timer created by a call
* The indicator which determines whether the Toolbox should always be * to setTimeout().
* visible. When false, the toolbar will fade out after timeoutMS. *
* * @type {number|null}
* @type {boolean} */
*/ timeoutID: null,
alwaysVisible,
/**
* The indicator which determines whether the Toolbox is enabled.
*
* @type {boolean}
*/
enabled: true,
/** /**
* The indicator which determines whether a Toolbar in the Toolbox is * The indicator that determines whether the Toolbox is visible.
* hovered. *
* * @type {boolean}
* @type {boolean} */
*/ visible: false
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
};
}
ReducerRegistry.register( ReducerRegistry.register(
'features/toolbox', 'features/toolbox',
(state: Object = _getInitialState(), action: Object) => { (state: Object = INITIAL_STATE, action: Object) => {
switch (action.type) { switch (action.type) {
case CLEAR_TOOLBOX_TIMEOUT: case CLEAR_TOOLBOX_TIMEOUT:
return { return {
@ -154,13 +99,6 @@ ReducerRegistry.register(
hovered: action.hovered hovered: action.hovered
}; };
case SET_TOOLBOX_ALWAYS_VISIBLE:
return {
...state,
alwaysVisible: action.alwaysVisible,
visible: action.alwaysVisible === true ? true : state.visible
};
case SET_TOOLBOX_ENABLED: case SET_TOOLBOX_ENABLED:
return { return {
...state, ...state,
@ -170,21 +108,14 @@ ReducerRegistry.register(
case SET_TOOLBOX_TIMEOUT: case SET_TOOLBOX_TIMEOUT:
return { return {
...state, ...state,
timeoutID: action.timeoutID, timeoutID: action.timeoutID
timeoutMS: action.timeoutMS
};
case SET_TOOLBOX_TIMEOUT_MS:
return {
...state,
timeoutMS: action.timeoutMS
}; };
case SET_TOOLBOX_VISIBLE: case SET_TOOLBOX_VISIBLE:
return set(state, 'visible', state.alwaysVisible || action.visible); return set(state, 'visible', action.visible);
case TOGGLE_TOOLBOX_VISIBLE: case TOGGLE_TOOLBOX_VISIBLE:
return set(state, 'visible', state.alwaysVisible || !state.visible); return set(state, 'visible', !state.visible);
} }
return state; return state;