ref(TS) Convert some base features to TS (#12138)
This commit is contained in:
parent
5502601fb3
commit
95084e1004
|
@ -121,7 +121,7 @@
|
||||||
"react-window": "1.8.6",
|
"react-window": "1.8.6",
|
||||||
"react-youtube": "7.13.1",
|
"react-youtube": "7.13.1",
|
||||||
"redux": "4.0.4",
|
"redux": "4.0.4",
|
||||||
"redux-thunk": "2.2.0",
|
"redux-thunk": "2.4.1",
|
||||||
"resemblejs": "4.0.0",
|
"resemblejs": "4.0.0",
|
||||||
"seamless-scroll-polyfill": "2.1.8",
|
"seamless-scroll-polyfill": "2.1.8",
|
||||||
"styled-components": "3.4.9",
|
"styled-components": "3.4.9",
|
||||||
|
@ -16941,9 +16941,12 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/redux-thunk": {
|
"node_modules/redux-thunk": {
|
||||||
"version": "2.2.0",
|
"version": "2.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.1.tgz",
|
||||||
"integrity": "sha1-5hWhbha0ehmlFXZhM9Hj6Zt4UuU="
|
"integrity": "sha512-OOYGNY5Jy2TWvTL1KgAlVy6dcx3siPJ1wTq741EPyUKfn6W6nChdICjZwCd0p8AZBs5kWpZlbkXW2nE/zjUa+Q==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"redux": "^4"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"node_modules/regenerate": {
|
"node_modules/regenerate": {
|
||||||
"version": "1.4.2",
|
"version": "1.4.2",
|
||||||
|
@ -33153,9 +33156,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"redux-thunk": {
|
"redux-thunk": {
|
||||||
"version": "2.2.0",
|
"version": "2.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.1.tgz",
|
||||||
"integrity": "sha1-5hWhbha0ehmlFXZhM9Hj6Zt4UuU="
|
"integrity": "sha512-OOYGNY5Jy2TWvTL1KgAlVy6dcx3siPJ1wTq741EPyUKfn6W6nChdICjZwCd0p8AZBs5kWpZlbkXW2nE/zjUa+Q=="
|
||||||
},
|
},
|
||||||
"regenerate": {
|
"regenerate": {
|
||||||
"version": "1.4.2",
|
"version": "1.4.2",
|
||||||
|
|
|
@ -126,7 +126,7 @@
|
||||||
"react-window": "1.8.6",
|
"react-window": "1.8.6",
|
||||||
"react-youtube": "7.13.1",
|
"react-youtube": "7.13.1",
|
||||||
"redux": "4.0.4",
|
"redux": "4.0.4",
|
||||||
"redux-thunk": "2.2.0",
|
"redux-thunk": "2.4.1",
|
||||||
"resemblejs": "4.0.0",
|
"resemblejs": "4.0.0",
|
||||||
"seamless-scroll-polyfill": "2.1.8",
|
"seamless-scroll-polyfill": "2.1.8",
|
||||||
"styled-components": "3.4.9",
|
"styled-components": "3.4.9",
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { AnyAction, Dispatch } from 'redux';
|
import { AnyAction } from 'redux';
|
||||||
|
import { ThunkDispatch } from 'redux-thunk';
|
||||||
|
|
||||||
import { IAnalyticsState } from '../analytics/reducer';
|
import { IAnalyticsState } from '../analytics/reducer';
|
||||||
import { IAuthenticationState } from '../authentication/reducer';
|
import { IAuthenticationState } from '../authentication/reducer';
|
||||||
|
@ -75,7 +76,7 @@ import { IVideoSipGW } from '../videosipgw/reducer';
|
||||||
import { IVirtualBackground } from '../virtual-background/reducer';
|
import { IVirtualBackground } from '../virtual-background/reducer';
|
||||||
|
|
||||||
export interface IStore {
|
export interface IStore {
|
||||||
dispatch: Dispatch<AnyAction>;
|
dispatch: ThunkDispatch<IState, void, AnyAction>;
|
||||||
getState: () => IState;
|
getState: () => IState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -145,7 +145,10 @@ class LoginDialog extends Component<Props, State> {
|
||||||
dispatch
|
dispatch
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const { password, username } = this.state;
|
const { password, username } = this.state;
|
||||||
const jid = toJid(username, configHosts);
|
const jid = toJid(username, configHosts ?? {
|
||||||
|
authdomain: '',
|
||||||
|
domain: ''
|
||||||
|
});
|
||||||
|
|
||||||
if (conference) {
|
if (conference) {
|
||||||
dispatch(authenticateAndUpgradeRole(jid, password, conference));
|
dispatch(authenticateAndUpgradeRole(jid, password, conference));
|
||||||
|
@ -217,7 +220,8 @@ class LoginDialog extends Component<Props, State> {
|
||||||
const { credentials } = error;
|
const { credentials } = error;
|
||||||
|
|
||||||
if (credentials
|
if (credentials
|
||||||
&& credentials.jid === toJid(username, configHosts)
|
&& credentials.jid === toJid(username, configHosts ?? { authdomain: '',
|
||||||
|
domain: '' })
|
||||||
&& credentials.password === password) {
|
&& credentials.password === password) {
|
||||||
messageKey = t('dialog.incorrectPassword');
|
messageKey = t('dialog.incorrectPassword');
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,7 +60,7 @@ export interface IConferenceState {
|
||||||
password?: string;
|
password?: string;
|
||||||
passwordRequired?: Object;
|
passwordRequired?: Object;
|
||||||
pendingSubjectChange?: string;
|
pendingSubjectChange?: string;
|
||||||
room?: Object;
|
room?: string;
|
||||||
startAudioMutedPolicy?: boolean;
|
startAudioMutedPolicy?: boolean;
|
||||||
startReactionsMuted?: boolean;
|
startReactionsMuted?: boolean;
|
||||||
startVideoMutedPolicy?: boolean;
|
startVideoMutedPolicy?: boolean;
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
// @flow
|
// @ts-ignore
|
||||||
|
|
||||||
import { jitsiLocalStorage } from '@jitsi/js-utils';
|
import { jitsiLocalStorage } from '@jitsi/js-utils';
|
||||||
import type { Dispatch } from 'redux';
|
import { Dispatch } from 'redux';
|
||||||
|
|
||||||
import { addKnownDomains } from '../known-domains';
|
import { addKnownDomains } from '../known-domains/actions';
|
||||||
import { parseURIString } from '../util';
|
import { parseURIString } from '../util/uri';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
CONFIG_WILL_LOAD,
|
CONFIG_WILL_LOAD,
|
||||||
|
@ -13,8 +12,9 @@ import {
|
||||||
UPDATE_CONFIG,
|
UPDATE_CONFIG,
|
||||||
OVERWRITE_CONFIG
|
OVERWRITE_CONFIG
|
||||||
} from './actionTypes';
|
} from './actionTypes';
|
||||||
|
import { IConfig } from './configType';
|
||||||
import { _CONFIG_STORE_PREFIX } from './constants';
|
import { _CONFIG_STORE_PREFIX } from './constants';
|
||||||
import { setConfigFromURLParams } from './functions';
|
import { setConfigFromURLParams } from './functions.any';
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -23,7 +23,7 @@ import { setConfigFromURLParams } from './functions';
|
||||||
* @param {Object} config - The new options (to add).
|
* @param {Object} config - The new options (to add).
|
||||||
* @returns {Function}
|
* @returns {Function}
|
||||||
*/
|
*/
|
||||||
export function updateConfig(config: Object) {
|
export function updateConfig(config: IConfig) {
|
||||||
return {
|
return {
|
||||||
type: UPDATE_CONFIG,
|
type: UPDATE_CONFIG,
|
||||||
config
|
config
|
||||||
|
@ -116,6 +116,8 @@ export function setConfig(config: Object = {}) {
|
||||||
// On Web the config also comes from the window.config global,
|
// On Web the config also comes from the window.config global,
|
||||||
// but it is resolved in the loadConfig procedure.
|
// but it is resolved in the loadConfig procedure.
|
||||||
config,
|
config,
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
window.interfaceConfig,
|
window.interfaceConfig,
|
||||||
locationURL);
|
locationURL);
|
||||||
|
|
||||||
|
@ -142,6 +144,7 @@ export function storeConfig(baseURL: string, config: Object) {
|
||||||
let b = false;
|
let b = false;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// @ts-ignore
|
||||||
if (typeof window.config === 'undefined' || window.config !== config) {
|
if (typeof window.config === 'undefined' || window.config !== config) {
|
||||||
jitsiLocalStorage.setItem(`${_CONFIG_STORE_PREFIX}/${baseURL}`, JSON.stringify(config));
|
jitsiLocalStorage.setItem(`${_CONFIG_STORE_PREFIX}/${baseURL}`, JSON.stringify(config));
|
||||||
b = true;
|
b = true;
|
||||||
|
@ -153,7 +156,7 @@ export function storeConfig(baseURL: string, config: Object) {
|
||||||
// If base/config knows a domain, then the app knows it.
|
// If base/config knows a domain, then the app knows it.
|
||||||
if (b) {
|
if (b) {
|
||||||
try {
|
try {
|
||||||
dispatch(addKnownDomains(parseURIString(baseURL).host));
|
dispatch(addKnownDomains(parseURIString(baseURL)?.host));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Ignore the error because the fiddling with "known domains" is
|
// Ignore the error because the fiddling with "known domains" is
|
||||||
// a side effect here.
|
// a side effect here.
|
|
@ -105,6 +105,7 @@ export interface IConfig {
|
||||||
scriptURLs?: Array<string>;
|
scriptURLs?: Array<string>;
|
||||||
};
|
};
|
||||||
apiLogLevels?: Array<'warn' | 'log' | 'error' | 'info' | 'debug'>;
|
apiLogLevels?: Array<'warn' | 'log' | 'error' | 'info' | 'debug'>;
|
||||||
|
appId?: string;
|
||||||
audioLevelsInterval?: number;
|
audioLevelsInterval?: number;
|
||||||
audioQuality?: {
|
audioQuality?: {
|
||||||
opusMaxAverageBitrate?: number | null;
|
opusMaxAverageBitrate?: number | null;
|
||||||
|
@ -316,6 +317,8 @@ export interface IConfig {
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
};
|
};
|
||||||
gravatarBaseURL?: string;
|
gravatarBaseURL?: string;
|
||||||
|
guestDialOutStatusUrl?: string;
|
||||||
|
guestDialOutUrl?: string;
|
||||||
helpCentreURL?: string;
|
helpCentreURL?: string;
|
||||||
hiddenPremeetingButtons?: Array<'microphone' | 'camera' | 'select-background' | 'invite' | 'settings'>;
|
hiddenPremeetingButtons?: Array<'microphone' | 'camera' | 'select-background' | 'invite' | 'settings'>;
|
||||||
hideAddRoomButton?: boolean;
|
hideAddRoomButton?: boolean;
|
||||||
|
@ -354,7 +357,7 @@ export interface IConfig {
|
||||||
notifyAllParticipants?: boolean;
|
notifyAllParticipants?: boolean;
|
||||||
};
|
};
|
||||||
localSubject?: string;
|
localSubject?: string;
|
||||||
locationURL?: string;
|
locationURL?: URL;
|
||||||
maxFullResolutionParticipants?: number;
|
maxFullResolutionParticipants?: number;
|
||||||
moderatedRoomServiceUrl?: string;
|
moderatedRoomServiceUrl?: string;
|
||||||
mouseMoveCallbackInterval?: number;
|
mouseMoveCallbackInterval?: number;
|
||||||
|
@ -403,12 +406,14 @@ export interface IConfig {
|
||||||
hideStorageWarning?: boolean;
|
hideStorageWarning?: boolean;
|
||||||
sharingEnabled?: boolean;
|
sharingEnabled?: boolean;
|
||||||
};
|
};
|
||||||
|
recordingSharingUrl?: string;
|
||||||
remoteVideoMenu?: {
|
remoteVideoMenu?: {
|
||||||
disableGrantModerator?: boolean;
|
disableGrantModerator?: boolean;
|
||||||
disableKick?: boolean;
|
disableKick?: boolean;
|
||||||
disablePrivateChat?: boolean;
|
disablePrivateChat?: boolean;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
};
|
};
|
||||||
|
replaceParticipant?: string;
|
||||||
requireDisplayName?: boolean;
|
requireDisplayName?: boolean;
|
||||||
resolution?: number;
|
resolution?: number;
|
||||||
roomPasswordNumberOfDigits?: number;
|
roomPasswordNumberOfDigits?: number;
|
||||||
|
@ -417,6 +422,7 @@ export interface IConfig {
|
||||||
enabled?: boolean;
|
enabled?: boolean;
|
||||||
mode?: 'always' | 'recording';
|
mode?: 'always' | 'recording';
|
||||||
};
|
};
|
||||||
|
serviceUrl?: string;
|
||||||
speakerStatsOrder?: Array<'role' | 'name' | 'hasLeft'>;
|
speakerStatsOrder?: Array<'role' | 'name' | 'hasLeft'>;
|
||||||
startAudioMuted?: boolean;
|
startAudioMuted?: boolean;
|
||||||
startAudioOnly?: boolean;
|
startAudioOnly?: boolean;
|
||||||
|
@ -481,4 +487,5 @@ export interface IConfig {
|
||||||
webrtcIceTcpDisable?: boolean;
|
webrtcIceTcpDisable?: boolean;
|
||||||
webrtcIceUdpDisable?: boolean;
|
webrtcIceUdpDisable?: boolean;
|
||||||
websocket?: string;
|
websocket?: string;
|
||||||
|
websocketKeepAliveUrl?: string;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,15 @@
|
||||||
// @flow
|
/* eslint-disable lines-around-comment */
|
||||||
|
// @ts-ignore
|
||||||
import Bourne from '@hapi/bourne';
|
import Bourne from '@hapi/bourne';
|
||||||
|
// @ts-ignore
|
||||||
import { jitsiLocalStorage } from '@jitsi/js-utils';
|
import { jitsiLocalStorage } from '@jitsi/js-utils';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
|
|
||||||
|
import { IState } from '../../app/types';
|
||||||
import { browser } from '../lib-jitsi-meet';
|
import { browser } from '../lib-jitsi-meet';
|
||||||
import { parseURLParams } from '../util';
|
import { parseURLParams } from '../util/parseURLParams';
|
||||||
|
|
||||||
|
import { IConfig } from './configType';
|
||||||
import CONFIG_WHITELIST from './configWhitelist';
|
import CONFIG_WHITELIST from './configWhitelist';
|
||||||
import { _CONFIG_STORE_PREFIX, FEATURE_FLAGS } from './constants';
|
import { _CONFIG_STORE_PREFIX, FEATURE_FLAGS } from './constants';
|
||||||
import INTERFACE_CONFIG_WHITELIST from './interfaceConfigWhitelist';
|
import INTERFACE_CONFIG_WHITELIST from './interfaceConfigWhitelist';
|
||||||
|
@ -46,7 +49,7 @@ export function createFakeConfig(baseURL: string) {
|
||||||
* @param {Object} state - The global state.
|
* @param {Object} state - The global state.
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
export function getMeetingRegion(state: Object) {
|
export function getMeetingRegion(state: IState) {
|
||||||
return state['features/base/config']?.deploymentInfo?.region || '';
|
return state['features/base/config']?.deploymentInfo?.region || '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,7 +59,7 @@ export function getMeetingRegion(state: Object) {
|
||||||
* @param {Object} state - The global state.
|
* @param {Object} state - The global state.
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
export function getMultipleVideoSupportFeatureFlag(state: Object) {
|
export function getMultipleVideoSupportFeatureFlag(state: IState) {
|
||||||
return getFeatureFlag(state, FEATURE_FLAGS.MULTIPLE_VIDEO_STREAMS_SUPPORT)
|
return getFeatureFlag(state, FEATURE_FLAGS.MULTIPLE_VIDEO_STREAMS_SUPPORT)
|
||||||
&& getSourceNameSignalingFeatureFlag(state);
|
&& getSourceNameSignalingFeatureFlag(state);
|
||||||
}
|
}
|
||||||
|
@ -67,7 +70,7 @@ export function getMultipleVideoSupportFeatureFlag(state: Object) {
|
||||||
* @param {Object} state - The global state.
|
* @param {Object} state - The global state.
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
export function getMultipleVideoSendingSupportFeatureFlag(state: Object) {
|
export function getMultipleVideoSendingSupportFeatureFlag(state: IState) {
|
||||||
return navigator.product !== 'ReactNative'
|
return navigator.product !== 'ReactNative'
|
||||||
&& getMultipleVideoSupportFeatureFlag(state) && isUnifiedPlanEnabled(state);
|
&& getMultipleVideoSupportFeatureFlag(state) && isUnifiedPlanEnabled(state);
|
||||||
}
|
}
|
||||||
|
@ -78,7 +81,7 @@ export function getMultipleVideoSendingSupportFeatureFlag(state: Object) {
|
||||||
* @param {Object} state - The global state.
|
* @param {Object} state - The global state.
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
export function getSourceNameSignalingFeatureFlag(state: Object) {
|
export function getSourceNameSignalingFeatureFlag(state: IState) {
|
||||||
return getFeatureFlag(state, FEATURE_FLAGS.SOURCE_NAME_SIGNALING);
|
return getFeatureFlag(state, FEATURE_FLAGS.SOURCE_NAME_SIGNALING);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,10 +92,10 @@ export function getSourceNameSignalingFeatureFlag(state: Object) {
|
||||||
* @param {string} featureFlag - The name of the feature flag.
|
* @param {string} featureFlag - The name of the feature flag.
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
export function getFeatureFlag(state: Object, featureFlag: string) {
|
export function getFeatureFlag(state: IState, featureFlag: string) {
|
||||||
const featureFlags = state['features/base/config']?.flags || {};
|
const featureFlags = state['features/base/config']?.flags || {};
|
||||||
|
|
||||||
return Boolean(featureFlags[featureFlag]);
|
return Boolean(featureFlags[featureFlag as keyof typeof featureFlags]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -101,7 +104,7 @@ export function getFeatureFlag(state: Object, featureFlag: string) {
|
||||||
* @param {Object} state - The global state.
|
* @param {Object} state - The global state.
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
export function getDisableRemoveRaisedHandOnFocus(state: Object) {
|
export function getDisableRemoveRaisedHandOnFocus(state: IState) {
|
||||||
return state['features/base/config']?.disableRemoveRaisedHandOnFocus || false;
|
return state['features/base/config']?.disableRemoveRaisedHandOnFocus || false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,7 +114,7 @@ export function getDisableRemoveRaisedHandOnFocus(state: Object) {
|
||||||
* @param {Object} state - The global state.
|
* @param {Object} state - The global state.
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
export function getRecordingSharingUrl(state: Object) {
|
export function getRecordingSharingUrl(state: IState) {
|
||||||
return state['features/base/config'].recordingSharingUrl;
|
return state['features/base/config'].recordingSharingUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,7 +139,7 @@ export function getRecordingSharingUrl(state: Object) {
|
||||||
* }.
|
* }.
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
export function overrideConfigJSON(config: ?Object, interfaceConfig: ?Object, json: Object) {
|
export function overrideConfigJSON(config: IConfig, interfaceConfig: any, json: any) {
|
||||||
for (const configName of Object.keys(json)) {
|
for (const configName of Object.keys(json)) {
|
||||||
let configObj;
|
let configObj;
|
||||||
|
|
||||||
|
@ -147,7 +150,7 @@ export function overrideConfigJSON(config: ?Object, interfaceConfig: ?Object, js
|
||||||
}
|
}
|
||||||
if (configObj) {
|
if (configObj) {
|
||||||
const configJSON
|
const configJSON
|
||||||
= getWhitelistedJSON(configName, json[configName]);
|
= getWhitelistedJSON(configName as 'interfaceConfig' | 'config', json[configName]);
|
||||||
|
|
||||||
if (!_.isEmpty(configJSON)) {
|
if (!_.isEmpty(configJSON)) {
|
||||||
logger.info(
|
logger.info(
|
||||||
|
@ -177,7 +180,7 @@ export function overrideConfigJSON(config: ?Object, interfaceConfig: ?Object, js
|
||||||
* @returns {Object} - The result object only with the keys
|
* @returns {Object} - The result object only with the keys
|
||||||
* that are whitelisted.
|
* that are whitelisted.
|
||||||
*/
|
*/
|
||||||
export function getWhitelistedJSON(configName: string, configJSON: Object): Object {
|
export function getWhitelistedJSON(configName: 'interfaceConfig' | 'config', configJSON: any): Object {
|
||||||
if (configName === 'interfaceConfig') {
|
if (configName === 'interfaceConfig') {
|
||||||
return _.pick(configJSON, INTERFACE_CONFIG_WHITELIST);
|
return _.pick(configJSON, INTERFACE_CONFIG_WHITELIST);
|
||||||
} else if (configName === 'config') {
|
} else if (configName === 'config') {
|
||||||
|
@ -193,9 +196,9 @@ export function getWhitelistedJSON(configName: string, configJSON: Object): Obje
|
||||||
* @param {Object} state - The state of the app.
|
* @param {Object} state - The state of the app.
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
export function isNameReadOnly(state: Object): boolean {
|
export function isNameReadOnly(state: IState): boolean {
|
||||||
return state['features/base/config'].disableProfile
|
return Boolean(state['features/base/config'].disableProfile
|
||||||
|| state['features/base/config'].readOnlyName;
|
|| state['features/base/config'].readOnlyName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -204,7 +207,7 @@ export function isNameReadOnly(state: Object): boolean {
|
||||||
* @param {Object} state - The state of the app.
|
* @param {Object} state - The state of the app.
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
export function isDisplayNameVisible(state: Object): boolean {
|
export function isDisplayNameVisible(state: IState): boolean {
|
||||||
return !state['features/base/config'].hideDisplayName;
|
return !state['features/base/config'].hideDisplayName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -214,7 +217,7 @@ export function isDisplayNameVisible(state: Object): boolean {
|
||||||
* @param {Object} state - The state of the app.
|
* @param {Object} state - The state of the app.
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
export function isUnifiedPlanEnabled(state: Object): boolean {
|
export function isUnifiedPlanEnabled(state: IState): boolean {
|
||||||
const { enableUnifiedOnChrome = true } = state['features/base/config'];
|
const { enableUnifiedOnChrome = true } = state['features/base/config'];
|
||||||
|
|
||||||
return browser.supportsUnifiedPlan()
|
return browser.supportsUnifiedPlan()
|
||||||
|
@ -232,7 +235,7 @@ export function isUnifiedPlanEnabled(state: Object): boolean {
|
||||||
* from {@code baseURL} and stored with {@code storeConfig} if it was restored;
|
* from {@code baseURL} and stored with {@code storeConfig} if it was restored;
|
||||||
* otherwise, {@code undefined}.
|
* otherwise, {@code undefined}.
|
||||||
*/
|
*/
|
||||||
export function restoreConfig(baseURL: string): ?Object {
|
export function restoreConfig(baseURL: string) {
|
||||||
const key = `${_CONFIG_STORE_PREFIX}/${baseURL}`;
|
const key = `${_CONFIG_STORE_PREFIX}/${baseURL}`;
|
||||||
const config = jitsiLocalStorage.getItem(key);
|
const config = jitsiLocalStorage.getItem(key);
|
||||||
|
|
||||||
|
@ -266,9 +269,9 @@ export function restoreConfig(baseURL: string): ?Object {
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
export function setConfigFromURLParams(
|
export function setConfigFromURLParams(
|
||||||
config: ?Object, interfaceConfig: ?Object, location: Object) {
|
config: IConfig, interfaceConfig: any, location: string | URL) {
|
||||||
const params = parseURLParams(location);
|
const params = parseURLParams(location);
|
||||||
const json = {};
|
const json: any = {};
|
||||||
|
|
||||||
// At this point we have:
|
// At this point we have:
|
||||||
// params = {
|
// params = {
|
||||||
|
@ -292,7 +295,7 @@ export function setConfigFromURLParams(
|
||||||
for (const param of Object.keys(params)) {
|
for (const param of Object.keys(params)) {
|
||||||
let base = json;
|
let base = json;
|
||||||
const names = param.split('.');
|
const names = param.split('.');
|
||||||
const last = names.pop();
|
const last = names.pop() ?? '';
|
||||||
|
|
||||||
for (const name of names) {
|
for (const name of names) {
|
||||||
base = base[name] = base[name] || {};
|
base = base[name] = base[name] || {};
|
|
@ -1,8 +1,10 @@
|
||||||
// @flow
|
|
||||||
|
|
||||||
import { NativeModules } from 'react-native';
|
import { NativeModules } from 'react-native';
|
||||||
|
|
||||||
import { getFeatureFlag, REPLACE_PARTICIPANT } from '../flags';
|
import { IState } from '../../app/types';
|
||||||
|
import { REPLACE_PARTICIPANT } from '../flags/constants';
|
||||||
|
import { getFeatureFlag } from '../flags/functions';
|
||||||
|
|
||||||
|
import { IConfig } from './configType';
|
||||||
|
|
||||||
export * from './functions.any';
|
export * from './functions.any';
|
||||||
|
|
||||||
|
@ -12,7 +14,8 @@ export * from './functions.any';
|
||||||
* @param {*} config - The configuration which needs to be cleaned up.
|
* @param {*} config - The configuration which needs to be cleaned up.
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
export function _cleanupConfig(config: Object) {
|
export function _cleanupConfig(config: IConfig) {
|
||||||
|
config.analytics ??= {};
|
||||||
config.analytics.scriptURLs = [];
|
config.analytics.scriptURLs = [];
|
||||||
if (NativeModules.AppInfo.LIBRE_BUILD) {
|
if (NativeModules.AppInfo.LIBRE_BUILD) {
|
||||||
delete config.analytics?.amplitudeAPPKey;
|
delete config.analytics?.amplitudeAPPKey;
|
||||||
|
@ -29,6 +32,6 @@ export function _cleanupConfig(config: Object) {
|
||||||
* @param {Object} state - The state of the app.
|
* @param {Object} state - The state of the app.
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
export function getReplaceParticipant(state: Object): string {
|
export function getReplaceParticipant(state: IState): string {
|
||||||
return getFeatureFlag(state, REPLACE_PARTICIPANT, false);
|
return getFeatureFlag(state, REPLACE_PARTICIPANT, false);
|
||||||
}
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
// @flow
|
import { IState } from '../../app/types';
|
||||||
|
|
||||||
|
import { IConfig } from './configType';
|
||||||
import { TOOLBAR_BUTTONS } from './constants';
|
import { TOOLBAR_BUTTONS } from './constants';
|
||||||
|
|
||||||
export * from './functions.any';
|
export * from './functions.any';
|
||||||
|
@ -10,7 +11,7 @@ export * from './functions.any';
|
||||||
* @param {*} config - The configuration which needs to be cleaned up.
|
* @param {*} config - The configuration which needs to be cleaned up.
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
export function _cleanupConfig(config: Object) { // eslint-disable-line no-unused-vars
|
export function _cleanupConfig(config: IConfig) { // eslint-disable-line @typescript-eslint/no-unused-vars
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -19,7 +20,7 @@ export function _cleanupConfig(config: Object) { // eslint-disable-line no-unuse
|
||||||
* @param {Object} state - The state of the app.
|
* @param {Object} state - The state of the app.
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
export function getDialOutStatusUrl(state: Object): string {
|
export function getDialOutStatusUrl(state: IState): string | undefined {
|
||||||
return state['features/base/config'].guestDialOutStatusUrl;
|
return state['features/base/config'].guestDialOutStatusUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,7 +30,7 @@ export function getDialOutStatusUrl(state: Object): string {
|
||||||
* @param {Object} state - The state of the app.
|
* @param {Object} state - The state of the app.
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
export function getDialOutUrl(state: Object): string {
|
export function getDialOutUrl(state: IState): string | undefined {
|
||||||
return state['features/base/config'].guestDialOutUrl;
|
return state['features/base/config'].guestDialOutUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,7 +40,7 @@ export function getDialOutUrl(state: Object): string {
|
||||||
* @param {Object} state - The state of the app.
|
* @param {Object} state - The state of the app.
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
export function getReplaceParticipant(state: Object): string {
|
export function getReplaceParticipant(state: IState): string | undefined {
|
||||||
return state['features/base/config'].replaceParticipant;
|
return state['features/base/config'].replaceParticipant;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,7 +50,7 @@ export function getReplaceParticipant(state: Object): string {
|
||||||
* @param {Object} state - The redux state.
|
* @param {Object} state - The redux state.
|
||||||
* @returns {Array<string>} - The list of enabled toolbar buttons.
|
* @returns {Array<string>} - The list of enabled toolbar buttons.
|
||||||
*/
|
*/
|
||||||
export function getToolbarButtons(state: Object): Array<string> {
|
export function getToolbarButtons(state: IState): Array<string> {
|
||||||
const { toolbarButtons } = state['features/base/config'];
|
const { toolbarButtons } = state['features/base/config'];
|
||||||
|
|
||||||
return Array.isArray(toolbarButtons) ? toolbarButtons : TOOLBAR_BUTTONS;
|
return Array.isArray(toolbarButtons) ? toolbarButtons : TOOLBAR_BUTTONS;
|
||||||
|
@ -63,7 +64,7 @@ export function getToolbarButtons(state: Object): Array<string> {
|
||||||
* @param {Object|Array<string>} state - The redux state or the array with the enabled buttons.
|
* @param {Object|Array<string>} state - The redux state or the array with the enabled buttons.
|
||||||
* @returns {boolean} - True if the button is enabled and false otherwise.
|
* @returns {boolean} - True if the button is enabled and false otherwise.
|
||||||
*/
|
*/
|
||||||
export function isToolbarButtonEnabled(buttonName: string, state: Object | Array<string>) {
|
export function isToolbarButtonEnabled(buttonName: string, state: IState | Array<string>) {
|
||||||
const buttons = Array.isArray(state) ? state : getToolbarButtons(state);
|
const buttons = Array.isArray(state) ? state : getToolbarButtons(state);
|
||||||
|
|
||||||
return buttons.includes(buttonName);
|
return buttons.includes(buttonName);
|
||||||
|
@ -75,7 +76,7 @@ export function isToolbarButtonEnabled(buttonName: string, state: Object | Array
|
||||||
* @param {Object} state - The state of the app.
|
* @param {Object} state - The state of the app.
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
export function areAudioLevelsEnabled(state: Object): boolean {
|
export function areAudioLevelsEnabled(state: IState): boolean {
|
||||||
// Default to false for React Native as audio levels are of no interest to the mobile app.
|
// Default to false for React Native as audio levels are of no interest to the mobile app.
|
||||||
return navigator.product !== 'ReactNative' && !state['features/base/config'].disableAudioLevels;
|
return navigator.product !== 'ReactNative' && !state['features/base/config'].disableAudioLevels;
|
||||||
}
|
}
|
|
@ -1,13 +1,11 @@
|
||||||
// @flow
|
import { getBackendSafeRoomName } from '../util/uri';
|
||||||
|
|
||||||
import { getBackendSafeRoomName } from '../util';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds and returns the room name.
|
* Builds and returns the room name.
|
||||||
*
|
*
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
export default function getRoomName(): ?string {
|
export default function getRoomName(): string | undefined {
|
||||||
const path = window.location.pathname;
|
const path = window.location.pathname;
|
||||||
|
|
||||||
// The last non-directory component of the path (name) is the room.
|
// The last non-directory component of the path (name) is the room.
|
|
@ -1,5 +1,3 @@
|
||||||
// @flow
|
|
||||||
|
|
||||||
import { getLogger } from '../logging/functions';
|
import { getLogger } from '../logging/functions';
|
||||||
|
|
||||||
export default getLogger('features/base/config');
|
export default getLogger('features/base/config');
|
|
@ -1,9 +1,13 @@
|
||||||
|
import { AnyAction } from 'redux';
|
||||||
|
|
||||||
|
import { IStore } from '../../app/types';
|
||||||
import { getFeatureFlag } from '../flags/functions';
|
import { getFeatureFlag } from '../flags/functions';
|
||||||
import { MiddlewareRegistry } from '../redux';
|
import MiddlewareRegistry from '../redux/MiddlewareRegistry';
|
||||||
import { updateSettings } from '../settings';
|
import { updateSettings } from '../settings/actions';
|
||||||
|
|
||||||
import { SET_CONFIG, OVERWRITE_CONFIG } from './actionTypes';
|
import { SET_CONFIG, OVERWRITE_CONFIG } from './actionTypes';
|
||||||
import { updateConfig } from './actions';
|
import { updateConfig } from './actions';
|
||||||
|
import { IConfig } from './configType';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The middleware of the feature {@code base/config}.
|
* The middleware of the feature {@code base/config}.
|
||||||
|
@ -37,7 +41,7 @@ MiddlewareRegistry.register(store => next => action => {
|
||||||
* @private
|
* @private
|
||||||
* @returns {*} The return value of {@code next(action)}.
|
* @returns {*} The return value of {@code next(action)}.
|
||||||
*/
|
*/
|
||||||
function _setConfig({ dispatch, getState }, next, action) {
|
function _setConfig({ dispatch, getState }: IStore, next: Function, action: AnyAction) {
|
||||||
// The reducer is doing some alterations to the config passed in the action,
|
// The reducer is doing some alterations to the config passed in the action,
|
||||||
// so make sure it's the final state by waiting for the action to be
|
// so make sure it's the final state by waiting for the action to be
|
||||||
// reduced.
|
// reduced.
|
||||||
|
@ -46,7 +50,7 @@ function _setConfig({ dispatch, getState }, next, action) {
|
||||||
|
|
||||||
// Update the config with user defined settings.
|
// Update the config with user defined settings.
|
||||||
const settings = state['features/base/settings'];
|
const settings = state['features/base/settings'];
|
||||||
const config = {};
|
const config: IConfig = {};
|
||||||
|
|
||||||
if (typeof settings.disableP2P !== 'undefined') {
|
if (typeof settings.disableP2P !== 'undefined') {
|
||||||
config.p2p = { enabled: !settings.disableP2P };
|
config.p2p = { enabled: !settings.disableP2P };
|
||||||
|
@ -77,7 +81,9 @@ function _setConfig({ dispatch, getState }, next, action) {
|
||||||
// not be the global variable which is being modified anymore due to
|
// not be the global variable which is being modified anymore due to
|
||||||
// different merge methods being used along the way. The global variable
|
// different merge methods being used along the way. The global variable
|
||||||
// must be synchronized with the final state resolved by the reducer.
|
// must be synchronized with the final state resolved by the reducer.
|
||||||
|
// @ts-ignore
|
||||||
if (typeof window.config !== 'undefined') {
|
if (typeof window.config !== 'undefined') {
|
||||||
|
// @ts-ignore
|
||||||
window.config = state['features/base/config'];
|
window.config = state['features/base/config'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,7 +102,7 @@ function _setConfig({ dispatch, getState }, next, action) {
|
||||||
* @private
|
* @private
|
||||||
* @returns {*} The return value of {@code next(action)}.
|
* @returns {*} The return value of {@code next(action)}.
|
||||||
*/
|
*/
|
||||||
function _updateSettings({ dispatch }, next, action) {
|
function _updateSettings({ dispatch }: IStore, next: Function, action: AnyAction) {
|
||||||
const { config: { doNotFlipLocalVideo } } = action;
|
const { config: { doNotFlipLocalVideo } } = action;
|
||||||
|
|
||||||
if (doNotFlipLocalVideo === true) {
|
if (doNotFlipLocalVideo === true) {
|
|
@ -1,10 +1,11 @@
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
|
|
||||||
|
import { IState } from '../../app/types';
|
||||||
import {
|
import {
|
||||||
appendURLParam,
|
appendURLParam,
|
||||||
getBackendSafeRoomName,
|
getBackendSafeRoomName,
|
||||||
parseURIString
|
parseURIString
|
||||||
} from '../util';
|
} from '../util/uri';
|
||||||
|
|
||||||
import logger from './logger';
|
import logger from './logger';
|
||||||
|
|
||||||
|
@ -16,7 +17,7 @@ import logger from './logger';
|
||||||
* @returns {Object} The options to be passed to the constructor of
|
* @returns {Object} The options to be passed to the constructor of
|
||||||
* {@code JitsiConnection}.
|
* {@code JitsiConnection}.
|
||||||
*/
|
*/
|
||||||
export function constructOptions(state) {
|
export function constructOptions(state: IState) {
|
||||||
// Deep clone the options to make sure we don't modify the object in the
|
// Deep clone the options to make sure we don't modify the object in the
|
||||||
// redux store.
|
// redux store.
|
||||||
const options = _.cloneDeep(state['features/base/config']);
|
const options = _.cloneDeep(state['features/base/config']);
|
||||||
|
@ -36,14 +37,14 @@ export function constructOptions(state) {
|
||||||
|
|
||||||
if (bosh.startsWith('//')) {
|
if (bosh.startsWith('//')) {
|
||||||
// By default our config.js doesn't include the protocol.
|
// By default our config.js doesn't include the protocol.
|
||||||
bosh = `${locationURL.protocol}${bosh}`;
|
bosh = `${locationURL?.protocol}${bosh}`;
|
||||||
} else if (bosh.startsWith('/')) {
|
} else if (bosh.startsWith('/')) {
|
||||||
// Handle relative URLs, which won't work on mobile.
|
// Handle relative URLs, which won't work on mobile.
|
||||||
const {
|
const {
|
||||||
protocol,
|
protocol,
|
||||||
host,
|
host,
|
||||||
contextRoot
|
contextRoot
|
||||||
} = parseURIString(locationURL.href);
|
} = parseURIString(locationURL?.href);
|
||||||
|
|
||||||
bosh = `${protocol}//${host}${contextRoot || '/'}${bosh.substr(1)}`;
|
bosh = `${protocol}//${host}${contextRoot || '/'}${bosh.substr(1)}`;
|
||||||
}
|
}
|
||||||
|
@ -60,10 +61,10 @@ export function constructOptions(state) {
|
||||||
if (serviceUrl && room) {
|
if (serviceUrl && room) {
|
||||||
const roomName = getBackendSafeRoomName(room);
|
const roomName = getBackendSafeRoomName(room);
|
||||||
|
|
||||||
options.serviceUrl = appendURLParam(serviceUrl, 'room', roomName);
|
options.serviceUrl = appendURLParam(serviceUrl, 'room', roomName ?? '');
|
||||||
|
|
||||||
if (options.websocketKeepAliveUrl) {
|
if (options.websocketKeepAliveUrl) {
|
||||||
options.websocketKeepAliveUrl = appendURLParam(options.websocketKeepAliveUrl, 'room', roomName);
|
options.websocketKeepAliveUrl = appendURLParam(options.websocketKeepAliveUrl, 'room', roomName ?? '');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
// @flow
|
/* eslint-disable lines-around-comment */
|
||||||
|
import { Dispatch } from 'redux';
|
||||||
import type { Dispatch } from 'redux';
|
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
import { conferenceLeft, conferenceWillLeave } from '../conference/actions';
|
import { conferenceLeft, conferenceWillLeave } from '../conference/actions';
|
||||||
|
// @ts-ignore
|
||||||
import { getCurrentConference } from '../conference/functions';
|
import { getCurrentConference } from '../conference/functions';
|
||||||
import JitsiMeetJS, { JitsiConnectionEvents } from '../lib-jitsi-meet';
|
import JitsiMeetJS, { JitsiConnectionEvents } from '../lib-jitsi-meet';
|
||||||
|
|
||||||
|
@ -36,34 +37,34 @@ export type ConnectionFailedError = {
|
||||||
/**
|
/**
|
||||||
* The XMPP user's ID.
|
* The XMPP user's ID.
|
||||||
*/
|
*/
|
||||||
jid: string,
|
jid: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The XMPP user's password.
|
* The XMPP user's password.
|
||||||
*/
|
*/
|
||||||
password: string
|
password: string;
|
||||||
},
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The details about the connection failed event.
|
* The details about the connection failed event.
|
||||||
*/
|
*/
|
||||||
details?: Object,
|
details?: Object;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Error message.
|
* Error message.
|
||||||
*/
|
*/
|
||||||
message?: string,
|
message?: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* One of {@link JitsiConnectionError} constants (defined in
|
* One of {@link JitsiConnectionError} constants (defined in
|
||||||
* lib-jitsi-meet).
|
* lib-jitsi-meet).
|
||||||
*/
|
*/
|
||||||
name: string,
|
name: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates whether this event is recoverable or not.
|
* Indicates whether this event is recoverable or not.
|
||||||
*/
|
*/
|
||||||
recoverable?: boolean
|
recoverable?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -73,7 +74,7 @@ export type ConnectionFailedError = {
|
||||||
* @param {string} [password] - The XMPP user's password.
|
* @param {string} [password] - The XMPP user's password.
|
||||||
* @returns {Function}
|
* @returns {Function}
|
||||||
*/
|
*/
|
||||||
export function connect(id: ?string, password: ?string) {
|
export function connect(id?: string, password?: string) {
|
||||||
return (dispatch: Dispatch<any>, getState: Function) => {
|
return (dispatch: Dispatch<any>, getState: Function) => {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
const options = constructOptions(state);
|
const options = constructOptions(state);
|
||||||
|
@ -141,7 +142,7 @@ export function connect(id: ?string, password: ?string) {
|
||||||
function _onConnectionFailed( // eslint-disable-line max-params
|
function _onConnectionFailed( // eslint-disable-line max-params
|
||||||
err: string,
|
err: string,
|
||||||
msg: string,
|
msg: string,
|
||||||
credentials: Object,
|
credentials: any,
|
||||||
details: Object) {
|
details: Object) {
|
||||||
unsubscribe();
|
unsubscribe();
|
||||||
dispatch(
|
dispatch(
|
||||||
|
@ -253,7 +254,7 @@ export function connectionFailed(
|
||||||
* connection: JitsiConnection
|
* connection: JitsiConnection
|
||||||
* }}
|
* }}
|
||||||
*/
|
*/
|
||||||
function _connectionWillConnect(connection) {
|
function _connectionWillConnect(connection: Object) {
|
||||||
return {
|
return {
|
||||||
type: CONNECTION_WILL_CONNECT,
|
type: CONNECTION_WILL_CONNECT,
|
||||||
connection
|
connection
|
||||||
|
@ -286,7 +287,7 @@ export function disconnect() {
|
||||||
|
|
||||||
promise
|
promise
|
||||||
= conference_.leave()
|
= conference_.leave()
|
||||||
.catch(error => {
|
.catch((error: Error) => {
|
||||||
logger.warn(
|
logger.warn(
|
||||||
'JitsiConference.leave() rejected with:',
|
'JitsiConference.leave() rejected with:',
|
||||||
error);
|
error);
|
||||||
|
@ -328,7 +329,7 @@ export function disconnect() {
|
||||||
* locationURL: URL
|
* locationURL: URL
|
||||||
* }}
|
* }}
|
||||||
*/
|
*/
|
||||||
export function setLocationURL(locationURL: ?URL) {
|
export function setLocationURL(locationURL?: URL) {
|
||||||
return {
|
return {
|
||||||
type: SET_LOCATION_URL,
|
type: SET_LOCATION_URL,
|
||||||
locationURL
|
locationURL
|
|
@ -1,12 +1,8 @@
|
||||||
// @flow
|
import { IStore } from '../../app/types';
|
||||||
|
import { configureInitialDevices } from '../devices/actions';
|
||||||
|
import { getBackendSafeRoomName } from '../util/uri';
|
||||||
|
|
||||||
import type { Dispatch } from 'redux';
|
declare const APP: any;
|
||||||
|
|
||||||
declare var APP: Object;
|
|
||||||
declare var config: Object;
|
|
||||||
|
|
||||||
import { configureInitialDevices } from '../devices';
|
|
||||||
import { getBackendSafeRoomName } from '../util';
|
|
||||||
|
|
||||||
export {
|
export {
|
||||||
connectionDisconnected,
|
connectionDisconnected,
|
||||||
|
@ -24,7 +20,7 @@ export * from './actions.any';
|
||||||
* @returns {Promise<JitsiConnection>}
|
* @returns {Promise<JitsiConnection>}
|
||||||
*/
|
*/
|
||||||
export function connect() {
|
export function connect() {
|
||||||
return (dispatch: Dispatch<any>, getState: Function) => {
|
return (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
|
||||||
const room = getBackendSafeRoomName(getState()['features/base/conference'].room);
|
const room = getBackendSafeRoomName(getState()['features/base/conference'].room);
|
||||||
|
|
||||||
// XXX For web based version we use conference initialization logic
|
// XXX For web based version we use conference initialization logic
|
||||||
|
@ -32,7 +28,7 @@ export function connect() {
|
||||||
return dispatch(configureInitialDevices()).then(
|
return dispatch(configureInitialDevices()).then(
|
||||||
() => APP.conference.init({
|
() => APP.conference.init({
|
||||||
roomName: room
|
roomName: room
|
||||||
}).catch(error => {
|
}).catch((error: Error) => {
|
||||||
APP.API.notifyConferenceLeft(APP.conference.roomName);
|
APP.API.notifyConferenceLeft(APP.conference.roomName);
|
||||||
logger.error(error);
|
logger.error(error);
|
||||||
}));
|
}));
|
||||||
|
@ -46,7 +42,7 @@ export function connect() {
|
||||||
* request for call feedback.
|
* request for call feedback.
|
||||||
* @returns {Function}
|
* @returns {Function}
|
||||||
*/
|
*/
|
||||||
export function disconnect(requestFeedback: boolean = false) {
|
export function disconnect(requestFeedback = false) {
|
||||||
// XXX For web based version we use conference hanging up logic from the old
|
// XXX For web based version we use conference hanging up logic from the old
|
||||||
// app.
|
// app.
|
||||||
return () => APP.conference.hangup(requestFeedback);
|
return () => APP.conference.hangup(requestFeedback);
|
|
@ -1,5 +1,3 @@
|
||||||
// @flow
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The name of the {@code JitsiConnection} property which identifies the {@code JitsiConference} currently associated
|
* The name of the {@code JitsiConnection} property which identifies the {@code JitsiConference} currently associated
|
||||||
* with it.
|
* with it.
|
|
@ -1,7 +1,6 @@
|
||||||
/* @flow */
|
import { IStateful } from '../app/types';
|
||||||
|
import { toState } from '../redux/functions';
|
||||||
import { toState } from '../redux';
|
import { toURLString } from '../util/uri';
|
||||||
import { toURLString } from '../util';
|
|
||||||
|
|
||||||
import { getURLWithoutParams } from './utils';
|
import { getURLWithoutParams } from './utils';
|
||||||
|
|
||||||
|
@ -13,7 +12,7 @@ import { getURLWithoutParams } from './utils';
|
||||||
* @returns {string|undefined}
|
* @returns {string|undefined}
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
export function getCurrentConferenceUrl(stateful: Function | Object) {
|
export function getCurrentConferenceUrl(stateful: IStateful) {
|
||||||
const state = toState(stateful);
|
const state = toState(stateful);
|
||||||
let currentUrl;
|
let currentUrl;
|
||||||
|
|
||||||
|
@ -40,7 +39,7 @@ export function getCurrentConferenceUrl(stateful: Function | Object) {
|
||||||
* to be stripped.
|
* to be stripped.
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
export function getInviteURL(stateOrGetState: Function | Object): string {
|
export function getInviteURL(stateOrGetState: IStateful): string {
|
||||||
const state = toState(stateOrGetState);
|
const state = toState(stateOrGetState);
|
||||||
let locationURL
|
let locationURL
|
||||||
= state instanceof URL
|
= state instanceof URL
|
||||||
|
@ -75,7 +74,7 @@ export function getInviteURL(stateOrGetState: Function | Object): string {
|
||||||
* @param {Function|Object} stateOrGetState - The redux state or redux's {@code getState} function.
|
* @param {Function|Object} stateOrGetState - The redux state or redux's {@code getState} function.
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
export function isInviteURLReady(stateOrGetState: Function | Object): boolean {
|
export function isInviteURLReady(stateOrGetState: IStateful): boolean {
|
||||||
const state = toState(stateOrGetState);
|
const state = toState(stateOrGetState);
|
||||||
|
|
||||||
return Boolean(state['features/base/connection'].locationURL || state['features/base/config'].locationURL);
|
return Boolean(state['features/base/connection'].locationURL || state['features/base/config'].locationURL);
|
||||||
|
@ -90,6 +89,6 @@ export function isInviteURLReady(stateOrGetState: Function | Object): boolean {
|
||||||
* @returns {string} A string in the form of a JID (i.e.
|
* @returns {string} A string in the form of a JID (i.e.
|
||||||
* {@code user@server.com}).
|
* {@code user@server.com}).
|
||||||
*/
|
*/
|
||||||
export function toJid(id: string, { authdomain, domain }: Object): string {
|
export function toJid(id: string, { authdomain, domain }: { authdomain?: string; domain?: string; }): string {
|
||||||
return id.indexOf('@') >= 0 ? id : `${id}@${authdomain || domain}`;
|
return id.indexOf('@') >= 0 ? id : `${id}@${authdomain || domain}`;
|
||||||
}
|
}
|
|
@ -1,5 +1,3 @@
|
||||||
// @flow
|
|
||||||
|
|
||||||
import { getLogger } from '../logging/functions';
|
import { getLogger } from '../logging/functions';
|
||||||
|
|
||||||
export default getLogger('features/base/connection');
|
export default getLogger('features/base/connection');
|
|
@ -1,8 +1,7 @@
|
||||||
|
import { IStore } from '../../app/types';
|
||||||
import JitsiMeetJS from '../lib-jitsi-meet';
|
import JitsiMeetJS from '../lib-jitsi-meet';
|
||||||
import {
|
import { updateSettings } from '../settings/actions';
|
||||||
getUserSelectedOutputDeviceId,
|
import { getUserSelectedOutputDeviceId } from '../settings/functions.any';
|
||||||
updateSettings
|
|
||||||
} from '../settings';
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ADD_PENDING_DEVICE_REQUEST,
|
ADD_PENDING_DEVICE_REQUEST,
|
||||||
|
@ -55,7 +54,7 @@ const DEVICE_TYPE_TO_SETTINGS_KEYS = {
|
||||||
* request: Object
|
* request: Object
|
||||||
* }}
|
* }}
|
||||||
*/
|
*/
|
||||||
export function addPendingDeviceRequest(request) {
|
export function addPendingDeviceRequest(request: Object) {
|
||||||
return {
|
return {
|
||||||
type: ADD_PENDING_DEVICE_REQUEST,
|
type: ADD_PENDING_DEVICE_REQUEST,
|
||||||
request
|
request
|
||||||
|
@ -68,7 +67,7 @@ export function addPendingDeviceRequest(request) {
|
||||||
* @returns {Function}
|
* @returns {Function}
|
||||||
*/
|
*/
|
||||||
export function configureInitialDevices() {
|
export function configureInitialDevices() {
|
||||||
return (dispatch, getState) => {
|
return (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
|
||||||
const deviceLabels = getDevicesFromURL(getState());
|
const deviceLabels = getDevicesFromURL(getState());
|
||||||
let updateSettingsPromise;
|
let updateSettingsPromise;
|
||||||
|
|
||||||
|
@ -86,9 +85,9 @@ export function configureInitialDevices() {
|
||||||
name: 'setDevice',
|
name: 'setDevice',
|
||||||
device: {
|
device: {
|
||||||
kind: key.toLowerCase(),
|
kind: key.toLowerCase(),
|
||||||
label: deviceLabels[key]
|
label: deviceLabels[key as keyof typeof deviceLabels]
|
||||||
},
|
},
|
||||||
// eslint-disable-next-line no-empty-function
|
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||||
responseCallback() {}
|
responseCallback() {}
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
@ -96,14 +95,17 @@ export function configureInitialDevices() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const newSettings = {};
|
const newSettings: any = {};
|
||||||
|
|
||||||
Object.keys(deviceLabels).forEach(key => {
|
Object.keys(deviceLabels).forEach(key => {
|
||||||
const label = deviceLabels[key];
|
const label = deviceLabels[key as keyof typeof deviceLabels];
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
const deviceId = getDeviceIdByLabel(state, label, key);
|
const deviceId = getDeviceIdByLabel(state, label, key);
|
||||||
|
|
||||||
if (deviceId) {
|
if (deviceId) {
|
||||||
const settingsTranslationMap = DEVICE_TYPE_TO_SETTINGS_KEYS[key];
|
const settingsTranslationMap = DEVICE_TYPE_TO_SETTINGS_KEYS[
|
||||||
|
key as keyof typeof DEVICE_TYPE_TO_SETTINGS_KEYS];
|
||||||
|
|
||||||
newSettings[settingsTranslationMap.currentDeviceId] = deviceId;
|
newSettings[settingsTranslationMap.currentDeviceId] = deviceId;
|
||||||
newSettings[settingsTranslationMap.userSelectedDeviceId] = deviceId;
|
newSettings[settingsTranslationMap.userSelectedDeviceId] = deviceId;
|
||||||
|
@ -135,12 +137,12 @@ export function configureInitialDevices() {
|
||||||
* @returns {Function}
|
* @returns {Function}
|
||||||
*/
|
*/
|
||||||
export function getAvailableDevices() {
|
export function getAvailableDevices() {
|
||||||
return dispatch => new Promise(resolve => {
|
return (dispatch: IStore['dispatch']) => new Promise(resolve => {
|
||||||
const { mediaDevices } = JitsiMeetJS;
|
const { mediaDevices } = JitsiMeetJS;
|
||||||
|
|
||||||
if (mediaDevices.isDeviceListAvailable()
|
if (mediaDevices.isDeviceListAvailable()
|
||||||
&& mediaDevices.isDeviceChangeAvailable()) {
|
&& mediaDevices.isDeviceChangeAvailable()) {
|
||||||
mediaDevices.enumerateDevices(devices => {
|
mediaDevices.enumerateDevices((devices: any) => {
|
||||||
dispatch(updateDeviceList(devices));
|
dispatch(updateDeviceList(devices));
|
||||||
|
|
||||||
resolve(devices);
|
resolve(devices);
|
||||||
|
@ -163,7 +165,7 @@ export function getAvailableDevices() {
|
||||||
* error: Object
|
* error: Object
|
||||||
* }}
|
* }}
|
||||||
*/
|
*/
|
||||||
export function notifyCameraError(error) {
|
export function notifyCameraError(error: Error) {
|
||||||
return {
|
return {
|
||||||
type: NOTIFY_CAMERA_ERROR,
|
type: NOTIFY_CAMERA_ERROR,
|
||||||
error
|
error
|
||||||
|
@ -182,7 +184,7 @@ export function notifyCameraError(error) {
|
||||||
* error: Object
|
* error: Object
|
||||||
* }}
|
* }}
|
||||||
*/
|
*/
|
||||||
export function notifyMicError(error) {
|
export function notifyMicError(error: Error) {
|
||||||
return {
|
return {
|
||||||
type: NOTIFY_MIC_ERROR,
|
type: NOTIFY_MIC_ERROR,
|
||||||
error
|
error
|
||||||
|
@ -211,7 +213,7 @@ export function removePendingDeviceRequests() {
|
||||||
* deviceId: string
|
* deviceId: string
|
||||||
* }}
|
* }}
|
||||||
*/
|
*/
|
||||||
export function setAudioInputDevice(deviceId) {
|
export function setAudioInputDevice(deviceId: string) {
|
||||||
return {
|
return {
|
||||||
type: SET_AUDIO_INPUT_DEVICE,
|
type: SET_AUDIO_INPUT_DEVICE,
|
||||||
deviceId
|
deviceId
|
||||||
|
@ -225,8 +227,8 @@ export function setAudioInputDevice(deviceId) {
|
||||||
* @param {string} deviceId - The id of the new audio input device.
|
* @param {string} deviceId - The id of the new audio input device.
|
||||||
* @returns {Function}
|
* @returns {Function}
|
||||||
*/
|
*/
|
||||||
export function setAudioInputDeviceAndUpdateSettings(deviceId) {
|
export function setAudioInputDeviceAndUpdateSettings(deviceId: string) {
|
||||||
return function(dispatch, getState) {
|
return function(dispatch: IStore['dispatch'], getState: IStore['getState']) {
|
||||||
const deviceLabel = getDeviceLabelById(getState(), deviceId, 'audioInput');
|
const deviceLabel = getDeviceLabelById(getState(), deviceId, 'audioInput');
|
||||||
|
|
||||||
dispatch(setAudioInputDevice(deviceId));
|
dispatch(setAudioInputDevice(deviceId));
|
||||||
|
@ -243,8 +245,8 @@ export function setAudioInputDeviceAndUpdateSettings(deviceId) {
|
||||||
* @param {string} deviceId - The id of the new output device.
|
* @param {string} deviceId - The id of the new output device.
|
||||||
* @returns {Function}
|
* @returns {Function}
|
||||||
*/
|
*/
|
||||||
export function setAudioOutputDevice(deviceId) {
|
export function setAudioOutputDevice(deviceId: string) {
|
||||||
return function(dispatch, getState) {
|
return function(dispatch: IStore['dispatch'], getState: IStore['getState']) {
|
||||||
const deviceLabel = getDeviceLabelById(getState(), deviceId, 'audioOutput');
|
const deviceLabel = getDeviceLabelById(getState(), deviceId, 'audioOutput');
|
||||||
|
|
||||||
return setAudioOutputDeviceId(deviceId, dispatch, true, deviceLabel);
|
return setAudioOutputDeviceId(deviceId, dispatch, true, deviceLabel);
|
||||||
|
@ -260,7 +262,7 @@ export function setAudioOutputDevice(deviceId) {
|
||||||
* deviceId: string
|
* deviceId: string
|
||||||
* }}
|
* }}
|
||||||
*/
|
*/
|
||||||
export function setVideoInputDevice(deviceId) {
|
export function setVideoInputDevice(deviceId: string) {
|
||||||
return {
|
return {
|
||||||
type: SET_VIDEO_INPUT_DEVICE,
|
type: SET_VIDEO_INPUT_DEVICE,
|
||||||
deviceId
|
deviceId
|
||||||
|
@ -274,8 +276,8 @@ export function setVideoInputDevice(deviceId) {
|
||||||
* @param {string} deviceId - The id of the new video input device.
|
* @param {string} deviceId - The id of the new video input device.
|
||||||
* @returns {Function}
|
* @returns {Function}
|
||||||
*/
|
*/
|
||||||
export function setVideoInputDeviceAndUpdateSettings(deviceId) {
|
export function setVideoInputDeviceAndUpdateSettings(deviceId: string) {
|
||||||
return function(dispatch, getState) {
|
return function(dispatch: IStore['dispatch'], getState: IStore['getState']) {
|
||||||
const deviceLabel = getDeviceLabelById(getState(), deviceId, 'videoInput');
|
const deviceLabel = getDeviceLabelById(getState(), deviceId, 'videoInput');
|
||||||
|
|
||||||
dispatch(setVideoInputDevice(deviceId));
|
dispatch(setVideoInputDevice(deviceId));
|
||||||
|
@ -296,7 +298,7 @@ export function setVideoInputDeviceAndUpdateSettings(deviceId) {
|
||||||
* devices: Array<MediaDeviceInfo>
|
* devices: Array<MediaDeviceInfo>
|
||||||
* }}
|
* }}
|
||||||
*/
|
*/
|
||||||
export function updateDeviceList(devices) {
|
export function updateDeviceList(devices: MediaDeviceInfo[]) {
|
||||||
return {
|
return {
|
||||||
type: UPDATE_DEVICE_LIST,
|
type: UPDATE_DEVICE_LIST,
|
||||||
devices
|
devices
|
||||||
|
@ -314,7 +316,7 @@ export function updateDeviceList(devices) {
|
||||||
* oldDevices: Array<MediaDeviceInfo>
|
* oldDevices: Array<MediaDeviceInfo>
|
||||||
* }}
|
* }}
|
||||||
*/
|
*/
|
||||||
export function checkAndNotifyForNewDevice(newDevices, oldDevices) {
|
export function checkAndNotifyForNewDevice(newDevices: MediaDeviceInfo[], oldDevices: MediaDeviceInfo[]) {
|
||||||
return {
|
return {
|
||||||
type: CHECK_AND_NOTIFY_FOR_NEW_DEVICE,
|
type: CHECK_AND_NOTIFY_FOR_NEW_DEVICE,
|
||||||
newDevices,
|
newDevices,
|
||||||
|
@ -331,7 +333,7 @@ export function checkAndNotifyForNewDevice(newDevices, oldDevices) {
|
||||||
* permissions: Object
|
* permissions: Object
|
||||||
* }}
|
* }}
|
||||||
*/
|
*/
|
||||||
export function devicePermissionsChanged(permissions) {
|
export function devicePermissionsChanged(permissions: Object) {
|
||||||
return {
|
return {
|
||||||
type: DEVICE_PERMISSIONS_CHANGED,
|
type: DEVICE_PERMISSIONS_CHANGED,
|
||||||
permissions
|
permissions
|
|
@ -1,12 +1,14 @@
|
||||||
// @flow
|
import { IState } from '../../app/types';
|
||||||
|
|
||||||
import JitsiMeetJS from '../lib-jitsi-meet';
|
import JitsiMeetJS from '../lib-jitsi-meet';
|
||||||
import { updateSettings } from '../settings';
|
import { updateSettings } from '../settings/actions';
|
||||||
import { parseURLParams } from '../util';
|
import { ISettingsState } from '../settings/reducer';
|
||||||
|
import { parseURLParams } from '../util/parseURLParams';
|
||||||
|
|
||||||
import logger from './logger';
|
import logger from './logger';
|
||||||
|
import { IDevicesState } from './reducer';
|
||||||
|
|
||||||
declare var APP: Object;
|
|
||||||
|
declare const APP: any;
|
||||||
|
|
||||||
const webrtcKindToJitsiKindTranslator = {
|
const webrtcKindToJitsiKindTranslator = {
|
||||||
audioinput: 'audioInput',
|
audioinput: 'audioInput',
|
||||||
|
@ -22,14 +24,16 @@ const webrtcKindToJitsiKindTranslator = {
|
||||||
* @returns {boolean} - True if the labels are already initialized and false
|
* @returns {boolean} - True if the labels are already initialized and false
|
||||||
* otherwise.
|
* otherwise.
|
||||||
*/
|
*/
|
||||||
export function areDeviceLabelsInitialized(state: Object) {
|
export function areDeviceLabelsInitialized(state: IState) {
|
||||||
// TODO: Replace with something that doesn't use APP when the conference.js logic is reactified.
|
// TODO: Replace with something that doesn't use APP when the conference.js logic is reactified.
|
||||||
if (APP.conference._localTracksInitialized) {
|
if (APP.conference._localTracksInitialized) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const type of [ 'audioInput', 'audioOutput', 'videoInput' ]) {
|
for (const type of [ 'audioInput', 'audioOutput', 'videoInput' ]) {
|
||||||
if ((state['features/base/devices'].availableDevices[type] || []).find(d => Boolean(d.label))) {
|
const availableDevices = state['features/base/devices'].availableDevices;
|
||||||
|
|
||||||
|
if ((availableDevices[type as keyof typeof availableDevices] || []).find(d => Boolean(d.label))) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -56,14 +60,15 @@ export function getAudioOutputDeviceId() {
|
||||||
* of the preceding types.
|
* of the preceding types.
|
||||||
* @returns {string|undefined}
|
* @returns {string|undefined}
|
||||||
*/
|
*/
|
||||||
export function getDefaultDeviceId(state: Object, kind: string) {
|
export function getDefaultDeviceId(state: IState, kind: string) {
|
||||||
const kindToSearch = webrtcKindToJitsiKindTranslator[kind] || kind;
|
const kindToSearch = webrtcKindToJitsiKindTranslator[kind as keyof typeof webrtcKindToJitsiKindTranslator] || kind;
|
||||||
const defaultDevice = (state['features/base/devices'].availableDevices[kindToSearch] || [])
|
const availableDevices = state['features/base/devices'].availableDevices;
|
||||||
|
const defaultDevice = (availableDevices[kindToSearch as keyof typeof availableDevices] || [])
|
||||||
.find(d => d.deviceId === 'default');
|
.find(d => d.deviceId === 'default');
|
||||||
|
|
||||||
// Find the device with a matching group id.
|
// Find the device with a matching group id.
|
||||||
const matchingDevice = (state['features/base/devices'].availableDevices[kindToSearch] || [])
|
const matchingDevice = (availableDevices[kindToSearch as keyof typeof availableDevices] || [])
|
||||||
.find(d => d.deviceId !== 'default' && d.groupId === defaultDevice.groupId);
|
.find(d => d.deviceId !== 'default' && d.groupId === defaultDevice?.groupId);
|
||||||
|
|
||||||
if (matchingDevice) {
|
if (matchingDevice) {
|
||||||
return matchingDevice.deviceId;
|
return matchingDevice.deviceId;
|
||||||
|
@ -80,11 +85,12 @@ export function getDefaultDeviceId(state: Object, kind: string) {
|
||||||
* of the preceding types.
|
* of the preceding types.
|
||||||
* @returns {string|undefined}
|
* @returns {string|undefined}
|
||||||
*/
|
*/
|
||||||
export function getDeviceIdByLabel(state: Object, label: string, kind: string) {
|
export function getDeviceIdByLabel(state: IState, label: string, kind: string) {
|
||||||
const kindToSearch = webrtcKindToJitsiKindTranslator[kind] || kind;
|
const kindToSearch = webrtcKindToJitsiKindTranslator[kind as keyof typeof webrtcKindToJitsiKindTranslator] || kind;
|
||||||
|
|
||||||
|
const availableDevices = state['features/base/devices'].availableDevices;
|
||||||
const device
|
const device
|
||||||
= (state['features/base/devices'].availableDevices[kindToSearch] || [])
|
= (availableDevices[kindToSearch as keyof typeof availableDevices] || [])
|
||||||
.find(d => d.label === label);
|
.find(d => d.label === label);
|
||||||
|
|
||||||
if (device) {
|
if (device) {
|
||||||
|
@ -102,11 +108,12 @@ export function getDeviceIdByLabel(state: Object, label: string, kind: string) {
|
||||||
* of the preceding types.
|
* of the preceding types.
|
||||||
* @returns {string|undefined}
|
* @returns {string|undefined}
|
||||||
*/
|
*/
|
||||||
export function getDeviceLabelById(state: Object, id: string, kind: string) {
|
export function getDeviceLabelById(state: IState, id: string, kind: string) {
|
||||||
const kindToSearch = webrtcKindToJitsiKindTranslator[kind] || kind;
|
const kindToSearch = webrtcKindToJitsiKindTranslator[kind as keyof typeof webrtcKindToJitsiKindTranslator] || kind;
|
||||||
|
|
||||||
|
const availableDevices = state['features/base/devices'].availableDevices;
|
||||||
const device
|
const device
|
||||||
= (state['features/base/devices'].availableDevices[kindToSearch] || [])
|
= (availableDevices[kindToSearch as keyof typeof availableDevices] || [])
|
||||||
.find(d => d.deviceId === id);
|
.find(d => d.deviceId === id);
|
||||||
|
|
||||||
if (device) {
|
if (device) {
|
||||||
|
@ -120,9 +127,9 @@ export function getDeviceLabelById(state: Object, id: string, kind: string) {
|
||||||
* @param {Object} state - The redux state.
|
* @param {Object} state - The redux state.
|
||||||
* @returns {Object|undefined}
|
* @returns {Object|undefined}
|
||||||
*/
|
*/
|
||||||
export function getDevicesFromURL(state: Object) {
|
export function getDevicesFromURL(state: IState) {
|
||||||
const urlParams
|
const urlParams
|
||||||
= parseURLParams(state['features/base/connection'].locationURL);
|
= parseURLParams(state['features/base/connection'].locationURL ?? '');
|
||||||
|
|
||||||
const audioOutput = urlParams['devices.audioOutput'];
|
const audioOutput = urlParams['devices.audioOutput'];
|
||||||
const videoInput = urlParams['devices.videoInput'];
|
const videoInput = urlParams['devices.videoInput'];
|
||||||
|
@ -132,7 +139,7 @@ export function getDevicesFromURL(state: Object) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
const devices = {};
|
const devices: IDevicesState['availableDevices'] = {};
|
||||||
|
|
||||||
audioOutput && (devices.audioOutput = audioOutput);
|
audioOutput && (devices.audioOutput = audioOutput);
|
||||||
videoInput && (devices.videoInput = videoInput);
|
videoInput && (devices.videoInput = videoInput);
|
||||||
|
@ -150,7 +157,7 @@ export function getDevicesFromURL(state: Object) {
|
||||||
* are device type and the values are arrays with devices matching the device
|
* are device type and the values are arrays with devices matching the device
|
||||||
* type.
|
* type.
|
||||||
*/
|
*/
|
||||||
export function groupDevicesByKind(devices: Object[]): Object {
|
export function groupDevicesByKind(devices: MediaDeviceInfo[]): IDevicesState['availableDevices'] {
|
||||||
return {
|
return {
|
||||||
audioInput: devices.filter(device => device.kind === 'audioinput'),
|
audioInput: devices.filter(device => device.kind === 'audioinput'),
|
||||||
audioOutput: devices.filter(device => device.kind === 'audiooutput'),
|
audioOutput: devices.filter(device => device.kind === 'audiooutput'),
|
||||||
|
@ -165,7 +172,7 @@ export function groupDevicesByKind(devices: Object[]): Object {
|
||||||
* @private
|
* @private
|
||||||
* @returns {Array<MediaDeviceInfo>} Filtered audio devices.
|
* @returns {Array<MediaDeviceInfo>} Filtered audio devices.
|
||||||
*/
|
*/
|
||||||
export function filterAudioDevices(devices: Object[]): Object {
|
export function filterAudioDevices(devices: MediaDeviceInfo[]) {
|
||||||
return devices.filter(device => device.kind === 'audioinput');
|
return devices.filter(device => device.kind === 'audioinput');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -197,8 +204,8 @@ export function formatDeviceLabel(label: string) {
|
||||||
* @param {Object} state - The state of the application.
|
* @param {Object} state - The state of the application.
|
||||||
* @returns {Object[]}
|
* @returns {Object[]}
|
||||||
*/
|
*/
|
||||||
export function getAudioInputDeviceData(state: Object) {
|
export function getAudioInputDeviceData(state: IState) {
|
||||||
return state['features/base/devices'].availableDevices.audioInput.map(
|
return state['features/base/devices'].availableDevices.audioInput?.map(
|
||||||
({ deviceId, label }) => {
|
({ deviceId, label }) => {
|
||||||
return {
|
return {
|
||||||
deviceId,
|
deviceId,
|
||||||
|
@ -213,8 +220,8 @@ export function getAudioInputDeviceData(state: Object) {
|
||||||
* @param {Object} state - The state of the application.
|
* @param {Object} state - The state of the application.
|
||||||
* @returns {Object[]}
|
* @returns {Object[]}
|
||||||
*/
|
*/
|
||||||
export function getAudioOutputDeviceData(state: Object) {
|
export function getAudioOutputDeviceData(state: IState) {
|
||||||
return state['features/base/devices'].availableDevices.audioOutput.map(
|
return state['features/base/devices'].availableDevices.audioOutput?.map(
|
||||||
({ deviceId, label }) => {
|
({ deviceId, label }) => {
|
||||||
return {
|
return {
|
||||||
deviceId,
|
deviceId,
|
||||||
|
@ -229,8 +236,8 @@ export function getAudioOutputDeviceData(state: Object) {
|
||||||
* @param {Object} state - The state of the application.
|
* @param {Object} state - The state of the application.
|
||||||
* @returns {string[]}
|
* @returns {string[]}
|
||||||
*/
|
*/
|
||||||
export function getVideoDeviceIds(state: Object) {
|
export function getVideoDeviceIds(state: IState) {
|
||||||
return state['features/base/devices'].availableDevices.videoInput.map(({ deviceId }) => deviceId);
|
return state['features/base/devices'].availableDevices.videoInput?.map(({ deviceId }) => deviceId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -241,12 +248,14 @@ export function getVideoDeviceIds(state: Object) {
|
||||||
*
|
*
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
export function hasAvailableDevices(state: Object, type: string) {
|
export function hasAvailableDevices(state: IState, type: string) {
|
||||||
if (state['features/base/devices'] === undefined) {
|
if (state['features/base/devices'] === undefined) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return state['features/base/devices'].availableDevices[type].length > 0;
|
const availableDevices = state['features/base/devices'].availableDevices;
|
||||||
|
|
||||||
|
return Number(availableDevices[type as keyof typeof availableDevices]?.length) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -260,10 +269,10 @@ export function hasAvailableDevices(state: Object, type: string) {
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
export function setAudioOutputDeviceId(
|
export function setAudioOutputDeviceId(
|
||||||
newId: string = 'default',
|
newId = 'default',
|
||||||
dispatch: Function,
|
dispatch: Function,
|
||||||
userSelection: boolean = false,
|
userSelection = false,
|
||||||
newLabel: ?string): Promise<*> {
|
newLabel?: string): Promise<any> {
|
||||||
|
|
||||||
logger.debug(`setAudioOutputDevice: ${String(newLabel)}[${newId}]`);
|
logger.debug(`setAudioOutputDevice: ${String(newLabel)}[${newId}]`);
|
||||||
|
|
||||||
|
@ -275,7 +284,7 @@ export function setAudioOutputDeviceId(
|
||||||
|
|
||||||
return JitsiMeetJS.mediaDevices.setAudioOutputDevice(newId)
|
return JitsiMeetJS.mediaDevices.setAudioOutputDevice(newId)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
const newSettings = {
|
const newSettings: Partial<ISettingsState> = {
|
||||||
audioOutputDeviceId: newId,
|
audioOutputDeviceId: newId,
|
||||||
userSelectedAudioOutputDeviceId: undefined,
|
userSelectedAudioOutputDeviceId: undefined,
|
||||||
userSelectedAudioOutputDeviceLabel: undefined
|
userSelectedAudioOutputDeviceLabel: undefined
|
|
@ -29,9 +29,9 @@ const DEFAULT_STATE: IDevicesState = {
|
||||||
|
|
||||||
export interface IDevicesState {
|
export interface IDevicesState {
|
||||||
availableDevices: {
|
availableDevices: {
|
||||||
audioInput: MediaDeviceInfo[];
|
audioInput?: MediaDeviceInfo[];
|
||||||
audioOutput: MediaDeviceInfo[];
|
audioOutput?: MediaDeviceInfo[];
|
||||||
videoInput: MediaDeviceInfo[];
|
videoInput?: MediaDeviceInfo[];
|
||||||
};
|
};
|
||||||
pendingRequests: Object[];
|
pendingRequests: Object[];
|
||||||
permissions: {
|
permissions: {
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
// @flow
|
|
||||||
|
|
||||||
import { UPDATE_FLAGS } from './actionTypes';
|
import { UPDATE_FLAGS } from './actionTypes';
|
||||||
|
|
||||||
/**
|
/**
|
|
@ -1,7 +1,7 @@
|
||||||
// @flow
|
// @ts-ignore
|
||||||
|
|
||||||
import { getAppProp } from '../app';
|
import { getAppProp } from '../app';
|
||||||
import { toState } from '../redux';
|
import { IStateful } from '../app/types';
|
||||||
|
import { toState } from '../redux/functions';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the value of a specific feature flag.
|
* Gets the value of a specific feature flag.
|
||||||
|
@ -14,11 +14,11 @@ import { toState } from '../redux';
|
||||||
* @returns {*} The value of the specified React {@code Component} prop of the
|
* @returns {*} The value of the specified React {@code Component} prop of the
|
||||||
* currently mounted {@code App}.
|
* currently mounted {@code App}.
|
||||||
*/
|
*/
|
||||||
export function getFeatureFlag(stateful: Function | Object, flag: string, defaultValue: any) {
|
export function getFeatureFlag(stateful: IStateful, flag: string, defaultValue?: any) {
|
||||||
const state = toState(stateful)['features/base/flags'];
|
const state = toState(stateful)['features/base/flags'];
|
||||||
|
|
||||||
if (state) {
|
if (state) {
|
||||||
const value = state[flag];
|
const value = state[flag as keyof typeof state];
|
||||||
|
|
||||||
if (typeof value !== 'undefined') {
|
if (typeof value !== 'undefined') {
|
||||||
return value;
|
return value;
|
|
@ -1,5 +1,3 @@
|
||||||
// @flow
|
|
||||||
|
|
||||||
import { ADD_KNOWN_DOMAINS } from './actionTypes';
|
import { ADD_KNOWN_DOMAINS } from './actionTypes';
|
||||||
|
|
||||||
/**
|
/**
|
|
@ -1,10 +1,10 @@
|
||||||
// @flow
|
// @ts-ignore
|
||||||
|
|
||||||
import { getDefaultURL } from '../../app/functions';
|
import { getDefaultURL } from '../../app/functions';
|
||||||
import { APP_WILL_MOUNT } from '../app';
|
import { IStore } from '../../app/types';
|
||||||
import { SET_ROOM } from '../conference';
|
import { APP_WILL_MOUNT } from '../app/actionTypes';
|
||||||
import { MiddlewareRegistry } from '../redux';
|
import { SET_ROOM } from '../conference/actionTypes';
|
||||||
import { parseURIString } from '../util';
|
import MiddlewareRegistry from '../redux/MiddlewareRegistry';
|
||||||
|
import { parseURIString } from '../util/uri';
|
||||||
|
|
||||||
import { addKnownDomains } from './actions';
|
import { addKnownDomains } from './actions';
|
||||||
|
|
||||||
|
@ -32,10 +32,10 @@ MiddlewareRegistry.register(store => next => action => {
|
||||||
* @private
|
* @private
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
function _appWillMount({ dispatch, getState }) {
|
function _appWillMount({ dispatch, getState }: IStore) {
|
||||||
const defaultURL = parseURIString(getDefaultURL(getState));
|
const defaultURL = parseURIString(getDefaultURL(getState));
|
||||||
|
|
||||||
dispatch(addKnownDomains(defaultURL.host));
|
dispatch(addKnownDomains(defaultURL?.host));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -46,7 +46,7 @@ function _appWillMount({ dispatch, getState }) {
|
||||||
* @private
|
* @private
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
function _setRoom({ dispatch, getState }) {
|
function _setRoom({ dispatch, getState }: IStore) {
|
||||||
const { locationURL } = getState()['features/base/connection'];
|
const { locationURL } = getState()['features/base/connection'];
|
||||||
let host;
|
let host;
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
/* @flow */
|
import { IStateful } from '../app/types';
|
||||||
|
import { toState } from '../redux/functions';
|
||||||
import { toState } from '../redux';
|
import { getPropertyValue } from '../settings/functions.any';
|
||||||
import { getPropertyValue } from '../settings';
|
|
||||||
|
|
||||||
import { VIDEO_MUTISM_AUTHORITY } from './constants';
|
import { VIDEO_MUTISM_AUTHORITY } from './constants';
|
||||||
|
|
||||||
|
@ -32,7 +31,7 @@ const START_WITH_AUDIO_VIDEO_MUTED_SOURCES = {
|
||||||
* {@code getState} function.
|
* {@code getState} function.
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
export function isAudioMuted(stateful: Function | Object) {
|
export function isAudioMuted(stateful: IStateful) {
|
||||||
return Boolean(toState(stateful)['features/base/media'].audio.muted);
|
return Boolean(toState(stateful)['features/base/media'].audio.muted);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,7 +42,7 @@ export function isAudioMuted(stateful: Function | Object) {
|
||||||
* {@code getState} function.
|
* {@code getState} function.
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
export function isVideoMutedByAudioOnly(stateful: Function | Object) {
|
export function isVideoMutedByAudioOnly(stateful: IStateful) {
|
||||||
return (
|
return (
|
||||||
_isVideoMutedByAuthority(stateful, VIDEO_MUTISM_AUTHORITY.AUDIO_ONLY));
|
_isVideoMutedByAuthority(stateful, VIDEO_MUTISM_AUTHORITY.AUDIO_ONLY));
|
||||||
}
|
}
|
||||||
|
@ -60,7 +59,7 @@ export function isVideoMutedByAudioOnly(stateful: Function | Object) {
|
||||||
* {@code videoMutismAuthority}, then {@code true}; otherwise, {@code false}.
|
* {@code videoMutismAuthority}, then {@code true}; otherwise, {@code false}.
|
||||||
*/
|
*/
|
||||||
function _isVideoMutedByAuthority(
|
function _isVideoMutedByAuthority(
|
||||||
stateful: Function | Object,
|
stateful: IStateful,
|
||||||
videoMutismAuthority: number) {
|
videoMutismAuthority: number) {
|
||||||
const { muted } = toState(stateful)['features/base/media'].video;
|
const { muted } = toState(stateful)['features/base/media'].video;
|
||||||
|
|
||||||
|
@ -74,7 +73,7 @@ function _isVideoMutedByAuthority(
|
||||||
* @param {Object|Function} stateful - The redux state object or {@code getState} function.
|
* @param {Object|Function} stateful - The redux state object or {@code getState} function.
|
||||||
* @returns {boolean} - The computed startWithAudioMuted value that will be used.
|
* @returns {boolean} - The computed startWithAudioMuted value that will be used.
|
||||||
*/
|
*/
|
||||||
export function getStartWithAudioMuted(stateful: Object | Function) {
|
export function getStartWithAudioMuted(stateful: IStateful) {
|
||||||
return Boolean(getPropertyValue(stateful, 'startWithAudioMuted', START_WITH_AUDIO_VIDEO_MUTED_SOURCES));
|
return Boolean(getPropertyValue(stateful, 'startWithAudioMuted', START_WITH_AUDIO_VIDEO_MUTED_SOURCES));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,7 +83,7 @@ export function getStartWithAudioMuted(stateful: Object | Function) {
|
||||||
* @param {Object|Function} stateful - The redux state object or {@code getState} function.
|
* @param {Object|Function} stateful - The redux state object or {@code getState} function.
|
||||||
* @returns {boolean} - The computed startWithVideoMuted value that will be used.
|
* @returns {boolean} - The computed startWithVideoMuted value that will be used.
|
||||||
*/
|
*/
|
||||||
export function getStartWithVideoMuted(stateful: Object | Function) {
|
export function getStartWithVideoMuted(stateful: IStateful) {
|
||||||
return Boolean(getPropertyValue(stateful, 'startWithVideoMuted', START_WITH_AUDIO_VIDEO_MUTED_SOURCES));
|
return Boolean(getPropertyValue(stateful, 'startWithVideoMuted', START_WITH_AUDIO_VIDEO_MUTED_SOURCES));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,7 +93,7 @@ export function getStartWithVideoMuted(stateful: Object | Function) {
|
||||||
* @param {Function|Object} stateful - The redux store, state, or {@code getState} function.
|
* @param {Function|Object} stateful - The redux store, state, or {@code getState} function.
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
export function isVideoMuted(stateful: Function | Object) {
|
export function isVideoMuted(stateful: IStateful) {
|
||||||
return Boolean(toState(stateful)['features/base/media'].video.muted);
|
return Boolean(toState(stateful)['features/base/media'].video.muted);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,7 +104,7 @@ export function isVideoMuted(stateful: Function | Object) {
|
||||||
* {@code getState} function.
|
* {@code getState} function.
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
export function isVideoMutedByUser(stateful: Function | Object) {
|
export function isVideoMutedByUser(stateful: IStateful) {
|
||||||
return _isVideoMutedByAuthority(stateful, VIDEO_MUTISM_AUTHORITY.USER);
|
return _isVideoMutedByAuthority(stateful, VIDEO_MUTISM_AUTHORITY.USER);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,7 +119,7 @@ export function isVideoMutedByUser(stateful: Function | Object) {
|
||||||
* otherwise, false.
|
* otherwise, false.
|
||||||
*/
|
*/
|
||||||
export function shouldRenderVideoTrack(
|
export function shouldRenderVideoTrack(
|
||||||
videoTrack: ?{ muted: boolean, videoStarted: boolean },
|
videoTrack: { muted: boolean; videoStarted: boolean; },
|
||||||
waitForVideoStarted: boolean) {
|
waitForVideoStarted: boolean) {
|
||||||
return (
|
return (
|
||||||
videoTrack
|
videoTrack
|
|
@ -1,5 +1,3 @@
|
||||||
// @flow
|
|
||||||
|
|
||||||
import { getLogger } from '../logging/functions';
|
import { getLogger } from '../logging/functions';
|
||||||
|
|
||||||
export default getLogger('features/base/media');
|
export default getLogger('features/base/media');
|
|
@ -80,16 +80,16 @@ export function getActiveSpeakersToBeDisplayed(stateful: IStateful) {
|
||||||
}
|
}
|
||||||
let availableSlotsForActiveSpeakers = visibleRemoteParticipants.size;
|
let availableSlotsForActiveSpeakers = visibleRemoteParticipants.size;
|
||||||
|
|
||||||
if (activeSpeakers.has(dominantSpeaker)) {
|
if (activeSpeakers.has(dominantSpeaker ?? '')) {
|
||||||
activeSpeakers.delete(dominantSpeaker);
|
activeSpeakers.delete(dominantSpeaker ?? '');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add dominant speaker to the beginning of the list (not including self) since the active speaker list is always
|
// Add dominant speaker to the beginning of the list (not including self) since the active speaker list is always
|
||||||
// alphabetically sorted.
|
// alphabetically sorted.
|
||||||
if (dominantSpeaker && dominantSpeaker !== getLocalParticipant(state).id) {
|
if (dominantSpeaker && dominantSpeaker !== getLocalParticipant(state)?.id) {
|
||||||
const updatedSpeakers = Array.from(activeSpeakers);
|
const updatedSpeakers = Array.from(activeSpeakers);
|
||||||
|
|
||||||
updatedSpeakers.splice(0, 0, [ dominantSpeaker, getParticipantById(state, dominantSpeaker)?.name ]);
|
updatedSpeakers.splice(0, 0, [ dominantSpeaker, getParticipantById(state, dominantSpeaker)?.name ?? '' ]);
|
||||||
activeSpeakers = new Map(updatedSpeakers);
|
activeSpeakers = new Map(updatedSpeakers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -359,11 +359,11 @@ export function getParticipantDisplayName(stateful: IStateful, id: string): stri
|
||||||
}
|
}
|
||||||
|
|
||||||
if (participant.local) {
|
if (participant.local) {
|
||||||
return defaultLocalDisplayName;
|
return defaultLocalDisplayName ?? '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return defaultRemoteDisplayName;
|
return defaultRemoteDisplayName ?? '';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -439,7 +439,7 @@ export function getPinnedParticipant(stateful: IStateful) {
|
||||||
|
|
||||||
if (stageFilmstrip) {
|
if (stageFilmstrip) {
|
||||||
const { activeParticipants } = state['features/filmstrip'];
|
const { activeParticipants } = state['features/filmstrip'];
|
||||||
const id = activeParticipants.find((p: Participant) => p.pinned)?.participantId;
|
const id = activeParticipants.find(p => p.pinned)?.participantId;
|
||||||
|
|
||||||
return id ? getParticipantById(stateful, id) : undefined;
|
return id ? getParticipantById(stateful, id) : undefined;
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@ export interface Participant {
|
||||||
export interface LocalParticipant extends Participant {
|
export interface LocalParticipant extends Participant {
|
||||||
audioOutputDeviceId?: string;
|
audioOutputDeviceId?: string;
|
||||||
cameraDeviceId?: string;
|
cameraDeviceId?: string;
|
||||||
|
jwtId?: string;
|
||||||
micDeviceId?: string;
|
micDeviceId?: string;
|
||||||
startWithAudioMuted?: boolean;
|
startWithAudioMuted?: boolean;
|
||||||
startWithVideoMuted?: boolean;
|
startWithVideoMuted?: boolean;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { connect as reduxConnect } from 'react-redux';
|
import { connect as reduxConnect } from 'react-redux';
|
||||||
|
|
||||||
|
import { IState } from '../../app/types';
|
||||||
import { IStateful } from '../app/types';
|
import { IStateful } from '../app/types';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -135,7 +136,7 @@ function _set<T extends Object>(
|
||||||
* returned.
|
* returned.
|
||||||
* @returns {Object} The redux state.
|
* @returns {Object} The redux state.
|
||||||
*/
|
*/
|
||||||
export function toState(stateful: IStateful) {
|
export function toState(stateful: IStateful): IState {
|
||||||
if (stateful) {
|
if (stateful) {
|
||||||
if (typeof stateful === 'function') {
|
if (typeof stateful === 'function') {
|
||||||
return stateful();
|
return stateful();
|
||||||
|
@ -149,5 +150,6 @@ export function toState(stateful: IStateful) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
return stateful;
|
return stateful;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
// @flow
|
|
||||||
|
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
|
|
||||||
import MiddlewareRegistry from './MiddlewareRegistry';
|
import MiddlewareRegistry from './MiddlewareRegistry';
|
|
@ -1,4 +1,5 @@
|
||||||
import { SETTINGS_UPDATED } from './actionTypes';
|
import { SETTINGS_UPDATED } from './actionTypes';
|
||||||
|
import { ISettingsState } from './reducer';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an action for when the settings are updated.
|
* Create an action for when the settings are updated.
|
||||||
|
@ -23,7 +24,7 @@ import { SETTINGS_UPDATED } from './actionTypes';
|
||||||
* }
|
* }
|
||||||
* }}
|
* }}
|
||||||
*/
|
*/
|
||||||
export function updateSettings(settings) {
|
export function updateSettings(settings: Partial<ISettingsState>) {
|
||||||
return {
|
return {
|
||||||
type: SETTINGS_UPDATED,
|
type: SETTINGS_UPDATED,
|
||||||
settings
|
settings
|
|
@ -1,5 +1,3 @@
|
||||||
// @flow
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The default server URL to open if no other was specified.
|
* The default server URL to open if no other was specified.
|
||||||
*/
|
*/
|
|
@ -1,10 +1,14 @@
|
||||||
// @flow
|
import { IState } from '../../app/types';
|
||||||
import { CONFIG_WHITELIST } from '../config';
|
import { IStateful } from '../app/types';
|
||||||
import { getParticipantCount } from '../participants';
|
import CONFIG_WHITELIST from '../config/configWhitelist';
|
||||||
import { toState } from '../redux';
|
import { IConfigState } from '../config/reducer';
|
||||||
import { parseURLParams } from '../util';
|
import { IJwtState } from '../jwt/reducer';
|
||||||
|
import { getParticipantCount } from '../participants/functions';
|
||||||
|
import { toState } from '../redux/functions';
|
||||||
|
import { parseURLParams } from '../util/parseURLParams';
|
||||||
|
|
||||||
import { DEFAULT_SERVER_URL } from './constants';
|
import { DEFAULT_SERVER_URL } from './constants';
|
||||||
|
import { ISettingsState } from './reducer';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the effective value of a configuration/preference/setting by applying
|
* Returns the effective value of a configuration/preference/setting by applying
|
||||||
|
@ -23,9 +27,9 @@ import { DEFAULT_SERVER_URL } from './constants';
|
||||||
* @returns {any}
|
* @returns {any}
|
||||||
*/
|
*/
|
||||||
export function getPropertyValue(
|
export function getPropertyValue(
|
||||||
stateful: Object | Function,
|
stateful: IStateful,
|
||||||
propertyName: string,
|
propertyName: string,
|
||||||
sources?: Object
|
sources?: any
|
||||||
) {
|
) {
|
||||||
// Default values don't play nicely with partial objects and we want to make
|
// Default values don't play nicely with partial objects and we want to make
|
||||||
// the function easy to use without exhaustively defining all flags:
|
// the function easy to use without exhaustively defining all flags:
|
||||||
|
@ -45,10 +49,10 @@ export function getPropertyValue(
|
||||||
|
|
||||||
// jwt
|
// jwt
|
||||||
if (sources.jwt) {
|
if (sources.jwt) {
|
||||||
const value = state['features/base/jwt'][propertyName];
|
const value = state['features/base/jwt'][propertyName as keyof IJwtState];
|
||||||
|
|
||||||
if (typeof value !== 'undefined') {
|
if (typeof value !== 'undefined') {
|
||||||
return value[propertyName];
|
return value[propertyName as keyof typeof value];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,7 +60,7 @@ export function getPropertyValue(
|
||||||
if (sources.urlParams) {
|
if (sources.urlParams) {
|
||||||
if (CONFIG_WHITELIST.indexOf(propertyName) !== -1) {
|
if (CONFIG_WHITELIST.indexOf(propertyName) !== -1) {
|
||||||
const urlParams
|
const urlParams
|
||||||
= parseURLParams(state['features/base/connection'].locationURL);
|
= parseURLParams(state['features/base/connection'].locationURL ?? '');
|
||||||
const value = urlParams[`config.${propertyName}`];
|
const value = urlParams[`config.${propertyName}`];
|
||||||
|
|
||||||
if (typeof value !== 'undefined') {
|
if (typeof value !== 'undefined') {
|
||||||
|
@ -67,7 +71,7 @@ export function getPropertyValue(
|
||||||
|
|
||||||
// settings
|
// settings
|
||||||
if (sources.settings) {
|
if (sources.settings) {
|
||||||
const value = state['features/base/settings'][propertyName];
|
const value = state['features/base/settings'][propertyName as keyof ISettingsState];
|
||||||
|
|
||||||
if (typeof value !== 'undefined') {
|
if (typeof value !== 'undefined') {
|
||||||
return value;
|
return value;
|
||||||
|
@ -76,7 +80,7 @@ export function getPropertyValue(
|
||||||
|
|
||||||
// config
|
// config
|
||||||
if (sources.config) {
|
if (sources.config) {
|
||||||
const value = state['features/base/config'][propertyName];
|
const value = state['features/base/config'][propertyName as keyof IConfigState];
|
||||||
|
|
||||||
if (typeof value !== 'undefined') {
|
if (typeof value !== 'undefined') {
|
||||||
return value;
|
return value;
|
||||||
|
@ -93,7 +97,7 @@ export function getPropertyValue(
|
||||||
* {@code getState} function.
|
* {@code getState} function.
|
||||||
* @returns {string} - The currently configured server URL.
|
* @returns {string} - The currently configured server URL.
|
||||||
*/
|
*/
|
||||||
export function getServerURL(stateful: Object | Function) {
|
export function getServerURL(stateful: IStateful) {
|
||||||
const state = toState(stateful);
|
const state = toState(stateful);
|
||||||
|
|
||||||
return state['features/base/settings'].serverURL || DEFAULT_SERVER_URL;
|
return state['features/base/settings'].serverURL || DEFAULT_SERVER_URL;
|
||||||
|
@ -107,7 +111,7 @@ export function getServerURL(stateful: Object | Function) {
|
||||||
* {@code getState} function.
|
* {@code getState} function.
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
export function getUserSelectedCameraDeviceId(stateful: Object | Function) {
|
export function getUserSelectedCameraDeviceId(stateful: IStateful) {
|
||||||
const state = toState(stateful);
|
const state = toState(stateful);
|
||||||
const {
|
const {
|
||||||
userSelectedCameraDeviceId,
|
userSelectedCameraDeviceId,
|
||||||
|
@ -135,7 +139,7 @@ export function getUserSelectedCameraDeviceId(stateful: Object | Function) {
|
||||||
* {@code getState} function.
|
* {@code getState} function.
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
export function getUserSelectedMicDeviceId(stateful: Object | Function) {
|
export function getUserSelectedMicDeviceId(stateful: IStateful) {
|
||||||
const state = toState(stateful);
|
const state = toState(stateful);
|
||||||
const {
|
const {
|
||||||
userSelectedMicDeviceId,
|
userSelectedMicDeviceId,
|
||||||
|
@ -163,7 +167,7 @@ export function getUserSelectedMicDeviceId(stateful: Object | Function) {
|
||||||
* {@code getState} function.
|
* {@code getState} function.
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
export function getUserSelectedOutputDeviceId(stateful: Object | Function) {
|
export function getUserSelectedOutputDeviceId(stateful: IStateful) {
|
||||||
const state = toState(stateful);
|
const state = toState(stateful);
|
||||||
const {
|
const {
|
||||||
userSelectedAudioOutputDeviceId,
|
userSelectedAudioOutputDeviceId,
|
||||||
|
@ -202,13 +206,19 @@ export function getUserSelectedOutputDeviceId(stateful: Object | Function) {
|
||||||
* @private
|
* @private
|
||||||
* @returns {string} The preferred device ID to use for media.
|
* @returns {string} The preferred device ID to use for media.
|
||||||
*/
|
*/
|
||||||
function _getUserSelectedDeviceId(options) {
|
function _getUserSelectedDeviceId(options: {
|
||||||
|
availableDevices: MediaDeviceInfo[] | undefined;
|
||||||
|
matchRegex?: RegExp;
|
||||||
|
replacement?: string;
|
||||||
|
userSelectedDeviceId?: string;
|
||||||
|
userSelectedDeviceLabel?: string;
|
||||||
|
}) {
|
||||||
const {
|
const {
|
||||||
availableDevices,
|
availableDevices,
|
||||||
matchRegex,
|
matchRegex = '',
|
||||||
userSelectedDeviceId,
|
userSelectedDeviceId,
|
||||||
userSelectedDeviceLabel,
|
userSelectedDeviceLabel,
|
||||||
replacement
|
replacement = ''
|
||||||
} = options;
|
} = options;
|
||||||
|
|
||||||
// If there is no label at all, there is no need to fall back to checking
|
// If there is no label at all, there is no need to fall back to checking
|
||||||
|
@ -217,7 +227,7 @@ function _getUserSelectedDeviceId(options) {
|
||||||
return userSelectedDeviceId;
|
return userSelectedDeviceId;
|
||||||
}
|
}
|
||||||
|
|
||||||
const foundMatchingBasedonDeviceId = availableDevices.find(
|
const foundMatchingBasedonDeviceId = availableDevices?.find(
|
||||||
candidate => candidate.deviceId === userSelectedDeviceId);
|
candidate => candidate.deviceId === userSelectedDeviceId);
|
||||||
|
|
||||||
// Prioritize matching the deviceId
|
// Prioritize matching the deviceId
|
||||||
|
@ -228,7 +238,7 @@ function _getUserSelectedDeviceId(options) {
|
||||||
const strippedDeviceLabel
|
const strippedDeviceLabel
|
||||||
= matchRegex ? userSelectedDeviceLabel.replace(matchRegex, replacement)
|
= matchRegex ? userSelectedDeviceLabel.replace(matchRegex, replacement)
|
||||||
: userSelectedDeviceLabel;
|
: userSelectedDeviceLabel;
|
||||||
const foundMatchBasedOnLabel = availableDevices.find(candidate => {
|
const foundMatchBasedOnLabel = availableDevices?.find(candidate => {
|
||||||
const { label } = candidate;
|
const { label } = candidate;
|
||||||
|
|
||||||
if (!label) {
|
if (!label) {
|
||||||
|
@ -253,7 +263,7 @@ function _getUserSelectedDeviceId(options) {
|
||||||
* @param {Object} state - The state of the application.
|
* @param {Object} state - The state of the application.
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
export function shouldHideShareAudioHelper(state: Object): boolean {
|
export function shouldHideShareAudioHelper(state: IState): boolean | undefined {
|
||||||
|
|
||||||
return state['features/base/settings'].hideShareAudioHelper;
|
return state['features/base/settings'].hideShareAudioHelper;
|
||||||
}
|
}
|
||||||
|
@ -264,7 +274,7 @@ export function shouldHideShareAudioHelper(state: Object): boolean {
|
||||||
* @param {Object} state - Redux state.
|
* @param {Object} state - Redux state.
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
export function shouldHideSelfView(state: Object) {
|
export function shouldHideSelfView(state: IState) {
|
||||||
return getParticipantCount(state) === 1 ? false : getHideSelfView(state);
|
return getParticipantCount(state) === 1 ? false : getHideSelfView(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -274,6 +284,6 @@ export function shouldHideSelfView(state: Object) {
|
||||||
* @param {Object} state - Redux state.
|
* @param {Object} state - Redux state.
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
export function getHideSelfView(state: Object) {
|
export function getHideSelfView(state: IState) {
|
||||||
return state['features/base/config'].disableSelfView || state['features/base/settings'].disableSelfView;
|
return state['features/base/config'].disableSelfView || state['features/base/settings'].disableSelfView;
|
||||||
}
|
}
|
|
@ -1,5 +1,3 @@
|
||||||
// @flow
|
|
||||||
|
|
||||||
import { NativeModules } from 'react-native';
|
import { NativeModules } from 'react-native';
|
||||||
import DefaultPreference from 'react-native-default-preference';
|
import DefaultPreference from 'react-native-default-preference';
|
||||||
|
|
||||||
|
@ -31,6 +29,6 @@ export function handleCallIntegrationChange(disabled: boolean) {
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
export function handleCrashReportingChange(disabled: boolean) {
|
export function handleCrashReportingChange(disabled: boolean) {
|
||||||
DefaultPreference.setName('jitsi-default-preferences').then(
|
DefaultPreference.setName('jitsi-default-preferences').then( // @ts-ignore
|
||||||
DefaultPreference.set('isCrashReportingDisabled', disabled.toString()));
|
DefaultPreference.set('isCrashReportingDisabled', disabled.toString()));
|
||||||
}
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
// @flow
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||||
|
import { IState } from '../../app/types';
|
||||||
|
|
||||||
export * from './functions.any';
|
export * from './functions.any';
|
||||||
|
|
||||||
|
@ -8,7 +9,7 @@ export * from './functions.any';
|
||||||
* @param {Object} state - The state of the application.
|
* @param {Object} state - The state of the application.
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
export function getCurrentCameraDeviceId(state: Object) {
|
export function getCurrentCameraDeviceId(state: IState) {
|
||||||
return getDeviceIdByType(state, 'isVideoTrack');
|
return getDeviceIdByType(state, 'isVideoTrack');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,7 +19,7 @@ export function getCurrentCameraDeviceId(state: Object) {
|
||||||
* @param {Object} state - The state of the application.
|
* @param {Object} state - The state of the application.
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
export function getCurrentMicDeviceId(state: Object) {
|
export function getCurrentMicDeviceId(state: IState) {
|
||||||
return getDeviceIdByType(state, 'isAudioTrack');
|
return getDeviceIdByType(state, 'isAudioTrack');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,7 +29,7 @@ export function getCurrentMicDeviceId(state: Object) {
|
||||||
* @param {Object} state - The state of the application.
|
* @param {Object} state - The state of the application.
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
export function getCurrentOutputDeviceId(state: Object) {
|
export function getCurrentOutputDeviceId(state: IState) {
|
||||||
return state['features/base/settings'].audioOutputDeviceId;
|
return state['features/base/settings'].audioOutputDeviceId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,11 +40,11 @@ export function getCurrentOutputDeviceId(state: Object) {
|
||||||
* @param {string} isType - Can be 'isVideoTrack' | 'isAudioTrack'.
|
* @param {string} isType - Can be 'isVideoTrack' | 'isAudioTrack'.
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
function getDeviceIdByType(state: Object, isType: string) {
|
function getDeviceIdByType(state: IState, isType: string) {
|
||||||
const [ deviceId ] = state['features/base/tracks']
|
const [ deviceId ] = state['features/base/tracks']
|
||||||
.map(t => t.jitsiTrack)
|
.map(t => t.jitsiTrack)
|
||||||
.filter(t => t && t.isLocal() && t[isType]())
|
.filter(t => t?.isLocal() && t[isType as keyof typeof t]())
|
||||||
.map(t => t.getDeviceId());
|
.map(t => t.getDeviceId());
|
||||||
|
|
||||||
return deviceId || '';
|
return deviceId || '';
|
||||||
}
|
}
|
||||||
|
@ -54,7 +55,7 @@ function getDeviceIdByType(state: Object, isType: string) {
|
||||||
* @param {Object} state - The state of the application.
|
* @param {Object} state - The state of the application.
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
export function getDisplayName(state: Object): string {
|
export function getDisplayName(state: IState): string {
|
||||||
return state['features/base/settings'].displayName || '';
|
return state['features/base/settings'].displayName || '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,8 +67,8 @@ export function getDisplayName(state: Object): string {
|
||||||
* @param {boolean} disabled - Whether call integration is disabled or not.
|
* @param {boolean} disabled - Whether call integration is disabled or not.
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
export function handleCallIntegrationChange(disabled: boolean) { // eslint-disable-line no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-empty-function, require-jsdoc
|
||||||
}
|
export function handleCallIntegrationChange(disabled: boolean) { }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles changes to the `disableCrashReporting` setting.
|
* Handles changes to the `disableCrashReporting` setting.
|
||||||
|
@ -76,5 +77,5 @@ export function handleCallIntegrationChange(disabled: boolean) { // eslint-disab
|
||||||
* @param {boolean} disabled - Whether crash reporting is disabled or not.
|
* @param {boolean} disabled - Whether crash reporting is disabled or not.
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
export function handleCrashReportingChange(disabled: boolean) { // eslint-disable-line no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-empty-function, require-jsdoc
|
||||||
}
|
export function handleCrashReportingChange(disabled: boolean) { }
|
|
@ -1,5 +1,3 @@
|
||||||
// @flow
|
|
||||||
|
|
||||||
import { getLogger } from '../logging/functions';
|
import { getLogger } from '../logging/functions';
|
||||||
|
|
||||||
export default getLogger('features/base/settings');
|
export default getLogger('features/base/settings');
|
|
@ -1,19 +1,26 @@
|
||||||
// @flow
|
/* eslint-disable lines-around-comment */
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
|
import { AnyAction } from 'redux';
|
||||||
|
|
||||||
|
import { IStore } from '../../app/types';
|
||||||
import { PREJOIN_INITIALIZED } from '../../prejoin/actionTypes';
|
import { PREJOIN_INITIALIZED } from '../../prejoin/actionTypes';
|
||||||
|
// @ts-ignore
|
||||||
import { setPrejoinPageVisibility } from '../../prejoin/actions';
|
import { setPrejoinPageVisibility } from '../../prejoin/actions';
|
||||||
import { APP_WILL_MOUNT } from '../app';
|
import { APP_WILL_MOUNT } from '../app/actionTypes';
|
||||||
import { setAudioOnly } from '../audio-only';
|
import { setAudioOnly } from '../audio-only/actions';
|
||||||
import { SET_LOCATION_URL } from '../connection/actionTypes'; // minimize imports to avoid circular imports
|
import { SET_LOCATION_URL } from '../connection/actionTypes'; // minimize imports to avoid circular imports
|
||||||
|
// @ts-ignore
|
||||||
import { getJwtName } from '../jwt/functions';
|
import { getJwtName } from '../jwt/functions';
|
||||||
import { getLocalParticipant, participantUpdated } from '../participants';
|
import { participantUpdated } from '../participants/actions';
|
||||||
import { MiddlewareRegistry } from '../redux';
|
import { getLocalParticipant } from '../participants/functions';
|
||||||
import { parseURLParams } from '../util';
|
import MiddlewareRegistry from '../redux/MiddlewareRegistry';
|
||||||
|
import { parseURLParams } from '../util/parseURLParams';
|
||||||
|
|
||||||
import { SETTINGS_UPDATED } from './actionTypes';
|
import { SETTINGS_UPDATED } from './actionTypes';
|
||||||
import { updateSettings } from './actions';
|
import { updateSettings } from './actions';
|
||||||
|
// @ts-ignore
|
||||||
import { handleCallIntegrationChange, handleCrashReportingChange } from './functions';
|
import { handleCallIntegrationChange, handleCrashReportingChange } from './functions';
|
||||||
|
import { ISettingsState } from './reducer';
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -57,7 +64,7 @@ MiddlewareRegistry.register(store => next => action => {
|
||||||
* @private
|
* @private
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
function _initializeShowPrejoin({ dispatch, getState }) {
|
function _initializeShowPrejoin({ dispatch, getState }: IStore) {
|
||||||
const { userSelectedSkipPrejoin } = getState()['features/base/settings'];
|
const { userSelectedSkipPrejoin } = getState()['features/base/settings'];
|
||||||
|
|
||||||
if (userSelectedSkipPrejoin) {
|
if (userSelectedSkipPrejoin) {
|
||||||
|
@ -72,7 +79,7 @@ function _initializeShowPrejoin({ dispatch, getState }) {
|
||||||
* @private
|
* @private
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
function _initializeCallIntegration({ getState }) {
|
function _initializeCallIntegration({ getState }: IStore) {
|
||||||
const { disableCallIntegration } = getState()['features/base/settings'];
|
const { disableCallIntegration } = getState()['features/base/settings'];
|
||||||
|
|
||||||
if (typeof disableCallIntegration === 'boolean') {
|
if (typeof disableCallIntegration === 'boolean') {
|
||||||
|
@ -88,7 +95,7 @@ function _initializeCallIntegration({ getState }) {
|
||||||
* @param {string} settingsField - The name of the settings field to map.
|
* @param {string} settingsField - The name of the settings field to map.
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
function _mapSettingsFieldToParticipant(settingsField) {
|
function _mapSettingsFieldToParticipant(settingsField: string) {
|
||||||
switch (settingsField) {
|
switch (settingsField) {
|
||||||
case 'displayName':
|
case 'displayName':
|
||||||
return 'name';
|
return 'name';
|
||||||
|
@ -104,7 +111,9 @@ function _mapSettingsFieldToParticipant(settingsField) {
|
||||||
* @private
|
* @private
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
function _maybeHandleCallIntegrationChange({ settings: { disableCallIntegration } }) {
|
function _maybeHandleCallIntegrationChange({ settings: { disableCallIntegration } }: {
|
||||||
|
settings: Partial<ISettingsState>;
|
||||||
|
}) {
|
||||||
if (typeof disableCallIntegration === 'boolean') {
|
if (typeof disableCallIntegration === 'boolean') {
|
||||||
handleCallIntegrationChange(disableCallIntegration);
|
handleCallIntegrationChange(disableCallIntegration);
|
||||||
}
|
}
|
||||||
|
@ -117,7 +126,9 @@ function _maybeHandleCallIntegrationChange({ settings: { disableCallIntegration
|
||||||
* @private
|
* @private
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
function _maybeCrashReportingChange({ settings: { disableCrashReporting } }) {
|
function _maybeCrashReportingChange({ settings: { disableCrashReporting } }: {
|
||||||
|
settings: Partial<ISettingsState>;
|
||||||
|
}) {
|
||||||
if (typeof disableCrashReporting === 'boolean') {
|
if (typeof disableCrashReporting === 'boolean') {
|
||||||
handleCrashReportingChange(disableCrashReporting);
|
handleCrashReportingChange(disableCrashReporting);
|
||||||
}
|
}
|
||||||
|
@ -132,8 +143,8 @@ function _maybeCrashReportingChange({ settings: { disableCrashReporting } }) {
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
function _maybeSetAudioOnly(
|
function _maybeSetAudioOnly(
|
||||||
{ dispatch },
|
{ dispatch }: IStore,
|
||||||
{ settings: { startAudioOnly } }) {
|
{ settings: { startAudioOnly } }: { settings: Partial<ISettingsState>; }) {
|
||||||
if (typeof startAudioOnly === 'boolean') {
|
if (typeof startAudioOnly === 'boolean') {
|
||||||
dispatch(setAudioOnly(startAudioOnly));
|
dispatch(setAudioOnly(startAudioOnly));
|
||||||
}
|
}
|
||||||
|
@ -146,7 +157,7 @@ function _maybeSetAudioOnly(
|
||||||
* @private
|
* @private
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
function _maybeUpdateDisplayName({ dispatch, getState }) {
|
function _maybeUpdateDisplayName({ dispatch, getState }: IStore) {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
const hasJwt = Boolean(state['features/base/jwt'].jwt);
|
const hasJwt = Boolean(state['features/base/jwt'].jwt);
|
||||||
|
|
||||||
|
@ -169,7 +180,7 @@ function _maybeUpdateDisplayName({ dispatch, getState }) {
|
||||||
* @private
|
* @private
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
function _updateLocalParticipant({ dispatch, getState }, action) {
|
function _updateLocalParticipant({ dispatch, getState }: IStore, action: AnyAction) {
|
||||||
const { settings } = action;
|
const { settings } = action;
|
||||||
const localParticipant = getLocalParticipant(getState());
|
const localParticipant = getLocalParticipant(getState());
|
||||||
const newLocalParticipant = {
|
const newLocalParticipant = {
|
||||||
|
@ -178,12 +189,15 @@ function _updateLocalParticipant({ dispatch, getState }, action) {
|
||||||
|
|
||||||
for (const key in settings) {
|
for (const key in settings) {
|
||||||
if (settings.hasOwnProperty(key)) {
|
if (settings.hasOwnProperty(key)) {
|
||||||
newLocalParticipant[_mapSettingsFieldToParticipant(key)]
|
newLocalParticipant[_mapSettingsFieldToParticipant(key) as keyof typeof newLocalParticipant]
|
||||||
= settings[key];
|
= settings[key];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatch(participantUpdated(newLocalParticipant));
|
dispatch(participantUpdated({
|
||||||
|
...newLocalParticipant,
|
||||||
|
id: newLocalParticipant.id ?? ''
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -194,9 +208,9 @@ function _updateLocalParticipant({ dispatch, getState }, action) {
|
||||||
* @private
|
* @private
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
function _updateLocalParticipantFromUrl({ dispatch, getState }) {
|
function _updateLocalParticipantFromUrl({ dispatch, getState }: IStore) {
|
||||||
const urlParams
|
const urlParams
|
||||||
= parseURLParams(getState()['features/base/connection'].locationURL);
|
= parseURLParams(getState()['features/base/connection'].locationURL ?? '');
|
||||||
const urlEmail = urlParams['userInfo.email'];
|
const urlEmail = urlParams['userInfo.email'];
|
||||||
const urlDisplayName = urlParams['userInfo.displayName'];
|
const urlDisplayName = urlParams['userInfo.displayName'];
|
||||||
|
|
|
@ -52,18 +52,18 @@ const DEFAULT_STATE: ISettingsState = {
|
||||||
|
|
||||||
export interface ISettingsState {
|
export interface ISettingsState {
|
||||||
audioOutputDeviceId?: string | boolean;
|
audioOutputDeviceId?: string | boolean;
|
||||||
avatarURL?: string | boolean;
|
avatarURL?: string;
|
||||||
cameraDeviceId?: string | boolean;
|
cameraDeviceId?: string | boolean;
|
||||||
disableCallIntegration?: boolean;
|
disableCallIntegration?: boolean;
|
||||||
disableCrashReporting?: boolean;
|
disableCrashReporting?: boolean;
|
||||||
disableP2P?: boolean;
|
disableP2P?: boolean;
|
||||||
disableSelfView?: boolean;
|
disableSelfView?: boolean;
|
||||||
displayName?: string | boolean;
|
displayName?: string;
|
||||||
email?: string | boolean;
|
email?: string;
|
||||||
hideShareAudioHelper?: boolean;
|
hideShareAudioHelper?: boolean;
|
||||||
localFlipX?: boolean;
|
localFlipX?: boolean;
|
||||||
micDeviceId?: string | boolean;
|
micDeviceId?: string | boolean;
|
||||||
serverURL?: string | boolean;
|
serverURL?: string;
|
||||||
soundsIncomingMessage?: boolean;
|
soundsIncomingMessage?: boolean;
|
||||||
soundsParticipantJoined?: boolean;
|
soundsParticipantJoined?: boolean;
|
||||||
soundsParticipantKnocking?: boolean;
|
soundsParticipantKnocking?: boolean;
|
||||||
|
@ -73,12 +73,12 @@ export interface ISettingsState {
|
||||||
startAudioOnly?: boolean;
|
startAudioOnly?: boolean;
|
||||||
startWithAudioMuted?: boolean;
|
startWithAudioMuted?: boolean;
|
||||||
startWithVideoMuted?: boolean;
|
startWithVideoMuted?: boolean;
|
||||||
userSelectedAudioOutputDeviceId?: string | boolean;
|
userSelectedAudioOutputDeviceId?: string;
|
||||||
userSelectedAudioOutputDeviceLabel?: string | boolean;
|
userSelectedAudioOutputDeviceLabel?: string;
|
||||||
userSelectedCameraDeviceId?: string | boolean;
|
userSelectedCameraDeviceId?: string;
|
||||||
userSelectedCameraDeviceLabel?: string | boolean;
|
userSelectedCameraDeviceLabel?: string;
|
||||||
userSelectedMicDeviceId?: string | boolean;
|
userSelectedMicDeviceId?: string;
|
||||||
userSelectedMicDeviceLabel?: string | boolean;
|
userSelectedMicDeviceLabel?: string;
|
||||||
userSelectedNotifications?: {
|
userSelectedNotifications?: {
|
||||||
[key: string]: boolean;
|
[key: string]: boolean;
|
||||||
} | boolean;
|
} | boolean;
|
||||||
|
@ -97,6 +97,7 @@ const filterSubtree: ISettingsState = {};
|
||||||
Object.keys(DEFAULT_STATE).forEach(key => {
|
Object.keys(DEFAULT_STATE).forEach(key => {
|
||||||
const key1 = key as keyof typeof filterSubtree;
|
const key1 = key as keyof typeof filterSubtree;
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
filterSubtree[key1] = true;
|
filterSubtree[key1] = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ import {
|
||||||
|
|
||||||
interface ITrack {
|
interface ITrack {
|
||||||
isReceivingData: boolean;
|
isReceivingData: boolean;
|
||||||
jitsiTrack: Object;
|
jitsiTrack: any;
|
||||||
lastMediaEvent?: string;
|
lastMediaEvent?: string;
|
||||||
local: boolean;
|
local: boolean;
|
||||||
mediaType: string;
|
mediaType: string;
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
// @flow
|
|
||||||
|
|
||||||
import { getLogger } from '../logging/functions';
|
import { getLogger } from '../logging/functions';
|
||||||
|
|
||||||
export default getLogger('features/base/util');
|
export default getLogger('features/base/util');
|
|
@ -24,7 +24,7 @@ const blacklist = [ '__proto__', 'constructor', 'prototype' ];
|
||||||
export function parseURLParams(
|
export function parseURLParams(
|
||||||
url: URL | string,
|
url: URL | string,
|
||||||
dontParse = false,
|
dontParse = false,
|
||||||
source = 'hash'): Object {
|
source = 'hash') {
|
||||||
if (typeof url === 'string') {
|
if (typeof url === 'string') {
|
||||||
// eslint-disable-next-line no-param-reassign
|
// eslint-disable-next-line no-param-reassign
|
||||||
url = new URL(url);
|
url = new URL(url);
|
||||||
|
|
|
@ -330,7 +330,7 @@ export function parseStandardURIString(str: string) {
|
||||||
* search: string
|
* search: string
|
||||||
* }}
|
* }}
|
||||||
*/
|
*/
|
||||||
export function parseURIString(uri?: string) {
|
export function parseURIString(uri?: string): any {
|
||||||
if (typeof uri !== 'string') {
|
if (typeof uri !== 'string') {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1276,7 +1276,7 @@ function _mapStateToProps(state: IState, ownProps: any): Object {
|
||||||
|
|
||||||
const { gifUrl: gifSrc } = getGifForParticipant(state, id);
|
const { gifUrl: gifSrc } = getGifForParticipant(state, id);
|
||||||
const mode = getGifDisplayMode(state);
|
const mode = getGifDisplayMode(state);
|
||||||
const participantId = isLocal ? getLocalParticipant(state).id : participantID;
|
const participantId = isLocal ? getLocalParticipant(state)?.id : participantID;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
_audioTrack,
|
_audioTrack,
|
||||||
|
|
|
@ -50,7 +50,7 @@ const AbstractPollAnswer = (Component: ComponentType<AbstractProps>) => (props:
|
||||||
|
|
||||||
const poll: Poll = useSelector((state: IState) => state['features/polls'].polls[pollId]);
|
const poll: Poll = useSelector((state: IState) => state['features/polls'].polls[pollId]);
|
||||||
|
|
||||||
const { id: localId } = useSelector(getLocalParticipant);
|
const { id: localId } = useSelector(getLocalParticipant) ?? { id: '' };
|
||||||
|
|
||||||
const [ checkBoxStates, setCheckBoxState ] = useState(() => {
|
const [ checkBoxStates, setCheckBoxState ] = useState(() => {
|
||||||
if (poll.lastVote !== null) {
|
if (poll.lastVote !== null) {
|
||||||
|
|
|
@ -33,7 +33,7 @@ const PollAnswer = (props: AbstractProps) => {
|
||||||
<>
|
<>
|
||||||
<Text style = { dialogStyles.questionText } >{ poll.question }</Text>
|
<Text style = { dialogStyles.questionText } >{ poll.question }</Text>
|
||||||
<Text style = { dialogStyles.questionOwnerText } >{
|
<Text style = { dialogStyles.questionOwnerText } >{
|
||||||
t('polls.by', { name: localParticipant.name })
|
t('polls.by', { name: localParticipant?.name })
|
||||||
}
|
}
|
||||||
</Text>
|
</Text>
|
||||||
<View style = { chatStyles.answerContent }>
|
<View style = { chatStyles.answerContent }>
|
||||||
|
|
|
@ -5,7 +5,6 @@ import clsx from 'clsx';
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import { WithTranslation } from 'react-i18next';
|
import { WithTranslation } from 'react-i18next';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { bindActionCreators } from 'redux';
|
|
||||||
|
|
||||||
import { createReactionMenuEvent, createToolbarEvent } from '../../../analytics/AnalyticsEvents';
|
import { createReactionMenuEvent, createToolbarEvent } from '../../../analytics/AnalyticsEvents';
|
||||||
import { sendAnalytics } from '../../../analytics/functions';
|
import { sendAnalytics } from '../../../analytics/functions';
|
||||||
|
@ -53,7 +52,7 @@ interface Props extends WithTranslation {
|
||||||
/**
|
/**
|
||||||
* The ID of the local participant.
|
* The ID of the local participant.
|
||||||
*/
|
*/
|
||||||
_localParticipantID: String;
|
_localParticipantID?: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether or not the local participant's hand is raised.
|
* Whether or not the local participant's hand is raised.
|
||||||
|
@ -241,7 +240,7 @@ function mapStateToProps(state: IState) {
|
||||||
const localParticipant = getLocalParticipant(state);
|
const localParticipant = getLocalParticipant(state);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
_localParticipantID: localParticipant.id,
|
_localParticipantID: localParticipant?.id,
|
||||||
_isMobile: isMobileBrowser(),
|
_isMobile: isMobileBrowser(),
|
||||||
_isGifEnabled: isGifEnabled(state),
|
_isGifEnabled: isGifEnabled(state),
|
||||||
_isGifMenuVisible: isGifsMenuOpen(state),
|
_isGifMenuVisible: isGifsMenuOpen(state),
|
||||||
|
@ -258,10 +257,7 @@ function mapStateToProps(state: IState) {
|
||||||
function mapDispatchToProps(dispatch: IStore['dispatch']) {
|
function mapDispatchToProps(dispatch: IStore['dispatch']) {
|
||||||
return {
|
return {
|
||||||
dispatch,
|
dispatch,
|
||||||
...bindActionCreators(
|
_dockToolbox: (dock: boolean) => dispatch(dockToolbox(dock))
|
||||||
{
|
|
||||||
_dockToolbox: dockToolbox
|
|
||||||
}, dispatch)
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -72,8 +72,8 @@ export async function sendReactionsWebhook(state: IState, reactions: Array<strin
|
||||||
sessionId: conference.sessionId,
|
sessionId: conference.sessionId,
|
||||||
submitted: Date.now(),
|
submitted: Date.now(),
|
||||||
reactions,
|
reactions,
|
||||||
participantId: localParticipant.jwtId,
|
participantId: localParticipant?.jwtId,
|
||||||
participantName: localParticipant.name,
|
participantName: localParticipant?.name,
|
||||||
participantJid: jid
|
participantJid: jid
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -204,7 +204,7 @@ MiddlewareRegistry.register((store: IStore) => (next: Function) => (action: any)
|
||||||
const { disableReactionsModeration } = state['features/base/config'];
|
const { disableReactionsModeration } = state['features/base/config'];
|
||||||
|
|
||||||
const customActions = [ 'notify.reactionSounds' ];
|
const customActions = [ 'notify.reactionSounds' ];
|
||||||
const customFunctions = [ () => dispatch(updateSettings({
|
const customFunctions: Function[] = [ () => dispatch(updateSettings({
|
||||||
soundsReactions: false
|
soundsReactions: false
|
||||||
})) ];
|
})) ];
|
||||||
|
|
||||||
|
|
|
@ -303,7 +303,7 @@ function _mapStateToProps(state: IState, ownProps: Partial<Props>) {
|
||||||
_showLocalVideoFlipButton: !disableLocalVideoFlip && videoTrack?.videoType !== 'desktop',
|
_showLocalVideoFlipButton: !disableLocalVideoFlip && videoTrack?.videoType !== 'desktop',
|
||||||
_showHideSelfViewButton: showHideSelfViewButton,
|
_showHideSelfViewButton: showHideSelfViewButton,
|
||||||
_overflowDrawer: overflowDrawer,
|
_overflowDrawer: overflowDrawer,
|
||||||
_localParticipantId: localParticipant.id,
|
_localParticipantId: localParticipant?.id,
|
||||||
_showConnectionInfo: showConnectionInfo,
|
_showConnectionInfo: showConnectionInfo,
|
||||||
_showPinToStage: isStageFilmstripAvailable(state)
|
_showPinToStage: isStageFilmstripAvailable(state)
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue