選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

functions.web.ts 8.5KB

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