ref(TS) Convert some features to TS (#12611)

This commit is contained in:
Robert Pintilii 2022-11-28 12:52:24 +02:00 committed by GitHub
parent 48a6472b3b
commit cb3fb3ada9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 203 additions and 175 deletions

1
globals.d.ts vendored
View File

@ -14,6 +14,7 @@ declare global {
registerShortcut: Function; registerShortcut: Function;
unregisterShortcut: Function; unregisterShortcut: Function;
openDialog: Function; openDialog: Function;
enable: Function;
} }
}; };
const interfaceConfig: any; const interfaceConfig: any;

View File

@ -71,6 +71,7 @@ export interface IJitsiConference {
muteParticipant: Function; muteParticipant: Function;
myLobbyUserId: Function; myLobbyUserId: Function;
myUserId: Function; myUserId: Function;
off: Function;
on: Function; on: Function;
removeTrack: Function; removeTrack: Function;
replaceTrack: Function; replaceTrack: Function;

View File

@ -316,6 +316,7 @@ export interface IConfig {
sdkKey?: string; sdkKey?: string;
tileTime?: number; tileTime?: number;
}; };
googleApiApplicationClientID?: string;
gravatar?: { gravatar?: {
baseUrl?: string; baseUrl?: string;
disabled?: boolean; disabled?: boolean;
@ -366,6 +367,7 @@ export interface IConfig {
localSubject?: string; localSubject?: string;
locationURL?: URL; locationURL?: URL;
maxFullResolutionParticipants?: number; maxFullResolutionParticipants?: number;
microsoftApiApplicationClientID?: string;
moderatedRoomServiceUrl?: string; moderatedRoomServiceUrl?: string;
mouseMoveCallbackInterval?: number; mouseMoveCallbackInterval?: number;
noticeMessage?: string; noticeMessage?: string;

View File

@ -77,6 +77,7 @@ export interface IConfigState extends IConfig {
analysis?: { analysis?: {
obfuscateRoomName?: boolean; obfuscateRoomName?: boolean;
}; };
disableRemoteControl?: boolean;
error?: Error; error?: Error;
} }

View File

@ -16,6 +16,7 @@ import { ConnectionFailedError } from './actions.any';
export interface IConnectionState { export interface IConnectionState {
connecting?: any; connecting?: any;
connection?: { connection?: {
addFeature: Function;
disconnect: Function; disconnect: Function;
getJid: () => string; getJid: () => string;
getLogs: () => Object; getLogs: () => Object;

View File

@ -1,5 +1,3 @@
// @flow
import { import {
REFRESH_CALENDAR, REFRESH_CALENDAR,
SET_CALENDAR_AUTHORIZATION, SET_CALENDAR_AUTHORIZATION,
@ -19,8 +17,7 @@ import {
* isInteractive: boolean * isInteractive: boolean
* }} * }}
*/ */
export function refreshCalendar( export function refreshCalendar(forcePermission = false, isInteractive = true) {
forcePermission: boolean = false, isInteractive: boolean = true) {
return { return {
type: REFRESH_CALENDAR, type: REFRESH_CALENDAR,
forcePermission, forcePermission,
@ -39,7 +36,7 @@ export function refreshCalendar(
* authorization: ?string * authorization: ?string
* }} * }}
*/ */
export function setCalendarAuthorization(authorization: ?string) { export function setCalendarAuthorization(authorization?: string) {
return { return {
type: SET_CALENDAR_AUTHORIZATION, type: SET_CALENDAR_AUTHORIZATION,
authorization authorization

View File

@ -1,13 +1,15 @@
// @flow // @ts-expect-error
import { generateRoomWithoutSeparator } from '@jitsi/js-utils/random'; import { generateRoomWithoutSeparator } from '@jitsi/js-utils/random';
import type { Dispatch } from 'redux';
import { getDefaultURL } from '../app/functions'; import { getDefaultURL } from '../app/functions';
import { openDialog } from '../base/dialog'; import { IStore } from '../app/types';
import { openDialog } from '../base/dialog/actions';
import { refreshCalendar } from './actions'; import { refreshCalendar } from './actions';
import { import {
UpdateCalendarEventDialog UpdateCalendarEventDialog
// @ts-ignore
} from './components'; } from './components';
import { addLinkToCalendarEntry } from './functions.native'; import { addLinkToCalendarEntry } from './functions.native';
@ -35,11 +37,13 @@ export function openUpdateCalendarEventDialog(eventId: string) {
* @returns {Function} * @returns {Function}
*/ */
export function updateCalendarEvent(eventId: string) { export function updateCalendarEvent(eventId: string) {
return (dispatch: Dispatch<any>, getState: Function) => { return (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
const defaultUrl = getDefaultURL(getState); const defaultUrl = getDefaultURL(getState);
const roomName = generateRoomWithoutSeparator(); const roomName = generateRoomWithoutSeparator();
addLinkToCalendarEntry(getState(), eventId, `${defaultUrl}/${roomName}`) addLinkToCalendarEntry(getState(), eventId, `${defaultUrl}/${roomName}`)
// @ts-ignore
.finally(() => { .finally(() => {
dispatch(refreshCalendar(false, false)); dispatch(refreshCalendar(false, false));
}); });

View File

@ -1,9 +1,11 @@
// @flow // @ts-expect-error
import { generateRoomWithoutSeparator } from '@jitsi/js-utils/random'; import { generateRoomWithoutSeparator } from '@jitsi/js-utils/random';
import type { Dispatch } from 'redux';
import { createCalendarConnectedEvent, sendAnalytics } from '../analytics'; import { createCalendarConnectedEvent } from '../analytics/AnalyticsEvents';
import { sendAnalytics } from '../analytics/functions';
import { IStore } from '../app/types';
// eslint-disable-next-line lines-around-comment
// @ts-ignore
import { loadGoogleAPI } from '../google-api'; import { loadGoogleAPI } from '../google-api';
import { import {
@ -14,8 +16,8 @@ import {
SET_CALENDAR_PROFILE_EMAIL, SET_CALENDAR_PROFILE_EMAIL,
SET_LOADING_CALENDAR_EVENTS SET_LOADING_CALENDAR_EVENTS
} from './actionTypes'; } from './actionTypes';
import { refreshCalendar, setCalendarEvents } from './actions'; import { refreshCalendar, setCalendarEvents } from './actions.web';
import { _getCalendarIntegration, isCalendarEnabled } from './functions'; import { _getCalendarIntegration, isCalendarEnabled } from './functions.web';
import logger from './logger'; import logger from './logger';
export * from './actions.any'; export * from './actions.any';
@ -26,8 +28,8 @@ export * from './actions.any';
* *
* @returns {Function} * @returns {Function}
*/ */
export function bootstrapCalendarIntegration(): Function { export function bootstrapCalendarIntegration() {
return (dispatch, getState) => { return (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
const state = getState(); const state = getState();
if (!isCalendarEnabled(state)) { if (!isCalendarEnabled(state)) {
@ -63,7 +65,7 @@ export function bootstrapCalendarIntegration(): Function {
} }
return dispatch(integrationToLoad._isSignedIn()) return dispatch(integrationToLoad._isSignedIn())
.then(signedIn => { .then((signedIn: boolean) => {
if (signedIn) { if (signedIn) {
dispatch(setIntegrationReady(integrationType)); dispatch(setIntegrationReady(integrationType));
dispatch(updateProfile(integrationType)); dispatch(updateProfile(integrationType));
@ -114,7 +116,7 @@ export function openUpdateCalendarEventDialog(
* msAuthState: Object * msAuthState: Object
* }} * }}
*/ */
export function setCalendarAPIAuthState(newState: ?Object) { export function setCalendarAPIAuthState(newState?: Object) {
return { return {
type: SET_CALENDAR_AUTH_STATE, type: SET_CALENDAR_AUTH_STATE,
msAuthState: newState msAuthState: newState
@ -130,7 +132,7 @@ export function setCalendarAPIAuthState(newState: ?Object) {
* error: Object * error: Object
* }} * }}
*/ */
export function setCalendarError(error: ?Object) { export function setCalendarError(error?: Object) {
return { return {
type: SET_CALENDAR_ERROR, type: SET_CALENDAR_ERROR,
error error
@ -146,7 +148,7 @@ export function setCalendarError(error: ?Object) {
* email: string * email: string
* }} * }}
*/ */
export function setCalendarProfileEmail(newEmail: ?string) { export function setCalendarProfileEmail(newEmail?: string) {
return { return {
type: SET_CALENDAR_PROFILE_EMAIL, type: SET_CALENDAR_PROFILE_EMAIL,
email: newEmail email: newEmail
@ -196,8 +198,8 @@ export function setIntegrationReady(integrationType: string) {
* signed into. * signed into.
* @returns {Function} * @returns {Function}
*/ */
export function signIn(calendarType: string): Function { export function signIn(calendarType: string) {
return (dispatch: Dispatch<any>) => { return (dispatch: IStore['dispatch']) => {
const integration = _getCalendarIntegration(calendarType); const integration = _getCalendarIntegration(calendarType);
if (!integration) { if (!integration) {
@ -210,7 +212,7 @@ export function signIn(calendarType: string): Function {
.then(() => dispatch(updateProfile(calendarType))) .then(() => dispatch(updateProfile(calendarType)))
.then(() => dispatch(refreshCalendar())) .then(() => dispatch(refreshCalendar()))
.then(() => sendAnalytics(createCalendarConnectedEvent())) .then(() => sendAnalytics(createCalendarConnectedEvent()))
.catch(error => { .catch((error: any) => {
logger.error( logger.error(
'Error occurred while signing into calendar integration', 'Error occurred while signing into calendar integration',
error); error);
@ -228,10 +230,10 @@ export function signIn(calendarType: string): Function {
* @param {string} calendarId - The id of the calendar to use. * @param {string} calendarId - The id of the calendar to use.
* @returns {Function} * @returns {Function}
*/ */
export function updateCalendarEvent(id: string, calendarId: string): Function { export function updateCalendarEvent(id: string, calendarId: string) {
return (dispatch: Dispatch<any>, getState: Function) => { return (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
const { integrationType } = getState()['features/calendar-sync']; const { integrationType = '' } = getState()['features/calendar-sync'];
const integration = _getCalendarIntegration(integrationType); const integration = _getCalendarIntegration(integrationType);
if (!integration) { if (!integration) {
@ -240,7 +242,7 @@ export function updateCalendarEvent(id: string, calendarId: string): Function {
const { locationURL } = getState()['features/base/connection']; const { locationURL } = getState()['features/base/connection'];
const newRoomName = generateRoomWithoutSeparator(); const newRoomName = generateRoomWithoutSeparator();
let href = locationURL.href; let href = locationURL?.href ?? '';
href.endsWith('/') || (href += '/'); href.endsWith('/') || (href += '/');
@ -275,8 +277,8 @@ export function updateCalendarEvent(id: string, calendarId: string): Function {
* should be updated. * should be updated.
* @returns {Function} * @returns {Function}
*/ */
export function updateProfile(calendarType: string): Function { export function updateProfile(calendarType: string) {
return (dispatch: Dispatch<any>) => { return (dispatch: IStore['dispatch']) => {
const integration = _getCalendarIntegration(calendarType); const integration = _getCalendarIntegration(calendarType);
if (!integration) { if (!integration) {
@ -284,7 +286,7 @@ export function updateProfile(calendarType: string): Function {
} }
return dispatch(integration.getCurrentEmail()) return dispatch(integration.getCurrentEmail())
.then(email => { .then((email: string) => {
dispatch(setCalendarProfileEmail(email)); dispatch(setCalendarProfileEmail(email));
}); });
}; };

View File

@ -1,8 +1,6 @@
// @flow
import md5 from 'js-md5'; import md5 from 'js-md5';
import { APP_LINK_SCHEME, parseURIString } from '../base/util'; import { APP_LINK_SCHEME, parseURIString } from '../base/util/uri';
import { setCalendarEvents } from './actions'; import { setCalendarEvents } from './actions';
import { MAX_LIST_LENGTH } from './constants'; import { MAX_LIST_LENGTH } from './constants';
@ -16,7 +14,8 @@ const ALLDAY_EVENT_LENGTH = 23 * 60 * 60 * 1000;
* @param {Object} entry - The calendar entry. * @param {Object} entry - The calendar entry.
* @returns {boolean} * @returns {boolean}
*/ */
function _isDisplayableCalendarEntry(entry) { function _isDisplayableCalendarEntry(entry: { allDay: boolean; attendees: Object[];
endDate: number; startDate: number; }) {
// Entries are displayable if: // Entries are displayable if:
// - Ends in the future (future or ongoing events) // - Ends in the future (future or ongoing events)
// - Is not an all day event and there is only one attendee (these events // - Is not an all day event and there is only one attendee (these events
@ -45,7 +44,8 @@ export function _updateCalendarEntries(events: Array<Object>) {
return; return;
} }
// eslint-disable-next-line no-invalid-this // @ts-ignore
// eslint-disable-next-line @typescript-eslint/no-invalid-this
const { dispatch, getState } = this; const { dispatch, getState } = this;
const knownDomains = getState()['features/base/known-domains']; const knownDomains = getState()['features/base/known-domains'];
const entryMap = new Map(); const entryMap = new Map();
@ -106,7 +106,7 @@ export function _updateCalendarEntries(events: Array<Object>) {
* @param {string} negativePattern - The negative pattern. * @param {string} negativePattern - The negative pattern.
* @returns {string} * @returns {string}
*/ */
function _checkPattern(str, positivePattern, negativePattern) { function _checkPattern(str: string, positivePattern: string, negativePattern: string) {
const positiveRegExp = new RegExp(positivePattern, 'gi'); const positiveRegExp = new RegExp(positivePattern, 'gi');
let positiveMatch = positiveRegExp.exec(str); let positiveMatch = positiveRegExp.exec(str);
@ -129,7 +129,7 @@ function _checkPattern(str, positivePattern, negativePattern) {
* @private * @private
* @returns {CalendarEntry} * @returns {CalendarEntry}
*/ */
function _parseCalendarEntry(event, knownDomains) { function _parseCalendarEntry(event: any, knownDomains: string[]) {
if (event) { if (event) {
const url = _getURLFromEvent(event, knownDomains); const url = _getURLFromEvent(event, knownDomains);
const startDate = Date.parse(event.startDate); const startDate = Date.parse(event.startDate);
@ -170,7 +170,8 @@ function _parseCalendarEntry(event, knownDomains) {
* @private * @private
* @returns {string} * @returns {string}
*/ */
function _getURLFromEvent(event, knownDomains) { function _getURLFromEvent(event: { description: string; location: string; notes: string; title: string;
url: string; }, knownDomains: string[]) {
const linkTerminatorPattern = '[^\\s<>$]'; const linkTerminatorPattern = '[^\\s<>$]';
const urlRegExp const urlRegExp
= `http(s)?://(${knownDomains.join('|')})/${linkTerminatorPattern}+`; = `http(s)?://(${knownDomains.join('|')})/${linkTerminatorPattern}+`;

View File

@ -1,15 +1,17 @@
// @flow
import { NativeModules, Platform } from 'react-native'; import { NativeModules, Platform } from 'react-native';
import RNCalendarEvents from 'react-native-calendar-events'; import RNCalendarEvents from 'react-native-calendar-events';
import type { Store } from 'redux';
import { CALENDAR_ENABLED, getFeatureFlag } from '../base/flags'; import { IReduxState, IStore } from '../app/types';
import { IStateful } from '../base/app/types';
import { CALENDAR_ENABLED } from '../base/flags/constants';
import { getFeatureFlag } from '../base/flags/functions';
// eslint-disable-next-line lines-around-comment
// @ts-ignore
import { getShareInfoText } from '../invite'; import { getShareInfoText } from '../invite';
import { setCalendarAuthorization } from './actions'; import { setCalendarAuthorization } from './actions.native';
import { FETCH_END_DAYS, FETCH_START_DAYS } from './constants'; import { FETCH_END_DAYS, FETCH_START_DAYS } from './constants';
import { _updateCalendarEntries } from './functions'; import { _updateCalendarEntries } from './functions.native';
import logger from './logger'; import logger from './logger';
export * from './functions.any'; export * from './functions.any';
@ -23,10 +25,10 @@ export * from './functions.any';
* @returns {Promise<*>} * @returns {Promise<*>}
*/ */
export function addLinkToCalendarEntry( export function addLinkToCalendarEntry(
state: Object, id: string, link: string): Promise<any> { state: IReduxState, id: string, link: string): Promise<any> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
getShareInfoText(state, link, true).then(shareInfoText => { getShareInfoText(state, link, true).then((shareInfoText: string) => {
RNCalendarEvents.findEventById(id).then(event => { RNCalendarEvents.findEventById(id).then((event: any) => {
const updateText const updateText
= event.description = event.description
? `${event.description}\n\n${shareInfoText}` ? `${event.description}\n\n${shareInfoText}`
@ -43,6 +45,7 @@ export function addLinkToCalendarEntry(
}) })
}; };
// @ts-ignore
RNCalendarEvents.saveEvent(event.title, updateObject) RNCalendarEvents.saveEvent(event.title, updateObject)
.then(resolve, reject); .then(resolve, reject);
}, reject); }, reject);
@ -61,7 +64,7 @@ export function addLinkToCalendarEntry(
* @returns {boolean} If the app has enabled the calendar feature, {@code true}; * @returns {boolean} If the app has enabled the calendar feature, {@code true};
* otherwise, {@code false}. * otherwise, {@code false}.
*/ */
export function isCalendarEnabled(stateful: Function | Object) { export function isCalendarEnabled(stateful: IStateful) {
const flag = getFeatureFlag(stateful, CALENDAR_ENABLED); const flag = getFeatureFlag(stateful, CALENDAR_ENABLED);
if (typeof flag !== 'undefined') { if (typeof flag !== 'undefined') {
@ -85,9 +88,9 @@ export function isCalendarEnabled(stateful: Function | Object) {
* @returns {void} * @returns {void}
*/ */
export function _fetchCalendarEntries( export function _fetchCalendarEntries(
store: Store<*, *>, store: IStore,
maybePromptForPermission: boolean, maybePromptForPermission: boolean,
forcePermission: ?boolean) { forcePermission?: boolean) {
const { dispatch, getState } = store; const { dispatch, getState } = store;
const promptForPermission const promptForPermission
= (maybePromptForPermission = (maybePromptForPermission
@ -104,6 +107,8 @@ export function _fetchCalendarEntries(
endDate.setDate(endDate.getDate() + FETCH_END_DAYS); endDate.setDate(endDate.getDate() + FETCH_END_DAYS);
RNCalendarEvents.fetchAllEvents( RNCalendarEvents.fetchAllEvents(
// @ts-ignore
startDate.getTime(), startDate.getTime(),
endDate.getTime(), endDate.getTime(),
[]) [])
@ -126,7 +131,7 @@ export function _fetchCalendarEntries(
* @private * @private
* @returns {Promise} * @returns {Promise}
*/ */
function _ensureCalendarAccess(promptForPermission, dispatch) { function _ensureCalendarAccess(promptForPermission: boolean | undefined, dispatch: IStore['dispatch']) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
RNCalendarEvents.checkPermissions() RNCalendarEvents.checkPermissions()
.then(status => { .then(status => {

View File

@ -1,12 +1,13 @@
// @flow /* eslint-disable lines-around-comment */
import { IStore } from '../app/types';
import { toState } from '../base/redux'; import { IStateful } from '../base/app/types';
import { toState } from '../base/redux/functions';
import { import {
clearCalendarIntegration, clearCalendarIntegration,
setCalendarError, setCalendarError,
setLoadingCalendarEvents setLoadingCalendarEvents
} from './actions'; } from './actions.web';
export * from './functions.any'; export * from './functions.any';
import { import {
CALENDAR_TYPE, CALENDAR_TYPE,
@ -14,10 +15,13 @@ import {
FETCH_END_DAYS, FETCH_END_DAYS,
FETCH_START_DAYS FETCH_START_DAYS
} from './constants'; } from './constants';
import { _updateCalendarEntries } from './functions'; import { _updateCalendarEntries } from './functions.web';
import logger from './logger'; import logger from './logger';
// @ts-ignore
import { googleCalendarApi } from './web/googleCalendar'; import { googleCalendarApi } from './web/googleCalendar';
// @ts-ignore
import { microsoftCalendarApi } from './web/microsoftCalendar'; import { microsoftCalendarApi } from './web/microsoftCalendar';
/* eslint-enable lines-around-comment */
/** /**
* Determines whether the calendar feature is enabled by the web. * Determines whether the calendar feature is enabled by the web.
@ -27,7 +31,7 @@ import { microsoftCalendarApi } from './web/microsoftCalendar';
* @returns {boolean} If the app has enabled the calendar feature, {@code true}; * @returns {boolean} If the app has enabled the calendar feature, {@code true};
* otherwise, {@code false}. * otherwise, {@code false}.
*/ */
export function isCalendarEnabled(stateful: Function | Object) { export function isCalendarEnabled(stateful: IStateful) {
const { const {
enableCalendarIntegration, enableCalendarIntegration,
googleApiApplicationClientID, googleApiApplicationClientID,
@ -37,26 +41,24 @@ export function isCalendarEnabled(stateful: Function | Object) {
return Boolean(enableCalendarIntegration && (googleApiApplicationClientID || microsoftApiApplicationClientID)); return Boolean(enableCalendarIntegration && (googleApiApplicationClientID || microsoftApiApplicationClientID));
} }
/* eslint-disable no-unused-vars */
/** /**
* Reads the user's calendar and updates the stored entries if need be. * Reads the user's calendar and updates the stored entries if need be.
* *
* @param {Object} store - The redux store. * @param {Object} store - The redux store.
* @param {boolean} maybePromptForPermission - Flag to tell the app if it should * @param {boolean} _maybePromptForPermission - Flag to tell the app if it should
* prompt for a calendar permission if it wasn't granted yet. * prompt for a calendar permission if it wasn't granted yet.
* @param {boolean|undefined} forcePermission - Whether to force to re-ask for * @param {boolean|undefined} _forcePermission - Whether to force to re-ask for
* the permission or not. * the permission or not.
* @private * @private
* @returns {void} * @returns {void}
*/ */
export function _fetchCalendarEntries( export function _fetchCalendarEntries(
store: Object, store: IStore,
maybePromptForPermission: boolean, _maybePromptForPermission: boolean,
forcePermission: ?boolean) { _forcePermission?: boolean) {
/* eslint-enable no-unused-vars */
const { dispatch, getState } = store; const { dispatch, getState } = store;
const { integrationType } = getState()['features/calendar-sync']; const { integrationType = '' } = getState()['features/calendar-sync'];
const integration = _getCalendarIntegration(integrationType); const integration = _getCalendarIntegration(integrationType);
if (!integration) { if (!integration) {
@ -69,7 +71,7 @@ export function _fetchCalendarEntries(
dispatch(integration.load()) dispatch(integration.load())
.then(() => dispatch(integration._isSignedIn())) .then(() => dispatch(integration._isSignedIn()))
.then(signedIn => { .then((signedIn: boolean) => {
if (signedIn) { if (signedIn) {
return Promise.resolve(); return Promise.resolve();
} }
@ -80,13 +82,13 @@ export function _fetchCalendarEntries(
}) })
.then(() => dispatch(integration.getCalendarEntries( .then(() => dispatch(integration.getCalendarEntries(
FETCH_START_DAYS, FETCH_END_DAYS))) FETCH_START_DAYS, FETCH_END_DAYS)))
.then(events => _updateCalendarEntries.call({ .then((events: Object[]) => _updateCalendarEntries.call({
dispatch, dispatch,
getState getState
}, events)) }, events))
.then(() => { .then(() => {
dispatch(setCalendarError()); dispatch(setCalendarError());
}, error => { }, (error: any) => {
logger.error('Error fetching calendar.', error); logger.error('Error fetching calendar.', error);
if (error.error === ERRORS.AUTH_FAILED) { if (error.error === ERRORS.AUTH_FAILED) {

View File

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

View File

@ -1,8 +1,8 @@
// @flow import { IStore } from '../app/types';
import { SET_CONFIG } from '../base/config/actionTypes';
import { SET_CONFIG } from '../base/config'; import { ADD_KNOWN_DOMAINS } from '../base/known-domains/actionTypes';
import { ADD_KNOWN_DOMAINS } from '../base/known-domains'; import MiddlewareRegistry from '../base/redux/MiddlewareRegistry';
import { MiddlewareRegistry, equals } from '../base/redux'; import { equals } from '../base/redux/functions';
import { APP_STATE_CHANGED } from '../mobile/background/actionTypes'; import { APP_STATE_CHANGED } from '../mobile/background/actionTypes';
import { REFRESH_CALENDAR } from './actionTypes'; import { REFRESH_CALENDAR } from './actionTypes';
@ -70,7 +70,7 @@ MiddlewareRegistry.register(store => next => action => {
* @private * @private
* @returns {void} * @returns {void}
*/ */
function _maybeClearAccessStatus(store, { appState }) { function _maybeClearAccessStatus(store: IStore, { appState }: { appState: string; }) {
appState === 'background' appState === 'background'
&& store.dispatch(setCalendarAuthorization(undefined)); && store.dispatch(setCalendarAuthorization(undefined));
} }

View File

@ -29,7 +29,11 @@ const DEFAULT_STATE = {
export interface ICalendarSyncState { export interface ICalendarSyncState {
authorization?: string; authorization?: string;
error?: Object; error?: Object;
events: Array<Object>; events: Array<{
calendarId: string;
id: string;
url: string;
}>;
integrationReady: boolean; integrationReady: boolean;
integrationType?: string; integrationType?: string;
isLoadingEvents?: boolean; isLoadingEvents?: boolean;

View File

@ -1,5 +1,4 @@
// @flow // @ts-expect-error
import { Transport } from '../../../modules/transport'; import { Transport } from '../../../modules/transport';
import { import {
@ -30,7 +29,7 @@ export function suspendDetected() {
* type: string * type: string
* }} * }}
*/ */
export function setTransport(transport: ?Transport) { export function setTransport(transport?: Transport) {
return { return {
type: SET_TRANSPORT, type: SET_TRANSPORT,
transport transport

View File

@ -1,16 +1,11 @@
// @flow // @ts-expect-error
import { PostMessageTransportBackend, Transport } from '../../../modules/transport';
import {
PostMessageTransportBackend,
Transport
} from '../../../modules/transport';
import { import {
CONFERENCE_JOINED, CONFERENCE_JOINED,
CONFERENCE_LEFT CONFERENCE_LEFT
} from '../base/conference'; } from '../base/conference/actionTypes';
import { MiddlewareRegistry } from '../base/redux'; import MiddlewareRegistry from '../base/redux/MiddlewareRegistry';
import { destroyLocalTracks } from '../base/tracks'; import { destroyLocalTracks } from '../base/tracks/actions';
import { SUSPEND_DETECTED } from './actionTypes'; import { SUSPEND_DETECTED } from './actionTypes';
import { import {
@ -18,8 +13,6 @@ import {
suspendDetected suspendDetected
} from './actions'; } from './actions';
declare var APP: Object;
MiddlewareRegistry.register(store => next => action => { MiddlewareRegistry.register(store => next => action => {
const result = next(action); const result = next(action);
const { dispatch, getState } = store; const { dispatch, getState } = store;
@ -34,7 +27,7 @@ MiddlewareRegistry.register(store => next => action => {
}) })
}); });
transport.on('event', event => { transport.on('event', (event: { event: string; name: string; }) => {
if (event && event.name === 'power-monitor' && event.event === 'suspend') { if (event && event.name === 'power-monitor' && event.event === 'suspend') {
dispatch(suspendDetected()); dispatch(suspendDetected());

View File

@ -1,17 +1,20 @@
// @flow // @ts-ignore
import $ from 'jquery'; import $ from 'jquery';
import React from 'react';
import { openDialog } from '../base/dialog'; import { IStore } from '../app/types';
import { openDialog } from '../base/dialog/actions';
import { JitsiConferenceEvents } from '../base/lib-jitsi-meet'; import { JitsiConferenceEvents } from '../base/lib-jitsi-meet';
import { pinParticipant } from '../base/participants/actions';
import { import {
getParticipantDisplayName, getParticipantDisplayName,
getPinnedParticipant, getPinnedParticipant,
getVirtualScreenshareParticipantByOwnerId, getVirtualScreenshareParticipantByOwnerId
pinParticipant } from '../base/participants/functions';
} from '../base/participants'; import { toggleScreensharing } from '../base/tracks/actions';
import { getLocalDesktopTrack, toggleScreensharing } from '../base/tracks'; import { getLocalDesktopTrack } from '../base/tracks/functions';
import { NOTIFICATION_TIMEOUT_TYPE, showNotification } from '../notifications'; import { showNotification } from '../notifications/actions';
import { NOTIFICATION_TIMEOUT_TYPE } from '../notifications/constants';
import { isScreenVideoShared } from '../screen-share/functions'; import { isScreenVideoShared } from '../screen-share/functions';
import { import {
@ -23,6 +26,8 @@ import {
SET_RECEIVER_TRANSPORT, SET_RECEIVER_TRANSPORT,
SET_REQUESTED_PARTICIPANT SET_REQUESTED_PARTICIPANT
} from './actionTypes'; } from './actionTypes';
// eslint-disable-next-line lines-around-comment
// @ts-ignore
import { RemoteControlAuthorizationDialog } from './components'; import { RemoteControlAuthorizationDialog } from './components';
import { import {
DISCO_REMOTE_CONTROL_FEATURE, DISCO_REMOTE_CONTROL_FEATURE,
@ -43,9 +48,8 @@ import logger from './logger';
/** /**
* Listeners. * Listeners.
*/ */
let permissionsReplyListener, receiverEndpointMessageListener, stopListener; let permissionsReplyListener: Function | undefined,
receiverEndpointMessageListener: Function, stopListener: Function | undefined;
declare var APP: Object;
/** /**
* Signals that the remote control authorization dialog should be displayed. * Signals that the remote control authorization dialog should be displayed.
@ -72,7 +76,7 @@ export function openRemoteControlAuthorizationDialog(participantId: string) {
* @returns {Function} * @returns {Function}
*/ */
export function setRemoteControlActive(active: boolean) { export function setRemoteControlActive(active: boolean) {
return (dispatch: Function, getState: Function) => { return (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
const state = getState(); const state = getState();
const { active: oldActive } = state['features/remote-control']; const { active: oldActive } = state['features/remote-control'];
const { conference } = state['features/base/conference']; const { conference } = state['features/base/conference'];
@ -82,7 +86,7 @@ export function setRemoteControlActive(active: boolean) {
type: REMOTE_CONTROL_ACTIVE, type: REMOTE_CONTROL_ACTIVE,
active active
}); });
conference.setLocalParticipantProperty('remoteControlSessionStatus', active); conference?.setLocalParticipantProperty('remoteControlSessionStatus', active);
} }
}; };
} }
@ -95,7 +99,7 @@ export function setRemoteControlActive(active: boolean) {
* @returns {Function} * @returns {Function}
*/ */
export function requestRemoteControl(userId: string) { export function requestRemoteControl(userId: string) {
return (dispatch: Function, getState: Function) => { return (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
const state = getState(); const state = getState();
const enabled = isRemoteControlEnabled(state); const enabled = isRemoteControlEnabled(state);
@ -110,11 +114,11 @@ export function requestRemoteControl(userId: string) {
const { conference } = state['features/base/conference']; const { conference } = state['features/base/conference'];
permissionsReplyListener = (participant, event) => { permissionsReplyListener = (participant: any, event: any) => {
dispatch(processPermissionRequestReply(participant.getId(), event)); dispatch(processPermissionRequestReply(participant.getId(), event));
}; };
conference.on(JitsiConferenceEvents.ENDPOINT_MESSAGE_RECEIVED, permissionsReplyListener); conference?.on(JitsiConferenceEvents.ENDPOINT_MESSAGE_RECEIVED, permissionsReplyListener);
dispatch({ dispatch({
type: SET_REQUESTED_PARTICIPANT, type: SET_REQUESTED_PARTICIPANT,
@ -140,8 +144,8 @@ export function requestRemoteControl(userId: string) {
* @param {EndpointMessage} event - The permission request event. * @param {EndpointMessage} event - The permission request event.
* @returns {Function} * @returns {Function}
*/ */
export function processPermissionRequestReply(participantId: string, event: Object) { export function processPermissionRequestReply(participantId: string, event: any) {
return (dispatch: Function, getState: Function) => { return (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
const state = getState(); const state = getState();
const { action, name, type } = event; const { action, name, type } = event;
const { requestedParticipant } = state['features/remote-control'].controller; const { requestedParticipant } = state['features/remote-control'].controller;
@ -162,11 +166,11 @@ export function processPermissionRequestReply(participantId: string, event: Obje
const { conference } = state['features/base/conference']; const { conference } = state['features/base/conference'];
stopListener = (participant, stopEvent) => { stopListener = (participant: any, stopEvent: { name: string; type: string; }) => {
dispatch(handleRemoteControlStoppedEvent(participant.getId(), stopEvent)); dispatch(handleRemoteControlStoppedEvent(participant.getId(), stopEvent));
}; };
conference.on(JitsiConferenceEvents.ENDPOINT_MESSAGE_RECEIVED, stopListener); conference?.on(JitsiConferenceEvents.ENDPOINT_MESSAGE_RECEIVED, stopListener);
dispatch(resume()); dispatch(resume());
@ -206,7 +210,9 @@ export function processPermissionRequestReply(participantId: string, event: Obje
const virtualScreenshareParticipantId = getVirtualScreenshareParticipantByOwnerId(state, participantId); const virtualScreenshareParticipantId = getVirtualScreenshareParticipantByOwnerId(state, participantId);
const pinnedId = pinnedParticipant?.id; const pinnedId = pinnedParticipant?.id;
// @ts-ignore
if (virtualScreenshareParticipantId && pinnedId !== virtualScreenshareParticipantId) { if (virtualScreenshareParticipantId && pinnedId !== virtualScreenshareParticipantId) {
// @ts-ignore
dispatch(pinParticipant(virtualScreenshareParticipantId)); dispatch(pinParticipant(virtualScreenshareParticipantId));
} else if (!virtualScreenshareParticipantId && pinnedId !== participantId) { } else if (!virtualScreenshareParticipantId && pinnedId !== participantId) {
dispatch(pinParticipant(participantId)); dispatch(pinParticipant(participantId));
@ -226,7 +232,7 @@ export function processPermissionRequestReply(participantId: string, event: Obje
* @property {string} type - The function process only events with name REMOTE_CONTROL_MESSAGE_NAME. * @property {string} type - The function process only events with name REMOTE_CONTROL_MESSAGE_NAME.
* @returns {void} * @returns {void}
*/ */
export function handleRemoteControlStoppedEvent(participantId: Object, event: Object) { export function handleRemoteControlStoppedEvent(participantId: Object, event: { name: string; type: string; }) {
return (dispatch: Function, getState: Function) => { return (dispatch: Function, getState: Function) => {
const state = getState(); const state = getState();
const { name, type } = event; const { name, type } = event;
@ -246,8 +252,8 @@ export function handleRemoteControlStoppedEvent(participantId: Object, event: Ob
* @param {boolean} notifyRemoteParty - If true a endpoint message to the controlled participant will be sent. * @param {boolean} notifyRemoteParty - If true a endpoint message to the controlled participant will be sent.
* @returns {void} * @returns {void}
*/ */
export function stopController(notifyRemoteParty: boolean = false) { export function stopController(notifyRemoteParty = false) {
return (dispatch: Function, getState: Function) => { return (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
const state = getState(); const state = getState();
const { controlled } = state['features/remote-control'].controller; const { controlled } = state['features/remote-control'].controller;
@ -265,7 +271,7 @@ export function stopController(notifyRemoteParty: boolean = false) {
logger.log('Stopping remote control controller.'); logger.log('Stopping remote control controller.');
conference.off(JitsiConferenceEvents.ENDPOINT_MESSAGE_RECEIVED, stopListener); conference?.off(JitsiConferenceEvents.ENDPOINT_MESSAGE_RECEIVED, stopListener);
stopListener = undefined; stopListener = undefined;
dispatch(pause()); dispatch(pause());
@ -289,7 +295,7 @@ export function stopController(notifyRemoteParty: boolean = false) {
* @returns {Function} * @returns {Function}
*/ */
export function clearRequest() { export function clearRequest() {
return (dispatch: Function, getState: Function) => { return (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
const { conference } = getState()['features/base/conference']; const { conference } = getState()['features/base/conference'];
dispatch({ dispatch({
@ -297,7 +303,7 @@ export function clearRequest() {
requestedParticipant: undefined requestedParticipant: undefined
}); });
conference.off(JitsiConferenceEvents.ENDPOINT_MESSAGE_RECEIVED, permissionsReplyListener); conference?.off(JitsiConferenceEvents.ENDPOINT_MESSAGE_RECEIVED, permissionsReplyListener);
permissionsReplyListener = undefined; permissionsReplyListener = undefined;
}; };
} }
@ -313,7 +319,7 @@ export function clearRequest() {
* transport: Transport * transport: Transport
* }} * }}
*/ */
export function setReceiverTransport(transport: Object) { export function setReceiverTransport(transport?: Object) {
return { return {
type: SET_RECEIVER_TRANSPORT, type: SET_RECEIVER_TRANSPORT,
transport transport
@ -326,7 +332,7 @@ export function setReceiverTransport(transport: Object) {
* @returns {Function} * @returns {Function}
*/ */
export function enableReceiver() { export function enableReceiver() {
return (dispatch: Function, getState: Function) => { return (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
const state = getState(); const state = getState();
const { enabled } = state['features/remote-control'].receiver; const { enabled } = state['features/remote-control'].receiver;
@ -349,7 +355,8 @@ export function enableReceiver() {
}); });
connection.addFeature(DISCO_REMOTE_CONTROL_FEATURE, true); connection.addFeature(DISCO_REMOTE_CONTROL_FEATURE, true);
receiverEndpointMessageListener = (participant, message) => { receiverEndpointMessageListener = (participant: any, message: {
action: string; name: string; type: string; }) => {
dispatch(endpointMessageReceived(participant.getId(), message)); dispatch(endpointMessageReceived(participant.getId(), message));
}; };
conference.on(JitsiConferenceEvents.ENDPOINT_MESSAGE_RECEIVED, receiverEndpointMessageListener); conference.on(JitsiConferenceEvents.ENDPOINT_MESSAGE_RECEIVED, receiverEndpointMessageListener);
@ -401,7 +408,7 @@ export function disableReceiver() {
* @param {boolean} [dontNotifyRemoteParty] - If true a endpoint message to the controller participant will be sent. * @param {boolean} [dontNotifyRemoteParty] - If true a endpoint message to the controller participant will be sent.
* @returns {Function} * @returns {Function}
*/ */
export function stopReceiver(dontNotifyLocalParty: boolean = false, dontNotifyRemoteParty: boolean = false) { export function stopReceiver(dontNotifyLocalParty = false, dontNotifyRemoteParty = false) {
return (dispatch: Function, getState: Function) => { return (dispatch: Function, getState: Function) => {
const state = getState(); const state = getState();
const { receiver } = state['features/remote-control']; const { receiver } = state['features/remote-control'];
@ -450,8 +457,9 @@ export function stopReceiver(dontNotifyLocalParty: boolean = false, dontNotifyRe
* name REMOTE_CONTROL_MESSAGE_NAME. * name REMOTE_CONTROL_MESSAGE_NAME.
* @returns {Function} * @returns {Function}
*/ */
export function endpointMessageReceived(participantId: string, message: Object) { export function endpointMessageReceived(participantId: string, message: {
return (dispatch: Function, getState: Function) => { action: string; name: string; type: string; }) {
return (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
const { action, name, type } = message; const { action, name, type } = message;
if (name !== REMOTE_CONTROL_MESSAGE_NAME) { if (name !== REMOTE_CONTROL_MESSAGE_NAME) {
@ -472,7 +480,7 @@ export function endpointMessageReceived(participantId: string, message: Object)
if (type === EVENTS.stop) { if (type === EVENTS.stop) {
dispatch(stopReceiver(false, true)); dispatch(stopReceiver(false, true));
} else { // forward the message } else { // forward the message
transport.sendEvent(message); transport?.sendEvent(message);
} }
} // else ignore } // else ignore
} else { } else {
@ -489,7 +497,7 @@ export function endpointMessageReceived(participantId: string, message: Object)
* @returns {Function} * @returns {Function}
*/ */
export function deny(participantId: string) { export function deny(participantId: string) {
return (dispatch: Function, getState: Function) => { return (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
const state = getState(); const state = getState();
const { conference } = state['features/base/conference']; const { conference } = state['features/base/conference'];
@ -507,7 +515,7 @@ export function deny(participantId: string) {
* @returns {Function} * @returns {Function}
*/ */
export function sendStartRequest() { export function sendStartRequest() {
return (dispatch: Function, getState: Function) => { return (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
const state = getState(); const state = getState();
const tracks = state['features/base/tracks']; const tracks = state['features/base/tracks'];
const track = getLocalDesktopTrack(tracks); const track = getLocalDesktopTrack(tracks);
@ -518,7 +526,7 @@ export function sendStartRequest() {
return Promise.reject(new Error('Cannot identify screen for the remote control session')); return Promise.reject(new Error('Cannot identify screen for the remote control session'));
} }
return transport.sendRequest({ return transport?.sendRequest({
name: REMOTE_CONTROL_MESSAGE_NAME, name: REMOTE_CONTROL_MESSAGE_NAME,
type: REQUESTS.start, type: REQUESTS.start,
sourceId sourceId
@ -534,7 +542,7 @@ export function sendStartRequest() {
* @returns {Function} * @returns {Function}
*/ */
export function grant(participantId: string) { export function grant(participantId: string) {
return (dispatch: Function, getState: Function) => { return (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
dispatch({ dispatch({
type: SET_CONTROLLER, type: SET_CONTROLLER,
controller: participantId controller: participantId
@ -555,7 +563,7 @@ export function grant(participantId: string) {
true, true,
false, false,
{ desktopSharingSources: [ 'screen' ] } { desktopSharingSources: [ 'screen' ] }
)) )) // @ts-ignore
.then(() => dispatch(sendStartRequest())); .then(() => dispatch(sendStartRequest()));
} }
@ -566,7 +574,7 @@ export function grant(participantId: string) {
type: EVENTS.permissions, type: EVENTS.permissions,
action: PERMISSIONS_ACTIONS.grant action: PERMISSIONS_ACTIONS.grant
})) }))
.catch(error => { .catch((error: any) => {
logger.error(error); logger.error(error);
sendRemoteControlEndpointMessage(conference, participantId, { sendRemoteControlEndpointMessage(conference, participantId, {
@ -591,14 +599,16 @@ export function grant(participantId: string) {
* @param {Event} event - The mouse event. * @param {Event} event - The mouse event.
* @returns {Function} * @returns {Function}
*/ */
export function mouseClicked(type: string, event: Object) { export function mouseClicked(type: string, event: React.MouseEvent) {
return (dispatch: Function, getState: Function) => { return (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
const state = getState(); const state = getState();
const { conference } = state['features/base/conference']; const { conference } = state['features/base/conference'];
const { controller } = state['features/remote-control']; const { controller } = state['features/remote-control'];
sendRemoteControlEndpointMessage(conference, controller.controlled, { sendRemoteControlEndpointMessage(conference, controller.controlled, {
type, type,
// @ts-ignore
button: event.which button: event.which
}); });
}; };
@ -610,8 +620,8 @@ export function mouseClicked(type: string, event: Object) {
* @param {Event} event - The mouse event. * @param {Event} event - The mouse event.
* @returns {Function} * @returns {Function}
*/ */
export function mouseMoved(event: Object) { export function mouseMoved(event: React.MouseEvent) {
return (dispatch: Function, getState: Function) => { return (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
const area = getRemoteConrolEventCaptureArea(); const area = getRemoteConrolEventCaptureArea();
if (!area) { if (!area) {
@ -637,8 +647,8 @@ export function mouseMoved(event: Object) {
* @param {Event} event - The mouse event. * @param {Event} event - The mouse event.
* @returns {Function} * @returns {Function}
*/ */
export function mouseScrolled(event: Object) { export function mouseScrolled(event: { deltaX: number; deltaY: number; }) {
return (dispatch: Function, getState: Function) => { return (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
const state = getState(); const state = getState();
const { conference } = state['features/base/conference']; const { conference } = state['features/base/conference'];
const { controller } = state['features/remote-control']; const { controller } = state['features/remote-control'];
@ -658,8 +668,8 @@ export function mouseScrolled(event: Object) {
* @param {Event} event - The key event. * @param {Event} event - The key event.
* @returns {Function} * @returns {Function}
*/ */
export function keyPressed(type: string, event: Object) { export function keyPressed(type: string, event: React.KeyboardEvent) {
return (dispatch: Function, getState: Function) => { return (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
const state = getState(); const state = getState();
const { conference } = state['features/base/conference']; const { conference } = state['features/base/conference'];
const { controller } = state['features/remote-control']; const { controller } = state['features/remote-control'];
@ -680,7 +690,7 @@ export function keyPressed(type: string, event: Object) {
* @returns {Function} * @returns {Function}
*/ */
export function resume() { export function resume() {
return (dispatch: Function, getState: Function) => { return (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
const area = getRemoteConrolEventCaptureArea(); const area = getRemoteConrolEventCaptureArea();
const state = getState(); const state = getState();
const { controller } = state['features/remote-control']; const { controller } = state['features/remote-control'];
@ -695,22 +705,22 @@ export function resume() {
// FIXME: Once the keyboard shortcuts are using react/redux. // FIXME: Once the keyboard shortcuts are using react/redux.
APP.keyboardshortcut.enable(false); APP.keyboardshortcut.enable(false);
area.mousemove(event => { area.mousemove((event: React.MouseEvent) => {
dispatch(mouseMoved(event)); dispatch(mouseMoved(event));
}); });
area.mousedown(event => dispatch(mouseClicked(EVENTS.mousedown, event))); area.mousedown((event: React.MouseEvent) => dispatch(mouseClicked(EVENTS.mousedown, event)));
area.mouseup(event => dispatch(mouseClicked(EVENTS.mouseup, event))); area.mouseup((event: React.MouseEvent) => dispatch(mouseClicked(EVENTS.mouseup, event)));
area.dblclick(event => dispatch(mouseClicked(EVENTS.mousedblclick, event))); area.dblclick((event: React.MouseEvent) => dispatch(mouseClicked(EVENTS.mousedblclick, event)));
area.contextmenu(() => false); area.contextmenu(() => false);
area[0].onwheel = event => { area[0].onwheel = (event: any) => {
event.preventDefault(); event.preventDefault();
event.stopPropagation(); event.stopPropagation();
dispatch(mouseScrolled(event)); dispatch(mouseScrolled(event));
return false; return false;
}; };
$(window).keydown(event => dispatch(keyPressed(EVENTS.keydown, event))); $(window).keydown((event: React.KeyboardEvent) => dispatch(keyPressed(EVENTS.keydown, event)));
$(window).keyup(event => dispatch(keyPressed(EVENTS.keyup, event))); $(window).keyup((event: React.KeyboardEvent) => dispatch(keyPressed(EVENTS.keyup, event)));
dispatch({ dispatch({
type: CAPTURE_EVENTS, type: CAPTURE_EVENTS,
@ -730,7 +740,7 @@ export function resume() {
* @returns {Function} * @returns {Function}
*/ */
export function pause() { export function pause() {
return (dispatch: Function, getState: Function) => { return (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
const state = getState(); const state = getState();
const { controller } = state['features/remote-control']; const { controller } = state['features/remote-control'];
const { controlled, isCapturingEvents } = controller; const { controlled, isCapturingEvents } = controller;

View File

@ -1,6 +1,9 @@
// @flow import React from 'react';
// @ts-expect-error
import VideoLayout from '../../../modules/UI/videolayout/VideoLayout'; import VideoLayout from '../../../modules/UI/videolayout/VideoLayout';
import { IReduxState, IStore } from '../app/types';
import { IJitsiConference } from '../base/conference/reducer';
import JitsiMeetJS from '../base/lib-jitsi-meet'; import JitsiMeetJS from '../base/lib-jitsi-meet';
import { enableReceiver, stopReceiver } from './actions'; import { enableReceiver, stopReceiver } from './actions';
@ -14,7 +17,7 @@ import logger from './logger';
* @param {*} state - The redux state. * @param {*} state - The redux state.
* @returns {boolean} - True if the remote control is enabled and false otherwise. * @returns {boolean} - True if the remote control is enabled and false otherwise.
*/ */
export function isRemoteControlEnabled(state: Object) { export function isRemoteControlEnabled(state: IReduxState) {
return !state['features/base/config'].disableRemoteControl && JitsiMeetJS.isDesktopSharingEnabled(); return !state['features/base/config'].disableRemoteControl && JitsiMeetJS.isDesktopSharingEnabled();
} }
@ -27,8 +30,8 @@ export function isRemoteControlEnabled(state: Object) {
* @returns {boolean} - True if the message was sent successfully and false otherwise. * @returns {boolean} - True if the message was sent successfully and false otherwise.
*/ */
export function sendRemoteControlEndpointMessage( export function sendRemoteControlEndpointMessage(
conference: Object, conference: IJitsiConference | undefined,
to: ?string, to: string | undefined,
event: Object) { event: Object) {
if (!to) { if (!to) {
logger.warn('Remote control: Skip sending remote control event. Params:', to); logger.warn('Remote control: Skip sending remote control event. Params:', to);
@ -37,7 +40,7 @@ export function sendRemoteControlEndpointMessage(
} }
try { try {
conference.sendEndpointMessage(to, { conference?.sendEndpointMessage(to, {
name: REMOTE_CONTROL_MESSAGE_NAME, name: REMOTE_CONTROL_MESSAGE_NAME,
...event ...event
}); });
@ -59,7 +62,7 @@ export function sendRemoteControlEndpointMessage(
* @param {Store} store - The redux store. * @param {Store} store - The redux store.
* @returns {void} * @returns {void}
*/ */
export function onRemoteControlAPIEvent(event: Object, { getState, dispatch }: Object) { export function onRemoteControlAPIEvent(event: { type: string; }, { getState, dispatch }: IStore) {
switch (event.type) { switch (event.type) {
case EVENTS.supported: case EVENTS.supported:
logger.log('Remote Control supported.'); logger.log('Remote Control supported.');
@ -93,7 +96,7 @@ export function getRemoteConrolEventCaptureArea() {
* @param {KeyboardEvent} event - The event. * @param {KeyboardEvent} event - The event.
* @returns {KEYS} The key that is pressed or undefined. * @returns {KEYS} The key that is pressed or undefined.
*/ */
export function getKey(event: Object) { export function getKey(event: React.KeyboardEvent) {
return keyboardEventToKey(event); return keyboardEventToKey(event);
} }
@ -103,7 +106,7 @@ export function getKey(event: Object) {
* @param {KeyboardEvent} event - The event. * @param {KeyboardEvent} event - The event.
* @returns {Array} With possible values: "shift", "control", "alt", "command". * @returns {Array} With possible values: "shift", "control", "alt", "command".
*/ */
export function getModifiers(event: Object) { export function getModifiers(event: React.KeyboardEvent) {
const modifiers = []; const modifiers = [];
if (event.shiftKey) { if (event.shiftKey) {

View File

@ -1,3 +1,5 @@
import React from 'react';
/** /**
* Enumerates the supported keys. * Enumerates the supported keys.
* NOTE: The maps represents physical keys on the keyboard, not chars. * NOTE: The maps represents physical keys on the keyboard, not chars.
@ -145,6 +147,7 @@ const keyCodeToKey = {
* Generate codes for digit keys (0-9). * Generate codes for digit keys (0-9).
*/ */
for (let i = 0; i < 10; i++) { for (let i = 0; i < 10; i++) {
// @ts-ignore
keyCodeToKey[i + 48] = `${i}`; keyCodeToKey[i + 48] = `${i}`;
} }
@ -154,7 +157,7 @@ for (let i = 0; i < 10; i++) {
for (let i = 0; i < 26; i++) { for (let i = 0; i < 26; i++) {
const keyCode = i + 65; const keyCode = i + 65;
keyCodeToKey[keyCode] = String.fromCharCode(keyCode).toLowerCase(); keyCodeToKey[keyCode as keyof typeof keyCodeToKey] = String.fromCharCode(keyCode).toLowerCase();
} }
/** /**
@ -163,6 +166,6 @@ for (let i = 0; i < 26; i++) {
* @param {KeyboardEvent} event - The event. * @param {KeyboardEvent} event - The event.
* @returns {KEYS} - The key on the keyboard. * @returns {KEYS} - The key on the keyboard.
*/ */
export function keyboardEventToKey(event) { export function keyboardEventToKey(event: React.KeyboardEvent) {
return keyCodeToKey[event.which]; return keyCodeToKey[event.which as keyof typeof keyCodeToKey];
} }

View File

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

View File

@ -1,10 +1,10 @@
// @flow // @ts-expect-error
import { PostMessageTransportBackend, Transport } from '@jitsi/js-utils/transport'; import { PostMessageTransportBackend, Transport } from '@jitsi/js-utils/transport';
import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../base/app'; import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../base/app/actionTypes';
import { CONFERENCE_JOINED } from '../base/conference'; import { CONFERENCE_JOINED } from '../base/conference/actionTypes';
import { PARTICIPANT_LEFT } from '../base/participants'; import { PARTICIPANT_LEFT } from '../base/participants/actionTypes';
import { MiddlewareRegistry } from '../base/redux'; import MiddlewareRegistry from '../base/redux/MiddlewareRegistry';
import { import {
clearRequest, setReceiverTransport, setRemoteControlActive, stopController, stopReceiver clearRequest, setReceiverTransport, setRemoteControlActive, stopController, stopReceiver
@ -51,7 +51,7 @@ MiddlewareRegistry.register(store => next => async action => {
if (transport) { if (transport) {
// We expect here that even if we receive the supported event earlier // We expect here that even if we receive the supported event earlier
// it will be cached and we'll receive it. // it will be cached and we'll receive it.
transport.on('event', event => { transport.on('event', (event: { name: string; type: string; }) => {
if (event.name === REMOTE_CONTROL_MESSAGE_NAME) { if (event.name === REMOTE_CONTROL_MESSAGE_NAME) {
onRemoteControlAPIEvent(event, store); onRemoteControlAPIEvent(event, store);

View File

@ -34,7 +34,12 @@ export interface IRemoteControlState {
receiver: { receiver: {
controller?: string; controller?: string;
enabled: boolean; enabled: boolean;
transport?: Object; transport?: {
dispose: Function;
on: Function;
sendEvent: Function;
sendRequest: Function;
};
}; };
} }

View File

@ -1,12 +1,10 @@
// @flow
import { import {
getParticipantById, getParticipantById,
getVirtualScreenshareParticipantByOwnerId, getVirtualScreenshareParticipantByOwnerId,
getVirtualScreenshareParticipantOwnerId, getVirtualScreenshareParticipantOwnerId,
isScreenShareParticipant isScreenShareParticipant
} from '../base/participants'; } from '../base/participants/functions';
import { StateListenerRegistry } from '../base/redux'; import StateListenerRegistry from '../base/redux/StateListenerRegistry';
import { pause, resume } from './actions'; import { pause, resume } from './actions';
@ -15,7 +13,7 @@ import { pause, resume } from './actions';
*/ */
StateListenerRegistry.register( StateListenerRegistry.register(
/* selector */ state => { /* selector */ state => {
const { participantId } = state['features/large-video']; const { participantId = '' } = state['features/large-video'];
const { controller } = state['features/remote-control']; const { controller } = state['features/remote-control'];
const { controlled } = controller; const { controlled } = controller;