您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

functions.web.ts 8.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. import { IReduxState } from '../app/types';
  2. import { hasAvailableDevices } from '../base/devices/functions.web';
  3. import { MEET_FEATURES } from '../base/jwt/constants';
  4. import { isJwtFeatureEnabled } from '../base/jwt/functions';
  5. import { IGUMPendingState } from '../base/media/types';
  6. import { isScreenMediaShared } from '../screen-share/functions';
  7. import { isWhiteboardVisible } from '../whiteboard/functions';
  8. import { MAIN_TOOLBAR_BUTTONS_PRIORITY, TOOLBAR_TIMEOUT } from './constants';
  9. import { isButtonEnabled } from './functions.any';
  10. import { IGetVisibleButtonsParams, IToolboxButton, NOTIFY_CLICK_MODE } from './types';
  11. export * from './functions.any';
  12. /**
  13. * Helper for getting the height of the toolbox.
  14. *
  15. * @returns {number} The height of the toolbox.
  16. */
  17. export function getToolboxHeight() {
  18. const toolbox = document.getElementById('new-toolbox');
  19. return toolbox?.clientHeight || 0;
  20. }
  21. /**
  22. * Indicates if the toolbox is visible or not.
  23. *
  24. * @param {IReduxState} state - The state from the Redux store.
  25. * @returns {boolean} - True to indicate that the toolbox is visible, false -
  26. * otherwise.
  27. */
  28. export function isToolboxVisible(state: IReduxState) {
  29. const { iAmRecorder, iAmSipGateway, toolbarConfig } = state['features/base/config'];
  30. const { alwaysVisible } = toolbarConfig || {};
  31. const {
  32. timeoutID,
  33. visible
  34. } = state['features/toolbox'];
  35. const { audioSettingsVisible, videoSettingsVisible } = state['features/settings'];
  36. const whiteboardVisible = isWhiteboardVisible(state);
  37. return Boolean(!iAmRecorder && !iAmSipGateway
  38. && (
  39. timeoutID
  40. || visible
  41. || alwaysVisible
  42. || audioSettingsVisible
  43. || videoSettingsVisible
  44. || whiteboardVisible
  45. ));
  46. }
  47. /**
  48. * Indicates if the audio settings button is disabled or not.
  49. *
  50. * @param {IReduxState} state - The state from the Redux store.
  51. * @returns {boolean}
  52. */
  53. export function isAudioSettingsButtonDisabled(state: IReduxState) {
  54. return !(hasAvailableDevices(state, 'audioInput')
  55. || hasAvailableDevices(state, 'audioOutput'))
  56. || state['features/base/config'].startSilent;
  57. }
  58. /**
  59. * Indicates if the desktop share button is disabled or not.
  60. *
  61. * @param {IReduxState} state - The state from the Redux store.
  62. * @returns {boolean}
  63. */
  64. export function isDesktopShareButtonDisabled(state: IReduxState) {
  65. const { muted, unmuteBlocked } = state['features/base/media'].video;
  66. const videoOrShareInProgress = !muted || isScreenMediaShared(state);
  67. const enabledInJwt = isJwtFeatureEnabled(state, MEET_FEATURES.SCREEN_SHARING, true);
  68. return !enabledInJwt || (unmuteBlocked && !videoOrShareInProgress);
  69. }
  70. /**
  71. * Indicates if the video settings button is disabled or not.
  72. *
  73. * @param {IReduxState} state - The state from the Redux store.
  74. * @returns {boolean}
  75. */
  76. export function isVideoSettingsButtonDisabled(state: IReduxState) {
  77. return !hasAvailableDevices(state, 'videoInput');
  78. }
  79. /**
  80. * Indicates if the video mute button is disabled or not.
  81. *
  82. * @param {IReduxState} state - The state from the Redux store.
  83. * @returns {boolean}
  84. */
  85. export function isVideoMuteButtonDisabled(state: IReduxState) {
  86. const { muted, unmuteBlocked, gumPending } = state['features/base/media'].video;
  87. return !hasAvailableDevices(state, 'videoInput')
  88. || (unmuteBlocked && Boolean(muted))
  89. || gumPending !== IGUMPendingState.NONE;
  90. }
  91. /**
  92. * If an overflow drawer should be displayed or not.
  93. * This is usually done for mobile devices or on narrow screens.
  94. *
  95. * @param {IReduxState} state - The state from the Redux store.
  96. * @returns {boolean}
  97. */
  98. export function showOverflowDrawer(state: IReduxState) {
  99. return state['features/toolbox'].overflowDrawer;
  100. }
  101. /**
  102. * Returns the toolbar timeout from config or the default value.
  103. *
  104. * @param {IReduxState} state - The state from the Redux store.
  105. * @returns {number} - Toolbar timeout in milliseconds.
  106. */
  107. export function getToolbarTimeout(state: IReduxState) {
  108. const { toolbarConfig } = state['features/base/config'];
  109. return toolbarConfig?.timeout || TOOLBAR_TIMEOUT;
  110. }
  111. /**
  112. * Sets the notify click mode for the buttons.
  113. *
  114. * @param {Object} buttons - The list of toolbar buttons.
  115. * @param {Map} buttonsWithNotifyClick - The buttons notify click configuration.
  116. * @returns {void}
  117. */
  118. function setButtonsNotifyClickMode(buttons: Object, buttonsWithNotifyClick: Map<string, NOTIFY_CLICK_MODE>) {
  119. if (typeof APP === 'undefined' || (buttonsWithNotifyClick?.size ?? 0) <= 0) {
  120. return;
  121. }
  122. Object.values(buttons).forEach((button: any) => {
  123. if (typeof button === 'object') {
  124. button.notifyMode = buttonsWithNotifyClick.get(button.key);
  125. }
  126. });
  127. }
  128. /**
  129. * Returns all buttons that need to be rendered.
  130. *
  131. * @param {IGetVisibleButtonsParams} params - The parameters needed to extract the visible buttons.
  132. * @returns {Object} - The visible buttons arrays .
  133. */
  134. export function getVisibleButtons({
  135. allButtons,
  136. buttonsWithNotifyClick,
  137. toolbarButtons,
  138. clientWidth,
  139. jwtDisabledButtons,
  140. mainToolbarButtonsThresholds
  141. }: IGetVisibleButtonsParams) {
  142. setButtonsNotifyClickMode(allButtons, buttonsWithNotifyClick);
  143. const filteredButtons = Object.keys(allButtons).filter(key =>
  144. typeof key !== 'undefined' // filter invalid buttons that may be coming from config.mainToolbarButtons
  145. // override
  146. && !jwtDisabledButtons.includes(key)
  147. && isButtonEnabled(key, toolbarButtons));
  148. const { order } = mainToolbarButtonsThresholds.find(({ width }) => clientWidth > width)
  149. || mainToolbarButtonsThresholds[mainToolbarButtonsThresholds.length - 1];
  150. const mainToolbarButtonKeysOrder = [
  151. ...order.filter(key => filteredButtons.includes(key)),
  152. ...MAIN_TOOLBAR_BUTTONS_PRIORITY.filter(key => !order.includes(key) && filteredButtons.includes(key)),
  153. ...filteredButtons.filter(key => !order.includes(key) && !MAIN_TOOLBAR_BUTTONS_PRIORITY.includes(key))
  154. ];
  155. const mainButtonsKeys = mainToolbarButtonKeysOrder.slice(0, order.length);
  156. const overflowMenuButtons = filteredButtons.reduce((acc, key) => {
  157. if (!mainButtonsKeys.includes(key)) {
  158. acc.push(allButtons[key]);
  159. }
  160. return acc;
  161. }, [] as IToolboxButton[]);
  162. // if we have 1 button in the overflow menu it is better to directly display it in the main toolbar by replacing
  163. // the "More" menu button with it.
  164. if (overflowMenuButtons.length === 1) {
  165. const button = overflowMenuButtons.shift()?.key;
  166. button && mainButtonsKeys.push(button);
  167. }
  168. const mainMenuButtons = mainButtonsKeys.map(key => allButtons[key]);
  169. return {
  170. mainMenuButtons,
  171. overflowMenuButtons
  172. };
  173. }
  174. /**
  175. * Returns the list of participant menu buttons that have that notify the api when clicked.
  176. *
  177. * @param {Object} state - The redux state.
  178. * @returns {Map<string, NOTIFY_CLICK_MODE>} - The list of participant menu buttons.
  179. */
  180. export function getParticipantMenuButtonsWithNotifyClick(state: IReduxState): Map<string, NOTIFY_CLICK_MODE> {
  181. return state['features/toolbox'].participantMenuButtonsWithNotifyClick;
  182. }
  183. interface ICSSTransitionObject {
  184. delay: number;
  185. duration: number;
  186. easingFunction: string;
  187. }
  188. /**
  189. * Returns the time, timing function and delay for elements that are position above the toolbar and need to move along
  190. * with the toolbar.
  191. *
  192. * @param {boolean} isToolbarVisible - Whether the toolbar is visible or not.
  193. * @returns {ICSSTransitionObject}
  194. */
  195. export function getTransitionParamsForElementsAboveToolbox(isToolbarVisible: boolean): ICSSTransitionObject {
  196. // The transition time and delay is different to account for the time when the toolbar is about to hide/show but
  197. // the elements don't have to move.
  198. return isToolbarVisible ? {
  199. duration: 0.15,
  200. easingFunction: 'ease-in',
  201. delay: 0.15
  202. } : {
  203. duration: 0.24,
  204. easingFunction: 'ease-in',
  205. delay: 0
  206. };
  207. }
  208. /**
  209. * Converts a given object to a css transition value string.
  210. *
  211. * @param {ICSSTransitionObject} object - The object.
  212. * @returns {string}
  213. */
  214. export function toCSSTransitionValue(object: ICSSTransitionObject) {
  215. const { delay, duration, easingFunction } = object;
  216. return `${duration}s ${easingFunction} ${delay}s`;
  217. }