From 4bd27730ce1c8a576dd106391abd2a69077466d3 Mon Sep 17 00:00:00 2001 From: Robert Pintilii Date: Thu, 10 Nov 2022 10:45:56 +0200 Subject: [PATCH] ref(TS) Convert some features to TS (#12523) --- react/features/app/functions.native.ts | 2 +- .../{actions.native.js => actions.native.ts} | 15 +-- .../{functions.js => functions.ts} | 11 +- ...dleware.native.js => middleware.native.ts} | 28 ++--- .../{middleware.web.js => middleware.web.ts} | 22 ++-- react/features/authentication/reducer.ts | 4 +- react/features/base/conference/actions.ts | 2 +- react/features/base/config/configType.ts | 1 + react/features/base/config/functions.any.ts | 20 +++ react/features/base/config/functions.web.ts | 20 --- .../features/base/environment/environment.ts | 2 +- react/features/base/media/functions.ts | 2 +- react/features/base/participants/actions.ts | 2 +- .../{actions.native.js => actions.native.ts} | 23 ++-- .../{actions.web.js => actions.web.ts} | 20 ++- .../{functions.any.js => functions.any.ts} | 9 +- ...unctions.native.js => functions.native.ts} | 7 +- .../{functions.web.js => functions.web.ts} | 10 +- .../conference/{logger.js => logger.ts} | 2 - .../{middleware.js => middleware.ts} | 29 ++--- .../connection-indicator/functions.ts | 2 +- .../dropbox/{actions.js => actions.ts} | 1 - .../{functions.any.js => functions.any.ts} | 7 +- ...unctions.native.js => functions.native.ts} | 22 ++-- .../{functions.web.js => functions.web.ts} | 23 ++-- .../features/dropbox/{logger.js => logger.ts} | 2 - .../{actions.any.js => actions.any.ts} | 2 - .../{actions.native.js => actions.native.ts} | 8 +- .../{actions.web.js => actions.web.ts} | 77 ++++++------ .../filmstrip/components/web/Filmstrip.tsx | 2 +- .../components/web/PinnedIndicator.tsx | 2 +- .../{functions.any.js => functions.any.ts} | 12 +- ...unctions.native.js => functions.native.ts} | 58 ++++++--- .../{functions.web.js => functions.web.ts} | 115 +++++++++++------- .../filmstrip/{logger.js => logger.ts} | 2 - ...dleware.native.js => middleware.native.ts} | 14 +-- .../{middleware.web.js => middleware.web.ts} | 41 +++---- .../{subscriber.any.js => subscriber.any.ts} | 4 +- ...scriber.native.js => subscriber.native.ts} | 8 +- .../{subscriber.web.js => subscriber.web.ts} | 21 ++-- react/features/follow-me/subscriber.ts | 2 +- react/features/notifications/types.ts | 1 + .../overlay/{functions.js => functions.ts} | 11 +- .../features/overlay/{logger.js => logger.ts} | 2 - .../overlay/{middleware.js => middleware.ts} | 23 ++-- react/features/overlay/overlays.native.js | 16 --- react/features/overlay/overlays.native.ts | 15 +++ .../{overlays.web.js => overlays.web.ts} | 4 +- react/features/prejoin/functions.ts | 2 +- react/features/reactions/actions.any.ts | 14 ++- react/features/reactions/actions.native.ts | 1 + react/features/reactions/actions.web.ts | 14 +-- react/features/reactions/middleware.ts | 4 +- react/features/screen-share/actions.web.ts | 4 +- .../components/web/ShareAudioDialog.tsx | 4 +- react/features/settings/middleware.web.ts | 2 +- react/features/toolbox/actions.any.ts | 2 +- react/features/video-layout/functions.web.ts | 2 +- react/features/video-layout/subscriber.ts | 4 +- react/features/video-quality/subscriber.ts | 3 +- 60 files changed, 410 insertions(+), 374 deletions(-) rename react/features/authentication/{actions.native.js => actions.native.ts} (84%) rename react/features/authentication/{functions.js => functions.ts} (63%) rename react/features/authentication/{middleware.native.js => middleware.native.ts} (88%) rename react/features/authentication/{middleware.web.js => middleware.web.ts} (86%) rename react/features/conference/{actions.native.js => actions.native.ts} (55%) rename react/features/conference/{actions.web.js => actions.web.ts} (61%) rename react/features/conference/{functions.any.js => functions.any.ts} (62%) rename react/features/conference/{functions.native.js => functions.native.ts} (71%) rename react/features/conference/{functions.web.js => functions.web.ts} (71%) rename react/features/conference/{logger.js => logger.ts} (91%) rename react/features/conference/{middleware.js => middleware.ts} (78%) rename react/features/dropbox/{actions.js => actions.ts} (99%) rename react/features/dropbox/{functions.any.js => functions.any.ts} (92%) rename react/features/dropbox/{functions.native.js => functions.native.ts} (75%) rename react/features/dropbox/{functions.web.js => functions.web.ts} (91%) rename react/features/dropbox/{logger.js => logger.ts} (91%) rename react/features/filmstrip/{actions.any.js => actions.any.ts} (99%) rename react/features/filmstrip/{actions.native.js => actions.native.ts} (93%) rename react/features/filmstrip/{actions.web.js => actions.web.ts} (88%) rename react/features/filmstrip/{functions.any.js => functions.any.ts} (88%) rename react/features/filmstrip/{functions.native.js => functions.native.ts} (83%) rename react/features/filmstrip/{functions.web.js => functions.web.ts} (89%) rename react/features/filmstrip/{logger.js => logger.ts} (91%) rename react/features/filmstrip/{middleware.native.js => middleware.native.ts} (83%) rename react/features/filmstrip/{middleware.web.js => middleware.web.ts} (90%) rename react/features/filmstrip/{subscriber.any.js => subscriber.any.ts} (94%) rename react/features/filmstrip/{subscriber.native.js => subscriber.native.ts} (89%) rename react/features/filmstrip/{subscriber.web.js => subscriber.web.ts} (93%) rename react/features/overlay/{functions.js => functions.ts} (69%) rename react/features/overlay/{logger.js => logger.ts} (91%) rename react/features/overlay/{middleware.js => middleware.ts} (87%) delete mode 100644 react/features/overlay/overlays.native.js create mode 100644 react/features/overlay/overlays.native.ts rename react/features/overlay/{overlays.web.js => overlays.web.ts} (95%) diff --git a/react/features/app/functions.native.ts b/react/features/app/functions.native.ts index 9c43aeea41..8743fa202a 100644 --- a/react/features/app/functions.native.ts +++ b/react/features/app/functions.native.ts @@ -2,7 +2,7 @@ import { NativeModules } from 'react-native'; import { IStateful } from '../base/app/types'; import { toState } from '../base/redux/functions'; -import { getServerURL } from '../base/settings/functions'; +import { getServerURL } from '../base/settings/functions.native'; export * from './functions.any'; diff --git a/react/features/authentication/actions.native.js b/react/features/authentication/actions.native.ts similarity index 84% rename from react/features/authentication/actions.native.js rename to react/features/authentication/actions.native.ts index e0719e6c37..1c61f7187e 100644 --- a/react/features/authentication/actions.native.js +++ b/react/features/authentication/actions.native.ts @@ -1,11 +1,8 @@ -// @flow - -import type { Dispatch } from 'redux'; - import { appNavigate } from '../app/actions'; +import { IStore } from '../app/types'; import { conferenceLeft } from '../base/conference/actions'; import { connectionFailed } from '../base/connection/actions.native'; -import { set } from '../base/redux'; +import { set } from '../base/redux/functions'; import { CANCEL_LOGIN } from './actionTypes'; import { stopWaitForOwner } from './actions.any'; @@ -20,7 +17,7 @@ export * from './actions.any'; * }} */ export function cancelLogin() { - return (dispatch: Dispatch, getState: Function) => { + return (dispatch: IStore['dispatch'], getState: IStore['getState']) => { dispatch({ type: CANCEL_LOGIN }); // XXX The error associated with CONNECTION_FAILED was marked as @@ -36,8 +33,8 @@ export function cancelLogin() { passwordRequired && dispatch( connectionFailed( - passwordRequired, - set(error, 'recoverable', false))); + passwordRequired, // @ts-ignore + set(error, 'recoverable', false) as any)); }; } @@ -47,7 +44,7 @@ export function cancelLogin() { * @returns {Function} */ export function cancelWaitForOwner() { - return (dispatch: Dispatch, getState: Function) => { + return (dispatch: IStore['dispatch'], getState: IStore['getState']) => { dispatch(stopWaitForOwner()); // XXX The error associated with CONFERENCE_FAILED was marked as diff --git a/react/features/authentication/functions.js b/react/features/authentication/functions.ts similarity index 63% rename from react/features/authentication/functions.js rename to react/features/authentication/functions.ts index 6735e548cc..b7200f7e83 100644 --- a/react/features/authentication/functions.js +++ b/react/features/authentication/functions.ts @@ -1,6 +1,5 @@ -// @flow - -import JitsiMeetJS from '../../../react/features/base/lib-jitsi-meet'; +import { IConfig } from '../base/config/configType'; +import JitsiMeetJS from '../base/lib-jitsi-meet'; /** @@ -9,7 +8,7 @@ import JitsiMeetJS from '../../../react/features/base/lib-jitsi-meet'; * @param {Object} config - Configuration state object from store. * @returns {boolean} */ -export const isTokenAuthEnabled = (config: Object) => +export const isTokenAuthEnabled = (config: IConfig) => typeof config.tokenAuthUrl === 'string' && config.tokenAuthUrl.length; @@ -20,6 +19,6 @@ export const isTokenAuthEnabled = (config: Object) => * @param {Object} config - Configuration state object from store. * @returns {string} */ -export const getTokenAuthUrl = (config: Object) => +export const getTokenAuthUrl = (config: IConfig) => JitsiMeetJS.util.AuthUtil.getTokenAuthUrl.bind(null, - config.tokenAuthUrl); + config.tokenAuthUrl); diff --git a/react/features/authentication/middleware.native.js b/react/features/authentication/middleware.native.ts similarity index 88% rename from react/features/authentication/middleware.native.js rename to react/features/authentication/middleware.native.ts index 338ab00b2f..8c853e3cf8 100644 --- a/react/features/authentication/middleware.native.js +++ b/react/features/authentication/middleware.native.ts @@ -1,20 +1,18 @@ -// @flow - -import type { Dispatch } from 'redux'; - -import { appNavigate } from '../app/actions'; +import { appNavigate } from '../app/actions.native'; +import { IStore } from '../app/types'; import { CONFERENCE_FAILED, CONFERENCE_JOINED, CONFERENCE_LEFT -} from '../base/conference'; -import { CONNECTION_ESTABLISHED, CONNECTION_FAILED } from '../base/connection'; -import { hideDialog, isDialogOpen } from '../base/dialog'; +} from '../base/conference/actionTypes'; +import { CONNECTION_ESTABLISHED, CONNECTION_FAILED } from '../base/connection/actionTypes'; +import { hideDialog } from '../base/dialog/actions'; +import { isDialogOpen } from '../base/dialog/functions'; import { JitsiConferenceErrors, JitsiConnectionErrors } from '../base/lib-jitsi-meet'; -import { MiddlewareRegistry } from '../base/redux'; +import MiddlewareRegistry from '../base/redux/MiddlewareRegistry'; import { CANCEL_LOGIN, @@ -26,7 +24,7 @@ import { openLoginDialog, openWaitForOwnerDialog, stopWaitForOwner, - waitForOwner } from './actions.native'; + waitForOwner } from './actions.native'; // @ts-ignore import { LoginDialog, WaitForOwnerDialog } from './components'; /** @@ -44,7 +42,7 @@ MiddlewareRegistry.register(store => next => action => { const { dispatch, getState } = store; const { thenableWithCancel } = getState()['features/authentication']; - thenableWithCancel && thenableWithCancel.cancel(); + thenableWithCancel?.cancel(); // The LoginDialog can be opened on top of "wait for owner". The app // should navigate only if LoginDialog was open without the @@ -142,7 +140,7 @@ MiddlewareRegistry.register(store => next => action => { case WAIT_FOR_OWNER: { _clearExistingWaitForOwnerTimeout(store); - const { handler, timeoutMs } = action; + const { handler, timeoutMs }: { handler: () => void; timeoutMs: number; } = action; action.waitForOwnerTimeoutID = setTimeout(handler, timeoutMs); @@ -165,7 +163,7 @@ MiddlewareRegistry.register(store => next => action => { * @returns {void} */ function _clearExistingWaitForOwnerTimeout( - { getState }: { getState: Function }) { + { getState }: IStore) { const { waitForOwnerTimeoutID } = getState()['features/authentication']; waitForOwnerTimeoutID && clearTimeout(waitForOwnerTimeoutID); @@ -177,7 +175,7 @@ function _clearExistingWaitForOwnerTimeout( * @param {Object} store - The redux store. * @returns {void} */ -function _hideLoginDialog({ dispatch }: { dispatch: Dispatch }) { +function _hideLoginDialog({ dispatch }: IStore) { dispatch(hideDialog(LoginDialog)); } @@ -187,6 +185,6 @@ function _hideLoginDialog({ dispatch }: { dispatch: Dispatch }) { * @param {Object} store - The redux store. * @returns {boolean} */ -function _isWaitingForOwner({ getState }: { getState: Function }) { +function _isWaitingForOwner({ getState }: IStore) { return Boolean(getState()['features/authentication'].waitForOwnerTimeoutID); } diff --git a/react/features/authentication/middleware.web.js b/react/features/authentication/middleware.web.ts similarity index 86% rename from react/features/authentication/middleware.web.js rename to react/features/authentication/middleware.web.ts index 20d97d4ee7..68ea7a1974 100644 --- a/react/features/authentication/middleware.web.js +++ b/react/features/authentication/middleware.web.ts @@ -1,17 +1,17 @@ -// @flow - -import { maybeRedirectToWelcomePage } from '../app/actions'; +import { maybeRedirectToWelcomePage } from '../app/actions.web'; +import { IStore } from '../app/types'; import { CONFERENCE_FAILED, CONFERENCE_JOINED, CONFERENCE_LEFT -} from '../base/conference'; -import { CONNECTION_ESTABLISHED } from '../base/connection'; -import { hideDialog, isDialogOpen } from '../base/dialog'; +} from '../base/conference/actionTypes'; +import { CONNECTION_ESTABLISHED } from '../base/connection/actionTypes'; +import { hideDialog } from '../base/dialog/actions'; +import { isDialogOpen } from '../base/dialog/functions'; import { JitsiConferenceErrors } from '../base/lib-jitsi-meet'; -import { MiddlewareRegistry } from '../base/redux'; +import MiddlewareRegistry from '../base/redux/MiddlewareRegistry'; import { CANCEL_LOGIN, @@ -24,6 +24,8 @@ import { openWaitForOwnerDialog, stopWaitForOwner } from './actions.web'; +// eslint-disable-next-line lines-around-comment +// @ts-ignore import { LoginDialog, WaitForOwnerDialog } from './components'; /** @@ -113,7 +115,7 @@ MiddlewareRegistry.register(store => next => action => { case WAIT_FOR_OWNER: { _clearExistingWaitForOwnerTimeout(store); - const { handler, timeoutMs } = action; + const { handler, timeoutMs }: { handler: () => void; timeoutMs: number; } = action; action.waitForOwnerTimeoutID = setTimeout(handler, timeoutMs); @@ -134,7 +136,7 @@ MiddlewareRegistry.register(store => next => action => { * @returns {void} */ function _clearExistingWaitForOwnerTimeout( - { getState }: { getState: Function }) { + { getState }: IStore) { const { waitForOwnerTimeoutID } = getState()['features/authentication']; waitForOwnerTimeoutID && clearTimeout(waitForOwnerTimeoutID); @@ -146,6 +148,6 @@ function _clearExistingWaitForOwnerTimeout( * @param {Object} store - The redux store. * @returns {void} */ -function _isWaitingForOwner({ getState }: { getState: Function }) { +function _isWaitingForOwner({ getState }: IStore) { return getState()['features/authentication'].waitForOwnerTimeoutID; } diff --git a/react/features/authentication/reducer.ts b/react/features/authentication/reducer.ts index 4dafd2d1ee..41a6e52204 100644 --- a/react/features/authentication/reducer.ts +++ b/react/features/authentication/reducer.ts @@ -12,7 +12,9 @@ import { export interface IAuthenticationState { error?: Object | undefined; progress?: number | undefined; - thenableWithCancel?: Object | undefined; + thenableWithCancel?: { + cancel: Function; + }; waitForOwnerTimeoutID?: number; } diff --git a/react/features/base/conference/actions.ts b/react/features/base/conference/actions.ts index e666060f21..36770f9a86 100644 --- a/react/features/base/conference/actions.ts +++ b/react/features/base/conference/actions.ts @@ -377,7 +377,7 @@ export function conferenceJoinInProgress(conference: IJitsiConference) { * conference: JitsiConference * }} */ -export function conferenceLeft(conference: IJitsiConference) { +export function conferenceLeft(conference: Partial) { return { type: CONFERENCE_LEFT, conference diff --git a/react/features/base/config/configType.ts b/react/features/base/config/configType.ts index 1aec6739d8..cfeda4f2b3 100644 --- a/react/features/base/config/configType.ts +++ b/react/features/base/config/configType.ts @@ -456,6 +456,7 @@ export interface IConfig { tileView?: { numberOfVisibleTiles?: number; }; + tokenAuthUrl?: string; toolbarButtons?: Array; toolbarConfig?: { alwaysVisible?: boolean; diff --git a/react/features/base/config/functions.any.ts b/react/features/base/config/functions.any.ts index 0dd47d7939..a7ac7d9e6b 100644 --- a/react/features/base/config/functions.any.ts +++ b/react/features/base/config/functions.any.ts @@ -286,3 +286,23 @@ export function setConfigFromURLParams( } /* eslint-enable max-params */ + +/** + * Returns the dial out url. + * + * @param {Object} state - The state of the app. + * @returns {string} + */ +export function getDialOutStatusUrl(state: IReduxState) { + return state['features/base/config'].guestDialOutStatusUrl; +} + +/** + * Returns the dial out status url. + * + * @param {Object} state - The state of the app. + * @returns {string} + */ +export function getDialOutUrl(state: IReduxState) { + return state['features/base/config'].guestDialOutUrl; +} diff --git a/react/features/base/config/functions.web.ts b/react/features/base/config/functions.web.ts index a16e62f73c..21d0cae4bd 100644 --- a/react/features/base/config/functions.web.ts +++ b/react/features/base/config/functions.web.ts @@ -14,26 +14,6 @@ export * from './functions.any'; export function _cleanupConfig(config: IConfig) { // eslint-disable-line @typescript-eslint/no-unused-vars } -/** - * Returns the dial out url. - * - * @param {Object} state - The state of the app. - * @returns {string} - */ -export function getDialOutStatusUrl(state: IReduxState): string | undefined { - return state['features/base/config'].guestDialOutStatusUrl; -} - -/** - * Returns the dial out status url. - * - * @param {Object} state - The state of the app. - * @returns {string} - */ -export function getDialOutUrl(state: IReduxState): string | undefined { - return state['features/base/config'].guestDialOutUrl; -} - /** * Returns the replaceParticipant config. * diff --git a/react/features/base/environment/environment.ts b/react/features/base/environment/environment.ts index 920f964b12..fad9795350 100644 --- a/react/features/base/environment/environment.ts +++ b/react/features/base/environment/environment.ts @@ -1,5 +1,5 @@ import JitsiMeetJS from '../lib-jitsi-meet'; -import Platform from '../react/Platform.web'; +import Platform from '../react/Platform'; import { isMobileBrowser } from './utils'; diff --git a/react/features/base/media/functions.ts b/react/features/base/media/functions.ts index 617b88fd74..e20c3bae2a 100644 --- a/react/features/base/media/functions.ts +++ b/react/features/base/media/functions.ts @@ -1,6 +1,6 @@ import { IStateful } from '../app/types'; import { toState } from '../redux/functions'; -import { getPropertyValue } from '../settings/functions.any'; +import { getPropertyValue } from '../settings/functions'; import { VIDEO_MUTISM_AUTHORITY } from './constants'; diff --git a/react/features/base/participants/actions.ts b/react/features/base/participants/actions.ts index 186209c688..5802443b74 100644 --- a/react/features/base/participants/actions.ts +++ b/react/features/base/participants/actions.ts @@ -540,7 +540,7 @@ export function participantKicked(kicker: any, kicked: any) { * } * }} */ -export function pinParticipant(id: string | null) { +export function pinParticipant(id?: string | null) { return { type: PIN_PARTICIPANT, participant: { diff --git a/react/features/conference/actions.native.js b/react/features/conference/actions.native.ts similarity index 55% rename from react/features/conference/actions.native.js rename to react/features/conference/actions.native.ts index 40b48e5691..14a091ccb6 100644 --- a/react/features/conference/actions.native.js +++ b/react/features/conference/actions.native.ts @@ -1,12 +1,9 @@ -// @flow - -import type { Dispatch } from 'redux'; - -import { - AlertDialog, - openDialog -} from '../base/dialog'; -import { getParticipantDisplayName } from '../base/participants'; +import { IStore } from '../app/types'; +import { openDialog } from '../base/dialog/actions'; +// eslint-disable-next-line lines-around-comment +// @ts-ignore +import { AlertDialog } from '../base/dialog/components/native'; +import { getParticipantDisplayName } from '../base/participants/functions'; /** * Notify that we've been kicked out of the conference. @@ -16,10 +13,10 @@ import { getParticipantDisplayName } from '../base/participants'; * @param {?Function} submit - The function to execute after submiting the dialog. * @returns {Function} */ -export function notifyKickedOut(participant: Object, submit: ?Function) { - return (dispatch: Dispatch, getState: Function) => { - if (!participant || (participant.isReplaced && participant.isReplaced())) { - submit && submit(); +export function notifyKickedOut(participant: any, submit?: Function) { + return (dispatch: IStore['dispatch'], getState: IStore['getState']) => { + if (!participant || participant?.isReplaced?.()) { + submit?.(); return; } diff --git a/react/features/conference/actions.web.js b/react/features/conference/actions.web.ts similarity index 61% rename from react/features/conference/actions.web.js rename to react/features/conference/actions.web.ts index faf83c8b9c..b1d42237e6 100644 --- a/react/features/conference/actions.web.js +++ b/react/features/conference/actions.web.ts @@ -1,13 +1,7 @@ -// @flow - -import type { Dispatch } from 'redux'; - -import { getParticipantDisplayName } from '../base/participants'; -import { - NOTIFICATION_TIMEOUT_TYPE, - NOTIFICATION_TYPE, - showNotification -} from '../notifications'; +import { IStore } from '../app/types'; +import { getParticipantDisplayName } from '../base/participants/functions'; +import { showNotification } from '../notifications/actions'; +import { NOTIFICATION_TIMEOUT_TYPE, NOTIFICATION_TYPE } from '../notifications/constants'; /** * Notify that we've been kicked out of the conference. @@ -17,9 +11,9 @@ import { * @param {?Function} _ - Used only in native code. * @returns {Function} */ -export function notifyKickedOut(participant: Object, _: ?Function) { // eslint-disable-line no-unused-vars - return (dispatch: Dispatch, getState: Function) => { - if (!participant || (participant.isReplaced && participant.isReplaced())) { +export function notifyKickedOut(participant: any, _?: Function) { + return (dispatch: IStore['dispatch'], getState: IStore['getState']) => { + if (!participant || participant?.isReplaced()) { return; } diff --git a/react/features/conference/functions.any.js b/react/features/conference/functions.any.ts similarity index 62% rename from react/features/conference/functions.any.js rename to react/features/conference/functions.any.ts index ece236f316..f310cc6332 100644 --- a/react/features/conference/functions.any.js +++ b/react/features/conference/functions.any.ts @@ -1,6 +1,7 @@ -import { toState } from '../base/redux'; -import { areThereNotifications } from '../notifications'; -import { getOverlayToRender } from '../overlay'; +import { IStateful } from '../base/app/types'; +import { toState } from '../base/redux/functions'; +import { areThereNotifications } from '../notifications/functions'; +import { getOverlayToRender } from '../overlay/functions'; /** * Tells whether or not the notifications should be displayed within @@ -9,7 +10,7 @@ import { getOverlayToRender } from '../overlay'; * @param {Object|Function} stateful - The redux store state. * @returns {boolean} */ -export function shouldDisplayNotifications(stateful) { +export function shouldDisplayNotifications(stateful: IStateful) { const state = toState(stateful); const isAnyOverlayVisible = Boolean(getOverlayToRender(state)); const { calleeInfoVisible } = state['features/invite']; diff --git a/react/features/conference/functions.native.js b/react/features/conference/functions.native.ts similarity index 71% rename from react/features/conference/functions.native.js rename to react/features/conference/functions.native.ts index c49aebfc58..d62a013613 100644 --- a/react/features/conference/functions.native.js +++ b/react/features/conference/functions.native.ts @@ -1,6 +1,5 @@ -// @flow - -import { toState } from '../base/redux'; +import { IStateful } from '../base/app/types'; +import { toState } from '../base/redux/functions'; export * from './functions.any'; @@ -14,7 +13,7 @@ export * from './functions.any'; * features/base/config. * @returns {boolean}. */ -export function getDisablePolls(stateful: Object) { +export function getDisablePolls(stateful: IStateful) { const state = toState(stateful)['features/base/config']; return state.disablePolls; diff --git a/react/features/conference/functions.web.js b/react/features/conference/functions.web.ts similarity index 71% rename from react/features/conference/functions.web.js rename to react/features/conference/functions.web.ts index fa56c34a6e..989d469b6d 100644 --- a/react/features/conference/functions.web.js +++ b/react/features/conference/functions.web.ts @@ -1,6 +1,8 @@ -import { isSuboptimalBrowser } from '../base/environment'; -import { translateToHTML } from '../base/i18n'; -import { NOTIFICATION_TIMEOUT_TYPE, showWarningNotification } from '../notifications'; +import { IStore } from '../app/types'; +import { isSuboptimalBrowser } from '../base/environment/environment'; +import { translateToHTML } from '../base/i18n/functions'; +import { showWarningNotification } from '../notifications/actions'; +import { NOTIFICATION_TIMEOUT_TYPE } from '../notifications/constants'; export * from './functions.any'; @@ -11,7 +13,7 @@ export * from './functions.any'; * @param {Function} t - The translation function. * @returns {void} */ -export function maybeShowSuboptimalExperienceNotification(dispatch, t) { +export function maybeShowSuboptimalExperienceNotification(dispatch: IStore['dispatch'], t: Function) { if (isSuboptimalBrowser()) { dispatch( showWarningNotification( diff --git a/react/features/conference/logger.js b/react/features/conference/logger.ts similarity index 91% rename from react/features/conference/logger.js rename to react/features/conference/logger.ts index 352219cb9a..d928123c07 100644 --- a/react/features/conference/logger.js +++ b/react/features/conference/logger.ts @@ -1,5 +1,3 @@ -// @flow - import { getLogger } from '../base/logging/functions'; export default getLogger('features/conference'); diff --git a/react/features/conference/middleware.js b/react/features/conference/middleware.ts similarity index 78% rename from react/features/conference/middleware.js rename to react/features/conference/middleware.ts index 4c89a8fb18..131a61a374 100644 --- a/react/features/conference/middleware.js +++ b/react/features/conference/middleware.ts @@ -1,17 +1,18 @@ -// @flow import { appNavigate } from '../app/actions'; -import { - CONFERENCE_JOINED, - KICKED_OUT, - conferenceLeft, - getCurrentConference -} from '../base/conference'; -import { hideDialog, isDialogOpen } from '../base/dialog'; -import { pinParticipant } from '../base/participants'; -import { MiddlewareRegistry, StateListenerRegistry } from '../base/redux'; -import { SET_REDUCED_UI } from '../base/responsive-ui'; +import { IStore } from '../app/types'; +import { CONFERENCE_JOINED, KICKED_OUT } from '../base/conference/actionTypes'; +import { conferenceLeft } from '../base/conference/actions'; +import { getCurrentConference } from '../base/conference/functions'; +import { hideDialog } from '../base/dialog/actions'; +import { isDialogOpen } from '../base/dialog/functions'; +import { pinParticipant } from '../base/participants/actions'; +import MiddlewareRegistry from '../base/redux/MiddlewareRegistry'; +import StateListenerRegistry from '../base/redux/StateListenerRegistry'; +import { SET_REDUCED_UI } from '../base/responsive-ui/actionTypes'; +// eslint-disable-next-line lines-around-comment +// @ts-ignore import { FeedbackDialog } from '../feedback'; -import { setFilmstripEnabled } from '../filmstrip'; +import { setFilmstripEnabled } from '../filmstrip/actions'; import { showSalesforceNotification } from '../salesforce/actions'; import { setToolboxEnabled } from '../toolbox/actions'; @@ -90,7 +91,7 @@ StateListenerRegistry.register( * @private * @returns {void} */ -function _setReducedUI({ dispatch, getState }) { +function _setReducedUI({ dispatch, getState }: IStore) { const { reducedUI } = getState()['features/base/responsive-ui']; dispatch(setToolboxEnabled(!reducedUI)); @@ -106,7 +107,7 @@ function _setReducedUI({ dispatch, getState }) { * @private * @returns {void} */ -function _conferenceJoined({ dispatch, getState }) { +function _conferenceJoined({ dispatch, getState }: IStore) { _setReducedUI({ dispatch, getState diff --git a/react/features/connection-indicator/functions.ts b/react/features/connection-indicator/functions.ts index 7d2e3cf1d2..74858ffc91 100644 --- a/react/features/connection-indicator/functions.ts +++ b/react/features/connection-indicator/functions.ts @@ -7,7 +7,7 @@ import { ITrack } from '../base/tracks/types'; * @param {Object} videoTrack - Track reference. * @returns {boolean} - Is streaming status active. */ -export function isTrackStreamingStatusActive(videoTrack: ITrack) { +export function isTrackStreamingStatusActive(videoTrack?: ITrack) { const streamingStatus = videoTrack?.streamingStatus; return streamingStatus === JitsiTrackStreamingStatus.ACTIVE; diff --git a/react/features/dropbox/actions.js b/react/features/dropbox/actions.ts similarity index 99% rename from react/features/dropbox/actions.js rename to react/features/dropbox/actions.ts index 258e5d3b01..3e7a609eb7 100644 --- a/react/features/dropbox/actions.js +++ b/react/features/dropbox/actions.ts @@ -1,4 +1,3 @@ -// @flow import { UPDATE_DROPBOX_TOKEN } from './actionTypes'; import { _authorizeDropbox } from './functions'; import logger from './logger'; diff --git a/react/features/dropbox/functions.any.js b/react/features/dropbox/functions.any.ts similarity index 92% rename from react/features/dropbox/functions.any.js rename to react/features/dropbox/functions.any.ts index 1a587c82a1..b6ea2da893 100644 --- a/react/features/dropbox/functions.any.js +++ b/react/features/dropbox/functions.any.ts @@ -1,4 +1,3 @@ -// @flow export * from './functions'; import { getDisplayName, getSpaceUsage } from './functions'; @@ -12,12 +11,12 @@ type DropboxUserData = { /** * The available space left in MB into the user's Dropbox account. */ - spaceLeft: number, + spaceLeft: number; /** * The display name of the user in Dropbox. */ - userName: string + userName: string; }; /** @@ -30,7 +29,7 @@ type DropboxUserData = { export function getDropboxData( token: string, appKey: string -): Promise { +): Promise { return Promise.all( [ getDisplayName(token, appKey), getSpaceUsage(token, appKey) ] ).then(([ userName, space ]) => { diff --git a/react/features/dropbox/functions.native.js b/react/features/dropbox/functions.native.ts similarity index 75% rename from react/features/dropbox/functions.native.js rename to react/features/dropbox/functions.native.ts index dbc8ae7d13..4a93764bbe 100644 --- a/react/features/dropbox/functions.native.js +++ b/react/features/dropbox/functions.native.ts @@ -1,18 +1,21 @@ -// @flow - import { NativeModules } from 'react-native'; -const { Dropbox } = NativeModules; - +import { IReduxState } from '../app/types'; +// eslint-disable-next-line lines-around-comment +// @ts-ignore import { setPictureInPictureEnabled } from '../mobile/picture-in-picture/functions'; +const { Dropbox } = NativeModules; + /** * Action to authorize the Jitsi Recording app in dropbox. * + * @param {any} _appKey - Used on web. + * @param {any} _redirectURI - Used on web. * @returns {Promise} - The promise will be resolved with the dropbox * access token or rejected with an error. */ -export async function _authorizeDropbox(): Promise { +export async function _authorizeDropbox(_appKey?: any, _redirectURI?: any): Promise { setPictureInPictureEnabled(false); try { @@ -35,10 +38,11 @@ export function getNewAccessToken() { * Returns the display name for the current dropbox account. * * @param {string} token - The dropbox access token. + * @param {any} _appKey - Used on web. * @returns {Promise} - The promise will be resolved with the display * name or rejected with an error. */ -export function getDisplayName(token: string) { +export function getDisplayName(token: string, _appKey?: any) { return Dropbox.getDisplayName(token); } @@ -46,12 +50,13 @@ export function getDisplayName(token: string) { * Returns information about the space usage for the current dropbox account. * * @param {string} token - The dropbox access token. + * @param {any} _appKey - Used on web. * @returns {Promise<{ used: number, allocated: number}>} - The promise will be * resolved with the object with information about the space usage (the used * space and the allocated space) for the current dropbox account or rejected * with an error. */ -export function getSpaceUsage(token: string) { +export function getSpaceUsage(token: string, _appKey?: any) { return Dropbox.getSpaceUsage(token); } @@ -62,8 +67,9 @@ export function getSpaceUsage(token: string) { * @param {Object} state - The redux state. * @returns {boolean} */ -export function isEnabled(state: Object) { +export function isEnabled(state: IReduxState) { const { dropbox = {} } = state['features/base/config']; + // @ts-ignore return Boolean(Dropbox?.ENABLED && typeof dropbox.appKey === 'string'); } diff --git a/react/features/dropbox/functions.web.js b/react/features/dropbox/functions.web.ts similarity index 91% rename from react/features/dropbox/functions.web.js rename to react/features/dropbox/functions.web.ts index bb90c82047..8f007c88b2 100644 --- a/react/features/dropbox/functions.web.js +++ b/react/features/dropbox/functions.web.ts @@ -1,7 +1,7 @@ -// @flow - import { Dropbox, DropboxAuth } from 'dropbox'; +import { IReduxState } from '../app/types'; + /** * Executes the oauth flow. * @@ -13,8 +13,8 @@ function authorize(authUrl: string): Promise { return new Promise(resolve => { // eslint-disable-next-line prefer-const - let popup; - const handleAuth = ({ data }) => { + let popup: any; + const handleAuth = ({ data }: { data: { type: string; url: string; windowName: string; }; }) => { if (data && data.type === 'dropbox-login' && data.windowName === windowName) { if (popup) { popup.close(); @@ -49,18 +49,20 @@ function getTokenExpiresAtTimestamp(expiresIn: number) { export function _authorizeDropbox( appKey: string, redirectURI: string -): Promise { +): Promise { const dropbox = new DropboxAuth({ clientId: appKey }); return dropbox.getAuthenticationUrl(redirectURI, undefined, 'code', 'offline', undefined, undefined, true) + + // @ts-ignore .then(authorize) .then(returnUrl => { const params = new URLSearchParams(new URL(returnUrl).search); const code = params.get('code'); - return dropbox.getAccessTokenFromCode(redirectURI, code); + return dropbox.getAccessTokenFromCode(redirectURI, code ?? ''); }) - .then(resp => { + .then((resp: any) => { return { token: resp.result.access_token, rToken: resp.result.refresh_token, @@ -82,7 +84,7 @@ export function getNewAccessToken(appKey: string, rToken: string) { dropbox.setRefreshToken(rToken); - return dropbox.refreshAccessToken() + return dropbox.refreshAccessToken() // @ts-ignore .then(() => { return { token: dropbox.getAccessToken(), @@ -125,6 +127,8 @@ export function getSpaceUsage(token: string, appKey: string) { return dropboxAPI.usersGetSpaceUsage().then(space => { const { allocation, used } = space.result; + + // @ts-ignore const { allocated } = allocation; return { @@ -141,8 +145,9 @@ export function getSpaceUsage(token: string, appKey: string) { * @param {Object} state - The redux state. * @returns {boolean} */ -export function isEnabled(state: Object) { +export function isEnabled(state: IReduxState) { const { dropbox = {} } = state['features/base/config']; + // @ts-ignore return typeof dropbox.appKey === 'string'; } diff --git a/react/features/dropbox/logger.js b/react/features/dropbox/logger.ts similarity index 91% rename from react/features/dropbox/logger.js rename to react/features/dropbox/logger.ts index f9a0376880..b94caf8753 100644 --- a/react/features/dropbox/logger.js +++ b/react/features/dropbox/logger.ts @@ -1,5 +1,3 @@ -// @flow - import { getLogger } from '../base/logging/functions'; export default getLogger('features/dropbox'); diff --git a/react/features/filmstrip/actions.any.js b/react/features/filmstrip/actions.any.ts similarity index 99% rename from react/features/filmstrip/actions.any.js rename to react/features/filmstrip/actions.any.ts index ba89ef23fd..9a82d57ecd 100644 --- a/react/features/filmstrip/actions.any.js +++ b/react/features/filmstrip/actions.any.ts @@ -1,5 +1,3 @@ -// @flow - import { SET_FILMSTRIP_ENABLED, SET_FILMSTRIP_VISIBLE, diff --git a/react/features/filmstrip/actions.native.js b/react/features/filmstrip/actions.native.ts similarity index 93% rename from react/features/filmstrip/actions.native.js rename to react/features/filmstrip/actions.native.ts index c5a151540c..a1be903c72 100644 --- a/react/features/filmstrip/actions.native.js +++ b/react/features/filmstrip/actions.native.ts @@ -1,12 +1,12 @@ -// @flow - +// @ts-ignore import conferenceStyles from '../conference/components/native/styles'; import { SET_TILE_VIEW_DIMENSIONS } from './actionTypes'; +// eslint-disable-next-line lines-around-comment +// @ts-ignore import { styles } from './components'; import { SQUARE_TILE_ASPECT_RATIO, TILE_MARGIN } from './constants'; -import { getColumnCount } from './functions'; -import { getTileViewParticipantCount } from './functions.native'; +import { getColumnCount, getTileViewParticipantCount } from './functions.native'; export * from './actions.any'; diff --git a/react/features/filmstrip/actions.web.js b/react/features/filmstrip/actions.web.ts similarity index 88% rename from react/features/filmstrip/actions.web.js rename to react/features/filmstrip/actions.web.ts index 1a4098c09c..d0b539701b 100644 --- a/react/features/filmstrip/actions.web.js +++ b/react/features/filmstrip/actions.web.ts @@ -1,14 +1,12 @@ -// @flow -import type { Dispatch } from 'redux'; - +import { IStore } from '../app/types'; +import { pinParticipant } from '../base/participants/actions'; import { getLocalParticipant, getParticipantById, - getRemoteParticipantCount, - pinParticipant -} from '../base/participants'; -import { shouldHideSelfView } from '../base/settings/functions.any'; -import { getMaxColumnCount } from '../video-layout'; + getRemoteParticipantCount +} from '../base/participants/functions'; +import { shouldHideSelfView } from '../base/settings/functions.web'; +import { getMaxColumnCount } from '../video-layout/functions.web'; import { ADD_STAGE_PARTICIPANT, @@ -54,10 +52,9 @@ import { getNumberOfPartipantsForTileView, getVerticalViewMaxWidth, isFilmstripResizable, - isStageFilmstripTopPanel, - showGridInVerticalView -} from './functions'; -import { isStageFilmstripAvailable } from './functions.web'; + isStageFilmstripAvailable, + isStageFilmstripTopPanel + , showGridInVerticalView } from './functions.web'; export * from './actions.any'; @@ -71,7 +68,7 @@ export * from './actions.any'; * width: number, * }} */ -export function resizeFilmStrip(width) { +export function resizeFilmStrip(width: number) { return { type: RESIZE_FILMSTRIP, width @@ -84,7 +81,7 @@ export function resizeFilmStrip(width) { * @returns {Function} */ export function setTileViewDimensions() { - return (dispatch: Dispatch, getState: Function) => { + return (dispatch: IStore['dispatch'], getState: IStore['getState']) => { const state = getState(); const { clientHeight, clientWidth } = state['features/base/responsive-ui']; const { @@ -111,11 +108,12 @@ export function setTileViewDimensions() { numberOfParticipants, desiredNumberOfVisibleTiles: numberOfVisibleTiles }); - const thumbnailsTotalHeight = rows * (TILE_VERTICAL_MARGIN + height); + const thumbnailsTotalHeight = (rows ?? 1) * (TILE_VERTICAL_MARGIN + (height ?? 0)); const availableHeight = clientHeight - TILE_VIEW_GRID_VERTICAL_MARGIN; const hasScroll = availableHeight < thumbnailsTotalHeight; const filmstripWidth - = Math.min(clientWidth - TILE_VIEW_GRID_HORIZONTAL_MARGIN, columns * (TILE_HORIZONTAL_MARGIN + width)) + = Math.min(clientWidth - TILE_VIEW_GRID_HORIZONTAL_MARGIN, + (columns ?? 1) * (TILE_HORIZONTAL_MARGIN + (width ?? 0))) + (hasScroll ? SCROLL_SIZE : 0); const filmstripHeight = Math.min(availableHeight, thumbnailsTotalHeight); @@ -144,7 +142,7 @@ export function setTileViewDimensions() { * @returns {Function} */ export function setVerticalViewDimensions() { - return (dispatch: Dispatch, getState: Function) => { + return (dispatch: IStore['dispatch'], getState: IStore['getState']) => { const state = getState(); const { clientHeight = 0, clientWidth = 0 } = state['features/base/responsive-ui']; const { width: filmstripWidth } = state['features/filmstrip']; @@ -155,7 +153,7 @@ export function setVerticalViewDimensions() { const { localScreenShare } = state['features/base/participants']; let gridView = {}; - let thumbnails = {}; + let thumbnails: any = {}; let filmstripDimensions = {}; let hasScroll = false; let remoteVideosContainerWidth; @@ -177,7 +175,7 @@ export function setVerticalViewDimensions() { columns, rows } = calculateResponsiveTileViewDimensions({ - clientWidth: filmstripWidth.current, + clientWidth: filmstripWidth.current ?? 0, clientHeight, disableTileEnlargement: false, maxColumns, @@ -185,10 +183,11 @@ export function setVerticalViewDimensions() { numberOfParticipants, desiredNumberOfVisibleTiles: numberOfVisibleTiles }); - const thumbnailsTotalHeight = rows * (TILE_VERTICAL_MARGIN + height); + const thumbnailsTotalHeight = (rows ?? 1) * (TILE_VERTICAL_MARGIN + (height ?? 0)); hasScroll = clientHeight < thumbnailsTotalHeight; - const widthOfFilmstrip = (columns * (TILE_HORIZONTAL_MARGIN + width)) + (hasScroll ? SCROLL_SIZE : 0); + const widthOfFilmstrip = ((columns ?? 1) * (TILE_HORIZONTAL_MARGIN + (width ?? 0))) + + (hasScroll ? SCROLL_SIZE : 0); const filmstripHeight = Math.min(clientHeight - TILE_VIEW_GRID_VERTICAL_MARGIN, thumbnailsTotalHeight); gridView = { @@ -208,7 +207,8 @@ export function setVerticalViewDimensions() { width: widthOfFilmstrip }; } else { - thumbnails = calculateThumbnailSizeForVerticalView(clientWidth, filmstripWidth.current, resizableFilmstrip); + thumbnails = calculateThumbnailSizeForVerticalView(clientWidth, filmstripWidth.current ?? 0, + resizableFilmstrip); remoteVideosContainerWidth = thumbnails?.local?.width + TILE_VERTICAL_CONTAINER_HORIZONTAL_MARGIN + SCROLL_SIZE; @@ -252,7 +252,7 @@ export function setVerticalViewDimensions() { * @returns {Function} */ export function setHorizontalViewDimensions() { - return (dispatch: Dispatch, getState: Function) => { + return (dispatch: IStore['dispatch'], getState: IStore['getState']) => { const state = getState(); const { clientHeight = 0, clientWidth = 0 } = state['features/base/responsive-ui']; const disableSelfView = shouldHideSelfView(state); @@ -286,7 +286,7 @@ export function setHorizontalViewDimensions() { * @returns {Function} */ export function setStageFilmstripViewDimensions() { - return (dispatch: Dispatch, getState: Function) => { + return (dispatch: IStore['dispatch'], getState: IStore['getState']) => { const state = getState(); const { clientHeight, clientWidth } = state['features/base/responsive-ui']; const { @@ -316,13 +316,14 @@ export function setStageFilmstripViewDimensions() { maxColumns, noHorizontalContainerMargin: verticalWidth > 0, numberOfParticipants, - numberOfVisibleTiles, + desiredNumberOfVisibleTiles: numberOfVisibleTiles, minTileHeight: topPanel ? TILE_MIN_HEIGHT_SMALL : null }); - const thumbnailsTotalHeight = rows * (TILE_VERTICAL_MARGIN + height); + const thumbnailsTotalHeight = (rows ?? 1) * (TILE_VERTICAL_MARGIN + (height ?? 0)); const hasScroll = clientHeight < thumbnailsTotalHeight; const filmstripWidth - = Math.min(clientWidth - TILE_VIEW_GRID_HORIZONTAL_MARGIN, columns * (TILE_HORIZONTAL_MARGIN + width)) + = Math.min(clientWidth - TILE_VIEW_GRID_HORIZONTAL_MARGIN, + (columns ?? 1) * (TILE_HORIZONTAL_MARGIN + (width ?? 0))) + (hasScroll ? SCROLL_SIZE : 0); const filmstripHeight = Math.min(clientHeight - TILE_VIEW_GRID_VERTICAL_MARGIN, thumbnailsTotalHeight); @@ -352,9 +353,9 @@ export function setStageFilmstripViewDimensions() { * @returns {Function} */ export function clickOnVideo(n: number) { - return (dispatch: Function, getState: Function) => { + return (dispatch: IStore['dispatch'], getState: IStore['getState']) => { const state = getState(); - const { id: localId } = getLocalParticipant(state); + const { id: localId } = getLocalParticipant(state) ?? {}; // Use the list that correctly represents the current order of the participants as visible in the UI. const { remoteParticipants } = state['features/filmstrip']; @@ -363,10 +364,10 @@ export function clickOnVideo(n: number) { if (participants.length - 1 < n) { return; } - const { id, pinned } = getParticipantById(state, participants[n]); + const { id, pinned } = getParticipantById(state, participants[n] ?? '') ?? {}; if (isStageFilmstripAvailable(state)) { - dispatch(togglePinStageParticipant(id)); + dispatch(togglePinStageParticipant(id ?? '')); } else { dispatch(pinParticipant(pinned ? null : id)); } @@ -476,7 +477,7 @@ export function setUserIsResizing(resizing: boolean) { * @param {boolean?} pinned - Whether the participant is pinned or not. * @returns {Object} */ -export function addStageParticipant(participantId, pinned = false) { +export function addStageParticipant(participantId: string, pinned = false) { return { type: ADD_STAGE_PARTICIPANT, participantId, @@ -490,7 +491,7 @@ export function addStageParticipant(participantId, pinned = false) { * @param {string} participantId - The Id of the participant to be removed. * @returns {Object} */ -export function removeStageParticipant(participantId) { +export function removeStageParticipant(participantId: string) { return { type: REMOVE_STAGE_PARTICIPANT, participantId @@ -503,7 +504,7 @@ export function removeStageParticipant(participantId) { * @param {Array} queue - The new list. * @returns {Object} */ -export function setStageParticipants(queue) { +export function setStageParticipants(queue: Object[]) { return { type: SET_STAGE_PARTICIPANTS, queue @@ -516,7 +517,7 @@ export function setStageParticipants(queue) { * @param {string} participantId - The id of the participant to be toggled. * @returns {Object} */ -export function togglePinStageParticipant(participantId) { +export function togglePinStageParticipant(participantId: string) { return { type: TOGGLE_PIN_STAGE_PARTICIPANT, participantId @@ -540,7 +541,7 @@ export function clearStageParticipants() { * @returns {Object} */ export function setScreensharingTileDimensions() { - return (dispatch: Dispatch, getState: Function) => { + return (dispatch: IStore['dispatch'], getState: IStore['getState']) => { const state = getState(); const { clientHeight, clientWidth } = state['features/base/responsive-ui']; const { visible, topPanelHeight, topPanelVisible } = state['features/filmstrip']; @@ -569,7 +570,7 @@ export function setScreensharingTileDimensions() { * @param {boolean} visible - Whether it should be visible or not. * @returns {Object} */ -export function setTopPanelVisible(visible) { +export function setTopPanelVisible(visible: boolean) { return { type: SET_TOP_PANEL_VISIBILITY, visible @@ -582,7 +583,7 @@ export function setTopPanelVisible(visible) { * @param {string|undefined} participantId - The id of the participant to be set. * @returns {Object} */ -export function setScreenshareFilmstripParticipant(participantId) { +export function setScreenshareFilmstripParticipant(participantId?: string) { return { type: SET_SCREENSHARE_FILMSTRIP_PARTICIPANT, participantId diff --git a/react/features/filmstrip/components/web/Filmstrip.tsx b/react/features/filmstrip/components/web/Filmstrip.tsx index afa53e0f97..e6316cc465 100644 --- a/react/features/filmstrip/components/web/Filmstrip.tsx +++ b/react/features/filmstrip/components/web/Filmstrip.tsx @@ -16,7 +16,7 @@ import Icon from '../../../base/icons/components/Icon'; import { IconArrowDown, IconArrowUp } from '../../../base/icons/svg'; import { IParticipant } from '../../../base/participants/types'; import { connect } from '../../../base/redux/functions'; -import { shouldHideSelfView } from '../../../base/settings/functions.any'; +import { shouldHideSelfView } from '../../../base/settings/functions.web'; // @ts-ignore import { showToolbox } from '../../../toolbox/actions.web'; import { isButtonEnabled, isToolboxVisible } from '../../../toolbox/functions.web'; diff --git a/react/features/filmstrip/components/web/PinnedIndicator.tsx b/react/features/filmstrip/components/web/PinnedIndicator.tsx index 18af61fc37..60f449bd1e 100644 --- a/react/features/filmstrip/components/web/PinnedIndicator.tsx +++ b/react/features/filmstrip/components/web/PinnedIndicator.tsx @@ -57,7 +57,7 @@ const PinnedIndicator = ({ }: IProps) => { const stageFilmstrip = useSelector(isStageFilmstripAvailable); const pinned = useSelector((state: IReduxState) => getParticipantById(state, participantId))?.pinned; - const activePinnedParticipants: Array<{ participantId: string; pinned: boolean; }> + const activePinnedParticipants: Array<{ participantId: string; pinned?: boolean; }> = useSelector(getPinnedActiveParticipants); const isPinned = activePinnedParticipants.find(p => p.participantId === participantId); const { classes: styles } = useStyles(); diff --git a/react/features/filmstrip/functions.any.js b/react/features/filmstrip/functions.any.ts similarity index 88% rename from react/features/filmstrip/functions.any.js rename to react/features/filmstrip/functions.any.ts index 2e7f529fbb..364f335961 100644 --- a/react/features/filmstrip/functions.any.js +++ b/react/features/filmstrip/functions.any.ts @@ -1,4 +1,8 @@ -import { getActiveSpeakersToBeDisplayed, getVirtualScreenshareParticipantOwnerId } from '../base/participants'; +import { IStore } from '../app/types'; +import { + getActiveSpeakersToBeDisplayed, + getVirtualScreenshareParticipantOwnerId +} from '../base/participants/functions'; import { setRemoteParticipants } from './actions'; import { isFilmstripScrollVisible } from './functions'; @@ -11,7 +15,7 @@ import { isFilmstripScrollVisible } from './functions'; * @returns {void} * @private */ -export function updateRemoteParticipants(store: Object, participantId: ?number) { +export function updateRemoteParticipants(store: IStore, participantId?: string) { const state = store.getState(); let reorderedParticipants = []; const { sortedRemoteVirtualScreenshareParticipants } = state['features/base/participants']; @@ -53,7 +57,7 @@ export function updateRemoteParticipants(store: Object, participantId: ?number) } // Always update the order of the thumnails. - const participantsWithScreenShare = screenShareParticipants.reduce((acc, screenshare) => { + const participantsWithScreenShare = screenShareParticipants.reduce((acc, screenshare) => { const ownerId = getVirtualScreenshareParticipantOwnerId(screenshare); acc.push(ownerId); @@ -80,7 +84,7 @@ export function updateRemoteParticipants(store: Object, participantId: ?number) * @returns {void} * @private */ -export function updateRemoteParticipantsOnLeave(store: Object, participantId: ?string = null) { +export function updateRemoteParticipantsOnLeave(store: IStore, participantId: string | null = null) { if (!participantId) { return; } diff --git a/react/features/filmstrip/functions.native.js b/react/features/filmstrip/functions.native.ts similarity index 83% rename from react/features/filmstrip/functions.native.js rename to react/features/filmstrip/functions.native.ts index d44f7f3208..ef1e58fbcd 100644 --- a/react/features/filmstrip/functions.native.js +++ b/react/features/filmstrip/functions.native.ts @@ -1,18 +1,22 @@ -// @flow - -import { FILMSTRIP_ENABLED, getFeatureFlag } from '../base/flags'; +import { IReduxState } from '../app/types'; +import { IStateful } from '../base/app/types'; +import { FILMSTRIP_ENABLED } from '../base/flags/constants'; +import { getFeatureFlag } from '../base/flags/functions'; import { getLocalParticipant, getParticipantCountWithFake, getPinnedParticipant -} from '../base/participants'; -import { Platform } from '../base/react'; -import { toState } from '../base/redux'; +} from '../base/participants/functions'; +import Platform from '../base/react/Platform.native'; +import { toState } from '../base/redux/functions'; import { ASPECT_RATIO_NARROW } from '../base/responsive-ui/constants'; -import { shouldHideSelfView } from '../base/settings/functions.any'; +import { shouldHideSelfView } from '../base/settings/functions.native'; +// eslint-disable-next-line lines-around-comment +// @ts-ignore import conferenceStyles from '../conference/components/native/styles'; -import { shouldDisplayTileView } from '../video-layout'; +import { shouldDisplayTileView } from '../video-layout/functions.native'; +// @ts-ignore import { styles } from './components'; export * from './functions.any'; @@ -27,7 +31,7 @@ export * from './functions.any'; * resolved to a Redux state object with the toState function. * @returns {boolean} */ -export function isFilmstripVisible(stateful: Object | Function) { +export function isFilmstripVisible(stateful: IStateful) { const state = toState(stateful); const enabled = getFeatureFlag(state, FILMSTRIP_ENABLED, true); @@ -47,7 +51,7 @@ export function isFilmstripVisible(stateful: Object | Function) { * @returns {boolean} - If remote video thumbnails should be displayed/visible * in the filmstrip, then {@code true}; otherwise, {@code false}. */ -export function shouldRemoteVideosBeVisible(state: Object) { +export function shouldRemoteVideosBeVisible(state: IReduxState) { if (state['features/invite'].calleeInfoVisible) { return false; } @@ -74,9 +78,10 @@ export function shouldRemoteVideosBeVisible(state: Object) { /** * Not implemented on mobile. * + * @param {any} _state - Used on web. * @returns {Array} */ -export function getActiveParticipantsIds() { +export function getActiveParticipantsIds(_state: any) { return []; } @@ -87,7 +92,7 @@ export function getActiveParticipantsIds() { * resolved to a Redux state object with the toState function. * @returns {number} - The number of participants displayed in tile view. */ -export function getTileViewParticipantCount(stateful: Object | Function) { +export function getTileViewParticipantCount(stateful: IStateful) { const state = toState(stateful); const disableSelfView = shouldHideSelfView(state); const localParticipant = getLocalParticipant(state); @@ -104,7 +109,7 @@ export function getTileViewParticipantCount(stateful: Object | Function) { * @returns {number} - The number of columns to be rendered in tile view. * @private */ -export function getColumnCount(stateful: Object | Function) { +export function getColumnCount(stateful: IStateful) { const state = toState(stateful); const participantCount = getTileViewParticipantCount(state); const { aspectRatio } = state['features/base/responsive-ui']; @@ -130,7 +135,7 @@ export function getColumnCount(stateful: Object | Function) { * @param {Object} state - The redux state. * @returns {boolean} - True if the scroll is displayed and false otherwise. */ -export function isFilmstripScrollVisible(state) { +export function isFilmstripScrollVisible(state: IReduxState) { if (shouldDisplayTileView(state)) { return state['features/filmstrip']?.tileViewDimensions?.hasScroll; } @@ -162,28 +167,31 @@ export function isFilmstripScrollVisible(state) { /** * Whether the stage filmstrip is available or not. * - * @param {Object} state - Redux state. + * @param {any} _state - Used on web. + * @param {any} _count - Used on web. * @returns {boolean} */ -export function isStageFilmstripAvailable() { +export function isStageFilmstripAvailable(_state: any, _count?: any) { return false; } /** * Whether the stage filmstrip is enabled. * + * @param {any} _state - Used on web. * @returns {boolean} */ -export function isStageFilmstripEnabled() { +export function isStageFilmstripEnabled(_state: any) { return false; } /** * Whether or not the top panel is enabled. * + * @param {any} _state - Used on web. * @returns {boolean} */ -export function isTopPanelEnabled() { +export function isTopPanelEnabled(_state: any) { return false; } @@ -200,6 +208,17 @@ export function getFilmstripDimensions({ clientHeight, insets = {}, localParticipantVisible = true +}: { + aspectRatio: Symbol; + clientHeight: number; + clientWidth: number; + insets: { + bottom?: number; + left?: number; + right?: number; + top?: number; + }; + localParticipantVisible?: boolean; }) { const { height, width, margin } = styles.thumbnail; const conferenceBorder = conferenceStyles.conference.borderWidth || 0; @@ -254,9 +273,10 @@ export function shouldDisplayLocalThumbnailSeparately() { /** * Not implemented on mobile. * + * @param {any} _state - Used on web. * @returns {undefined} */ -export function getScreenshareFilmstripParticipantId() { +export function getScreenshareFilmstripParticipantId(_state: any) { return undefined; } diff --git a/react/features/filmstrip/functions.web.js b/react/features/filmstrip/functions.web.ts similarity index 89% rename from react/features/filmstrip/functions.web.js rename to react/features/filmstrip/functions.web.ts index 4d251b7848..b25f7c3a63 100644 --- a/react/features/filmstrip/functions.web.js +++ b/react/features/filmstrip/functions.web.ts @@ -1,7 +1,7 @@ -// @flow - +import { IReduxState } from '../app/types'; +import { IStateful } from '../base/app/types'; import { isMobileBrowser } from '../base/environment/utils'; -import { MEDIA_TYPE } from '../base/media'; +import { MEDIA_TYPE } from '../base/media/constants'; import { getLocalParticipant, getParticipantById, @@ -9,9 +9,9 @@ import { getParticipantCountWithFake, getPinnedParticipant, isScreenShareParticipant -} from '../base/participants'; -import { toState } from '../base/redux'; -import { shouldHideSelfView } from '../base/settings/functions.any'; +} from '../base/participants/functions'; +import { toState } from '../base/redux/functions'; +import { shouldHideSelfView } from '../base/settings/functions.web'; import { getVideoTrackByParticipant, isLocalTrackMuted, @@ -19,11 +19,8 @@ import { } from '../base/tracks/functions'; import { isTrackStreamingStatusActive } from '../connection-indicator/functions'; import { isSharingStatus } from '../shared-video/functions'; -import { - LAYOUTS, - getCurrentLayout, - getNotResponsiveTileViewGridDimensions -} from '../video-layout'; +import { LAYOUTS } from '../video-layout/constants'; +import { getCurrentLayout, getNotResponsiveTileViewGridDimensions } from '../video-layout/functions.web'; import { ASPECT_RATIO_BREAKPOINT, @@ -51,8 +48,6 @@ import { export * from './functions.any'; -declare var interfaceConfig: Object; - /** * Returns true if the filmstrip on mobile is visible, false otherwise. * @@ -60,11 +55,11 @@ declare var interfaceConfig: Object; * function lies here only for the sake of consistency and to avoid flow errors * on import. * - * @param {Object | Function} stateful - The Object or Function that can be + * @param {IStateful} stateful - The Object or Function that can be * resolved to a Redux state object with the toState function. * @returns {boolean} */ -export function isFilmstripVisible(stateful: Object | Function) { +export function isFilmstripVisible(stateful: IStateful) { return toState(stateful)['features/filmstrip'].visible; } @@ -72,11 +67,11 @@ export function isFilmstripVisible(stateful: Object | Function) { * Determines whether the remote video thumbnails should be displayed/visible in * the filmstrip. * - * @param {Object} state - The full redux state. + * @param {IReduxState} state - The full redux state. * @returns {boolean} - If remote video thumbnails should be displayed/visible * in the filmstrip, then {@code true}; otherwise, {@code false}. */ -export function shouldRemoteVideosBeVisible(state: Object) { +export function shouldRemoteVideosBeVisible(state: IReduxState) { if (state['features/invite'].calleeInfoVisible) { return false; } @@ -107,13 +102,13 @@ export function shouldRemoteVideosBeVisible(state: Object) { /** * Checks whether there is a playable video stream available for the user associated with the passed ID. * - * @param {Object | Function} stateful - The Object or Function that can be + * @param {IStateful} stateful - The Object or Function that can be * resolved to a Redux state object with the toState function. * @param {string} id - The id of the participant. * @returns {boolean} true if there is a playable video stream available * or false otherwise. */ -export function isVideoPlayable(stateful: Object | Function, id: String) { +export function isVideoPlayable(stateful: IStateful, id: string) { const state = toState(stateful); const tracks = state['features/base/tracks']; const participant = id ? getParticipantById(state, id) : getLocalParticipant(state); @@ -142,7 +137,7 @@ export function isVideoPlayable(stateful: Object | Function, id: String) { * @param {number} clientHeight - The height of the app window. * @returns {{local: {height, width}, remote: {height, width}}} */ -export function calculateThumbnailSizeForHorizontalView(clientHeight: number = 0) { +export function calculateThumbnailSizeForHorizontalView(clientHeight = 0) { const topBottomMargin = 15; const availableHeight = Math.min(clientHeight, (interfaceConfig.FILM_STRIP_MAX_HEIGHT || DEFAULT_FILMSTRIP_WIDTH) + topBottomMargin); @@ -168,8 +163,7 @@ export function calculateThumbnailSizeForHorizontalView(clientHeight: number = 0 * @param {boolean} isResizable - Whether the filmstrip is resizable or not. * @returns {{local: {height, width}, remote: {height, width}}} */ -export function calculateThumbnailSizeForVerticalView(clientWidth: number = 0, - filmstripWidth: number = 0, isResizable = false) { +export function calculateThumbnailSizeForVerticalView(clientWidth = 0, filmstripWidth = 0, isResizable = false) { const availableWidth = Math.min( Math.max(clientWidth - VERTICAL_VIEW_HORIZONTAL_MARGIN, 0), (isResizable ? filmstripWidth : interfaceConfig.FILM_STRIP_MAX_HEIGHT) || DEFAULT_FILMSTRIP_WIDTH); @@ -195,7 +189,7 @@ export function calculateThumbnailSizeForVerticalView(clientWidth: number = 0, * @param {number} clientWidth - The width of the window. * @returns {number} The minimum height of a thumbnail. */ -export function getThumbnailMinHeight(clientWidth) { +export function getThumbnailMinHeight(clientWidth: number) { return clientWidth < ASPECT_RATIO_BREAKPOINT ? TILE_MIN_HEIGHT_SMALL : TILE_MIN_HEIGHT_LARGE; } @@ -207,7 +201,8 @@ export function getThumbnailMinHeight(clientWidth) { * @param {number} clientWidth - The width of the window. * @returns {number} The default aspect ratio for a tile. */ -export function getTileDefaultAspectRatio(disableResponsiveTiles, disableTileEnlargement, clientWidth) { +export function getTileDefaultAspectRatio(disableResponsiveTiles: boolean, + disableTileEnlargement: boolean, clientWidth: number) { if (!disableResponsiveTiles && disableTileEnlargement && clientWidth < ASPECT_RATIO_BREAKPOINT) { return SQUARE_TILE_ASPECT_RATIO; } @@ -221,7 +216,7 @@ export function getTileDefaultAspectRatio(disableResponsiveTiles, disableTileEnl * @param {Object} state - The redux store state. * @returns {number} The number of participants that will be displayed in tile view. */ -export function getNumberOfPartipantsForTileView(state) { +export function getNumberOfPartipantsForTileView(state: IReduxState) { const { iAmRecorder } = state['features/base/config']; const disableSelfView = shouldHideSelfView(state); const { localScreenShare } = state['features/base/participants']; @@ -240,7 +235,7 @@ export function getNumberOfPartipantsForTileView(state) { * @param {Object} state - The redux store state. * @returns {Object} - The dimensions. */ -export function calculateNonResponsiveTileViewDimensions(state) { +export function calculateNonResponsiveTileViewDimensions(state: IReduxState) { const { clientHeight, clientWidth } = state['features/base/responsive-ui']; const { disableTileEnlargement } = state['features/base/config']; const { columns: c, minVisibleRows, rows: r } = getNotResponsiveTileViewGridDimensions(state); @@ -292,16 +287,35 @@ export function calculateResponsiveTileViewDimensions({ numberOfParticipants, desiredNumberOfVisibleTiles = TILE_VIEW_DEFAULT_NUMBER_OF_VISIBLE_TILES, minTileHeight +}: { + clientHeight: number; + clientWidth: number; + desiredNumberOfVisibleTiles: number; + disableTileEnlargement?: boolean; + maxColumns: number; + minTileHeight?: number | null; + noHorizontalContainerMargin?: boolean; + numberOfParticipants: number; }) { let height, width; let columns, rows; - let dimensions = { + + interface IDimensions { + columns?: number; + height?: number; + maxArea: number; + numberOfVisibleParticipants?: number; + rows?: number; + width?: number; + } + + let dimensions: IDimensions = { maxArea: 0 }; - let minHeightEnforcedDimensions = { + let minHeightEnforcedDimensions: IDimensions = { maxArea: 0 }; - let zeroVisibleRowsDimensions = { + let zeroVisibleRowsDimensions: IDimensions = { maxArea: 0 }; @@ -411,7 +425,16 @@ export function calculateThumbnailSizeForTileView({ disableTileEnlargement = false, noHorizontalContainerMargin = false, minTileHeight -}: Object) { +}: { + clientHeight: number; + clientWidth: number; + columns: number; + disableResponsiveTiles: boolean; + disableTileEnlargement?: boolean; + minTileHeight?: number | null; + minVisibleRows: number; + noHorizontalContainerMargin?: boolean; +}) { const aspectRatio = getTileDefaultAspectRatio(disableResponsiveTiles, disableTileEnlargement, clientWidth); const minHeight = minTileHeight || getThumbnailMinHeight(clientWidth); const viewWidth = clientWidth - (columns * TILE_HORIZONTAL_MARGIN) @@ -501,7 +524,7 @@ export function getVerticalFilmstripVisibleAreaWidth() { * the thumbnail. * @returns {number} - One of DISPLAY_VIDEO or DISPLAY_AVATAR. */ -export function computeDisplayModeFromInput(input: Object) { +export function computeDisplayModeFromInput(input: any) { const { filmstripType, isActiveParticipant, @@ -550,7 +573,7 @@ export function computeDisplayModeFromInput(input: Object) { * @param {Object} state - The Thumbnail component's state. * @returns {Object} */ -export function getDisplayModeInput(props: Object, state: Object) { +export function getDisplayModeInput(props: any, state: { canPlayEventReceived: boolean; }) { const { _currentLayout, _isActiveParticipant, @@ -600,7 +623,7 @@ export function getIndicatorsTooltipPosition(thumbnailType: string) { * @param {Object} state - Redux state. * @returns {boolean} */ -export function isFilmstripResizable(state: Object) { +export function isFilmstripResizable(state: IReduxState) { const { filmstrip } = state['features/base/config']; const _currentLayout = getCurrentLayout(state); @@ -614,7 +637,7 @@ export function isFilmstripResizable(state: Object) { * @param {Object} state - Redux state. * @returns {boolean} */ -export function showGridInVerticalView(state) { +export function showGridInVerticalView(state: IReduxState) { const resizableFilmstrip = isFilmstripResizable(state); const { width } = state['features/filmstrip']; @@ -627,7 +650,7 @@ export function showGridInVerticalView(state) { * @param {Object} state - Redux state. * @returns {number} */ -export function getVerticalViewMaxWidth(state) { +export function getVerticalViewMaxWidth(state: IReduxState) { const { width } = state['features/filmstrip']; const _resizableFilmstrip = isFilmstripResizable(state); const _verticalViewGrid = showGridInVerticalView(state); @@ -649,13 +672,13 @@ export function getVerticalViewMaxWidth(state) { * @param {Object} state - The redux state. * @returns {boolean} - True if the scroll is displayed and false otherwise. */ -export function isFilmstripScrollVisible(state) { +export function isFilmstripScrollVisible(state: IReduxState) { const _currentLayout = getCurrentLayout(state); let hasScroll = false; switch (_currentLayout) { case LAYOUTS.TILE_VIEW: - ({ hasScroll = false } = state['features/filmstrip'].tileViewDimensions); + ({ hasScroll = false } = state['features/filmstrip'].tileViewDimensions ?? {}); break; case LAYOUTS.VERTICAL_FILMSTRIP_VIEW: case LAYOUTS.STAGE_FILMSTRIP_VIEW: { @@ -677,7 +700,7 @@ export function isFilmstripScrollVisible(state) { * @param {Object} state - Redux state. * @returns {Array} */ -export function getActiveParticipantsIds(state) { +export function getActiveParticipantsIds(state: IReduxState) { const { activeParticipants } = state['features/filmstrip']; return activeParticipants.map(p => p.participantId); @@ -689,7 +712,7 @@ export function getActiveParticipantsIds(state) { * @param {Object} state - Redux state. * @returns {Array} */ -export function getPinnedActiveParticipants(state) { +export function getPinnedActiveParticipants(state: IReduxState) { const { activeParticipants } = state['features/filmstrip']; return activeParticipants.filter(p => p.pinned); @@ -703,10 +726,10 @@ export function getPinnedActiveParticipants(state) { * to be displayed. * @returns {boolean} */ -export function isStageFilmstripAvailable(state, minParticipantCount = 0) { +export function isStageFilmstripAvailable(state: IReduxState, minParticipantCount = 0) { const { activeParticipants } = state['features/filmstrip']; const { remoteScreenShares } = state['features/video-layout']; - const sharedVideo = isSharingStatus(state['features/shared-video']?.status); + const sharedVideo = isSharingStatus(state['features/shared-video']?.status ?? ''); return isStageFilmstripEnabled(state) && !sharedVideo && activeParticipants.length >= minParticipantCount @@ -721,7 +744,7 @@ export function isStageFilmstripAvailable(state, minParticipantCount = 0) { * to be displayed. * @returns {boolean} */ -export function isStageFilmstripTopPanel(state, minParticipantCount = 0) { +export function isStageFilmstripTopPanel(state: IReduxState, minParticipantCount = 0) { const { remoteScreenShares } = state['features/video-layout']; return isTopPanelEnabled(state) @@ -734,7 +757,7 @@ export function isStageFilmstripTopPanel(state, minParticipantCount = 0) { * @param {Object} state - Redux state. * @returns {boolean} */ -export function isStageFilmstripEnabled(state) { +export function isStageFilmstripEnabled(state: IReduxState) { const { filmstrip } = state['features/base/config']; return !filmstrip?.disableStageFilmstrip && interfaceConfig.VERTICAL_FILMSTRIP; @@ -747,7 +770,7 @@ export function isStageFilmstripEnabled(state) { * @param {string} filmstripType - The current filmstrip type. * @returns {string} */ -export function getThumbnailTypeFromLayout(currentLayout, filmstripType) { +export function getThumbnailTypeFromLayout(currentLayout: string, filmstripType: string) { switch (currentLayout) { case LAYOUTS.TILE_VIEW: return THUMBNAIL_TYPE.TILE; @@ -770,7 +793,7 @@ export function getThumbnailTypeFromLayout(currentLayout, filmstripType) { * @param {Object} state - Redux state. * @returns {string} - The participant id. */ -export function getScreenshareFilmstripParticipantId(state) { +export function getScreenshareFilmstripParticipantId(state: IReduxState) { const { screenshareFilmstripParticipantId } = state['features/filmstrip']; const screenshares = state['features/video-layout'].remoteScreenShares; let id = screenshares.find(sId => sId === screenshareFilmstripParticipantId); @@ -788,7 +811,7 @@ export function getScreenshareFilmstripParticipantId(state) { * @param {Object} state - Redux state. * @returns {boolean} */ -export function isTopPanelEnabled(state) { +export function isTopPanelEnabled(state: IReduxState) { const { filmstrip } = state['features/base/config']; const participantsCount = getParticipantCount(state); diff --git a/react/features/filmstrip/logger.js b/react/features/filmstrip/logger.ts similarity index 91% rename from react/features/filmstrip/logger.js rename to react/features/filmstrip/logger.ts index 314205bc44..d53cfbc78b 100644 --- a/react/features/filmstrip/logger.js +++ b/react/features/filmstrip/logger.ts @@ -1,5 +1,3 @@ -// @flow - import { getLogger } from '../base/logging/functions'; export default getLogger('features/filmstrip'); diff --git a/react/features/filmstrip/middleware.native.js b/react/features/filmstrip/middleware.native.ts similarity index 83% rename from react/features/filmstrip/middleware.native.js rename to react/features/filmstrip/middleware.native.ts index b714e87550..8b198795bd 100644 --- a/react/features/filmstrip/middleware.native.js +++ b/react/features/filmstrip/middleware.native.ts @@ -1,12 +1,10 @@ -// @flow +import { PARTICIPANT_JOINED, PARTICIPANT_LEFT } from '../base/participants/actionTypes'; +import MiddlewareRegistry from '../base/redux/MiddlewareRegistry'; +import { CLIENT_RESIZED, SAFE_AREA_INSETS_CHANGED, SET_ASPECT_RATIO } from '../base/responsive-ui/actionTypes'; -import { PARTICIPANT_JOINED, PARTICIPANT_LEFT } from '../base/participants'; -import { MiddlewareRegistry } from '../base/redux'; -import { CLIENT_RESIZED, SAFE_AREA_INSETS_CHANGED, SET_ASPECT_RATIO } from '../base/responsive-ui'; - -import { setTileViewDimensions } from './actions'; -import { updateRemoteParticipants, updateRemoteParticipantsOnLeave } from './functions'; -import './subscriber'; +import { setTileViewDimensions } from './actions.native'; +import { updateRemoteParticipants, updateRemoteParticipantsOnLeave } from './functions.native'; +import './subscriber.native'; /** * The middleware of the feature Filmstrip. diff --git a/react/features/filmstrip/middleware.web.js b/react/features/filmstrip/middleware.web.ts similarity index 90% rename from react/features/filmstrip/middleware.web.js rename to react/features/filmstrip/middleware.web.ts index 4ad6fd722b..f4f04b2390 100644 --- a/react/features/filmstrip/middleware.web.js +++ b/react/features/filmstrip/middleware.web.ts @@ -1,25 +1,24 @@ -// @flow - import { batch } from 'react-redux'; +// @ts-expect-error import VideoLayout from '../../../modules/UI/videolayout/VideoLayout'; import { DOMINANT_SPEAKER_CHANGED, PARTICIPANT_JOINED, - PARTICIPANT_LEFT, + PARTICIPANT_LEFT +} from '../base/participants/actionTypes'; +import { getDominantSpeakerParticipant, getLocalParticipant, getLocalScreenShareParticipant, isScreenShareParticipant -} from '../base/participants'; -import { MiddlewareRegistry } from '../base/redux'; -import { CLIENT_RESIZED } from '../base/responsive-ui'; -import { SETTINGS_UPDATED } from '../base/settings'; -import { - LAYOUTS, - getCurrentLayout, - setTileView -} from '../video-layout'; +} from '../base/participants/functions'; +import MiddlewareRegistry from '../base/redux/MiddlewareRegistry'; +import { CLIENT_RESIZED } from '../base/responsive-ui/actionTypes'; +import { SETTINGS_UPDATED } from '../base/settings/actionTypes'; +import { setTileView } from '../video-layout/actions.web'; +import { LAYOUTS } from '../video-layout/constants'; +import { getCurrentLayout } from '../video-layout/functions.web'; import { ADD_STAGE_PARTICIPANT, @@ -54,7 +53,7 @@ import { updateRemoteParticipants, updateRemoteParticipantsOnLeave } from './functions.web'; -import './subscriber'; +import './subscriber.web'; /** * Map of timers. @@ -87,19 +86,19 @@ MiddlewareRegistry.register(store => next => action => { const { clientWidth, clientHeight } = action; let height, width; - if (filmstripWidth.current > clientWidth - MIN_STAGE_VIEW_WIDTH) { + if ((filmstripWidth.current ?? 0) > clientWidth - MIN_STAGE_VIEW_WIDTH) { width = Math.max(clientWidth - MIN_STAGE_VIEW_WIDTH, DEFAULT_FILMSTRIP_WIDTH); } else { - width = Math.min(clientWidth - MIN_STAGE_VIEW_WIDTH, filmstripWidth.userSet); + width = Math.min(clientWidth - MIN_STAGE_VIEW_WIDTH, filmstripWidth.userSet ?? 0); } if (width !== filmstripWidth.current) { store.dispatch(setFilmstripWidth(width)); } - if (topPanelHeight.current > clientHeight - MIN_STAGE_VIEW_HEIGHT) { + if ((topPanelHeight.current ?? 0) > clientHeight - MIN_STAGE_VIEW_HEIGHT) { height = Math.max(clientHeight - MIN_STAGE_VIEW_HEIGHT, TOP_FILMSTRIP_HEIGHT); } else { - height = Math.min(clientHeight - MIN_STAGE_VIEW_HEIGHT, topPanelHeight.userSet); + height = Math.min(clientHeight - MIN_STAGE_VIEW_HEIGHT, topPanelHeight.userSet ?? 0); } if (height !== topPanelHeight.current) { store.dispatch(setFilmstripHeight(height)); @@ -127,8 +126,8 @@ MiddlewareRegistry.register(store => next => action => { const localScreenShare = getLocalScreenShareParticipant(state); const activeParticipantsIds = getActiveParticipantsIds(state); - if (activeParticipantsIds.find(id => id === local.id)) { - store.dispatch(removeStageParticipant(local.id)); + if (activeParticipantsIds.find(id => id === local?.id)) { + store.dispatch(removeStageParticipant(local?.id ?? '')); } if (localScreenShare) { @@ -181,7 +180,7 @@ MiddlewareRegistry.register(store => next => action => { clearTimeout(tid); timers.delete(participantId); - } else if (activeParticipants.length < maxStageParticipants) { + } else if (activeParticipants.length < (maxStageParticipants ?? 0)) { queue = [ ...activeParticipants, { participantId, pinned @@ -252,7 +251,7 @@ MiddlewareRegistry.register(store => next => action => { const currentLayout = getCurrentLayout(state); const dominantSpeaker = getDominantSpeakerParticipant(state); - if (dominantSpeaker?.id === id || id === local.id || currentLayout === LAYOUTS.TILE_VIEW) { + if (dominantSpeaker?.id === id || id === local?.id || currentLayout === LAYOUTS.TILE_VIEW) { break; } diff --git a/react/features/filmstrip/subscriber.any.js b/react/features/filmstrip/subscriber.any.ts similarity index 94% rename from react/features/filmstrip/subscriber.any.js rename to react/features/filmstrip/subscriber.any.ts index c3115ba638..f61d057e3b 100644 --- a/react/features/filmstrip/subscriber.any.js +++ b/react/features/filmstrip/subscriber.any.ts @@ -1,6 +1,4 @@ -// @flow - -import { StateListenerRegistry } from '../base/redux'; +import StateListenerRegistry from '../base/redux/StateListenerRegistry'; import { isFilmstripScrollVisible, updateRemoteParticipants } from './functions'; diff --git a/react/features/filmstrip/subscriber.native.js b/react/features/filmstrip/subscriber.native.ts similarity index 89% rename from react/features/filmstrip/subscriber.native.js rename to react/features/filmstrip/subscriber.native.ts index b71b0a0324..93f759736d 100644 --- a/react/features/filmstrip/subscriber.native.js +++ b/react/features/filmstrip/subscriber.native.ts @@ -1,10 +1,8 @@ -// @flow - import { getCurrentConference } from '../base/conference/functions'; -import { StateListenerRegistry } from '../base/redux'; -import { shouldDisplayTileView } from '../video-layout'; +import StateListenerRegistry from '../base/redux/StateListenerRegistry'; +import { shouldDisplayTileView } from '../video-layout/functions.native'; -import { setRemoteParticipants, setTileViewDimensions } from './actions'; +import { setRemoteParticipants, setTileViewDimensions } from './actions.native'; import { getTileViewParticipantCount } from './functions.native'; import './subscriber.any'; diff --git a/react/features/filmstrip/subscriber.web.js b/react/features/filmstrip/subscriber.web.ts similarity index 93% rename from react/features/filmstrip/subscriber.web.js rename to react/features/filmstrip/subscriber.web.ts index 8223d7dc29..aa5824de5f 100644 --- a/react/features/filmstrip/subscriber.web.js +++ b/react/features/filmstrip/subscriber.web.ts @@ -1,18 +1,19 @@ -// @flow - import { isMobileBrowser } from '../base/environment/utils'; -import { getParticipantCountWithFake, pinParticipant } from '../base/participants'; -import { StateListenerRegistry } from '../base/redux'; -import { clientResized } from '../base/responsive-ui'; -import { shouldHideSelfView } from '../base/settings'; -import { setFilmstripVisible } from '../filmstrip/actions'; +import { pinParticipant } from '../base/participants/actions'; +import { getParticipantCountWithFake } from '../base/participants/functions'; +import StateListenerRegistry from '../base/redux/StateListenerRegistry'; +import { clientResized } from '../base/responsive-ui/actions'; +import { shouldHideSelfView } from '../base/settings/functions.web'; +// eslint-disable-next-line lines-around-comment +// @ts-ignore import { selectParticipantInLargeVideo } from '../large-video/actions.any'; import { getParticipantsPaneOpen } from '../participants-pane/functions'; import { setOverflowDrawer } from '../toolbox/actions.web'; -import { LAYOUTS, getCurrentLayout, shouldDisplayTileView } from '../video-layout'; +import { LAYOUTS } from '../video-layout/constants'; +import { getCurrentLayout, shouldDisplayTileView } from '../video-layout/functions.web'; -import { - clearStageParticipants, +import { clearStageParticipants, + setFilmstripVisible, setHorizontalViewDimensions, setScreenshareFilmstripParticipant, setScreensharingTileDimensions, diff --git a/react/features/follow-me/subscriber.ts b/react/features/follow-me/subscriber.ts index 71af651da6..894884c3e0 100644 --- a/react/features/follow-me/subscriber.ts +++ b/react/features/follow-me/subscriber.ts @@ -7,7 +7,7 @@ import { import StateListenerRegistry from '../base/redux/StateListenerRegistry'; // eslint-disable-next-line lines-around-comment // @ts-ignore -import { getPinnedActiveParticipants, isStageFilmstripEnabled } from '../filmstrip/functions.web'; +import { getPinnedActiveParticipants, isStageFilmstripEnabled } from '../filmstrip/functions'; import { shouldDisplayTileView } from '../video-layout/functions'; import { FOLLOW_ME_COMMAND } from './constants'; diff --git a/react/features/notifications/types.ts b/react/features/notifications/types.ts index 1a583ee0c0..7713199475 100644 --- a/react/features/notifications/types.ts +++ b/react/features/notifications/types.ts @@ -8,6 +8,7 @@ export interface INotificationProps { description?: string | React.ReactNode; descriptionArguments?: Object; descriptionKey?: string; + hideErrorSupportLink?: boolean; icon?: string; maxLines?: number; sticky?: boolean; diff --git a/react/features/overlay/functions.js b/react/features/overlay/functions.ts similarity index 69% rename from react/features/overlay/functions.js rename to react/features/overlay/functions.ts index ea1fb1f8a4..21a59f1d87 100644 --- a/react/features/overlay/functions.js +++ b/react/features/overlay/functions.ts @@ -1,17 +1,18 @@ -// @flow +import { IReduxState } from '../app/types'; import { getOverlays } from './overlays'; /** * Returns the overlay to be currently rendered. * - * @param {Object} state - The Redux state. + * @param {IReduxState} state - The Redux state. * @returns {?React$ComponentType<*>} */ -export function getOverlayToRender(state: Object) { +export function getOverlayToRender(state: IReduxState) { for (const overlay of getOverlays()) { // react-i18n / react-redux wrap components and thus we cannot access // the wrapped component's static methods directly. + // @ts-ignore const component = overlay.WrappedComponent || overlay; if (component.needsRender(state)) { @@ -25,9 +26,9 @@ export function getOverlayToRender(state: Object) { /** * Returns the visibility of the media permissions prompt. * - * @param {Object} state - The Redux state. + * @param {IReduxState} state - The Redux state. * @returns {boolean} */ -export function getMediaPermissionPromptVisibility(state: Object) { +export function getMediaPermissionPromptVisibility(state: IReduxState) { return state['features/overlay'].isMediaPermissionPromptVisible; } diff --git a/react/features/overlay/logger.js b/react/features/overlay/logger.ts similarity index 91% rename from react/features/overlay/logger.js rename to react/features/overlay/logger.ts index 292e81403b..9b449d1207 100644 --- a/react/features/overlay/logger.js +++ b/react/features/overlay/logger.ts @@ -1,5 +1,3 @@ -// @flow - import { getLogger } from '../base/logging/functions'; export default getLogger('features/overlay'); diff --git a/react/features/overlay/middleware.js b/react/features/overlay/middleware.ts similarity index 87% rename from react/features/overlay/middleware.js rename to react/features/overlay/middleware.ts index 7271c42912..40bf323ae6 100644 --- a/react/features/overlay/middleware.js +++ b/react/features/overlay/middleware.ts @@ -1,36 +1,33 @@ -// @flow - +import { IStore } from '../app/types'; import { JitsiConferenceErrors } from '../base/lib-jitsi-meet'; import { isFatalJitsiConferenceError, isFatalJitsiConnectionError } from '../base/lib-jitsi-meet/functions'; -import { StateListenerRegistry } from '../base/redux'; +import StateListenerRegistry from '../base/redux/StateListenerRegistry'; import { setFatalError } from './actions'; -declare var APP: Object; - /** * Error type. Basically like Error, but augmented with a recoverable property. */ -type ErrorType = {| +type ErrorType = { /** * Error message. */ - message?: string, + message?: string; /** * Error name. */ - name: string, + name: string; /** * Indicates whether this event is recoverable or not. */ - recoverable?: boolean -|}; + recoverable?: boolean; +}; /** * List of errors that are not fatal (or handled differently) so then the overlays won't kick in. @@ -54,7 +51,7 @@ const ERROR_TYPES = { * @param {Object|string} error - The error to process. * @returns {void} */ -const getErrorExtraInfo = (getState, error) => { +const getErrorExtraInfo = (getState: IStore['getState'], error: ErrorType) => { const state = getState(); const { error: conferenceError } = state['features/base/conference']; const { error: configError } = state['features/base/config']; @@ -62,7 +59,7 @@ const getErrorExtraInfo = (getState, error) => { if (error === conferenceError) { return { - type: ERROR_TYPES.CONFERENCE, + type: ERROR_TYPES.CONFERENCE, // @ts-ignore isFatal: isFatalJitsiConferenceError(error.name || error) }; } @@ -76,7 +73,7 @@ const getErrorExtraInfo = (getState, error) => { if (error === connectionError) { return { - type: ERROR_TYPES.CONNECTION, + type: ERROR_TYPES.CONNECTION, // @ts-ignore isFatal: isFatalJitsiConnectionError(error.name || error) }; } diff --git a/react/features/overlay/overlays.native.js b/react/features/overlay/overlays.native.js deleted file mode 100644 index 9978e35852..0000000000 --- a/react/features/overlay/overlays.native.js +++ /dev/null @@ -1,16 +0,0 @@ -// @flow - -import { - PageReloadOverlay -} from './components/native'; - -/** - * Returns the list of available platform specific overlays. - * - * @returns {Array} - */ -export function getOverlays(): Array> { - return [ - PageReloadOverlay - ]; -} diff --git a/react/features/overlay/overlays.native.ts b/react/features/overlay/overlays.native.ts new file mode 100644 index 0000000000..8bd8e60fad --- /dev/null +++ b/react/features/overlay/overlays.native.ts @@ -0,0 +1,15 @@ +import { ReactElement } from 'react'; + +// @ts-ignore +import { PageReloadOverlay } from './components/native'; + +/** + * Returns the list of available platform specific overlays. + * + * @returns {Array} + */ +export function getOverlays(): Array { + return [ + PageReloadOverlay + ]; +} diff --git a/react/features/overlay/overlays.web.js b/react/features/overlay/overlays.web.ts similarity index 95% rename from react/features/overlay/overlays.web.js rename to react/features/overlay/overlays.web.ts index 20004a915b..244d423a89 100644 --- a/react/features/overlay/overlays.web.js +++ b/react/features/overlay/overlays.web.ts @@ -1,9 +1,9 @@ -// @flow - import { PageReloadOverlay, SuspendedOverlay, UserMediaPermissionsOverlay + + // @ts-ignore } from './components/web'; /** diff --git a/react/features/prejoin/functions.ts b/react/features/prejoin/functions.ts index 4f9c9cab7b..0de518d5ff 100644 --- a/react/features/prejoin/functions.ts +++ b/react/features/prejoin/functions.ts @@ -1,6 +1,6 @@ import { IReduxState } from '../app/types'; import { getRoomName } from '../base/conference/functions'; -import { getDialOutStatusUrl, getDialOutUrl } from '../base/config/functions.web'; +import { getDialOutStatusUrl, getDialOutUrl } from '../base/config/functions'; import { isAudioMuted, isVideoMutedByUser } from '../base/media/functions'; /** diff --git a/react/features/reactions/actions.any.ts b/react/features/reactions/actions.any.ts index 1b661bdc01..d21e64d8ad 100644 --- a/react/features/reactions/actions.any.ts +++ b/react/features/reactions/actions.any.ts @@ -4,7 +4,8 @@ import { FLUSH_REACTION_BUFFER, PUSH_REACTIONS, SEND_REACTIONS, - SET_REACTION_QUEUE + SET_REACTION_QUEUE, + SHOW_SOUNDS_NOTIFICATION } from './actionTypes'; import { IReactionEmojiProps } from './constants'; import { IReactionsAction } from './reducer'; @@ -98,3 +99,14 @@ export function pushReactions(reactions: Array): IReactionsAction { reactions }; } + +/** + * Displays the disable sounds notification. + * + * @returns {void} + */ +export function displayReactionSoundsNotification(): IReactionsAction { + return { + type: SHOW_SOUNDS_NOTIFICATION + }; +} diff --git a/react/features/reactions/actions.native.ts b/react/features/reactions/actions.native.ts index e69de29bb2..02b37d475d 100644 --- a/react/features/reactions/actions.native.ts +++ b/react/features/reactions/actions.native.ts @@ -0,0 +1 @@ +export * from './actions.any'; diff --git a/react/features/reactions/actions.web.ts b/react/features/reactions/actions.web.ts index 7082d1ea7b..8f078a8fe6 100644 --- a/react/features/reactions/actions.web.ts +++ b/react/features/reactions/actions.web.ts @@ -1,9 +1,10 @@ import { - SHOW_SOUNDS_NOTIFICATION, TOGGLE_REACTIONS_VISIBLE } from './actionTypes'; import { IReactionsAction } from './reducer'; +export * from './actions.any'; + /** * Toggles the visibility of the reactions menu. * @@ -14,14 +15,3 @@ export function toggleReactionsMenuVisibility(): IReactionsAction { type: TOGGLE_REACTIONS_VISIBLE }; } - -/** - * Displays the disable sounds notification. - * - * @returns {void} - */ -export function displayReactionSoundsNotification(): IReactionsAction { - return { - type: SHOW_SOUNDS_NOTIFICATION - }; -} diff --git a/react/features/reactions/middleware.ts b/react/features/reactions/middleware.ts index e6b4d89e26..926f50c093 100644 --- a/react/features/reactions/middleware.ts +++ b/react/features/reactions/middleware.ts @@ -28,12 +28,12 @@ import { } from './actionTypes'; import { addReactionsToChat, + displayReactionSoundsNotification, flushReactionBuffer, pushReactions, sendReactions, setReactionQueue -} from './actions.any'; -import { displayReactionSoundsNotification } from './actions.web'; +} from './actions'; import { ENDPOINT_REACTION_NAME, IMuteCommandAttributes, diff --git a/react/features/screen-share/actions.web.ts b/react/features/screen-share/actions.web.ts index 0d0d1f5009..6de8b38e79 100644 --- a/react/features/screen-share/actions.web.ts +++ b/react/features/screen-share/actions.web.ts @@ -1,8 +1,8 @@ import { IStore } from '../app/types'; import { openDialog } from '../base/dialog/actions'; import { browser } from '../base/lib-jitsi-meet'; -import { shouldHideShareAudioHelper } from '../base/settings/functions'; -import { toggleScreensharing } from '../base/tracks/actions'; +import { shouldHideShareAudioHelper } from '../base/settings/functions.web'; +import { toggleScreensharing } from '../base/tracks/actions.web'; import { SET_SCREENSHARE_TRACKS, diff --git a/react/features/screen-share/components/web/ShareAudioDialog.tsx b/react/features/screen-share/components/web/ShareAudioDialog.tsx index aba4848fc3..6d8f6ed2ad 100644 --- a/react/features/screen-share/components/web/ShareAudioDialog.tsx +++ b/react/features/screen-share/components/web/ShareAudioDialog.tsx @@ -5,8 +5,8 @@ import { IReduxState, IStore } from '../../../app/types'; import { translate } from '../../../base/i18n/functions'; import { connect } from '../../../base/redux/functions'; import { updateSettings } from '../../../base/settings/actions'; -import { shouldHideShareAudioHelper } from '../../../base/settings/functions.any'; -import { toggleScreensharing } from '../../../base/tracks/actions'; +import { shouldHideShareAudioHelper } from '../../../base/settings/functions.web'; +import { toggleScreensharing } from '../../../base/tracks/actions.web'; import Checkbox from '../../../base/ui/components/web/Checkbox'; import Dialog from '../../../base/ui/components/web/Dialog'; diff --git a/react/features/settings/middleware.web.ts b/react/features/settings/middleware.web.ts index da6c918b77..7868c1b024 100644 --- a/react/features/settings/middleware.web.ts +++ b/react/features/settings/middleware.web.ts @@ -1,6 +1,6 @@ import MiddlewareRegistry from '../base/redux/MiddlewareRegistry'; import { SETTINGS_UPDATED } from '../base/settings/actionTypes'; -import { getHideSelfView } from '../base/settings/functions'; +import { getHideSelfView } from '../base/settings/functions.web'; import { showNotification } from '../notifications/actions'; import { DISABLE_SELF_VIEW_NOTIFICATION_ID, NOTIFICATION_TIMEOUT_TYPE } from '../notifications/constants'; diff --git a/react/features/toolbox/actions.any.ts b/react/features/toolbox/actions.any.ts index 74cf2498b1..98e76d1ffa 100644 --- a/react/features/toolbox/actions.any.ts +++ b/react/features/toolbox/actions.any.ts @@ -22,7 +22,7 @@ import { * enabled: boolean * }} */ -export function setToolboxEnabled(enabled: boolean): Object { +export function setToolboxEnabled(enabled: boolean) { return { type: SET_TOOLBOX_ENABLED, enabled diff --git a/react/features/video-layout/functions.web.ts b/react/features/video-layout/functions.web.ts index 9703466e6c..1606ff2a0c 100644 --- a/react/features/video-layout/functions.web.ts +++ b/react/features/video-layout/functions.web.ts @@ -26,7 +26,7 @@ export * from './functions.any'; * @returns {number} */ export function getMaxColumnCount(state: IReduxState, options: { - disableResponsiveTiles?: boolean; disableTileEnlargement?: boolean; width?: number; } = {}) { + disableResponsiveTiles?: boolean; disableTileEnlargement?: boolean; width?: number | null; } = {}) { if (typeof interfaceConfig === 'undefined') { return DEFAULT_MAX_COLUMNS; } diff --git a/react/features/video-layout/subscriber.ts b/react/features/video-layout/subscriber.ts index 385cd5079a..fc6163a196 100644 --- a/react/features/video-layout/subscriber.ts +++ b/react/features/video-layout/subscriber.ts @@ -2,8 +2,8 @@ import StateListenerRegistry from '../base/redux/StateListenerRegistry'; import { equals } from '../base/redux/functions'; import { isFollowMeActive } from '../follow-me/functions'; -import { virtualScreenshareParticipantsUpdated } from './actions.web'; -import { getAutoPinSetting, updateAutoPinnedParticipant } from './functions.web'; +import { virtualScreenshareParticipantsUpdated } from './actions'; +import { getAutoPinSetting, updateAutoPinnedParticipant } from './functions'; StateListenerRegistry.register( /* selector */ state => state['features/base/participants'].sortedRemoteVirtualScreenshareParticipants, diff --git a/react/features/video-quality/subscriber.ts b/react/features/video-quality/subscriber.ts index c4a300d3d5..46d3a8d900 100644 --- a/react/features/video-quality/subscriber.ts +++ b/react/features/video-quality/subscriber.ts @@ -16,12 +16,13 @@ import { } from '../filmstrip/functions'; import { LAYOUTS } from '../video-layout/constants'; import { + getCurrentLayout, getVideoQualityForLargeVideo, getVideoQualityForResizableFilmstripThumbnails, + getVideoQualityForScreenSharingFilmstrip, getVideoQualityForStageThumbnails, shouldDisplayTileView } from '../video-layout/functions'; -import { getCurrentLayout, getVideoQualityForScreenSharingFilmstrip } from '../video-layout/functions.any'; import { setMaxReceiverVideoQualityForLargeVideo,