diff --git a/package.json b/package.json index 49dd228358..7ebd444d5c 100644 --- a/package.json +++ b/package.json @@ -197,6 +197,8 @@ "lint-fix": "eslint --ext .js,.ts,.tsx --max-warnings 0 --fix .", "postinstall": "patch-package --error-on-fail && jetify", "validate": "npm ls", + "tsc-test:web": "tsc --project tsconfig.web.json --listFilesOnly | grep -v node_modules | grep native", + "tsc-test:native": "tsc --project tsconfig.native.json --listFilesOnly | grep -v node_modules | grep web", "start": "make dev" }, "resolutions": { diff --git a/react/features/base/conference/middleware.any.js b/react/features/base/conference/middleware.any.ts similarity index 92% rename from react/features/base/conference/middleware.any.js rename to react/features/base/conference/middleware.any.ts index b956dca5ff..9d64b24ec6 100644 --- a/react/features/base/conference/middleware.any.js +++ b/react/features/base/conference/middleware.any.ts @@ -1,6 +1,5 @@ -// @flow +import { AnyAction } from 'redux'; -import { readyToClose } from '../../../features/mobile/external-api/actions'; import { ACTION_PINNED, ACTION_UNPINNED, @@ -9,8 +8,10 @@ import { } from '../../analytics/AnalyticsEvents'; import { sendAnalytics } from '../../analytics/functions'; import { reloadNow } from '../../app/actions'; +import { IReduxState, IStore } from '../../app/types'; import { removeLobbyChatParticipant } from '../../chat/actions.any'; import { openDisplayNamePrompt } from '../../display-name/actions'; +import { readyToClose } from '../../mobile/external-api/actions'; import { showErrorNotification, showWarningNotification } from '../../notifications/actions'; import { NOTIFICATION_TIMEOUT_TYPE } from '../../notifications/constants'; import { setIAmVisitor } from '../../visitors/actions'; @@ -62,12 +63,10 @@ import { } from './functions'; import logger from './logger'; -declare var APP: Object; - /** * Handler for before unload event. */ -let beforeUnloadHandler; +let beforeUnloadHandler: Function | undefined; /** * Implements the middleware of the feature base/conference. @@ -129,7 +128,7 @@ MiddlewareRegistry.register(store => next => action => { * @private * @returns {Object} The value returned by {@code next(action)}. */ -function _conferenceFailed({ dispatch, getState }, next, action) { +function _conferenceFailed({ dispatch, getState }: IStore, next: Function, action: AnyAction) { const { conference, error } = action; if (error.name === JitsiConferenceErrors.REDIRECTED) { @@ -191,7 +190,7 @@ function _conferenceFailed({ dispatch, getState }, next, action) { const newConfig = restoreConferenceOptions(getState); if (newConfig) { - dispatch(overwriteConfig(newConfig)) + dispatch(overwriteConfig(newConfig)) // @ts-ignore .then(dispatch(conferenceWillLeave(conference))) .then(conference.leave()) .then(dispatch(disconnect())) @@ -217,7 +216,7 @@ function _conferenceFailed({ dispatch, getState }, next, action) { const [ vnode ] = error.params; - dispatch(overwriteConfig(newConfig)) + dispatch(overwriteConfig(newConfig)) // @ts-ignore .then(dispatch(conferenceWillLeave(conference))) .then(conference.leave()) .then(dispatch(disconnect())) @@ -234,7 +233,7 @@ function _conferenceFailed({ dispatch, getState }, next, action) { if (typeof APP === 'undefined') { !error.recoverable && conference - && conference.leave(CONFERENCE_LEAVE_REASONS.UNRECOVERABLE_ERROR).catch(reason => { + && conference.leave(CONFERENCE_LEAVE_REASONS.UNRECOVERABLE_ERROR).catch((reason: Error) => { // Even though we don't care too much about the failure, it may be // good to know that it happen, so log it (on the info level). logger.info('JitsiConference.leave() rejected with:', reason); @@ -267,7 +266,7 @@ function _conferenceFailed({ dispatch, getState }, next, action) { * @private * @returns {Object} The value returned by {@code next(action)}. */ -function _conferenceJoined({ dispatch, getState }, next, action) { +function _conferenceJoined({ dispatch, getState }: IStore, next: Function, action: AnyAction) { const result = next(action); const { conference } = action; const { pendingSubjectChange } = getState()['features/base/conference']; @@ -288,6 +287,8 @@ function _conferenceJoined({ dispatch, getState }, next, action) { beforeUnloadHandler = () => { dispatch(conferenceWillLeave(conference)); }; + + // @ts-ignore window.addEventListener(disableBeforeUnloadHandlers ? 'unload' : 'beforeunload', beforeUnloadHandler); if (requireDisplayName @@ -313,7 +314,7 @@ function _conferenceJoined({ dispatch, getState }, next, action) { * @private * @returns {Object} The value returned by {@code next(action)}. */ -function _connectionEstablished({ dispatch }, next, action) { +function _connectionEstablished({ dispatch }: IStore, next: Function, action: AnyAction) { const result = next(action); // FIXME: Workaround for the web version. Currently, the creation of the @@ -330,7 +331,7 @@ function _connectionEstablished({ dispatch }, next, action) { * @param {Object} state - The redux state. * @returns {void} */ -function _logJwtErrors(message, state) { +function _logJwtErrors(message: string, state: IReduxState) { const { jwt } = state['features/base/jwt']; if (!jwt) { @@ -357,7 +358,7 @@ function _logJwtErrors(message, state) { * @private * @returns {Object} The value returned by {@code next(action)}. */ -function _connectionFailed({ dispatch, getState }, next, action) { +function _connectionFailed({ dispatch, getState }: IStore, next: Function, action: AnyAction) { _logJwtErrors(action.error.message, getState()); const result = next(action); @@ -417,7 +418,7 @@ function _connectionFailed({ dispatch, getState }, next, action) { * @private * @returns {Object} The value returned by {@code next(action)}. */ -function _conferenceSubjectChanged({ dispatch, getState }, next, action) { +function _conferenceSubjectChanged({ dispatch, getState }: IStore, next: Function, action: AnyAction) { const result = next(action); const { subject } = getState()['features/base/conference']; @@ -442,7 +443,7 @@ function _conferenceSubjectChanged({ dispatch, getState }, next, action) { * @param {Object} store - The redux store. * @returns {void} */ -function _conferenceWillLeave({ getState }: { getState: Function }) { +function _conferenceWillLeave({ getState }: IStore) { _removeUnloadHandler(getState); } @@ -460,7 +461,7 @@ function _conferenceWillLeave({ getState }: { getState: Function }) { * @private * @returns {Object} The value returned by {@code next(action)}. */ -function _pinParticipant({ getState }, next, action) { +function _pinParticipant({ getState }: IStore, next: Function, action: AnyAction) { const state = getState(); const { conference } = state['features/base/conference']; @@ -473,7 +474,7 @@ function _pinParticipant({ getState }, next, action) { const pinnedParticipant = getPinnedParticipant(state); const actionName = id ? ACTION_PINNED : ACTION_UNPINNED; const local - = (participantById && participantById.local) + = participantById?.local || (!id && pinnedParticipant && pinnedParticipant.local); let participantIdForEvent; @@ -481,7 +482,7 @@ function _pinParticipant({ getState }, next, action) { participantIdForEvent = local; } else { participantIdForEvent - = actionName === ACTION_PINNED ? id : pinnedParticipant && pinnedParticipant.id; + = actionName === ACTION_PINNED ? id : pinnedParticipant?.id; } sendAnalytics(createPinnedEvent( @@ -501,10 +502,11 @@ function _pinParticipant({ getState }, next, action) { * @param {Function} getState - The redux getState function. * @returns {void} */ -function _removeUnloadHandler(getState) { +function _removeUnloadHandler(getState: IStore['getState']) { if (typeof beforeUnloadHandler !== 'undefined') { const { disableBeforeUnloadHandlers = false } = getState()['features/base/config']; + // @ts-ignore window.removeEventListener(disableBeforeUnloadHandlers ? 'unload' : 'beforeunload', beforeUnloadHandler); beforeUnloadHandler = undefined; } @@ -522,7 +524,7 @@ function _removeUnloadHandler(getState) { * @private * @returns {Object} The value returned by {@code next(action)}. */ -function _sendTones({ getState }, next, action) { +function _sendTones({ getState }: IStore, next: Function, action: AnyAction) { const state = getState(); const { conference } = state['features/base/conference']; @@ -549,15 +551,15 @@ function _sendTones({ getState }, next, action) { * @private * @returns {Object} The value returned by {@code next(action)}. */ -function _setRoom({ dispatch, getState }, next, action) { +function _setRoom({ dispatch, getState }: IStore, next: Function, action: AnyAction) { const state = getState(); const { localSubject, subject } = state['features/base/config']; const { room } = action; if (room) { // Set the stored subject. - dispatch(setLocalSubject(localSubject)); - dispatch(setSubject(subject)); + dispatch(setLocalSubject(localSubject ?? '')); + dispatch(setSubject(subject ?? '')); } return next(action); @@ -572,7 +574,7 @@ function _setRoom({ dispatch, getState }, next, action) { * @private * @returns {Promise} */ -function _syncConferenceLocalTracksWithState({ getState }, action) { +function _syncConferenceLocalTracksWithState({ getState }: IStore, action: AnyAction) { const conference = getCurrentConference(getState); let promise; @@ -603,7 +605,7 @@ function _syncConferenceLocalTracksWithState({ getState }, action) { * @private * @returns {Object} The value returned by {@code next(action)}. */ -function _trackAddedOrRemoved(store, next, action) { +function _trackAddedOrRemoved(store: IStore, next: Function, action: AnyAction) { const track = action.track; // TODO All track swapping should happen here instead of conference.js. @@ -628,7 +630,7 @@ function _trackAddedOrRemoved(store, next, action) { * @private * @returns {Object} The value returned by {@code next(action)}. */ -function _updateLocalParticipantInConference({ dispatch, getState }, next, action) { +function _updateLocalParticipantInConference({ dispatch, getState }: IStore, next: Function, action: AnyAction) { const { conference } = getState()['features/base/conference']; const { participant } = action; const result = next(action); diff --git a/react/features/base/conference/middleware.web.js b/react/features/base/conference/middleware.web.ts similarity index 99% rename from react/features/base/conference/middleware.web.js rename to react/features/base/conference/middleware.web.ts index c36ec290c4..19b7a4e93d 100644 --- a/react/features/base/conference/middleware.web.js +++ b/react/features/base/conference/middleware.web.ts @@ -1,4 +1,3 @@ - import { setPrejoinPageVisibility, setSkipPrejoinOnReload diff --git a/react/features/base/conference/reducer.ts b/react/features/base/conference/reducer.ts index 647162637e..0d0557b401 100644 --- a/react/features/base/conference/reducer.ts +++ b/react/features/base/conference/reducer.ts @@ -60,6 +60,7 @@ export interface IJitsiConference { getMetadataHandler: Function; getName: Function; getParticipantById: Function; + getParticipantCount: Function; getParticipants: Function; getRole: Function; getSpeakerStats: () => ISpeakerStats; @@ -101,6 +102,7 @@ export interface IJitsiConference { sendMessage: Function; sendPrivateTextMessage: Function; sendTextMessage: Function; + sendTones: Function; sessionId: string; setDesktopSharingFrameRate: Function; setDisplayName: Function; diff --git a/react/features/base/config/functions.any.ts b/react/features/base/config/functions.any.ts index 8d5f938b54..b33a71825b 100644 --- a/react/features/base/config/functions.any.ts +++ b/react/features/base/config/functions.any.ts @@ -7,6 +7,7 @@ import _ from 'lodash'; import { IReduxState } from '../../app/types'; import { browser } from '../lib-jitsi-meet'; +import { IMediaState } from '../media/reducer'; import { parseURLParams } from '../util/parseURLParams'; import { IConfig } from './configType'; @@ -65,7 +66,7 @@ export function getMeetingRegion(state: IReduxState) { * @param {Object} _state - The global state. * @returns {boolean} */ -export function getMultipleVideoSendingSupportFeatureFlag(_state: IReduxState) { +export function getMultipleVideoSendingSupportFeatureFlag(_state: IReduxState | IMediaState) { return browser.supportsUnifiedPlan(); } diff --git a/react/features/base/connection/actions.any.ts b/react/features/base/connection/actions.any.ts index 080181138d..627aa40010 100644 --- a/react/features/base/connection/actions.any.ts +++ b/react/features/base/connection/actions.any.ts @@ -72,7 +72,7 @@ export type ConnectionFailedError = { * connection: JitsiConnection * }} */ -export function connectionDisconnected(connection: Object) { +export function connectionDisconnected(connection?: Object) { return { type: CONNECTION_DISCONNECTED, connection diff --git a/react/features/base/jitsi-local-storage/logger.js b/react/features/base/jitsi-local-storage/logger.ts similarity index 91% rename from react/features/base/jitsi-local-storage/logger.js rename to react/features/base/jitsi-local-storage/logger.ts index 0101edf189..5f7acc27a1 100644 --- a/react/features/base/jitsi-local-storage/logger.js +++ b/react/features/base/jitsi-local-storage/logger.ts @@ -1,5 +1,3 @@ -// @flow - import { getLogger } from '../logging/functions'; export default getLogger('features/base/jitsi-local-storage'); diff --git a/react/features/base/jitsi-local-storage/setup.web.js b/react/features/base/jitsi-local-storage/setup.web.ts similarity index 92% rename from react/features/base/jitsi-local-storage/setup.web.js rename to react/features/base/jitsi-local-storage/setup.web.ts index 85a37f0d80..bab4a1d8af 100644 --- a/react/features/base/jitsi-local-storage/setup.web.js +++ b/react/features/base/jitsi-local-storage/setup.web.ts @@ -1,6 +1,7 @@ -// @flow - +// @ts-ignore import Bourne from '@hapi/bourne'; +// eslint-disable-next-line lines-around-comment +// @ts-ignore import { jitsiLocalStorage } from '@jitsi/js-utils/jitsi-local-storage'; import { browser } from '../lib-jitsi-meet'; @@ -9,9 +10,6 @@ import { parseURLParams } from '../util/parseURLParams'; import logger from './logger'; -declare var APP: Object; -declare var config: Object; - /** * Handles changes of the fake local storage. @@ -29,7 +27,7 @@ function onFakeLocalStorageChanged() { * @returns {boolean} - True if the local storage of the host page needs to be used instead jitsi-meet's local storage * and false otherwise. */ -function shouldUseHostPageLocalStorage(urlParams) { +function shouldUseHostPageLocalStorage(urlParams: { 'config.useHostPageLocalStorage'?: boolean; }) { // NOTE: normally the url params and the config will be merged into the redux store. But we want to setup the local // storage as soon as possible, the store is not created yet and the merging of the URL params and the config // haven't been executed yet. That's why we need to manually parse the URL params and also access the config through @@ -58,6 +56,7 @@ function shouldUseHostPageLocalStorage(urlParams) { * @returns {void} */ function setupJitsiLocalStorage() { + // @ts-ignore const urlParams = parseURLParams(window.location); if (shouldUseHostPageLocalStorage(urlParams)) { diff --git a/react/features/base/lib-jitsi-meet/_.native.js b/react/features/base/lib-jitsi-meet/_.native.ts similarity index 93% rename from react/features/base/lib-jitsi-meet/_.native.js rename to react/features/base/lib-jitsi-meet/_.native.ts index e4c4244ecf..1934eb94d2 100644 --- a/react/features/base/lib-jitsi-meet/_.native.js +++ b/react/features/base/lib-jitsi-meet/_.native.ts @@ -2,5 +2,6 @@ // of) the project jitsi-meet. // +// @ts-ignore import JitsiMeetJS from 'lib-jitsi-meet'; export { JitsiMeetJS as default }; diff --git a/react/features/base/lib-jitsi-meet/_.web.js b/react/features/base/lib-jitsi-meet/_.web.js deleted file mode 100644 index 28eeac3ca1..0000000000 --- a/react/features/base/lib-jitsi-meet/_.web.js +++ /dev/null @@ -1,5 +0,0 @@ -// @flow - -declare var JitsiMeetJS: Object; - -export default JitsiMeetJS; diff --git a/react/features/base/lib-jitsi-meet/_.web.ts b/react/features/base/lib-jitsi-meet/_.web.ts new file mode 100644 index 0000000000..44f1945619 --- /dev/null +++ b/react/features/base/lib-jitsi-meet/_.web.ts @@ -0,0 +1,3 @@ +declare let JitsiMeetJS: any; + +export default JitsiMeetJS; diff --git a/react/features/base/media/actions.ts b/react/features/base/media/actions.ts index cae1ded005..b69aec57ec 100644 --- a/react/features/base/media/actions.ts +++ b/react/features/base/media/actions.ts @@ -157,7 +157,7 @@ export function setVideoAvailable(available: boolean) { * @returns {Function} */ export function setVideoMuted( - muted: boolean, + muted: boolean | number, authority: number = VIDEO_MUTISM_AUTHORITY.USER, ensureTrack = false) { return (dispatch: IStore['dispatch'], getState: IStore['getState']) => { diff --git a/react/features/base/media/middleware.any.js b/react/features/base/media/middleware.any.ts similarity index 96% rename from react/features/base/media/middleware.any.js rename to react/features/base/media/middleware.any.ts index 99602d77a4..2754cde031 100644 --- a/react/features/base/media/middleware.any.js +++ b/react/features/base/media/middleware.any.ts @@ -1,4 +1,4 @@ -// @flow +import { AnyAction } from 'redux'; import { createStartAudioOnlyEvent, @@ -7,6 +7,7 @@ import { createTrackMutedEvent } from '../../analytics/AnalyticsEvents'; import { sendAnalytics } from '../../analytics/functions'; +import { IStore } from '../../app/types'; import { APP_STATE_CHANGED } from '../../mobile/background/actionTypes'; import { showWarningNotification } from '../../notifications/actions'; import { NOTIFICATION_TIMEOUT_TYPE } from '../../notifications/constants'; @@ -23,6 +24,7 @@ import { getPropertyValue } from '../settings/functions.any'; import { TRACK_ADDED } from '../tracks/actionTypes'; import { destroyLocalTracks } from '../tracks/actions.any'; import { isLocalTrackMuted, isLocalVideoTrackDesktop, setTrackMuted } from '../tracks/functions.any'; +import { ITrack } from '../tracks/types'; import { SET_AUDIO_MUTED, @@ -155,7 +157,7 @@ MiddlewareRegistry.register(store => next => action => { * @private * @returns {Object} The value returned by {@code next(action)}. */ -function _appStateChanged({ dispatch, getState }, next, action) { +function _appStateChanged({ dispatch, getState }: IStore, next: Function, action: AnyAction) { if (navigator.product === 'ReactNative') { const { appState } = action; const mute = appState !== 'active' && !isLocalVideoTrackDesktop(getState()); @@ -180,7 +182,7 @@ function _appStateChanged({ dispatch, getState }, next, action) { * @private * @returns {Object} The value returned by {@code next(action)}. */ -function _setAudioOnly({ dispatch, getState }, next, action) { +function _setAudioOnly({ dispatch, getState }: IStore, next: Function, action: AnyAction) { const { audioOnly } = action; const state = getState(); @@ -209,7 +211,7 @@ function _setAudioOnly({ dispatch, getState }, next, action) { * @returns {Object} The new state that is the result of the reduction of the * specified {@code action}. */ -function _setRoom({ dispatch, getState }, next, action) { +function _setRoom({ dispatch, getState }: IStore, next: Function, action: AnyAction) { // Figure out the desires/intents i.e. the state of base/media. There are // multiple desires/intents ordered by precedence such as server-side // config, config overrides in the user-supplied URL, user's own app @@ -222,7 +224,7 @@ function _setRoom({ dispatch, getState }, next, action) { const videoMuted = roomIsValid ? getStartWithVideoMuted(state) : _VIDEO_INITIAL_MEDIA_STATE.muted; sendAnalytics( - createStartMutedConfigurationEvent('local', audioMuted, videoMuted)); + createStartMutedConfigurationEvent('local', audioMuted, Boolean(videoMuted))); logger.log( `Start muted: ${audioMuted ? 'audio, ' : ''}${ videoMuted ? 'video' : ''}`); @@ -295,7 +297,7 @@ function _setRoom({ dispatch, getState }, next, action) { * @private * @returns {void} */ -function _syncTrackMutedState({ getState }, track) { +function _syncTrackMutedState({ getState }: IStore, track: ITrack) { const state = getState()['features/base/media']; const mediaType = track.mediaType; const muted = Boolean(state[mediaType].muted); diff --git a/react/features/base/media/middleware.native.ts b/react/features/base/media/middleware.native.ts index 15c62d75ce..fefd329e8a 100644 --- a/react/features/base/media/middleware.native.ts +++ b/react/features/base/media/middleware.native.ts @@ -1 +1 @@ -import './middleware.any.js'; +import './middleware.any'; diff --git a/react/features/base/media/middleware.web.ts b/react/features/base/media/middleware.web.ts index 485c1803b8..c270edc8c3 100644 --- a/react/features/base/media/middleware.web.ts +++ b/react/features/base/media/middleware.web.ts @@ -1,4 +1,4 @@ -import './middleware.any.js'; +import './middleware.any'; import { IStore } from '../../app/types'; import { showNotification } from '../../notifications/actions'; diff --git a/react/features/base/tracks/functions.any.ts b/react/features/base/tracks/functions.any.ts index 459b14eca2..4c2c75e6e8 100644 --- a/react/features/base/tracks/functions.any.ts +++ b/react/features/base/tracks/functions.any.ts @@ -4,6 +4,7 @@ import { } from '../config/functions.any'; import { JitsiTrackErrors, browser } from '../lib-jitsi-meet'; import { MEDIA_TYPE, MediaType, VIDEO_TYPE } from '../media/constants'; +import { IMediaState } from '../media/reducer'; import { getVirtualScreenshareParticipantOwnerId, isScreenShareParticipant @@ -359,7 +360,7 @@ export function isUserInteractionRequiredForUnmute(state: IReduxState) { * @param {Object} state - The redux state. * @returns {Promise} */ -export function setTrackMuted(track: any, muted: boolean, state: IReduxState) { +export function setTrackMuted(track: any, muted: boolean, state: IReduxState | IMediaState) { muted = Boolean(muted); // eslint-disable-line no-param-reassign // Ignore the check for desktop track muted operation. When the screenshare is terminated by clicking on the diff --git a/react/features/calendar-sync/actions.web.ts b/react/features/calendar-sync/actions.web.ts index 1a9bff0042..4bfaa33870 100644 --- a/react/features/calendar-sync/actions.web.ts +++ b/react/features/calendar-sync/actions.web.ts @@ -283,6 +283,7 @@ export function updateProfile(calendarType: string) { return Promise.reject('No integration found'); } + // @ts-ignore return dispatch(integration.getCurrentEmail()) .then((email: string) => { dispatch(setCalendarProfileEmail(email)); diff --git a/react/features/calendar-sync/components/styles.ts b/react/features/calendar-sync/components/styles.ts index be730caab9..42bd01c7f3 100644 --- a/react/features/calendar-sync/components/styles.ts +++ b/react/features/calendar-sync/components/styles.ts @@ -1,6 +1,6 @@ import { ColorPalette } from '../../base/styles/components/styles/ColorPalette'; import { createStyleSheet } from '../../base/styles/functions.any'; -import BaseTheme from '../../base/ui/components/BaseTheme.native'; +import BaseTheme from '../../base/ui/components/BaseTheme'; const NOTIFICATION_SIZE = 55; diff --git a/react/features/calendar-sync/reducer.tsx b/react/features/calendar-sync/reducer.tsx index 0b6950d639..b73fceba0b 100644 --- a/react/features/calendar-sync/reducer.tsx +++ b/react/features/calendar-sync/reducer.tsx @@ -39,7 +39,7 @@ export interface ICalendarSyncState { integrationReady: boolean; integrationType?: string; isLoadingEvents?: boolean; - msAuthState?: Object; + msAuthState?: any; profileEmail?: string; } diff --git a/react/features/calendar-sync/web/googleCalendar.js b/react/features/calendar-sync/web/googleCalendar.ts similarity index 91% rename from react/features/calendar-sync/web/googleCalendar.js rename to react/features/calendar-sync/web/googleCalendar.ts index 47fabfbd55..11226ee981 100644 --- a/react/features/calendar-sync/web/googleCalendar.js +++ b/react/features/calendar-sync/web/googleCalendar.ts @@ -1,14 +1,11 @@ -// @flow - -import type { Dispatch } from 'redux'; - +import { IStore } from '../../app/types'; import { getCalendarEntries, loadGoogleAPI, signIn, updateCalendarEvent, updateProfile -} from '../../google-api/actions'; +} from '../../google-api/actions'; // @ts-ignore import googleApi from '../../google-api/googleApi.web'; /** @@ -43,7 +40,7 @@ export const googleCalendarApi = { * @returns {function(Dispatch, Function): Promise} */ load() { - return (dispatch: Dispatch) => dispatch(loadGoogleAPI()); + return (dispatch: IStore['dispatch']) => dispatch(loadGoogleAPI()); }, /** diff --git a/react/features/calendar-sync/web/microsoftCalendar.js b/react/features/calendar-sync/web/microsoftCalendar.ts similarity index 87% rename from react/features/calendar-sync/web/microsoftCalendar.js rename to react/features/calendar-sync/web/microsoftCalendar.ts index 8fca3e18f0..3494e11cd6 100644 --- a/react/features/calendar-sync/web/microsoftCalendar.js +++ b/react/features/calendar-sync/web/microsoftCalendar.ts @@ -1,16 +1,18 @@ -// @flow - import { Client } from '@microsoft/microsoft-graph-client'; +// eslint-disable-next-line lines-around-comment +// @ts-ignore import base64js from 'base64-js'; -import type { Dispatch } from 'redux'; import { v4 as uuidV4 } from 'uuid'; import { findWindows } from 'windows-iana'; +import { IanaName } from 'windows-iana/dist/enums'; +// @ts-expect-error import { createDeferred } from '../../../../modules/util/helpers'; +import { IStore } from '../../app/types'; import { parseURLParams } from '../../base/util/parseURLParams'; import { parseStandardURIString } from '../../base/util/uri'; import { getShareInfoText } from '../../invite/functions'; -import { setCalendarAPIAuthState } from '../actions'; +import { setCalendarAPIAuthState } from '../actions.web'; /** @@ -63,7 +65,7 @@ const MS_API_CONFIGURATION = { * @private * @type {Object|null} */ -let popupAuthWindow = null; +let popupAuthWindow: Window | null = null; /** * A stateless collection of action creators that implements the expected @@ -81,10 +83,10 @@ export const microsoftCalendarApi = { * @param {number} fetchEndDays - The number of days to fetch. * @returns {function(Dispatch, Function): Promise} */ - getCalendarEntries(fetchStartDays: ?number, fetchEndDays: ?number) { - return (dispatch: Dispatch, getState: Function): Promise<*> => { + getCalendarEntries(fetchStartDays?: number, fetchEndDays?: number) { + return (dispatch: IStore['dispatch'], getState: IStore['getState']): Promise => { const state = getState()['features/calendar-sync'] || {}; - const token = state.msAuthState && state.msAuthState.accessToken; + const token = state.msAuthState?.accessToken; if (!token) { return Promise.reject('Not authorized, please sign in!'); @@ -98,8 +100,8 @@ export const microsoftCalendarApi = { .api(MS_API_CONFIGURATION.CALENDAR_ENDPOINT) .get() .then(response => { - const calendarIds = response.value.map(en => en.id); - const getEventsPromises = calendarIds.map(id => + const calendarIds = response.value.map((en: any) => en.id); + const getEventsPromises = calendarIds.map((id: string) => requestCalendarEvents( client, id, fetchStartDays, fetchEndDays)); @@ -120,7 +122,7 @@ export const microsoftCalendarApi = { * @returns {function(Dispatch<*, Function>): Promise} */ getCurrentEmail(): Function { - return (dispatch: Dispatch, getState: Function) => { + return (dispatch: IStore['dispatch'], getState: IStore['getState']) => { const { msAuthState = {} } = getState()['features/calendar-sync'] || {}; const email = msAuthState.userSigninName || ''; @@ -134,7 +136,7 @@ export const microsoftCalendarApi = { * * @returns {function(): Promise} */ - load(): Function { + load() { return () => Promise.resolve(); }, @@ -143,8 +145,8 @@ export const microsoftCalendarApi = { * * @returns {function(Dispatch, Function): Promise} */ - signIn(): Function { - return (dispatch: Dispatch, getState: Function) => { + signIn() { + return (dispatch: IStore['dispatch'], getState: IStore['getState']) => { // Ensure only one popup window at a time. if (popupAuthWindow) { popupAuthWindow.focus(); @@ -164,7 +166,7 @@ export const microsoftCalendarApi = { const { microsoftApiApplicationClientID } = getState()['features/base/config']; const authUrl = getAuthUrl( - microsoftApiApplicationClientID, + microsoftApiApplicationClientID ?? '', guids.authState, guids.authNonce); const h = 600; @@ -178,7 +180,7 @@ export const microsoftCalendarApi = { (screen.width / 2) - (w / 2)}`); const windowCloseCheck = setInterval(() => { - if (popupAuthWindow && popupAuthWindow.closed) { + if (popupAuthWindow?.closed) { signInDeferred.reject( 'Popup closed before completing auth.'); popupAuthWindow = null; @@ -199,19 +201,19 @@ export const microsoftCalendarApi = { * @private * @returns {void} */ - function handleAuth({ data }) { + function handleAuth({ data }: any) { if (!data || data.type !== 'ms-login') { return; } window.removeEventListener('message', handleAuth); - popupAuthWindow && popupAuthWindow.close(); + popupAuthWindow?.close(); popupAuthWindow = null; const params = getParamsFromHash(data.url); const tokenParts = getValidatedTokenParts( - params, guids, microsoftApiApplicationClientID); + params, guids, microsoftApiApplicationClientID ?? ''); if (!tokenParts) { signInDeferred.reject('Invalid token received'); @@ -242,8 +244,8 @@ export const microsoftCalendarApi = { * * @returns {function(Dispatch, Function): Promise} */ - _isSignedIn(): Function { - return (dispatch: Dispatch, getState: Function) => { + _isSignedIn() { + return (dispatch: IStore['dispatch'], getState: IStore['getState']) => { const now = new Date().getTime(); const state = getState()['features/calendar-sync'].msAuthState || {}; @@ -271,9 +273,9 @@ export const microsoftCalendarApi = { * @returns {function(Dispatch): Promise} */ updateCalendarEvent(id: string, calendarId: string, location: string) { - return (dispatch: Dispatch, getState: Function): Promise<*> => { + return (dispatch: IStore['dispatch'], getState: IStore['getState']) => { const state = getState()['features/calendar-sync'] || {}; - const token = state.msAuthState && state.msAuthState.accessToken; + const token = state.msAuthState?.accessToken; if (!token) { return Promise.reject('Not authorized, please sign in!'); @@ -329,7 +331,7 @@ export const microsoftCalendarApi = { * title: string * }} */ -function formatCalendarEntry(entry) { +function formatCalendarEntry(entry: any) { return { calendarId: entry.calendarId, description: entry.body.content, @@ -352,7 +354,7 @@ function formatCalendarEntry(entry) { * @private * @returns {string} - The auth URL. */ -function getAuthRefreshUrl(appId, userDomainType, userSigninName) { +function getAuthRefreshUrl(appId: string, userDomainType: string, userSigninName: string) { return [ getAuthUrl(appId, 'undefined', 'undefined'), 'prompt=none', @@ -370,7 +372,7 @@ function getAuthRefreshUrl(appId, userDomainType, userSigninName) { * @private * @returns {string} - The auth URL. */ -function getAuthUrl(appId, authState, authNonce) { +function getAuthUrl(appId: string, authState: string, authNonce: string) { const authParams = [ 'response_type=id_token+token', `client_id=${appId}`, @@ -392,7 +394,8 @@ function getAuthUrl(appId, authState, authNonce) { * @private * @returns {Object} */ -function getParamsFromHash(url) { +function getParamsFromHash(url: string) { + // @ts-ignore const params = parseURLParams(parseStandardURIString(url), true, 'hash'); // Get the number of seconds the token is valid for, subtract 5 minutes @@ -418,7 +421,7 @@ function getParamsFromHash(url) { * @private * @returns {Object|null} */ -function getValidatedTokenParts(tokenInfo, guids, appId) { +function getValidatedTokenParts(tokenInfo: any, guids: any, appId: string) { // Make sure the token matches the request source by matching the GUID. if (tokenInfo.state !== guids.authState) { return null; @@ -479,15 +482,15 @@ function getValidatedTokenParts(tokenInfo, guids, appId) { * @private * @returns {function(Dispatch, Function): Promise} */ -function refreshAuthToken(): Function { - return (dispatch: Dispatch, getState: Function) => { +function refreshAuthToken() { + return (dispatch: IStore['dispatch'], getState: IStore['getState']) => { const { microsoftApiApplicationClientID } = getState()['features/base/config']; const { msAuthState = {} } = getState()['features/calendar-sync'] || {}; const refreshAuthUrl = getAuthRefreshUrl( - microsoftApiApplicationClientID, + microsoftApiApplicationClientID ?? '', msAuthState.userDomainType, msAuthState.userSigninName); @@ -500,7 +503,7 @@ function refreshAuthToken(): Function { const signInPromise = new Promise(resolve => { iframe.onload = () => { - resolve(iframe.contentWindow.location.hash); + resolve(iframe.contentWindow?.location.hash); }; }); @@ -514,7 +517,7 @@ function refreshAuthToken(): Function { document.body.appendChild(iframe); return signInPromise.then(hash => { - const params = getParamsFromHash(hash); + const params = getParamsFromHash(hash as string); dispatch(setCalendarAPIAuthState({ accessToken: params.access_token, @@ -537,22 +540,22 @@ function refreshAuthToken(): Function { * @private */ function requestCalendarEvents( // eslint-disable-line max-params - client, - calendarId, - fetchStartDays, - fetchEndDays): Promise<*> { + client: any, + calendarId: string, + fetchStartDays?: number, + fetchEndDays?: number): Promise { const startDate = new Date(); const endDate = new Date(); - startDate.setDate(startDate.getDate() + fetchStartDays); - endDate.setDate(endDate.getDate() + fetchEndDays); + startDate.setDate(startDate.getDate() + Number(fetchStartDays)); + endDate.setDate(endDate.getDate() + Number(fetchEndDays)); const filter = `Start/DateTime ge '${ startDate.toISOString()}' and End/DateTime lt '${ endDate.toISOString()}'`; const ianaTimeZone = new Intl.DateTimeFormat().resolvedOptions().timeZone; - const windowsTimeZone = findWindows(ianaTimeZone); + const windowsTimeZone = findWindows(ianaTimeZone as IanaName); return client .api(`/me/calendars/${calendarId}/events`) @@ -561,7 +564,7 @@ function requestCalendarEvents( // eslint-disable-line max-params .select('id,subject,start,end,location,body') .orderby('createdDateTime DESC') .get() - .then(result => result.value.map(item => { + .then((result: any) => result.value.map((item: Object) => { return { ...item, calendarId @@ -576,7 +579,7 @@ function requestCalendarEvents( // eslint-disable-line max-params * @private * @returns {string} - The converted string. */ -function b64utoutf8(str) { +function b64utoutf8(str: string) { let s = str; // Convert from Base64URL to Base64. @@ -595,7 +598,7 @@ function b64utoutf8(str) { // Convert bytes to hex. - s = bytes.reduce((str_, byte) => str_ + byte.toString(16).padStart(2, '0'), ''); + s = bytes.reduce((str_: any, byte: any) => str_ + byte.toString(16).padStart(2, '0'), ''); // Convert a hexadecimal string to a URLComponent string diff --git a/react/features/deep-linking/middleware.js b/react/features/deep-linking/middleware.ts similarity index 98% rename from react/features/deep-linking/middleware.js rename to react/features/deep-linking/middleware.ts index 4fcf86b063..e4ef4a8aac 100644 --- a/react/features/deep-linking/middleware.js +++ b/react/features/deep-linking/middleware.ts @@ -1,5 +1,3 @@ -// @flow - import MiddlewareRegistry from '../base/redux/MiddlewareRegistry'; import { OPEN_DESKTOP_APP } from './actionTypes'; diff --git a/react/features/invite/components/callee-info/CalleeInfo.tsx b/react/features/invite/components/callee-info/CalleeInfo.tsx index ed84946270..c50b023662 100644 --- a/react/features/invite/components/callee-info/CalleeInfo.tsx +++ b/react/features/invite/components/callee-info/CalleeInfo.tsx @@ -9,12 +9,12 @@ import { getParticipantPresenceStatus, getRemoteParticipants } from '../../../base/participants/functions'; -import { Container, Text } from '../../../base/react/components/index.web'; +import { Container, Text } from '../../../base/react/components/index'; import { isLocalTrackMuted } from '../../../base/tracks/functions.any'; import PresenceLabel from '../../../presence-status/components/PresenceLabel'; import { CALLING } from '../../../presence-status/constants'; -import styles from './styles.web'; +import styles from './styles'; /** * The type of the React {@code Component} props of {@link CalleeInfo}. diff --git a/react/features/invite/components/callee-info/styles.native.js b/react/features/invite/components/callee-info/styles.native.ts similarity index 100% rename from react/features/invite/components/callee-info/styles.native.js rename to react/features/invite/components/callee-info/styles.native.ts diff --git a/react/features/large-video/components/LargeVideoBackground.web.js b/react/features/large-video/components/LargeVideoBackground.web.tsx similarity index 88% rename from react/features/large-video/components/LargeVideoBackground.web.js rename to react/features/large-video/components/LargeVideoBackground.web.tsx index c54f99a925..e8102fe1e4 100644 --- a/react/features/large-video/components/LargeVideoBackground.web.js +++ b/react/features/large-video/components/LargeVideoBackground.web.tsx @@ -1,8 +1,7 @@ -// @flow - import React, { Component } from 'react'; import { connect } from 'react-redux'; +import { IReduxState } from '../../app/types'; import { shouldDisplayTileView } from '../../video-layout/functions.web'; /** @@ -22,7 +21,7 @@ export const ORIENTATION = { * The type of the React {@code Component} props of * {@link LargeVideoBackgroundCanvas}. */ -type Props = { +interface IProps { /** * Whether or not the layout should change to support tile view mode. @@ -30,35 +29,35 @@ type Props = { * @protected * @type {boolean} */ - _shouldDisplayTileView: boolean, + _shouldDisplayTileView: boolean; /** * Additional CSS class names to add to the root of the component. */ - className: String, + className: String; /** * Whether or not the background should have its visibility hidden. */ - hidden: boolean, + hidden: boolean; /** * Whether or not the video should display flipped horizontally, so left * becomes right and right becomes left. */ - mirror: boolean, + mirror: boolean; /** * Whether the component should ensure full width of the video is displayed * (landscape) or full height (portrait). */ - orientationFit: string, + orientationFit: string; /** * The video stream to display. */ - videoElement: Object -}; + videoElement: HTMLVideoElement; +} /** @@ -67,10 +66,10 @@ type Props = { * * @augments Component */ -export class LargeVideoBackground extends Component { - _canvasEl: Object; +export class LargeVideoBackground extends Component { + _canvasEl: HTMLCanvasElement; - _updateCanvasInterval: *; + _updateCanvasInterval: number | undefined; /** * Initializes new {@code LargeVideoBackground} instance. @@ -78,7 +77,7 @@ export class LargeVideoBackground extends Component { * @param {*} props - The read-only properties with which the new instance * is to be initialized. */ - constructor(props: Props) { + constructor(props: IProps) { super(props); // Bind event handlers so they are only bound once per instance. @@ -107,7 +106,7 @@ export class LargeVideoBackground extends Component { * * @inheritdoc */ - componentDidUpdate(prevProps: Props) { + componentDidUpdate(prevProps: IProps) { const wasCanvasUpdating = !prevProps.hidden && !prevProps._shouldDisplayTileView && prevProps.videoElement; const shouldCanvasUpdating = !this.props.hidden && !this.props._shouldDisplayTileView && this.props.videoElement; @@ -163,7 +162,7 @@ export class LargeVideoBackground extends Component { _clearCanvas() { const cavnasContext = this._canvasEl.getContext('2d'); - cavnasContext.clearRect( + cavnasContext?.clearRect( 0, 0, this._canvasEl.width, this._canvasEl.height); } @@ -177,8 +176,6 @@ export class LargeVideoBackground extends Component { clearInterval(this._updateCanvasInterval); } - _setCanvasEl: () => void; - /** * Sets the instance variable for the component's canvas element so it can * be accessed directly for drawing on. @@ -187,7 +184,7 @@ export class LargeVideoBackground extends Component { * @private * @returns {void} */ - _setCanvasEl(element) { + _setCanvasEl(element: HTMLCanvasElement) { this._canvasEl = element; } @@ -199,11 +196,9 @@ export class LargeVideoBackground extends Component { */ _setUpdateCanvasInterval() { this._clearUpdateCanvasInterval(); - this._updateCanvasInterval = setInterval(this._updateCanvas, 200); + this._updateCanvasInterval = window.setInterval(this._updateCanvas, 200); } - _updateCanvas: () => void; - /** * Draws the current frame of the passed in video element onto the canvas. * @@ -235,13 +230,13 @@ export class LargeVideoBackground extends Component { if (this.props.orientationFit === ORIENTATION.LANDSCAPE) { const heightScaledToFit = (canvasWidth / videoWidth) * videoHeight; - canvasContext.drawImage( - videoElement, 0, 0, canvasWidth, heightScaledToFit); + canvasContext?.drawImage( + videoElement as any, 0, 0, canvasWidth, heightScaledToFit); } else { const widthScaledToFit = (canvasHeight / videoHeight) * videoWidth; - canvasContext.drawImage( - videoElement, 0, 0, widthScaledToFit, canvasHeight); + canvasContext?.drawImage( + videoElement as any, 0, 0, widthScaledToFit, canvasHeight); } } } @@ -255,7 +250,7 @@ export class LargeVideoBackground extends Component { * _shouldDisplayTileView: boolean * }} */ -function _mapStateToProps(state) { +function _mapStateToProps(state: IReduxState) { return { _shouldDisplayTileView: shouldDisplayTileView(state) }; diff --git a/react/features/shared-video/components/web/AbstractVideoManager.ts b/react/features/shared-video/components/web/AbstractVideoManager.ts index 860155532e..26a5376401 100644 --- a/react/features/shared-video/components/web/AbstractVideoManager.ts +++ b/react/features/shared-video/components/web/AbstractVideoManager.ts @@ -7,6 +7,7 @@ import { createSharedVideoEvent as createEvent } from '../../../analytics/Analyt import { sendAnalytics } from '../../../analytics/functions'; import { IReduxState } from '../../../app/types'; import { getCurrentConference } from '../../../base/conference/functions'; +import { IJitsiConference } from '../../../base/conference/reducer'; import { MEDIA_TYPE } from '../../../base/media/constants'; import { getLocalParticipant } from '../../../base/participants/functions'; import { isLocalTrackMuted } from '../../../base/tracks/functions'; @@ -39,7 +40,7 @@ export interface IProps { /** * The current conference. */ - _conference: Object; + _conference?: IJitsiConference; /** * Warning that indicates an incorrect video url. @@ -71,12 +72,12 @@ export interface IProps { /** * Store flag for muted state. */ - _muted: boolean; + _muted?: boolean; /** * The shared video owner id. */ - _ownerId: string; + _ownerId?: string; /** * Updates the shared video status. @@ -86,7 +87,7 @@ export interface IProps { /** * The shared video status. */ - _status: string; + _status?: string; /** * Action to stop video sharing. @@ -97,12 +98,12 @@ export interface IProps { * Seek time in seconds. * */ - _time: number; + _time?: number; /** * The video url. */ - _videoUrl: string; + _videoUrl?: string; /** * The video id. @@ -185,8 +186,8 @@ class AbstractVideoManager extends PureComponent { const playerTime = this.getTime(); - if (shouldSeekToPosition(_time, playerTime)) { - this.seek(_time); + if (shouldSeekToPosition(Number(_time), Number(playerTime))) { + this.seek(Number(_time)); } if (this.getPlaybackStatus() !== _status) { @@ -214,7 +215,7 @@ class AbstractVideoManager extends PureComponent { * @param {Object|undefined} e - The error returned by the API or none. * @returns {void} */ - onError(e: any) { + onError(e?: any) { logger.error('Error in the video player', e?.data, e?.data ? 'Check error code at https://developers.google.com/youtube/iframe_api_reference#onError' : ''); this.props._stopSharedVideo(); @@ -251,7 +252,7 @@ class AbstractVideoManager extends PureComponent { const volume = this.getVolume(); const muted = this.isMuted(); - if (volume > 0 && !muted) { + if (Number(volume) > 0 && !muted) { this.smartAudioMute(); } @@ -290,7 +291,7 @@ class AbstractVideoManager extends PureComponent { const status = this.getPlaybackStatus(); - if (!Object.values(PLAYBACK_STATUSES).includes(status)) { + if (!Object.values(PLAYBACK_STATUSES).includes(status ?? '')) { return; } @@ -320,7 +321,7 @@ class AbstractVideoManager extends PureComponent { isSharedVideoVolumeOn() { return this.getPlaybackStatus() === PLAYBACK_STATUSES.PLAYING && !this.isMuted() - && this.getVolume() > 0; + && Number(this.getVolume()) > 0; } /** @@ -342,54 +343,93 @@ class AbstractVideoManager extends PureComponent { /** * Seeks video to provided time. * - * @param {number} time + * @param {number} _time - Time to seek to. + * @returns {void} */ - seek: (time: number) => void; + seek(_time: number) { + // to be implemented by subclass + } /** * Indicates the playback state of the video. + * + * @returns {string} */ - getPlaybackStatus: () => string; + getPlaybackStatus(): string | undefined { + return; + } /** * Indicates whether the video is muted. + * + * @returns {boolean} */ - isMuted: () => boolean; + isMuted(): boolean | undefined { + return; + } /** * Retrieves current volume. + * + * @returns {number} */ - getVolume: () => number; + getVolume() { + return 1; + } /** * Plays video. + * + * @returns {void} */ - play: () => void; + play() { + // to be implemented by subclass + } /** * Pauses video. + * + * @returns {void} */ - pause: () => void; + pause() { + // to be implemented by subclass + } /** * Mutes video. + * + * @returns {void} */ - mute: () => void; + mute() { + // to be implemented by subclass + } /** * Unmutes video. + * + * @returns {void} */ - unMute: () => void; + unMute() { + // to be implemented by subclass + } /** * Retrieves current time. + * + * @returns {number} */ - getTime: () => number; + getTime() { + return 0; + } /** * Disposes current video player. + * + * @returns {void} */ - dispose: () => void; + dispose() { + // to be implemented by subclass + } } diff --git a/react/features/shared-video/components/web/VideoManager.js b/react/features/shared-video/components/web/VideoManager.tsx similarity index 91% rename from react/features/shared-video/components/web/VideoManager.js rename to react/features/shared-video/components/web/VideoManager.tsx index a15c1e7d67..744f04cb69 100644 --- a/react/features/shared-video/components/web/VideoManager.js +++ b/react/features/shared-video/components/web/VideoManager.tsx @@ -4,7 +4,7 @@ import { connect } from 'react-redux'; import { PLAYBACK_STATUSES } from '../../constants'; import AbstractVideoManager, { - Props, + IProps, _mapDispatchToProps, _mapStateToProps } from './AbstractVideoManager'; @@ -13,7 +13,9 @@ import AbstractVideoManager, { /** * Manager of shared video. */ -class VideoManager extends AbstractVideoManager { +class VideoManager extends AbstractVideoManager { + playerRef: React.RefObject; + /** * Initializes a new VideoManager instance. * @@ -21,7 +23,7 @@ class VideoManager extends AbstractVideoManager { * * @returns {void} */ - constructor(props) { + constructor(props: IProps) { super(props); this.playerRef = React.createRef(); @@ -70,7 +72,7 @@ class VideoManager extends AbstractVideoManager { * @returns {number} */ getVolume() { - return this.player?.volume; + return Number(this.player?.volume); } /** @@ -79,7 +81,7 @@ class VideoManager extends AbstractVideoManager { * @returns {number} */ getTime() { - return this.player?.currentTime; + return Number(this.player?.currentTime); } /** @@ -89,7 +91,7 @@ class VideoManager extends AbstractVideoManager { * * @returns {void} */ - seek(time) { + seek(time: number) { if (this.player) { this.player.currentTime = time; } @@ -143,7 +145,7 @@ class VideoManager extends AbstractVideoManager { getPlayerOptions() { const { _isOwner, videoId } = this.props; - let options = { + let options: any = { autoPlay: true, src: videoId, controls: _isOwner, diff --git a/react/features/shared-video/components/web/YoutubeVideoManager.js b/react/features/shared-video/components/web/YoutubeVideoManager.tsx similarity index 94% rename from react/features/shared-video/components/web/YoutubeVideoManager.js rename to react/features/shared-video/components/web/YoutubeVideoManager.tsx index 033b71351d..d7a048b10e 100644 --- a/react/features/shared-video/components/web/YoutubeVideoManager.js +++ b/react/features/shared-video/components/web/YoutubeVideoManager.tsx @@ -6,6 +6,7 @@ import YouTube from 'react-youtube'; import { PLAYBACK_STATUSES } from '../../constants'; import AbstractVideoManager, { + IProps, _mapDispatchToProps, _mapStateToProps } from './AbstractVideoManager'; @@ -16,6 +17,9 @@ import AbstractVideoManager, { * @returns {void} */ class YoutubeVideoManager extends AbstractVideoManager { + isPlayerAPILoaded: boolean; + player?: any; + /** * Initializes a new YoutubeVideoManager instance. * @@ -23,7 +27,7 @@ class YoutubeVideoManager extends AbstractVideoManager { * * @returns {void} */ - constructor(props) { + constructor(props: IProps) { super(props); this.isPlayerAPILoaded = false; @@ -88,7 +92,7 @@ class YoutubeVideoManager extends AbstractVideoManager { * * @returns {void} */ - seek(time) { + seek(time: number) { return this.player?.seekTo(time); } @@ -147,7 +151,7 @@ class YoutubeVideoManager extends AbstractVideoManager { * * @returns {void} */ - onPlayerStateChange = event => { + onPlayerStateChange = (event: any) => { if (event.data === YouTube.PlayerState.PLAYING) { this.onPlay(); } else if (event.data === YouTube.PlayerState.PAUSED) { @@ -162,7 +166,7 @@ class YoutubeVideoManager extends AbstractVideoManager { * * @returns {void} */ - onPlayerReady = event => { + onPlayerReady = (event: any) => { const { _isOwner } = this.props; this.player = event.target; @@ -201,7 +205,7 @@ class YoutubeVideoManager extends AbstractVideoManager { 'rel': 0 } }, - onError: e => this.onError(e), + onError: (e: any) => this.onError(e), onReady: this.onPlayerReady, onStateChange: this.onPlayerStateChange, videoId diff --git a/react/features/stream-effects/audio-mixer/AudioMixerEffect.js b/react/features/stream-effects/audio-mixer/AudioMixerEffect.ts similarity index 94% rename from react/features/stream-effects/audio-mixer/AudioMixerEffect.js rename to react/features/stream-effects/audio-mixer/AudioMixerEffect.ts index fc43c47006..7046239b88 100644 --- a/react/features/stream-effects/audio-mixer/AudioMixerEffect.js +++ b/react/features/stream-effects/audio-mixer/AudioMixerEffect.ts @@ -1,5 +1,3 @@ -// @flow - import JitsiMeetJS from '../../base/lib-jitsi-meet'; import { MEDIA_TYPE } from '../../base/media/constants'; @@ -12,12 +10,12 @@ export class AudioMixerEffect { /** * JitsiLocalTrack that is going to be mixed into the track that uses this effect. */ - _mixAudio: Object; + _mixAudio: any; /** * MediaStream resulted from mixing. */ - _mixedMediaStream: Object; + _mixedMediaStream: any; /** * MediaStreamTrack obtained from mixed stream. @@ -32,19 +30,19 @@ export class AudioMixerEffect { /** * MediaStreamTrack obtained from the original MediaStream. */ - _originalTrack: Object; + _originalTrack: any; /** * Lib-jitsi-meet AudioMixer. */ - _audioMixer: Object; + _audioMixer: any; /** * Creates AudioMixerEffect. * * @param {JitsiLocalTrack} mixAudio - JitsiLocalTrack which will be mixed with the original track. */ - constructor(mixAudio: Object) { + constructor(mixAudio: any) { if (mixAudio.getType() !== MEDIA_TYPE.AUDIO) { throw new Error('AudioMixerEffect only supports audio JitsiLocalTracks; effect will not work!'); } @@ -58,7 +56,7 @@ export class AudioMixerEffect { * @param {JitsiLocalTrack} sourceLocalTrack - Track to which the effect will be applied. * @returns {boolean} - Returns true if this effect can run on the specified track, false otherwise. */ - isEnabled(sourceLocalTrack: Object) { + isEnabled(sourceLocalTrack: any) { // Both JitsiLocalTracks need to be audio i.e. contain an audio MediaStreamTrack return sourceLocalTrack.isAudioTrack() && this._mixAudio.isAudioTrack(); } diff --git a/react/features/stream-effects/rnnoise/index.js b/react/features/stream-effects/rnnoise/index.ts similarity index 82% rename from react/features/stream-effects/rnnoise/index.js rename to react/features/stream-effects/rnnoise/index.ts index e67032d65a..824de3bfc7 100644 --- a/react/features/stream-effects/rnnoise/index.js +++ b/react/features/stream-effects/rnnoise/index.ts @@ -1,7 +1,6 @@ -// @flow - // Script expects to find rnnoise webassembly binary in the same public path root, otherwise it won't load // During the build phase this needs to be taken care of manually +// @ts-ignore import { createRNNWasmModule } from '@jitsi/rnnoise-wasm'; import RnnoiseProcessor from './RnnoiseProcessor'; @@ -9,7 +8,7 @@ import RnnoiseProcessor from './RnnoiseProcessor'; export { RNNOISE_SAMPLE_LENGTH } from './RnnoiseProcessor'; export type { RnnoiseProcessor }; -let rnnoiseModule; +let rnnoiseModule: Promise | undefined; /** * Creates a new instance of RnnoiseProcessor. @@ -21,5 +20,5 @@ export function createRnnoiseProcessor() { rnnoiseModule = createRNNWasmModule(); } - return rnnoiseModule.then(mod => new RnnoiseProcessor(mod)); + return rnnoiseModule?.then(mod => new RnnoiseProcessor(mod)); } diff --git a/react/features/welcome/components/WelcomePage.native.tsx b/react/features/welcome/components/WelcomePage.native.tsx index acadfa13c5..48339adc8a 100644 --- a/react/features/welcome/components/WelcomePage.native.tsx +++ b/react/features/welcome/components/WelcomePage.native.tsx @@ -29,7 +29,7 @@ import { AbstractWelcomePage, _mapStateToProps as _abstractMapStateToProps } from './AbstractWelcomePage'; -import styles from './styles'; +import styles from './styles.native'; interface IProps extends AbstractProps { diff --git a/react/features/welcome/components/styles.ts b/react/features/welcome/components/styles.native.ts similarity index 100% rename from react/features/welcome/components/styles.ts rename to react/features/welcome/components/styles.native.ts diff --git a/tsconfig.native.json b/tsconfig.native.json index 2d7728c73d..aeda3033e3 100644 --- a/tsconfig.native.json +++ b/tsconfig.native.json @@ -31,9 +31,7 @@ "react/features/remote-control", "react/features/screen-share", "react/features/screenshot-capture", - "react/features/stream-effects/noise-suppression", - "react/features/stream-effects/rnnoise", - "react/features/stream-effects/virtual-background", + "react/features/stream-effects", "react/features/virtual-background", "react/features/web-hid", "react/features/whiteboard",