ref: Convert material-ui files to TS (#12013)

Convert files that use material-ui to TS (needed for material-ui upgrade)
This commit is contained in:
Robert Pintilii 2022-08-25 14:35:19 +03:00 committed by GitHub
parent 94dc6309de
commit dfb2a07cfa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
62 changed files with 802 additions and 673 deletions

View File

@ -1,5 +1,3 @@
// @flow
import { Component } from 'react'; import { Component } from 'react';
export type Props = { export type Props = {
@ -7,7 +5,7 @@ export type Props = {
/** /**
* An SVG icon to be rendered as the content of the label. * An SVG icon to be rendered as the content of the label.
*/ */
icon: Component<any>, icon: Function,
/** /**
* String or component that will be rendered as the label itself. * String or component that will be rendered as the label itself.
@ -18,6 +16,6 @@ export type Props = {
/** /**
* Abstract class for the {@code Label} component. * Abstract class for the {@code Label} component.
*/ */
export default class Label<P: Props, S: *> export default class Label<P extends Props, S>
extends Component<P, S> { extends Component<P, S> {
} }

View File

@ -0,0 +1 @@
export * from './native';

View File

@ -0,0 +1 @@
export * from './web';

View File

@ -1,2 +1 @@
export { default as Label } from './Label'; export * from './_';
export { default as ExpandedLabel } from './ExpandedLabel';

View File

@ -2,12 +2,12 @@
import React from 'react'; import React from 'react';
import { Animated, Text } from 'react-native'; import { Animated, Text } from 'react-native';
import Icon from '../../icons/components/Icon'; import Icon from '../../../icons/components/Icon';
import { combineStyles, type StyleType } from '../../styles'; import { combineStyles, type StyleType } from '../../../styles';
import AbstractLabel, { import AbstractLabel, {
type Props as AbstractProps type Props as AbstractProps
} from './AbstractLabel'; } from '../AbstractLabel';
import styles from './styles'; import styles from './styles';
/** /**

View File

@ -0,0 +1,2 @@
export { default as Label } from './Label';
export { default as ExpandedLabel } from './ExpandedLabel';

View File

@ -1,7 +1,7 @@
// @flow // @flow
import { ColorPalette } from '../../styles'; import { ColorPalette } from '../../../styles';
import BaseTheme from '../../ui/components/BaseTheme'; import BaseTheme from '../../../ui/components/BaseTheme';
/** /**
* The default color of the {@code Label} and {@code ExpandedLabel}. * The default color of the {@code Label} and {@code ExpandedLabel}.

View File

@ -1,48 +1,46 @@
// @flow
import { withStyles } from '@material-ui/core/styles'; import { withStyles } from '@material-ui/core/styles';
import clsx from 'clsx'; import clsx from 'clsx';
import React from 'react'; import React from 'react';
import Icon from '../../icons/components/Icon'; import Icon from '../../../icons/components/Icon';
import { withPixelLineHeight } from '../../styles/functions.web'; import { withPixelLineHeight } from '../../../styles/functions.web';
import { COLORS } from '../constants'; import { COLORS } from '../../constants';
import AbstractLabel, { import AbstractLabel, {
type Props as AbstractProps type Props as AbstractProps
} from './AbstractLabel'; } from '../AbstractLabel';
type Props = AbstractProps & { type Props = AbstractProps & {
/**
* An object containing the CSS classes.
*/
classes: Object,
/** /**
* Own CSS class name. * Own CSS class name.
*/ */
className: string, className: string,
/**
* An object containing the CSS classes.
*/
classes: any,
/** /**
* The color of the label. * The color of the label.
*/ */
color: string, color: string,
/**
* HTML ID attribute to add to the root of {@code Label}.
*/
id: string,
/** /**
* Color for the icon. * Color for the icon.
*/ */
iconColor?: string, iconColor?: string,
/**
* HTML ID attribute to add to the root of {@code Label}.
*/
id: string,
/** /**
* Click handler if any. * Click handler if any.
*/ */
onClick?: Function, onClick?: (e?: React.MouseEvent) => void,
}; };
@ -53,7 +51,7 @@ type Props = AbstractProps & {
* *
* @returns {Object} * @returns {Object}
*/ */
const styles = theme => { const styles = (theme: any) => {
return { return {
label: { label: {
...withPixelLineHeight(theme.typography.labelRegular), ...withPixelLineHeight(theme.typography.labelRegular),
@ -96,7 +94,7 @@ const styles = theme => {
* *
* @augments Component * @augments Component
*/ */
class Label extends AbstractLabel<Props, *> { class Label extends AbstractLabel<Props, any> {
/** /**
* Implements React's {@link Component#render()}. * Implements React's {@link Component#render()}.
* *

View File

@ -0,0 +1,2 @@
export { default as Label } from './Label';
export { default as ExpandedLabel } from './ExpandedLabel';

View File

@ -1,5 +1,3 @@
// @flow
export const COLORS = { export const COLORS = {
white: 'white', white: 'white',
green: 'green', green: 'green',

View File

@ -581,7 +581,7 @@ export function participantKicked(kicker: any, kicked: any) {
* } * }
* }} * }}
*/ */
export function pinParticipant(id: string) { export function pinParticipant(id: string|null) {
return { return {
type: PIN_PARTICIPANT, type: PIN_PARTICIPANT,
participant: { participant: {

View File

@ -224,7 +224,7 @@ export function getNormalizedDisplayName(name: string) {
* @returns {(Participant|undefined)} * @returns {(Participant|undefined)}
*/ */
export function getParticipantById( export function getParticipantById(
stateful: IStore | Function, id: string): Participant|undefined { stateful: IStore | Function | IState, id: string): Participant|undefined {
const state = toState(stateful)['features/base/participants']; const state = toState(stateful)['features/base/participants'];
const { local, localScreenShare, remote } = state; const { local, localScreenShare, remote } = state;

View File

@ -177,7 +177,7 @@ const useStyles = makeStyles((theme: Theme) => {
}; };
}); });
const Button = ({ const Button = React.forwardRef<any, any>(({
accessibilityLabel, accessibilityLabel,
className, className,
disabled, disabled,
@ -191,7 +191,7 @@ const Button = ({
size = 'medium', size = 'medium',
testId, testId,
type = BUTTON_TYPES.PRIMARY type = BUTTON_TYPES.PRIMARY
}: IButtonProps) => { }: IButtonProps, ref) => {
const styles = useStyles(); const styles = useStyles();
const { t } = useTranslation(); const { t } = useTranslation();
@ -206,6 +206,7 @@ const Button = ({
disabled = { disabled } disabled = { disabled }
{ ...(id ? { id } : {}) } { ...(id ? { id } : {}) }
onClick = { onClick } onClick = { onClick }
ref = { ref }
title = { accessibilityLabel } title = { accessibilityLabel }
type = { isSubmit ? 'submit' : 'button' }> type = { isSubmit ? 'submit' : 'button' }>
{icon && <Icon {icon && <Icon
@ -216,6 +217,6 @@ const Button = ({
</span>} </span>}
</button> </button>
); );
}; });
export default Button; export default Button;

View File

@ -1,24 +1,29 @@
// @flow /* eslint-disable lines-around-comment */
import { withStyles } from '@material-ui/styles'; import { withStyles } from '@material-ui/styles';
import clsx from 'clsx'; import clsx from 'clsx';
import debounce from 'lodash/debounce'; import debounce from 'lodash/debounce';
import React, { Component } from 'react'; import React, { Component } from 'react';
// @ts-ignore
import { createScreenSharingIssueEvent, sendAnalytics } from '../../../analytics'; import { createScreenSharingIssueEvent, sendAnalytics } from '../../../analytics';
// @ts-ignore
import { Avatar } from '../../../base/avatar'; import { Avatar } from '../../../base/avatar';
// @ts-ignore
import { getMultipleVideoSupportFeatureFlag, getSourceNameSignalingFeatureFlag } from '../../../base/config'; import { getMultipleVideoSupportFeatureFlag, getSourceNameSignalingFeatureFlag } from '../../../base/config';
import { isMobileBrowser } from '../../../base/environment/utils'; import { isMobileBrowser } from '../../../base/environment/utils';
import { JitsiTrackEvents } from '../../../base/lib-jitsi-meet'; import { JitsiTrackEvents } from '../../../base/lib-jitsi-meet';
// @ts-ignore
import { MEDIA_TYPE, VideoTrack } from '../../../base/media'; import { MEDIA_TYPE, VideoTrack } from '../../../base/media';
import { pinParticipant } from '../../../base/participants/actions';
import { import {
getLocalParticipant, getLocalParticipant,
getParticipantByIdOrUndefined, getParticipantByIdOrUndefined,
hasRaisedHand, hasRaisedHand
pinParticipant } from '../../../base/participants/functions';
} from '../../../base/participants'; import { Participant } from '../../../base/participants/reducer';
import { connect } from '../../../base/redux'; import { connect } from '../../../base/redux/functions';
import { ASPECT_RATIO_NARROW } from '../../../base/responsive-ui/constants'; import { ASPECT_RATIO_NARROW } from '../../../base/responsive-ui/constants';
// @ts-ignore
import { isTestModeEnabled } from '../../../base/testing'; import { isTestModeEnabled } from '../../../base/testing';
import { import {
getLocalAudioTrack, getLocalAudioTrack,
@ -27,12 +32,19 @@ import {
getVirtualScreenshareParticipantTrack, getVirtualScreenshareParticipantTrack,
updateLastTrackVideoMediaEvent, updateLastTrackVideoMediaEvent,
trackStreamingStatusChanged trackStreamingStatusChanged
// @ts-ignore
} from '../../../base/tracks'; } from '../../../base/tracks';
// @ts-ignore
import { getVideoObjectPosition } from '../../../face-landmarks/functions'; import { getVideoObjectPosition } from '../../../face-landmarks/functions';
// @ts-ignore
import { hideGif, showGif } from '../../../gifs/actions'; import { hideGif, showGif } from '../../../gifs/actions';
// @ts-ignore
import { getGifDisplayMode, getGifForParticipant } from '../../../gifs/functions'; import { getGifDisplayMode, getGifForParticipant } from '../../../gifs/functions';
// @ts-ignore
import { PresenceLabel } from '../../../presence-status'; import { PresenceLabel } from '../../../presence-status';
// @ts-ignore
import { getCurrentLayout, LAYOUTS } from '../../../video-layout'; import { getCurrentLayout, LAYOUTS } from '../../../video-layout';
// @ts-ignore
import { togglePinStageParticipant } from '../../actions'; import { togglePinStageParticipant } from '../../actions';
import { import {
DISPLAY_MODE_TO_CLASS_NAME, DISPLAY_MODE_TO_CLASS_NAME,
@ -50,20 +62,22 @@ import {
isVideoPlayable, isVideoPlayable,
isStageFilmstripAvailable, isStageFilmstripAvailable,
showGridInVerticalView showGridInVerticalView
// @ts-ignore
} from '../../functions'; } from '../../functions';
// @ts-ignore
import ThumbnailAudioIndicator from './ThumbnailAudioIndicator'; import ThumbnailAudioIndicator from './ThumbnailAudioIndicator';
import ThumbnailBottomIndicators from './ThumbnailBottomIndicators'; import ThumbnailBottomIndicators from './ThumbnailBottomIndicators';
import ThumbnailTopIndicators from './ThumbnailTopIndicators'; import ThumbnailTopIndicators from './ThumbnailTopIndicators';
// @ts-ignore
import VirtualScreenshareParticipant from './VirtualScreenshareParticipant'; import VirtualScreenshareParticipant from './VirtualScreenshareParticipant';
declare let interfaceConfig: any;
declare var interfaceConfig: Object;
/** /**
* The type of the React {@code Component} state of {@link Thumbnail}. * The type of the React {@code Component} state of {@link Thumbnail}.
*/ */
export type State = {| export type State = {
/** /**
* Indicates that the canplay event has been received. * Indicates that the canplay event has been received.
@ -75,26 +89,26 @@ export type State = {|
*/ */
displayMode: number, displayMode: number,
/**
* Whether popover is visible or not.
*/
popoverVisible: boolean,
/** /**
* Indicates whether the thumbnail is hovered or not. * Indicates whether the thumbnail is hovered or not.
*/ */
isHovered: boolean isHovered: boolean,
|};
/**
* Whether popover is visible or not.
*/
popoverVisible: boolean
};
/** /**
* The type of the React {@code Component} props of {@link Thumbnail}. * The type of the React {@code Component} props of {@link Thumbnail}.
*/ */
export type Props = {| export type Props = {
/** /**
* The audio track related to the participant. * The audio track related to the participant.
*/ */
_audioTrack: ?Object, _audioTrack?: Object,
/** /**
* Indicates whether the local video flip feature is disabled or not. * Indicates whether the local video flip feature is disabled or not.
@ -109,7 +123,7 @@ export type Props = {|
/** /**
* URL of GIF sent by this participant, null if there's none. * URL of GIF sent by this participant, null if there's none.
*/ */
_gifSrc ?: string, _gifSrc?: string,
/** /**
* The height of the Thumbnail. * The height of the Thumbnail.
@ -122,11 +136,6 @@ export type Props = {|
*/ */
_isActiveParticipant: boolean, _isActiveParticipant: boolean,
/**
* Indicates whether the thumbnail should be hidden or not.
*/
_isHidden: boolean,
/** /**
* Indicates whether audio only mode is enabled. * Indicates whether audio only mode is enabled.
*/ */
@ -142,6 +151,11 @@ export type Props = {|
*/ */
_isDominantSpeakerDisabled: boolean, _isDominantSpeakerDisabled: boolean,
/**
* Indicates whether the thumbnail should be hidden or not.
*/
_isHidden: boolean,
/** /**
* Whether we are currently running in a mobile browser. * Whether we are currently running in a mobile browser.
*/ */
@ -181,7 +195,7 @@ export type Props = {|
/** /**
* An object with information about the participant related to the thumbnail. * An object with information about the participant related to the thumbnail.
*/ */
_participant: Object, _participant: Participant,
/** /**
* Whether or not the participant has the hand raised. * Whether or not the participant has the hand raised.
@ -218,7 +232,7 @@ export type Props = {|
/** /**
* The video track that will be displayed in the thumbnail. * The video track that will be displayed in the thumbnail.
*/ */
_videoTrack: ?Object, _videoTrack?: any,
/** /**
* The width of the thumbnail. * The width of the thumbnail.
@ -228,7 +242,7 @@ export type Props = {|
/** /**
* An object containing CSS classes. * An object containing CSS classes.
*/ */
classes: Object, classes: any,
/** /**
* The redux dispatch function. * The redux dispatch function.
@ -248,21 +262,21 @@ export type Props = {|
/** /**
* The ID of the participant related to the thumbnail. * The ID of the participant related to the thumbnail.
*/ */
participantID: ?string, participantID?: string,
/** /**
* Styles that will be set to the Thumbnail's main span element. * Styles that will be set to the Thumbnail's main span element.
*/ */
style?: ?Object, style?: any,
/** /**
* The width of the thumbnail. Used for expanding the width of the thumbnails on last row in case * The width of the thumbnail. Used for expanding the width of the thumbnails on last row in case
* there is empty space. * there is empty space.
*/ */
width?: number width?: number
|}; };
const defaultStyles = theme => { const defaultStyles = (theme: any) => {
return { return {
indicatorsContainer: { indicatorsContainer: {
position: 'absolute', position: 'absolute',
@ -372,13 +386,13 @@ class Thumbnail extends Component<Props, State> {
/** /**
* The long touch setTimeout handler. * The long touch setTimeout handler.
*/ */
timeoutHandle: Object; timeoutHandle?: number;
/** /**
* Timeout used to detect double tapping. * Timeout used to detect double tapping.
* It is active while user has tapped once. * It is active while user has tapped once.
*/ */
_firstTap: ?TimeoutID; _firstTap?: number;
/** /**
* Initializes a new Thumbnail instance. * Initializes a new Thumbnail instance.
@ -400,7 +414,7 @@ class Thumbnail extends Component<Props, State> {
...state, ...state,
displayMode: computeDisplayModeFromInput(getDisplayModeInput(props, state)) displayMode: computeDisplayModeFromInput(getDisplayModeInput(props, state))
}; };
this.timeoutHandle = null; this.timeoutHandle = undefined;
this._clearDoubleClickTimeout = this._clearDoubleClickTimeout.bind(this); this._clearDoubleClickTimeout = this._clearDoubleClickTimeout.bind(this);
this._onCanPlay = this._onCanPlay.bind(this); this._onCanPlay = this._onCanPlay.bind(this);
@ -505,7 +519,7 @@ class Thumbnail extends Component<Props, State> {
* @param {JitsiTrackStreamingStatus} streamingStatus - The updated track streaming status. * @param {JitsiTrackStreamingStatus} streamingStatus - The updated track streaming status.
* @returns {void} * @returns {void}
*/ */
handleTrackStreamingStatusChanged(jitsiTrack, streamingStatus) { handleTrackStreamingStatusChanged(jitsiTrack: any, streamingStatus: any) {
this.props.dispatch(trackStreamingStatusChanged(jitsiTrack, streamingStatus)); this.props.dispatch(trackStreamingStatusChanged(jitsiTrack, streamingStatus));
} }
@ -526,7 +540,7 @@ class Thumbnail extends Component<Props, State> {
* @param {Object} input - The input used to compute the thumbnail display mode. * @param {Object} input - The input used to compute the thumbnail display mode.
* @returns {void} * @returns {void}
*/ */
_maybeSendScreenSharingIssueEvents(input) { _maybeSendScreenSharingIssueEvents(input: any) {
const { const {
_isAudioOnly, _isAudioOnly,
_isScreenSharing, _isScreenSharing,
@ -576,8 +590,6 @@ class Thumbnail extends Component<Props, State> {
return null; return null;
} }
_clearDoubleClickTimeout: () => void;
/** /**
* Clears the first click timeout. * Clears the first click timeout.
* *
@ -588,8 +600,6 @@ class Thumbnail extends Component<Props, State> {
this._firstTap = undefined; this._firstTap = undefined;
} }
_showPopover: () => void;
/** /**
* Shows popover. * Shows popover.
* *
@ -602,8 +612,6 @@ class Thumbnail extends Component<Props, State> {
}); });
} }
_hidePopover: () => void;
/** /**
* Hides popover. * Hides popover.
* *
@ -628,7 +636,7 @@ class Thumbnail extends Component<Props, State> {
* *
* @returns {Object} - The styles for the thumbnail. * @returns {Object} - The styles for the thumbnail.
*/ */
_getStyles(): Object { _getStyles(): any {
const { canPlayEventReceived } = this.state; const { canPlayEventReceived } = this.state;
const { const {
_disableTileEnlargement, _disableTileEnlargement,
@ -652,7 +660,7 @@ class Thumbnail extends Component<Props, State> {
let styles: { let styles: {
avatar: Object, avatar: Object,
thumbnail: Object, thumbnail: any,
video: Object video: Object
} = { } = {
thumbnail: {}, thumbnail: {},
@ -667,7 +675,7 @@ class Thumbnail extends Component<Props, State> {
left += horizontalOffset; left += horizontalOffset;
} }
let videoStyles = null; let videoStyles: any = null;
const doNotStretchVideo = (isPortraitVideo && isTileType) const doNotStretchVideo = (isPortraitVideo && isTileType)
|| _disableTileEnlargement || _disableTileEnlargement
|| _isScreenSharing; || _isScreenSharing;
@ -709,8 +717,6 @@ class Thumbnail extends Component<Props, State> {
return styles; return styles;
} }
_onClick: () => void;
/** /**
* On click handler. * On click handler.
* *
@ -727,8 +733,6 @@ class Thumbnail extends Component<Props, State> {
} }
} }
_onMouseEnter: () => void;
/** /**
* Mouse enter handler. * Mouse enter handler.
* *
@ -752,8 +756,6 @@ class Thumbnail extends Component<Props, State> {
} }
} }
_onMouseLeave: () => void;
/** /**
* Mouse leave handler. * Mouse leave handler.
* *
@ -763,15 +765,13 @@ class Thumbnail extends Component<Props, State> {
this.setState({ isHovered: false }); this.setState({ isHovered: false });
} }
_onTouchStart: () => void;
/** /**
* Handler for touch start. * Handler for touch start.
* *
* @returns {void} * @returns {void}
*/ */
_onTouchStart() { _onTouchStart() {
this.timeoutHandle = setTimeout(this._showPopover, SHOW_TOOLBAR_CONTEXT_MENU_AFTER); this.timeoutHandle = window.setTimeout(this._showPopover, SHOW_TOOLBAR_CONTEXT_MENU_AFTER);
if (this._firstTap) { if (this._firstTap) {
this._clearDoubleClickTimeout(); this._clearDoubleClickTimeout();
@ -780,11 +780,9 @@ class Thumbnail extends Component<Props, State> {
return; return;
} }
this._firstTap = setTimeout(this._clearDoubleClickTimeout, 300); this._firstTap = window.setTimeout(this._clearDoubleClickTimeout, 300);
} }
_onTouchEnd: () => void;
/** /**
* Cancel showing popover context menu after x miliseconds if the no. Of miliseconds is not reached yet, * Cancel showing popover context menu after x miliseconds if the no. Of miliseconds is not reached yet,
* or just clears the timeout. * or just clears the timeout.
@ -795,8 +793,6 @@ class Thumbnail extends Component<Props, State> {
clearTimeout(this.timeoutHandle); clearTimeout(this.timeoutHandle);
} }
_onTouchMove: () => void;
/** /**
* Cancel showing Context menu after x miliseconds if the number of miliseconds is not reached * Cancel showing Context menu after x miliseconds if the number of miliseconds is not reached
* before a touch move(drag), or just clears the timeout. * before a touch move(drag), or just clears the timeout.
@ -845,7 +841,7 @@ class Thumbnail extends Component<Props, State> {
* @param {Object} styles - The styles that will be applied to the avatar. * @param {Object} styles - The styles that will be applied to the avatar.
* @returns {ReactElement} * @returns {ReactElement}
*/ */
_renderAvatar(styles) { _renderAvatar(styles: Object) {
const { _participant } = this.props; const { _participant } = this.props;
const { id } = _participant; const { id } = _participant;
@ -892,8 +888,6 @@ class Thumbnail extends Component<Props, State> {
return className; return className;
} }
_onGifMouseEnter: () => void;
/** /**
* Keep showing the GIF for the current participant. * Keep showing the GIF for the current participant.
* *
@ -905,8 +899,6 @@ class Thumbnail extends Component<Props, State> {
dispatch(showGif(id)); dispatch(showGif(id));
} }
_onGifMouseLeave: () => void;
/** /**
* Keep showing the GIF for the current participant. * Keep showing the GIF for the current participant.
* *
@ -935,15 +927,13 @@ class Thumbnail extends Component<Props, State> {
); );
} }
_onCanPlay: Object => void;
/** /**
* Canplay event listener. * Canplay event listener.
* *
* @param {SyntheticEvent} event - The event. * @param {SyntheticEvent} event - The event.
* @returns {void} * @returns {void}
*/ */
_onCanPlay(event) { _onCanPlay(event: any) {
this.setState({ canPlayEventReceived: true }); this.setState({ canPlayEventReceived: true });
const { const {
@ -956,15 +946,13 @@ class Thumbnail extends Component<Props, State> {
} }
} }
_onTestingEvent: Object => void;
/** /**
* Event handler for testing events. * Event handler for testing events.
* *
* @param {SyntheticEvent} event - The event. * @param {SyntheticEvent} event - The event.
* @returns {void} * @returns {void}
*/ */
_onTestingEvent(event) { _onTestingEvent(event: any) {
const { const {
_videoTrack, _videoTrack,
dispatch dispatch
@ -1004,7 +992,7 @@ class Thumbnail extends Component<Props, State> {
= !_disableLocalVideoFlip && _videoTrack && !_isScreenSharing && _localFlipX ? 'flipVideoX' : ''; = !_disableLocalVideoFlip && _videoTrack && !_isScreenSharing && _localFlipX ? 'flipVideoX' : '';
const jitsiVideoTrack = _videoTrack?.jitsiTrack; const jitsiVideoTrack = _videoTrack?.jitsiTrack;
const videoTrackId = jitsiVideoTrack && jitsiVideoTrack.getId(); const videoTrackId = jitsiVideoTrack && jitsiVideoTrack.getId();
const videoEventListeners = {}; const videoEventListeners: any = {};
if (local) { if (local) {
if (_isMobilePortrait) { if (_isMobilePortrait) {
@ -1168,7 +1156,7 @@ class Thumbnail extends Component<Props, State> {
* @private * @private
* @returns {Props} * @returns {Props}
*/ */
function _mapStateToProps(state, ownProps): Object { function _mapStateToProps(state: any, ownProps: any): Object {
const { participantID, filmstripType = FILMSTRIP_TYPE.MAIN } = ownProps; const { participantID, filmstripType = FILMSTRIP_TYPE.MAIN } = ownProps;
const participant = getParticipantByIdOrUndefined(state, participantID); const participant = getParticipantByIdOrUndefined(state, participantID);
@ -1188,7 +1176,7 @@ function _mapStateToProps(state, ownProps): Object {
const _audioTrack = isLocal const _audioTrack = isLocal
? getLocalAudioTrack(tracks) : getTrackByMediaTypeAndParticipant(tracks, MEDIA_TYPE.AUDIO, participantID); ? getLocalAudioTrack(tracks) : getTrackByMediaTypeAndParticipant(tracks, MEDIA_TYPE.AUDIO, participantID);
const _currentLayout = getCurrentLayout(state); const _currentLayout = getCurrentLayout(state);
let size = {}; let size: any = {};
let _isMobilePortrait = false; let _isMobilePortrait = false;
const { const {
defaultLocalDisplayName, defaultLocalDisplayName,
@ -1287,7 +1275,7 @@ function _mapStateToProps(state, ownProps): Object {
_defaultLocalDisplayName: defaultLocalDisplayName, _defaultLocalDisplayName: defaultLocalDisplayName,
_disableLocalVideoFlip: Boolean(disableLocalVideoFlip), _disableLocalVideoFlip: Boolean(disableLocalVideoFlip),
_disableTileEnlargement: Boolean(disableTileEnlargement), _disableTileEnlargement: Boolean(disableTileEnlargement),
_isActiveParticipant: activeParticipants.find(pId => pId === participantId), _isActiveParticipant: activeParticipants.find((pId: string) => pId === participantId),
_isHidden: isLocal && iAmRecorder && !iAmSipGateway, _isHidden: isLocal && iAmRecorder && !iAmSipGateway,
_isAudioOnly: Boolean(state['features/base/audio-only'].enabled), _isAudioOnly: Boolean(state['features/base/audio-only'].enabled),
_isCurrentlyOnLargeVideo: state['features/large-video']?.participantId === id, _isCurrentlyOnLargeVideo: state['features/large-video']?.participantId === id,
@ -1313,4 +1301,5 @@ function _mapStateToProps(state, ownProps): Object {
}; };
} }
// @ts-ignore
export default connect(_mapStateToProps)(withStyles(defaultStyles)(Thumbnail)); export default connect(_mapStateToProps)(withStyles(defaultStyles)(Thumbnail));

View File

@ -1,5 +1,4 @@
// @flow /* eslint-disable lines-around-comment */
import { makeStyles } from '@material-ui/styles'; import { makeStyles } from '@material-ui/styles';
import React from 'react'; import React from 'react';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
@ -8,13 +7,16 @@ import {
getMultipleVideoSupportFeatureFlag, getMultipleVideoSupportFeatureFlag,
isDisplayNameVisible, isDisplayNameVisible,
isNameReadOnly isNameReadOnly
// @ts-ignore
} from '../../../base/config/functions.any'; } from '../../../base/config/functions.any';
// @ts-ignore
import DisplayName from '../../../display-name/components/web/DisplayName'; import DisplayName from '../../../display-name/components/web/DisplayName';
import { THUMBNAIL_TYPE } from '../../constants'; import { THUMBNAIL_TYPE } from '../../constants';
// @ts-ignore
import StatusIndicators from './StatusIndicators'; import StatusIndicators from './StatusIndicators';
declare var interfaceConfig: Object; declare let interfaceConfig: any;
type Props = { type Props = {
@ -41,7 +43,7 @@ type Props = {
/** /**
* Whether or not to show the status indicators. * Whether or not to show the status indicators.
*/ */
showStatusIndicators: string, showStatusIndicators?: boolean,
/** /**
* The type of thumbnail. * The type of thumbnail.

View File

@ -1,22 +1,28 @@
// @flow /* eslint-disable lines-around-comment */
import { makeStyles } from '@material-ui/styles'; import { makeStyles } from '@material-ui/styles';
import clsx from 'clsx'; import clsx from 'clsx';
import React from 'react'; import React from 'react';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
import { IState } from '../../../app/types';
// @ts-ignore
import { getMultipleVideoSupportFeatureFlag } from '../../../base/config'; import { getMultipleVideoSupportFeatureFlag } from '../../../base/config';
import { isMobileBrowser } from '../../../base/environment/utils'; import { isMobileBrowser } from '../../../base/environment/utils';
// @ts-ignore
import ConnectionIndicator from '../../../connection-indicator/components/web/ConnectionIndicator'; import ConnectionIndicator from '../../../connection-indicator/components/web/ConnectionIndicator';
import { STATS_POPOVER_POSITION, THUMBNAIL_TYPE } from '../../constants'; import { STATS_POPOVER_POSITION, THUMBNAIL_TYPE } from '../../constants';
// @ts-ignore
import { getIndicatorsTooltipPosition } from '../../functions.web'; import { getIndicatorsTooltipPosition } from '../../functions.web';
// @ts-ignore
import PinnedIndicator from './PinnedIndicator'; import PinnedIndicator from './PinnedIndicator';
// @ts-ignore
import RaisedHandIndicator from './RaisedHandIndicator'; import RaisedHandIndicator from './RaisedHandIndicator';
// @ts-ignore
import StatusIndicators from './StatusIndicators'; import StatusIndicators from './StatusIndicators';
import VideoMenuTriggerButton from './VideoMenuTriggerButton'; import VideoMenuTriggerButton from './VideoMenuTriggerButton';
declare var interfaceConfig: Object; declare let interfaceConfig: any;
type Props = { type Props = {
@ -38,7 +44,7 @@ type Props = {
/** /**
* Whether or not the thumbnail is a virtual screen share participant. * Whether or not the thumbnail is a virtual screen share participant.
*/ */
isVirtualScreenshareParticipant: boolean, isVirtualScreenshareParticipant?: boolean,
/** /**
* Whether or not the indicators are for the local participant. * Whether or not the indicators are for the local participant.
@ -95,9 +101,9 @@ const ThumbnailTopIndicators = ({
const { NORMAL = 16 } = interfaceConfig.INDICATOR_FONT_SIZES || {}; const { NORMAL = 16 } = interfaceConfig.INDICATOR_FONT_SIZES || {};
const _indicatorIconSize = NORMAL; const _indicatorIconSize = NORMAL;
const _connectionIndicatorAutoHideEnabled = Boolean( const _connectionIndicatorAutoHideEnabled = Boolean(
useSelector(state => state['features/base/config'].connectionIndicators?.autoHide) ?? true); useSelector((state: IState) => state['features/base/config'].connectionIndicators?.autoHide) ?? true);
const _connectionIndicatorDisabled = _isMobile const _connectionIndicatorDisabled = _isMobile
|| Boolean(useSelector(state => state['features/base/config'].connectionIndicators?.disabled)); || Boolean(useSelector((state: IState) => state['features/base/config'].connectionIndicators?.disabled));
const _isMultiStreamEnabled = useSelector(getMultipleVideoSupportFeatureFlag); const _isMultiStreamEnabled = useSelector(getMultipleVideoSupportFeatureFlag);
const showConnectionIndicator = isHovered || !_connectionIndicatorAutoHideEnabled; const showConnectionIndicator = isHovered || !_connectionIndicatorAutoHideEnabled;

View File

@ -1,5 +1,4 @@
// @flow // @ts-ignore
import { BoxModel } from '../base/styles'; import { BoxModel } from '../base/styles';
/** /**

View File

@ -1,6 +1,5 @@
// @flow /* eslint-disable lines-around-comment */
import { GiphyFetch, TrendingOptions } from '@giphy/js-fetch-api';
import { GiphyFetch } from '@giphy/js-fetch-api';
import { Grid } from '@giphy/react-components'; import { Grid } from '@giphy/react-components';
import { makeStyles } from '@material-ui/core'; import { makeStyles } from '@material-ui/core';
import clsx from 'clsx'; import clsx from 'clsx';
@ -8,21 +7,30 @@ import React, { useCallback, useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { batch, useDispatch, useSelector } from 'react-redux'; import { batch, useDispatch, useSelector } from 'react-redux';
// @ts-ignore
import { createGifSentEvent, sendAnalytics } from '../../../analytics'; import { createGifSentEvent, sendAnalytics } from '../../../analytics';
import { IState } from '../../../app/types';
// @ts-ignore
import InputField from '../../../base/premeeting/components/web/InputField'; import InputField from '../../../base/premeeting/components/web/InputField';
import BaseTheme from '../../../base/ui/components/BaseTheme'; import BaseTheme from '../../../base/ui/components/BaseTheme.web';
// @ts-ignore
import { sendMessage } from '../../../chat/actions.any'; import { sendMessage } from '../../../chat/actions.any';
import { SCROLL_SIZE } from '../../../filmstrip'; import { SCROLL_SIZE } from '../../../filmstrip/constants';
import { toggleReactionsMenuVisibility } from '../../../reactions/actions.web'; import { toggleReactionsMenuVisibility } from '../../../reactions/actions.web';
// @ts-ignore
import { setOverflowMenuVisible } from '../../../toolbox/actions.web'; import { setOverflowMenuVisible } from '../../../toolbox/actions.web';
// @ts-ignore
import { Drawer, JitsiPortal } from '../../../toolbox/components/web'; import { Drawer, JitsiPortal } from '../../../toolbox/components/web';
// @ts-ignore
import { showOverflowDrawer } from '../../../toolbox/functions.web'; import { showOverflowDrawer } from '../../../toolbox/functions.web';
// @ts-ignore
import { setGifDrawerVisibility } from '../../actions'; import { setGifDrawerVisibility } from '../../actions';
// @ts-ignore
import { formatGifUrlMessage, getGifAPIKey, getGifUrl } from '../../functions'; import { formatGifUrlMessage, getGifAPIKey, getGifUrl } from '../../functions';
const OVERFLOW_DRAWER_PADDING = BaseTheme.spacing(3); const OVERFLOW_DRAWER_PADDING = BaseTheme.spacing(3);
const useStyles = makeStyles(theme => { const useStyles = makeStyles((theme: any) => {
return { return {
gifsMenu: { gifsMenu: {
width: '100%', width: '100%',
@ -87,17 +95,17 @@ const useStyles = makeStyles(theme => {
* @returns {ReactElement} * @returns {ReactElement}
*/ */
function GifsMenu() { function GifsMenu() {
const API_KEY = useSelector(getGifAPIKey); const API_KEY: string = useSelector(getGifAPIKey);
const giphyFetch = new GiphyFetch(API_KEY); const giphyFetch = new GiphyFetch(API_KEY);
const [ searchKey, setSearchKey ] = useState(); const [ searchKey, setSearchKey ] = useState<string>();
const styles = useStyles(); const styles = useStyles();
const dispatch = useDispatch(); const dispatch = useDispatch();
const { t } = useTranslation(); const { t } = useTranslation();
const overflowDrawer = useSelector(showOverflowDrawer); const overflowDrawer: boolean = useSelector(showOverflowDrawer);
const { clientWidth } = useSelector(state => state['features/base/responsive-ui']); const { clientWidth } = useSelector((state: IState) => state['features/base/responsive-ui']);
const fetchGifs = useCallback(async (offset = 0) => { const fetchGifs = useCallback(async (offset = 0) => {
const options = { const options: TrendingOptions = {
rating: 'pg-13', rating: 'pg-13',
limit: 20, limit: 20,
offset offset
@ -113,7 +121,7 @@ function GifsMenu() {
const onDrawerClose = useCallback(() => { const onDrawerClose = useCallback(() => {
dispatch(setGifDrawerVisibility(false)); dispatch(setGifDrawerVisibility(false));
dispatch(setOverflowMenuVisible(false)); dispatch(setOverflowMenuVisible(false));
}); }, []);
const handleGifClick = useCallback((gif, e) => { const handleGifClick = useCallback((gif, e) => {
e?.stopPropagation(); e?.stopPropagation();
@ -135,26 +143,37 @@ function GifsMenu() {
const handleSearchKeyChange = useCallback(value => { const handleSearchKeyChange = useCallback(value => {
setSearchKey(value); setSearchKey(value);
}); }, []);
const handleKeyDown = useCallback(e => { const handleKeyDown = useCallback(e => {
if (!document.activeElement) {
return;
}
if (e.keyCode === 38) { // up arrow if (e.keyCode === 38) { // up arrow
e.preventDefault(); e.preventDefault();
// if the first gif is focused move focus to the input // if the first gif is focused move focus to the input
if (document.activeElement.previousElementSibling === null) { if (document.activeElement.previousElementSibling === null) {
document.querySelector('.gif-input').focus(); const element = document.querySelector('.gif-input') as HTMLElement;
element?.focus();
} else { } else {
document.activeElement.previousElementSibling.focus(); const element = document.activeElement.previousElementSibling as HTMLElement;
element?.focus();
} }
} else if (e.keyCode === 40) { // down arrow } else if (e.keyCode === 40) { // down arrow
e.preventDefault(); e.preventDefault();
// if the input is focused move focus to the first gif // if the input is focused move focus to the first gif
if (document.activeElement.classList.contains('gif-input')) { if (document.activeElement.classList.contains('gif-input')) {
document.querySelector('.giphy-gif').focus(); const element = document.querySelector('.giphy-gif') as HTMLElement;
element?.focus();
} else { } else {
document.activeElement.nextElementSibling.focus(); const element = document.activeElement.nextElementSibling as HTMLElement;
element?.focus();
} }
} }
}, []); }, []);

View File

@ -0,0 +1 @@
export * from './native';

View File

@ -0,0 +1 @@
export * from './web';

View File

@ -1,2 +1 @@
export { default as KeyboardShortcutsButton } from './KeyboardShortcutsButton'; export * from './_';
export { default as KeyboardShortcutsDialog } from './KeyboardShortcutsDialog';

View File

@ -1,11 +1,11 @@
// @flow // @flow
import { createToolbarEvent, sendAnalytics } from '../../analytics'; import { createToolbarEvent, sendAnalytics } from '../../../analytics';
import { translate } from '../../base/i18n'; import { translate } from '../../../base/i18n';
import { IconDeviceDocument } from '../../base/icons'; import { IconDeviceDocument } from '../../../base/icons';
import { connect } from '../../base/redux'; import { connect } from '../../../base/redux';
import { AbstractButton, type AbstractButtonProps } from '../../base/toolbox/components'; import { AbstractButton, type AbstractButtonProps } from '../../../base/toolbox/components';
import { openKeyboardShortcutsDialog } from '../actions'; import { openKeyboardShortcutsDialog } from '../../actions';
/** /**
* The type of the React {@code Component} props of {@link KeyboardShortcutsButton}. * The type of the React {@code Component} props of {@link KeyboardShortcutsButton}.

View File

@ -1,33 +1,28 @@
/* @flow */
import { withStyles } from '@material-ui/core/styles'; import { withStyles } from '@material-ui/core/styles';
import clsx from 'clsx'; import clsx from 'clsx';
import React, { Component } from 'react'; import React, { Component } from 'react';
import { WithTranslation } from 'react-i18next';
import { Dialog } from '../../base/dialog'; // @ts-ignore
import { translate } from '../../base/i18n'; import { Dialog } from '../../../base/dialog';
import { translate } from '../../../base/i18n/functions';
/** /**
* The type of the React {@code Component} props of * The type of the React {@code Component} props of
* {@link KeyboardShortcutsDialog}. * {@link KeyboardShortcutsDialog}.
*/ */
type Props = { interface Props extends WithTranslation {
/** /**
* An object containing the CSS classes. * An object containing the CSS classes.
*/ */
classes: Object, classes: any,
/** /**
* A Map with keyboard keys as keys and translation keys as values. * A Map with keyboard keys as keys and translation keys as values.
*/ */
shortcutDescriptions: Object, shortcutDescriptions: Map<string, string>
}
/**
* Invoked to obtain translated strings.
*/
t: Function
};
/** /**
* Creates the styles for the component. * Creates the styles for the component.
@ -36,7 +31,7 @@ type Props = {
* *
* @returns {Object} * @returns {Object}
*/ */
const styles = theme => { const styles = (theme: any) => {
return { return {
list: { list: {
listStyleType: 'none', listStyleType: 'none',
@ -86,7 +81,7 @@ class KeyboardShortcutsDialog extends Component<Props> {
<ul <ul
className = { clsx('shortcuts-list', this.props.classes.list) } className = { clsx('shortcuts-list', this.props.classes.list) }
id = 'keyboard-shortcuts-list'> id = 'keyboard-shortcuts-list'>
{ shortcuts } {shortcuts}
</ul> </ul>
</div> </div>
</Dialog> </Dialog>
@ -101,7 +96,7 @@ class KeyboardShortcutsDialog extends Component<Props> {
* @private * @private
* @returns {ReactElement} * @returns {ReactElement}
*/ */
_renderShortcutsListItem(keyboardKey, translationKey) { _renderShortcutsListItem(keyboardKey: string, translationKey: string) {
let modifierKey = 'Alt'; let modifierKey = 'Alt';
if (window.navigator?.platform) { if (window.navigator?.platform) {

View File

@ -0,0 +1,2 @@
export { default as KeyboardShortcutsButton } from './KeyboardShortcutsButton';
export { default as KeyboardShortcutsDialog } from './KeyboardShortcutsDialog';

View File

@ -1,20 +1,23 @@
// @flow /* eslint-disable lines-around-comment */
import { FlagGroupContext } from '@atlaskit/flag/flag-group'; import { FlagGroupContext } from '@atlaskit/flag/flag-group';
import { AtlasKitThemeProvider } from '@atlaskit/theme'; import { AtlasKitThemeProvider } from '@atlaskit/theme';
import { withStyles } from '@material-ui/styles'; import { withStyles } from '@material-ui/styles';
import clsx from 'clsx'; import clsx from 'clsx';
import React, { Component } from 'react'; import React, { Component } from 'react';
import { WithTranslation } from 'react-i18next';
import { CSSTransition, TransitionGroup } from 'react-transition-group'; import { CSSTransition, TransitionGroup } from 'react-transition-group';
import { translate } from '../../../base/i18n'; import { translate } from '../../../base/i18n/functions';
import { connect } from '../../../base/redux'; import { connect } from '../../../base/redux/functions';
// @ts-ignore
import { hideNotification } from '../../actions'; import { hideNotification } from '../../actions';
// @ts-ignore
import { areThereNotifications } from '../../functions'; import { areThereNotifications } from '../../functions';
// @ts-ignore
import Notification from './Notification'; import Notification from './Notification';
type Props = { interface Props extends WithTranslation {
/** /**
* Whether we are a SIP gateway or not. * Whether we are a SIP gateway or not.
@ -30,12 +33,15 @@ type Props = {
* The notifications to be displayed, with the first index being the * The notifications to be displayed, with the first index being the
* notification at the top and the rest shown below it in order. * notification at the top and the rest shown below it in order.
*/ */
_notifications: Array<Object>, _notifications: Array<{
props: Object;
uid: number;
}>,
/** /**
* JSS classes object. * JSS classes object.
*/ */
classes: Object, classes: any,
/** /**
* Invoked to update the redux store in order to remove notifications. * Invoked to update the redux store in order to remove notifications.
@ -45,15 +51,10 @@ type Props = {
/** /**
* Whether or not the notifications are displayed in a portal. * Whether or not the notifications are displayed in a portal.
*/ */
portal?: boolean, portal?: boolean
}
/** const useStyles = (theme: any) => {
* Invoked to obtain translated strings.
*/
t: Function
};
const useStyles = theme => {
return { return {
container: { container: {
position: 'absolute', position: 'absolute',
@ -124,7 +125,7 @@ const useStyles = theme => {
*/ */
class NotificationsContainer extends Component<Props> { class NotificationsContainer extends Component<Props> {
_api: Object; _api: Object;
_timeouts: Map<string, TimeoutID>; _timeouts: Map<string, number>;
/** /**
* Initializes a new {@code NotificationsContainer} instance. * Initializes a new {@code NotificationsContainer} instance.
@ -161,6 +162,7 @@ class NotificationsContainer extends Component<Props> {
return ( return (
<AtlasKitThemeProvider mode = 'light'> <AtlasKitThemeProvider mode = 'light'>
{/* @ts-ignore */}
<FlagGroupContext.Provider value = { this._api }> <FlagGroupContext.Provider value = { this._api }>
<div <div
className = { clsx(this.props.classes.container, { className = { clsx(this.props.classes.container, {
@ -176,8 +178,6 @@ class NotificationsContainer extends Component<Props> {
); );
} }
_onDismissed: number => void;
/** /**
* Emits an action to remove the notification from the redux store so it * Emits an action to remove the notification from the redux store so it
* stops displaying. * stops displaying.
@ -186,12 +186,12 @@ class NotificationsContainer extends Component<Props> {
* @private * @private
* @returns {void} * @returns {void}
*/ */
_onDismissed(uid) { _onDismissed(uid: number) {
const timeout = this._timeouts.get(uid); const timeout = this._timeouts.get(`${uid}`);
if (timeout) { if (timeout) {
clearTimeout(timeout); clearTimeout(timeout);
this._timeouts.delete(uid); this._timeouts.delete(`${uid}`);
} }
this.props.dispatch(hideNotification(uid)); this.props.dispatch(hideNotification(uid));
@ -238,7 +238,7 @@ class NotificationsContainer extends Component<Props> {
* @private * @private
* @returns {Props} * @returns {Props}
*/ */
function _mapStateToProps(state) { function _mapStateToProps(state: any) {
const { notifications } = state['features/notifications']; const { notifications } = state['features/notifications'];
const { iAmSipGateway } = state['features/base/config']; const { iAmSipGateway } = state['features/base/config'];
const { isOpen: isChatOpen } = state['features/chat']; const { isOpen: isChatOpen } = state['features/chat'];
@ -251,4 +251,5 @@ function _mapStateToProps(state) {
}; };
} }
// @ts-ignore
export default translate(connect(_mapStateToProps)(withStyles(useStyles)(NotificationsContainer))); export default translate(connect(_mapStateToProps)(withStyles(useStyles)(NotificationsContainer)));

View File

@ -1,18 +1,24 @@
// @flow /* eslint-disable lines-around-comment */
import { makeStyles } from '@material-ui/styles'; import { makeStyles } from '@material-ui/styles';
import clsx from 'clsx'; import clsx from 'clsx';
import React, { useCallback, useState } from 'react'; import React, { ReactElement, useCallback, useState } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
import { IState } from '../../../../../app/types';
// @ts-ignore
import { ListItem } from '../../../../../base/components'; import { ListItem } from '../../../../../base/components';
import { Icon, IconArrowDown, IconArrowUp } from '../../../../../base/icons'; import Icon from '../../../../../base/icons/components/Icon';
import { isLocalParticipantModerator } from '../../../../../base/participants'; import { IconArrowDown, IconArrowUp } from '../../../../../base/icons/svg/index';
import { isLocalParticipantModerator } from '../../../../../base/participants/functions';
// @ts-ignore
import { showOverflowDrawer } from '../../../../../toolbox/functions.web'; import { showOverflowDrawer } from '../../../../../toolbox/functions.web';
// @ts-ignore
import { ACTION_TRIGGER } from '../../../../constants'; import { ACTION_TRIGGER } from '../../../../constants';
// @ts-ignore
import { participantMatchesSearch } from '../../../../functions'; import { participantMatchesSearch } from '../../../../functions';
import ParticipantActionEllipsis from '../../../web/ParticipantActionEllipsis'; import ParticipantActionEllipsis from '../../../web/ParticipantActionEllipsis';
// @ts-ignore
import ParticipantItem from '../../../web/ParticipantItem'; import ParticipantItem from '../../../web/ParticipantItem';
type Props = { type Props = {
@ -25,27 +31,29 @@ type Props = {
/** /**
* React children. * React children.
*/ */
children: React$Node, children: ReactElement,
/** /**
* Is this item highlighted/raised. * Is this item highlighted/raised.
*/ */
isHighlighted?: boolean, isHighlighted?: boolean,
/**
* Callback to raise menu. Used to raise menu on mobile long press.
*/
onRaiseMenu: Function,
/** /**
* Callback for when the mouse leaves this component. * Callback for when the mouse leaves this component.
*/ */
onLeave?: Function, onLeave?: Function,
/**
* Callback to raise menu. Used to raise menu on mobile long press.
*/
onRaiseMenu: Function,
/** /**
* The raise context for the participant menu. * The raise context for the participant menu.
*/ */
participantContextEntity: ?Object, participantContextEntity?: {
jid: string
},
/** /**
* Callback to raise participant context menu. * Callback to raise participant context menu.
@ -55,7 +63,16 @@ type Props = {
/** /**
* Room reference. * Room reference.
*/ */
room: Object, room: {
id: string;
name: string;
participants: {
[jid: string]: {
displayName: string;
jid: string;
}
};
},
/** /**
* Participants search string. * Participants search string.
@ -68,7 +85,7 @@ type Props = {
toggleParticipantMenu: Function toggleParticipantMenu: Function
} }
const useStyles = makeStyles(theme => { const useStyles = makeStyles((theme: any) => {
return { return {
container: { container: {
boxShadow: 'none' boxShadow: 'none'
@ -117,7 +134,7 @@ export const CollapsibleRoom = ({
const raiseMenu = useCallback(target => { const raiseMenu = useCallback(target => {
onRaiseMenu(target); onRaiseMenu(target);
}, [ onRaiseMenu ]); }, [ onRaiseMenu ]);
const { defaultRemoteDisplayName } = useSelector(state => state['features/base/config']); const { defaultRemoteDisplayName } = useSelector((state: IState) => state['features/base/config']);
const overflowDrawer = useSelector(showOverflowDrawer); const overflowDrawer = useSelector(showOverflowDrawer);
const moderator = useSelector(isLocalParticipantModerator); const moderator = useSelector(isLocalParticipantModerator);
@ -153,7 +170,7 @@ export const CollapsibleRoom = ({
textChildren = { roomName } textChildren = { roomName }
trigger = { actionsTrigger } /> trigger = { actionsTrigger } />
{!collapsed && room?.participants {!collapsed && room?.participants
&& Object.values(room?.participants || {}).map((p: Object) => && Object.values(room?.participants || {}).map(p =>
participantMatchesSearch(p, searchString) && ( participantMatchesSearch(p, searchString) && (
<ParticipantItem <ParticipantItem
actionsTrigger = { ACTION_TRIGGER.HOVER } actionsTrigger = { ACTION_TRIGGER.HOVER }
@ -166,6 +183,7 @@ export const CollapsibleRoom = ({
participantID = { p.jid }> participantID = { p.jid }>
{!overflowDrawer && moderator && ( {!overflowDrawer && moderator && (
<ParticipantActionEllipsis <ParticipantActionEllipsis
accessibilityLabel = { t('breakoutRoom.more') }
onClick = { toggleParticipantMenu({ room, onClick = { toggleParticipantMenu({ room,
jid: p.jid, jid: p.jid,
participantName: p.displayName }) } /> participantName: p.displayName }) } />

View File

@ -1,5 +1,4 @@
// @flow /* eslint-disable lines-around-comment */
import { makeStyles } from '@material-ui/core/styles'; import { makeStyles } from '@material-ui/core/styles';
import React, { useCallback } from 'react'; import React, { useCallback } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
@ -10,32 +9,39 @@ import {
requestDisableVideoModeration, requestDisableVideoModeration,
requestEnableAudioModeration, requestEnableAudioModeration,
requestEnableVideoModeration requestEnableVideoModeration
// @ts-ignore
} from '../../../av-moderation/actions'; } from '../../../av-moderation/actions';
import { import {
isEnabled as isAvModerationEnabled, isEnabled as isAvModerationEnabled,
isSupported as isAvModerationSupported isSupported as isAvModerationSupported
// @ts-ignore
} from '../../../av-moderation/functions'; } from '../../../av-moderation/functions';
// @ts-ignore
import { ContextMenu, ContextMenuItemGroup } from '../../../base/components'; import { ContextMenu, ContextMenuItemGroup } from '../../../base/components';
// @ts-ignore
import { openDialog } from '../../../base/dialog'; import { openDialog } from '../../../base/dialog';
import { import {
IconCheck, IconCheck,
IconHorizontalPoints, IconHorizontalPoints,
IconVideoOff IconVideoOff
} from '../../../base/icons'; } from '../../../base/icons/svg';
import { MEDIA_TYPE } from '../../../base/media'; import { MEDIA_TYPE } from '../../../base/media/constants';
import { import {
getParticipantCount, getParticipantCount,
isEveryoneModerator isEveryoneModerator
} from '../../../base/participants'; } from '../../../base/participants/functions';
// @ts-ignore
import { isInBreakoutRoom } from '../../../breakout-rooms/functions'; import { isInBreakoutRoom } from '../../../breakout-rooms/functions';
import { import {
SETTINGS_TABS, SETTINGS_TABS,
openSettingsDialog, openSettingsDialog,
shouldShowModeratorSettings shouldShowModeratorSettings
// @ts-ignore
} from '../../../settings'; } from '../../../settings';
// @ts-ignore
import { MuteEveryonesVideoDialog } from '../../../video-menu/components'; import { MuteEveryonesVideoDialog } from '../../../video-menu/components';
const useStyles = makeStyles(theme => { const useStyles = makeStyles((theme: any) => {
return { return {
contextMenu: { contextMenu: {
bottom: 'auto', bottom: 'auto',

View File

@ -1,40 +1,45 @@
// @flow /* eslint-disable lines-around-comment */
import { makeStyles } from '@material-ui/styles'; import { makeStyles } from '@material-ui/styles';
import React, { useCallback, useState, useRef } from 'react'; import React, { useCallback, useState, useRef } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
// @ts-ignore
import { ContextMenu, ContextMenuItemGroup } from '../../../base/components'; import { ContextMenu, ContextMenuItemGroup } from '../../../base/components';
import { IconChat, IconCloseCircle, IconHorizontalPoints } from '../../../base/icons'; import { IconChat, IconCloseCircle, IconHorizontalPoints } from '../../../base/icons/svg/index';
import { hasRaisedHand } from '../../../base/participants'; import { hasRaisedHand } from '../../../base/participants/functions';
import { Participant } from '../../../base/participants/reducer';
import Button from '../../../base/ui/components/web/Button'; import Button from '../../../base/ui/components/web/Button';
import { BUTTON_TYPES } from '../../../base/ui/constants'; import { BUTTON_TYPES } from '../../../base/ui/constants';
// @ts-ignore
import { showLobbyChatButton } from '../../../lobby/functions'; import { showLobbyChatButton } from '../../../lobby/functions';
// @ts-ignore
import { ACTION_TRIGGER, MEDIA_STATE } from '../../constants'; import { ACTION_TRIGGER, MEDIA_STATE } from '../../constants';
// @ts-ignore
import { useLobbyActions } from '../../hooks'; import { useLobbyActions } from '../../hooks';
// @ts-ignore
import ParticipantItem from './ParticipantItem'; import ParticipantItem from './ParticipantItem';
type Props = { type Props = {
/**
* If an overflow drawer should be displayed.
*/
overflowDrawer: boolean,
/** /**
* Callback used to open a drawer with admit/reject actions. * Callback used to open a drawer with admit/reject actions.
*/ */
openDrawerForParticipant: Function, openDrawerForParticipant: Function,
/**
* If an overflow drawer should be displayed.
*/
overflowDrawer: boolean,
/** /**
* Participant reference. * Participant reference.
*/ */
participant: Object participant: Participant
}; };
const useStyles = makeStyles(theme => { const useStyles = makeStyles((theme: any) => {
return { return {
button: { button: {
marginRight: `${theme.spacing(2)}px` marginRight: `${theme.spacing(2)}px`
@ -67,8 +72,8 @@ export const LobbyParticipantItem = ({
const moreButtonRef = useRef(); const moreButtonRef = useRef();
const openContextMenu = useCallback(() => setIsOpen(true)); const openContextMenu = useCallback(() => setIsOpen(true), []);
const closeContextMenu = useCallback(() => setIsOpen(false)); const closeContextMenu = useCallback(() => setIsOpen(false), []);
const renderAdmitButton = () => ( const renderAdmitButton = () => (
<Button <Button

View File

@ -1,22 +1,29 @@
// @flow /* eslint-disable lines-around-comment */
import { makeStyles } from '@material-ui/core/styles'; import { makeStyles } from '@material-ui/core/styles';
import React, { useCallback } from 'react'; import React, { useCallback } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useSelector, useDispatch } from 'react-redux'; import { useSelector, useDispatch } from 'react-redux';
// @ts-ignore
import { Avatar } from '../../../base/avatar'; import { Avatar } from '../../../base/avatar';
import { Icon, IconCheck, IconClose } from '../../../base/icons'; import Icon from '../../../base/icons/components/Icon';
import { IconCheck, IconClose } from '../../../base/icons/svg/index';
import { withPixelLineHeight } from '../../../base/styles/functions.web'; import { withPixelLineHeight } from '../../../base/styles/functions.web';
// @ts-ignore
import { admitMultiple } from '../../../lobby/actions.web'; import { admitMultiple } from '../../../lobby/actions.web';
// @ts-ignore
import { getLobbyEnabled, getKnockingParticipants } from '../../../lobby/functions'; import { getLobbyEnabled, getKnockingParticipants } from '../../../lobby/functions';
// @ts-ignore
import { Drawer, JitsiPortal } from '../../../toolbox/components/web'; import { Drawer, JitsiPortal } from '../../../toolbox/components/web';
// @ts-ignore
import { showOverflowDrawer } from '../../../toolbox/functions'; import { showOverflowDrawer } from '../../../toolbox/functions';
// @ts-ignore
import { useLobbyActions, useParticipantDrawer } from '../../hooks'; import { useLobbyActions, useParticipantDrawer } from '../../hooks';
// @ts-ignore
import LobbyParticipantItems from './LobbyParticipantItems'; import LobbyParticipantItems from './LobbyParticipantItems';
const useStyles = makeStyles(theme => { const useStyles = makeStyles((theme: any) => {
return { return {
drawerActions: { drawerActions: {
listStyleType: 'none', listStyleType: 'none',
@ -67,7 +74,7 @@ const useStyles = makeStyles(theme => {
*/ */
export default function LobbyParticipants() { export default function LobbyParticipants() {
const lobbyEnabled = useSelector(getLobbyEnabled); const lobbyEnabled = useSelector(getLobbyEnabled);
const participants = useSelector(getKnockingParticipants); const participants: Array<Object> = useSelector(getKnockingParticipants);
const { t } = useTranslation(); const { t } = useTranslation();
const classes = useStyles(); const classes = useStyles();
const dispatch = useDispatch(); const dispatch = useDispatch();

View File

@ -1,30 +1,40 @@
// @flow /* eslint-disable lines-around-comment */
import { makeStyles } from '@material-ui/styles'; import { makeStyles } from '@material-ui/styles';
import React, { useCallback } from 'react'; import React, { useCallback } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useDispatch, useSelector } from 'react-redux'; import { useDispatch, useSelector } from 'react-redux';
import { IState } from '../../../app/types';
// @ts-ignore
import { rejectParticipantAudio } from '../../../av-moderation/actions'; import { rejectParticipantAudio } from '../../../av-moderation/actions';
// @ts-ignore
import useContextMenu from '../../../base/components/context-menu/useContextMenu'; import useContextMenu from '../../../base/components/context-menu/useContextMenu';
import participantsPaneTheme from '../../../base/components/themes/participantsPaneTheme.json'; import participantsPaneTheme from '../../../base/components/themes/participantsPaneTheme.json';
// @ts-ignore
import { isToolbarButtonEnabled } from '../../../base/config/functions.web'; import { isToolbarButtonEnabled } from '../../../base/config/functions.web';
import { MEDIA_TYPE } from '../../../base/media'; import { MEDIA_TYPE } from '../../../base/media/constants';
import { getParticipantById } from '../../../base/participants'; import { getParticipantById } from '../../../base/participants/functions';
import { connect } from '../../../base/redux'; import { connect } from '../../../base/redux/functions';
import Input from '../../../base/ui/components/web/Input'; import Input from '../../../base/ui/components/web/Input';
import { normalizeAccents } from '../../../base/util/strings'; import { normalizeAccents } from '../../../base/util/strings.web';
// @ts-ignore
import { getBreakoutRooms, getCurrentRoomId, isInBreakoutRoom } from '../../../breakout-rooms/functions'; import { getBreakoutRooms, getCurrentRoomId, isInBreakoutRoom } from '../../../breakout-rooms/functions';
// @ts-ignore
import { showOverflowDrawer } from '../../../toolbox/functions'; import { showOverflowDrawer } from '../../../toolbox/functions';
// @ts-ignore
import { muteRemote } from '../../../video-menu/actions.any'; import { muteRemote } from '../../../video-menu/actions.any';
// @ts-ignore
import { getSortedParticipantIds, shouldRenderInviteButton } from '../../functions'; import { getSortedParticipantIds, shouldRenderInviteButton } from '../../functions';
// @ts-ignore
import { useParticipantDrawer } from '../../hooks'; import { useParticipantDrawer } from '../../hooks';
import { InviteButton } from './InviteButton'; import { InviteButton } from './InviteButton';
// @ts-ignore
import MeetingParticipantContextMenu from './MeetingParticipantContextMenu'; import MeetingParticipantContextMenu from './MeetingParticipantContextMenu';
// @ts-ignore
import MeetingParticipantItems from './MeetingParticipantItems'; import MeetingParticipantItems from './MeetingParticipantItems';
const useStyles = makeStyles(theme => { const useStyles = makeStyles((theme: any) => {
return { return {
heading: { heading: {
color: theme.palette.text02, color: theme.palette.text02,
@ -48,13 +58,13 @@ const useStyles = makeStyles(theme => {
}); });
type Props = { type Props = {
currentRoom: ?Object, currentRoom?: {name: string},
participantsCount: number, overflowDrawer?: boolean,
overflowDrawer: boolean, participantsCount?: number,
searchString: string, searchString: string,
setSearchString: Function, setSearchString: (newValue: string) => void,
showInviteButton: boolean, showInviteButton?: boolean,
sortedParticipantIds: Array<string> sortedParticipantIds?: Array<string>
}; };
/** /**
@ -156,15 +166,15 @@ function MeetingParticipants({
* @private * @private
* @returns {Props} * @returns {Props}
*/ */
function _mapStateToProps(state): Object { function _mapStateToProps(state: IState): Object {
let sortedParticipantIds = getSortedParticipantIds(state); let sortedParticipantIds: any = getSortedParticipantIds(state);
// Filter out the virtual screenshare participants since we do not want them to be displayed as separate // Filter out the virtual screenshare participants since we do not want them to be displayed as separate
// participants in the participants pane. // participants in the participants pane.
sortedParticipantIds = sortedParticipantIds.filter(id => { sortedParticipantIds = sortedParticipantIds.filter((id: any) => {
const participant = getParticipantById(state, id); const participant = getParticipantById(state, id);
return !participant.isVirtualScreenshareParticipant; return !participant?.isVirtualScreenshareParticipant;
}); });
const participantsCount = sortedParticipantIds.length; const participantsCount = sortedParticipantIds.length;

View File

@ -1,10 +1,13 @@
// @flow /* eslint-disable lines-around-comment */
import { makeStyles } from '@material-ui/styles'; import { makeStyles } from '@material-ui/styles';
import React, { type Node, useCallback } from 'react'; import React, { ReactElement, useCallback } from 'react';
import { WithTranslation } from 'react-i18next';
// @ts-ignore
import { Avatar } from '../../../base/avatar'; import { Avatar } from '../../../base/avatar';
// @ts-ignore
import { ListItem } from '../../../base/components'; import { ListItem } from '../../../base/components';
// @ts-ignore
import { translate } from '../../../base/i18n'; import { translate } from '../../../base/i18n';
import { import {
ACTION_TRIGGER, ACTION_TRIGGER,
@ -13,11 +16,13 @@ import {
type ActionTrigger, type ActionTrigger,
type MediaState, type MediaState,
VideoStateIcons VideoStateIcons
// @ts-ignore
} from '../../constants'; } from '../../constants';
// @ts-ignore
import { RaisedHandIndicator } from './RaisedHandIndicator'; import { RaisedHandIndicator } from './RaisedHandIndicator';
type Props = { interface Props extends WithTranslation {
/** /**
* Type of trigger for the participant actions. * Type of trigger for the participant actions.
@ -32,7 +37,7 @@ type Props = {
/** /**
* React children. * React children.
*/ */
children?: Node, children?: ReactElement,
/** /**
* Whether or not to disable the moderator indicator. * Whether or not to disable the moderator indicator.
@ -59,16 +64,16 @@ type Props = {
*/ */
local: boolean, local: boolean,
/**
* Opens a drawer with participant actions.
*/
openDrawerForParticipant?: Function,
/** /**
* Callback for when the mouse leaves this component. * Callback for when the mouse leaves this component.
*/ */
onLeave?: Function, onLeave?: Function,
/**
* Opens a drawer with participant actions.
*/
openDrawerForParticipant?: Function,
/** /**
* If an overflow drawer can be opened. * If an overflow drawer can be opened.
*/ */
@ -89,18 +94,13 @@ type Props = {
*/ */
videoMediaState?: MediaState, videoMediaState?: MediaState,
/**
* Invoked to obtain translated strings.
*/
t: Function,
/** /**
* The translated "you" text. * The translated "you" text.
*/ */
youText?: string youText?: string
} }
const useStyles = makeStyles(theme => { const useStyles = makeStyles((theme: any) => {
return { return {
nameContainer: { nameContainer: {
display: 'flex', display: 'flex',
@ -150,7 +150,7 @@ function ParticipantItem({
() => openDrawerForParticipant && openDrawerForParticipant({ () => openDrawerForParticipant && openDrawerForParticipant({
participantID, participantID,
displayName displayName
})); }), []);
const styles = useStyles(); const styles = useStyles();

View File

@ -1,12 +1,11 @@
// @flow
import { makeStyles } from '@material-ui/styles'; import { makeStyles } from '@material-ui/styles';
import React from 'react'; import React from 'react';
import { Icon, IconRaisedHandHollow } from '../../../base/icons'; import Icon from '../../../base/icons/components/Icon';
import BaseTheme from '../../../base/ui/components/BaseTheme'; import { IconRaisedHandHollow } from '../../../base/icons/svg/index';
import BaseTheme from '../../../base/ui/components/BaseTheme.web';
const useStyles = makeStyles(theme => { const useStyles = makeStyles((theme: any) => {
return { return {
indicator: { indicator: {
backgroundColor: theme.palette.warning02, backgroundColor: theme.palette.warning02,

View File

@ -1,16 +1,14 @@
// @flow
import { withStyles } from '@material-ui/styles'; import { withStyles } from '@material-ui/styles';
import React from 'react'; import React from 'react';
import { Icon } from '../../base/icons'; import Icon from '../../base/icons/components/Icon';
type Props = { type Props = {
/** /**
* The css classes generated from theme. * The css classes generated from theme.
*/ */
classes: Object, classes: any,
/** /**
* Attribute used in automated testing. * Attribute used in automated testing.
@ -20,7 +18,7 @@ type Props = {
/** /**
* The button's icon. * The button's icon.
*/ */
icon: HTMLElement, icon: Function,
/** /**
* The button's label. * The button's label.
@ -30,17 +28,12 @@ type Props = {
/** /**
* Function to be called when button is clicked. * Function to be called when button is clicked.
*/ */
onButtonClick: Function, onButtonClick: (e?: React.MouseEvent) => void,
/** /**
* Function to be called on key pressed. * Function to be called on key pressed.
*/ */
onKeyPressed: Function, onKeyPressed: (e?: React.KeyboardEvent) => void
/**
* Used for translation.
*/
t: Function
}; };
/** /**
@ -50,7 +43,7 @@ type Props = {
* *
* @returns {Object} * @returns {Object}
*/ */
const styles = theme => { const styles = (theme: any) => {
return { return {
prejoinPreviewDropdownBtn: { prejoinPreviewDropdownBtn: {
alignItems: 'center', alignItems: 'center',

View File

@ -1,14 +1,17 @@
// @flow /* eslint-disable lines-around-comment */
import { makeStyles } from '@material-ui/styles'; import { makeStyles } from '@material-ui/styles';
import React from 'react'; import React from 'react';
import { WithTranslation } from 'react-i18next';
// @ts-ignore
import { Avatar } from '../../../base/avatar'; import { Avatar } from '../../../base/avatar';
import { translate } from '../../../base/i18n'; import { translate } from '../../../base/i18n/functions';
import { Icon, IconClose } from '../../../base/icons'; import Icon from '../../../base/icons/components/Icon';
import { IconClose } from '../../../base/icons/svg/index';
// @ts-ignore
import Label from '../Label'; import Label from '../Label';
type Props = { interface Props extends WithTranslation {
/** /**
* The phone number that is being called. * The phone number that is being called.
@ -28,15 +31,10 @@ type Props = {
/** /**
* The status of the call. * The status of the call.
*/ */
status: string, status: string
}
/** const useStyles = makeStyles((theme: any) => {
* Used for translation.
*/
t: Function,
};
const useStyles = makeStyles(theme => {
return { return {
callingDialog: { callingDialog: {
padding: theme.spacing(3), padding: theme.spacing(3),

View File

@ -1,15 +1,19 @@
// @flow /* eslint-disable lines-around-comment */
import { makeStyles } from '@material-ui/styles'; import { makeStyles } from '@material-ui/styles';
import React from 'react'; import React from 'react';
import { WithTranslation } from 'react-i18next';
import { translate } from '../../../base/i18n'; import { translate } from '../../../base/i18n/functions';
import { Icon, IconArrowLeft } from '../../../base/icons'; import Icon from '../../../base/icons/components/Icon';
import { IconArrowLeft } from '../../../base/icons/svg/index';
// @ts-ignore
import { ActionButton } from '../../../base/premeeting'; import { ActionButton } from '../../../base/premeeting';
// @ts-ignore
import { getCountryCodeFromPhone } from '../../utils'; import { getCountryCodeFromPhone } from '../../utils';
// @ts-ignore
import Label from '../Label'; import Label from '../Label';
type Props = { interface Props extends WithTranslation {
/** /**
* The number to call in order to join the conference. * The number to call in order to join the conference.
@ -21,11 +25,6 @@ type Props = {
*/ */
onBack: Function, onBack: Function,
/**
* Click handler for the text button.
*/
onTextButtonClick: Function,
/** /**
* Click handler for primary button. * Click handler for primary button.
*/ */
@ -34,20 +33,20 @@ type Props = {
/** /**
* Click handler for the small additional text. * Click handler for the small additional text.
*/ */
onSmallTextClick: Function, onSmallTextClick: (e?: React.MouseEvent) => void,
/**
* Click handler for the text button.
*/
onTextButtonClick: (e?: React.MouseEvent) => void,
/** /**
* The passCode of the conference. * The passCode of the conference.
*/ */
passCode: string, passCode: string
}
/** const useStyles = makeStyles((theme: any) => {
* Used for translation.
*/
t: Function,
};
const useStyles = makeStyles(theme => {
return { return {
dialInDialog: { dialInDialog: {
textAlign: 'center', textAlign: 'center',

View File

@ -1,15 +1,19 @@
// @flow /* eslint-disable lines-around-comment */
import { makeStyles } from '@material-ui/styles'; import { makeStyles } from '@material-ui/styles';
import React from 'react'; import React from 'react';
import { WithTranslation } from 'react-i18next';
import { translate } from '../../../base/i18n'; import { translate } from '../../../base/i18n/functions';
import { Icon, IconClose } from '../../../base/icons'; import Icon from '../../../base/icons/components/Icon';
import { IconClose } from '../../../base/icons/svg/index';
// @ts-ignore
import { ActionButton } from '../../../base/premeeting'; import { ActionButton } from '../../../base/premeeting';
// @ts-ignore
import Label from '../Label'; import Label from '../Label';
// @ts-ignore
import CountryPicker from '../country-picker/CountryPicker'; import CountryPicker from '../country-picker/CountryPicker';
type Props = { interface Props extends WithTranslation {
/** /**
* Closes a dialog. * Closes a dialog.
@ -24,15 +28,10 @@ type Props = {
/** /**
* Handler for text button. * Handler for text button.
*/ */
onTextButtonClick: Function, onTextButtonClick: Function
}
/** const useStyles = makeStyles((theme: any) => {
* Used for translation.
*/
t: Function,
};
const useStyles = makeStyles(theme => {
return { return {
dialOutDialog: { dialOutDialog: {
padding: `${theme.spacing(3)}px` padding: `${theme.spacing(3)}px`

View File

@ -1,18 +1,21 @@
// @flow
import { makeStyles } from '@material-ui/styles'; import { makeStyles } from '@material-ui/styles';
import clsx from 'clsx'; import clsx from 'clsx';
import React from 'react'; import React from 'react';
import { WithTranslation } from 'react-i18next';
import { translate } from '../../../base/i18n'; import { IState } from '../../../app/types';
import { Icon, IconCheckSolid, IconExclamationTriangle } from '../../../base/icons'; import { translate } from '../../../base/i18n/functions';
import { connect } from '../../../base/redux'; import Icon from '../../../base/icons/components/Icon';
import { IconCheckSolid, IconExclamationTriangle } from '../../../base/icons/svg';
import { connect } from '../../../base/redux/functions';
import { import {
getDeviceStatusType, getDeviceStatusType,
getDeviceStatusText getDeviceStatusText
// @ts-ignore
} from '../../functions'; } from '../../functions';
export type Props = { export interface Props extends WithTranslation {
/** /**
* The text to be displayed in relation to the status of the audio/video devices. * The text to be displayed in relation to the status of the audio/video devices.
@ -23,15 +26,10 @@ export type Props = {
* The type of status for current devices, controlling the background color of the text. * The type of status for current devices, controlling the background color of the text.
* Can be `ok` or `warning`. * Can be `ok` or `warning`.
*/ */
deviceStatusType: string, deviceStatusType: string
}
/** const useStyles = makeStyles((theme: any) => {
* Used for translation.
*/
t: Function
};
const useStyles = makeStyles(theme => {
return { return {
deviceStatus: { deviceStatus: {
alignItems: 'center', alignItems: 'center',
@ -87,7 +85,7 @@ const iconMap = {
*/ */
function DeviceStatus({ deviceStatusType, deviceStatusText, t }: Props) { function DeviceStatus({ deviceStatusType, deviceStatusText, t }: Props) {
const classes = useStyles(); const classes = useStyles();
const { src, className } = iconMap[deviceStatusType]; const { src, className } = iconMap[deviceStatusType as keyof typeof iconMap];
const hasError = deviceStatusType === 'warning'; const hasError = deviceStatusType === 'warning';
const containerClassName = clsx(classes.deviceStatus, { 'device-status-error': hasError }); const containerClassName = clsx(classes.deviceStatus, { 'device-status-error': hasError });
@ -113,7 +111,7 @@ function DeviceStatus({ deviceStatusType, deviceStatusText, t }: Props) {
* @param {Object} state - The redux state. * @param {Object} state - The redux state.
* @returns {{ deviceStatusText: string, deviceStatusText: string }} * @returns {{ deviceStatusText: string, deviceStatusText: string }}
*/ */
function mapStateToProps(state) { function mapStateToProps(state: IState) {
return { return {
deviceStatusText: getDeviceStatusText(state), deviceStatusText: getDeviceStatusText(state),
deviceStatusType: getDeviceStatusType(state) deviceStatusType: getDeviceStatusType(state)

View File

@ -1,21 +1,26 @@
// @flow /* eslint-disable lines-around-comment */
import { withStyles } from '@material-ui/core'; import { withStyles } from '@material-ui/core';
import React from 'react'; import React from 'react';
// @ts-ignore
import { StartRecordingDialog } from '../..';
// @ts-ignore
import { openDialog } from '../../../../base/dialog'; import { openDialog } from '../../../../base/dialog';
import { translate } from '../../../../base/i18n'; import { translate } from '../../../../base/i18n/functions';
import { IconHighlight } from '../../../../base/icons'; import { IconHighlight } from '../../../../base/icons/svg';
// @ts-ignore
import { Label } from '../../../../base/label'; import { Label } from '../../../../base/label';
import { connect } from '../../../../base/redux'; import { connect } from '../../../../base/redux/functions';
// @ts-ignore
import { Tooltip } from '../../../../base/tooltip'; import { Tooltip } from '../../../../base/tooltip';
import BaseTheme from '../../../../base/ui/components/BaseTheme'; import BaseTheme from '../../../../base/ui/components/BaseTheme.web';
// @ts-ignore
import { maybeShowPremiumFeatureDialog } from '../../../../jaas/actions'; import { maybeShowPremiumFeatureDialog } from '../../../../jaas/actions';
import { FEATURES } from '../../../../jaas/constants'; import { FEATURES } from '../../../../jaas/constants';
import { StartRecordingDialog } from '../../../components';
import AbstractHighlightButton, { import AbstractHighlightButton, {
_abstractMapStateToProps, _abstractMapStateToProps,
type Props as AbstractProps type Props as AbstractProps
// @ts-ignore
} from '../AbstractHighlightButton'; } from '../AbstractHighlightButton';
type Props = AbstractProps & { type Props = AbstractProps & {
@ -35,7 +40,7 @@ type Props = AbstractProps & {
/** /**
* The type of the React {@code Component} state of {@link HighlightButton}. * The type of the React {@code Component} state of {@link HighlightButton}.
*/ */
type State = { type State = {
/** /**
* Whether the notification which prompts for starting recording is open is not. * Whether the notification which prompts for starting recording is open is not.
@ -50,7 +55,7 @@ type Props = AbstractProps & {
* *
* @returns {Object} * @returns {Object}
*/ */
const styles = theme => { const styles = (theme: any) => {
return { return {
container: { container: {
position: 'relative' position: 'relative'
@ -100,6 +105,7 @@ export class HighlightButton extends AbstractHighlightButton<Props, State> {
constructor(props: Props) { constructor(props: Props) {
super(props); super(props);
// @ts-ignore
this.state = { this.state = {
isNotificationOpen: false isNotificationOpen: false
}; };
@ -132,6 +138,7 @@ export class HighlightButton extends AbstractHighlightButton<Props, State> {
* @returns {void} * @returns {void}
*/ */
async _onOpenDialog() { async _onOpenDialog() {
// @ts-ignore
const { dispatch } = this.props; const { dispatch } = this.props;
const dialogShown = await dispatch(maybeShowPremiumFeatureDialog(FEATURES.RECORDING)); const dialogShown = await dispatch(maybeShowPremiumFeatureDialog(FEATURES.RECORDING));
@ -147,12 +154,14 @@ export class HighlightButton extends AbstractHighlightButton<Props, State> {
* @param {Event} e - The click event. * @param {Event} e - The click event.
* @returns {void} * @returns {void}
*/ */
_onClick(e) { _onClick(e: React.MouseEvent) {
e.stopPropagation(); e.stopPropagation();
// @ts-ignore
const { _disabled } = this.props; const { _disabled } = this.props;
if (_disabled) { if (_disabled) {
// @ts-ignore
this.setState({ this.setState({
isNotificationOpen: true isNotificationOpen: true
}); });
@ -167,6 +176,7 @@ export class HighlightButton extends AbstractHighlightButton<Props, State> {
* @returns {void} * @returns {void}
*/ */
_onWindowClickListener() { _onWindowClickListener() {
// @ts-ignore
this.setState({ this.setState({
isNotificationOpen: false isNotificationOpen: false
}); });
@ -184,6 +194,7 @@ export class HighlightButton extends AbstractHighlightButton<Props, State> {
_visible, _visible,
classes, classes,
t t
// @ts-ignore
} = this.props; } = this.props;
@ -206,6 +217,7 @@ export class HighlightButton extends AbstractHighlightButton<Props, State> {
id = 'highlightMeetingLabel' id = 'highlightMeetingLabel'
onClick = { this._onClick } /> onClick = { this._onClick } />
</Tooltip> </Tooltip>
{/* @ts-ignore */}
{this.state.isNotificationOpen && ( {this.state.isNotificationOpen && (
<div className = { classes.highlightNotification }> <div className = { classes.highlightNotification }>
{t('recording.highlightMomentDisabled')} {t('recording.highlightMomentDisabled')}
@ -221,4 +233,5 @@ export class HighlightButton extends AbstractHighlightButton<Props, State> {
} }
} }
// @ts-ignore
export default withStyles(styles)(translate(connect(_abstractMapStateToProps)(HighlightButton))); export default withStyles(styles)(translate(connect(_abstractMapStateToProps)(HighlightButton)));

View File

@ -1,14 +1,15 @@
// @flow /* eslint-disable lines-around-comment */
import { withStyles } from '@material-ui/core/styles'; import { withStyles } from '@material-ui/core/styles';
import React from 'react'; import React from 'react';
import { translate } from '../../../base/i18n'; import { translate } from '../../../base/i18n/functions';
// @ts-ignore
import { Label } from '../../../base/label'; import { Label } from '../../../base/label';
import { JitsiRecordingConstants } from '../../../base/lib-jitsi-meet'; import { JitsiRecordingConstants } from '../../../base/lib-jitsi-meet';
import { connect } from '../../../base/redux'; import { connect } from '../../../base/redux/functions';
import AbstractRecordingLabel, { import AbstractRecordingLabel, {
_mapStateToProps _mapStateToProps
// @ts-ignore
} from '../AbstractRecordingLabel'; } from '../AbstractRecordingLabel';
/** /**
@ -18,7 +19,7 @@ import AbstractRecordingLabel, {
* *
* @returns {Object} * @returns {Object}
*/ */
const styles = theme => { const styles = (theme: any) => {
return { return {
[JitsiRecordingConstants.mode.STREAM]: { [JitsiRecordingConstants.mode.STREAM]: {
background: theme.palette.ui03 background: theme.palette.ui03
@ -42,24 +43,26 @@ class RecordingLabel extends AbstractRecordingLabel {
* @inheritdoc * @inheritdoc
*/ */
_renderLabel() { _renderLabel() {
// @ts-ignore
if (this.props._status !== JitsiRecordingConstants.status.ON) { if (this.props._status !== JitsiRecordingConstants.status.ON) {
// Since there are no expanded labels on web, we only render this // Since there are no expanded labels on web, we only render this
// label when the recording status is ON. // label when the recording status is ON.
return null; return null;
} }
// @ts-ignore
const { classes, mode, t } = this.props; const { classes, mode, t } = this.props;
return ( return (
<div> <div>
<Label <Label
className = { classes && classes[mode] } className = { classes && classes[mode] }
// @ts-ignore
text = { t(this._getLabelKey()) } /> text = { t(this._getLabelKey()) } />
</div> </div>
); );
} }
_getLabelKey: () => ?string;
} }
// @ts-ignore
export default withStyles(styles)(translate(connect(_mapStateToProps)(RecordingLabel))); export default withStyles(styles)(translate(connect(_mapStateToProps)(RecordingLabel)));

View File

@ -1,8 +1,8 @@
// @flow
import { makeStyles } from '@material-ui/core'; import { makeStyles } from '@material-ui/core';
import React from 'react'; import React from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
// @ts-ignore
import { RECORD_TYPE } from '../../constants'; import { RECORD_TYPE } from '../../constants';
/** /**
@ -13,25 +13,25 @@ type Props = {
/** /**
* The id of the record. * The id of the record.
*/ */
id: String, id: string,
/** /**
* The name of the record. * The name of the record.
*/ */
name: String, name: string,
/**
* The type of the record.
*/
type: String,
/** /**
* The handler for the click event. * The handler for the click event.
*/ */
onClick: Function onClick: (e?: React.MouseEvent) => void,
/**
* The type of the record.
*/
type: string
} }
const useStyles = makeStyles(theme => { const useStyles = makeStyles((theme: any) => {
return { return {
recordItem: { recordItem: {
display: 'flex', display: 'flex',

View File

@ -1,21 +1,26 @@
// @flow /* eslint-disable lines-around-comment */
import Spinner from '@atlaskit/spinner'; import Spinner from '@atlaskit/spinner';
import { makeStyles } from '@material-ui/core'; import { makeStyles } from '@material-ui/core';
import React, { useCallback } from 'react'; import React, { useCallback } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useDispatch } from 'react-redux'; import { useDispatch } from 'react-redux';
// @ts-ignore
import { Dialog, hideDialog } from '../../../base/dialog'; import { Dialog, hideDialog } from '../../../base/dialog';
import { Icon, IconSearch } from '../../../base/icons'; import Icon from '../../../base/icons/components/Icon';
import { IconSearch } from '../../../base/icons/svg/index';
// @ts-ignore
import { getFieldValue } from '../../../base/react'; import { getFieldValue } from '../../../base/react';
import BaseTheme from '../../../base/ui/components/BaseTheme'; import BaseTheme from '../../../base/ui/components/BaseTheme.web';
// @ts-ignore
import { NOTES_MAX_LENGTH } from '../../constants'; import { NOTES_MAX_LENGTH } from '../../constants';
// @ts-ignore
import { useSalesforceLinkDialog } from '../../useSalesforceLinkDialog'; import { useSalesforceLinkDialog } from '../../useSalesforceLinkDialog';
import { RecordItem } from './RecordItem'; import { RecordItem } from './RecordItem';
const useStyles = makeStyles(theme => { // @ts-ignore
const useStyles = makeStyles((theme: any) => {
return { return {
container: { container: {
minHeight: '450px', minHeight: '450px',
@ -136,7 +141,7 @@ function SalesforceLinkDialog() {
showSearchResults showSearchResults
} = useSalesforceLinkDialog(); } = useSalesforceLinkDialog();
const handleChange = useCallback((event: Event) => { const handleChange = useCallback((event: React.ChangeEvent<HTMLInputElement>) => {
const value = getFieldValue(event); const value = getFieldValue(event);
setSearchTerm(value); setSearchTerm(value);
@ -150,6 +155,7 @@ function SalesforceLinkDialog() {
const renderSpinner = () => ( const renderSpinner = () => (
<div className = { classes.spinner }> <div className = { classes.spinner }>
<Spinner <Spinner
// @ts-ignore
isCompleting = { false } isCompleting = { false }
size = 'medium' /> size = 'medium' />
</div> </div>
@ -176,7 +182,7 @@ function SalesforceLinkDialog() {
/* eslint-disable-next-line react/jsx-no-bind */ /* eslint-disable-next-line react/jsx-no-bind */
onChange = { e => setNotes(e.target.value) } onChange = { e => setNotes(e.target.value) }
placeholder = { t('dialog.addMeetingNote') } placeholder = { t('dialog.addMeetingNote') }
row = '4' rows = { 4 }
value = { notes } /> value = { notes } />
</div> </div>
); );
@ -236,7 +242,7 @@ function SalesforceLinkDialog() {
return ( return (
<ul className = { classes.recordList }> <ul className = { classes.recordList }>
{records.map(item => ( {records.map((item: any) => (
<RecordItem <RecordItem
key = { `record-${item.id}` } key = { `record-${item.id}` }
/* eslint-disable-next-line react/jsx-no-bind */ /* eslint-disable-next-line react/jsx-no-bind */

View File

@ -1,38 +1,46 @@
// @flow /* eslint-disable lines-around-comment */
import { withStyles } from '@material-ui/styles'; import { withStyles } from '@material-ui/styles';
import React, { Component } from 'react'; import React, { Component } from 'react';
import { IState } from '../../../app/types';
// @ts-ignore
import { getAvailableDevices } from '../../../base/devices'; import { getAvailableDevices } from '../../../base/devices';
// @ts-ignore
import { DialogWithTabs, hideDialog } from '../../../base/dialog'; import { DialogWithTabs, hideDialog } from '../../../base/dialog';
import { connect } from '../../../base/redux'; import { connect } from '../../../base/redux/functions';
// @ts-ignore
import { isCalendarEnabled } from '../../../calendar-sync'; import { isCalendarEnabled } from '../../../calendar-sync';
import { import {
DeviceSelection, DeviceSelection,
getDeviceSelectionDialogProps, getDeviceSelectionDialogProps,
submitDeviceSelectionTab submitDeviceSelectionTab
// @ts-ignore
} from '../../../device-selection'; } from '../../../device-selection';
import { import {
submitModeratorTab, submitModeratorTab,
submitMoreTab, submitMoreTab,
submitProfileTab, submitProfileTab,
submitSoundsTab submitSoundsTab
// @ts-ignore
} from '../../actions'; } from '../../actions';
// @ts-ignore
import { SETTINGS_TABS } from '../../constants'; import { SETTINGS_TABS } from '../../constants';
import { import {
getModeratorTabProps, getModeratorTabProps,
getMoreTabProps, getMoreTabProps,
getProfileTabProps, getProfileTabProps,
getSoundsTabProps getSoundsTabProps
// @ts-ignore
} from '../../functions'; } from '../../functions';
// @ts-ignore
import CalendarTab from './CalendarTab'; import CalendarTab from './CalendarTab';
import ModeratorTab from './ModeratorTab'; import ModeratorTab from './ModeratorTab';
import MoreTab from './MoreTab'; import MoreTab from './MoreTab';
import ProfileTab from './ProfileTab'; import ProfileTab from './ProfileTab';
import SoundsTab from './SoundsTab'; import SoundsTab from './SoundsTab';
declare var interfaceConfig: Object; declare let interfaceConfig: any;
/** /**
* The type of the React {@code Component} props of * The type of the React {@code Component} props of
@ -40,6 +48,15 @@ declare var interfaceConfig: Object;
*/ */
type Props = { type Props = {
/**
* Information about the tabs to be rendered.
*/
_tabs: Array<{
name: string;
onMount: () => void;
submit: () => void;
}>,
/** /**
* An object containing the CSS classes. * An object containing the CSS classes.
*/ */
@ -51,11 +68,6 @@ type Props = {
*/ */
defaultTab: string, defaultTab: string,
/**
* Information about the tabs to be rendered.
*/
_tabs: Array<Object>,
/** /**
* Invoked to save changed settings. * Invoked to save changed settings.
*/ */
@ -75,7 +87,7 @@ type Props = {
* *
* @returns {Object} * @returns {Object}
*/ */
const styles = theme => { const styles = (theme: any) => {
return { return {
settingsDialog: { settingsDialog: {
display: 'flex', display: 'flex',
@ -110,6 +122,7 @@ const styles = theme => {
color: '#9FB0CC' color: '#9FB0CC'
}, },
// @ts-ignore
[[ '& .calendar-tab', [[ '& .calendar-tab',
'& .more-tab', '& .more-tab',
'& .box' ]]: { '& .box' ]]: {
@ -225,9 +238,11 @@ class SettingsDialog extends Component<Props> {
return { return {
...tab, ...tab,
onMount: tab.onMount onMount: tab.onMount
? (...args) => dispatch(tab.onMount(...args)) // @ts-ignore
? (...args: any) => dispatch(tab.onMount(...args))
: undefined, : undefined,
submit: (...args) => tab.submit submit: (...args: any) => tab.submit
// @ts-ignore
&& dispatch(tab.submit(...args)) && dispatch(tab.submit(...args))
}; };
}); });
@ -245,8 +260,6 @@ class SettingsDialog extends Component<Props> {
); );
} }
_closeDialog: () => void;
/** /**
* Callback invoked to close the dialog without saving changes. * Callback invoked to close the dialog without saving changes.
* *
@ -269,7 +282,7 @@ class SettingsDialog extends Component<Props> {
* tabs: Array<Object> * tabs: Array<Object>
* }} * }}
*/ */
function _mapStateToProps(state, ownProps) { function _mapStateToProps(state: IState, ownProps: any) {
const { classes, isDisplayedOnWelcomePage } = ownProps; const { classes, isDisplayedOnWelcomePage } = ownProps;
const configuredTabs = interfaceConfig.SETTINGS_SECTIONS || []; const configuredTabs = interfaceConfig.SETTINGS_SECTIONS || [];
@ -293,7 +306,7 @@ function _mapStateToProps(state, ownProps) {
label: 'settings.devices', label: 'settings.devices',
onMount: getAvailableDevices, onMount: getAvailableDevices,
props: getDeviceSelectionDialogProps(state, isDisplayedOnWelcomePage), props: getDeviceSelectionDialogProps(state, isDisplayedOnWelcomePage),
propsUpdateFunction: (tabState, newProps) => { propsUpdateFunction: (tabState: any, newProps: any) => {
// Ensure the device selection tab gets updated when new devices // Ensure the device selection tab gets updated when new devices
// are found by taking the new props and only preserving the // are found by taking the new props and only preserving the
// current user selected devices. If this were not done, the // current user selected devices. If this were not done, the
@ -308,7 +321,7 @@ function _mapStateToProps(state, ownProps) {
}; };
}, },
styles: `settings-pane ${classes.settingsDialog} devices-pane`, styles: `settings-pane ${classes.settingsDialog} devices-pane`,
submit: newState => submitDeviceSelectionTab(newState, isDisplayedOnWelcomePage) submit: (newState: any) => submitDeviceSelectionTab(newState, isDisplayedOnWelcomePage)
}); });
} }
@ -329,7 +342,7 @@ function _mapStateToProps(state, ownProps) {
component: ModeratorTab, component: ModeratorTab,
label: 'settings.moderator', label: 'settings.moderator',
props: moderatorTabProps, props: moderatorTabProps,
propsUpdateFunction: (tabState, newProps) => { propsUpdateFunction: (tabState: any, newProps: any) => {
// Updates tab props, keeping users selection // Updates tab props, keeping users selection
return { return {
@ -371,7 +384,7 @@ function _mapStateToProps(state, ownProps) {
component: MoreTab, component: MoreTab,
label: 'settings.more', label: 'settings.more',
props: moreTabProps, props: moreTabProps,
propsUpdateFunction: (tabState, newProps) => { propsUpdateFunction: (tabState: any, newProps: any) => {
// Updates tab props, keeping users selection // Updates tab props, keeping users selection
return { return {

View File

@ -1,24 +1,30 @@
// @flow /* eslint-disable lines-around-comment */
import { makeStyles } from '@material-ui/core/styles'; import { makeStyles } from '@material-ui/core/styles';
import React, { useCallback, useEffect } from 'react'; import React, { useCallback, useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux'; import { useSelector, useDispatch } from 'react-redux';
import { IState } from '../../../app/types';
// @ts-ignore
import { Dialog } from '../../../base/dialog'; import { Dialog } from '../../../base/dialog';
import { escapeRegexp } from '../../../base/util'; import { escapeRegexp } from '../../../base/util/helpers';
// @ts-ignore
import { resetSearchCriteria, toggleFaceExpressions, initSearch } from '../../actions'; import { resetSearchCriteria, toggleFaceExpressions, initSearch } from '../../actions';
import { import {
DISPLAY_SWITCH_BREAKPOINT, DISPLAY_SWITCH_BREAKPOINT,
MOBILE_BREAKPOINT, MOBILE_BREAKPOINT,
RESIZE_SEARCH_SWITCH_CONTAINER_BREAKPOINT RESIZE_SEARCH_SWITCH_CONTAINER_BREAKPOINT
// @ts-ignore
} from '../../constants'; } from '../../constants';
import FaceExpressionsSwitch from './FaceExpressionsSwitch'; import FaceExpressionsSwitch from './FaceExpressionsSwitch';
// @ts-ignore
import SpeakerStatsLabels from './SpeakerStatsLabels'; import SpeakerStatsLabels from './SpeakerStatsLabels';
// @ts-ignore
import SpeakerStatsList from './SpeakerStatsList'; import SpeakerStatsList from './SpeakerStatsList';
// @ts-ignore
import SpeakerStatsSearch from './SpeakerStatsSearch'; import SpeakerStatsSearch from './SpeakerStatsSearch';
const useStyles = makeStyles(theme => { const useStyles = makeStyles((theme: any) => {
return { return {
speakerStats: { speakerStats: {
'& .row': { '& .row': {
@ -88,9 +94,9 @@ const useStyles = makeStyles(theme => {
}); });
const SpeakerStats = () => { const SpeakerStats = () => {
const { faceLandmarks } = useSelector(state => state['features/base/config']); const { faceLandmarks } = useSelector((state: IState) => state['features/base/config']);
const { showFaceExpressions } = useSelector(state => state['features/speaker-stats']); const { showFaceExpressions } = useSelector((state: any) => state['features/speaker-stats']);
const { clientWidth } = useSelector(state => state['features/base/responsive-ui']); const { clientWidth } = useSelector((state: IState) => state['features/base/responsive-ui']);
const displaySwitch = faceLandmarks?.enableDisplayFaceExpressions && clientWidth > DISPLAY_SWITCH_BREAKPOINT; const displaySwitch = faceLandmarks?.enableDisplayFaceExpressions && clientWidth > DISPLAY_SWITCH_BREAKPOINT;
const displayLabels = clientWidth > MOBILE_BREAKPOINT; const displayLabels = clientWidth > MOBILE_BREAKPOINT;
const dispatch = useDispatch(); const dispatch = useDispatch();

View File

@ -1,12 +1,12 @@
/* @flow */
import { makeStyles } from '@material-ui/core/styles'; import { makeStyles } from '@material-ui/core/styles';
import React from 'react'; import React from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
// @ts-ignore
import { Tooltip } from '../../../base/tooltip'; import { Tooltip } from '../../../base/tooltip';
import { FACE_EXPRESSIONS_EMOJIS } from '../../../face-landmarks/constants'; import { FACE_EXPRESSIONS_EMOJIS } from '../../../face-landmarks/constants';
const useStyles = makeStyles(theme => { const useStyles = makeStyles((theme: any) => {
return { return {
labels: { labels: {
padding: '22px 0 7px 0', padding: '22px 0 7px 0',
@ -34,22 +34,6 @@ type Props = {
const SpeakerStatsLabels = (props: Props) => { const SpeakerStatsLabels = (props: Props) => {
const { t } = useTranslation(); const { t } = useTranslation();
const classes = useStyles(); const classes = useStyles();
const FaceExpressionsLabels = () => Object.keys(FACE_EXPRESSIONS_EMOJIS).map(
expression => (
<div
className = 'expression'
key = { expression }>
<Tooltip
content = { t(`speakerStats.${expression}`) }
position = { 'top' } >
<div>
{ FACE_EXPRESSIONS_EMOJIS[expression] }
</div>
</Tooltip>
</div>
)
);
const nameTimeClass = `name-time${ const nameTimeClass = `name-time${
props.showFaceExpressions ? ' name-time_expressions-on' : '' props.showFaceExpressions ? ' name-time_expressions-on' : ''
}`; }`;
@ -69,7 +53,22 @@ const SpeakerStatsLabels = (props: Props) => {
{ {
props.showFaceExpressions props.showFaceExpressions
&& <div className = { `expressions ${classes.emojis}` }> && <div className = { `expressions ${classes.emojis}` }>
<FaceExpressionsLabels /> {Object.keys(FACE_EXPRESSIONS_EMOJIS).map(
expression => (
<div
className = 'expression'
key = { expression }>
<Tooltip
content = { t(`speakerStats.${expression}`) }
position = { 'top' } >
<div>
{FACE_EXPRESSIONS_EMOJIS[expression as keyof typeof FACE_EXPRESSIONS_EMOJIS]}
</div>
</Tooltip>
</div>
)
)}
</div> </div>
} }
</div> </div>

View File

@ -1,14 +1,16 @@
// @flow /* eslint-disable lines-around-comment */
import { makeStyles } from '@material-ui/core/styles'; import { makeStyles } from '@material-ui/core/styles';
import React from 'react'; import React from 'react';
// @ts-ignore
import { MOBILE_BREAKPOINT } from '../../constants'; import { MOBILE_BREAKPOINT } from '../../constants';
// @ts-ignore
import abstractSpeakerStatsList from '../AbstractSpeakerStatsList'; import abstractSpeakerStatsList from '../AbstractSpeakerStatsList';
// @ts-ignore
import SpeakerStatsItem from './SpeakerStatsItem'; import SpeakerStatsItem from './SpeakerStatsItem';
const useStyles = makeStyles(theme => { const useStyles = makeStyles((theme: any) => {
return { return {
list: { list: {
marginTop: `${theme.spacing(3)}px`, marginTop: `${theme.spacing(3)}px`,

View File

@ -1,17 +1,20 @@
/* @flow */ /* eslint-disable lines-around-comment */
import { makeStyles } from '@material-ui/core/styles'; import { makeStyles } from '@material-ui/core/styles';
import React, { useCallback, useState } from 'react'; import React, { useCallback, useState } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
import { IconSearch, Icon } from '../../../base/icons'; import Icon from '../../../base/icons/components/Icon';
import { IconSearch } from '../../../base/icons/svg/index';
// @ts-ignore
import { getFieldValue } from '../../../base/react'; import { getFieldValue } from '../../../base/react';
import BaseTheme from '../../../base/ui/components/BaseTheme'; import BaseTheme from '../../../base/ui/components/BaseTheme.web';
// @ts-ignore
import { MOBILE_BREAKPOINT } from '../../constants'; import { MOBILE_BREAKPOINT } from '../../constants';
// @ts-ignore
import { isSpeakerStatsSearchDisabled } from '../../functions'; import { isSpeakerStatsSearchDisabled } from '../../functions';
const useStyles = makeStyles(theme => { const useStyles = makeStyles((theme: any) => {
return { return {
speakerStatsSearchContainer: { speakerStatsSearchContainer: {
position: 'relative' position: 'relative'
@ -83,13 +86,13 @@ function SpeakerStatsSearch({ onSearch }: Props) {
* @param {Object} evt - The static event. * @param {Object} evt - The static event.
* @returns {void} * @returns {void}
*/ */
const onChange = useCallback((evt: Event) => { const onChange = useCallback((evt: React.ChangeEvent<HTMLInputElement>) => {
const value = getFieldValue(evt); const value = getFieldValue(evt);
setSearchValue(value); setSearchValue(value);
onSearch && onSearch(value); onSearch && onSearch(value);
}, []); }, []);
const preventDismiss = useCallback((evt: KeyboardEvent) => { const preventDismiss = useCallback((evt: React.KeyboardEvent) => {
if (evt.key === 'Enter') { if (evt.key === 'Enter') {
evt.preventDefault(); evt.preventDefault();
} }
@ -103,7 +106,7 @@ function SpeakerStatsSearch({ onSearch }: Props) {
<div className = { classes.speakerStatsSearchContainer }> <div className = { classes.speakerStatsSearchContainer }>
<Icon <Icon
className = { classes.searchIcon } className = { classes.searchIcon }
color = { BaseTheme.palette.surface07 } color = { BaseTheme.palette.icon03 }
src = { IconSearch } /> src = { IconSearch } />
<input <input
autoComplete = 'off' autoComplete = 'off'

View File

@ -1,22 +1,20 @@
// @flow
import { makeStyles } from '@material-ui/core'; import { makeStyles } from '@material-ui/core';
import React, { useCallback } from 'react'; import React, { ReactElement, useCallback } from 'react';
import { DRAWER_MAX_HEIGHT } from '../../constants'; import { DRAWER_MAX_HEIGHT } from '../../constants';
type Props = { type Props = {
/**
* Class name for custom styles.
*/
className: string,
/** /**
* The component(s) to be displayed within the drawer menu. * The component(s) to be displayed within the drawer menu.
*/ */
children: React$Node, children: ReactElement,
/**
* Class name for custom styles.
*/
className?: string,
/** /**
* Whether the drawer should be shown or not. * Whether the drawer should be shown or not.
@ -29,7 +27,7 @@ type Props = {
onClose: Function onClose: Function
}; };
const useStyles = makeStyles(theme => { const useStyles = makeStyles((theme: any) => {
return { return {
drawer: { drawer: {
backgroundColor: theme.palette.ui02, backgroundColor: theme.palette.ui02,

View File

@ -1,25 +1,30 @@
/* @flow */ /* eslint-disable lines-around-comment */
import InlineDialog from '@atlaskit/inline-dialog'; import InlineDialog from '@atlaskit/inline-dialog';
import { withStyles } from '@material-ui/styles'; import { withStyles } from '@material-ui/styles';
import React, { Component } from 'react'; import React, { Component, ReactElement } from 'react';
import { WithTranslation } from 'react-i18next';
// @ts-ignore
import { createToolbarEvent, sendAnalytics } from '../../../analytics'; import { createToolbarEvent, sendAnalytics } from '../../../analytics';
import { translate } from '../../../base/i18n'; import { translate } from '../../../base/i18n/functions';
import { connect } from '../../../base/redux'; import { connect } from '../../../base/redux/functions';
// @ts-ignore
import { ReactionEmoji, ReactionsMenu } from '../../../reactions/components'; import { ReactionEmoji, ReactionsMenu } from '../../../reactions/components';
import { type ReactionEmojiProps, REACTIONS_MENU_HEIGHT } from '../../../reactions/constants'; import { type ReactionEmojiProps, REACTIONS_MENU_HEIGHT } from '../../../reactions/constants';
import { getReactionsQueue } from '../../../reactions/functions.any'; import { getReactionsQueue } from '../../../reactions/functions.any';
import { DRAWER_MAX_HEIGHT } from '../../constants'; import { DRAWER_MAX_HEIGHT } from '../../constants';
// @ts-ignore
import Drawer from './Drawer'; import Drawer from './Drawer';
// @ts-ignore
import JitsiPortal from './JitsiPortal'; import JitsiPortal from './JitsiPortal';
// @ts-ignore
import OverflowToggleButton from './OverflowToggleButton'; import OverflowToggleButton from './OverflowToggleButton';
/** /**
* The type of the React {@code Component} props of {@link OverflowMenuButton}. * The type of the React {@code Component} props of {@link OverflowMenuButton}.
*/ */
type Props = { interface Props extends WithTranslation {
/** /**
* ID of the menu that is controlled by this button. * ID of the menu that is controlled by this button.
@ -29,12 +34,12 @@ type Props = {
/** /**
* A child React Element to display within {@code InlineDialog}. * A child React Element to display within {@code InlineDialog}.
*/ */
children: React$Node, children: ReactElement,
/** /**
* An object containing the CSS classes. * An object containing the CSS classes.
*/ */
classes: Object, classes: any,
/** /**
* Whether or not the OverflowMenu popover should display. * Whether or not the OverflowMenu popover should display.
@ -51,11 +56,6 @@ type Props = {
*/ */
overflowDrawer: boolean, overflowDrawer: boolean,
/**
* Invoked to obtain translated strings.
*/
t: Function,
/** /**
* The array of reactions to be displayed. * The array of reactions to be displayed.
*/ */
@ -65,7 +65,7 @@ type Props = {
* Whether or not to display the reactions in the mobile menu. * Whether or not to display the reactions in the mobile menu.
*/ */
showMobileReactions: boolean showMobileReactions: boolean
}; }
const styles = () => { const styles = () => {
return { return {
@ -98,15 +98,13 @@ class OverflowMenuButton extends Component<Props> {
this._onEscClick = this._onEscClick.bind(this); this._onEscClick = this._onEscClick.bind(this);
} }
_onEscClick: (KeyboardEvent) => void;
/** /**
* Click handler for the more actions entries. * Click handler for the more actions entries.
* *
* @param {KeyboardEvent} event - Esc key click to close the popup. * @param {KeyboardEvent} event - Esc key click to close the popup.
* @returns {void} * @returns {void}
*/ */
_onEscClick(event) { _onEscClick(event: React.KeyboardEvent) {
if (event.key === 'Escape' && this.props.isOpen) { if (event.key === 'Escape' && this.props.isOpen) {
event.preventDefault(); event.preventDefault();
event.stopPropagation(); event.stopPropagation();
@ -136,10 +134,12 @@ class OverflowMenuButton extends Component<Props> {
<Drawer <Drawer
isOpen = { isOpen } isOpen = { isOpen }
onClose = { this._onCloseDialog }> onClose = { this._onCloseDialog }>
<>
<div className = { classes.overflowMenuDrawer }> <div className = { classes.overflowMenuDrawer }>
{children} {children}
</div> </div>
{showMobileReactions && <ReactionsMenu overflowMenu = { true } />} {showMobileReactions && <ReactionsMenu overflowMenu = { true } />}
</>
</Drawer> </Drawer>
{showMobileReactions && <div className = 'reactions-animations-container'> {showMobileReactions && <div className = 'reactions-animations-container'>
{reactionsQueue.map(({ reaction, uid }, index) => (<ReactionEmoji {reactionsQueue.map(({ reaction, uid }, index) => (<ReactionEmoji
@ -167,8 +167,6 @@ class OverflowMenuButton extends Component<Props> {
); );
} }
_onCloseDialog: () => void;
/** /**
* Callback invoked when {@code InlineDialog} signals that it should be * Callback invoked when {@code InlineDialog} signals that it should be
* close. * close.
@ -180,8 +178,6 @@ class OverflowMenuButton extends Component<Props> {
this.props.onVisibilityChange(false); this.props.onVisibilityChange(false);
} }
_toggleDialogVisibility: () => void;
/** /**
* Callback invoked to signal that an event has occurred that should change * Callback invoked to signal that an event has occurred that should change
* the visibility of the {@code InlineDialog} component. * the visibility of the {@code InlineDialog} component.
@ -203,7 +199,7 @@ class OverflowMenuButton extends Component<Props> {
* @param {Object} state - The Redux state. * @param {Object} state - The Redux state.
* @returns {Props} * @returns {Props}
*/ */
function mapStateToProps(state) { function mapStateToProps(state: any) {
const { overflowDrawer } = state['features/toolbox']; const { overflowDrawer } = state['features/toolbox'];
return { return {
@ -212,4 +208,5 @@ function mapStateToProps(state) {
}; };
} }
// @ts-ignore
export default withStyles(styles)(translate(connect(mapStateToProps)(OverflowMenuButton))); export default withStyles(styles)(translate(connect(mapStateToProps)(OverflowMenuButton)));

View File

@ -1,76 +1,109 @@
// @flow /* eslint-disable lines-around-comment */
import { withStyles } from '@material-ui/core/styles'; import { withStyles } from '@material-ui/core/styles';
import React, { Component } from 'react'; import React, { Component } from 'react';
import { WithTranslation } from 'react-i18next';
import { batch } from 'react-redux'; import { batch } from 'react-redux';
// @ts-ignore
import keyboardShortcut from '../../../../../modules/keyboardshortcut/keyboardshortcut'; import keyboardShortcut from '../../../../../modules/keyboardshortcut/keyboardshortcut';
import { import {
ACTION_SHORTCUT_TRIGGERED, ACTION_SHORTCUT_TRIGGERED,
createShortcutEvent, createShortcutEvent,
createToolbarEvent, createToolbarEvent,
sendAnalytics sendAnalytics
// @ts-ignore
} from '../../../analytics'; } from '../../../analytics';
// @ts-ignore
import { ContextMenu, ContextMenuItemGroup } from '../../../base/components'; import { ContextMenu, ContextMenuItemGroup } from '../../../base/components';
// @ts-ignore
import { getMultipleVideoSendingSupportFeatureFlag, getToolbarButtons } from '../../../base/config'; import { getMultipleVideoSendingSupportFeatureFlag, getToolbarButtons } from '../../../base/config';
// @ts-ignore
import { isToolbarButtonEnabled } from '../../../base/config/functions.web'; import { isToolbarButtonEnabled } from '../../../base/config/functions.web';
// @ts-ignore
import { openDialog, toggleDialog } from '../../../base/dialog'; import { openDialog, toggleDialog } from '../../../base/dialog';
import { isIosMobileBrowser, isMobileBrowser } from '../../../base/environment/utils'; import { isIosMobileBrowser, isMobileBrowser } from '../../../base/environment/utils';
import { translate } from '../../../base/i18n'; import { translate } from '../../../base/i18n/functions';
import JitsiMeetJS from '../../../base/lib-jitsi-meet'; import JitsiMeetJS from '../../../base/lib-jitsi-meet';
import { import {
getLocalParticipant,
hasRaisedHand,
raiseHand raiseHand
} from '../../../base/participants'; } from '../../../base/participants/actions';
import { connect } from '../../../base/redux'; import {
getLocalParticipant,
hasRaisedHand
} from '../../../base/participants/functions';
import { connect } from '../../../base/redux/functions';
// @ts-ignore
import { getLocalVideoTrack } from '../../../base/tracks'; import { getLocalVideoTrack } from '../../../base/tracks';
// @ts-ignore
import { toggleChat } from '../../../chat'; import { toggleChat } from '../../../chat';
// @ts-ignore
import { ChatButton } from '../../../chat/components'; import { ChatButton } from '../../../chat/components';
// @ts-ignore
import { EmbedMeetingButton } from '../../../embed-meeting'; import { EmbedMeetingButton } from '../../../embed-meeting';
// @ts-ignore
import { SharedDocumentButton } from '../../../etherpad'; import { SharedDocumentButton } from '../../../etherpad';
// @ts-ignore
import { FeedbackButton } from '../../../feedback'; import { FeedbackButton } from '../../../feedback';
// @ts-ignore
import { setGifMenuVisibility } from '../../../gifs/actions'; import { setGifMenuVisibility } from '../../../gifs/actions';
// @ts-ignore
import { isGifEnabled } from '../../../gifs/functions'; import { isGifEnabled } from '../../../gifs/functions';
// @ts-ignore
import { InviteButton } from '../../../invite/components/add-people-dialog'; import { InviteButton } from '../../../invite/components/add-people-dialog';
// @ts-ignore
import { isVpaasMeeting } from '../../../jaas/functions'; import { isVpaasMeeting } from '../../../jaas/functions';
// @ts-ignore
import { KeyboardShortcutsButton } from '../../../keyboard-shortcuts'; import { KeyboardShortcutsButton } from '../../../keyboard-shortcuts';
import { NoiseSuppressionButton } from '../../../noise-suppression/components'; import { NoiseSuppressionButton } from '../../../noise-suppression/components';
import { import {
close as closeParticipantsPane, close as closeParticipantsPane,
open as openParticipantsPane open as openParticipantsPane
// @ts-ignore
} from '../../../participants-pane/actions'; } from '../../../participants-pane/actions';
// @ts-ignore
import { ParticipantsPaneButton } from '../../../participants-pane/components/web'; import { ParticipantsPaneButton } from '../../../participants-pane/components/web';
// @ts-ignore
import { getParticipantsPaneOpen } from '../../../participants-pane/functions'; import { getParticipantsPaneOpen } from '../../../participants-pane/functions';
import { addReactionToBuffer } from '../../../reactions/actions.any'; import { addReactionToBuffer } from '../../../reactions/actions.any';
import { toggleReactionsMenuVisibility } from '../../../reactions/actions.web'; import { toggleReactionsMenuVisibility } from '../../../reactions/actions.web';
import { ReactionsMenuButton } from '../../../reactions/components'; import ReactionsMenuButton from '../../../reactions/components/web/ReactionsMenuButton';
import { REACTIONS } from '../../../reactions/constants'; import { REACTIONS } from '../../../reactions/constants';
import { isReactionsEnabled } from '../../../reactions/functions.any'; import { isReactionsEnabled } from '../../../reactions/functions.any';
import { import {
LiveStreamButton, LiveStreamButton,
RecordButton RecordButton
// @ts-ignore
} from '../../../recording'; } from '../../../recording';
// @ts-ignore
import { isSalesforceEnabled } from '../../../salesforce/functions'; import { isSalesforceEnabled } from '../../../salesforce/functions';
import { import {
isScreenAudioSupported, isScreenAudioSupported,
isScreenVideoShared, isScreenVideoShared,
ShareAudioButton, ShareAudioButton,
startScreenShareFlow startScreenShareFlow
} from '../../../screen-share/'; // @ts-ignore
} from '../../../screen-share';
// @ts-ignore
import SecurityDialogButton from '../../../security/components/security-dialog/web/SecurityDialogButton'; import SecurityDialogButton from '../../../security/components/security-dialog/web/SecurityDialogButton';
// @ts-ignore
import { SettingsButton } from '../../../settings'; import { SettingsButton } from '../../../settings';
// @ts-ignore
import { SharedVideoButton } from '../../../shared-video/components'; import { SharedVideoButton } from '../../../shared-video/components';
// @ts-ignore
import { SpeakerStatsButton } from '../../../speaker-stats/components/web'; import { SpeakerStatsButton } from '../../../speaker-stats/components/web';
import { import {
ClosedCaptionButton ClosedCaptionButton
// @ts-ignore
} from '../../../subtitles'; } from '../../../subtitles';
import { import {
TileViewButton, TileViewButton,
shouldDisplayTileView, shouldDisplayTileView,
toggleTileView toggleTileView
// @ts-ignore
} from '../../../video-layout'; } from '../../../video-layout';
// @ts-ignore
import { VideoQualityDialog, VideoQualityButton } from '../../../video-quality/components'; import { VideoQualityDialog, VideoQualityButton } from '../../../video-quality/components';
// @ts-ignore
import { VideoBackgroundButton, toggleBackgroundEffect } from '../../../virtual-background'; import { VideoBackgroundButton, toggleBackgroundEffect } from '../../../virtual-background';
import { VIRTUAL_BACKGROUND_TYPE } from '../../../virtual-background/constants'; import { VIRTUAL_BACKGROUND_TYPE } from '../../../virtual-background/constants';
import { import {
@ -78,29 +111,45 @@ import {
setOverflowMenuVisible, setOverflowMenuVisible,
setToolbarHovered, setToolbarHovered,
showToolbox showToolbox
// @ts-ignore
} from '../../actions'; } from '../../actions';
import { THRESHOLDS, NOT_APPLICABLE, NOTIFY_CLICK_MODE } from '../../constants'; import { THRESHOLDS, NOT_APPLICABLE, NOTIFY_CLICK_MODE } from '../../constants';
// @ts-ignore
import { isDesktopShareButtonDisabled, isToolboxVisible } from '../../functions'; import { isDesktopShareButtonDisabled, isToolboxVisible } from '../../functions';
// @ts-ignore
import DownloadButton from '../DownloadButton'; import DownloadButton from '../DownloadButton';
// @ts-ignore
import HangupButton from '../HangupButton'; import HangupButton from '../HangupButton';
// @ts-ignore
import HelpButton from '../HelpButton'; import HelpButton from '../HelpButton';
// @ts-ignore
import AudioSettingsButton from './AudioSettingsButton'; import AudioSettingsButton from './AudioSettingsButton';
// @ts-ignore
import DockIframeButton from './DockIframeButton'; import DockIframeButton from './DockIframeButton';
// @ts-ignore
import FullscreenButton from './FullscreenButton'; import FullscreenButton from './FullscreenButton';
// @ts-ignore
import LinkToSalesforceButton from './LinkToSalesforceButton'; import LinkToSalesforceButton from './LinkToSalesforceButton';
// @ts-ignore
import OverflowMenuButton from './OverflowMenuButton'; import OverflowMenuButton from './OverflowMenuButton';
// @ts-ignore
import ProfileButton from './ProfileButton'; import ProfileButton from './ProfileButton';
// @ts-ignore
import Separator from './Separator'; import Separator from './Separator';
// @ts-ignore
import ShareDesktopButton from './ShareDesktopButton'; import ShareDesktopButton from './ShareDesktopButton';
// @ts-ignore
import ToggleCameraButton from './ToggleCameraButton'; import ToggleCameraButton from './ToggleCameraButton';
// @ts-ignore
import UndockIframeButton from './UndockIframeButton'; import UndockIframeButton from './UndockIframeButton';
// @ts-ignore
import VideoSettingsButton from './VideoSettingsButton'; import VideoSettingsButton from './VideoSettingsButton';
/** /**
* The type of the React {@code Component} props of {@link Toolbox}. * The type of the React {@code Component} props of {@link Toolbox}.
*/ */
type Props = { interface Props extends WithTranslation {
/** /**
* String showing if the virtual background type is desktop-share. * String showing if the virtual background type is desktop-share.
@ -110,7 +159,10 @@ type Props = {
/** /**
* Toolbar buttons which have their click exposed through the API. * Toolbar buttons which have their click exposed through the API.
*/ */
_buttonsWithNotifyClick: Array<string | Object>, _buttonsWithNotifyClick: Array<string | {
key: string;
preventExecution: boolean;
}>,
/** /**
* Whether or not the chat feature is currently displayed. * Whether or not the chat feature is currently displayed.
@ -248,39 +300,33 @@ type Props = {
*/ */
_toolbarButtons: Array<string>, _toolbarButtons: Array<string>,
/**
* Returns the selected virtual source object.
*/
_virtualSource: any,
/** /**
* Flag showing whether toolbar is visible. * Flag showing whether toolbar is visible.
*/ */
_visible: boolean, _visible: boolean,
/**
* Returns the selected virtual source object.
*/
_virtualSource: Object,
/** /**
* An object containing the CSS classes. * An object containing the CSS classes.
*/ */
classes: Object, classes: any,
/** /**
* Invoked to active other features of the app. * Invoked to active other features of the app.
*/ */
dispatch: Function, dispatch: Function,
/**
* Invoked to obtain translated strings.
*/
t: Function,
/** /**
* Explicitly passed array with the buttons which this Toolbox should display. * Explicitly passed array with the buttons which this Toolbox should display.
*/ */
toolbarButtons: Array<string>, toolbarButtons: Array<string>,
}
}; declare let APP: any;
declare var APP: Object;
const styles = () => { const styles = () => {
return { return {
@ -435,7 +481,7 @@ class Toolbox extends Component<Props> {
* *
* @inheritdoc * @inheritdoc
*/ */
componentDidUpdate(prevProps) { componentDidUpdate(prevProps: Props) {
const { _dialog, dispatch } = this.props; const { _dialog, dispatch } = this.props;
@ -488,15 +534,13 @@ class Toolbox extends Component<Props> {
); );
} }
_onEscKey: (KeyboardEvent) => void;
/** /**
* Key handler for overflow menu. * Key handler for overflow menu.
* *
* @param {KeyboardEvent} e - Esc key click to close the popup. * @param {KeyboardEvent} e - Esc key click to close the popup.
* @returns {void} * @returns {void}
*/ */
_onEscKey(e) { _onEscKey(e: React.KeyboardEvent) {
if (e.key === 'Escape') { if (e.key === 'Escape') {
e.stopPropagation(); e.stopPropagation();
this._closeOverflowMenuIfOpen(); this._closeOverflowMenuIfOpen();
@ -870,9 +914,9 @@ class Toolbox extends Component<Props> {
* @param {string} btnName - The toolbar button's name. * @param {string} btnName - The toolbar button's name.
* @returns {string|undefined} - The button's notify mode. * @returns {string|undefined} - The button's notify mode.
*/ */
_getButtonNotifyMode(btnName) { _getButtonNotifyMode(btnName: string) {
const notify = this.props._buttonsWithNotifyClick?.find( const notify = this.props._buttonsWithNotifyClick?.find(
(btn: string | Object) => btn =>
(typeof btn === 'string' && btn === btnName) (typeof btn === 'string' && btn === btnName)
|| (typeof btn === 'object' && btn.key === btnName) || (typeof btn === 'object' && btn.key === btnName)
); );
@ -890,7 +934,7 @@ class Toolbox extends Component<Props> {
* @param {Object} buttons - The list of toolbar buttons. * @param {Object} buttons - The list of toolbar buttons.
* @returns {void} * @returns {void}
*/ */
_setButtonsNotifyClickMode(buttons) { _setButtonsNotifyClickMode(buttons: Object) {
if (typeof APP === 'undefined' || !this.props._buttonsWithNotifyClick?.length) { if (typeof APP === 'undefined' || !this.props._buttonsWithNotifyClick?.length) {
return; return;
} }
@ -926,7 +970,7 @@ class Toolbox extends Component<Props> {
const keys = Object.keys(buttons); const keys = Object.keys(buttons);
const filtered = [ const filtered = [
...order.map(key => buttons[key]), ...order.map(key => buttons[key as keyof typeof buttons]),
...Object.values(buttons).filter((button, index) => !order.includes(keys[index])) ...Object.values(buttons).filter((button, index) => !order.includes(keys[index]))
].filter(Boolean).filter(({ key, alias = NOT_APPLICABLE }) => ].filter(Boolean).filter(({ key, alias = NOT_APPLICABLE }) =>
isToolbarButtonEnabled(key, _toolbarButtons) || isToolbarButtonEnabled(alias, _toolbarButtons)); isToolbarButtonEnabled(key, _toolbarButtons) || isToolbarButtonEnabled(alias, _toolbarButtons));
@ -946,8 +990,6 @@ class Toolbox extends Component<Props> {
}; };
} }
_onMouseOut: () => void;
/** /**
* Dispatches an action signaling the toolbar is not being hovered. * Dispatches an action signaling the toolbar is not being hovered.
* *
@ -960,8 +1002,6 @@ class Toolbox extends Component<Props> {
!_overflowMenuVisible && dispatch(setToolbarHovered(false)); !_overflowMenuVisible && dispatch(setToolbarHovered(false));
} }
_onMouseOver: () => void;
/** /**
* Dispatches an action signaling the toolbar is being hovered. * Dispatches an action signaling the toolbar is being hovered.
* *
@ -972,9 +1012,6 @@ class Toolbox extends Component<Props> {
this.props.dispatch(setToolbarHovered(true)); this.props.dispatch(setToolbarHovered(true));
} }
_onSetOverflowVisible: (boolean) => void;
/** /**
* Sets the visibility of the overflow menu. * Sets the visibility of the overflow menu.
* *
@ -983,13 +1020,11 @@ class Toolbox extends Component<Props> {
* @private * @private
* @returns {void} * @returns {void}
*/ */
_onSetOverflowVisible(visible) { _onSetOverflowVisible(visible: boolean) {
this.props.dispatch(setOverflowMenuVisible(visible)); this.props.dispatch(setOverflowMenuVisible(visible));
this.props.dispatch(setToolbarHovered(visible)); this.props.dispatch(setToolbarHovered(visible));
} }
_onShortcutToggleChat: () => void;
/** /**
* Creates an analytics keyboard shortcut event and dispatches an action for * Creates an analytics keyboard shortcut event and dispatches an action for
* toggling the display of chat. * toggling the display of chat.
@ -1007,15 +1042,13 @@ class Toolbox extends Component<Props> {
// Checks if there was any text selected by the user. // Checks if there was any text selected by the user.
// Used for when we press simultaneously keys for copying // Used for when we press simultaneously keys for copying
// text messages from the chat board // text messages from the chat board
if (window.getSelection().toString() !== '') { if (window.getSelection()?.toString() !== '') {
return false; return false;
} }
this._doToggleChat(); this._doToggleChat();
} }
_onShortcutToggleParticipantsPane: () => void;
/** /**
* Creates an analytics keyboard shortcut event and dispatches an action for * Creates an analytics keyboard shortcut event and dispatches an action for
* toggling the display of the participants pane. * toggling the display of the participants pane.
@ -1033,8 +1066,6 @@ class Toolbox extends Component<Props> {
this._onToolbarToggleParticipantsPane(); this._onToolbarToggleParticipantsPane();
} }
_onShortcutToggleVideoQuality: () => void;
/** /**
* Creates an analytics keyboard shortcut event and dispatches an action for * Creates an analytics keyboard shortcut event and dispatches an action for
* toggling the display of Video Quality. * toggling the display of Video Quality.
@ -1048,8 +1079,6 @@ class Toolbox extends Component<Props> {
this._doToggleVideoQuality(); this._doToggleVideoQuality();
} }
_onShortcutToggleTileView: () => void;
/** /**
* Dispatches an action for toggling the tile view. * Dispatches an action for toggling the tile view.
* *
@ -1066,8 +1095,6 @@ class Toolbox extends Component<Props> {
this._doToggleTileView(); this._doToggleTileView();
} }
_onShortcutToggleFullScreen: () => void;
/** /**
* Creates an analytics keyboard shortcut event and dispatches an action for * Creates an analytics keyboard shortcut event and dispatches an action for
* toggling full screen mode. * toggling full screen mode.
@ -1085,8 +1112,6 @@ class Toolbox extends Component<Props> {
this._doToggleFullScreen(); this._doToggleFullScreen();
} }
_onShortcutToggleRaiseHand: () => void;
/** /**
* Creates an analytics keyboard shortcut event and dispatches an action for * Creates an analytics keyboard shortcut event and dispatches an action for
* toggling raise hand. * toggling raise hand.
@ -1103,8 +1128,6 @@ class Toolbox extends Component<Props> {
this._doToggleRaiseHand(); this._doToggleRaiseHand();
} }
_onShortcutToggleScreenshare: () => void;
/** /**
* Creates an analytics keyboard shortcut event and dispatches an action for * Creates an analytics keyboard shortcut event and dispatches an action for
* toggling screensharing. * toggling screensharing.
@ -1127,7 +1150,6 @@ class Toolbox extends Component<Props> {
this._doToggleScreenshare(); this._doToggleScreenshare();
} }
_onTabIn: () => void;
/** /**
* Toggle the toolbar visibility when tabbing into it. * Toggle the toolbar visibility when tabbing into it.
@ -1139,7 +1161,6 @@ class Toolbox extends Component<Props> {
this.props.dispatch(showToolbox()); this.props.dispatch(showToolbox());
} }
} }
_onToolbarToggleParticipantsPane: () => void;
/** /**
* Dispatches an action for toggling the participants pane. * Dispatches an action for toggling the participants pane.
@ -1157,8 +1178,6 @@ class Toolbox extends Component<Props> {
} }
} }
_onToolbarOpenVideoQuality: () => void;
/** /**
* Creates an analytics toolbar event and dispatches an action for toggling * Creates an analytics toolbar event and dispatches an action for toggling
* open the video quality dialog. * open the video quality dialog.
@ -1172,8 +1191,6 @@ class Toolbox extends Component<Props> {
this._doOpenVideoQuality(); this._doOpenVideoQuality();
} }
_onToolbarToggleChat: () => void;
/** /**
* Creates an analytics toolbar event and dispatches an action for toggling * Creates an analytics toolbar event and dispatches an action for toggling
* the display of chat. * the display of chat.
@ -1191,8 +1208,6 @@ class Toolbox extends Component<Props> {
this._doToggleChat(); this._doToggleChat();
} }
_onToolbarToggleFullScreen: () => void;
/** /**
* Creates an analytics toolbar event and dispatches an action for toggling * Creates an analytics toolbar event and dispatches an action for toggling
* full screen mode. * full screen mode.
@ -1210,8 +1225,6 @@ class Toolbox extends Component<Props> {
this._doToggleFullScreen(); this._doToggleFullScreen();
} }
_onToolbarToggleRaiseHand: () => void;
/** /**
* Creates an analytics toolbar event and dispatches an action for toggling * Creates an analytics toolbar event and dispatches an action for toggling
* raise hand. * raise hand.
@ -1227,8 +1240,6 @@ class Toolbox extends Component<Props> {
this._doToggleRaiseHand(); this._doToggleRaiseHand();
} }
_onToolbarToggleScreenshare: () => void;
/** /**
* Creates an analytics toolbar event and dispatches an action for toggling * Creates an analytics toolbar event and dispatches an action for toggling
* screensharing. * screensharing.
@ -1357,9 +1368,9 @@ class Toolbox extends Component<Props> {
} }
return acc; return acc;
}, []).map(buttonGroup => ( }, []).map((buttonGroup: any) => (
<ContextMenuItemGroup key = { `group-${buttonGroup[0].group}` }> <ContextMenuItemGroup key = { `group-${buttonGroup[0].group}` }>
{buttonGroup.map(({ key, Content, ...rest }) => ( {buttonGroup.map(({ key, Content, ...rest }: any) => (
key !== 'raisehand' || !_reactionsEnabled) key !== 'raisehand' || !_reactionsEnabled)
&& <Content && <Content
{ ...rest } { ...rest }
@ -1394,7 +1405,7 @@ class Toolbox extends Component<Props> {
* @private * @private
* @returns {{}} * @returns {{}}
*/ */
function _mapStateToProps(state, ownProps) { function _mapStateToProps(state: any, ownProps: Partial<Props>) {
const { conference } = state['features/base/conference']; const { conference } = state['features/base/conference'];
const { const {
buttonsWithNotifyClick, buttonsWithNotifyClick,
@ -1447,4 +1458,5 @@ function _mapStateToProps(state, ownProps) {
}; };
} }
// @ts-ignore
export default translate(connect(_mapStateToProps)(withStyles(styles)(Toolbox))); export default translate(connect(_mapStateToProps)(withStyles(styles)(Toolbox)));

View File

@ -1,28 +1,44 @@
// @flow /* eslint-disable lines-around-comment */
import { makeStyles } from '@material-ui/styles'; import { makeStyles } from '@material-ui/styles';
import React, { useCallback } from 'react'; import React, { useCallback } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useDispatch, useSelector } from 'react-redux'; import { useDispatch, useSelector } from 'react-redux';
import { IState } from '../../../app/types';
// @ts-ignore
import { isSupported as isAvModerationSupported } from '../../../av-moderation/functions'; import { isSupported as isAvModerationSupported } from '../../../av-moderation/functions';
// @ts-ignore
import { Avatar } from '../../../base/avatar'; import { Avatar } from '../../../base/avatar';
// @ts-ignore
import ContextMenu from '../../../base/components/context-menu/ContextMenu'; import ContextMenu from '../../../base/components/context-menu/ContextMenu';
// @ts-ignore
import ContextMenuItemGroup from '../../../base/components/context-menu/ContextMenuItemGroup'; import ContextMenuItemGroup from '../../../base/components/context-menu/ContextMenuItemGroup';
import { isIosMobileBrowser, isMobileBrowser } from '../../../base/environment/utils'; import { isIosMobileBrowser, isMobileBrowser } from '../../../base/environment/utils';
import { IconShareVideo } from '../../../base/icons'; import { IconShareVideo } from '../../../base/icons/svg/index';
import { MEDIA_TYPE } from '../../../base/media'; import { MEDIA_TYPE } from '../../../base/media/constants';
import { getLocalParticipant, PARTICIPANT_ROLE } from '../../../base/participants'; import { PARTICIPANT_ROLE } from '../../../base/participants/constants';
import { getLocalParticipant } from '../../../base/participants/functions';
import { Participant } from '../../../base/participants/reducer';
// @ts-ignore
import { isParticipantAudioMuted } from '../../../base/tracks'; import { isParticipantAudioMuted } from '../../../base/tracks';
// @ts-ignore
import { getBreakoutRooms, getCurrentRoomId, isInBreakoutRoom } from '../../../breakout-rooms/functions'; import { getBreakoutRooms, getCurrentRoomId, isInBreakoutRoom } from '../../../breakout-rooms/functions';
// @ts-ignore
import { setVolume } from '../../../filmstrip/actions.web'; import { setVolume } from '../../../filmstrip/actions.web';
// @ts-ignore
import { isStageFilmstripAvailable } from '../../../filmstrip/functions.web'; import { isStageFilmstripAvailable } from '../../../filmstrip/functions.web';
// @ts-ignore
import { isForceMuted } from '../../../participants-pane/functions'; import { isForceMuted } from '../../../participants-pane/functions';
// @ts-ignore
import { requestRemoteControl, stopController } from '../../../remote-control'; import { requestRemoteControl, stopController } from '../../../remote-control';
// @ts-ignore
import { stopSharedVideo } from '../../../shared-video/actions.any'; import { stopSharedVideo } from '../../../shared-video/actions.any';
// @ts-ignore
import { showOverflowDrawer } from '../../../toolbox/functions.web'; import { showOverflowDrawer } from '../../../toolbox/functions.web';
// @ts-ignore
import { REMOTE_CONTROL_MENU_STATES } from './RemoteControlButton'; import { REMOTE_CONTROL_MENU_STATES } from './RemoteControlButton';
// @ts-ignore
import SendToRoomButton from './SendToRoomButton'; import SendToRoomButton from './SendToRoomButton';
import { import {
@ -38,6 +54,7 @@ import {
RemoteControlButton, RemoteControlButton,
TogglePinToStageButton, TogglePinToStageButton,
VolumeSlider VolumeSlider
// @ts-ignore
} from './'; } from './';
type Props = { type Props = {
@ -56,7 +73,10 @@ type Props = {
* The participant for which the drawer is open. * The participant for which the drawer is open.
* It contains the displayName & participantID. * It contains the displayName & participantID.
*/ */
drawerParticipant?: Object, drawerParticipant?: {
displayName: string;
participantID: string;
},
/** /**
* Shared video local participant owner. * Shared video local participant owner.
@ -86,7 +106,7 @@ type Props = {
/** /**
* Participant reference. * Participant reference.
*/ */
participant: Object, participant: Participant,
/** /**
* The current state of the participant's remote control session. * The current state of the participant's remote control session.
@ -96,10 +116,10 @@ type Props = {
/** /**
* Whether or not the menu is displayed in the thumbnail remote video menu. * Whether or not the menu is displayed in the thumbnail remote video menu.
*/ */
thumbnailMenu: ?boolean thumbnailMenu?: boolean
} }
const useStyles = makeStyles(theme => { const useStyles = makeStyles((theme: any) => {
return { return {
text: { text: {
color: theme.palette.text02, color: theme.palette.text02,
@ -139,9 +159,9 @@ const ParticipantContextMenu = ({
const _isAudioMuted = useSelector(state => isParticipantAudioMuted(participant, state)); const _isAudioMuted = useSelector(state => isParticipantAudioMuted(participant, state));
const _overflowDrawer = useSelector(showOverflowDrawer); const _overflowDrawer = useSelector(showOverflowDrawer);
const { remoteVideoMenu = {}, disableRemoteMute, startSilent } const { remoteVideoMenu = {}, disableRemoteMute, startSilent }
= useSelector(state => state['features/base/config']); = useSelector((state: IState) => state['features/base/config']);
const { disableKick, disableGrantModerator, disablePrivateChat } = remoteVideoMenu; const { disableKick, disableGrantModerator, disablePrivateChat } = remoteVideoMenu;
const { participantsVolume } = useSelector(state => state['features/filmstrip']); const { participantsVolume } = useSelector((state: any) => state['features/filmstrip']);
const _volume = (participant?.local ?? true ? undefined const _volume = (participant?.local ?? true ? undefined
: participant?.id ? participantsVolume[participant?.id] : undefined) ?? 1; : participant?.id ? participantsVolume[participant?.id] : undefined) ?? 1;
const isBreakoutRoom = useSelector(isInBreakoutRoom); const isBreakoutRoom = useSelector(isInBreakoutRoom);
@ -149,7 +169,7 @@ const ParticipantContextMenu = ({
const stageFilmstrip = useSelector(isStageFilmstripAvailable); const stageFilmstrip = useSelector(isStageFilmstripAvailable);
const _currentRoomId = useSelector(getCurrentRoomId); const _currentRoomId = useSelector(getCurrentRoomId);
const _rooms = Object.values(useSelector(getBreakoutRooms)); const _rooms: Array<{id: string}> = Object.values(useSelector(getBreakoutRooms));
const _onVolumeChange = useCallback(value => { const _onVolumeChange = useCallback(value => {
dispatch(setVolume(participant.id, value)); dispatch(setVolume(participant.id, value));
@ -273,10 +293,10 @@ const ParticipantContextMenu = ({
); );
} }
const breakoutRoomsButtons = []; const breakoutRoomsButtons: any = [];
if (!thumbnailMenu && _isModerator) { if (!thumbnailMenu && _isModerator) {
_rooms.forEach((room: Object) => { _rooms.forEach(room => {
if (room.id !== _currentRoomId) { if (room.id !== _currentRoomId) {
breakoutRoomsButtons.push( breakoutRoomsButtons.push(
<SendToRoomButton <SendToRoomButton

View File

@ -9,6 +9,7 @@ import { isMobileBrowser } from '../../../base/environment/utils';
import { translate } from '../../../base/i18n'; import { translate } from '../../../base/i18n';
import { IconHorizontalPoints } from '../../../base/icons/svg/index'; import { IconHorizontalPoints } from '../../../base/icons/svg/index';
import { getParticipantById } from '../../../base/participants/functions'; import { getParticipantById } from '../../../base/participants/functions';
import { Participant } from '../../../base/participants/reducer';
// @ts-ignore // @ts-ignore
import { Popover } from '../../../base/popover'; import { Popover } from '../../../base/popover';
// @ts-ignore // @ts-ignore
@ -57,7 +58,7 @@ interface Props extends WithTranslation {
/** /**
* Participant reference. * Participant reference.
*/ */
_participant: Object, _participant: Participant,
/** /**
* The ID for the participant on which the remote video menu will act. * The ID for the participant on which the remote video menu will act.

View File

@ -1,22 +1,24 @@
/* @flow */ /* eslint-disable lines-around-comment */
import { withStyles } from '@material-ui/styles'; import { withStyles } from '@material-ui/styles';
import clsx from 'clsx'; import clsx from 'clsx';
import React, { Component } from 'react'; import React, { Component } from 'react';
import { WithTranslation } from 'react-i18next';
import { translate } from '../../../base/i18n'; import { translate } from '../../../base/i18n/functions';
import { Icon, IconVolume } from '../../../base/icons'; import Icon from '../../../base/icons/components/Icon';
import { IconVolume } from '../../../base/icons/svg/index';
// @ts-ignore
import { VOLUME_SLIDER_SCALE } from '../../constants'; import { VOLUME_SLIDER_SCALE } from '../../constants';
/** /**
* The type of the React {@code Component} props of {@link VolumeSlider}. * The type of the React {@code Component} props of {@link VolumeSlider}.
*/ */
type Props = { interface Props extends WithTranslation {
/** /**
* An object containing the CSS classes. * An object containing the CSS classes.
*/ */
classes: Object, classes: any,
/** /**
* The value of the audio slider should display at when the component first * The value of the audio slider should display at when the component first
@ -28,13 +30,8 @@ type Props = {
/** /**
* The callback to invoke when the audio slider value changes. * The callback to invoke when the audio slider value changes.
*/ */
onChange: Function, onChange: Function
}
/**
* Invoked to obtain translated strings.
*/
t: Function
};
/** /**
* The type of the React {@code Component} state of {@link VolumeSlider}. * The type of the React {@code Component} state of {@link VolumeSlider}.
@ -48,7 +45,7 @@ type State = {
volumeLevel: number volumeLevel: number
}; };
const styles = theme => { const styles = (theme: any) => {
return { return {
container: { container: {
minHeight: '40px', minHeight: '40px',
@ -116,7 +113,7 @@ class VolumeSlider extends Component<Props, State> {
* @param {MouseEvent} e - Click event. * @param {MouseEvent} e - Click event.
* @returns {void} * @returns {void}
*/ */
_onClick(e) { _onClick(e: React.MouseEvent) {
e.stopPropagation(); e.stopPropagation();
} }
@ -156,8 +153,6 @@ class VolumeSlider extends Component<Props, State> {
); );
} }
_onVolumeChange: (Object) => void;
/** /**
* Sets the internal state of the volume level for the volume slider. * Sets the internal state of the volume level for the volume slider.
* Invokes the prop onVolumeChange to notify of volume changes. * Invokes the prop onVolumeChange to notify of volume changes.
@ -166,12 +161,13 @@ class VolumeSlider extends Component<Props, State> {
* @private * @private
* @returns {void} * @returns {void}
*/ */
_onVolumeChange(event) { _onVolumeChange(event: React.ChangeEvent<HTMLInputElement>) {
const volumeLevel = event.currentTarget.value; const volumeLevel = Number(event.currentTarget.value);
this.props.onChange(volumeLevel / VOLUME_SLIDER_SCALE); this.props.onChange(volumeLevel / VOLUME_SLIDER_SCALE);
this.setState({ volumeLevel }); this.setState({ volumeLevel });
} }
} }
// @ts-ignore
export default translate(withStyles(styles)(VolumeSlider)); export default translate(withStyles(styles)(VolumeSlider));

View File

@ -1,4 +1,3 @@
// @flow
import { makeStyles } from '@material-ui/core/styles'; import { makeStyles } from '@material-ui/core/styles';
import clsx from 'clsx'; import clsx from 'clsx';
import React from 'react'; import React from 'react';
@ -25,7 +24,7 @@ type Props = {
/** /**
* Callback invoked on change. * Callback invoked on change.
*/ */
onChange: Function, onChange: (e: React.ChangeEvent<HTMLInputElement>) => void,
/** /**
* The granularity that the value must adhere to. * The granularity that the value must adhere to.
@ -38,7 +37,7 @@ type Props = {
value: number value: number
} }
const useStyles = makeStyles(theme => { const useStyles = makeStyles((theme: any) => {
// keep the same height for all elements: // keep the same height for all elements:
// input, input track & fake track(div) // input, input track & fake track(div)
const height = 6; const height = 6;

View File

@ -2,7 +2,7 @@ import React, { Component } from 'react';
import { Dialog } from '../../base/dialog'; import { Dialog } from '../../base/dialog';
import VideoQualitySlider from './VideoQualitySlider'; import VideoQualitySlider from './VideoQualitySlider.web';
/** /**
* Implements a React {@link Component} which displays the component * Implements a React {@link Component} which displays the component

View File

@ -1,17 +1,24 @@
// @flow /* eslint-disable lines-around-comment */
import { withStyles } from '@material-ui/core/styles'; import { withStyles } from '@material-ui/core/styles';
import clsx from 'clsx'; import clsx from 'clsx';
import React, { Component } from 'react'; import React, { Component } from 'react';
import { WithTranslation } from 'react-i18next';
import type { Dispatch } from 'redux'; import type { Dispatch } from 'redux';
// @ts-ignore
import { createToolbarEvent, sendAnalytics } from '../../analytics'; import { createToolbarEvent, sendAnalytics } from '../../analytics';
// @ts-ignore
import { setAudioOnly } from '../../base/audio-only'; import { setAudioOnly } from '../../base/audio-only';
import { translate } from '../../base/i18n'; import { translate } from '../../base/i18n/functions';
// @ts-ignore
import { setLastN, getLastNForQualityLevel } from '../../base/lastn'; import { setLastN, getLastNForQualityLevel } from '../../base/lastn';
import { connect } from '../../base/redux'; import { connect } from '../../base/redux/functions';
import { withPixelLineHeight } from '../../base/styles/functions.web'; import { withPixelLineHeight } from '../../base/styles/functions.web';
// @ts-ignore
import { setPreferredVideoQuality } from '../actions'; import { setPreferredVideoQuality } from '../actions';
// @ts-ignore
import { DEFAULT_LAST_N, VIDEO_QUALITY_LEVELS } from '../constants'; import { DEFAULT_LAST_N, VIDEO_QUALITY_LEVELS } from '../constants';
// @ts-ignore
import logger from '../logger'; import logger from '../logger';
import Slider from './Slider'; import Slider from './Slider';
@ -31,7 +38,7 @@ const {
* @returns {Object} The event in a format suitable for sending via * @returns {Object} The event in a format suitable for sending via
* sendAnalytics. * sendAnalytics.
*/ */
const createEvent = function(quality) { const createEvent = function(quality: string) {
return createToolbarEvent( return createToolbarEvent(
'video.quality', 'video.quality',
{ {
@ -42,7 +49,7 @@ const createEvent = function(quality) {
/** /**
* The type of the React {@code Component} props of {@link VideoQualitySlider}. * The type of the React {@code Component} props of {@link VideoQualitySlider}.
*/ */
type Props = { interface Props extends WithTranslation {
/** /**
* Whether or not the conference is in audio only mode. * Whether or not the conference is in audio only mode.
@ -68,19 +75,13 @@ type Props = {
/** /**
* An object containing the CSS classes. * An object containing the CSS classes.
*/ */
classes: Object, classes: any,
/** /**
* Invoked to request toggling of audio only mode. * Invoked to request toggling of audio only mode.
*/ */
dispatch: Dispatch<any>, dispatch: Dispatch<any>
}
/**
* Invoked to obtain translated strings.
*/
t: Function
};
/** /**
* Creates the styles for the component. * Creates the styles for the component.
@ -89,7 +90,7 @@ type Props = {
* *
* @returns {Object} * @returns {Object}
*/ */
const styles = theme => { const styles = (theme: any) => {
return { return {
dialog: { dialog: {
color: theme.palette.text01 color: theme.palette.text01
@ -128,7 +129,7 @@ class VideoQualitySlider extends Component<Props> {
* @param {Object} props - The read-only React Component props with which * @param {Object} props - The read-only React Component props with which
* the new instance is to be initialized. * the new instance is to be initialized.
*/ */
constructor(props) { constructor(props: Props) {
super(props); super(props);
// Bind event handlers so they are only bound once for every instance. // Bind event handlers so they are only bound once for every instance.
@ -203,8 +204,6 @@ class VideoQualitySlider extends Component<Props> {
); );
} }
_enableAudioOnly: () => void;
/** /**
* Dispatches an action to enable audio only mode. * Dispatches an action to enable audio only mode.
* *
@ -217,8 +216,6 @@ class VideoQualitySlider extends Component<Props> {
this.props.dispatch(setAudioOnly(true)); this.props.dispatch(setAudioOnly(true));
} }
_enableHighDefinition: () => void;
/** /**
* Handles the action of the high definition video being selected. * Handles the action of the high definition video being selected.
* Dispatches an action to receive high quality video from remote * Dispatches an action to receive high quality video from remote
@ -233,8 +230,6 @@ class VideoQualitySlider extends Component<Props> {
this._setPreferredVideoQuality(HIGH); this._setPreferredVideoQuality(HIGH);
} }
_enableLowDefinition: () => void;
/** /**
* Dispatches an action to receive low quality video from remote * Dispatches an action to receive low quality video from remote
* participants. * participants.
@ -248,8 +243,6 @@ class VideoQualitySlider extends Component<Props> {
this._setPreferredVideoQuality(LOW); this._setPreferredVideoQuality(LOW);
} }
_enableStandardDefinition: () => void;
/** /**
* Dispatches an action to receive standard quality video from remote * Dispatches an action to receive standard quality video from remote
* participants. * participants.
@ -263,8 +256,6 @@ class VideoQualitySlider extends Component<Props> {
this._setPreferredVideoQuality(STANDARD); this._setPreferredVideoQuality(STANDARD);
} }
_enableUltraHighDefinition: () => void;
/** /**
* Dispatches an action to receive ultra HD quality video from remote * Dispatches an action to receive ultra HD quality video from remote
* participants. * participants.
@ -291,12 +282,14 @@ class VideoQualitySlider extends Component<Props> {
if (_audioOnly) { if (_audioOnly) {
const audioOnlyOption = _sliderOptions.find( const audioOnlyOption = _sliderOptions.find(
({ audioOnly }) => audioOnly); ({ audioOnly }: any) => audioOnly);
// @ts-ignore
return _sliderOptions.indexOf(audioOnlyOption); return _sliderOptions.indexOf(audioOnlyOption);
} }
for (let i = 0; i < _sliderOptions.length; i++) { for (let i = 0; i < _sliderOptions.length; i++) {
// @ts-ignore
if (_sliderOptions[i].videoQuality >= _sendrecvVideoQuality) { if (_sliderOptions[i].videoQuality >= _sendrecvVideoQuality) {
return i; return i;
} }
@ -305,8 +298,6 @@ class VideoQualitySlider extends Component<Props> {
return -1; return -1;
} }
_onSliderChange: () => void;
/** /**
* Invokes a callback when the selected video quality changes. * Invokes a callback when the selected video quality changes.
* *
@ -314,13 +305,16 @@ class VideoQualitySlider extends Component<Props> {
* @private * @private
* @returns {void} * @returns {void}
*/ */
_onSliderChange(event) { _onSliderChange(event: React.ChangeEvent<HTMLInputElement>) {
const { _audioOnly, _sendrecvVideoQuality } = this.props; const { _audioOnly, _sendrecvVideoQuality } = this.props;
const { const {
// @ts-ignore
audioOnly, audioOnly,
// @ts-ignore
onSelect, onSelect,
// @ts-ignore
videoQuality videoQuality
} = this._sliderOptions[event.target.value]; } = this._sliderOptions[event.target.value as keyof typeof this._sliderOptions];
// Take no action if the newly chosen option does not change audio only // Take no action if the newly chosen option does not change audio only
// or video quality state. // or video quality state.
@ -341,7 +335,7 @@ class VideoQualitySlider extends Component<Props> {
* @private * @private
* @returns {void} * @returns {void}
*/ */
_setPreferredVideoQuality(qualityLevel) { _setPreferredVideoQuality(qualityLevel: number) {
this.props.dispatch(setPreferredVideoQuality(qualityLevel)); this.props.dispatch(setPreferredVideoQuality(qualityLevel));
if (this.props._audioOnly) { if (this.props._audioOnly) {
this.props.dispatch(setAudioOnly(false)); this.props.dispatch(setAudioOnly(false));
@ -366,7 +360,7 @@ class VideoQualitySlider extends Component<Props> {
* @private * @private
* @returns {Props} * @returns {Props}
*/ */
function _mapStateToProps(state) { function _mapStateToProps(state: any) {
const { enabled: audioOnly } = state['features/base/audio-only']; const { enabled: audioOnly } = state['features/base/audio-only'];
const { p2p } = state['features/base/conference']; const { p2p } = state['features/base/conference'];
const { preferredVideoQuality } = state['features/video-quality']; const { preferredVideoQuality } = state['features/video-quality'];

View File

@ -1,16 +1,19 @@
// @flow /* eslint-disable lines-around-comment */
import { makeStyles } from '@material-ui/styles'; import { makeStyles } from '@material-ui/styles';
import React, { useCallback, useRef } from 'react'; import React, { useCallback, useRef } from 'react';
import { WithTranslation } from 'react-i18next';
import { v4 as uuidv4 } from 'uuid'; import { v4 as uuidv4 } from 'uuid';
import { translate } from '../../base/i18n'; import { translate } from '../../base/i18n/functions';
import { Icon, IconPlusCircle } from '../../base/icons'; import Icon from '../../base/icons/components/Icon';
import { IconPlusCircle } from '../../base/icons/svg/index';
import { VIRTUAL_BACKGROUND_TYPE, type Image } from '../constants'; import { VIRTUAL_BACKGROUND_TYPE, type Image } from '../constants';
// @ts-ignore
import { resizeImage } from '../functions'; import { resizeImage } from '../functions';
// @ts-ignore
import logger from '../logger'; import logger from '../logger';
type Props = { interface Props extends WithTranslation {
/** /**
* Callback used to set the 'loading' state of the parent component. * Callback used to set the 'loading' state of the parent component.
@ -27,23 +30,19 @@ type Props = {
*/ */
setStoredImages: Function, setStoredImages: Function,
/**
* A list of images locally stored.
*/
storedImages: Array<Image>,
/** /**
* If a label should be displayed alongside the button. * If a label should be displayed alongside the button.
*/ */
showLabel: boolean, showLabel: boolean,
/** /**
* Used for translation. * A list of images locally stored.
*/ */
t: Function storedImages: Array<Image>
} }
const useStyles = makeStyles(theme => { // @ts-ignore
const useStyles = makeStyles((theme: any) => {
return { return {
addBackground: { addBackground: {
marginRight: `${theme.spacing(2)}px` marginRight: `${theme.spacing(2)}px`
@ -80,7 +79,7 @@ function UploadImageButton({
t t
}: Props) { }: Props) {
const classes = useStyles(); const classes = useStyles();
const uploadImageButton: Object = useRef(null); const uploadImageButton = useRef<HTMLInputElement>(null);
const uploadImageKeyPress = useCallback(e => { const uploadImageKeyPress = useCallback(e => {
if (uploadImageButton.current && (e.key === ' ' || e.key === 'Enter')) { if (uploadImageButton.current && (e.key === ' ' || e.key === 'Enter')) {
e.preventDefault(); e.preventDefault();

View File

@ -1,34 +1,49 @@
// @flow /* eslint-disable lines-around-comment */
import Spinner from '@atlaskit/spinner'; import Spinner from '@atlaskit/spinner';
// @ts-ignore
import Bourne from '@hapi/bourne'; import Bourne from '@hapi/bourne';
// @ts-ignore
import { jitsiLocalStorage } from '@jitsi/js-utils/jitsi-local-storage'; import { jitsiLocalStorage } from '@jitsi/js-utils/jitsi-local-storage';
import { makeStyles } from '@material-ui/styles'; import { makeStyles } from '@material-ui/styles';
import clsx from 'clsx'; import clsx from 'clsx';
import React, { useState, useEffect, useCallback } from 'react'; import React, { useState, useEffect, useCallback } from 'react';
import { WithTranslation } from 'react-i18next';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
import { IState } from '../../app/types';
// @ts-ignore
import { getMultipleVideoSendingSupportFeatureFlag } from '../../base/config'; import { getMultipleVideoSendingSupportFeatureFlag } from '../../base/config';
// @ts-ignore
import { Dialog, hideDialog, openDialog } from '../../base/dialog'; import { Dialog, hideDialog, openDialog } from '../../base/dialog';
import { translate } from '../../base/i18n'; import { translate } from '../../base/i18n/functions';
import { Icon, IconCloseSmall, IconShareDesktop } from '../../base/icons'; import Icon from '../../base/icons/components/Icon';
import { IconCloseSmall, IconShareDesktop } from '../../base/icons/svg/index';
import { browser, JitsiTrackErrors } from '../../base/lib-jitsi-meet'; import { browser, JitsiTrackErrors } from '../../base/lib-jitsi-meet';
// @ts-ignore
import { createLocalTrack } from '../../base/lib-jitsi-meet/functions'; import { createLocalTrack } from '../../base/lib-jitsi-meet/functions';
import { VIDEO_TYPE } from '../../base/media'; import { VIDEO_TYPE } from '../../base/media/constants';
import { connect } from '../../base/redux'; import { connect } from '../../base/redux/functions';
// @ts-ignore
import { updateSettings } from '../../base/settings'; import { updateSettings } from '../../base/settings';
// @ts-ignore
import { Tooltip } from '../../base/tooltip'; import { Tooltip } from '../../base/tooltip';
// @ts-ignore
import { getLocalVideoTrack } from '../../base/tracks'; import { getLocalVideoTrack } from '../../base/tracks';
// @ts-ignore
import { NOTIFICATION_TIMEOUT_TYPE, showErrorNotification } from '../../notifications'; import { NOTIFICATION_TIMEOUT_TYPE, showErrorNotification } from '../../notifications';
// @ts-ignore
import { toggleBackgroundEffect, virtualBackgroundTrackChanged } from '../actions'; import { toggleBackgroundEffect, virtualBackgroundTrackChanged } from '../actions';
import { IMAGES, BACKGROUNDS_LIMIT, VIRTUAL_BACKGROUND_TYPE, type Image } from '../constants'; import { IMAGES, BACKGROUNDS_LIMIT, VIRTUAL_BACKGROUND_TYPE, type Image } from '../constants';
// @ts-ignore
import { toDataURL } from '../functions'; import { toDataURL } from '../functions';
// @ts-ignore
import logger from '../logger'; import logger from '../logger';
import UploadImageButton from './UploadImageButton'; import UploadImageButton from './UploadImageButton';
// @ts-ignore
import VirtualBackgroundPreview from './VirtualBackgroundPreview'; import VirtualBackgroundPreview from './VirtualBackgroundPreview';
type Props = { interface Props extends WithTranslation {
/** /**
* The list of Images to choose from. * The list of Images to choose from.
@ -63,7 +78,7 @@ type Props = {
/** /**
* Returns the selected virtual background object. * Returns the selected virtual background object.
*/ */
_virtualBackground: Object, _virtualBackground: any,
/** /**
* The redux {@code dispatch} function. * The redux {@code dispatch} function.
@ -76,15 +91,10 @@ type Props = {
* NOTE: currently used only for electron in order to open the dialog in the correct state after desktop sharing * NOTE: currently used only for electron in order to open the dialog in the correct state after desktop sharing
* selection. * selection.
*/ */
initialOptions: Object, initialOptions: Object
}
/** const onError = (event: any) => {
* Invoked to obtain translated strings.
*/
t: Function
};
const onError = event => {
event.target.style.display = 'none'; event.target.style.display = 'none';
}; };
@ -97,7 +107,7 @@ const onError = event => {
* @private * @private
* @returns {{Props}} * @returns {{Props}}
*/ */
function _mapStateToProps(state): Object { function _mapStateToProps(state: any): Object {
const { localFlipX } = state['features/base/settings']; const { localFlipX } = state['features/base/settings'];
const dynamicBrandingImages = state['features/dynamic-branding'].virtualBackgrounds; const dynamicBrandingImages = state['features/dynamic-branding'].virtualBackgrounds;
const hasBrandingImages = Boolean(dynamicBrandingImages.length); const hasBrandingImages = Boolean(dynamicBrandingImages.length);
@ -115,7 +125,7 @@ function _mapStateToProps(state): Object {
const VirtualBackgroundDialog = translate(connect(_mapStateToProps)(VirtualBackground)); const VirtualBackgroundDialog = translate(connect(_mapStateToProps)(VirtualBackground));
const useStyles = makeStyles(theme => { const useStyles = makeStyles((theme: any) => {
return { return {
container: { container: {
display: 'flex', display: 'flex',
@ -131,6 +141,7 @@ const useStyles = makeStyles(theme => {
gridTemplateColumns: 'auto auto auto auto auto', gridTemplateColumns: 'auto auto auto auto auto',
columnGap: '9px', columnGap: '9px',
cursor: 'pointer', cursor: 'pointer',
// @ts-ignore
[[ '& .desktop-share:hover', [[ '& .desktop-share:hover',
'& .thumbnail:hover', '& .thumbnail:hover',
'& .blur:hover', '& .blur:hover',
@ -217,6 +228,7 @@ const useStyles = makeStyles(theme => {
gridTemplateColumns: 'auto auto auto auto auto', gridTemplateColumns: 'auto auto auto auto auto',
fontSize: '1.5vw', fontSize: '1.5vw',
// @ts-ignore
[[ '& .desktop-share:hover', [[ '& .desktop-share:hover',
'& .thumbnail:hover', '& .thumbnail:hover',
'& .blur:hover', '& .blur:hover',
@ -226,6 +238,7 @@ const useStyles = makeStyles(theme => {
width: '60px' width: '60px'
}, },
// @ts-ignore
[[ '& .desktop-share', [[ '& .desktop-share',
'& .virtual-background-none,', '& .virtual-background-none,',
'& .thumbnail,', '& .thumbnail,',
@ -234,6 +247,7 @@ const useStyles = makeStyles(theme => {
height: '60px', height: '60px',
width: '60px' width: '60px'
}, },
// @ts-ignore
[[ '& .desktop-share-selected', [[ '& .desktop-share-selected',
'& .thumbnail-selected', '& .thumbnail-selected',
'& .none-selected', '& .none-selected',
@ -282,11 +296,11 @@ function VirtualBackground({
}: Props) { }: Props) {
const classes = useStyles(); const classes = useStyles();
const [ previewIsLoaded, setPreviewIsLoaded ] = useState(false); const [ previewIsLoaded, setPreviewIsLoaded ] = useState(false);
const [ options, setOptions ] = useState({ ...initialOptions }); const [ options, setOptions ] = useState<any>({ ...initialOptions });
const localImages = jitsiLocalStorage.getItem('virtualBackgrounds'); const localImages = jitsiLocalStorage.getItem('virtualBackgrounds');
const [ storedImages, setStoredImages ] = useState<Array<Image>>((localImages && Bourne.parse(localImages)) || []); const [ storedImages, setStoredImages ] = useState<Array<Image>>((localImages && Bourne.parse(localImages)) || []);
const [ loading, setLoading ] = useState(false); const [ loading, setLoading ] = useState(false);
let { disableScreensharingVirtualBackground } = useSelector(state => state['features/base/config']); let { disableScreensharingVirtualBackground } = useSelector((state: IState) => state['features/base/config']);
// Disable screenshare as virtual background in multi-stream mode. // Disable screenshare as virtual background in multi-stream mode.
disableScreensharingVirtualBackground = disableScreensharingVirtualBackground || _multiStreamModeEnabled; disableScreensharingVirtualBackground = disableScreensharingVirtualBackground || _multiStreamModeEnabled;
@ -369,7 +383,7 @@ function VirtualBackground({
try { try {
url = await createLocalTrack('desktop', ''); url = await createLocalTrack('desktop', '');
} catch (e) { } catch (e: any) {
if (e.name === JitsiTrackErrors.SCREENSHARING_USER_CANCELED) { if (e.name === JitsiTrackErrors.SCREENSHARING_USER_CANCELED) {
isCancelled = true; isCancelled = true;
} else { } else {
@ -526,11 +540,11 @@ function VirtualBackground({
blurValue: initialVirtualBackground.blurValue blurValue: initialVirtualBackground.blurValue
}); });
dispatch(hideDialog()); dispatch(hideDialog());
}); }, []);
const loadedPreviewState = useCallback(async loaded => { const loadedPreviewState = useCallback(async loaded => {
await setPreviewIsLoaded(loaded); await setPreviewIsLoaded(loaded);
}); }, []);
return ( return (
<Dialog <Dialog
@ -546,6 +560,7 @@ function VirtualBackground({
{loading ? ( {loading ? (
<div className = { classes.virtualBackgroundLoading }> <div className = { classes.virtualBackgroundLoading }>
<Spinner <Spinner
// @ts-ignore
isCompleting = { false } isCompleting = { false }
size = 'medium' /> size = 'medium' />
</div> </div>
@ -561,7 +576,7 @@ function VirtualBackground({
<div <div
className = { clsx(classes.dialog, { [classes.dialogMarginTop]: previewIsLoaded }) } className = { clsx(classes.dialog, { [classes.dialogMarginTop]: previewIsLoaded }) }
role = 'radiogroup' role = 'radiogroup'
tabIndex = '-1'> tabIndex = { -1 }>
<Tooltip <Tooltip
content = { t('virtualBackground.removeBackground') } content = { t('virtualBackground.removeBackground') }
position = { 'top' }> position = { 'top' }>

View File

@ -1,21 +1,32 @@
// @flow /* eslint-disable lines-around-comment */
import Spinner from '@atlaskit/spinner'; import Spinner from '@atlaskit/spinner';
import { withStyles } from '@material-ui/core/styles'; import { withStyles } from '@material-ui/core/styles';
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import { WithTranslation } from 'react-i18next';
import { IState } from '../../app/types';
// @ts-ignore
import { hideDialog } from '../../base/dialog'; import { hideDialog } from '../../base/dialog';
// @ts-ignore
import { translate } from '../../base/i18n'; import { translate } from '../../base/i18n';
import { VIDEO_TYPE } from '../../base/media'; // @ts-ignore
import Video from '../../base/media/components/Video'; import Video from '../../base/media/components/Video';
import { connect, equals } from '../../base/redux'; import { VIDEO_TYPE } from '../../base/media/constants';
import { connect, equals } from '../../base/redux/functions';
// @ts-ignore
import { getCurrentCameraDeviceId } from '../../base/settings'; import { getCurrentCameraDeviceId } from '../../base/settings';
// @ts-ignore
import { createLocalTracksF } from '../../base/tracks/functions'; import { createLocalTracksF } from '../../base/tracks/functions';
// @ts-ignore
import { NOTIFICATION_TIMEOUT_TYPE } from '../../notifications'; import { NOTIFICATION_TIMEOUT_TYPE } from '../../notifications';
// @ts-ignore
import { showWarningNotification } from '../../notifications/actions'; import { showWarningNotification } from '../../notifications/actions';
// @ts-ignore
import { toggleBackgroundEffect } from '../actions'; import { toggleBackgroundEffect } from '../actions';
import { VIRTUAL_BACKGROUND_TYPE } from '../constants'; import { VIRTUAL_BACKGROUND_TYPE } from '../constants';
// @ts-ignore
import { localTrackStopped } from '../functions'; import { localTrackStopped } from '../functions';
// @ts-ignore
import logger from '../logger'; import logger from '../logger';
const videoClassName = 'video-preview-video'; const videoClassName = 'video-preview-video';
@ -23,7 +34,7 @@ const videoClassName = 'video-preview-video';
/** /**
* The type of the React {@code PureComponent} props of {@link VirtualBackgroundPreview}. * The type of the React {@code PureComponent} props of {@link VirtualBackgroundPreview}.
*/ */
export type Props = { export type Props = WithTranslation & {
/** /**
* The deviceId of the camera device currently being used. * The deviceId of the camera device currently being used.
@ -33,7 +44,7 @@ export type Props = {
/** /**
* An object containing the CSS classes. * An object containing the CSS classes.
*/ */
classes: Object, classes: any,
/** /**
* The redux {@code dispatch} function. * The redux {@code dispatch} function.
@ -48,12 +59,7 @@ export type Props = {
/** /**
* Represents the virtual background set options. * Represents the virtual background set options.
*/ */
options: Object, options: any
/**
* Invoked to obtain translated strings.
*/
t: Function
}; };
/** /**
@ -61,6 +67,11 @@ export type Props = {
*/ */
type State = { type State = {
/**
* Activate the selected device camera only.
*/
jitsiTrack: Object|null,
/** /**
* Loader activated on setting virtual background. * Loader activated on setting virtual background.
*/ */
@ -69,12 +80,7 @@ type State = {
/** /**
* Flag that indicates if the local track was loaded. * Flag that indicates if the local track was loaded.
*/ */
localTrackLoaded: boolean, localTrackLoaded: boolean
/**
* Activate the selected device camera only.
*/
jitsiTrack: Object
}; };
/** /**
@ -84,7 +90,7 @@ type State = {
* *
* @returns {Object} * @returns {Object}
*/ */
const styles = theme => { const styles = (theme: any) => {
return { return {
virtualBackgroundPreview: { virtualBackgroundPreview: {
'& .video-preview': { '& .video-preview': {
@ -141,7 +147,7 @@ class VirtualBackgroundPreview extends PureComponent<Props, State> {
* @param {Object} props - The read-only properties with which the new * @param {Object} props - The read-only properties with which the new
* instance is to be initialized. * instance is to be initialized.
*/ */
constructor(props) { constructor(props: Props) {
super(props); super(props);
this.state = { this.state = {
@ -157,7 +163,7 @@ class VirtualBackgroundPreview extends PureComponent<Props, State> {
* @param {Object} jitsiTrack - The track that needs to be disposed. * @param {Object} jitsiTrack - The track that needs to be disposed.
* @returns {Promise<void>} * @returns {Promise<void>}
*/ */
_stopStream(jitsiTrack) { _stopStream(jitsiTrack: any) {
if (jitsiTrack) { if (jitsiTrack) {
jitsiTrack.dispose(); jitsiTrack.dispose();
} }
@ -231,6 +237,7 @@ class VirtualBackgroundPreview extends PureComponent<Props, State> {
return ( return (
<div className = 'video-preview-loader'> <div className = 'video-preview-loader'>
<Spinner <Spinner
// @ts-ignore
invertColor = { true } invertColor = { true }
isCompleting = { false } isCompleting = { false }
size = { 'large' } /> size = { 'large' } />
@ -244,7 +251,7 @@ class VirtualBackgroundPreview extends PureComponent<Props, State> {
* @param {Object} data - The track data. * @param {Object} data - The track data.
* @returns {React$Node} * @returns {React$Node}
*/ */
_renderPreviewEntry(data) { _renderPreviewEntry(data: Object) {
const { t } = this.props; const { t } = this.props;
const className = 'video-background-preview-entry'; const className = 'video-background-preview-entry';
@ -298,7 +305,7 @@ class VirtualBackgroundPreview extends PureComponent<Props, State> {
* *
* @inheritdoc * @inheritdoc
*/ */
async componentDidUpdate(prevProps) { async componentDidUpdate(prevProps: Props) {
if (!equals(this.props._currentCameraDeviceId, prevProps._currentCameraDeviceId)) { if (!equals(this.props._currentCameraDeviceId, prevProps._currentCameraDeviceId)) {
this._setTracks(); this._setTracks();
} }
@ -338,7 +345,7 @@ class VirtualBackgroundPreview extends PureComponent<Props, State> {
* @private * @private
* @returns {{Props}} * @returns {{Props}}
*/ */
function _mapStateToProps(state): Object { function _mapStateToProps(state: IState): Object {
return { return {
_currentCameraDeviceId: getCurrentCameraDeviceId(state) _currentCameraDeviceId: getCurrentCameraDeviceId(state)
}; };