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';
export type Props = {
@ -7,7 +5,7 @@ export type Props = {
/**
* 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.
@ -18,6 +16,6 @@ export type Props = {
/**
* 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> {
}

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 { default as ExpandedLabel } from './ExpandedLabel';
export * from './_';

View File

@ -2,12 +2,12 @@
import React from 'react';
import { Animated, Text } from 'react-native';
import Icon from '../../icons/components/Icon';
import { combineStyles, type StyleType } from '../../styles';
import Icon from '../../../icons/components/Icon';
import { combineStyles, type StyleType } from '../../../styles';
import AbstractLabel, {
type Props as AbstractProps
} from './AbstractLabel';
} from '../AbstractLabel';
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
import { ColorPalette } from '../../styles';
import BaseTheme from '../../ui/components/BaseTheme';
import { ColorPalette } from '../../../styles';
import BaseTheme from '../../../ui/components/BaseTheme';
/**
* 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 clsx from 'clsx';
import React from 'react';
import Icon from '../../icons/components/Icon';
import { withPixelLineHeight } from '../../styles/functions.web';
import { COLORS } from '../constants';
import Icon from '../../../icons/components/Icon';
import { withPixelLineHeight } from '../../../styles/functions.web';
import { COLORS } from '../../constants';
import AbstractLabel, {
type Props as AbstractProps
} from './AbstractLabel';
} from '../AbstractLabel';
type Props = AbstractProps & {
/**
* An object containing the CSS classes.
*/
classes: Object,
/**
* Own CSS class name.
*/
className: string,
/**
* An object containing the CSS classes.
*/
classes: any,
/**
* The color of the label.
*/
color: string,
/**
* HTML ID attribute to add to the root of {@code Label}.
*/
id: string,
/**
* Color for the icon.
*/
iconColor?: string,
/**
* HTML ID attribute to add to the root of {@code Label}.
*/
id: string,
/**
* Click handler if any.
*/
onClick?: Function,
onClick?: (e?: React.MouseEvent) => void,
};
@ -53,7 +51,7 @@ type Props = AbstractProps & {
*
* @returns {Object}
*/
const styles = theme => {
const styles = (theme: any) => {
return {
label: {
...withPixelLineHeight(theme.typography.labelRegular),
@ -96,7 +94,7 @@ const styles = theme => {
*
* @augments Component
*/
class Label extends AbstractLabel<Props, *> {
class Label extends AbstractLabel<Props, any> {
/**
* 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 = {
white: 'white',
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 {
type: PIN_PARTICIPANT,
participant: {

View File

@ -224,7 +224,7 @@ export function getNormalizedDisplayName(name: string) {
* @returns {(Participant|undefined)}
*/
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 { local, localScreenShare, remote } = state;

View File

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

View File

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

View File

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

View File

@ -1,22 +1,28 @@
// @flow
/* eslint-disable lines-around-comment */
import { makeStyles } from '@material-ui/styles';
import clsx from 'clsx';
import React from 'react';
import { useSelector } from 'react-redux';
import { IState } from '../../../app/types';
// @ts-ignore
import { getMultipleVideoSupportFeatureFlag } from '../../../base/config';
import { isMobileBrowser } from '../../../base/environment/utils';
// @ts-ignore
import ConnectionIndicator from '../../../connection-indicator/components/web/ConnectionIndicator';
import { STATS_POPOVER_POSITION, THUMBNAIL_TYPE } from '../../constants';
// @ts-ignore
import { getIndicatorsTooltipPosition } from '../../functions.web';
// @ts-ignore
import PinnedIndicator from './PinnedIndicator';
// @ts-ignore
import RaisedHandIndicator from './RaisedHandIndicator';
// @ts-ignore
import StatusIndicators from './StatusIndicators';
import VideoMenuTriggerButton from './VideoMenuTriggerButton';
declare var interfaceConfig: Object;
declare let interfaceConfig: any;
type Props = {
@ -38,7 +44,7 @@ type Props = {
/**
* 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.
@ -95,9 +101,9 @@ const ThumbnailTopIndicators = ({
const { NORMAL = 16 } = interfaceConfig.INDICATOR_FONT_SIZES || {};
const _indicatorIconSize = NORMAL;
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
|| Boolean(useSelector(state => state['features/base/config'].connectionIndicators?.disabled));
|| Boolean(useSelector((state: IState) => state['features/base/config'].connectionIndicators?.disabled));
const _isMultiStreamEnabled = useSelector(getMultipleVideoSupportFeatureFlag);
const showConnectionIndicator = isHovered || !_connectionIndicatorAutoHideEnabled;

View File

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

View File

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

View File

@ -1,11 +1,11 @@
// @flow
import { createToolbarEvent, sendAnalytics } from '../../analytics';
import { translate } from '../../base/i18n';
import { IconDeviceDocument } from '../../base/icons';
import { connect } from '../../base/redux';
import { AbstractButton, type AbstractButtonProps } from '../../base/toolbox/components';
import { openKeyboardShortcutsDialog } from '../actions';
import { createToolbarEvent, sendAnalytics } from '../../../analytics';
import { translate } from '../../../base/i18n';
import { IconDeviceDocument } from '../../../base/icons';
import { connect } from '../../../base/redux';
import { AbstractButton, type AbstractButtonProps } from '../../../base/toolbox/components';
import { openKeyboardShortcutsDialog } from '../../actions';
/**
* 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 clsx from 'clsx';
import React, { Component } from 'react';
import { WithTranslation } from 'react-i18next';
import { Dialog } from '../../base/dialog';
import { translate } from '../../base/i18n';
// @ts-ignore
import { Dialog } from '../../../base/dialog';
import { translate } from '../../../base/i18n/functions';
/**
* The type of the React {@code Component} props of
* {@link KeyboardShortcutsDialog}.
*/
type Props = {
interface Props extends WithTranslation {
/**
* An object containing the CSS classes.
*/
classes: Object,
classes: any,
/**
* A Map with keyboard keys as keys and translation keys as values.
*/
shortcutDescriptions: Object,
/**
* Invoked to obtain translated strings.
*/
t: Function
};
shortcutDescriptions: Map<string, string>
}
/**
* Creates the styles for the component.
@ -36,7 +31,7 @@ type Props = {
*
* @returns {Object}
*/
const styles = theme => {
const styles = (theme: any) => {
return {
list: {
listStyleType: 'none',
@ -86,7 +81,7 @@ class KeyboardShortcutsDialog extends Component<Props> {
<ul
className = { clsx('shortcuts-list', this.props.classes.list) }
id = 'keyboard-shortcuts-list'>
{ shortcuts }
{shortcuts}
</ul>
</div>
</Dialog>
@ -101,7 +96,7 @@ class KeyboardShortcutsDialog extends Component<Props> {
* @private
* @returns {ReactElement}
*/
_renderShortcutsListItem(keyboardKey, translationKey) {
_renderShortcutsListItem(keyboardKey: string, translationKey: string) {
let modifierKey = 'Alt';
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 { AtlasKitThemeProvider } from '@atlaskit/theme';
import { withStyles } from '@material-ui/styles';
import clsx from 'clsx';
import React, { Component } from 'react';
import { WithTranslation } from 'react-i18next';
import { CSSTransition, TransitionGroup } from 'react-transition-group';
import { translate } from '../../../base/i18n';
import { connect } from '../../../base/redux';
import { translate } from '../../../base/i18n/functions';
import { connect } from '../../../base/redux/functions';
// @ts-ignore
import { hideNotification } from '../../actions';
// @ts-ignore
import { areThereNotifications } from '../../functions';
// @ts-ignore
import Notification from './Notification';
type Props = {
interface Props extends WithTranslation {
/**
* 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
* notification at the top and the rest shown below it in order.
*/
_notifications: Array<Object>,
_notifications: Array<{
props: Object;
uid: number;
}>,
/**
* JSS classes object.
*/
classes: Object,
classes: any,
/**
* 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.
*/
portal?: boolean,
portal?: boolean
}
/**
* Invoked to obtain translated strings.
*/
t: Function
};
const useStyles = theme => {
const useStyles = (theme: any) => {
return {
container: {
position: 'absolute',
@ -124,7 +125,7 @@ const useStyles = theme => {
*/
class NotificationsContainer extends Component<Props> {
_api: Object;
_timeouts: Map<string, TimeoutID>;
_timeouts: Map<string, number>;
/**
* Initializes a new {@code NotificationsContainer} instance.
@ -161,6 +162,7 @@ class NotificationsContainer extends Component<Props> {
return (
<AtlasKitThemeProvider mode = 'light'>
{/* @ts-ignore */}
<FlagGroupContext.Provider value = { this._api }>
<div
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
* stops displaying.
@ -186,12 +186,12 @@ class NotificationsContainer extends Component<Props> {
* @private
* @returns {void}
*/
_onDismissed(uid) {
const timeout = this._timeouts.get(uid);
_onDismissed(uid: number) {
const timeout = this._timeouts.get(`${uid}`);
if (timeout) {
clearTimeout(timeout);
this._timeouts.delete(uid);
this._timeouts.delete(`${uid}`);
}
this.props.dispatch(hideNotification(uid));
@ -238,7 +238,7 @@ class NotificationsContainer extends Component<Props> {
* @private
* @returns {Props}
*/
function _mapStateToProps(state) {
function _mapStateToProps(state: any) {
const { notifications } = state['features/notifications'];
const { iAmSipGateway } = state['features/base/config'];
const { isOpen: isChatOpen } = state['features/chat'];
@ -251,4 +251,5 @@ function _mapStateToProps(state) {
};
}
// @ts-ignore
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 clsx from 'clsx';
import React, { useCallback, useState } from 'react';
import React, { ReactElement, useCallback, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useSelector } from 'react-redux';
import { IState } from '../../../../../app/types';
// @ts-ignore
import { ListItem } from '../../../../../base/components';
import { Icon, IconArrowDown, IconArrowUp } from '../../../../../base/icons';
import { isLocalParticipantModerator } from '../../../../../base/participants';
import Icon from '../../../../../base/icons/components/Icon';
import { IconArrowDown, IconArrowUp } from '../../../../../base/icons/svg/index';
import { isLocalParticipantModerator } from '../../../../../base/participants/functions';
// @ts-ignore
import { showOverflowDrawer } from '../../../../../toolbox/functions.web';
// @ts-ignore
import { ACTION_TRIGGER } from '../../../../constants';
// @ts-ignore
import { participantMatchesSearch } from '../../../../functions';
import ParticipantActionEllipsis from '../../../web/ParticipantActionEllipsis';
// @ts-ignore
import ParticipantItem from '../../../web/ParticipantItem';
type Props = {
@ -25,27 +31,29 @@ type Props = {
/**
* React children.
*/
children: React$Node,
children: ReactElement,
/**
* Is this item highlighted/raised.
*/
isHighlighted?: boolean,
/**
* Callback to raise menu. Used to raise menu on mobile long press.
*/
onRaiseMenu: Function,
/**
* Callback for when the mouse leaves this component.
*/
onLeave?: Function,
/**
* Callback to raise menu. Used to raise menu on mobile long press.
*/
onRaiseMenu: Function,
/**
* The raise context for the participant menu.
*/
participantContextEntity: ?Object,
participantContextEntity?: {
jid: string
},
/**
* Callback to raise participant context menu.
@ -55,7 +63,16 @@ type Props = {
/**
* Room reference.
*/
room: Object,
room: {
id: string;
name: string;
participants: {
[jid: string]: {
displayName: string;
jid: string;
}
};
},
/**
* Participants search string.
@ -68,7 +85,7 @@ type Props = {
toggleParticipantMenu: Function
}
const useStyles = makeStyles(theme => {
const useStyles = makeStyles((theme: any) => {
return {
container: {
boxShadow: 'none'
@ -117,7 +134,7 @@ export const CollapsibleRoom = ({
const raiseMenu = useCallback(target => {
onRaiseMenu(target);
}, [ onRaiseMenu ]);
const { defaultRemoteDisplayName } = useSelector(state => state['features/base/config']);
const { defaultRemoteDisplayName } = useSelector((state: IState) => state['features/base/config']);
const overflowDrawer = useSelector(showOverflowDrawer);
const moderator = useSelector(isLocalParticipantModerator);
@ -153,7 +170,7 @@ export const CollapsibleRoom = ({
textChildren = { roomName }
trigger = { actionsTrigger } />
{!collapsed && room?.participants
&& Object.values(room?.participants || {}).map((p: Object) =>
&& Object.values(room?.participants || {}).map(p =>
participantMatchesSearch(p, searchString) && (
<ParticipantItem
actionsTrigger = { ACTION_TRIGGER.HOVER }
@ -166,6 +183,7 @@ export const CollapsibleRoom = ({
participantID = { p.jid }>
{!overflowDrawer && moderator && (
<ParticipantActionEllipsis
accessibilityLabel = { t('breakoutRoom.more') }
onClick = { toggleParticipantMenu({ room,
jid: p.jid,
participantName: p.displayName }) } />

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,12 +1,11 @@
// @flow
import { makeStyles } from '@material-ui/styles';
import React from 'react';
import { Icon, IconRaisedHandHollow } from '../../../base/icons';
import BaseTheme from '../../../base/ui/components/BaseTheme';
import Icon from '../../../base/icons/components/Icon';
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 {
indicator: {
backgroundColor: theme.palette.warning02,

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,21 +1,26 @@
// @flow
/* eslint-disable lines-around-comment */
import { withStyles } from '@material-ui/core';
import React from 'react';
// @ts-ignore
import { StartRecordingDialog } from '../..';
// @ts-ignore
import { openDialog } from '../../../../base/dialog';
import { translate } from '../../../../base/i18n';
import { IconHighlight } from '../../../../base/icons';
import { translate } from '../../../../base/i18n/functions';
import { IconHighlight } from '../../../../base/icons/svg';
// @ts-ignore
import { Label } from '../../../../base/label';
import { connect } from '../../../../base/redux';
import { connect } from '../../../../base/redux/functions';
// @ts-ignore
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 { FEATURES } from '../../../../jaas/constants';
import { StartRecordingDialog } from '../../../components';
import AbstractHighlightButton, {
_abstractMapStateToProps,
type Props as AbstractProps
// @ts-ignore
} from '../AbstractHighlightButton';
type Props = AbstractProps & {
@ -35,7 +40,7 @@ type Props = AbstractProps & {
/**
* 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.
@ -50,7 +55,7 @@ type Props = AbstractProps & {
*
* @returns {Object}
*/
const styles = theme => {
const styles = (theme: any) => {
return {
container: {
position: 'relative'
@ -100,6 +105,7 @@ export class HighlightButton extends AbstractHighlightButton<Props, State> {
constructor(props: Props) {
super(props);
// @ts-ignore
this.state = {
isNotificationOpen: false
};
@ -132,6 +138,7 @@ export class HighlightButton extends AbstractHighlightButton<Props, State> {
* @returns {void}
*/
async _onOpenDialog() {
// @ts-ignore
const { dispatch } = this.props;
const dialogShown = await dispatch(maybeShowPremiumFeatureDialog(FEATURES.RECORDING));
@ -147,12 +154,14 @@ export class HighlightButton extends AbstractHighlightButton<Props, State> {
* @param {Event} e - The click event.
* @returns {void}
*/
_onClick(e) {
_onClick(e: React.MouseEvent) {
e.stopPropagation();
// @ts-ignore
const { _disabled } = this.props;
if (_disabled) {
// @ts-ignore
this.setState({
isNotificationOpen: true
});
@ -167,6 +176,7 @@ export class HighlightButton extends AbstractHighlightButton<Props, State> {
* @returns {void}
*/
_onWindowClickListener() {
// @ts-ignore
this.setState({
isNotificationOpen: false
});
@ -184,6 +194,7 @@ export class HighlightButton extends AbstractHighlightButton<Props, State> {
_visible,
classes,
t
// @ts-ignore
} = this.props;
@ -206,6 +217,7 @@ export class HighlightButton extends AbstractHighlightButton<Props, State> {
id = 'highlightMeetingLabel'
onClick = { this._onClick } />
</Tooltip>
{/* @ts-ignore */}
{this.state.isNotificationOpen && (
<div className = { classes.highlightNotification }>
{t('recording.highlightMomentDisabled')}
@ -221,4 +233,5 @@ export class HighlightButton extends AbstractHighlightButton<Props, State> {
}
}
// @ts-ignore
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 React from 'react';
import { translate } from '../../../base/i18n';
import { translate } from '../../../base/i18n/functions';
// @ts-ignore
import { Label } from '../../../base/label';
import { JitsiRecordingConstants } from '../../../base/lib-jitsi-meet';
import { connect } from '../../../base/redux';
import { connect } from '../../../base/redux/functions';
import AbstractRecordingLabel, {
_mapStateToProps
// @ts-ignore
} from '../AbstractRecordingLabel';
/**
@ -18,7 +19,7 @@ import AbstractRecordingLabel, {
*
* @returns {Object}
*/
const styles = theme => {
const styles = (theme: any) => {
return {
[JitsiRecordingConstants.mode.STREAM]: {
background: theme.palette.ui03
@ -42,24 +43,26 @@ class RecordingLabel extends AbstractRecordingLabel {
* @inheritdoc
*/
_renderLabel() {
// @ts-ignore
if (this.props._status !== JitsiRecordingConstants.status.ON) {
// Since there are no expanded labels on web, we only render this
// label when the recording status is ON.
return null;
}
// @ts-ignore
const { classes, mode, t } = this.props;
return (
<div>
<Label
className = { classes && classes[mode] }
// @ts-ignore
text = { t(this._getLabelKey()) } />
</div>
);
}
_getLabelKey: () => ?string;
}
// @ts-ignore
export default withStyles(styles)(translate(connect(_mapStateToProps)(RecordingLabel)));

View File

@ -1,8 +1,8 @@
// @flow
import { makeStyles } from '@material-ui/core';
import React from 'react';
import { useTranslation } from 'react-i18next';
// @ts-ignore
import { RECORD_TYPE } from '../../constants';
/**
@ -13,25 +13,25 @@ type Props = {
/**
* The id of the record.
*/
id: String,
id: string,
/**
* The name of the record.
*/
name: String,
/**
* The type of the record.
*/
type: String,
name: string,
/**
* 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 {
recordItem: {
display: 'flex',

View File

@ -1,21 +1,26 @@
// @flow
/* eslint-disable lines-around-comment */
import Spinner from '@atlaskit/spinner';
import { makeStyles } from '@material-ui/core';
import React, { useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { useDispatch } from 'react-redux';
// @ts-ignore
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 BaseTheme from '../../../base/ui/components/BaseTheme';
import BaseTheme from '../../../base/ui/components/BaseTheme.web';
// @ts-ignore
import { NOTES_MAX_LENGTH } from '../../constants';
// @ts-ignore
import { useSalesforceLinkDialog } from '../../useSalesforceLinkDialog';
import { RecordItem } from './RecordItem';
const useStyles = makeStyles(theme => {
// @ts-ignore
const useStyles = makeStyles((theme: any) => {
return {
container: {
minHeight: '450px',
@ -136,7 +141,7 @@ function SalesforceLinkDialog() {
showSearchResults
} = useSalesforceLinkDialog();
const handleChange = useCallback((event: Event) => {
const handleChange = useCallback((event: React.ChangeEvent<HTMLInputElement>) => {
const value = getFieldValue(event);
setSearchTerm(value);
@ -150,6 +155,7 @@ function SalesforceLinkDialog() {
const renderSpinner = () => (
<div className = { classes.spinner }>
<Spinner
// @ts-ignore
isCompleting = { false }
size = 'medium' />
</div>
@ -176,7 +182,7 @@ function SalesforceLinkDialog() {
/* eslint-disable-next-line react/jsx-no-bind */
onChange = { e => setNotes(e.target.value) }
placeholder = { t('dialog.addMeetingNote') }
row = '4'
rows = { 4 }
value = { notes } />
</div>
);
@ -236,7 +242,7 @@ function SalesforceLinkDialog() {
return (
<ul className = { classes.recordList }>
{records.map(item => (
{records.map((item: any) => (
<RecordItem
key = { `record-${item.id}` }
/* 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 React, { Component } from 'react';
import { IState } from '../../../app/types';
// @ts-ignore
import { getAvailableDevices } from '../../../base/devices';
// @ts-ignore
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 {
DeviceSelection,
getDeviceSelectionDialogProps,
submitDeviceSelectionTab
// @ts-ignore
} from '../../../device-selection';
import {
submitModeratorTab,
submitMoreTab,
submitProfileTab,
submitSoundsTab
// @ts-ignore
} from '../../actions';
// @ts-ignore
import { SETTINGS_TABS } from '../../constants';
import {
getModeratorTabProps,
getMoreTabProps,
getProfileTabProps,
getSoundsTabProps
// @ts-ignore
} from '../../functions';
// @ts-ignore
import CalendarTab from './CalendarTab';
import ModeratorTab from './ModeratorTab';
import MoreTab from './MoreTab';
import ProfileTab from './ProfileTab';
import SoundsTab from './SoundsTab';
declare var interfaceConfig: Object;
declare let interfaceConfig: any;
/**
* The type of the React {@code Component} props of
@ -40,6 +48,15 @@ declare var interfaceConfig: Object;
*/
type Props = {
/**
* Information about the tabs to be rendered.
*/
_tabs: Array<{
name: string;
onMount: () => void;
submit: () => void;
}>,
/**
* An object containing the CSS classes.
*/
@ -51,11 +68,6 @@ type Props = {
*/
defaultTab: string,
/**
* Information about the tabs to be rendered.
*/
_tabs: Array<Object>,
/**
* Invoked to save changed settings.
*/
@ -75,7 +87,7 @@ type Props = {
*
* @returns {Object}
*/
const styles = theme => {
const styles = (theme: any) => {
return {
settingsDialog: {
display: 'flex',
@ -110,6 +122,7 @@ const styles = theme => {
color: '#9FB0CC'
},
// @ts-ignore
[[ '& .calendar-tab',
'& .more-tab',
'& .box' ]]: {
@ -225,9 +238,11 @@ class SettingsDialog extends Component<Props> {
return {
...tab,
onMount: tab.onMount
? (...args) => dispatch(tab.onMount(...args))
// @ts-ignore
? (...args: any) => dispatch(tab.onMount(...args))
: undefined,
submit: (...args) => tab.submit
submit: (...args: any) => tab.submit
// @ts-ignore
&& dispatch(tab.submit(...args))
};
});
@ -245,8 +260,6 @@ class SettingsDialog extends Component<Props> {
);
}
_closeDialog: () => void;
/**
* Callback invoked to close the dialog without saving changes.
*
@ -269,7 +282,7 @@ class SettingsDialog extends Component<Props> {
* tabs: Array<Object>
* }}
*/
function _mapStateToProps(state, ownProps) {
function _mapStateToProps(state: IState, ownProps: any) {
const { classes, isDisplayedOnWelcomePage } = ownProps;
const configuredTabs = interfaceConfig.SETTINGS_SECTIONS || [];
@ -293,7 +306,7 @@ function _mapStateToProps(state, ownProps) {
label: 'settings.devices',
onMount: getAvailableDevices,
props: getDeviceSelectionDialogProps(state, isDisplayedOnWelcomePage),
propsUpdateFunction: (tabState, newProps) => {
propsUpdateFunction: (tabState: any, newProps: any) => {
// Ensure the device selection tab gets updated when new devices
// are found by taking the new props and only preserving 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`,
submit: newState => submitDeviceSelectionTab(newState, isDisplayedOnWelcomePage)
submit: (newState: any) => submitDeviceSelectionTab(newState, isDisplayedOnWelcomePage)
});
}
@ -329,7 +342,7 @@ function _mapStateToProps(state, ownProps) {
component: ModeratorTab,
label: 'settings.moderator',
props: moderatorTabProps,
propsUpdateFunction: (tabState, newProps) => {
propsUpdateFunction: (tabState: any, newProps: any) => {
// Updates tab props, keeping users selection
return {
@ -371,7 +384,7 @@ function _mapStateToProps(state, ownProps) {
component: MoreTab,
label: 'settings.more',
props: moreTabProps,
propsUpdateFunction: (tabState, newProps) => {
propsUpdateFunction: (tabState: any, newProps: any) => {
// Updates tab props, keeping users selection
return {

View File

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

View File

@ -1,12 +1,12 @@
/* @flow */
import { makeStyles } from '@material-ui/core/styles';
import React from 'react';
import { useTranslation } from 'react-i18next';
// @ts-ignore
import { Tooltip } from '../../../base/tooltip';
import { FACE_EXPRESSIONS_EMOJIS } from '../../../face-landmarks/constants';
const useStyles = makeStyles(theme => {
const useStyles = makeStyles((theme: any) => {
return {
labels: {
padding: '22px 0 7px 0',
@ -34,22 +34,6 @@ type Props = {
const SpeakerStatsLabels = (props: Props) => {
const { t } = useTranslation();
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${
props.showFaceExpressions ? ' name-time_expressions-on' : ''
}`;
@ -69,7 +53,22 @@ const SpeakerStatsLabels = (props: Props) => {
{
props.showFaceExpressions
&& <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>

View File

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

View File

@ -1,22 +1,20 @@
// @flow
import { makeStyles } from '@material-ui/core';
import React, { useCallback } from 'react';
import React, { ReactElement, useCallback } from 'react';
import { DRAWER_MAX_HEIGHT } from '../../constants';
type Props = {
/**
* Class name for custom styles.
*/
className: string,
/**
* 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.
@ -29,7 +27,7 @@ type Props = {
onClose: Function
};
const useStyles = makeStyles(theme => {
const useStyles = makeStyles((theme: any) => {
return {
drawer: {
backgroundColor: theme.palette.ui02,

View File

@ -1,25 +1,30 @@
/* @flow */
/* eslint-disable lines-around-comment */
import InlineDialog from '@atlaskit/inline-dialog';
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 { translate } from '../../../base/i18n';
import { connect } from '../../../base/redux';
import { translate } from '../../../base/i18n/functions';
import { connect } from '../../../base/redux/functions';
// @ts-ignore
import { ReactionEmoji, ReactionsMenu } from '../../../reactions/components';
import { type ReactionEmojiProps, REACTIONS_MENU_HEIGHT } from '../../../reactions/constants';
import { getReactionsQueue } from '../../../reactions/functions.any';
import { DRAWER_MAX_HEIGHT } from '../../constants';
// @ts-ignore
import Drawer from './Drawer';
// @ts-ignore
import JitsiPortal from './JitsiPortal';
// @ts-ignore
import OverflowToggleButton from './OverflowToggleButton';
/**
* 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.
@ -29,12 +34,12 @@ type Props = {
/**
* A child React Element to display within {@code InlineDialog}.
*/
children: React$Node,
children: ReactElement,
/**
* An object containing the CSS classes.
*/
classes: Object,
classes: any,
/**
* Whether or not the OverflowMenu popover should display.
@ -51,11 +56,6 @@ type Props = {
*/
overflowDrawer: boolean,
/**
* Invoked to obtain translated strings.
*/
t: Function,
/**
* The array of reactions to be displayed.
*/
@ -65,7 +65,7 @@ type Props = {
* Whether or not to display the reactions in the mobile menu.
*/
showMobileReactions: boolean
};
}
const styles = () => {
return {
@ -98,15 +98,13 @@ class OverflowMenuButton extends Component<Props> {
this._onEscClick = this._onEscClick.bind(this);
}
_onEscClick: (KeyboardEvent) => void;
/**
* Click handler for the more actions entries.
*
* @param {KeyboardEvent} event - Esc key click to close the popup.
* @returns {void}
*/
_onEscClick(event) {
_onEscClick(event: React.KeyboardEvent) {
if (event.key === 'Escape' && this.props.isOpen) {
event.preventDefault();
event.stopPropagation();
@ -136,10 +134,12 @@ class OverflowMenuButton extends Component<Props> {
<Drawer
isOpen = { isOpen }
onClose = { this._onCloseDialog }>
<div className = { classes.overflowMenuDrawer }>
{children}
</div>
{showMobileReactions && <ReactionsMenu overflowMenu = { true } />}
<>
<div className = { classes.overflowMenuDrawer }>
{children}
</div>
{showMobileReactions && <ReactionsMenu overflowMenu = { true } />}
</>
</Drawer>
{showMobileReactions && <div className = 'reactions-animations-container'>
{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
* close.
@ -180,8 +178,6 @@ class OverflowMenuButton extends Component<Props> {
this.props.onVisibilityChange(false);
}
_toggleDialogVisibility: () => void;
/**
* Callback invoked to signal that an event has occurred that should change
* the visibility of the {@code InlineDialog} component.
@ -203,7 +199,7 @@ class OverflowMenuButton extends Component<Props> {
* @param {Object} state - The Redux state.
* @returns {Props}
*/
function mapStateToProps(state) {
function mapStateToProps(state: any) {
const { overflowDrawer } = state['features/toolbox'];
return {
@ -212,4 +208,5 @@ function mapStateToProps(state) {
};
}
// @ts-ignore
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 React, { Component } from 'react';
import { WithTranslation } from 'react-i18next';
import { batch } from 'react-redux';
// @ts-ignore
import keyboardShortcut from '../../../../../modules/keyboardshortcut/keyboardshortcut';
import {
ACTION_SHORTCUT_TRIGGERED,
createShortcutEvent,
createToolbarEvent,
sendAnalytics
// @ts-ignore
} from '../../../analytics';
// @ts-ignore
import { ContextMenu, ContextMenuItemGroup } from '../../../base/components';
// @ts-ignore
import { getMultipleVideoSendingSupportFeatureFlag, getToolbarButtons } from '../../../base/config';
// @ts-ignore
import { isToolbarButtonEnabled } from '../../../base/config/functions.web';
// @ts-ignore
import { openDialog, toggleDialog } from '../../../base/dialog';
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 {
getLocalParticipant,
hasRaisedHand,
raiseHand
} from '../../../base/participants';
import { connect } from '../../../base/redux';
} from '../../../base/participants/actions';
import {
getLocalParticipant,
hasRaisedHand
} from '../../../base/participants/functions';
import { connect } from '../../../base/redux/functions';
// @ts-ignore
import { getLocalVideoTrack } from '../../../base/tracks';
// @ts-ignore
import { toggleChat } from '../../../chat';
// @ts-ignore
import { ChatButton } from '../../../chat/components';
// @ts-ignore
import { EmbedMeetingButton } from '../../../embed-meeting';
// @ts-ignore
import { SharedDocumentButton } from '../../../etherpad';
// @ts-ignore
import { FeedbackButton } from '../../../feedback';
// @ts-ignore
import { setGifMenuVisibility } from '../../../gifs/actions';
// @ts-ignore
import { isGifEnabled } from '../../../gifs/functions';
// @ts-ignore
import { InviteButton } from '../../../invite/components/add-people-dialog';
// @ts-ignore
import { isVpaasMeeting } from '../../../jaas/functions';
// @ts-ignore
import { KeyboardShortcutsButton } from '../../../keyboard-shortcuts';
import { NoiseSuppressionButton } from '../../../noise-suppression/components';
import {
close as closeParticipantsPane,
open as openParticipantsPane
// @ts-ignore
} from '../../../participants-pane/actions';
// @ts-ignore
import { ParticipantsPaneButton } from '../../../participants-pane/components/web';
// @ts-ignore
import { getParticipantsPaneOpen } from '../../../participants-pane/functions';
import { addReactionToBuffer } from '../../../reactions/actions.any';
import { toggleReactionsMenuVisibility } from '../../../reactions/actions.web';
import { ReactionsMenuButton } from '../../../reactions/components';
import ReactionsMenuButton from '../../../reactions/components/web/ReactionsMenuButton';
import { REACTIONS } from '../../../reactions/constants';
import { isReactionsEnabled } from '../../../reactions/functions.any';
import {
LiveStreamButton,
RecordButton
// @ts-ignore
} from '../../../recording';
// @ts-ignore
import { isSalesforceEnabled } from '../../../salesforce/functions';
import {
isScreenAudioSupported,
isScreenVideoShared,
ShareAudioButton,
startScreenShareFlow
} from '../../../screen-share/';
// @ts-ignore
} from '../../../screen-share';
// @ts-ignore
import SecurityDialogButton from '../../../security/components/security-dialog/web/SecurityDialogButton';
// @ts-ignore
import { SettingsButton } from '../../../settings';
// @ts-ignore
import { SharedVideoButton } from '../../../shared-video/components';
// @ts-ignore
import { SpeakerStatsButton } from '../../../speaker-stats/components/web';
import {
ClosedCaptionButton
// @ts-ignore
} from '../../../subtitles';
import {
TileViewButton,
shouldDisplayTileView,
toggleTileView
// @ts-ignore
} from '../../../video-layout';
// @ts-ignore
import { VideoQualityDialog, VideoQualityButton } from '../../../video-quality/components';
// @ts-ignore
import { VideoBackgroundButton, toggleBackgroundEffect } from '../../../virtual-background';
import { VIRTUAL_BACKGROUND_TYPE } from '../../../virtual-background/constants';
import {
@ -78,29 +111,45 @@ import {
setOverflowMenuVisible,
setToolbarHovered,
showToolbox
// @ts-ignore
} from '../../actions';
import { THRESHOLDS, NOT_APPLICABLE, NOTIFY_CLICK_MODE } from '../../constants';
// @ts-ignore
import { isDesktopShareButtonDisabled, isToolboxVisible } from '../../functions';
// @ts-ignore
import DownloadButton from '../DownloadButton';
// @ts-ignore
import HangupButton from '../HangupButton';
// @ts-ignore
import HelpButton from '../HelpButton';
// @ts-ignore
import AudioSettingsButton from './AudioSettingsButton';
// @ts-ignore
import DockIframeButton from './DockIframeButton';
// @ts-ignore
import FullscreenButton from './FullscreenButton';
// @ts-ignore
import LinkToSalesforceButton from './LinkToSalesforceButton';
// @ts-ignore
import OverflowMenuButton from './OverflowMenuButton';
// @ts-ignore
import ProfileButton from './ProfileButton';
// @ts-ignore
import Separator from './Separator';
// @ts-ignore
import ShareDesktopButton from './ShareDesktopButton';
// @ts-ignore
import ToggleCameraButton from './ToggleCameraButton';
// @ts-ignore
import UndockIframeButton from './UndockIframeButton';
// @ts-ignore
import VideoSettingsButton from './VideoSettingsButton';
/**
* 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.
@ -110,7 +159,10 @@ type Props = {
/**
* 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.
@ -248,39 +300,33 @@ type Props = {
*/
_toolbarButtons: Array<string>,
/**
* Returns the selected virtual source object.
*/
_virtualSource: any,
/**
* Flag showing whether toolbar is visible.
*/
_visible: boolean,
/**
* Returns the selected virtual source object.
*/
_virtualSource: Object,
/**
* An object containing the CSS classes.
*/
classes: Object,
classes: any,
/**
* Invoked to active other features of the app.
*/
dispatch: Function,
/**
* Invoked to obtain translated strings.
*/
t: Function,
/**
* Explicitly passed array with the buttons which this Toolbox should display.
*/
toolbarButtons: Array<string>,
}
};
declare var APP: Object;
declare let APP: any;
const styles = () => {
return {
@ -435,7 +481,7 @@ class Toolbox extends Component<Props> {
*
* @inheritdoc
*/
componentDidUpdate(prevProps) {
componentDidUpdate(prevProps: Props) {
const { _dialog, dispatch } = this.props;
@ -488,15 +534,13 @@ class Toolbox extends Component<Props> {
);
}
_onEscKey: (KeyboardEvent) => void;
/**
* Key handler for overflow menu.
*
* @param {KeyboardEvent} e - Esc key click to close the popup.
* @returns {void}
*/
_onEscKey(e) {
_onEscKey(e: React.KeyboardEvent) {
if (e.key === 'Escape') {
e.stopPropagation();
this._closeOverflowMenuIfOpen();
@ -870,9 +914,9 @@ class Toolbox extends Component<Props> {
* @param {string} btnName - The toolbar button's name.
* @returns {string|undefined} - The button's notify mode.
*/
_getButtonNotifyMode(btnName) {
_getButtonNotifyMode(btnName: string) {
const notify = this.props._buttonsWithNotifyClick?.find(
(btn: string | Object) =>
btn =>
(typeof btn === 'string' && btn === btnName)
|| (typeof btn === 'object' && btn.key === btnName)
);
@ -890,7 +934,7 @@ class Toolbox extends Component<Props> {
* @param {Object} buttons - The list of toolbar buttons.
* @returns {void}
*/
_setButtonsNotifyClickMode(buttons) {
_setButtonsNotifyClickMode(buttons: Object) {
if (typeof APP === 'undefined' || !this.props._buttonsWithNotifyClick?.length) {
return;
}
@ -926,7 +970,7 @@ class Toolbox extends Component<Props> {
const keys = Object.keys(buttons);
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]))
].filter(Boolean).filter(({ key, alias = NOT_APPLICABLE }) =>
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.
*
@ -960,8 +1002,6 @@ class Toolbox extends Component<Props> {
!_overflowMenuVisible && dispatch(setToolbarHovered(false));
}
_onMouseOver: () => void;
/**
* Dispatches an action signaling the toolbar is being hovered.
*
@ -972,9 +1012,6 @@ class Toolbox extends Component<Props> {
this.props.dispatch(setToolbarHovered(true));
}
_onSetOverflowVisible: (boolean) => void;
/**
* Sets the visibility of the overflow menu.
*
@ -983,13 +1020,11 @@ class Toolbox extends Component<Props> {
* @private
* @returns {void}
*/
_onSetOverflowVisible(visible) {
_onSetOverflowVisible(visible: boolean) {
this.props.dispatch(setOverflowMenuVisible(visible));
this.props.dispatch(setToolbarHovered(visible));
}
_onShortcutToggleChat: () => void;
/**
* Creates an analytics keyboard shortcut event and dispatches an action for
* toggling the display of chat.
@ -1007,15 +1042,13 @@ class Toolbox extends Component<Props> {
// Checks if there was any text selected by the user.
// Used for when we press simultaneously keys for copying
// text messages from the chat board
if (window.getSelection().toString() !== '') {
if (window.getSelection()?.toString() !== '') {
return false;
}
this._doToggleChat();
}
_onShortcutToggleParticipantsPane: () => void;
/**
* Creates an analytics keyboard shortcut event and dispatches an action for
* toggling the display of the participants pane.
@ -1033,8 +1066,6 @@ class Toolbox extends Component<Props> {
this._onToolbarToggleParticipantsPane();
}
_onShortcutToggleVideoQuality: () => void;
/**
* Creates an analytics keyboard shortcut event and dispatches an action for
* toggling the display of Video Quality.
@ -1048,8 +1079,6 @@ class Toolbox extends Component<Props> {
this._doToggleVideoQuality();
}
_onShortcutToggleTileView: () => void;
/**
* Dispatches an action for toggling the tile view.
*
@ -1066,8 +1095,6 @@ class Toolbox extends Component<Props> {
this._doToggleTileView();
}
_onShortcutToggleFullScreen: () => void;
/**
* Creates an analytics keyboard shortcut event and dispatches an action for
* toggling full screen mode.
@ -1085,8 +1112,6 @@ class Toolbox extends Component<Props> {
this._doToggleFullScreen();
}
_onShortcutToggleRaiseHand: () => void;
/**
* Creates an analytics keyboard shortcut event and dispatches an action for
* toggling raise hand.
@ -1103,8 +1128,6 @@ class Toolbox extends Component<Props> {
this._doToggleRaiseHand();
}
_onShortcutToggleScreenshare: () => void;
/**
* Creates an analytics keyboard shortcut event and dispatches an action for
* toggling screensharing.
@ -1127,7 +1150,6 @@ class Toolbox extends Component<Props> {
this._doToggleScreenshare();
}
_onTabIn: () => void;
/**
* Toggle the toolbar visibility when tabbing into it.
@ -1139,7 +1161,6 @@ class Toolbox extends Component<Props> {
this.props.dispatch(showToolbox());
}
}
_onToolbarToggleParticipantsPane: () => void;
/**
* 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
* open the video quality dialog.
@ -1172,8 +1191,6 @@ class Toolbox extends Component<Props> {
this._doOpenVideoQuality();
}
_onToolbarToggleChat: () => void;
/**
* Creates an analytics toolbar event and dispatches an action for toggling
* the display of chat.
@ -1191,8 +1208,6 @@ class Toolbox extends Component<Props> {
this._doToggleChat();
}
_onToolbarToggleFullScreen: () => void;
/**
* Creates an analytics toolbar event and dispatches an action for toggling
* full screen mode.
@ -1210,8 +1225,6 @@ class Toolbox extends Component<Props> {
this._doToggleFullScreen();
}
_onToolbarToggleRaiseHand: () => void;
/**
* Creates an analytics toolbar event and dispatches an action for toggling
* raise hand.
@ -1227,8 +1240,6 @@ class Toolbox extends Component<Props> {
this._doToggleRaiseHand();
}
_onToolbarToggleScreenshare: () => void;
/**
* Creates an analytics toolbar event and dispatches an action for toggling
* screensharing.
@ -1357,9 +1368,9 @@ class Toolbox extends Component<Props> {
}
return acc;
}, []).map(buttonGroup => (
}, []).map((buttonGroup: any) => (
<ContextMenuItemGroup key = { `group-${buttonGroup[0].group}` }>
{buttonGroup.map(({ key, Content, ...rest }) => (
{buttonGroup.map(({ key, Content, ...rest }: any) => (
key !== 'raisehand' || !_reactionsEnabled)
&& <Content
{ ...rest }
@ -1394,7 +1405,7 @@ class Toolbox extends Component<Props> {
* @private
* @returns {{}}
*/
function _mapStateToProps(state, ownProps) {
function _mapStateToProps(state: any, ownProps: Partial<Props>) {
const { conference } = state['features/base/conference'];
const {
buttonsWithNotifyClick,
@ -1447,4 +1458,5 @@ function _mapStateToProps(state, ownProps) {
};
}
// @ts-ignore
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 React, { useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { useDispatch, useSelector } from 'react-redux';
import { IState } from '../../../app/types';
// @ts-ignore
import { isSupported as isAvModerationSupported } from '../../../av-moderation/functions';
// @ts-ignore
import { Avatar } from '../../../base/avatar';
// @ts-ignore
import ContextMenu from '../../../base/components/context-menu/ContextMenu';
// @ts-ignore
import ContextMenuItemGroup from '../../../base/components/context-menu/ContextMenuItemGroup';
import { isIosMobileBrowser, isMobileBrowser } from '../../../base/environment/utils';
import { IconShareVideo } from '../../../base/icons';
import { MEDIA_TYPE } from '../../../base/media';
import { getLocalParticipant, PARTICIPANT_ROLE } from '../../../base/participants';
import { IconShareVideo } from '../../../base/icons/svg/index';
import { MEDIA_TYPE } from '../../../base/media/constants';
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';
// @ts-ignore
import { getBreakoutRooms, getCurrentRoomId, isInBreakoutRoom } from '../../../breakout-rooms/functions';
// @ts-ignore
import { setVolume } from '../../../filmstrip/actions.web';
// @ts-ignore
import { isStageFilmstripAvailable } from '../../../filmstrip/functions.web';
// @ts-ignore
import { isForceMuted } from '../../../participants-pane/functions';
// @ts-ignore
import { requestRemoteControl, stopController } from '../../../remote-control';
// @ts-ignore
import { stopSharedVideo } from '../../../shared-video/actions.any';
// @ts-ignore
import { showOverflowDrawer } from '../../../toolbox/functions.web';
// @ts-ignore
import { REMOTE_CONTROL_MENU_STATES } from './RemoteControlButton';
// @ts-ignore
import SendToRoomButton from './SendToRoomButton';
import {
@ -38,6 +54,7 @@ import {
RemoteControlButton,
TogglePinToStageButton,
VolumeSlider
// @ts-ignore
} from './';
type Props = {
@ -56,7 +73,10 @@ type Props = {
* The participant for which the drawer is open.
* It contains the displayName & participantID.
*/
drawerParticipant?: Object,
drawerParticipant?: {
displayName: string;
participantID: string;
},
/**
* Shared video local participant owner.
@ -86,7 +106,7 @@ type Props = {
/**
* Participant reference.
*/
participant: Object,
participant: Participant,
/**
* 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.
*/
thumbnailMenu: ?boolean
thumbnailMenu?: boolean
}
const useStyles = makeStyles(theme => {
const useStyles = makeStyles((theme: any) => {
return {
text: {
color: theme.palette.text02,
@ -139,9 +159,9 @@ const ParticipantContextMenu = ({
const _isAudioMuted = useSelector(state => isParticipantAudioMuted(participant, state));
const _overflowDrawer = useSelector(showOverflowDrawer);
const { remoteVideoMenu = {}, disableRemoteMute, startSilent }
= useSelector(state => state['features/base/config']);
= useSelector((state: IState) => state['features/base/config']);
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
: participant?.id ? participantsVolume[participant?.id] : undefined) ?? 1;
const isBreakoutRoom = useSelector(isInBreakoutRoom);
@ -149,7 +169,7 @@ const ParticipantContextMenu = ({
const stageFilmstrip = useSelector(isStageFilmstripAvailable);
const _currentRoomId = useSelector(getCurrentRoomId);
const _rooms = Object.values(useSelector(getBreakoutRooms));
const _rooms: Array<{id: string}> = Object.values(useSelector(getBreakoutRooms));
const _onVolumeChange = useCallback(value => {
dispatch(setVolume(participant.id, value));
@ -273,10 +293,10 @@ const ParticipantContextMenu = ({
);
}
const breakoutRoomsButtons = [];
const breakoutRoomsButtons: any = [];
if (!thumbnailMenu && _isModerator) {
_rooms.forEach((room: Object) => {
_rooms.forEach(room => {
if (room.id !== _currentRoomId) {
breakoutRoomsButtons.push(
<SendToRoomButton

View File

@ -9,6 +9,7 @@ import { isMobileBrowser } from '../../../base/environment/utils';
import { translate } from '../../../base/i18n';
import { IconHorizontalPoints } from '../../../base/icons/svg/index';
import { getParticipantById } from '../../../base/participants/functions';
import { Participant } from '../../../base/participants/reducer';
// @ts-ignore
import { Popover } from '../../../base/popover';
// @ts-ignore
@ -57,7 +58,7 @@ interface Props extends WithTranslation {
/**
* Participant reference.
*/
_participant: Object,
_participant: Participant,
/**
* 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 clsx from 'clsx';
import React, { Component } from 'react';
import { WithTranslation } from 'react-i18next';
import { translate } from '../../../base/i18n';
import { Icon, IconVolume } from '../../../base/icons';
import { translate } from '../../../base/i18n/functions';
import Icon from '../../../base/icons/components/Icon';
import { IconVolume } from '../../../base/icons/svg/index';
// @ts-ignore
import { VOLUME_SLIDER_SCALE } from '../../constants';
/**
* The type of the React {@code Component} props of {@link VolumeSlider}.
*/
type Props = {
interface Props extends WithTranslation {
/**
* An object containing the CSS classes.
*/
classes: Object,
classes: any,
/**
* 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.
*/
onChange: Function,
/**
* Invoked to obtain translated strings.
*/
t: Function
};
onChange: Function
}
/**
* The type of the React {@code Component} state of {@link VolumeSlider}.
@ -48,7 +45,7 @@ type State = {
volumeLevel: number
};
const styles = theme => {
const styles = (theme: any) => {
return {
container: {
minHeight: '40px',
@ -116,7 +113,7 @@ class VolumeSlider extends Component<Props, State> {
* @param {MouseEvent} e - Click event.
* @returns {void}
*/
_onClick(e) {
_onClick(e: React.MouseEvent) {
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.
* Invokes the prop onVolumeChange to notify of volume changes.
@ -166,12 +161,13 @@ class VolumeSlider extends Component<Props, State> {
* @private
* @returns {void}
*/
_onVolumeChange(event) {
const volumeLevel = event.currentTarget.value;
_onVolumeChange(event: React.ChangeEvent<HTMLInputElement>) {
const volumeLevel = Number(event.currentTarget.value);
this.props.onChange(volumeLevel / VOLUME_SLIDER_SCALE);
this.setState({ volumeLevel });
}
}
// @ts-ignore
export default translate(withStyles(styles)(VolumeSlider));

View File

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

View File

@ -2,7 +2,7 @@ import React, { Component } from 'react';
import { Dialog } from '../../base/dialog';
import VideoQualitySlider from './VideoQualitySlider';
import VideoQualitySlider from './VideoQualitySlider.web';
/**
* 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 clsx from 'clsx';
import React, { Component } from 'react';
import { WithTranslation } from 'react-i18next';
import type { Dispatch } from 'redux';
// @ts-ignore
import { createToolbarEvent, sendAnalytics } from '../../analytics';
// @ts-ignore
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 { connect } from '../../base/redux';
import { connect } from '../../base/redux/functions';
import { withPixelLineHeight } from '../../base/styles/functions.web';
// @ts-ignore
import { setPreferredVideoQuality } from '../actions';
// @ts-ignore
import { DEFAULT_LAST_N, VIDEO_QUALITY_LEVELS } from '../constants';
// @ts-ignore
import logger from '../logger';
import Slider from './Slider';
@ -31,7 +38,7 @@ const {
* @returns {Object} The event in a format suitable for sending via
* sendAnalytics.
*/
const createEvent = function(quality) {
const createEvent = function(quality: string) {
return createToolbarEvent(
'video.quality',
{
@ -42,7 +49,7 @@ const createEvent = function(quality) {
/**
* 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.
@ -65,22 +72,16 @@ type Props = {
*/
_sendrecvVideoQuality: Number,
/**
/**
* An object containing the CSS classes.
*/
classes: Object,
classes: any,
/**
* Invoked to request toggling of audio only mode.
*/
dispatch: Dispatch<any>,
/**
* Invoked to obtain translated strings.
*/
t: Function
};
dispatch: Dispatch<any>
}
/**
* Creates the styles for the component.
@ -89,7 +90,7 @@ type Props = {
*
* @returns {Object}
*/
const styles = theme => {
const styles = (theme: any) => {
return {
dialog: {
color: theme.palette.text01
@ -128,7 +129,7 @@ class VideoQualitySlider extends Component<Props> {
* @param {Object} props - The read-only React Component props with which
* the new instance is to be initialized.
*/
constructor(props) {
constructor(props: Props) {
super(props);
// 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.
*
@ -217,8 +216,6 @@ class VideoQualitySlider extends Component<Props> {
this.props.dispatch(setAudioOnly(true));
}
_enableHighDefinition: () => void;
/**
* Handles the action of the high definition video being selected.
* Dispatches an action to receive high quality video from remote
@ -233,8 +230,6 @@ class VideoQualitySlider extends Component<Props> {
this._setPreferredVideoQuality(HIGH);
}
_enableLowDefinition: () => void;
/**
* Dispatches an action to receive low quality video from remote
* participants.
@ -248,8 +243,6 @@ class VideoQualitySlider extends Component<Props> {
this._setPreferredVideoQuality(LOW);
}
_enableStandardDefinition: () => void;
/**
* Dispatches an action to receive standard quality video from remote
* participants.
@ -263,8 +256,6 @@ class VideoQualitySlider extends Component<Props> {
this._setPreferredVideoQuality(STANDARD);
}
_enableUltraHighDefinition: () => void;
/**
* Dispatches an action to receive ultra HD quality video from remote
* participants.
@ -291,12 +282,14 @@ class VideoQualitySlider extends Component<Props> {
if (_audioOnly) {
const audioOnlyOption = _sliderOptions.find(
({ audioOnly }) => audioOnly);
({ audioOnly }: any) => audioOnly);
// @ts-ignore
return _sliderOptions.indexOf(audioOnlyOption);
}
for (let i = 0; i < _sliderOptions.length; i++) {
// @ts-ignore
if (_sliderOptions[i].videoQuality >= _sendrecvVideoQuality) {
return i;
}
@ -305,8 +298,6 @@ class VideoQualitySlider extends Component<Props> {
return -1;
}
_onSliderChange: () => void;
/**
* Invokes a callback when the selected video quality changes.
*
@ -314,13 +305,16 @@ class VideoQualitySlider extends Component<Props> {
* @private
* @returns {void}
*/
_onSliderChange(event) {
_onSliderChange(event: React.ChangeEvent<HTMLInputElement>) {
const { _audioOnly, _sendrecvVideoQuality } = this.props;
const {
// @ts-ignore
audioOnly,
// @ts-ignore
onSelect,
// @ts-ignore
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
// or video quality state.
@ -341,7 +335,7 @@ class VideoQualitySlider extends Component<Props> {
* @private
* @returns {void}
*/
_setPreferredVideoQuality(qualityLevel) {
_setPreferredVideoQuality(qualityLevel: number) {
this.props.dispatch(setPreferredVideoQuality(qualityLevel));
if (this.props._audioOnly) {
this.props.dispatch(setAudioOnly(false));
@ -366,7 +360,7 @@ class VideoQualitySlider extends Component<Props> {
* @private
* @returns {Props}
*/
function _mapStateToProps(state) {
function _mapStateToProps(state: any) {
const { enabled: audioOnly } = state['features/base/audio-only'];
const { p2p } = state['features/base/conference'];
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 React, { useCallback, useRef } from 'react';
import { WithTranslation } from 'react-i18next';
import { v4 as uuidv4 } from 'uuid';
import { translate } from '../../base/i18n';
import { Icon, IconPlusCircle } from '../../base/icons';
import { translate } from '../../base/i18n/functions';
import Icon from '../../base/icons/components/Icon';
import { IconPlusCircle } from '../../base/icons/svg/index';
import { VIRTUAL_BACKGROUND_TYPE, type Image } from '../constants';
// @ts-ignore
import { resizeImage } from '../functions';
// @ts-ignore
import logger from '../logger';
type Props = {
interface Props extends WithTranslation {
/**
* Callback used to set the 'loading' state of the parent component.
@ -27,23 +30,19 @@ type Props = {
*/
setStoredImages: Function,
/**
* A list of images locally stored.
*/
storedImages: Array<Image>,
/**
* If a label should be displayed alongside the button.
*/
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 {
addBackground: {
marginRight: `${theme.spacing(2)}px`
@ -80,7 +79,7 @@ function UploadImageButton({
t
}: Props) {
const classes = useStyles();
const uploadImageButton: Object = useRef(null);
const uploadImageButton = useRef<HTMLInputElement>(null);
const uploadImageKeyPress = useCallback(e => {
if (uploadImageButton.current && (e.key === ' ' || e.key === 'Enter')) {
e.preventDefault();

View File

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

View File

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