diff --git a/conference.js b/conference.js index e4e9010c94..01a3a95caf 100644 --- a/conference.js +++ b/conference.js @@ -104,11 +104,8 @@ import { trackAdded, trackRemoved } from './react/features/base/tracks'; -import { - getBackendSafePath, - getJitsiMeetGlobalNS -} from './react/features/base/util'; import { downloadJSON } from './react/features/base/util/downloadJSON'; +import { getConferenceOptions } from './react/features/conference/functions'; import { showDesktopPicker } from './react/features/desktop-picker'; import { appendSuffix } from './react/features/display-name'; import { @@ -124,7 +121,6 @@ import { isPrejoinPageVisible, makePrecallTest } from './react/features/prejoin'; -import { createRnnoiseProcessorPromise } from './react/features/rnnoise'; import { toggleScreenshotCaptureEffect } from './react/features/screenshot-capture'; import { setSharedVideoStatus } from './react/features/shared-video'; import { AudioMixerEffect } from './react/features/stream-effects/audio-mixer/AudioMixerEffect'; @@ -1319,53 +1315,7 @@ export default { }, _getConferenceOptions() { - const options = config; - const { email, name: nick } = getLocalParticipant(APP.store.getState()); - - const state = APP.store.getState(); - const { locationURL } = state['features/base/connection']; - const { tenant } = state['features/base/jwt']; - - if (tenant) { - options.siteID = tenant; - } - - if (options.enableDisplayNameInStats && nick) { - options.statisticsDisplayName = nick; - } - - if (options.enableEmailInStats && email) { - options.statisticsId = email; - } - - options.applicationName = interfaceConfig.APP_NAME; - options.getWiFiStatsMethod = this._getWiFiStatsMethod; - options.confID = `${locationURL.host}${getBackendSafePath(locationURL.pathname)}`; - options.createVADProcessor = createRnnoiseProcessorPromise; - - // Disable CallStats, if requessted. - if (options.disableThirdPartyRequests) { - delete options.callStatsID; - delete options.callStatsSecret; - delete options.getWiFiStatsMethod; - } - - return options; - }, - - /** - * Returns the result of getWiFiStats from the global NS or does nothing - * (returns empty result). - * Fixes a concurrency problem where we need to pass a function when creating - * JitsiConference, but that method is added to the context later. - * - * @returns {Promise} - * @private - */ - _getWiFiStatsMethod() { - const gloabalNS = getJitsiMeetGlobalNS(); - - return gloabalNS.getWiFiStats ? gloabalNS.getWiFiStats() : Promise.resolve('{}'); + return getConferenceOptions(APP.store.getState()); }, /** diff --git a/flow-typed/npm/react-redux_v7.x.x.js b/flow-typed/npm/react-redux_v7.x.x.js index 60f6f2a42f..afb2da710d 100644 --- a/flow-typed/npm/react-redux_v7.x.x.js +++ b/flow-typed/npm/react-redux_v7.x.x.js @@ -1,5 +1,5 @@ -// flow-typed signature: d2ddacbbca9700881249a9435381e689 -// flow-typed version: c6154227d1/react-redux_v7.x.x/flow_>=v0.89.x <=v0.103.x +// flow-typed signature: 8da1e134b3de1d6f6bf9ba1cc7e2dc7e +// flow-typed version: 387a235736/react-redux_v7.x.x/flow_>=v0.104.x /** The order of type arguments for connect() is as follows: @@ -219,6 +219,7 @@ declare module "react-redux" { declare export class Provider extends React$Component<{ store: Store, children?: React$Node, + ... }> {} declare export function createProvider( @@ -237,6 +238,7 @@ declare module "react-redux" { shouldHandleStateChanges?: boolean, storeKey?: string, forwardRef?: boolean, + ... }; declare type SelectorFactoryOptions = { @@ -249,6 +251,7 @@ declare module "react-redux" { displayName: string, wrappedComponentName: string, WrappedComponent: Com, + ... }; declare type MapStateToPropsEx = ( @@ -275,12 +278,14 @@ declare module "react-redux" { OP: Object, CP: Object, EFO: Object, - ST: { [_: $Keys]: any }, + ST: { [_: $Keys]: any, ... }, >( selectorFactory: SelectorFactory, connectAdvancedOptions: ?(ConnectAdvancedOptions & EFO), ): (component: Com) => React$ComponentType & $Shape; + declare export function batch(() => void): void + declare export default { Provider: typeof Provider, createProvider: typeof createProvider, @@ -289,5 +294,7 @@ declare module "react-redux" { useDispatch: typeof useDispatch, useSelector: typeof useSelector, useStore: typeof useStore, + batch: typeof batch, + ... }; } diff --git a/react/features/conference/functions.js b/react/features/conference/functions.js deleted file mode 100644 index 7930c0585c..0000000000 --- a/react/features/conference/functions.js +++ /dev/null @@ -1,51 +0,0 @@ -import { isSuboptimalBrowser } from '../base/environment'; -import { translateToHTML } from '../base/i18n'; -import { toState } from '../base/redux'; -import { - areThereNotifications, - showWarningNotification -} from '../notifications'; -import { getOverlayToRender } from '../overlay'; - -/** - * Shows the suboptimal experience notification if needed. - * - * @param {Function} dispatch - The dispatch method. - * @param {Function} t - The translation function. - * @returns {void} - */ -export function maybeShowSuboptimalExperienceNotification(dispatch, t) { - if (isSuboptimalBrowser()) { - dispatch( - showWarningNotification( - { - titleKey: 'notify.suboptimalExperienceTitle', - description: translateToHTML( - t, - 'notify.suboptimalBrowserWarning', - { - recommendedBrowserPageLink: `${window.location.origin}/static/recommendedBrowsers.html` - } - ) - } - ) - ); - } -} - -/** - * Tells whether or not the notifications should be displayed within - * the conference feature based on the current Redux state. - * - * @param {Object|Function} stateful - The redux store state. - * @returns {boolean} - */ -export function shouldDisplayNotifications(stateful) { - const state = toState(stateful); - const isAnyOverlayVisible = Boolean(getOverlayToRender(state)); - const { calleeInfoVisible } = state['features/invite']; - - return areThereNotifications(state) - && !isAnyOverlayVisible - && !calleeInfoVisible; -} diff --git a/react/features/conference/functions.native.js b/react/features/conference/functions.native.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/react/features/conference/functions.web.js b/react/features/conference/functions.web.js new file mode 100644 index 0000000000..25e3ee45a8 --- /dev/null +++ b/react/features/conference/functions.web.js @@ -0,0 +1,112 @@ +import { getName } from '../app/functions.web'; +import { isSuboptimalBrowser } from '../base/environment'; +import { translateToHTML } from '../base/i18n'; +import { getLocalParticipant } from '../base/participants'; +import { toState } from '../base/redux'; +import { getBackendSafePath, getJitsiMeetGlobalNS } from '../base/util'; +import { + areThereNotifications, + showWarningNotification +} from '../notifications'; +import { getOverlayToRender } from '../overlay'; +import { createRnnoiseProcessorPromise } from '../rnnoise'; + +/** + * Returns the result of getWiFiStats from the global NS or does nothing +(returns empty result). + * Fixes a concurrency problem where we need to pass a function when creating + * a JitsiConference, but that method is added to the context later. + * + * @returns {Promise} + * @private + */ +const getWiFiStatsMethod = () => { + const gloabalNS = getJitsiMeetGlobalNS(); + + return gloabalNS.getWiFiStats ? gloabalNS.getWiFiStats() : Promise.resolve('{}'); +}; + +/** + * Shows the suboptimal experience notification if needed. + * + * @param {Function} dispatch - The dispatch method. + * @param {Function} t - The translation function. + * @returns {void} + */ +export function maybeShowSuboptimalExperienceNotification(dispatch, t) { + if (isSuboptimalBrowser()) { + dispatch( + showWarningNotification( + { + titleKey: 'notify.suboptimalExperienceTitle', + description: translateToHTML( + t, + 'notify.suboptimalBrowserWarning', + { + recommendedBrowserPageLink: `${window.location.origin}/static/recommendedBrowsers.html` + } + ) + } + ) + ); + } +} + +/** + * Tells whether or not the notifications should be displayed within + * the conference feature based on the current Redux state. + * + * @param {Object|Function} stateful - The redux store state. + * @returns {boolean} + */ +export function shouldDisplayNotifications(stateful) { + const state = toState(stateful); + const isAnyOverlayVisible = Boolean(getOverlayToRender(state)); + const { calleeInfoVisible } = state['features/invite']; + + return areThereNotifications(state) + && !isAnyOverlayVisible + && !calleeInfoVisible; +} + +/** + * Returns an object aggregating the conference options. + * + * @param {Object|Function} stateful - The redux store state. + * @returns {Object} - Options object. + */ +export function getConferenceOptions(stateful) { + const state = toState(stateful); + + const options = state['features/base/config']; + const { locationURL } = state['features/base/connection']; + const { tenant } = state['features/base/jwt']; + + const { email, name: nick } = getLocalParticipant(state); + + if (tenant) { + options.siteID = tenant; + } + + if (options.enableDisplayNameInStats && nick) { + options.statisticsDisplayName = nick; + } + + if (options.enableEmailInStats && email) { + options.statisticsId = email; + } + + options.applicationName = getName(); + options.getWiFiStatsMethod = getWiFiStatsMethod; + options.confID = `${locationURL.host}${getBackendSafePath(locationURL.pathname)}`; + options.createVADProcessor = createRnnoiseProcessorPromise; + + // Disable CallStats, if requessted. + if (options.disableThirdPartyRequests) { + delete options.callStatsID; + delete options.callStatsSecret; + delete options.getWiFiStatsMethod; + } + + return options; +} diff --git a/react/features/prejoin/components/PrejoinApp.js b/react/features/prejoin/components/PrejoinApp.js index 57b0747aa5..a2a9e9066c 100644 --- a/react/features/prejoin/components/PrejoinApp.js +++ b/react/features/prejoin/components/PrejoinApp.js @@ -2,11 +2,13 @@ import { AtlasKitThemeProvider } from '@atlaskit/theme'; import React from 'react'; +import { batch } from 'react-redux'; import { BaseApp } from '../../../features/base/app'; import { setConfig } from '../../base/config'; import { createPrejoinTracks } from '../../base/tracks'; -import { initPrejoin } from '../actions'; +import { getConferenceOptions } from '../../conference/functions'; +import { initPrejoin, makePrecallTest } from '../actions'; import Prejoin from './Prejoin'; @@ -70,7 +72,10 @@ export default class PrejoinApp extends BaseApp { const tracks = await tryCreateLocalTracks; - dispatch(initPrejoin(tracks, errors)); + batch(() => { + dispatch(initPrejoin(tracks, errors)); + dispatch(makePrecallTest(getConferenceOptions(store.getState()))); + }); }); }