ref(TS) Convert more base files to TS (#12222)

This commit is contained in:
Robert Pintilii 2022-09-23 11:13:32 +03:00 committed by GitHub
parent 3426960d5a
commit 0bccda2c9e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 154 additions and 141 deletions

View File

@ -1,11 +1,7 @@
// @flow import { IStore } from '../../app/types';
import type { Dispatch } from 'redux';
import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from './actionTypes'; import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from './actionTypes';
declare var APP;
/** /**
* Signals that a specific App will mount (in the terms of React). * Signals that a specific App will mount (in the terms of React).
* *
@ -16,7 +12,7 @@ declare var APP;
* }} * }}
*/ */
export function appWillMount(app: Object) { export function appWillMount(app: Object) {
return (dispatch: Dispatch<any>) => { return (dispatch: IStore['dispatch']) => {
// TODO There was a redux action creator appInit which I did not like // TODO There was a redux action creator appInit which I did not like
// because we already had the redux action creator appWillMount and, // because we already had the redux action creator appWillMount and,
// respectively, the redux action APP_WILL_MOUNT. So I set out to remove // respectively, the redux action APP_WILL_MOUNT. So I set out to remove

View File

@ -1,19 +1,19 @@
// @flow import { toState } from '../redux/functions';
import { toState } from '../redux'; import { IStateful } from './types';
/** /**
* Gets the value of a specific React {@code Component} prop of the currently * Gets the value of a specific React {@code Component} prop of the currently
* mounted {@link App}. * mounted {@link App}.
* *
* @param {Function|Object} stateful - The redux store or {@code getState} * @param {IStateful} stateful - The redux store or {@code getState}
* function. * function.
* @param {string} propName - The name of the React {@code Component} prop of * @param {string} propName - The name of the React {@code Component} prop of
* the currently mounted {@code App} to get. * the currently mounted {@code App} to get.
* @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 getAppProp(stateful: Function | Object, propName: string) { export function getAppProp(stateful: IStateful, propName: string) {
const state = toState(stateful)['features/base/app']; const state = toState(stateful)['features/base/app'];
if (state) { if (state) {

View File

@ -1,5 +1,3 @@
// @flow
import { getLogger } from '../logging/functions'; import { getLogger } from '../logging/functions';
export default getLogger('features/base/app'); export default getLogger('features/base/app');

View File

@ -3,7 +3,7 @@ import ReducerRegistry from '../redux/ReducerRegistry';
import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from './actionTypes'; import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from './actionTypes';
export interface IAppState { export interface IAppState {
app?: Object | undefined; app?: any;
} }
ReducerRegistry.register<IAppState>('features/base/app', (state = {}, action): IAppState => { ReducerRegistry.register<IAppState>('features/base/app', (state = {}, action): IAppState => {

View File

@ -425,7 +425,7 @@ export interface IConfig {
}; };
serviceUrl?: string; serviceUrl?: string;
speakerStatsOrder?: Array<'role' | 'name' | 'hasLeft'>; speakerStatsOrder?: Array<'role' | 'name' | 'hasLeft'>;
startAudioMuted?: boolean; startAudioMuted?: number;
startAudioOnly?: boolean; startAudioOnly?: boolean;
startLastN?: number; startLastN?: number;
startScreenSharing?: boolean; startScreenSharing?: boolean;

View File

@ -1,18 +1,21 @@
/* global APP */ import { AnyAction } from 'redux';
/* eslint-disable lines-around-comment */
// @ts-ignore
import UIEvents from '../../../../service/UI/UIEvents'; import UIEvents from '../../../../service/UI/UIEvents';
import { processExternalDeviceRequest } from '../../device-selection'; import { IStore } from '../../app/types';
import { import { processExternalDeviceRequest } from '../../device-selection/functions';
NOTIFICATION_TIMEOUT_TYPE, import { showNotification, showWarningNotification } from '../../notifications/actions';
showNotification, import { NOTIFICATION_TIMEOUT_TYPE } from '../../notifications/constants';
showWarningNotification // @ts-ignore
} from '../../notifications';
import { replaceAudioTrackById, replaceVideoTrackById, setDeviceStatusWarning } from '../../prejoin/actions'; import { replaceAudioTrackById, replaceVideoTrackById, setDeviceStatusWarning } from '../../prejoin/actions';
// @ts-ignore
import { isPrejoinPageVisible } from '../../prejoin/functions'; import { isPrejoinPageVisible } from '../../prejoin/functions';
import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../app'; import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../app/actionTypes';
import JitsiMeetJS, { JitsiMediaDevicesEvents, JitsiTrackErrors } from '../lib-jitsi-meet'; import JitsiMeetJS, { JitsiMediaDevicesEvents, JitsiTrackErrors } from '../lib-jitsi-meet';
import { MiddlewareRegistry } from '../redux'; import MiddlewareRegistry from '../redux/MiddlewareRegistry';
import { updateSettings } from '../settings'; import { updateSettings } from '../settings/actions';
import { import {
CHECK_AND_NOTIFY_FOR_NEW_DEVICE, CHECK_AND_NOTIFY_FOR_NEW_DEVICE,
@ -35,6 +38,7 @@ import {
setAudioOutputDeviceId setAudioOutputDeviceId
} from './functions'; } from './functions';
import logger from './logger'; import logger from './logger';
import { IDevicesState } from './reducer';
const JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP = { const JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP = {
microphone: { microphone: {
@ -57,7 +61,7 @@ const JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP = {
/** /**
* A listener for device permissions changed reported from lib-jitsi-meet. * A listener for device permissions changed reported from lib-jitsi-meet.
*/ */
let permissionsListener; let permissionsListener: Function | undefined;
/** /**
* Logs the current device list. * Logs the current device list.
@ -65,8 +69,9 @@ let permissionsListener;
* @param {Object} deviceList - Whatever is returned by {@link groupDevicesByKind}. * @param {Object} deviceList - Whatever is returned by {@link groupDevicesByKind}.
* @returns {string} * @returns {string}
*/ */
function logDeviceList(deviceList) { function logDeviceList(deviceList: IDevicesState['availableDevices']) {
const devicesToStr = list => list.map(device => `\t\t${device.label}[${device.deviceId}]`).join('\n'); const devicesToStr = (list?: MediaDeviceInfo[]) =>
list?.map(device => `\t\t${device.label}[${device.deviceId}]`).join('\n');
const audioInputs = devicesToStr(deviceList.audioInput); const audioInputs = devicesToStr(deviceList.audioInput);
const audioOutputs = devicesToStr(deviceList.audioOutput); const audioOutputs = devicesToStr(deviceList.audioOutput);
const videoInputs = devicesToStr(deviceList.videoInput); const videoInputs = devicesToStr(deviceList.videoInput);
@ -87,7 +92,7 @@ function logDeviceList(deviceList) {
MiddlewareRegistry.register(store => next => action => { MiddlewareRegistry.register(store => next => action => {
switch (action.type) { switch (action.type) {
case APP_WILL_MOUNT: { case APP_WILL_MOUNT: {
const _permissionsListener = permissions => { const _permissionsListener = (permissions: Object) => {
store.dispatch(devicePermissionsChanged(permissions)); store.dispatch(devicePermissionsChanged(permissions));
}; };
const { mediaDevices } = JitsiMeetJS; const { mediaDevices } = JitsiMeetJS;
@ -214,7 +219,7 @@ MiddlewareRegistry.register(store => next => action => {
* @private * @private
* @returns {Object} The value returned by {@code next(action)}. * @returns {Object} The value returned by {@code next(action)}.
*/ */
function _processPendingRequests({ dispatch, getState }, next, action) { function _processPendingRequests({ dispatch, getState }: IStore, next: Function, action: AnyAction) {
const result = next(action); const result = next(action);
const state = getState(); const state = getState();
const { pendingRequests } = state['features/base/devices']; const { pendingRequests } = state['features/base/devices'];
@ -223,7 +228,7 @@ function _processPendingRequests({ dispatch, getState }, next, action) {
return result; return result;
} }
pendingRequests.forEach(request => { pendingRequests.forEach((request: any) => {
processExternalDeviceRequest( processExternalDeviceRequest(
dispatch, dispatch,
getState, getState,
@ -248,7 +253,7 @@ function _processPendingRequests({ dispatch, getState }, next, action) {
* @private * @private
* @returns {void} * @returns {void}
*/ */
function _checkAndNotifyForNewDevice(store, newDevices, oldDevices) { function _checkAndNotifyForNewDevice(store: IStore, newDevices: MediaDeviceInfo[], oldDevices: MediaDeviceInfo[]) {
const { dispatch } = store; const { dispatch } = store;
// let's intersect both newDevices and oldDevices and handle thew newly // let's intersect both newDevices and oldDevices and handle thew newly
@ -260,7 +265,9 @@ function _checkAndNotifyForNewDevice(store, newDevices, oldDevices) {
// we group devices by groupID which normally is the grouping by physical device // we group devices by groupID which normally is the grouping by physical device
// plugging in headset we provide normally two device, one input and one output // plugging in headset we provide normally two device, one input and one output
// and we want to show only one notification for this physical audio device // and we want to show only one notification for this physical audio device
const devicesGroupBy = onlyNewDevices.reduce((accumulated, value) => { const devicesGroupBy: {
[key: string]: MediaDeviceInfo[];
} = onlyNewDevices.reduce((accumulated: any, value) => {
accumulated[value.groupId] = accumulated[value.groupId] || []; accumulated[value.groupId] = accumulated[value.groupId] || [];
accumulated[value.groupId].push(value); accumulated[value.groupId].push(value);
@ -314,7 +321,7 @@ function _checkAndNotifyForNewDevice(store, newDevices, oldDevices) {
* @returns {boolean} - Returns true in order notifications to be dismissed. * @returns {boolean} - Returns true in order notifications to be dismissed.
* @private * @private
*/ */
function _useDevice({ dispatch }, devices) { function _useDevice({ dispatch }: IStore, devices: MediaDeviceInfo[]) {
devices.forEach(device => { devices.forEach(device => {
switch (device.kind) { switch (device.kind) {
case 'videoinput': { case 'videoinput': {

View File

@ -1,5 +1,3 @@
// @flow
import { SET_JWT } from './actionTypes'; import { SET_JWT } from './actionTypes';
/** /**
@ -11,7 +9,7 @@ import { SET_JWT } from './actionTypes';
* jwt: (string|undefined) * jwt: (string|undefined)
* }} * }}
*/ */
export function setJWT(jwt: ?string) { export function setJWT(jwt?: string) {
return { return {
type: SET_JWT, type: SET_JWT,
jwt jwt

View File

@ -1,5 +1,3 @@
// @flow
import { SET_LAST_N } from './actionTypes'; import { SET_LAST_N } from './actionTypes';
/** /**

View File

@ -7,7 +7,7 @@ import { VIDEO_QUALITY_LEVELS } from '../../video-quality/constants';
* @param {number} channelLastN - LastN value set for the whole conference. * @param {number} channelLastN - LastN value set for the whole conference.
* @returns {number} LastN value applicable to the quality level specified. * @returns {number} LastN value applicable to the quality level specified.
*/ */
export function getLastNForQualityLevel(qualityLevel, channelLastN) { export function getLastNForQualityLevel(qualityLevel: number, channelLastN: number) {
let lastN = channelLastN; let lastN = channelLastN;
const videoQualityLevels = Object.values(VIDEO_QUALITY_LEVELS); const videoQualityLevels = Object.values(VIDEO_QUALITY_LEVELS);
@ -15,8 +15,8 @@ export function getLastNForQualityLevel(qualityLevel, channelLastN) {
for (const lvl in videoQualityLevels) { for (const lvl in videoQualityLevels) {
if (videoQualityLevels.hasOwnProperty(lvl) if (videoQualityLevels.hasOwnProperty(lvl)
&& qualityLevel === videoQualityLevels[lvl] && qualityLevel === videoQualityLevels[lvl]
&& lvl > 1) { && Number(lvl) > 1) {
lastN = Math.floor(channelLastN / Math.pow(2, lvl - 1)); lastN = Math.floor(channelLastN / Math.pow(2, Number(lvl) - 1));
} }
} }
@ -30,7 +30,7 @@ export function getLastNForQualityLevel(qualityLevel, channelLastN) {
* @param {Object} lastNLimits - The Object to be verified. * @param {Object} lastNLimits - The Object to be verified.
* @returns {undefined|Map<number, number>} * @returns {undefined|Map<number, number>}
*/ */
export function validateLastNLimits(lastNLimits) { export function validateLastNLimits(lastNLimits: any) {
// Checks if only numbers are used // Checks if only numbers are used
if (typeof lastNLimits !== 'object' if (typeof lastNLimits !== 'object'
|| !Object.keys(lastNLimits).length || !Object.keys(lastNLimits).length
@ -64,7 +64,7 @@ export function validateLastNLimits(lastNLimits) {
* @returns {number|undefined} - A "last N" number if there was a corresponding "last N" value matched with the number * @returns {number|undefined} - A "last N" number if there was a corresponding "last N" value matched with the number
* of participants or {@code undefined} otherwise. * of participants or {@code undefined} otherwise.
*/ */
export function limitLastN(participantsCount, lastNLimits) { export function limitLastN(participantsCount: number, lastNLimits: Map<number, number>) {
if (!lastNLimits || !lastNLimits.keys) { if (!lastNLimits || !lastNLimits.keys) {
return undefined; return undefined;
} }

View File

@ -1,5 +1,3 @@
// @flow
import { getLogger } from '../logging/functions'; import { getLogger } from '../logging/functions';
export default getLogger('features/base/lastn'); export default getLogger('features/base/lastn');

View File

@ -1,7 +1,6 @@
// @flow
import debounce from 'lodash/debounce'; import debounce from 'lodash/debounce';
import { IStore } from '../../app/types';
import { SET_FILMSTRIP_ENABLED } from '../../filmstrip/actionTypes'; import { SET_FILMSTRIP_ENABLED } from '../../filmstrip/actionTypes';
import { SELECT_LARGE_VIDEO_PARTICIPANT } from '../../large-video/actionTypes'; import { SELECT_LARGE_VIDEO_PARTICIPANT } from '../../large-video/actionTypes';
import { APP_STATE_CHANGED } from '../../mobile/background/actionTypes'; import { APP_STATE_CHANGED } from '../../mobile/background/actionTypes';
@ -22,7 +21,9 @@ import {
getParticipantById, getParticipantById,
getParticipantCount getParticipantCount
} from '../participants/functions'; } from '../participants/functions';
import { MiddlewareRegistry } from '../redux'; import MiddlewareRegistry from '../redux/MiddlewareRegistry';
// eslint-disable-next-line lines-around-comment
// @ts-ignore
import { isLocalVideoTrackDesktop } from '../tracks/functions'; import { isLocalVideoTrackDesktop } from '../tracks/functions';
import { setLastN } from './actions'; import { setLastN } from './actions';
@ -36,7 +37,7 @@ import logger from './logger';
* @private * @private
* @returns {void} * @returns {void}
*/ */
const _updateLastN = debounce(({ dispatch, getState }) => { const _updateLastN = debounce(({ dispatch, getState }: IStore) => {
const state = getState(); const state = getState();
const { conference } = state['features/base/conference']; const { conference } = state['features/base/conference'];
@ -61,6 +62,7 @@ const _updateLastN = debounce(({ dispatch, getState }) => {
let lastNSelected = config.startLastN ?? (config.channelLastN ?? -1); let lastNSelected = config.startLastN ?? (config.channelLastN ?? -1);
// Apply last N limit based on the # of participants and config settings. // Apply last N limit based on the # of participants and config settings.
// @ts-ignore
const limitedLastN = limitLastN(participantCount, lastNLimits); const limitedLastN = limitLastN(participantCount, lastNLimits);
if (limitedLastN !== undefined) { if (limitedLastN !== undefined) {
@ -81,7 +83,7 @@ const _updateLastN = debounce(({ dispatch, getState }) => {
// view since we make an exception only for screenshare when in audio-only mode. If the user unpins // view since we make an exception only for screenshare when in audio-only mode. If the user unpins
// the screenshare, lastN will be set to 0 here. It will be set to 1 if screenshare has been auto pinned. // the screenshare, lastN will be set to 0 here. It will be set to 1 if screenshare has been auto pinned.
if (!tileViewEnabled && largeVideoParticipant && !largeVideoParticipant.local) { if (!tileViewEnabled && largeVideoParticipant && !largeVideoParticipant.local) {
lastNSelected = (remoteScreenShares || []).includes(largeVideoParticipantId) ? 1 : 0; lastNSelected = (remoteScreenShares || []).includes(largeVideoParticipantId ?? '') ? 1 : 0;
} else { } else {
lastNSelected = 0; lastNSelected = 0;
} }

View File

@ -1,36 +1,35 @@
// @flow
import i18n from 'i18next'; import i18n from 'i18next';
import { batch } from 'react-redux'; import { batch } from 'react-redux';
// @ts-ignore
import UIEvents from '../../../../service/UI/UIEvents'; import UIEvents from '../../../../service/UI/UIEvents';
import { IStore } from '../../app/types';
import { approveParticipant } from '../../av-moderation/actions'; import { approveParticipant } from '../../av-moderation/actions';
import { UPDATE_BREAKOUT_ROOMS } from '../../breakout-rooms/actionTypes'; import { UPDATE_BREAKOUT_ROOMS } from '../../breakout-rooms/actionTypes';
import { getBreakoutRooms } from '../../breakout-rooms/functions'; import { getBreakoutRooms } from '../../breakout-rooms/functions';
import { toggleE2EE } from '../../e2ee/actions'; import { toggleE2EE } from '../../e2ee/actions';
import { MAX_MODE } from '../../e2ee/constants'; import { MAX_MODE } from '../../e2ee/constants';
import { showNotification } from '../../notifications/actions';
import { import {
LOCAL_RECORDING_NOTIFICATION_ID, LOCAL_RECORDING_NOTIFICATION_ID,
NOTIFICATION_TIMEOUT_TYPE, NOTIFICATION_TIMEOUT_TYPE,
RAISE_HAND_NOTIFICATION_ID, RAISE_HAND_NOTIFICATION_ID
showNotification } from '../../notifications/constants';
} from '../../notifications';
import { isForceMuted } from '../../participants-pane/functions'; import { isForceMuted } from '../../participants-pane/functions';
import { CALLING, INVITED } from '../../presence-status'; import { CALLING, INVITED } from '../../presence-status/constants';
import { RAISE_HAND_SOUND_ID } from '../../reactions/constants'; import { RAISE_HAND_SOUND_ID } from '../../reactions/constants';
import { RECORDING_OFF_SOUND_ID, RECORDING_ON_SOUND_ID } from '../../recording'; import { RECORDING_OFF_SOUND_ID, RECORDING_ON_SOUND_ID } from '../../recording/constants';
import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../app'; import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../app/actionTypes';
import { import { CONFERENCE_WILL_JOIN } from '../conference/actionTypes';
CONFERENCE_WILL_JOIN, import { forEachConference, getCurrentConference } from '../conference/functions';
forEachConference, import { IJitsiConference } from '../conference/reducer';
getCurrentConference import { SET_CONFIG } from '../config/actionTypes';
} from '../conference';
import { SET_CONFIG } from '../config';
import { getDisableRemoveRaisedHandOnFocus } from '../config/functions.any'; import { getDisableRemoveRaisedHandOnFocus } from '../config/functions.any';
import { JitsiConferenceEvents } from '../lib-jitsi-meet'; import { JitsiConferenceEvents } from '../lib-jitsi-meet';
import { MEDIA_TYPE } from '../media'; import { MEDIA_TYPE } from '../media/constants';
import { MiddlewareRegistry, StateListenerRegistry } from '../redux'; import MiddlewareRegistry from '../redux/MiddlewareRegistry';
import { playSound, registerSound, unregisterSound } from '../sounds'; import StateListenerRegistry from '../redux/StateListenerRegistry';
import { playSound, registerSound, unregisterSound } from '../sounds/actions';
import { import {
DOMINANT_SPEAKER_CHANGED, DOMINANT_SPEAKER_CHANGED,
@ -79,9 +78,9 @@ import {
} from './functions'; } from './functions';
import logger from './logger'; import logger from './logger';
import { PARTICIPANT_JOINED_FILE, PARTICIPANT_LEFT_FILE } from './sounds'; import { PARTICIPANT_JOINED_FILE, PARTICIPANT_LEFT_FILE } from './sounds';
import './subscriber'; import { IJitsiParticipant } from './types';
declare var APP: Object; import './subscriber';
/** /**
* Middleware that captures CONFERENCE_JOINED and CONFERENCE_LEFT actions and * Middleware that captures CONFERENCE_JOINED and CONFERENCE_LEFT actions and
@ -128,8 +127,7 @@ MiddlewareRegistry.register(store => next => action => {
const participant = getDominantSpeakerParticipant(state); const participant = getDominantSpeakerParticipant(state);
if ( if (
participant participant?.local
&& participant.local
&& hasRaisedHand(participant) && hasRaisedHand(participant)
&& action.level > LOWER_HAND_AUDIO_LEVEL && action.level > LOWER_HAND_AUDIO_LEVEL
&& !getDisableRemoveRaisedHandOnFocus(state) && !getDisableRemoveRaisedHandOnFocus(state)
@ -142,14 +140,14 @@ MiddlewareRegistry.register(store => next => action => {
case GRANT_MODERATOR: { case GRANT_MODERATOR: {
const { conference } = store.getState()['features/base/conference']; const { conference } = store.getState()['features/base/conference'];
conference.grantOwner(action.id); conference?.grantOwner(action.id);
break; break;
} }
case KICK_PARTICIPANT: { case KICK_PARTICIPANT: {
const { conference } = store.getState()['features/base/conference']; const { conference } = store.getState()['features/base/conference'];
conference.kickParticipant(action.id); conference?.kickParticipant(action.id);
break; break;
} }
@ -164,13 +162,13 @@ MiddlewareRegistry.register(store => next => action => {
// participant is uniquely identified by the very fact that there is // participant is uniquely identified by the very fact that there is
// only one local participant. // only one local participant.
id: localId, id: localId ?? '',
local: true, local: true,
raisedHandTimestamp raisedHandTimestamp
})); }));
store.dispatch(raiseHandUpdateQueue({ store.dispatch(raiseHandUpdateQueue({
id: localId, id: localId ?? '',
raisedHandTimestamp raisedHandTimestamp
})); }));
@ -188,14 +186,16 @@ MiddlewareRegistry.register(store => next => action => {
const { deploymentInfo } = state['features/base/config']; const { deploymentInfo } = state['features/base/config'];
// if there userRegion set let's use it for the local participant // if there userRegion set let's use it for the local participant
if (deploymentInfo && deploymentInfo.userRegion) { if (deploymentInfo?.userRegion) {
const localId = getLocalParticipant(state)?.id; const localId = getLocalParticipant(state)?.id;
store.dispatch(participantUpdated({ if (localId) {
id: localId, store.dispatch(participantUpdated({
local: true, id: localId,
region: deploymentInfo.userRegion local: true,
})); region: deploymentInfo.userRegion
}));
}
} }
return result; return result;
@ -207,7 +207,7 @@ MiddlewareRegistry.register(store => next => action => {
const localId = getLocalParticipant(state)?.id; const localId = getLocalParticipant(state)?.id;
const { localRecording } = state['features/base/config']; const { localRecording } = state['features/base/config'];
if (localRecording?.notifyAllParticipants && !onlySelf) { if (localRecording?.notifyAllParticipants && !onlySelf && localId) {
store.dispatch(participantUpdated({ store.dispatch(participantUpdated({
// XXX Only the local participant is allowed to update without // XXX Only the local participant is allowed to update without
// stating the JitsiConference instance (i.e. participant property // stating the JitsiConference instance (i.e. participant property
@ -227,7 +227,7 @@ MiddlewareRegistry.register(store => next => action => {
case MUTE_REMOTE_PARTICIPANT: { case MUTE_REMOTE_PARTICIPANT: {
const { conference } = store.getState()['features/base/conference']; const { conference } = store.getState()['features/base/conference'];
conference.muteParticipant(action.id, action.mediaType); conference?.muteParticipant(action.id, action.mediaType);
break; break;
} }
@ -319,7 +319,7 @@ MiddlewareRegistry.register(store => next => action => {
if (breakoutRoom) { if (breakoutRoom) {
const rooms = getBreakoutRooms(state); const rooms = getBreakoutRooms(state);
const roomCounter = state['features/breakout-rooms'].roomCounter; const roomCounter = state['features/breakout-rooms'].roomCounter;
const newRooms = {}; const newRooms: any = {};
Object.entries(rooms).forEach(([ key, r ]) => { Object.entries(rooms).forEach(([ key, r ]) => {
const participants = r?.participants || {}; const participants = r?.participants || {};
@ -393,7 +393,7 @@ StateListenerRegistry.register(
/* listener */ ({ leaving }, { dispatch, getState }) => { /* listener */ ({ leaving }, { dispatch, getState }) => {
const state = getState(); const state = getState();
const localParticipant = getLocalParticipant(state); const localParticipant = getLocalParticipant(state);
let id; let id: string;
if (!localParticipant if (!localParticipant
|| (id = localParticipant.id) || (id = localParticipant.id)
@ -421,37 +421,41 @@ StateListenerRegistry.register(
state => state['features/base/conference'].conference, state => state['features/base/conference'].conference,
(conference, store) => { (conference, store) => {
if (conference) { if (conference) {
const propertyHandlers = { const propertyHandlers: {
'e2ee.enabled': (participant, value) => _e2eeUpdated(store, conference, participant.getId(), value), [key: string]: Function;
'features_e2ee': (participant, value) => } = {
'e2ee.enabled': (participant: IJitsiParticipant, value: string) =>
_e2eeUpdated(store, conference, participant.getId(), value),
'features_e2ee': (participant: IJitsiParticipant, value: boolean) =>
store.dispatch(participantUpdated({ store.dispatch(participantUpdated({
conference, conference,
id: participant.getId(), id: participant.getId(),
e2eeSupported: value e2eeSupported: value
})), })),
'features_jigasi': (participant, value) => 'features_jigasi': (participant: IJitsiParticipant, value: boolean) =>
store.dispatch(participantUpdated({ store.dispatch(participantUpdated({
conference, conference,
id: participant.getId(), id: participant.getId(),
isJigasi: value isJigasi: value
})), })),
'features_screen-sharing': (participant, value) => // eslint-disable-line no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
'features_screen-sharing': (participant: IJitsiParticipant, value: string) =>
store.dispatch(participantUpdated({ store.dispatch(participantUpdated({
conference, conference,
id: participant.getId(), id: participant.getId(),
features: { 'screen-sharing': true } features: { 'screen-sharing': true }
})), })),
'localRecording': (participant, value) => 'localRecording': (participant: IJitsiParticipant, value: string) =>
_localRecordingUpdated(store, conference, participant.getId(), value), _localRecordingUpdated(store, conference, participant.getId(), value),
'raisedHand': (participant, value) => 'raisedHand': (participant: IJitsiParticipant, value: string) =>
_raiseHandUpdated(store, conference, participant.getId(), value), _raiseHandUpdated(store, conference, participant.getId(), value),
'region': (participant, value) => 'region': (participant: IJitsiParticipant, value: string) =>
store.dispatch(participantUpdated({ store.dispatch(participantUpdated({
conference, conference,
id: participant.getId(), id: participant.getId(),
region: value region: value
})), })),
'remoteControlSessionStatus': (participant, value) => 'remoteControlSessionStatus': (participant: IJitsiParticipant, value: boolean) =>
store.dispatch(participantUpdated({ store.dispatch(participantUpdated({
conference, conference,
id: participant.getId(), id: participant.getId(),
@ -460,12 +464,12 @@ StateListenerRegistry.register(
}; };
// update properties for the participants that are already in the conference // update properties for the participants that are already in the conference
conference.getParticipants().forEach(participant => { conference.getParticipants().forEach((participant: any) => {
Object.keys(propertyHandlers).forEach(propertyName => { Object.keys(propertyHandlers).forEach(propertyName => {
const value = participant.getProperty(propertyName); const value = participant.getProperty(propertyName);
if (value !== undefined) { if (value !== undefined) {
propertyHandlers[propertyName](participant, value); propertyHandlers[propertyName as keyof typeof propertyHandlers](participant, value);
} }
}); });
}); });
@ -473,17 +477,17 @@ StateListenerRegistry.register(
// We joined a conference // We joined a conference
conference.on( conference.on(
JitsiConferenceEvents.PARTICIPANT_PROPERTY_CHANGED, JitsiConferenceEvents.PARTICIPANT_PROPERTY_CHANGED,
(participant, propertyName, oldValue, newValue) => { (participant: IJitsiParticipant, propertyName: string, oldValue: string, newValue: string) => {
if (propertyHandlers.hasOwnProperty(propertyName)) { if (propertyHandlers.hasOwnProperty(propertyName)) {
propertyHandlers[propertyName](participant, newValue); propertyHandlers[propertyName](participant, newValue);
} }
}); });
} else { } else {
const localParticipantId = getLocalParticipant(store.getState).id; const localParticipantId = getLocalParticipant(store.getState)?.id;
// We left the conference, the local participant must be updated. // We left the conference, the local participant must be updated.
_e2eeUpdated(store, conference, localParticipantId, false); _e2eeUpdated(store, conference, localParticipantId ?? '', false);
_raiseHandUpdated(store, conference, localParticipantId, 0); _raiseHandUpdated(store, conference, localParticipantId ?? '', 0);
} }
} }
); );
@ -497,7 +501,8 @@ StateListenerRegistry.register(
* @param {boolean} newValue - The new value of the E2EE enabled status. * @param {boolean} newValue - The new value of the E2EE enabled status.
* @returns {void} * @returns {void}
*/ */
function _e2eeUpdated({ getState, dispatch }, conference, participantId, newValue) { function _e2eeUpdated({ getState, dispatch }: IStore, conference: IJitsiConference,
participantId: string, newValue: string | boolean) {
const e2eeEnabled = newValue === 'true'; const e2eeEnabled = newValue === 'true';
const { e2ee = {} } = getState()['features/base/config']; const { e2ee = {} } = getState()['features/base/config'];
@ -530,11 +535,12 @@ function _e2eeUpdated({ getState, dispatch }, conference, participantId, newValu
* @private * @private
* @returns {Object} The value returned by {@code next(action)}. * @returns {Object} The value returned by {@code next(action)}.
*/ */
function _localParticipantJoined({ getState, dispatch }, next, action) { function _localParticipantJoined({ getState, dispatch }: IStore, next: Function, action: any) {
const result = next(action); const result = next(action);
const settings = getState()['features/base/settings']; const settings = getState()['features/base/settings'];
// @ts-ignore
dispatch(localParticipantJoined({ dispatch(localParticipantJoined({
avatarURL: settings.avatarURL, avatarURL: settings.avatarURL,
email: settings.email, email: settings.email,
@ -555,7 +561,7 @@ function _localParticipantJoined({ getState, dispatch }, next, action) {
* @private * @private
* @returns {Object} The value returned by {@code next(action)}. * @returns {Object} The value returned by {@code next(action)}.
*/ */
function _localParticipantLeft({ dispatch }, next, action) { function _localParticipantLeft({ dispatch }: IStore, next: Function, action: any) {
const result = next(action); const result = next(action);
dispatch(localParticipantLeft()); dispatch(localParticipantLeft());
@ -572,7 +578,7 @@ function _localParticipantLeft({ dispatch }, next, action) {
* @private * @private
* @returns {void} * @returns {void}
*/ */
function _maybePlaySounds({ getState, dispatch }, action) { function _maybePlaySounds({ getState, dispatch }: IStore, action: any) {
const state = getState(); const state = getState();
const { startAudioMuted } = state['features/base/config']; const { startAudioMuted } = state['features/base/config'];
const { soundsParticipantJoined: joinSound, soundsParticipantLeft: leftSound } = state['features/base/settings']; const { soundsParticipantJoined: joinSound, soundsParticipantLeft: leftSound } = state['features/base/settings'];
@ -617,7 +623,7 @@ function _maybePlaySounds({ getState, dispatch }, action) {
* @private * @private
* @returns {Object} The value returned by {@code next(action)}. * @returns {Object} The value returned by {@code next(action)}.
*/ */
function _participantJoinedOrUpdated(store, next, action) { function _participantJoinedOrUpdated(store: IStore, next: Function, action: any) {
const { dispatch, getState } = store; const { dispatch, getState } = store;
const { overwrittenNameList } = store.getState()['features/base/participants']; const { overwrittenNameList } = store.getState()['features/base/participants'];
const { participant: { const { participant: {
@ -639,7 +645,7 @@ function _participantJoinedOrUpdated(store, next, action) {
const rHand = parseInt(raisedHandTimestamp, 10); const rHand = parseInt(raisedHandTimestamp, 10);
// Send raisedHand signalling only if there is a change // Send raisedHand signalling only if there is a change
if (conference && rHand !== getLocalParticipant(getState()).raisedHandTimestamp) { if (conference && rHand !== getLocalParticipant(getState())?.raisedHandTimestamp) {
conference.setLocalParticipantProperty('raisedHand', rHand); conference.setLocalParticipantProperty('raisedHand', rHand);
} }
} }
@ -657,7 +663,7 @@ function _participantJoinedOrUpdated(store, next, action) {
// Send localRecording signalling only if there is a change // Send localRecording signalling only if there is a change
if (conference if (conference
&& localRecording !== getLocalParticipant(getState()).localRecording) { && localRecording !== getLocalParticipant(getState())?.localRecording) {
conference.setLocalParticipantProperty('localRecording', localRecording); conference.setLocalParticipantProperty('localRecording', localRecording);
} }
} }
@ -673,12 +679,12 @@ function _participantJoinedOrUpdated(store, next, action) {
const { disableThirdPartyRequests } = getState()['features/base/config']; const { disableThirdPartyRequests } = getState()['features/base/config'];
if (!disableThirdPartyRequests && (avatarURL || email || id || name)) { if (!disableThirdPartyRequests && (avatarURL || email || id || name)) {
const participantId = !id && local ? getLocalParticipant(getState()).id : id; const participantId = !id && local ? getLocalParticipant(getState())?.id : id;
const updatedParticipant = getParticipantById(getState(), participantId); const updatedParticipant = getParticipantById(getState(), participantId);
getFirstLoadableAvatarUrl(updatedParticipant, store) getFirstLoadableAvatarUrl(updatedParticipant ?? { id: '' }, store)
.then(urlData => { .then((urlData?: { isUsingCORS: boolean; src: string; }) => {
dispatch(setLoadableAvatarUrl(participantId, urlData?.src, urlData?.isUsingCORS)); dispatch(setLoadableAvatarUrl(participantId, urlData?.src ?? '', Boolean(urlData?.isUsingCORS)));
}); });
} }
} }
@ -703,7 +709,8 @@ function _participantJoinedOrUpdated(store, next, action) {
* @param {boolean} newValue - The new value of the local recording status. * @param {boolean} newValue - The new value of the local recording status.
* @returns {void} * @returns {void}
*/ */
function _localRecordingUpdated({ dispatch, getState }, conference, participantId, newValue) { function _localRecordingUpdated({ dispatch, getState }: IStore, conference: IJitsiConference,
participantId: string, newValue: string) {
const state = getState(); const state = getState();
dispatch(participantUpdated({ dispatch(participantUpdated({
@ -732,7 +739,8 @@ function _localRecordingUpdated({ dispatch, getState }, conference, participantI
* @param {boolean} newValue - The new value of the raise hand status. * @param {boolean} newValue - The new value of the raise hand status.
* @returns {void} * @returns {void}
*/ */
function _raiseHandUpdated({ dispatch, getState }, conference, participantId, newValue) { function _raiseHandUpdated({ dispatch, getState }: IStore, conference: IJitsiConference,
participantId: string, newValue: string | number) {
let raisedHandTimestamp; let raisedHandTimestamp;
switch (newValue) { switch (newValue) {
@ -744,7 +752,7 @@ function _raiseHandUpdated({ dispatch, getState }, conference, participantId, ne
raisedHandTimestamp = Date.now(); raisedHandTimestamp = Date.now();
break; break;
default: default:
raisedHandTimestamp = parseInt(newValue, 10); raisedHandTimestamp = parseInt(`${newValue}`, 10);
} }
const state = getState(); const state = getState();
@ -811,7 +819,7 @@ function _raiseHandUpdated({ dispatch, getState }, conference, participantId, ne
* @private * @private
* @returns {void} * @returns {void}
*/ */
function _registerSounds({ dispatch }) { function _registerSounds({ dispatch }: IStore) {
dispatch( dispatch(
registerSound(PARTICIPANT_JOINED_SOUND_ID, PARTICIPANT_JOINED_FILE)); registerSound(PARTICIPANT_JOINED_SOUND_ID, PARTICIPANT_JOINED_FILE));
dispatch(registerSound(PARTICIPANT_LEFT_SOUND_ID, PARTICIPANT_LEFT_FILE)); dispatch(registerSound(PARTICIPANT_LEFT_SOUND_ID, PARTICIPANT_LEFT_FILE));
@ -824,7 +832,7 @@ function _registerSounds({ dispatch }) {
* @private * @private
* @returns {void} * @returns {void}
*/ */
function _unregisterSounds({ dispatch }) { function _unregisterSounds({ dispatch }: IStore) {
dispatch(unregisterSound(PARTICIPANT_JOINED_SOUND_ID)); dispatch(unregisterSound(PARTICIPANT_JOINED_SOUND_ID));
dispatch(unregisterSound(PARTICIPANT_LEFT_SOUND_ID)); dispatch(unregisterSound(PARTICIPANT_LEFT_SOUND_ID));
} }

View File

@ -5,6 +5,7 @@ export interface Participant {
connectionStatus?: string; connectionStatus?: string;
displayName?: string; displayName?: string;
dominantSpeaker?: boolean; dominantSpeaker?: boolean;
e2eeEnabled?: boolean;
e2eeSupported?: boolean; e2eeSupported?: boolean;
email?: string; email?: string;
features?: { features?: {
@ -42,3 +43,7 @@ export interface LocalParticipant extends Participant {
userSelectedMicDeviceId?: string; userSelectedMicDeviceId?: string;
userSelectedMicDeviceLabel?: string; userSelectedMicDeviceLabel?: string;
} }
export interface IJitsiParticipant {
getId: () => string;
}

View File

@ -68,7 +68,7 @@ export function _removeAudioElement(soundId: string) {
* which was used in {@link registerSound} to register the sound). * which was used in {@link registerSound} to register the sound).
* @returns {Function} * @returns {Function}
*/ */
export function playSound(soundId: string): Object { export function playSound(soundId: string) {
return (dispatch: Function, getState: Function) => { return (dispatch: Function, getState: Function) => {
const disabledSounds = getDisabledSounds(getState()); const disabledSounds = getDisabledSounds(getState());
@ -103,7 +103,7 @@ export function playSound(soundId: string): Object {
* }} * }}
*/ */
export function registerSound( export function registerSound(
soundId: string, soundName: string, options: Object = {}): Object { soundId: string, soundName: string, options: Object = {}) {
return { return {
type: REGISTER_SOUND, type: REGISTER_SOUND,
soundId, soundId,
@ -122,7 +122,7 @@ export function registerSound(
* soundId: string * soundId: string
* }} * }}
*/ */
export function stopSound(soundId: string): Object { export function stopSound(soundId: string) {
return { return {
type: STOP_SOUND, type: STOP_SOUND,
soundId soundId
@ -141,7 +141,7 @@ export function stopSound(soundId: string): Object {
* soundId: string * soundId: string
* }} * }}
*/ */
export function unregisterSound(soundId: string): Object { export function unregisterSound(soundId: string) {
return { return {
type: UNREGISTER_SOUND, type: UNREGISTER_SOUND,
soundId soundId

View File

@ -1,37 +1,37 @@
// @flow import { IStore } from '../app/types';
import { IStateful } from '../base/app/types';
import type { Dispatch } from 'redux';
import { import {
addPendingDeviceRequest, addPendingDeviceRequest,
areDeviceLabelsInitialized,
getAudioOutputDeviceId,
getAvailableDevices, getAvailableDevices,
getDeviceIdByLabel,
groupDevicesByKind,
setAudioInputDeviceAndUpdateSettings, setAudioInputDeviceAndUpdateSettings,
setAudioOutputDevice, setAudioOutputDevice,
setVideoInputDeviceAndUpdateSettings setVideoInputDeviceAndUpdateSettings
} from '../base/devices'; } from '../base/devices/actions';
import {
areDeviceLabelsInitialized,
getAudioOutputDeviceId,
getDeviceIdByLabel,
groupDevicesByKind
} from '../base/devices/functions';
import { isIosMobileBrowser } from '../base/environment/utils'; import { isIosMobileBrowser } from '../base/environment/utils';
import JitsiMeetJS from '../base/lib-jitsi-meet'; import JitsiMeetJS from '../base/lib-jitsi-meet';
import { toState } from '../base/redux'; import { toState } from '../base/redux/functions';
import { import {
getUserSelectedCameraDeviceId, getUserSelectedCameraDeviceId,
getUserSelectedMicDeviceId, getUserSelectedMicDeviceId,
getUserSelectedOutputDeviceId getUserSelectedOutputDeviceId
} from '../base/settings'; } from '../base/settings/functions.any';
/** /**
* Returns the properties for the device selection dialog from Redux state. * Returns the properties for the device selection dialog from Redux state.
* *
* @param {(Function|Object)} stateful -The (whole) redux state, or redux's * @param {IStateful} stateful -The (whole) redux state, or redux's
* {@code getState} function to be used to retrieve the state. * {@code getState} function to be used to retrieve the state.
* @param {boolean} isDisplayedOnWelcomePage - Indicates whether the device selection dialog is displayed on the * @param {boolean} isDisplayedOnWelcomePage - Indicates whether the device selection dialog is displayed on the
* welcome page or not. * welcome page or not.
* @returns {Object} - The properties for the device selection dialog. * @returns {Object} - The properties for the device selection dialog.
*/ */
export function getDeviceSelectionDialogProps(stateful: Object | Function, isDisplayedOnWelcomePage) { export function getDeviceSelectionDialogProps(stateful: IStateful, isDisplayedOnWelcomePage: boolean) {
// On mobile Safari because of https://bugs.webkit.org/show_bug.cgi?id=179363#c30, the old track is stopped // On mobile Safari because of https://bugs.webkit.org/show_bug.cgi?id=179363#c30, the old track is stopped
// by the browser when a new track is created for preview. That's why we are disabling all previews. // by the browser when a new track is created for preview. That's why we are disabling all previews.
const disablePreviews = isIosMobileBrowser(); const disablePreviews = isIosMobileBrowser();
@ -96,9 +96,9 @@ export function getDeviceSelectionDialogProps(stateful: Object | Function, isDis
* @returns {boolean} - True if the request has been processed and false otherwise. * @returns {boolean} - True if the request has been processed and false otherwise.
*/ */
export function processExternalDeviceRequest( // eslint-disable-line max-params export function processExternalDeviceRequest( // eslint-disable-line max-params
dispatch: Dispatch<any>, dispatch: IStore['dispatch'],
getState: Function, getState: IStore['getState'],
request: Object, request: any,
responseCallback: Function) { responseCallback: Function) {
if (request.type !== 'devices') { if (request.type !== 'devices') {
return false; return false;
@ -119,10 +119,10 @@ export function processExternalDeviceRequest( // eslint-disable-line max-params
case 'isMultipleAudioInputSupported': case 'isMultipleAudioInputSupported':
responseCallback(JitsiMeetJS.isMultipleAudioInputSupported()); responseCallback(JitsiMeetJS.isMultipleAudioInputSupported());
break; break;
case 'getCurrentDevices': case 'getCurrentDevices': // @ts-ignore
dispatch(getAvailableDevices()).then(devices => { dispatch(getAvailableDevices()).then((devices: MediaDeviceInfo[]) => {
if (areDeviceLabelsInitialized(state)) { if (areDeviceLabelsInitialized(state)) {
const deviceDescriptions = { const deviceDescriptions: any = {
audioInput: undefined, audioInput: undefined,
audioOutput: undefined, audioOutput: undefined,
videoInput: undefined videoInput: undefined
@ -164,8 +164,8 @@ export function processExternalDeviceRequest( // eslint-disable-line max-params
}); });
break; break;
case 'getAvailableDevices': case 'getAvailableDevices': // @ts-ignore
dispatch(getAvailableDevices()).then(devices => { dispatch(getAvailableDevices()).then((devices: MediaDeviceInfo[]) => {
if (areDeviceLabelsInitialized(state)) { if (areDeviceLabelsInitialized(state)) {
responseCallback(groupDevicesByKind(devices)); responseCallback(groupDevicesByKind(devices));
} else { } else {

View File

@ -92,9 +92,12 @@ export function setNotificationsEnabled(enabled: boolean) {
interface INotificationProps { interface INotificationProps {
appearance?: string; appearance?: string;
concatText?: boolean; concatText?: boolean;
customActionHandler?: Function[];
customActionNameKey?: string[];
description?: string; description?: string;
descriptionKey?: string; descriptionKey?: string;
icon?: string; icon?: string;
title?: string;
titleArguments?: { titleArguments?: {
[key: string]: string; [key: string]: string;
}; };