ref(TS) Convert some features to TS (#12591)
This commit is contained in:
parent
6bce0bc917
commit
643cc2db81
|
@ -13,6 +13,7 @@ declare global {
|
|||
keyboardshortcut: {
|
||||
registerShortcut: Function;
|
||||
unregisterShortcut: Function;
|
||||
openDialog: Function;
|
||||
}
|
||||
};
|
||||
const interfaceConfig: any;
|
||||
|
|
|
@ -454,18 +454,18 @@ export function sendLocalParticipant(
|
|||
name
|
||||
} = getLocalParticipant(stateful) ?? {};
|
||||
|
||||
avatarURL && conference.sendCommand(AVATAR_URL_COMMAND, {
|
||||
avatarURL && conference?.sendCommand(AVATAR_URL_COMMAND, {
|
||||
value: avatarURL
|
||||
});
|
||||
email && conference.sendCommand(EMAIL_COMMAND, {
|
||||
email && conference?.sendCommand(EMAIL_COMMAND, {
|
||||
value: email
|
||||
});
|
||||
|
||||
if (features && features['screen-sharing'] === 'true') {
|
||||
conference.setLocalParticipantProperty('features_screen-sharing', true);
|
||||
conference?.setLocalParticipantProperty('features_screen-sharing', true);
|
||||
}
|
||||
|
||||
conference.setDisplayName(name);
|
||||
conference?.setDisplayName(name);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -65,6 +65,7 @@ export interface IJitsiConference {
|
|||
isStartAudioMuted: Function;
|
||||
isStartVideoMuted: Function;
|
||||
join: Function;
|
||||
joinLobby: Function;
|
||||
kickParticipant: Function;
|
||||
lock: Function;
|
||||
muteParticipant: Function;
|
||||
|
@ -104,7 +105,7 @@ export interface IConferenceState {
|
|||
leaving?: Object;
|
||||
localSubject?: string;
|
||||
locked?: string;
|
||||
membersOnly?: Object;
|
||||
membersOnly?: IJitsiConference;
|
||||
obfuscatedRoom?: string;
|
||||
obfuscatedRoomSource?: string;
|
||||
p2p?: Object;
|
||||
|
@ -227,7 +228,8 @@ function _authStatusChanged(state: IConferenceState,
|
|||
* @returns {Object} The new state of the feature base/conference after the
|
||||
* reduction of the specified action.
|
||||
*/
|
||||
function _conferenceFailed(state: IConferenceState, { conference, error }: { conference: Object; error: Error; }) {
|
||||
function _conferenceFailed(state: IConferenceState, { conference, error }: {
|
||||
conference: IJitsiConference; error: Error; }) {
|
||||
// The current (similar to getCurrentConference in
|
||||
// base/conference/functions.any.js) conference which is joining or joined:
|
||||
const conference_ = state.conference || state.joining;
|
||||
|
|
|
@ -214,7 +214,7 @@ export function getVideoTrackByParticipant(
|
|||
export function getTrackByMediaTypeAndParticipant(
|
||||
tracks: ITrack[],
|
||||
mediaType: MediaType,
|
||||
participantId: string) {
|
||||
participantId?: string) {
|
||||
return tracks.find(
|
||||
t => Boolean(t.jitsiTrack) && t.participantId === participantId && t.mediaType === mediaType
|
||||
);
|
||||
|
|
|
@ -11,7 +11,6 @@ import {
|
|||
getParticipantDisplayName,
|
||||
isWhiteboardParticipant
|
||||
} from '../../../base/participants/functions';
|
||||
import { IParticipant } from '../../../base/participants/types';
|
||||
import { withPixelLineHeight } from '../../../base/styles/functions.web';
|
||||
// @ts-ignore
|
||||
import { getLargeVideoParticipant } from '../../../large-video/functions';
|
||||
|
@ -50,9 +49,9 @@ const useStyles = makeStyles()(theme => {
|
|||
*/
|
||||
const StageParticipantNameLabel = () => {
|
||||
const { classes, cx } = useStyles();
|
||||
const largeVideoParticipant: IParticipant = useSelector(getLargeVideoParticipant);
|
||||
const largeVideoParticipant = useSelector(getLargeVideoParticipant);
|
||||
const selectedId = largeVideoParticipant?.id;
|
||||
const nameToDisplay = useSelector((state: IReduxState) => getParticipantDisplayName(state, selectedId));
|
||||
const nameToDisplay = useSelector((state: IReduxState) => getParticipantDisplayName(state, selectedId ?? ''));
|
||||
|
||||
const localParticipant = useSelector(getLocalParticipant);
|
||||
const localId = localParticipant?.id;
|
||||
|
|
|
@ -1,19 +1,14 @@
|
|||
// @flow
|
||||
|
||||
import { MiddlewareRegistry } from '../base/redux';
|
||||
import MiddlewareRegistry from '../base/redux/MiddlewareRegistry';
|
||||
|
||||
import { OPEN_KEYBOARD_SHORTCUTS_DIALOG } from './actionTypes';
|
||||
|
||||
declare var APP: Object;
|
||||
|
||||
/**
|
||||
* Implements the middleware of the feature keyboard-shortcuts.
|
||||
*
|
||||
* @param {Store} store - The redux store.
|
||||
* @returns {Function}
|
||||
*/
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
MiddlewareRegistry.register(store => next => action => {
|
||||
MiddlewareRegistry.register(_store => next => action => {
|
||||
switch (action.type) {
|
||||
case OPEN_KEYBOARD_SHORTCUTS_DIALOG:
|
||||
if (typeof APP === 'object') {
|
|
@ -1,8 +1,5 @@
|
|||
// @flow
|
||||
|
||||
import type { Dispatch } from 'redux';
|
||||
|
||||
import { MEDIA_TYPE } from '../base/media';
|
||||
import { IReduxState, IStore } from '../app/types';
|
||||
import { MEDIA_TYPE } from '../base/media/constants';
|
||||
import {
|
||||
getDominantSpeakerParticipant,
|
||||
getLocalParticipant,
|
||||
|
@ -10,9 +7,10 @@ import {
|
|||
getPinnedParticipant,
|
||||
getRemoteParticipants,
|
||||
getVirtualScreenshareParticipantByOwnerId
|
||||
} from '../base/participants';
|
||||
} from '../base/participants/functions';
|
||||
import { ITrack } from '../base/tracks/types';
|
||||
import { isStageFilmstripAvailable } from '../filmstrip/functions';
|
||||
import { getAutoPinSetting } from '../video-layout';
|
||||
import { getAutoPinSetting } from '../video-layout/functions';
|
||||
|
||||
import {
|
||||
SELECT_LARGE_VIDEO_PARTICIPANT,
|
||||
|
@ -30,8 +28,8 @@ import {
|
|||
* displayed on the large video.
|
||||
* @returns {Function}
|
||||
*/
|
||||
export function selectParticipantInLargeVideo(participant: ?string) {
|
||||
return (dispatch: Dispatch<any>, getState: Function) => {
|
||||
export function selectParticipantInLargeVideo(participant?: string) {
|
||||
return (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
|
||||
const state = getState();
|
||||
|
||||
if (isStageFilmstripAvailable(state, 2)) {
|
||||
|
@ -48,7 +46,7 @@ export function selectParticipantInLargeVideo(participant: ?string) {
|
|||
const remoteScreenShares = state['features/video-layout'].remoteScreenShares;
|
||||
let latestScreenshareParticipantId;
|
||||
|
||||
if (remoteScreenShares && remoteScreenShares.length) {
|
||||
if (remoteScreenShares?.length) {
|
||||
latestScreenshareParticipantId = remoteScreenShares[remoteScreenShares.length - 1];
|
||||
}
|
||||
|
||||
|
@ -94,7 +92,7 @@ export function updateKnownLargeVideoResolution(resolution: number) {
|
|||
* width: number
|
||||
* }}
|
||||
*/
|
||||
export function setLargeVideoDimensions(height, width) {
|
||||
export function setLargeVideoDimensions(height: number, width: number) {
|
||||
return {
|
||||
type: SET_LARGE_VIDEO_DIMENSIONS,
|
||||
height,
|
||||
|
@ -109,7 +107,7 @@ export function setLargeVideoDimensions(height, width) {
|
|||
* @private
|
||||
* @returns {(Track|undefined)}
|
||||
*/
|
||||
function _electLastVisibleRemoteVideo(tracks) {
|
||||
function _electLastVisibleRemoteVideo(tracks: ITrack[]) {
|
||||
// First we try to get most recent remote video track.
|
||||
for (let i = tracks.length - 1; i >= 0; --i) {
|
||||
const track = tracks[i];
|
||||
|
@ -129,7 +127,7 @@ function _electLastVisibleRemoteVideo(tracks) {
|
|||
* @private
|
||||
* @returns {(string|undefined)}
|
||||
*/
|
||||
function _electParticipantInLargeVideo(state) {
|
||||
function _electParticipantInLargeVideo(state: IReduxState) {
|
||||
// If a participant is pinned, they will be shown in the LargeVideo (regardless of whether they are local or
|
||||
// remote) when the filmstrip on stage is disabled.
|
||||
let participant = getPinnedParticipant(state);
|
|
@ -1,3 +1 @@
|
|||
// @flow
|
||||
|
||||
export * from './actions.any';
|
|
@ -1,10 +1,8 @@
|
|||
// @flow
|
||||
|
||||
import type { Dispatch } from 'redux';
|
||||
|
||||
// @ts-expect-error
|
||||
import VideoLayout from '../../../modules/UI/videolayout/VideoLayout';
|
||||
import { MEDIA_TYPE } from '../base/media';
|
||||
import { getTrackByMediaTypeAndParticipant } from '../base/tracks';
|
||||
import { IStore } from '../app/types';
|
||||
import { MEDIA_TYPE } from '../base/media/constants';
|
||||
import { getTrackByMediaTypeAndParticipant } from '../base/tracks/functions.web';
|
||||
|
||||
import { SET_SEE_WHAT_IS_BEING_SHARED, UPDATE_LAST_LARGE_VIDEO_MEDIA_EVENT } from './actionTypes';
|
||||
|
||||
|
@ -16,7 +14,7 @@ export * from './actions.any';
|
|||
* @returns {Function}
|
||||
*/
|
||||
export function captureLargeVideoScreenshot() {
|
||||
return (dispatch: Dispatch<any>, getState: Function): Promise<string> => {
|
||||
return (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
|
||||
const state = getState();
|
||||
const largeVideo = state['features/large-video'];
|
||||
const promise = Promise.resolve();
|
||||
|
@ -28,7 +26,7 @@ export function captureLargeVideoScreenshot() {
|
|||
const participantTrack = getTrackByMediaTypeAndParticipant(tracks, MEDIA_TYPE.VIDEO, largeVideo.participantId);
|
||||
|
||||
// Participants that join the call video muted do not have a jitsiTrack attached.
|
||||
if (!(participantTrack && participantTrack.jitsiTrack)) {
|
||||
if (!participantTrack?.jitsiTrack) {
|
||||
return promise;
|
||||
}
|
||||
const videoStream = participantTrack.jitsiTrack.getOriginalStream();
|
||||
|
@ -39,7 +37,7 @@ export function captureLargeVideoScreenshot() {
|
|||
|
||||
// Get the video element for the large video, cast HTMLElement to HTMLVideoElement to make flow happy.
|
||||
/* eslint-disable-next-line no-extra-parens*/
|
||||
const videoElement = ((document.getElementById('largeVideo'): any): HTMLVideoElement);
|
||||
const videoElement = (document.getElementById('largeVideo') as any);
|
||||
|
||||
if (!videoElement) {
|
||||
return promise;
|
||||
|
@ -54,11 +52,11 @@ export function captureLargeVideoScreenshot() {
|
|||
canvasElement.style.display = 'none';
|
||||
canvasElement.height = parseInt(height, 10);
|
||||
canvasElement.width = parseInt(width, 10);
|
||||
ctx.drawImage(videoElement, 0, 0);
|
||||
ctx?.drawImage(videoElement, 0, 0);
|
||||
const dataURL = canvasElement.toDataURL('image/png', 1.0);
|
||||
|
||||
// Cleanup.
|
||||
ctx.clearRect(0, 0, canvasElement.width, canvasElement.height);
|
||||
ctx?.clearRect(0, 0, canvasElement.width, canvasElement.height);
|
||||
canvasElement.remove();
|
||||
|
||||
return Promise.resolve(dataURL);
|
||||
|
@ -73,7 +71,7 @@ export function captureLargeVideoScreenshot() {
|
|||
* @returns {Function}
|
||||
*/
|
||||
export function resizeLargeVideo(width: number, height: number) {
|
||||
return (dispatch: Dispatch<any>, getState: Function) => {
|
||||
return (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
|
||||
const state = getState();
|
||||
const largeVideo = state['features/large-video'];
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
// @flow
|
||||
|
||||
import { getParticipantById } from '../base/participants';
|
||||
|
||||
/**
|
||||
* Selector for the participant currently displaying on the large video.
|
||||
*
|
||||
* @param {Object} state - The redux state.
|
||||
* @returns {Object}
|
||||
*/
|
||||
export function getLargeVideoParticipant(state: Object) {
|
||||
const { participantId } = state['features/large-video'];
|
||||
|
||||
return getParticipantById(state, participantId);
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
import { IReduxState } from '../app/types';
|
||||
import { getParticipantById } from '../base/participants/functions';
|
||||
|
||||
/**
|
||||
* Selector for the participant currently displaying on the large video.
|
||||
*
|
||||
* @param {Object} state - The redux state.
|
||||
* @returns {Object}
|
||||
*/
|
||||
export function getLargeVideoParticipant(state: IReduxState) {
|
||||
const { participantId } = state['features/large-video'];
|
||||
|
||||
return getParticipantById(state, participantId ?? '');
|
||||
}
|
|
@ -1,5 +1,3 @@
|
|||
// @flow
|
||||
|
||||
import { getLogger } from '../base/logging/functions';
|
||||
|
||||
export default getLogger('features/large-video');
|
|
@ -1,19 +1,16 @@
|
|||
// @flow
|
||||
|
||||
import {
|
||||
DOMINANT_SPEAKER_CHANGED,
|
||||
PARTICIPANT_JOINED,
|
||||
PARTICIPANT_LEFT,
|
||||
PIN_PARTICIPANT,
|
||||
getDominantSpeakerParticipant,
|
||||
getLocalParticipant
|
||||
} from '../base/participants';
|
||||
import { MiddlewareRegistry } from '../base/redux';
|
||||
import { isTestModeEnabled } from '../base/testing';
|
||||
PIN_PARTICIPANT
|
||||
} from '../base/participants/actionTypes';
|
||||
import { getDominantSpeakerParticipant, getLocalParticipant } from '../base/participants/functions';
|
||||
import MiddlewareRegistry from '../base/redux/MiddlewareRegistry';
|
||||
import { isTestModeEnabled } from '../base/testing/functions';
|
||||
import {
|
||||
TRACK_ADDED,
|
||||
TRACK_REMOVED
|
||||
} from '../base/tracks';
|
||||
} from '../base/tracks/actionTypes';
|
||||
import { TOGGLE_DOCUMENT_EDITING } from '../etherpad/actionTypes';
|
||||
|
||||
import { selectParticipantInLargeVideo } from './actions';
|
|
@ -1,8 +1,7 @@
|
|||
// @flow
|
||||
|
||||
// @ts-expect-error
|
||||
import VideoLayout from '../../../modules/UI/videolayout/VideoLayout';
|
||||
import { StateListenerRegistry } from '../base/redux';
|
||||
import { getVideoTrackByParticipant } from '../base/tracks';
|
||||
import StateListenerRegistry from '../base/redux/StateListenerRegistry';
|
||||
import { getVideoTrackByParticipant } from '../base/tracks/functions.web';
|
||||
|
||||
import { getLargeVideoParticipant } from './functions';
|
||||
|
||||
|
@ -29,7 +28,7 @@ StateListenerRegistry.register(
|
|||
streamingStatus: videoTrack?.streamingStatus
|
||||
};
|
||||
},
|
||||
/* listener */ ({ participantId, streamingStatus }, previousState = {}) => {
|
||||
/* listener */ ({ participantId, streamingStatus }, previousState: any = {}) => {
|
||||
if (streamingStatus !== previousState.streamingStatus) {
|
||||
VideoLayout.updateLargeVideo(participantId, true);
|
||||
}
|
|
@ -1,19 +1,13 @@
|
|||
// @flow
|
||||
|
||||
import { type Dispatch } from 'redux';
|
||||
|
||||
import {
|
||||
conferenceWillJoin,
|
||||
getCurrentConference,
|
||||
sendLocalParticipant,
|
||||
setPassword
|
||||
} from '../base/conference';
|
||||
import { getLocalParticipant } from '../base/participants';
|
||||
import { IStore } from '../app/types';
|
||||
import { conferenceWillJoin, setPassword } from '../base/conference/actions';
|
||||
import { getCurrentConference, sendLocalParticipant } from '../base/conference/functions';
|
||||
import { getLocalParticipant } from '../base/participants/functions';
|
||||
import { IParticipant } from '../base/participants/types';
|
||||
import { onLobbyChatInitialized, removeLobbyChatParticipant, sendMessage } from '../chat/actions.any';
|
||||
import { LOBBY_CHAT_MESSAGE } from '../chat/constants';
|
||||
import { handleLobbyMessageReceived } from '../chat/middleware';
|
||||
import { LOBBY_NOTIFICATION_ID, hideNotification } from '../notifications';
|
||||
import { showNotification } from '../notifications/actions';
|
||||
import { hideNotification, showNotification } from '../notifications/actions';
|
||||
import { LOBBY_NOTIFICATION_ID } from '../notifications/constants';
|
||||
|
||||
import {
|
||||
KNOCKING_PARTICIPANT_ARRIVED_OR_UPDATED,
|
||||
|
@ -27,6 +21,7 @@ import {
|
|||
} from './actionTypes';
|
||||
import { LOBBY_CHAT_INITIALIZED, MODERATOR_IN_CHAT_WITH_LEFT } from './constants';
|
||||
import { getKnockingParticipants, getLobbyEnabled } from './functions';
|
||||
import { IKnockingParticipant } from './types';
|
||||
|
||||
/**
|
||||
* Tries to join with a preset password.
|
||||
|
@ -35,7 +30,7 @@ import { getKnockingParticipants, getLobbyEnabled } from './functions';
|
|||
* @returns {Function}
|
||||
*/
|
||||
export function joinWithPassword(password: string) {
|
||||
return async (dispatch: Dispatch<any>, getState: Function) => {
|
||||
return async (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
|
||||
const conference = getCurrentConference(getState);
|
||||
|
||||
dispatch(setPassword(conference, conference.join, password));
|
||||
|
@ -67,7 +62,7 @@ export function knockingParticipantLeft(id: string) {
|
|||
* type: KNOCKING_PARTICIPANT_ARRIVED_OR_UPDATED
|
||||
* }}
|
||||
*/
|
||||
export function participantIsKnockingOrUpdated(participant: Object) {
|
||||
export function participantIsKnockingOrUpdated(participant: IKnockingParticipant | Object) {
|
||||
return {
|
||||
participant,
|
||||
type: KNOCKING_PARTICIPANT_ARRIVED_OR_UPDATED
|
||||
|
@ -82,7 +77,7 @@ export function participantIsKnockingOrUpdated(participant: Object) {
|
|||
* @returns {Function}
|
||||
*/
|
||||
export function answerKnockingParticipant(id: string, approved: boolean) {
|
||||
return async (dispatch: Dispatch<any>) => {
|
||||
return async (dispatch: IStore['dispatch']) => {
|
||||
dispatch(setKnockingParticipantApproval(id, approved));
|
||||
dispatch(hideNotification(LOBBY_NOTIFICATION_ID));
|
||||
};
|
||||
|
@ -96,7 +91,7 @@ export function answerKnockingParticipant(id: string, approved: boolean) {
|
|||
* @returns {Function}
|
||||
*/
|
||||
export function setKnockingParticipantApproval(id: string, approved: boolean) {
|
||||
return async (dispatch: Dispatch<any>, getState: Function) => {
|
||||
return async (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
|
||||
const conference = getCurrentConference(getState);
|
||||
|
||||
if (conference) {
|
||||
|
@ -115,8 +110,8 @@ export function setKnockingParticipantApproval(id: string, approved: boolean) {
|
|||
* @param {Array<Object>} participants - A list of knocking participants.
|
||||
* @returns {void}
|
||||
*/
|
||||
export function admitMultiple(participants: Array<Object>) {
|
||||
return (dispatch: Function, getState: Function) => {
|
||||
export function admitMultiple(participants: Array<IKnockingParticipant>) {
|
||||
return (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
|
||||
const conference = getCurrentConference(getState);
|
||||
|
||||
participants.forEach(p => {
|
||||
|
@ -132,10 +127,10 @@ export function admitMultiple(participants: Array<Object>) {
|
|||
* @returns {Function}
|
||||
*/
|
||||
export function approveKnockingParticipant(id: string) {
|
||||
return (dispatch: Dispatch<any>, getState: Function) => {
|
||||
return (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
|
||||
const conference = getCurrentConference(getState);
|
||||
|
||||
conference && conference.lobbyApproveAccess(id);
|
||||
conference?.lobbyApproveAccess(id);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -146,10 +141,10 @@ export function approveKnockingParticipant(id: string) {
|
|||
* @returns {Function}
|
||||
*/
|
||||
export function rejectKnockingParticipant(id: string) {
|
||||
return (dispatch: Dispatch<any>, getState: Function) => {
|
||||
return (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
|
||||
const conference = getCurrentConference(getState);
|
||||
|
||||
conference && conference.lobbyDenyAccess(id);
|
||||
conference?.lobbyDenyAccess(id);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -207,18 +202,20 @@ export function setPasswordJoinFailed(failed: boolean) {
|
|||
* @returns {Function}
|
||||
*/
|
||||
export function startKnocking() {
|
||||
return async (dispatch: Dispatch<any>, getState: Function) => {
|
||||
return async (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
|
||||
const state = getState();
|
||||
const { membersOnly } = state['features/base/conference'];
|
||||
const localParticipant = getLocalParticipant(state);
|
||||
|
||||
// @ts-ignore
|
||||
dispatch(conferenceWillJoin(membersOnly));
|
||||
|
||||
// We need to update the conference object with the current display name, if approved
|
||||
// we want to send that display name, it was not updated in case when pre-join is disabled
|
||||
// @ts-ignore
|
||||
sendLocalParticipant(state, membersOnly);
|
||||
|
||||
membersOnly.joinLobby(localParticipant.name, localParticipant.email);
|
||||
membersOnly?.joinLobby(localParticipant?.name, localParticipant?.email);
|
||||
dispatch(setLobbyMessageListener());
|
||||
dispatch(setKnockingState(true));
|
||||
};
|
||||
|
@ -231,7 +228,7 @@ export function startKnocking() {
|
|||
* @returns {Function}
|
||||
*/
|
||||
export function toggleLobbyMode(enabled: boolean) {
|
||||
return async (dispatch: Dispatch<any>, getState: Function) => {
|
||||
return async (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
|
||||
const conference = getCurrentConference(getState);
|
||||
|
||||
if (enabled) {
|
||||
|
@ -275,8 +272,8 @@ export function hideLobbyScreen() {
|
|||
*
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
export function handleLobbyChatInitialized(payload: Object) {
|
||||
return async (dispatch: Dispatch<any>, getState: Function) => {
|
||||
export function handleLobbyChatInitialized(payload: { attendee: IParticipant; moderator: IParticipant; }) {
|
||||
return async (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
|
||||
const state = getState();
|
||||
const conference = getCurrentConference(state);
|
||||
|
||||
|
@ -296,8 +293,8 @@ export function handleLobbyChatInitialized(payload: Object) {
|
|||
dispatch(showNotification({
|
||||
titleKey: 'lobby.lobbyChatStartedNotification',
|
||||
titleArguments: {
|
||||
moderator: payload.moderator.name,
|
||||
attendee: payload.attendee.name
|
||||
moderator: payload.moderator.name ?? '',
|
||||
attendee: payload.attendee.name ?? ''
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
@ -312,7 +309,7 @@ export function handleLobbyChatInitialized(payload: Object) {
|
|||
* @returns {Promise<void>}
|
||||
*/
|
||||
export function onSendMessage(message: string) {
|
||||
return async (dispatch: Dispatch<any>) => {
|
||||
return async (dispatch: IStore['dispatch']) => {
|
||||
dispatch(sendMessage(message));
|
||||
};
|
||||
}
|
||||
|
@ -325,7 +322,7 @@ export function onSendMessage(message: string) {
|
|||
* @returns {Promise<void>}
|
||||
*/
|
||||
export function sendLobbyChatMessage(message: Object) {
|
||||
return async (dispatch: Dispatch<any>, getState: Function) => {
|
||||
return async (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
|
||||
const conference = getCurrentConference(getState);
|
||||
|
||||
conference.sendLobbyMessage(message);
|
||||
|
@ -338,7 +335,7 @@ export function sendLobbyChatMessage(message: Object) {
|
|||
* @returns {Function}
|
||||
*/
|
||||
export function maybeSetLobbyChatMessageListener() {
|
||||
return async (dispatch: Dispatch<any>, getState: Function) => {
|
||||
return async (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
|
||||
const state = getState();
|
||||
const lobbyEnabled = getLobbyEnabled(state);
|
||||
|
||||
|
@ -355,7 +352,7 @@ export function maybeSetLobbyChatMessageListener() {
|
|||
* @returns {Function}
|
||||
*/
|
||||
export function updateLobbyParticipantOnLeave(participantId: string) {
|
||||
return async (dispatch: Dispatch<any>, getState: Function) => {
|
||||
return async (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
|
||||
const state = getState();
|
||||
const { knocking, knockingParticipants } = state['features/lobby'];
|
||||
const { lobbyMessageRecipient } = state['features/chat'];
|
||||
|
@ -370,7 +367,7 @@ export function updateLobbyParticipantOnLeave(participantId: string) {
|
|||
const participantToNotify = knockingParticipants.find(p => p.chattingWithModerator === participantId);
|
||||
|
||||
if (participantToNotify) {
|
||||
conference.sendLobbyMessage({
|
||||
conference?.sendLobbyMessage({
|
||||
type: MODERATOR_IN_CHAT_WITH_LEFT,
|
||||
moderatorId: participantToNotify.chattingWithModerator
|
||||
}, participantToNotify.id);
|
||||
|
@ -389,7 +386,7 @@ export function updateLobbyParticipantOnLeave(participantId: string) {
|
|||
* @returns {Function}
|
||||
*/
|
||||
export function setLobbyMessageListener() {
|
||||
return async (dispatch: Dispatch<any>, getState: Function) => {
|
||||
return async (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
|
||||
const state = getState();
|
||||
const conference = getCurrentConference(state);
|
||||
const { enableLobbyChat = true } = state['features/base/config'];
|
||||
|
@ -398,7 +395,7 @@ export function setLobbyMessageListener() {
|
|||
return;
|
||||
}
|
||||
|
||||
conference.addLobbyMessageListener((message: Object, participantId: string) => {
|
||||
conference.addLobbyMessageListener((message: any, participantId: string) => {
|
||||
if (message.type === LOBBY_CHAT_MESSAGE) {
|
||||
return dispatch(handleLobbyMessageReceived(message.message, participantId));
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
import { batch } from 'react-redux';
|
||||
|
||||
import { appNavigate } from '../app/actions';
|
||||
import { appNavigate } from '../app/actions.native';
|
||||
import { IStore } from '../app/types';
|
||||
|
||||
import { hideLobbyScreen, setKnockingState } from './actions.any';
|
||||
|
||||
|
@ -12,7 +13,7 @@ export * from './actions.any';
|
|||
* @returns {Function}
|
||||
*/
|
||||
export function cancelKnocking() {
|
||||
return dispatch => {
|
||||
return (dispatch: IStore['dispatch']) => {
|
||||
batch(() => {
|
||||
dispatch(setKnockingState(false));
|
||||
dispatch(hideLobbyScreen());
|
|
@ -1,20 +1,15 @@
|
|||
// @flow
|
||||
|
||||
import { type Dispatch } from 'redux';
|
||||
|
||||
import { maybeRedirectToWelcomePage } from '../app/actions';
|
||||
import { maybeRedirectToWelcomePage } from '../app/actions.web';
|
||||
import { IStore } from '../app/types';
|
||||
|
||||
export * from './actions.any';
|
||||
|
||||
declare var APP: Object;
|
||||
|
||||
/**
|
||||
* Cancels the ongoing knocking and abandons the join flow.
|
||||
*
|
||||
* @returns {Function}
|
||||
*/
|
||||
export function cancelKnocking() {
|
||||
return async (dispatch: Dispatch<any>) => {
|
||||
return async (dispatch: IStore['dispatch']) => {
|
||||
// when we are redirecting the library should handle any
|
||||
// unload and clean of the connection.
|
||||
APP.API.notifyReadyToClose();
|
|
@ -1,44 +1,46 @@
|
|||
// @flow
|
||||
import { IReduxState } from '../app/types';
|
||||
import { getCurrentConference } from '../base/conference/functions';
|
||||
|
||||
import { IKnockingParticipant } from './types';
|
||||
|
||||
import { getCurrentConference } from '../base/conference';
|
||||
|
||||
/**
|
||||
* Selector to return lobby enable state.
|
||||
*
|
||||
* @param {any} state - State object.
|
||||
* @param {IReduxState} state - State object.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function getLobbyEnabled(state: any) {
|
||||
export function getLobbyEnabled(state: IReduxState) {
|
||||
return state['features/lobby'].lobbyEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Selector to return a list of knocking participants.
|
||||
*
|
||||
* @param {any} state - State object.
|
||||
* @param {IReduxState} state - State object.
|
||||
* @returns {Array<Object>}
|
||||
*/
|
||||
export function getKnockingParticipants(state: any) {
|
||||
export function getKnockingParticipants(state: IReduxState) {
|
||||
return state['features/lobby'].knockingParticipants;
|
||||
}
|
||||
|
||||
/**
|
||||
* Selector to return lobby visibility.
|
||||
*
|
||||
* @param {any} state - State object.
|
||||
* @param {IReduxState} state - State object.
|
||||
* @returns {any}
|
||||
*/
|
||||
export function getIsLobbyVisible(state: any) {
|
||||
export function getIsLobbyVisible(state: IReduxState) {
|
||||
return state['features/lobby'].lobbyVisible;
|
||||
}
|
||||
|
||||
/**
|
||||
* Selector to return array with knocking participant ids.
|
||||
*
|
||||
* @param {any} state - State object.
|
||||
* @param {IReduxState} state - State object.
|
||||
* @returns {Array}
|
||||
*/
|
||||
export function getKnockingParticipantsById(state: any) {
|
||||
export function getKnockingParticipantsById(state: IReduxState) {
|
||||
return getKnockingParticipants(state).map(participant => participant.id);
|
||||
}
|
||||
|
||||
|
@ -50,9 +52,9 @@ export function getKnockingParticipantsById(state: any) {
|
|||
* @returns {Function}
|
||||
*/
|
||||
export function showLobbyChatButton(
|
||||
participant: Object
|
||||
participant: IKnockingParticipant
|
||||
) {
|
||||
return function(state: Object) {
|
||||
return function(state: IReduxState) {
|
||||
|
||||
const { enableLobbyChat = true } = state['features/base/config'];
|
||||
const { lobbyMessageRecipient, isLobbyChatActive } = state['features/chat'];
|
|
@ -1,5 +1,3 @@
|
|||
// @flow
|
||||
|
||||
import { getLogger } from '../base/logging/functions';
|
||||
|
||||
export default getLogger('features/lobby');
|
|
@ -1,39 +1,41 @@
|
|||
// @flow
|
||||
|
||||
import i18n from 'i18next';
|
||||
import { batch } from 'react-redux';
|
||||
import { AnyAction } from 'redux';
|
||||
|
||||
import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../base/app';
|
||||
import {
|
||||
CONFERENCE_FAILED,
|
||||
CONFERENCE_JOINED,
|
||||
conferenceWillJoin
|
||||
} from '../base/conference';
|
||||
import { IStore } from '../app/types';
|
||||
import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../base/app/actionTypes';
|
||||
import { CONFERENCE_FAILED, CONFERENCE_JOINED } from '../base/conference/actionTypes';
|
||||
import { conferenceWillJoin } from '../base/conference/actions';
|
||||
import { JitsiConferenceErrors, JitsiConferenceEvents } from '../base/lib-jitsi-meet';
|
||||
import { getFirstLoadableAvatarUrl, getParticipantDisplayName } from '../base/participants';
|
||||
import { MiddlewareRegistry, StateListenerRegistry } from '../base/redux';
|
||||
import { playSound, registerSound, unregisterSound } from '../base/sounds';
|
||||
import { isTestModeEnabled } from '../base/testing';
|
||||
import { getFirstLoadableAvatarUrl, getParticipantDisplayName } from '../base/participants/functions';
|
||||
import MiddlewareRegistry from '../base/redux/MiddlewareRegistry';
|
||||
import StateListenerRegistry from '../base/redux/StateListenerRegistry';
|
||||
import { playSound, registerSound, unregisterSound } from '../base/sounds/actions';
|
||||
import { isTestModeEnabled } from '../base/testing/functions';
|
||||
import { handleLobbyChatInitialized, removeLobbyChatParticipant } from '../chat/actions.any';
|
||||
import { approveKnockingParticipant, rejectKnockingParticipant } from '../lobby/actions';
|
||||
import {
|
||||
hideNotification,
|
||||
showNotification
|
||||
} from '../notifications/actions';
|
||||
import {
|
||||
LOBBY_NOTIFICATION_ID,
|
||||
NOTIFICATION_ICON,
|
||||
NOTIFICATION_TIMEOUT_TYPE,
|
||||
NOTIFICATION_TYPE,
|
||||
hideNotification,
|
||||
showNotification
|
||||
} from '../notifications';
|
||||
NOTIFICATION_TYPE
|
||||
} from '../notifications/constants';
|
||||
import { INotificationProps } from '../notifications/types';
|
||||
import { open as openParticipantsPane } from '../participants-pane/actions';
|
||||
import { getParticipantsPaneOpen } from '../participants-pane/functions';
|
||||
import { shouldAutoKnock } from '../prejoin/functions';
|
||||
|
||||
import { KNOCKING_PARTICIPANT_ARRIVED_OR_UPDATED, KNOCKING_PARTICIPANT_LEFT } from './actionTypes';
|
||||
import {
|
||||
approveKnockingParticipant,
|
||||
hideLobbyScreen,
|
||||
knockingParticipantLeft,
|
||||
openLobbyScreen,
|
||||
participantIsKnockingOrUpdated,
|
||||
rejectKnockingParticipant,
|
||||
setLobbyMessageListener,
|
||||
setLobbyModeEnabled,
|
||||
setPasswordJoinFailed,
|
||||
|
@ -43,8 +45,7 @@ import { updateLobbyParticipantOnLeave } from './actions.any';
|
|||
import { KNOCKING_PARTICIPANT_SOUND_ID } from './constants';
|
||||
import { getKnockingParticipants, showLobbyChatButton } from './functions';
|
||||
import { KNOCKING_PARTICIPANT_FILE } from './sounds';
|
||||
|
||||
declare var APP: Object;
|
||||
import { IKnockingParticipant } from './types';
|
||||
|
||||
MiddlewareRegistry.register(store => next => action => {
|
||||
switch (action.type) {
|
||||
|
@ -88,14 +89,14 @@ StateListenerRegistry.register(
|
|||
state => state['features/base/conference'].conference,
|
||||
(conference, { dispatch, getState }, previousConference) => {
|
||||
if (conference && !previousConference) {
|
||||
conference.on(JitsiConferenceEvents.MEMBERS_ONLY_CHANGED, enabled => {
|
||||
conference.on(JitsiConferenceEvents.MEMBERS_ONLY_CHANGED, (enabled: boolean) => {
|
||||
dispatch(setLobbyModeEnabled(enabled));
|
||||
if (enabled) {
|
||||
dispatch(setLobbyMessageListener());
|
||||
}
|
||||
});
|
||||
|
||||
conference.on(JitsiConferenceEvents.LOBBY_USER_JOINED, (id, name) => {
|
||||
conference.on(JitsiConferenceEvents.LOBBY_USER_JOINED, (id: string, name: string) => {
|
||||
const { soundsParticipantKnocking } = getState()['features/base/settings'];
|
||||
|
||||
batch(() => {
|
||||
|
@ -180,7 +181,7 @@ StateListenerRegistry.register(
|
|||
});
|
||||
});
|
||||
|
||||
conference.on(JitsiConferenceEvents.LOBBY_USER_UPDATED, (id, participant) => {
|
||||
conference.on(JitsiConferenceEvents.LOBBY_USER_UPDATED, (id: string, participant: IKnockingParticipant) => {
|
||||
dispatch(
|
||||
participantIsKnockingOrUpdated({
|
||||
...participant,
|
||||
|
@ -189,7 +190,7 @@ StateListenerRegistry.register(
|
|||
);
|
||||
});
|
||||
|
||||
conference.on(JitsiConferenceEvents.LOBBY_USER_LEFT, id => {
|
||||
conference.on(JitsiConferenceEvents.LOBBY_USER_LEFT, (id: string) => {
|
||||
batch(() => {
|
||||
dispatch(knockingParticipantLeft(id));
|
||||
dispatch(removeLobbyChatParticipant());
|
||||
|
@ -197,7 +198,7 @@ StateListenerRegistry.register(
|
|||
});
|
||||
});
|
||||
|
||||
conference.on(JitsiConferenceEvents.ENDPOINT_MESSAGE_RECEIVED, (origin, sender) =>
|
||||
conference.on(JitsiConferenceEvents.ENDPOINT_MESSAGE_RECEIVED, (origin: any, sender: any) =>
|
||||
_maybeSendLobbyNotification(origin, sender, {
|
||||
dispatch,
|
||||
getState
|
||||
|
@ -213,7 +214,7 @@ StateListenerRegistry.register(
|
|||
* @param {Object} store - The Redux store.
|
||||
* @returns {void}
|
||||
*/
|
||||
function _handleLobbyNotification(store) {
|
||||
function _handleLobbyNotification(store: IStore) {
|
||||
const { dispatch, getState } = store;
|
||||
const knockingParticipants = getKnockingParticipants(getState());
|
||||
|
||||
|
@ -275,7 +276,7 @@ function _handleLobbyNotification(store) {
|
|||
* @param {Object} action - The Redux action.
|
||||
* @returns {Object}
|
||||
*/
|
||||
function _conferenceFailed({ dispatch, getState }, next, action) {
|
||||
function _conferenceFailed({ dispatch, getState }: IStore, next: Function, action: AnyAction) {
|
||||
const { error } = action;
|
||||
const state = getState();
|
||||
const { membersOnly } = state['features/base/conference'];
|
||||
|
@ -296,6 +297,7 @@ function _conferenceFailed({ dispatch, getState }, next, action) {
|
|||
|
||||
// In case of wrong password we need to be in the right state if in the meantime someone allows us to join
|
||||
if (nonFirstFailure) {
|
||||
// @ts-ignore
|
||||
dispatch(conferenceWillJoin(membersOnly));
|
||||
}
|
||||
|
||||
|
@ -328,7 +330,7 @@ function _conferenceFailed({ dispatch, getState }, next, action) {
|
|||
* @param {Object} action - The Redux action.
|
||||
* @returns {Object}
|
||||
*/
|
||||
function _conferenceJoined({ dispatch }, next, action) {
|
||||
function _conferenceJoined({ dispatch }: IStore, next: Function, action: AnyAction) {
|
||||
dispatch(hideLobbyScreen());
|
||||
|
||||
return next(action);
|
||||
|
@ -341,13 +343,13 @@ function _conferenceJoined({ dispatch }, next, action) {
|
|||
* @param {Object} participant - The knocking participant.
|
||||
* @returns {void}
|
||||
*/
|
||||
function _findLoadableAvatarForKnockingParticipant(store, { id }) {
|
||||
function _findLoadableAvatarForKnockingParticipant(store: IStore, { id }: { id: string; }) {
|
||||
const { dispatch, getState } = store;
|
||||
const updatedParticipant = getState()['features/lobby'].knockingParticipants.find(p => p.id === id);
|
||||
const { disableThirdPartyRequests } = getState()['features/base/config'];
|
||||
|
||||
if (!disableThirdPartyRequests && updatedParticipant && !updatedParticipant.loadableAvatarUrl) {
|
||||
getFirstLoadableAvatarUrl(updatedParticipant, store).then(result => {
|
||||
getFirstLoadableAvatarUrl(updatedParticipant, store).then((result: { isUsingCORS: boolean; src: string; }) => {
|
||||
if (result) {
|
||||
const { isUsingCORS, src } = result;
|
||||
|
||||
|
@ -372,12 +374,12 @@ function _findLoadableAvatarForKnockingParticipant(store, { id }) {
|
|||
* @param {Object} store - The Redux store.
|
||||
* @returns {void}
|
||||
*/
|
||||
function _maybeSendLobbyNotification(origin, message, { dispatch, getState }) {
|
||||
function _maybeSendLobbyNotification(origin: any, message: any, { dispatch, getState }: IStore) {
|
||||
if (!origin?._id || message?.type !== 'lobby-notify') {
|
||||
return;
|
||||
}
|
||||
|
||||
const notificationProps: any = {
|
||||
const notificationProps: INotificationProps = {
|
||||
descriptionArguments: {
|
||||
originParticipantName: getParticipantDisplayName(getState, origin._id),
|
||||
targetParticipantName: message.name
|
|
@ -1,5 +1,4 @@
|
|||
import { CONFERENCE_JOINED, CONFERENCE_LEFT, SET_PASSWORD } from '../base/conference/actionTypes';
|
||||
import { IParticipant } from '../base/participants/types';
|
||||
import ReducerRegistry from '../base/redux/ReducerRegistry';
|
||||
|
||||
import {
|
||||
|
@ -12,6 +11,7 @@ import {
|
|||
SET_LOBBY_VISIBILITY,
|
||||
SET_PASSWORD_JOIN_FAILED
|
||||
} from './actionTypes';
|
||||
import { IKnockingParticipant } from './types';
|
||||
|
||||
const DEFAULT_STATE = {
|
||||
knocking: false,
|
||||
|
@ -21,10 +21,6 @@ const DEFAULT_STATE = {
|
|||
passwordJoinFailed: false
|
||||
};
|
||||
|
||||
interface IKnockingParticipant extends IParticipant {
|
||||
chattingWithModerator?: string;
|
||||
}
|
||||
|
||||
export interface ILobbyState {
|
||||
knocking: boolean;
|
||||
knockingParticipants: IKnockingParticipant[];
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
import { IParticipant } from '../base/participants/types';
|
||||
|
||||
export interface IKnockingParticipant extends IParticipant {
|
||||
chattingWithModerator?: string;
|
||||
}
|
|
@ -1,6 +1,4 @@
|
|||
// @flow
|
||||
|
||||
import { browser } from '../../../react/features/base/lib-jitsi-meet';
|
||||
import { browser } from '../base/lib-jitsi-meet';
|
||||
|
||||
/**
|
||||
* Returns true if Jitsi Meet is running in too old jitsi-meet-electron app and false otherwise.
|
|
@ -1,16 +1,16 @@
|
|||
// @flow
|
||||
|
||||
import React from 'react';
|
||||
import { AnyAction } from 'redux';
|
||||
|
||||
import { APP_WILL_MOUNT } from '../base/app';
|
||||
import { MiddlewareRegistry } from '../base/redux';
|
||||
import { NOTIFICATION_TIMEOUT_TYPE, showErrorNotification } from '../notifications';
|
||||
import { IStore } from '../app/types';
|
||||
import { APP_WILL_MOUNT } from '../base/app/actionTypes';
|
||||
import MiddlewareRegistry from '../base/redux/MiddlewareRegistry';
|
||||
import { showErrorNotification } from '../notifications/actions';
|
||||
import { NOTIFICATION_TIMEOUT_TYPE } from '../notifications/constants';
|
||||
|
||||
// @ts-ignore
|
||||
import { OldElectronAPPNotificationDescription } from './components';
|
||||
import { isOldJitsiMeetElectronApp } from './functions';
|
||||
|
||||
declare var interfaceConfig: Object;
|
||||
|
||||
MiddlewareRegistry.register(store => next => action => {
|
||||
switch (action.type) {
|
||||
case APP_WILL_MOUNT:
|
||||
|
@ -29,7 +29,7 @@ MiddlewareRegistry.register(store => next => action => {
|
|||
* @private
|
||||
* @returns {Object} The new state that is the result of the reduction of the specified {@code action}.
|
||||
*/
|
||||
function _appWillMount(store, next, action) {
|
||||
function _appWillMount(store: IStore, next: Function, action: AnyAction) {
|
||||
if (isOldJitsiMeetElectronApp()) {
|
||||
const { dispatch } = store;
|
||||
|
|
@ -9,9 +9,7 @@ import { Avatar } from '../../../base/avatar';
|
|||
import Icon from '../../../base/icons/components/Icon';
|
||||
import { IconCheck, IconCloseLarge } from '../../../base/icons/svg';
|
||||
import { withPixelLineHeight } from '../../../base/styles/functions.web';
|
||||
// @ts-ignore
|
||||
import { admitMultiple } from '../../../lobby/actions.web';
|
||||
// @ts-ignore
|
||||
import { getKnockingParticipants, getLobbyEnabled } from '../../../lobby/functions';
|
||||
// @ts-ignore
|
||||
import { Drawer, JitsiPortal } from '../../../toolbox/components/web';
|
||||
|
@ -72,7 +70,7 @@ const useStyles = makeStyles()(theme => {
|
|||
*/
|
||||
export default function LobbyParticipants() {
|
||||
const lobbyEnabled = useSelector(getLobbyEnabled);
|
||||
const participants: Array<Object> = useSelector(getKnockingParticipants);
|
||||
const participants = useSelector(getKnockingParticipants);
|
||||
const { t } = useTranslation();
|
||||
const { classes } = useStyles();
|
||||
const dispatch = useDispatch();
|
||||
|
|
|
@ -2,9 +2,7 @@ import { useCallback, useState } from 'react';
|
|||
import { useDispatch } from 'react-redux';
|
||||
|
||||
import { handleLobbyChatInitialized } from '../chat/actions.any';
|
||||
// eslint-disable-next-line lines-around-comment
|
||||
// @ts-ignore
|
||||
import { approveKnockingParticipant, rejectKnockingParticipant } from '../lobby/actions';
|
||||
import { approveKnockingParticipant, rejectKnockingParticipant } from '../lobby/actions.web';
|
||||
|
||||
interface IDrawerParticipant {
|
||||
displayName?: string;
|
||||
|
@ -24,12 +22,12 @@ export function useLobbyActions(participant?: IDrawerParticipant | null, closeDr
|
|||
return [
|
||||
useCallback(e => {
|
||||
e.stopPropagation();
|
||||
dispatch(approveKnockingParticipant(participant?.participantID));
|
||||
dispatch(approveKnockingParticipant(participant?.participantID ?? ''));
|
||||
closeDrawer?.();
|
||||
}, [ dispatch, closeDrawer ]),
|
||||
|
||||
useCallback(() => {
|
||||
dispatch(rejectKnockingParticipant(participant?.participantID));
|
||||
dispatch(rejectKnockingParticipant(participant?.participantID ?? ''));
|
||||
closeDrawer?.();
|
||||
}, [ dispatch, closeDrawer ]),
|
||||
|
|
@ -26,6 +26,7 @@
|
|||
"react/features/feedback",
|
||||
"react/features/no-audio-signal",
|
||||
"react/features/noise-suppression",
|
||||
"react/features/old-client-notification",
|
||||
"react/features/screen-share",
|
||||
"react/features/stream-effects/noise-suppression",
|
||||
"react/features/stream-effects/rnnoise",
|
||||
|
|
Loading…
Reference in New Issue