You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

functions.any.ts 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. // @ts-expect-error
  2. import keyboardShortcut from '../../../modules/keyboardshortcut/keyboardshortcut';
  3. import { IReduxState } from '../app/types';
  4. import { IStateful } from '../base/app/types';
  5. import { isNameReadOnly } from '../base/config/functions';
  6. import { SERVER_URL_CHANGE_ENABLED } from '../base/flags/constants';
  7. import { getFeatureFlag } from '../base/flags/functions';
  8. import i18next, { DEFAULT_LANGUAGE, LANGUAGES } from '../base/i18n/i18next';
  9. import {
  10. getLocalParticipant,
  11. isLocalParticipantModerator
  12. } from '../base/participants/functions';
  13. import { toState } from '../base/redux/functions';
  14. import { getHideSelfView } from '../base/settings/functions';
  15. import { parseStandardURIString } from '../base/util/uri';
  16. import { isStageFilmstripEnabled } from '../filmstrip/functions';
  17. import { isFollowMeActive } from '../follow-me/functions';
  18. import { getParticipantsPaneConfig } from '../participants-pane/functions';
  19. import { isPrejoinPageVisible } from '../prejoin/functions';
  20. import { isReactionsEnabled } from '../reactions/functions.any';
  21. /**
  22. * Used for web. Indicates if the setting section is enabled.
  23. *
  24. * @param {string} settingName - The name of the setting section as defined in
  25. * interface_config.js and SettingsMenu.js.
  26. * @returns {boolean} True to indicate that the given setting section
  27. * is enabled, false otherwise.
  28. */
  29. export function isSettingEnabled(settingName: string) {
  30. return interfaceConfig.SETTINGS_SECTIONS.includes(settingName);
  31. }
  32. /**
  33. * Returns true if user is allowed to change Server URL.
  34. *
  35. * @param {(Function|Object)} stateful - The (whole) redux state, or redux's
  36. * {@code getState} function to be used to retrieve the state.
  37. * @returns {boolean} True to indicate that user can change Server URL, false otherwise.
  38. */
  39. export function isServerURLChangeEnabled(stateful: IStateful) {
  40. const state = toState(stateful);
  41. const flag = getFeatureFlag(state, SERVER_URL_CHANGE_ENABLED, true);
  42. return flag;
  43. }
  44. /**
  45. * Normalizes a URL entered by the user.
  46. * FIXME: Consider adding this to base/util/uri.
  47. *
  48. * @param {string} url - The URL to validate.
  49. * @returns {string|null} - The normalized URL, or null if the URL is invalid.
  50. */
  51. export function normalizeUserInputURL(url: string) {
  52. /* eslint-disable no-param-reassign */
  53. if (url) {
  54. url = url.replace(/\s/g, '').toLowerCase();
  55. const urlRegExp = new RegExp('^(\\w+://)?(.+)$');
  56. const urlComponents = urlRegExp.exec(url);
  57. if (urlComponents && (!urlComponents[1]
  58. || !urlComponents[1].startsWith('http'))) {
  59. url = `https://${urlComponents[2]}`;
  60. }
  61. const parsedURI = parseStandardURIString(url);
  62. if (!parsedURI.host) {
  63. return null;
  64. }
  65. return parsedURI.toString();
  66. }
  67. return url;
  68. /* eslint-enable no-param-reassign */
  69. }
  70. /**
  71. * Returns the notification types and their user selected configuration.
  72. *
  73. * @param {(Function|Object)} stateful -The (whole) redux state, or redux's
  74. * {@code getState} function to be used to retrieve the state.
  75. * @returns {Object} - The section of notifications to be configured.
  76. */
  77. export function getNotificationsMap(stateful: IStateful) {
  78. const state = toState(stateful);
  79. const { notifications } = state['features/base/config'];
  80. const { userSelectedNotifications } = state['features/base/settings'];
  81. if (!userSelectedNotifications) {
  82. return {};
  83. }
  84. return Object.keys(userSelectedNotifications)
  85. .filter(key => !notifications || notifications.includes(key))
  86. .reduce((notificationsMap, key) => {
  87. return {
  88. ...notificationsMap,
  89. [key]: userSelectedNotifications[key]
  90. };
  91. }, {});
  92. }
  93. /**
  94. * Returns the properties for the "More" tab from settings dialog from Redux
  95. * state.
  96. *
  97. * @param {(Function|Object)} stateful -The (whole) redux state, or redux's
  98. * {@code getState} function to be used to retrieve the state.
  99. * @returns {Object} - The properties for the "More" tab from settings dialog.
  100. */
  101. export function getMoreTabProps(stateful: IStateful) {
  102. const state = toState(stateful);
  103. const stageFilmstripEnabled = isStageFilmstripEnabled(state);
  104. return {
  105. showPrejoinPage: !state['features/base/settings'].userSelectedSkipPrejoin,
  106. showPrejoinSettings: state['features/base/config'].prejoinConfig?.enabled,
  107. maxStageParticipants: state['features/base/settings'].maxStageParticipants,
  108. stageFilmstripEnabled
  109. };
  110. }
  111. /**
  112. * Returns the properties for the "More" tab from settings dialog from Redux
  113. * state.
  114. *
  115. * @param {(Function|Object)} stateful -The (whole) redux state, or redux's
  116. * {@code getState} function to be used to retrieve the state.
  117. * @returns {Object} - The properties for the "More" tab from settings dialog.
  118. */
  119. export function getModeratorTabProps(stateful: IStateful) {
  120. const state = toState(stateful);
  121. const {
  122. conference,
  123. followMeEnabled,
  124. startAudioMutedPolicy,
  125. startVideoMutedPolicy,
  126. startReactionsMuted
  127. } = state['features/base/conference'];
  128. const { disableReactionsModeration } = state['features/base/config'];
  129. const followMeActive = isFollowMeActive(state);
  130. const showModeratorSettings = shouldShowModeratorSettings(state);
  131. // The settings sections to display.
  132. return {
  133. showModeratorSettings: Boolean(conference && showModeratorSettings),
  134. disableReactionsModeration: Boolean(disableReactionsModeration),
  135. followMeActive: Boolean(conference && followMeActive),
  136. followMeEnabled: Boolean(conference && followMeEnabled),
  137. startReactionsMuted: Boolean(conference && startReactionsMuted),
  138. startAudioMuted: Boolean(conference && startAudioMutedPolicy),
  139. startVideoMuted: Boolean(conference && startVideoMutedPolicy)
  140. };
  141. }
  142. /**
  143. * Returns true if moderator tab in settings should be visible/accessible.
  144. *
  145. * @param {(Function|Object)} stateful - The (whole) redux state, or redux's
  146. * {@code getState} function to be used to retrieve the state.
  147. * @returns {boolean} True to indicate that moderator tab should be visible, false otherwise.
  148. */
  149. export function shouldShowModeratorSettings(stateful: IStateful) {
  150. const state = toState(stateful);
  151. const { hideModeratorSettingsTab } = getParticipantsPaneConfig(state);
  152. const hasModeratorRights = Boolean(isSettingEnabled('moderator') && isLocalParticipantModerator(state));
  153. return hasModeratorRights && !hideModeratorSettingsTab;
  154. }
  155. /**
  156. * Returns the properties for the "Profile" tab from settings dialog from Redux
  157. * state.
  158. *
  159. * @param {(Function|Object)} stateful -The (whole) redux state, or redux's
  160. * {@code getState} function to be used to retrieve the state.
  161. * @returns {Object} - The properties for the "Profile" tab from settings
  162. * dialog.
  163. */
  164. export function getProfileTabProps(stateful: IStateful) {
  165. const state = toState(stateful);
  166. const {
  167. authEnabled,
  168. authLogin,
  169. conference
  170. } = state['features/base/conference'];
  171. const { hideEmailInSettings } = state['features/base/config'];
  172. const localParticipant = getLocalParticipant(state);
  173. const language = i18next.language || DEFAULT_LANGUAGE;
  174. const configuredTabs: string[] = interfaceConfig.SETTINGS_SECTIONS || [];
  175. // when self view is controlled by the config we hide the settings
  176. const { disableSelfView, disableSelfViewSettings } = state['features/base/config'];
  177. return {
  178. authEnabled: Boolean(conference && authEnabled),
  179. authLogin,
  180. disableHideSelfView: disableSelfViewSettings || disableSelfView,
  181. currentLanguage: language,
  182. displayName: localParticipant?.name,
  183. email: localParticipant?.email,
  184. hideEmailInSettings,
  185. hideSelfView: getHideSelfView(state),
  186. id: localParticipant?.id,
  187. languages: LANGUAGES,
  188. readOnlyName: isNameReadOnly(state),
  189. showLanguageSettings: configuredTabs.includes('language')
  190. };
  191. }
  192. /**
  193. * Returns the properties for the "Sounds" tab from settings dialog from Redux
  194. * state.
  195. *
  196. * @param {(Function|Object)} stateful -The (whole) redux state, or redux's
  197. * {@code getState} function to be used to retrieve the state.
  198. * @param {boolean} showSoundsSettings - Whether to show the sound settings or not.
  199. * @returns {Object} - The properties for the "Sounds" tab from settings
  200. * dialog.
  201. */
  202. export function getNotificationsTabProps(stateful: IStateful, showSoundsSettings?: boolean) {
  203. const state = toState(stateful);
  204. const {
  205. soundsIncomingMessage,
  206. soundsParticipantJoined,
  207. soundsParticipantKnocking,
  208. soundsParticipantLeft,
  209. soundsTalkWhileMuted,
  210. soundsReactions
  211. } = state['features/base/settings'];
  212. const enableReactions = isReactionsEnabled(state);
  213. const moderatorMutedSoundsReactions = state['features/base/conference'].startReactionsMuted ?? false;
  214. const enabledNotifications = getNotificationsMap(stateful);
  215. return {
  216. disabledSounds: state['features/base/config'].disabledSounds || [],
  217. enabledNotifications,
  218. showNotificationsSettings: Object.keys(enabledNotifications).length > 0,
  219. soundsIncomingMessage,
  220. soundsParticipantJoined,
  221. soundsParticipantKnocking,
  222. soundsParticipantLeft,
  223. soundsTalkWhileMuted,
  224. soundsReactions,
  225. enableReactions,
  226. moderatorMutedSoundsReactions,
  227. showSoundsSettings
  228. };
  229. }
  230. /**
  231. * Returns the visibility state of the audio settings.
  232. *
  233. * @param {Object} state - The state of the application.
  234. * @returns {boolean}
  235. */
  236. export function getAudioSettingsVisibility(state: IReduxState) {
  237. return state['features/settings'].audioSettingsVisible;
  238. }
  239. /**
  240. * Returns the visibility state of the video settings.
  241. *
  242. * @param {Object} state - The state of the application.
  243. * @returns {boolean}
  244. */
  245. export function getVideoSettingsVisibility(state: IReduxState) {
  246. return state['features/settings'].videoSettingsVisible;
  247. }
  248. /**
  249. * Returns the properties for the "Shortcuts" tab from settings dialog from Redux
  250. * state.
  251. *
  252. * @param {(Function|Object)} stateful -The (whole) redux state, or redux's
  253. * {@code getState} function to be used to retrieve the state.
  254. * @param {boolean} isDisplayedOnWelcomePage - Indicates whether the shortcuts dialog is displayed on the
  255. * welcome page or not.
  256. * @returns {Object} - The properties for the "Shortcuts" tab from settings
  257. * dialog.
  258. */
  259. export function getShortcutsTabProps(stateful: IStateful, isDisplayedOnWelcomePage?: boolean) {
  260. const state = toState(stateful);
  261. return {
  262. displayShortcuts: !isDisplayedOnWelcomePage && !isPrejoinPageVisible(state),
  263. keyboardShortcutsEnabled: keyboardShortcut.getEnabled()
  264. };
  265. }