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.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. // @flow
  2. import { isNameReadOnly } from '../base/config';
  3. import { SERVER_URL_CHANGE_ENABLED, getFeatureFlag } from '../base/flags';
  4. import { i18next, DEFAULT_LANGUAGE, LANGUAGES } from '../base/i18n';
  5. import { createLocalTrack } from '../base/lib-jitsi-meet/functions';
  6. import {
  7. getLocalParticipant,
  8. isLocalParticipantModerator
  9. } from '../base/participants';
  10. import { toState } from '../base/redux';
  11. import { parseStandardURIString } from '../base/util';
  12. import { isFollowMeActive } from '../follow-me';
  13. import { isReactionsEnabled } from '../reactions/functions.any';
  14. import { SS_DEFAULT_FRAME_RATE, SS_SUPPORTED_FRAMERATES } from './constants';
  15. declare var interfaceConfig: Object;
  16. /**
  17. * Used for web. Indicates if the setting section is enabled.
  18. *
  19. * @param {string} settingName - The name of the setting section as defined in
  20. * interface_config.js and SettingsMenu.js.
  21. * @returns {boolean} True to indicate that the given setting section
  22. * is enabled, false otherwise.
  23. */
  24. export function isSettingEnabled(settingName: string) {
  25. return interfaceConfig.SETTINGS_SECTIONS.includes(settingName);
  26. }
  27. /**
  28. * Returns true if user is allowed to change Server URL.
  29. *
  30. * @param {(Function|Object)} stateful - The (whole) redux state, or redux's
  31. * {@code getState} function to be used to retrieve the state.
  32. * @returns {boolean} True to indicate that user can change Server URL, false otherwise.
  33. */
  34. export function isServerURLChangeEnabled(stateful: Object | Function) {
  35. const state = toState(stateful);
  36. const flag = getFeatureFlag(state, SERVER_URL_CHANGE_ENABLED, true);
  37. return flag;
  38. }
  39. /**
  40. * Normalizes a URL entered by the user.
  41. * FIXME: Consider adding this to base/util/uri.
  42. *
  43. * @param {string} url - The URL to validate.
  44. * @returns {string|null} - The normalized URL, or null if the URL is invalid.
  45. */
  46. export function normalizeUserInputURL(url: string) {
  47. /* eslint-disable no-param-reassign */
  48. if (url) {
  49. url = url.replace(/\s/g, '').toLowerCase();
  50. const urlRegExp = new RegExp('^(\\w+://)?(.+)$');
  51. const urlComponents = urlRegExp.exec(url);
  52. if (urlComponents && (!urlComponents[1]
  53. || !urlComponents[1].startsWith('http'))) {
  54. url = `https://${urlComponents[2]}`;
  55. }
  56. const parsedURI = parseStandardURIString(url);
  57. if (!parsedURI.host) {
  58. return null;
  59. }
  60. return parsedURI.toString();
  61. }
  62. return url;
  63. /* eslint-enable no-param-reassign */
  64. }
  65. /**
  66. * Returns the properties for the "More" tab from settings dialog from Redux
  67. * state.
  68. *
  69. * @param {(Function|Object)} stateful -The (whole) redux state, or redux's
  70. * {@code getState} function to be used to retrieve the state.
  71. * @returns {Object} - The properties for the "More" tab from settings dialog.
  72. */
  73. export function getMoreTabProps(stateful: Object | Function) {
  74. const state = toState(stateful);
  75. const framerate = state['features/screen-share'].captureFrameRate ?? SS_DEFAULT_FRAME_RATE;
  76. const language = i18next.language || DEFAULT_LANGUAGE;
  77. const configuredTabs = interfaceConfig.SETTINGS_SECTIONS || [];
  78. return {
  79. currentFramerate: framerate,
  80. currentLanguage: language,
  81. desktopShareFramerates: SS_SUPPORTED_FRAMERATES,
  82. languages: LANGUAGES,
  83. showLanguageSettings: configuredTabs.includes('language'),
  84. showPrejoinPage: !state['features/base/settings'].userSelectedSkipPrejoin,
  85. showPrejoinSettings: state['features/base/config'].prejoinPageEnabled
  86. };
  87. }
  88. /**
  89. * Returns the properties for the "More" tab from settings dialog from Redux
  90. * state.
  91. *
  92. * @param {(Function|Object)} stateful -The (whole) redux state, or redux's
  93. * {@code getState} function to be used to retrieve the state.
  94. * @returns {Object} - The properties for the "More" tab from settings dialog.
  95. */
  96. export function getModeratorTabProps(stateful: Object | Function) {
  97. const state = toState(stateful);
  98. const {
  99. conference,
  100. followMeEnabled,
  101. startAudioMutedPolicy,
  102. startVideoMutedPolicy,
  103. startReactionsMuted
  104. } = state['features/base/conference'];
  105. const followMeActive = isFollowMeActive(state);
  106. const configuredTabs = interfaceConfig.SETTINGS_SECTIONS || [];
  107. const showModeratorSettings = Boolean(
  108. conference
  109. && configuredTabs.includes('moderator')
  110. && isLocalParticipantModerator(state));
  111. // The settings sections to display.
  112. return {
  113. showModeratorSettings,
  114. followMeActive: Boolean(conference && followMeActive),
  115. followMeEnabled: Boolean(conference && followMeEnabled),
  116. startReactionsMuted: Boolean(conference && startReactionsMuted),
  117. startAudioMuted: Boolean(conference && startAudioMutedPolicy),
  118. startVideoMuted: Boolean(conference && startVideoMutedPolicy)
  119. };
  120. }
  121. /**
  122. * Returns the properties for the "Profile" tab from settings dialog from Redux
  123. * state.
  124. *
  125. * @param {(Function|Object)} stateful -The (whole) redux state, or redux's
  126. * {@code getState} function to be used to retrieve the state.
  127. * @returns {Object} - The properties for the "Profile" tab from settings
  128. * dialog.
  129. */
  130. export function getProfileTabProps(stateful: Object | Function) {
  131. const state = toState(stateful);
  132. const {
  133. authEnabled,
  134. authLogin,
  135. conference
  136. } = state['features/base/conference'];
  137. const localParticipant = getLocalParticipant(state);
  138. return {
  139. authEnabled: Boolean(conference && authEnabled),
  140. authLogin,
  141. displayName: localParticipant.name,
  142. email: localParticipant.email,
  143. readOnlyName: isNameReadOnly(state)
  144. };
  145. }
  146. /**
  147. * Returns the properties for the "Sounds" tab from settings dialog from Redux
  148. * state.
  149. *
  150. * @param {(Function|Object)} stateful -The (whole) redux state, or redux's
  151. * {@code getState} function to be used to retrieve the state.
  152. * @returns {Object} - The properties for the "Sounds" tab from settings
  153. * dialog.
  154. */
  155. export function getSoundsTabProps(stateful: Object | Function) {
  156. const state = toState(stateful);
  157. const {
  158. soundsIncomingMessage,
  159. soundsParticipantJoined,
  160. soundsParticipantLeft,
  161. soundsTalkWhileMuted,
  162. soundsReactions
  163. } = state['features/base/settings'];
  164. const enableReactions = isReactionsEnabled(state);
  165. const moderatorMutedSoundsReactions = state['features/base/conference'].startReactionsMuted ?? false;
  166. return {
  167. soundsIncomingMessage,
  168. soundsParticipantJoined,
  169. soundsParticipantLeft,
  170. soundsTalkWhileMuted,
  171. soundsReactions,
  172. enableReactions,
  173. moderatorMutedSoundsReactions
  174. };
  175. }
  176. /**
  177. * Returns a promise which resolves with a list of objects containing
  178. * all the video jitsiTracks and appropriate errors for the given device ids.
  179. *
  180. * @param {string[]} ids - The list of the camera ids for which to create tracks.
  181. * @param {number} [timeout] - A timeout for the createLocalTrack function call.
  182. *
  183. * @returns {Promise<Object[]>}
  184. */
  185. export function createLocalVideoTracks(ids: string[], timeout: ?number) {
  186. return Promise.all(ids.map(deviceId => createLocalTrack('video', deviceId, timeout)
  187. .then(jitsiTrack => {
  188. return {
  189. jitsiTrack,
  190. deviceId
  191. };
  192. })
  193. .catch(() => {
  194. return {
  195. jitsiTrack: null,
  196. deviceId,
  197. error: 'deviceSelection.previewUnavailable'
  198. };
  199. })));
  200. }
  201. /**
  202. * Returns a promise which resolves with a list of objects containing
  203. * the audio track and the corresponding audio device information.
  204. *
  205. * @param {Object[]} devices - A list of microphone devices.
  206. * @param {number} [timeout] - A timeout for the createLocalTrack function call.
  207. * @returns {Promise<{
  208. * deviceId: string,
  209. * hasError: boolean,
  210. * jitsiTrack: Object,
  211. * label: string
  212. * }[]>}
  213. */
  214. export function createLocalAudioTracks(devices: Object[], timeout: ?number) {
  215. return Promise.all(
  216. devices.map(async ({ deviceId, label }) => {
  217. let jitsiTrack = null;
  218. let hasError = false;
  219. try {
  220. jitsiTrack = await createLocalTrack('audio', deviceId, timeout);
  221. } catch (err) {
  222. hasError = true;
  223. }
  224. return {
  225. deviceId,
  226. hasError,
  227. jitsiTrack,
  228. label
  229. };
  230. }));
  231. }
  232. /**
  233. * Returns the visibility state of the audio settings.
  234. *
  235. * @param {Object} state - The state of the application.
  236. * @returns {boolean}
  237. */
  238. export function getAudioSettingsVisibility(state: Object) {
  239. return state['features/settings'].audioSettingsVisible;
  240. }
  241. /**
  242. * Returns the visibility state of the video settings.
  243. *
  244. * @param {Object} state - The state of the application.
  245. * @returns {boolean}
  246. */
  247. export function getVideoSettingsVisibility(state: Object) {
  248. return state['features/settings'].videoSettingsVisible;
  249. }