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:
parent
94dc6309de
commit
dfb2a07cfa
|
@ -1,5 +1,3 @@
|
||||||
// @flow
|
|
||||||
|
|
||||||
import { Component } from 'react';
|
import { Component } from 'react';
|
||||||
|
|
||||||
export type Props = {
|
export type Props = {
|
||||||
|
@ -7,7 +5,7 @@ export type Props = {
|
||||||
/**
|
/**
|
||||||
* An SVG icon to be rendered as the content of the label.
|
* An SVG icon to be rendered as the content of the label.
|
||||||
*/
|
*/
|
||||||
icon: Component<any>,
|
icon: Function,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* String or component that will be rendered as the label itself.
|
* String or component that will be rendered as the label itself.
|
||||||
|
@ -18,6 +16,6 @@ export type Props = {
|
||||||
/**
|
/**
|
||||||
* Abstract class for the {@code Label} component.
|
* Abstract class for the {@code Label} component.
|
||||||
*/
|
*/
|
||||||
export default class Label<P: Props, S: *>
|
export default class Label<P extends Props, S>
|
||||||
extends Component<P, S> {
|
extends Component<P, S> {
|
||||||
}
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
export * from './native';
|
|
@ -0,0 +1 @@
|
||||||
|
export * from './web';
|
|
@ -1,2 +1 @@
|
||||||
export { default as Label } from './Label';
|
export * from './_';
|
||||||
export { default as ExpandedLabel } from './ExpandedLabel';
|
|
||||||
|
|
|
@ -2,12 +2,12 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Animated, Text } from 'react-native';
|
import { Animated, Text } from 'react-native';
|
||||||
|
|
||||||
import Icon from '../../icons/components/Icon';
|
import Icon from '../../../icons/components/Icon';
|
||||||
import { combineStyles, type StyleType } from '../../styles';
|
import { combineStyles, type StyleType } from '../../../styles';
|
||||||
|
|
||||||
import AbstractLabel, {
|
import AbstractLabel, {
|
||||||
type Props as AbstractProps
|
type Props as AbstractProps
|
||||||
} from './AbstractLabel';
|
} from '../AbstractLabel';
|
||||||
|
|
||||||
import styles from './styles';
|
import styles from './styles';
|
||||||
|
|
||||||
/**
|
/**
|
|
@ -0,0 +1,2 @@
|
||||||
|
export { default as Label } from './Label';
|
||||||
|
export { default as ExpandedLabel } from './ExpandedLabel';
|
|
@ -1,7 +1,7 @@
|
||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
import { ColorPalette } from '../../styles';
|
import { ColorPalette } from '../../../styles';
|
||||||
import BaseTheme from '../../ui/components/BaseTheme';
|
import BaseTheme from '../../../ui/components/BaseTheme';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The default color of the {@code Label} and {@code ExpandedLabel}.
|
* The default color of the {@code Label} and {@code ExpandedLabel}.
|
|
@ -1,48 +1,46 @@
|
||||||
// @flow
|
|
||||||
import { withStyles } from '@material-ui/core/styles';
|
import { withStyles } from '@material-ui/core/styles';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import Icon from '../../icons/components/Icon';
|
import Icon from '../../../icons/components/Icon';
|
||||||
import { withPixelLineHeight } from '../../styles/functions.web';
|
import { withPixelLineHeight } from '../../../styles/functions.web';
|
||||||
import { COLORS } from '../constants';
|
import { COLORS } from '../../constants';
|
||||||
|
|
||||||
import AbstractLabel, {
|
import AbstractLabel, {
|
||||||
type Props as AbstractProps
|
type Props as AbstractProps
|
||||||
} from './AbstractLabel';
|
} from '../AbstractLabel';
|
||||||
|
|
||||||
type Props = AbstractProps & {
|
type Props = AbstractProps & {
|
||||||
|
|
||||||
/**
|
|
||||||
* An object containing the CSS classes.
|
|
||||||
*/
|
|
||||||
classes: Object,
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Own CSS class name.
|
* Own CSS class name.
|
||||||
*/
|
*/
|
||||||
className: string,
|
className: string,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An object containing the CSS classes.
|
||||||
|
*/
|
||||||
|
classes: any,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The color of the label.
|
* The color of the label.
|
||||||
*/
|
*/
|
||||||
color: string,
|
color: string,
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* HTML ID attribute to add to the root of {@code Label}.
|
|
||||||
*/
|
|
||||||
id: string,
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Color for the icon.
|
* Color for the icon.
|
||||||
*/
|
*/
|
||||||
iconColor?: string,
|
iconColor?: string,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HTML ID attribute to add to the root of {@code Label}.
|
||||||
|
*/
|
||||||
|
id: string,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Click handler if any.
|
* Click handler if any.
|
||||||
*/
|
*/
|
||||||
onClick?: Function,
|
onClick?: (e?: React.MouseEvent) => void,
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -53,7 +51,7 @@ type Props = AbstractProps & {
|
||||||
*
|
*
|
||||||
* @returns {Object}
|
* @returns {Object}
|
||||||
*/
|
*/
|
||||||
const styles = theme => {
|
const styles = (theme: any) => {
|
||||||
return {
|
return {
|
||||||
label: {
|
label: {
|
||||||
...withPixelLineHeight(theme.typography.labelRegular),
|
...withPixelLineHeight(theme.typography.labelRegular),
|
||||||
|
@ -96,7 +94,7 @@ const styles = theme => {
|
||||||
*
|
*
|
||||||
* @augments Component
|
* @augments Component
|
||||||
*/
|
*/
|
||||||
class Label extends AbstractLabel<Props, *> {
|
class Label extends AbstractLabel<Props, any> {
|
||||||
/**
|
/**
|
||||||
* Implements React's {@link Component#render()}.
|
* Implements React's {@link Component#render()}.
|
||||||
*
|
*
|
|
@ -0,0 +1,2 @@
|
||||||
|
export { default as Label } from './Label';
|
||||||
|
export { default as ExpandedLabel } from './ExpandedLabel';
|
|
@ -1,5 +1,3 @@
|
||||||
// @flow
|
|
||||||
|
|
||||||
export const COLORS = {
|
export const COLORS = {
|
||||||
white: 'white',
|
white: 'white',
|
||||||
green: 'green',
|
green: 'green',
|
|
@ -581,7 +581,7 @@ export function participantKicked(kicker: any, kicked: any) {
|
||||||
* }
|
* }
|
||||||
* }}
|
* }}
|
||||||
*/
|
*/
|
||||||
export function pinParticipant(id: string) {
|
export function pinParticipant(id: string|null) {
|
||||||
return {
|
return {
|
||||||
type: PIN_PARTICIPANT,
|
type: PIN_PARTICIPANT,
|
||||||
participant: {
|
participant: {
|
||||||
|
|
|
@ -224,7 +224,7 @@ export function getNormalizedDisplayName(name: string) {
|
||||||
* @returns {(Participant|undefined)}
|
* @returns {(Participant|undefined)}
|
||||||
*/
|
*/
|
||||||
export function getParticipantById(
|
export function getParticipantById(
|
||||||
stateful: IStore | Function, id: string): Participant|undefined {
|
stateful: IStore | Function | IState, id: string): Participant|undefined {
|
||||||
const state = toState(stateful)['features/base/participants'];
|
const state = toState(stateful)['features/base/participants'];
|
||||||
const { local, localScreenShare, remote } = state;
|
const { local, localScreenShare, remote } = state;
|
||||||
|
|
||||||
|
|
|
@ -177,7 +177,7 @@ const useStyles = makeStyles((theme: Theme) => {
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
const Button = ({
|
const Button = React.forwardRef<any, any>(({
|
||||||
accessibilityLabel,
|
accessibilityLabel,
|
||||||
className,
|
className,
|
||||||
disabled,
|
disabled,
|
||||||
|
@ -191,7 +191,7 @@ const Button = ({
|
||||||
size = 'medium',
|
size = 'medium',
|
||||||
testId,
|
testId,
|
||||||
type = BUTTON_TYPES.PRIMARY
|
type = BUTTON_TYPES.PRIMARY
|
||||||
}: IButtonProps) => {
|
}: IButtonProps, ref) => {
|
||||||
const styles = useStyles();
|
const styles = useStyles();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
@ -206,6 +206,7 @@ const Button = ({
|
||||||
disabled = { disabled }
|
disabled = { disabled }
|
||||||
{ ...(id ? { id } : {}) }
|
{ ...(id ? { id } : {}) }
|
||||||
onClick = { onClick }
|
onClick = { onClick }
|
||||||
|
ref = { ref }
|
||||||
title = { accessibilityLabel }
|
title = { accessibilityLabel }
|
||||||
type = { isSubmit ? 'submit' : 'button' }>
|
type = { isSubmit ? 'submit' : 'button' }>
|
||||||
{icon && <Icon
|
{icon && <Icon
|
||||||
|
@ -216,6 +217,6 @@ const Button = ({
|
||||||
</span>}
|
</span>}
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
};
|
});
|
||||||
|
|
||||||
export default Button;
|
export default Button;
|
||||||
|
|
|
@ -1,24 +1,29 @@
|
||||||
// @flow
|
/* eslint-disable lines-around-comment */
|
||||||
|
|
||||||
import { withStyles } from '@material-ui/styles';
|
import { withStyles } from '@material-ui/styles';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import debounce from 'lodash/debounce';
|
import debounce from 'lodash/debounce';
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
import { createScreenSharingIssueEvent, sendAnalytics } from '../../../analytics';
|
import { createScreenSharingIssueEvent, sendAnalytics } from '../../../analytics';
|
||||||
|
// @ts-ignore
|
||||||
import { Avatar } from '../../../base/avatar';
|
import { Avatar } from '../../../base/avatar';
|
||||||
|
// @ts-ignore
|
||||||
import { getMultipleVideoSupportFeatureFlag, getSourceNameSignalingFeatureFlag } from '../../../base/config';
|
import { getMultipleVideoSupportFeatureFlag, getSourceNameSignalingFeatureFlag } from '../../../base/config';
|
||||||
import { isMobileBrowser } from '../../../base/environment/utils';
|
import { isMobileBrowser } from '../../../base/environment/utils';
|
||||||
import { JitsiTrackEvents } from '../../../base/lib-jitsi-meet';
|
import { JitsiTrackEvents } from '../../../base/lib-jitsi-meet';
|
||||||
|
// @ts-ignore
|
||||||
import { MEDIA_TYPE, VideoTrack } from '../../../base/media';
|
import { MEDIA_TYPE, VideoTrack } from '../../../base/media';
|
||||||
|
import { pinParticipant } from '../../../base/participants/actions';
|
||||||
import {
|
import {
|
||||||
getLocalParticipant,
|
getLocalParticipant,
|
||||||
getParticipantByIdOrUndefined,
|
getParticipantByIdOrUndefined,
|
||||||
hasRaisedHand,
|
hasRaisedHand
|
||||||
pinParticipant
|
} from '../../../base/participants/functions';
|
||||||
} from '../../../base/participants';
|
import { Participant } from '../../../base/participants/reducer';
|
||||||
import { connect } from '../../../base/redux';
|
import { connect } from '../../../base/redux/functions';
|
||||||
import { ASPECT_RATIO_NARROW } from '../../../base/responsive-ui/constants';
|
import { ASPECT_RATIO_NARROW } from '../../../base/responsive-ui/constants';
|
||||||
|
// @ts-ignore
|
||||||
import { isTestModeEnabled } from '../../../base/testing';
|
import { isTestModeEnabled } from '../../../base/testing';
|
||||||
import {
|
import {
|
||||||
getLocalAudioTrack,
|
getLocalAudioTrack,
|
||||||
|
@ -27,12 +32,19 @@ import {
|
||||||
getVirtualScreenshareParticipantTrack,
|
getVirtualScreenshareParticipantTrack,
|
||||||
updateLastTrackVideoMediaEvent,
|
updateLastTrackVideoMediaEvent,
|
||||||
trackStreamingStatusChanged
|
trackStreamingStatusChanged
|
||||||
|
// @ts-ignore
|
||||||
} from '../../../base/tracks';
|
} from '../../../base/tracks';
|
||||||
|
// @ts-ignore
|
||||||
import { getVideoObjectPosition } from '../../../face-landmarks/functions';
|
import { getVideoObjectPosition } from '../../../face-landmarks/functions';
|
||||||
|
// @ts-ignore
|
||||||
import { hideGif, showGif } from '../../../gifs/actions';
|
import { hideGif, showGif } from '../../../gifs/actions';
|
||||||
|
// @ts-ignore
|
||||||
import { getGifDisplayMode, getGifForParticipant } from '../../../gifs/functions';
|
import { getGifDisplayMode, getGifForParticipant } from '../../../gifs/functions';
|
||||||
|
// @ts-ignore
|
||||||
import { PresenceLabel } from '../../../presence-status';
|
import { PresenceLabel } from '../../../presence-status';
|
||||||
|
// @ts-ignore
|
||||||
import { getCurrentLayout, LAYOUTS } from '../../../video-layout';
|
import { getCurrentLayout, LAYOUTS } from '../../../video-layout';
|
||||||
|
// @ts-ignore
|
||||||
import { togglePinStageParticipant } from '../../actions';
|
import { togglePinStageParticipant } from '../../actions';
|
||||||
import {
|
import {
|
||||||
DISPLAY_MODE_TO_CLASS_NAME,
|
DISPLAY_MODE_TO_CLASS_NAME,
|
||||||
|
@ -50,20 +62,22 @@ import {
|
||||||
isVideoPlayable,
|
isVideoPlayable,
|
||||||
isStageFilmstripAvailable,
|
isStageFilmstripAvailable,
|
||||||
showGridInVerticalView
|
showGridInVerticalView
|
||||||
|
// @ts-ignore
|
||||||
} from '../../functions';
|
} from '../../functions';
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
import ThumbnailAudioIndicator from './ThumbnailAudioIndicator';
|
import ThumbnailAudioIndicator from './ThumbnailAudioIndicator';
|
||||||
import ThumbnailBottomIndicators from './ThumbnailBottomIndicators';
|
import ThumbnailBottomIndicators from './ThumbnailBottomIndicators';
|
||||||
import ThumbnailTopIndicators from './ThumbnailTopIndicators';
|
import ThumbnailTopIndicators from './ThumbnailTopIndicators';
|
||||||
|
// @ts-ignore
|
||||||
import VirtualScreenshareParticipant from './VirtualScreenshareParticipant';
|
import VirtualScreenshareParticipant from './VirtualScreenshareParticipant';
|
||||||
|
|
||||||
|
declare let interfaceConfig: any;
|
||||||
declare var interfaceConfig: Object;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The type of the React {@code Component} state of {@link Thumbnail}.
|
* The type of the React {@code Component} state of {@link Thumbnail}.
|
||||||
*/
|
*/
|
||||||
export type State = {|
|
export type State = {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates that the canplay event has been received.
|
* Indicates that the canplay event has been received.
|
||||||
|
@ -75,26 +89,26 @@ export type State = {|
|
||||||
*/
|
*/
|
||||||
displayMode: number,
|
displayMode: number,
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether popover is visible or not.
|
|
||||||
*/
|
|
||||||
popoverVisible: boolean,
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates whether the thumbnail is hovered or not.
|
* Indicates whether the thumbnail is hovered or not.
|
||||||
*/
|
*/
|
||||||
isHovered: boolean
|
isHovered: boolean,
|
||||||
|};
|
|
||||||
|
/**
|
||||||
|
* Whether popover is visible or not.
|
||||||
|
*/
|
||||||
|
popoverVisible: boolean
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The type of the React {@code Component} props of {@link Thumbnail}.
|
* The type of the React {@code Component} props of {@link Thumbnail}.
|
||||||
*/
|
*/
|
||||||
export type Props = {|
|
export type Props = {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The audio track related to the participant.
|
* The audio track related to the participant.
|
||||||
*/
|
*/
|
||||||
_audioTrack: ?Object,
|
_audioTrack?: Object,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates whether the local video flip feature is disabled or not.
|
* Indicates whether the local video flip feature is disabled or not.
|
||||||
|
@ -109,7 +123,7 @@ export type Props = {|
|
||||||
/**
|
/**
|
||||||
* URL of GIF sent by this participant, null if there's none.
|
* URL of GIF sent by this participant, null if there's none.
|
||||||
*/
|
*/
|
||||||
_gifSrc ?: string,
|
_gifSrc?: string,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The height of the Thumbnail.
|
* The height of the Thumbnail.
|
||||||
|
@ -122,11 +136,6 @@ export type Props = {|
|
||||||
*/
|
*/
|
||||||
_isActiveParticipant: boolean,
|
_isActiveParticipant: boolean,
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates whether the thumbnail should be hidden or not.
|
|
||||||
*/
|
|
||||||
_isHidden: boolean,
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates whether audio only mode is enabled.
|
* Indicates whether audio only mode is enabled.
|
||||||
*/
|
*/
|
||||||
|
@ -142,6 +151,11 @@ export type Props = {|
|
||||||
*/
|
*/
|
||||||
_isDominantSpeakerDisabled: boolean,
|
_isDominantSpeakerDisabled: boolean,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates whether the thumbnail should be hidden or not.
|
||||||
|
*/
|
||||||
|
_isHidden: boolean,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether we are currently running in a mobile browser.
|
* Whether we are currently running in a mobile browser.
|
||||||
*/
|
*/
|
||||||
|
@ -181,7 +195,7 @@ export type Props = {|
|
||||||
/**
|
/**
|
||||||
* An object with information about the participant related to the thumbnail.
|
* An object with information about the participant related to the thumbnail.
|
||||||
*/
|
*/
|
||||||
_participant: Object,
|
_participant: Participant,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether or not the participant has the hand raised.
|
* Whether or not the participant has the hand raised.
|
||||||
|
@ -218,7 +232,7 @@ export type Props = {|
|
||||||
/**
|
/**
|
||||||
* The video track that will be displayed in the thumbnail.
|
* The video track that will be displayed in the thumbnail.
|
||||||
*/
|
*/
|
||||||
_videoTrack: ?Object,
|
_videoTrack?: any,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The width of the thumbnail.
|
* The width of the thumbnail.
|
||||||
|
@ -228,7 +242,7 @@ export type Props = {|
|
||||||
/**
|
/**
|
||||||
* An object containing CSS classes.
|
* An object containing CSS classes.
|
||||||
*/
|
*/
|
||||||
classes: Object,
|
classes: any,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The redux dispatch function.
|
* The redux dispatch function.
|
||||||
|
@ -248,21 +262,21 @@ export type Props = {|
|
||||||
/**
|
/**
|
||||||
* The ID of the participant related to the thumbnail.
|
* The ID of the participant related to the thumbnail.
|
||||||
*/
|
*/
|
||||||
participantID: ?string,
|
participantID?: string,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Styles that will be set to the Thumbnail's main span element.
|
* Styles that will be set to the Thumbnail's main span element.
|
||||||
*/
|
*/
|
||||||
style?: ?Object,
|
style?: any,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The width of the thumbnail. Used for expanding the width of the thumbnails on last row in case
|
* The width of the thumbnail. Used for expanding the width of the thumbnails on last row in case
|
||||||
* there is empty space.
|
* there is empty space.
|
||||||
*/
|
*/
|
||||||
width?: number
|
width?: number
|
||||||
|};
|
};
|
||||||
|
|
||||||
const defaultStyles = theme => {
|
const defaultStyles = (theme: any) => {
|
||||||
return {
|
return {
|
||||||
indicatorsContainer: {
|
indicatorsContainer: {
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
|
@ -372,13 +386,13 @@ class Thumbnail extends Component<Props, State> {
|
||||||
/**
|
/**
|
||||||
* The long touch setTimeout handler.
|
* The long touch setTimeout handler.
|
||||||
*/
|
*/
|
||||||
timeoutHandle: Object;
|
timeoutHandle?: number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Timeout used to detect double tapping.
|
* Timeout used to detect double tapping.
|
||||||
* It is active while user has tapped once.
|
* It is active while user has tapped once.
|
||||||
*/
|
*/
|
||||||
_firstTap: ?TimeoutID;
|
_firstTap?: number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes a new Thumbnail instance.
|
* Initializes a new Thumbnail instance.
|
||||||
|
@ -400,7 +414,7 @@ class Thumbnail extends Component<Props, State> {
|
||||||
...state,
|
...state,
|
||||||
displayMode: computeDisplayModeFromInput(getDisplayModeInput(props, state))
|
displayMode: computeDisplayModeFromInput(getDisplayModeInput(props, state))
|
||||||
};
|
};
|
||||||
this.timeoutHandle = null;
|
this.timeoutHandle = undefined;
|
||||||
|
|
||||||
this._clearDoubleClickTimeout = this._clearDoubleClickTimeout.bind(this);
|
this._clearDoubleClickTimeout = this._clearDoubleClickTimeout.bind(this);
|
||||||
this._onCanPlay = this._onCanPlay.bind(this);
|
this._onCanPlay = this._onCanPlay.bind(this);
|
||||||
|
@ -505,7 +519,7 @@ class Thumbnail extends Component<Props, State> {
|
||||||
* @param {JitsiTrackStreamingStatus} streamingStatus - The updated track streaming status.
|
* @param {JitsiTrackStreamingStatus} streamingStatus - The updated track streaming status.
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
handleTrackStreamingStatusChanged(jitsiTrack, streamingStatus) {
|
handleTrackStreamingStatusChanged(jitsiTrack: any, streamingStatus: any) {
|
||||||
this.props.dispatch(trackStreamingStatusChanged(jitsiTrack, streamingStatus));
|
this.props.dispatch(trackStreamingStatusChanged(jitsiTrack, streamingStatus));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -526,7 +540,7 @@ class Thumbnail extends Component<Props, State> {
|
||||||
* @param {Object} input - The input used to compute the thumbnail display mode.
|
* @param {Object} input - The input used to compute the thumbnail display mode.
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
_maybeSendScreenSharingIssueEvents(input) {
|
_maybeSendScreenSharingIssueEvents(input: any) {
|
||||||
const {
|
const {
|
||||||
_isAudioOnly,
|
_isAudioOnly,
|
||||||
_isScreenSharing,
|
_isScreenSharing,
|
||||||
|
@ -576,8 +590,6 @@ class Thumbnail extends Component<Props, State> {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
_clearDoubleClickTimeout: () => void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clears the first click timeout.
|
* Clears the first click timeout.
|
||||||
*
|
*
|
||||||
|
@ -588,8 +600,6 @@ class Thumbnail extends Component<Props, State> {
|
||||||
this._firstTap = undefined;
|
this._firstTap = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
_showPopover: () => void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shows popover.
|
* Shows popover.
|
||||||
*
|
*
|
||||||
|
@ -602,8 +612,6 @@ class Thumbnail extends Component<Props, State> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_hidePopover: () => void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hides popover.
|
* Hides popover.
|
||||||
*
|
*
|
||||||
|
@ -628,7 +636,7 @@ class Thumbnail extends Component<Props, State> {
|
||||||
*
|
*
|
||||||
* @returns {Object} - The styles for the thumbnail.
|
* @returns {Object} - The styles for the thumbnail.
|
||||||
*/
|
*/
|
||||||
_getStyles(): Object {
|
_getStyles(): any {
|
||||||
const { canPlayEventReceived } = this.state;
|
const { canPlayEventReceived } = this.state;
|
||||||
const {
|
const {
|
||||||
_disableTileEnlargement,
|
_disableTileEnlargement,
|
||||||
|
@ -652,7 +660,7 @@ class Thumbnail extends Component<Props, State> {
|
||||||
|
|
||||||
let styles: {
|
let styles: {
|
||||||
avatar: Object,
|
avatar: Object,
|
||||||
thumbnail: Object,
|
thumbnail: any,
|
||||||
video: Object
|
video: Object
|
||||||
} = {
|
} = {
|
||||||
thumbnail: {},
|
thumbnail: {},
|
||||||
|
@ -667,7 +675,7 @@ class Thumbnail extends Component<Props, State> {
|
||||||
left += horizontalOffset;
|
left += horizontalOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
let videoStyles = null;
|
let videoStyles: any = null;
|
||||||
const doNotStretchVideo = (isPortraitVideo && isTileType)
|
const doNotStretchVideo = (isPortraitVideo && isTileType)
|
||||||
|| _disableTileEnlargement
|
|| _disableTileEnlargement
|
||||||
|| _isScreenSharing;
|
|| _isScreenSharing;
|
||||||
|
@ -709,8 +717,6 @@ class Thumbnail extends Component<Props, State> {
|
||||||
return styles;
|
return styles;
|
||||||
}
|
}
|
||||||
|
|
||||||
_onClick: () => void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* On click handler.
|
* On click handler.
|
||||||
*
|
*
|
||||||
|
@ -727,8 +733,6 @@ class Thumbnail extends Component<Props, State> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_onMouseEnter: () => void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mouse enter handler.
|
* Mouse enter handler.
|
||||||
*
|
*
|
||||||
|
@ -752,8 +756,6 @@ class Thumbnail extends Component<Props, State> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_onMouseLeave: () => void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mouse leave handler.
|
* Mouse leave handler.
|
||||||
*
|
*
|
||||||
|
@ -763,15 +765,13 @@ class Thumbnail extends Component<Props, State> {
|
||||||
this.setState({ isHovered: false });
|
this.setState({ isHovered: false });
|
||||||
}
|
}
|
||||||
|
|
||||||
_onTouchStart: () => void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handler for touch start.
|
* Handler for touch start.
|
||||||
*
|
*
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
_onTouchStart() {
|
_onTouchStart() {
|
||||||
this.timeoutHandle = setTimeout(this._showPopover, SHOW_TOOLBAR_CONTEXT_MENU_AFTER);
|
this.timeoutHandle = window.setTimeout(this._showPopover, SHOW_TOOLBAR_CONTEXT_MENU_AFTER);
|
||||||
|
|
||||||
if (this._firstTap) {
|
if (this._firstTap) {
|
||||||
this._clearDoubleClickTimeout();
|
this._clearDoubleClickTimeout();
|
||||||
|
@ -780,11 +780,9 @@ class Thumbnail extends Component<Props, State> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._firstTap = setTimeout(this._clearDoubleClickTimeout, 300);
|
this._firstTap = window.setTimeout(this._clearDoubleClickTimeout, 300);
|
||||||
}
|
}
|
||||||
|
|
||||||
_onTouchEnd: () => void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cancel showing popover context menu after x miliseconds if the no. Of miliseconds is not reached yet,
|
* Cancel showing popover context menu after x miliseconds if the no. Of miliseconds is not reached yet,
|
||||||
* or just clears the timeout.
|
* or just clears the timeout.
|
||||||
|
@ -795,8 +793,6 @@ class Thumbnail extends Component<Props, State> {
|
||||||
clearTimeout(this.timeoutHandle);
|
clearTimeout(this.timeoutHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
_onTouchMove: () => void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cancel showing Context menu after x miliseconds if the number of miliseconds is not reached
|
* Cancel showing Context menu after x miliseconds if the number of miliseconds is not reached
|
||||||
* before a touch move(drag), or just clears the timeout.
|
* before a touch move(drag), or just clears the timeout.
|
||||||
|
@ -845,7 +841,7 @@ class Thumbnail extends Component<Props, State> {
|
||||||
* @param {Object} styles - The styles that will be applied to the avatar.
|
* @param {Object} styles - The styles that will be applied to the avatar.
|
||||||
* @returns {ReactElement}
|
* @returns {ReactElement}
|
||||||
*/
|
*/
|
||||||
_renderAvatar(styles) {
|
_renderAvatar(styles: Object) {
|
||||||
const { _participant } = this.props;
|
const { _participant } = this.props;
|
||||||
const { id } = _participant;
|
const { id } = _participant;
|
||||||
|
|
||||||
|
@ -892,8 +888,6 @@ class Thumbnail extends Component<Props, State> {
|
||||||
return className;
|
return className;
|
||||||
}
|
}
|
||||||
|
|
||||||
_onGifMouseEnter: () => void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Keep showing the GIF for the current participant.
|
* Keep showing the GIF for the current participant.
|
||||||
*
|
*
|
||||||
|
@ -905,8 +899,6 @@ class Thumbnail extends Component<Props, State> {
|
||||||
dispatch(showGif(id));
|
dispatch(showGif(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
_onGifMouseLeave: () => void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Keep showing the GIF for the current participant.
|
* Keep showing the GIF for the current participant.
|
||||||
*
|
*
|
||||||
|
@ -935,15 +927,13 @@ class Thumbnail extends Component<Props, State> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
_onCanPlay: Object => void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Canplay event listener.
|
* Canplay event listener.
|
||||||
*
|
*
|
||||||
* @param {SyntheticEvent} event - The event.
|
* @param {SyntheticEvent} event - The event.
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
_onCanPlay(event) {
|
_onCanPlay(event: any) {
|
||||||
this.setState({ canPlayEventReceived: true });
|
this.setState({ canPlayEventReceived: true });
|
||||||
|
|
||||||
const {
|
const {
|
||||||
|
@ -956,15 +946,13 @@ class Thumbnail extends Component<Props, State> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_onTestingEvent: Object => void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Event handler for testing events.
|
* Event handler for testing events.
|
||||||
*
|
*
|
||||||
* @param {SyntheticEvent} event - The event.
|
* @param {SyntheticEvent} event - The event.
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
_onTestingEvent(event) {
|
_onTestingEvent(event: any) {
|
||||||
const {
|
const {
|
||||||
_videoTrack,
|
_videoTrack,
|
||||||
dispatch
|
dispatch
|
||||||
|
@ -1004,7 +992,7 @@ class Thumbnail extends Component<Props, State> {
|
||||||
= !_disableLocalVideoFlip && _videoTrack && !_isScreenSharing && _localFlipX ? 'flipVideoX' : '';
|
= !_disableLocalVideoFlip && _videoTrack && !_isScreenSharing && _localFlipX ? 'flipVideoX' : '';
|
||||||
const jitsiVideoTrack = _videoTrack?.jitsiTrack;
|
const jitsiVideoTrack = _videoTrack?.jitsiTrack;
|
||||||
const videoTrackId = jitsiVideoTrack && jitsiVideoTrack.getId();
|
const videoTrackId = jitsiVideoTrack && jitsiVideoTrack.getId();
|
||||||
const videoEventListeners = {};
|
const videoEventListeners: any = {};
|
||||||
|
|
||||||
if (local) {
|
if (local) {
|
||||||
if (_isMobilePortrait) {
|
if (_isMobilePortrait) {
|
||||||
|
@ -1168,7 +1156,7 @@ class Thumbnail extends Component<Props, State> {
|
||||||
* @private
|
* @private
|
||||||
* @returns {Props}
|
* @returns {Props}
|
||||||
*/
|
*/
|
||||||
function _mapStateToProps(state, ownProps): Object {
|
function _mapStateToProps(state: any, ownProps: any): Object {
|
||||||
const { participantID, filmstripType = FILMSTRIP_TYPE.MAIN } = ownProps;
|
const { participantID, filmstripType = FILMSTRIP_TYPE.MAIN } = ownProps;
|
||||||
|
|
||||||
const participant = getParticipantByIdOrUndefined(state, participantID);
|
const participant = getParticipantByIdOrUndefined(state, participantID);
|
||||||
|
@ -1188,7 +1176,7 @@ function _mapStateToProps(state, ownProps): Object {
|
||||||
const _audioTrack = isLocal
|
const _audioTrack = isLocal
|
||||||
? getLocalAudioTrack(tracks) : getTrackByMediaTypeAndParticipant(tracks, MEDIA_TYPE.AUDIO, participantID);
|
? getLocalAudioTrack(tracks) : getTrackByMediaTypeAndParticipant(tracks, MEDIA_TYPE.AUDIO, participantID);
|
||||||
const _currentLayout = getCurrentLayout(state);
|
const _currentLayout = getCurrentLayout(state);
|
||||||
let size = {};
|
let size: any = {};
|
||||||
let _isMobilePortrait = false;
|
let _isMobilePortrait = false;
|
||||||
const {
|
const {
|
||||||
defaultLocalDisplayName,
|
defaultLocalDisplayName,
|
||||||
|
@ -1287,7 +1275,7 @@ function _mapStateToProps(state, ownProps): Object {
|
||||||
_defaultLocalDisplayName: defaultLocalDisplayName,
|
_defaultLocalDisplayName: defaultLocalDisplayName,
|
||||||
_disableLocalVideoFlip: Boolean(disableLocalVideoFlip),
|
_disableLocalVideoFlip: Boolean(disableLocalVideoFlip),
|
||||||
_disableTileEnlargement: Boolean(disableTileEnlargement),
|
_disableTileEnlargement: Boolean(disableTileEnlargement),
|
||||||
_isActiveParticipant: activeParticipants.find(pId => pId === participantId),
|
_isActiveParticipant: activeParticipants.find((pId: string) => pId === participantId),
|
||||||
_isHidden: isLocal && iAmRecorder && !iAmSipGateway,
|
_isHidden: isLocal && iAmRecorder && !iAmSipGateway,
|
||||||
_isAudioOnly: Boolean(state['features/base/audio-only'].enabled),
|
_isAudioOnly: Boolean(state['features/base/audio-only'].enabled),
|
||||||
_isCurrentlyOnLargeVideo: state['features/large-video']?.participantId === id,
|
_isCurrentlyOnLargeVideo: state['features/large-video']?.participantId === id,
|
||||||
|
@ -1313,4 +1301,5 @@ function _mapStateToProps(state, ownProps): Object {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
export default connect(_mapStateToProps)(withStyles(defaultStyles)(Thumbnail));
|
export default connect(_mapStateToProps)(withStyles(defaultStyles)(Thumbnail));
|
|
@ -1,5 +1,4 @@
|
||||||
// @flow
|
/* eslint-disable lines-around-comment */
|
||||||
|
|
||||||
import { makeStyles } from '@material-ui/styles';
|
import { makeStyles } from '@material-ui/styles';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useSelector } from 'react-redux';
|
import { useSelector } from 'react-redux';
|
||||||
|
@ -8,13 +7,16 @@ import {
|
||||||
getMultipleVideoSupportFeatureFlag,
|
getMultipleVideoSupportFeatureFlag,
|
||||||
isDisplayNameVisible,
|
isDisplayNameVisible,
|
||||||
isNameReadOnly
|
isNameReadOnly
|
||||||
|
// @ts-ignore
|
||||||
} from '../../../base/config/functions.any';
|
} from '../../../base/config/functions.any';
|
||||||
|
// @ts-ignore
|
||||||
import DisplayName from '../../../display-name/components/web/DisplayName';
|
import DisplayName from '../../../display-name/components/web/DisplayName';
|
||||||
import { THUMBNAIL_TYPE } from '../../constants';
|
import { THUMBNAIL_TYPE } from '../../constants';
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
import StatusIndicators from './StatusIndicators';
|
import StatusIndicators from './StatusIndicators';
|
||||||
|
|
||||||
declare var interfaceConfig: Object;
|
declare let interfaceConfig: any;
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
|
||||||
|
@ -41,7 +43,7 @@ type Props = {
|
||||||
/**
|
/**
|
||||||
* Whether or not to show the status indicators.
|
* Whether or not to show the status indicators.
|
||||||
*/
|
*/
|
||||||
showStatusIndicators: string,
|
showStatusIndicators?: boolean,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The type of thumbnail.
|
* The type of thumbnail.
|
|
@ -1,22 +1,28 @@
|
||||||
// @flow
|
/* eslint-disable lines-around-comment */
|
||||||
|
|
||||||
import { makeStyles } from '@material-ui/styles';
|
import { makeStyles } from '@material-ui/styles';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useSelector } from 'react-redux';
|
import { useSelector } from 'react-redux';
|
||||||
|
|
||||||
|
import { IState } from '../../../app/types';
|
||||||
|
// @ts-ignore
|
||||||
import { getMultipleVideoSupportFeatureFlag } from '../../../base/config';
|
import { getMultipleVideoSupportFeatureFlag } from '../../../base/config';
|
||||||
import { isMobileBrowser } from '../../../base/environment/utils';
|
import { isMobileBrowser } from '../../../base/environment/utils';
|
||||||
|
// @ts-ignore
|
||||||
import ConnectionIndicator from '../../../connection-indicator/components/web/ConnectionIndicator';
|
import ConnectionIndicator from '../../../connection-indicator/components/web/ConnectionIndicator';
|
||||||
import { STATS_POPOVER_POSITION, THUMBNAIL_TYPE } from '../../constants';
|
import { STATS_POPOVER_POSITION, THUMBNAIL_TYPE } from '../../constants';
|
||||||
|
// @ts-ignore
|
||||||
import { getIndicatorsTooltipPosition } from '../../functions.web';
|
import { getIndicatorsTooltipPosition } from '../../functions.web';
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
import PinnedIndicator from './PinnedIndicator';
|
import PinnedIndicator from './PinnedIndicator';
|
||||||
|
// @ts-ignore
|
||||||
import RaisedHandIndicator from './RaisedHandIndicator';
|
import RaisedHandIndicator from './RaisedHandIndicator';
|
||||||
|
// @ts-ignore
|
||||||
import StatusIndicators from './StatusIndicators';
|
import StatusIndicators from './StatusIndicators';
|
||||||
import VideoMenuTriggerButton from './VideoMenuTriggerButton';
|
import VideoMenuTriggerButton from './VideoMenuTriggerButton';
|
||||||
|
|
||||||
declare var interfaceConfig: Object;
|
declare let interfaceConfig: any;
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
|
||||||
|
@ -38,7 +44,7 @@ type Props = {
|
||||||
/**
|
/**
|
||||||
* Whether or not the thumbnail is a virtual screen share participant.
|
* Whether or not the thumbnail is a virtual screen share participant.
|
||||||
*/
|
*/
|
||||||
isVirtualScreenshareParticipant: boolean,
|
isVirtualScreenshareParticipant?: boolean,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether or not the indicators are for the local participant.
|
* Whether or not the indicators are for the local participant.
|
||||||
|
@ -95,9 +101,9 @@ const ThumbnailTopIndicators = ({
|
||||||
const { NORMAL = 16 } = interfaceConfig.INDICATOR_FONT_SIZES || {};
|
const { NORMAL = 16 } = interfaceConfig.INDICATOR_FONT_SIZES || {};
|
||||||
const _indicatorIconSize = NORMAL;
|
const _indicatorIconSize = NORMAL;
|
||||||
const _connectionIndicatorAutoHideEnabled = Boolean(
|
const _connectionIndicatorAutoHideEnabled = Boolean(
|
||||||
useSelector(state => state['features/base/config'].connectionIndicators?.autoHide) ?? true);
|
useSelector((state: IState) => state['features/base/config'].connectionIndicators?.autoHide) ?? true);
|
||||||
const _connectionIndicatorDisabled = _isMobile
|
const _connectionIndicatorDisabled = _isMobile
|
||||||
|| Boolean(useSelector(state => state['features/base/config'].connectionIndicators?.disabled));
|
|| Boolean(useSelector((state: IState) => state['features/base/config'].connectionIndicators?.disabled));
|
||||||
const _isMultiStreamEnabled = useSelector(getMultipleVideoSupportFeatureFlag);
|
const _isMultiStreamEnabled = useSelector(getMultipleVideoSupportFeatureFlag);
|
||||||
const showConnectionIndicator = isHovered || !_connectionIndicatorAutoHideEnabled;
|
const showConnectionIndicator = isHovered || !_connectionIndicatorAutoHideEnabled;
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
// @flow
|
// @ts-ignore
|
||||||
|
|
||||||
import { BoxModel } from '../base/styles';
|
import { BoxModel } from '../base/styles';
|
||||||
|
|
||||||
/**
|
/**
|
|
@ -1,6 +1,5 @@
|
||||||
// @flow
|
/* eslint-disable lines-around-comment */
|
||||||
|
import { GiphyFetch, TrendingOptions } from '@giphy/js-fetch-api';
|
||||||
import { GiphyFetch } from '@giphy/js-fetch-api';
|
|
||||||
import { Grid } from '@giphy/react-components';
|
import { Grid } from '@giphy/react-components';
|
||||||
import { makeStyles } from '@material-ui/core';
|
import { makeStyles } from '@material-ui/core';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
|
@ -8,21 +7,30 @@ import React, { useCallback, useEffect, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { batch, useDispatch, useSelector } from 'react-redux';
|
import { batch, useDispatch, useSelector } from 'react-redux';
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
import { createGifSentEvent, sendAnalytics } from '../../../analytics';
|
import { createGifSentEvent, sendAnalytics } from '../../../analytics';
|
||||||
|
import { IState } from '../../../app/types';
|
||||||
|
// @ts-ignore
|
||||||
import InputField from '../../../base/premeeting/components/web/InputField';
|
import InputField from '../../../base/premeeting/components/web/InputField';
|
||||||
import BaseTheme from '../../../base/ui/components/BaseTheme';
|
import BaseTheme from '../../../base/ui/components/BaseTheme.web';
|
||||||
|
// @ts-ignore
|
||||||
import { sendMessage } from '../../../chat/actions.any';
|
import { sendMessage } from '../../../chat/actions.any';
|
||||||
import { SCROLL_SIZE } from '../../../filmstrip';
|
import { SCROLL_SIZE } from '../../../filmstrip/constants';
|
||||||
import { toggleReactionsMenuVisibility } from '../../../reactions/actions.web';
|
import { toggleReactionsMenuVisibility } from '../../../reactions/actions.web';
|
||||||
|
// @ts-ignore
|
||||||
import { setOverflowMenuVisible } from '../../../toolbox/actions.web';
|
import { setOverflowMenuVisible } from '../../../toolbox/actions.web';
|
||||||
|
// @ts-ignore
|
||||||
import { Drawer, JitsiPortal } from '../../../toolbox/components/web';
|
import { Drawer, JitsiPortal } from '../../../toolbox/components/web';
|
||||||
|
// @ts-ignore
|
||||||
import { showOverflowDrawer } from '../../../toolbox/functions.web';
|
import { showOverflowDrawer } from '../../../toolbox/functions.web';
|
||||||
|
// @ts-ignore
|
||||||
import { setGifDrawerVisibility } from '../../actions';
|
import { setGifDrawerVisibility } from '../../actions';
|
||||||
|
// @ts-ignore
|
||||||
import { formatGifUrlMessage, getGifAPIKey, getGifUrl } from '../../functions';
|
import { formatGifUrlMessage, getGifAPIKey, getGifUrl } from '../../functions';
|
||||||
|
|
||||||
const OVERFLOW_DRAWER_PADDING = BaseTheme.spacing(3);
|
const OVERFLOW_DRAWER_PADDING = BaseTheme.spacing(3);
|
||||||
|
|
||||||
const useStyles = makeStyles(theme => {
|
const useStyles = makeStyles((theme: any) => {
|
||||||
return {
|
return {
|
||||||
gifsMenu: {
|
gifsMenu: {
|
||||||
width: '100%',
|
width: '100%',
|
||||||
|
@ -87,17 +95,17 @@ const useStyles = makeStyles(theme => {
|
||||||
* @returns {ReactElement}
|
* @returns {ReactElement}
|
||||||
*/
|
*/
|
||||||
function GifsMenu() {
|
function GifsMenu() {
|
||||||
const API_KEY = useSelector(getGifAPIKey);
|
const API_KEY: string = useSelector(getGifAPIKey);
|
||||||
const giphyFetch = new GiphyFetch(API_KEY);
|
const giphyFetch = new GiphyFetch(API_KEY);
|
||||||
const [ searchKey, setSearchKey ] = useState();
|
const [ searchKey, setSearchKey ] = useState<string>();
|
||||||
const styles = useStyles();
|
const styles = useStyles();
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const overflowDrawer = useSelector(showOverflowDrawer);
|
const overflowDrawer: boolean = useSelector(showOverflowDrawer);
|
||||||
const { clientWidth } = useSelector(state => state['features/base/responsive-ui']);
|
const { clientWidth } = useSelector((state: IState) => state['features/base/responsive-ui']);
|
||||||
|
|
||||||
const fetchGifs = useCallback(async (offset = 0) => {
|
const fetchGifs = useCallback(async (offset = 0) => {
|
||||||
const options = {
|
const options: TrendingOptions = {
|
||||||
rating: 'pg-13',
|
rating: 'pg-13',
|
||||||
limit: 20,
|
limit: 20,
|
||||||
offset
|
offset
|
||||||
|
@ -113,7 +121,7 @@ function GifsMenu() {
|
||||||
const onDrawerClose = useCallback(() => {
|
const onDrawerClose = useCallback(() => {
|
||||||
dispatch(setGifDrawerVisibility(false));
|
dispatch(setGifDrawerVisibility(false));
|
||||||
dispatch(setOverflowMenuVisible(false));
|
dispatch(setOverflowMenuVisible(false));
|
||||||
});
|
}, []);
|
||||||
|
|
||||||
const handleGifClick = useCallback((gif, e) => {
|
const handleGifClick = useCallback((gif, e) => {
|
||||||
e?.stopPropagation();
|
e?.stopPropagation();
|
||||||
|
@ -135,26 +143,37 @@ function GifsMenu() {
|
||||||
|
|
||||||
const handleSearchKeyChange = useCallback(value => {
|
const handleSearchKeyChange = useCallback(value => {
|
||||||
setSearchKey(value);
|
setSearchKey(value);
|
||||||
});
|
}, []);
|
||||||
|
|
||||||
const handleKeyDown = useCallback(e => {
|
const handleKeyDown = useCallback(e => {
|
||||||
|
if (!document.activeElement) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (e.keyCode === 38) { // up arrow
|
if (e.keyCode === 38) { // up arrow
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
// if the first gif is focused move focus to the input
|
// if the first gif is focused move focus to the input
|
||||||
if (document.activeElement.previousElementSibling === null) {
|
if (document.activeElement.previousElementSibling === null) {
|
||||||
document.querySelector('.gif-input').focus();
|
const element = document.querySelector('.gif-input') as HTMLElement;
|
||||||
|
|
||||||
|
element?.focus();
|
||||||
} else {
|
} else {
|
||||||
document.activeElement.previousElementSibling.focus();
|
const element = document.activeElement.previousElementSibling as HTMLElement;
|
||||||
|
|
||||||
|
element?.focus();
|
||||||
}
|
}
|
||||||
} else if (e.keyCode === 40) { // down arrow
|
} else if (e.keyCode === 40) { // down arrow
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
// if the input is focused move focus to the first gif
|
// if the input is focused move focus to the first gif
|
||||||
if (document.activeElement.classList.contains('gif-input')) {
|
if (document.activeElement.classList.contains('gif-input')) {
|
||||||
document.querySelector('.giphy-gif').focus();
|
const element = document.querySelector('.giphy-gif') as HTMLElement;
|
||||||
|
|
||||||
|
element?.focus();
|
||||||
} else {
|
} else {
|
||||||
document.activeElement.nextElementSibling.focus();
|
const element = document.activeElement.nextElementSibling as HTMLElement;
|
||||||
|
|
||||||
|
element?.focus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
|
@ -0,0 +1 @@
|
||||||
|
export * from './native';
|
|
@ -0,0 +1 @@
|
||||||
|
export * from './web';
|
|
@ -1,2 +1 @@
|
||||||
export { default as KeyboardShortcutsButton } from './KeyboardShortcutsButton';
|
export * from './_';
|
||||||
export { default as KeyboardShortcutsDialog } from './KeyboardShortcutsDialog';
|
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
import { createToolbarEvent, sendAnalytics } from '../../analytics';
|
import { createToolbarEvent, sendAnalytics } from '../../../analytics';
|
||||||
import { translate } from '../../base/i18n';
|
import { translate } from '../../../base/i18n';
|
||||||
import { IconDeviceDocument } from '../../base/icons';
|
import { IconDeviceDocument } from '../../../base/icons';
|
||||||
import { connect } from '../../base/redux';
|
import { connect } from '../../../base/redux';
|
||||||
import { AbstractButton, type AbstractButtonProps } from '../../base/toolbox/components';
|
import { AbstractButton, type AbstractButtonProps } from '../../../base/toolbox/components';
|
||||||
import { openKeyboardShortcutsDialog } from '../actions';
|
import { openKeyboardShortcutsDialog } from '../../actions';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The type of the React {@code Component} props of {@link KeyboardShortcutsButton}.
|
* The type of the React {@code Component} props of {@link KeyboardShortcutsButton}.
|
|
@ -1,33 +1,28 @@
|
||||||
/* @flow */
|
|
||||||
|
|
||||||
import { withStyles } from '@material-ui/core/styles';
|
import { withStyles } from '@material-ui/core/styles';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
|
import { WithTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import { Dialog } from '../../base/dialog';
|
// @ts-ignore
|
||||||
import { translate } from '../../base/i18n';
|
import { Dialog } from '../../../base/dialog';
|
||||||
|
import { translate } from '../../../base/i18n/functions';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The type of the React {@code Component} props of
|
* The type of the React {@code Component} props of
|
||||||
* {@link KeyboardShortcutsDialog}.
|
* {@link KeyboardShortcutsDialog}.
|
||||||
*/
|
*/
|
||||||
type Props = {
|
interface Props extends WithTranslation {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An object containing the CSS classes.
|
* An object containing the CSS classes.
|
||||||
*/
|
*/
|
||||||
classes: Object,
|
classes: any,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A Map with keyboard keys as keys and translation keys as values.
|
* A Map with keyboard keys as keys and translation keys as values.
|
||||||
*/
|
*/
|
||||||
shortcutDescriptions: Object,
|
shortcutDescriptions: Map<string, string>
|
||||||
|
}
|
||||||
/**
|
|
||||||
* Invoked to obtain translated strings.
|
|
||||||
*/
|
|
||||||
t: Function
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates the styles for the component.
|
* Creates the styles for the component.
|
||||||
|
@ -36,7 +31,7 @@ type Props = {
|
||||||
*
|
*
|
||||||
* @returns {Object}
|
* @returns {Object}
|
||||||
*/
|
*/
|
||||||
const styles = theme => {
|
const styles = (theme: any) => {
|
||||||
return {
|
return {
|
||||||
list: {
|
list: {
|
||||||
listStyleType: 'none',
|
listStyleType: 'none',
|
||||||
|
@ -86,7 +81,7 @@ class KeyboardShortcutsDialog extends Component<Props> {
|
||||||
<ul
|
<ul
|
||||||
className = { clsx('shortcuts-list', this.props.classes.list) }
|
className = { clsx('shortcuts-list', this.props.classes.list) }
|
||||||
id = 'keyboard-shortcuts-list'>
|
id = 'keyboard-shortcuts-list'>
|
||||||
{ shortcuts }
|
{shortcuts}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
@ -101,7 +96,7 @@ class KeyboardShortcutsDialog extends Component<Props> {
|
||||||
* @private
|
* @private
|
||||||
* @returns {ReactElement}
|
* @returns {ReactElement}
|
||||||
*/
|
*/
|
||||||
_renderShortcutsListItem(keyboardKey, translationKey) {
|
_renderShortcutsListItem(keyboardKey: string, translationKey: string) {
|
||||||
let modifierKey = 'Alt';
|
let modifierKey = 'Alt';
|
||||||
|
|
||||||
if (window.navigator?.platform) {
|
if (window.navigator?.platform) {
|
|
@ -0,0 +1,2 @@
|
||||||
|
export { default as KeyboardShortcutsButton } from './KeyboardShortcutsButton';
|
||||||
|
export { default as KeyboardShortcutsDialog } from './KeyboardShortcutsDialog';
|
|
@ -1,20 +1,23 @@
|
||||||
// @flow
|
/* eslint-disable lines-around-comment */
|
||||||
|
|
||||||
import { FlagGroupContext } from '@atlaskit/flag/flag-group';
|
import { FlagGroupContext } from '@atlaskit/flag/flag-group';
|
||||||
import { AtlasKitThemeProvider } from '@atlaskit/theme';
|
import { AtlasKitThemeProvider } from '@atlaskit/theme';
|
||||||
import { withStyles } from '@material-ui/styles';
|
import { withStyles } from '@material-ui/styles';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
|
import { WithTranslation } from 'react-i18next';
|
||||||
import { CSSTransition, TransitionGroup } from 'react-transition-group';
|
import { CSSTransition, TransitionGroup } from 'react-transition-group';
|
||||||
|
|
||||||
import { translate } from '../../../base/i18n';
|
import { translate } from '../../../base/i18n/functions';
|
||||||
import { connect } from '../../../base/redux';
|
import { connect } from '../../../base/redux/functions';
|
||||||
|
// @ts-ignore
|
||||||
import { hideNotification } from '../../actions';
|
import { hideNotification } from '../../actions';
|
||||||
|
// @ts-ignore
|
||||||
import { areThereNotifications } from '../../functions';
|
import { areThereNotifications } from '../../functions';
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
import Notification from './Notification';
|
import Notification from './Notification';
|
||||||
|
|
||||||
type Props = {
|
interface Props extends WithTranslation {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether we are a SIP gateway or not.
|
* Whether we are a SIP gateway or not.
|
||||||
|
@ -30,12 +33,15 @@ type Props = {
|
||||||
* The notifications to be displayed, with the first index being the
|
* The notifications to be displayed, with the first index being the
|
||||||
* notification at the top and the rest shown below it in order.
|
* notification at the top and the rest shown below it in order.
|
||||||
*/
|
*/
|
||||||
_notifications: Array<Object>,
|
_notifications: Array<{
|
||||||
|
props: Object;
|
||||||
|
uid: number;
|
||||||
|
}>,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JSS classes object.
|
* JSS classes object.
|
||||||
*/
|
*/
|
||||||
classes: Object,
|
classes: any,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoked to update the redux store in order to remove notifications.
|
* Invoked to update the redux store in order to remove notifications.
|
||||||
|
@ -45,15 +51,10 @@ type Props = {
|
||||||
/**
|
/**
|
||||||
* Whether or not the notifications are displayed in a portal.
|
* Whether or not the notifications are displayed in a portal.
|
||||||
*/
|
*/
|
||||||
portal?: boolean,
|
portal?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
const useStyles = (theme: any) => {
|
||||||
* Invoked to obtain translated strings.
|
|
||||||
*/
|
|
||||||
t: Function
|
|
||||||
};
|
|
||||||
|
|
||||||
const useStyles = theme => {
|
|
||||||
return {
|
return {
|
||||||
container: {
|
container: {
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
|
@ -124,7 +125,7 @@ const useStyles = theme => {
|
||||||
*/
|
*/
|
||||||
class NotificationsContainer extends Component<Props> {
|
class NotificationsContainer extends Component<Props> {
|
||||||
_api: Object;
|
_api: Object;
|
||||||
_timeouts: Map<string, TimeoutID>;
|
_timeouts: Map<string, number>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes a new {@code NotificationsContainer} instance.
|
* Initializes a new {@code NotificationsContainer} instance.
|
||||||
|
@ -161,6 +162,7 @@ class NotificationsContainer extends Component<Props> {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AtlasKitThemeProvider mode = 'light'>
|
<AtlasKitThemeProvider mode = 'light'>
|
||||||
|
{/* @ts-ignore */}
|
||||||
<FlagGroupContext.Provider value = { this._api }>
|
<FlagGroupContext.Provider value = { this._api }>
|
||||||
<div
|
<div
|
||||||
className = { clsx(this.props.classes.container, {
|
className = { clsx(this.props.classes.container, {
|
||||||
|
@ -176,8 +178,6 @@ class NotificationsContainer extends Component<Props> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
_onDismissed: number => void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Emits an action to remove the notification from the redux store so it
|
* Emits an action to remove the notification from the redux store so it
|
||||||
* stops displaying.
|
* stops displaying.
|
||||||
|
@ -186,12 +186,12 @@ class NotificationsContainer extends Component<Props> {
|
||||||
* @private
|
* @private
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
_onDismissed(uid) {
|
_onDismissed(uid: number) {
|
||||||
const timeout = this._timeouts.get(uid);
|
const timeout = this._timeouts.get(`${uid}`);
|
||||||
|
|
||||||
if (timeout) {
|
if (timeout) {
|
||||||
clearTimeout(timeout);
|
clearTimeout(timeout);
|
||||||
this._timeouts.delete(uid);
|
this._timeouts.delete(`${uid}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.props.dispatch(hideNotification(uid));
|
this.props.dispatch(hideNotification(uid));
|
||||||
|
@ -238,7 +238,7 @@ class NotificationsContainer extends Component<Props> {
|
||||||
* @private
|
* @private
|
||||||
* @returns {Props}
|
* @returns {Props}
|
||||||
*/
|
*/
|
||||||
function _mapStateToProps(state) {
|
function _mapStateToProps(state: any) {
|
||||||
const { notifications } = state['features/notifications'];
|
const { notifications } = state['features/notifications'];
|
||||||
const { iAmSipGateway } = state['features/base/config'];
|
const { iAmSipGateway } = state['features/base/config'];
|
||||||
const { isOpen: isChatOpen } = state['features/chat'];
|
const { isOpen: isChatOpen } = state['features/chat'];
|
||||||
|
@ -251,4 +251,5 @@ function _mapStateToProps(state) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
export default translate(connect(_mapStateToProps)(withStyles(useStyles)(NotificationsContainer)));
|
export default translate(connect(_mapStateToProps)(withStyles(useStyles)(NotificationsContainer)));
|
|
@ -1,18 +1,24 @@
|
||||||
// @flow
|
/* eslint-disable lines-around-comment */
|
||||||
|
|
||||||
import { makeStyles } from '@material-ui/styles';
|
import { makeStyles } from '@material-ui/styles';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import React, { useCallback, useState } from 'react';
|
import React, { ReactElement, useCallback, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useSelector } from 'react-redux';
|
import { useSelector } from 'react-redux';
|
||||||
|
|
||||||
|
import { IState } from '../../../../../app/types';
|
||||||
|
// @ts-ignore
|
||||||
import { ListItem } from '../../../../../base/components';
|
import { ListItem } from '../../../../../base/components';
|
||||||
import { Icon, IconArrowDown, IconArrowUp } from '../../../../../base/icons';
|
import Icon from '../../../../../base/icons/components/Icon';
|
||||||
import { isLocalParticipantModerator } from '../../../../../base/participants';
|
import { IconArrowDown, IconArrowUp } from '../../../../../base/icons/svg/index';
|
||||||
|
import { isLocalParticipantModerator } from '../../../../../base/participants/functions';
|
||||||
|
// @ts-ignore
|
||||||
import { showOverflowDrawer } from '../../../../../toolbox/functions.web';
|
import { showOverflowDrawer } from '../../../../../toolbox/functions.web';
|
||||||
|
// @ts-ignore
|
||||||
import { ACTION_TRIGGER } from '../../../../constants';
|
import { ACTION_TRIGGER } from '../../../../constants';
|
||||||
|
// @ts-ignore
|
||||||
import { participantMatchesSearch } from '../../../../functions';
|
import { participantMatchesSearch } from '../../../../functions';
|
||||||
import ParticipantActionEllipsis from '../../../web/ParticipantActionEllipsis';
|
import ParticipantActionEllipsis from '../../../web/ParticipantActionEllipsis';
|
||||||
|
// @ts-ignore
|
||||||
import ParticipantItem from '../../../web/ParticipantItem';
|
import ParticipantItem from '../../../web/ParticipantItem';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
@ -25,27 +31,29 @@ type Props = {
|
||||||
/**
|
/**
|
||||||
* React children.
|
* React children.
|
||||||
*/
|
*/
|
||||||
children: React$Node,
|
children: ReactElement,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is this item highlighted/raised.
|
* Is this item highlighted/raised.
|
||||||
*/
|
*/
|
||||||
isHighlighted?: boolean,
|
isHighlighted?: boolean,
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback to raise menu. Used to raise menu on mobile long press.
|
|
||||||
*/
|
|
||||||
onRaiseMenu: Function,
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback for when the mouse leaves this component.
|
* Callback for when the mouse leaves this component.
|
||||||
*/
|
*/
|
||||||
onLeave?: Function,
|
onLeave?: Function,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback to raise menu. Used to raise menu on mobile long press.
|
||||||
|
*/
|
||||||
|
onRaiseMenu: Function,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The raise context for the participant menu.
|
* The raise context for the participant menu.
|
||||||
*/
|
*/
|
||||||
participantContextEntity: ?Object,
|
participantContextEntity?: {
|
||||||
|
jid: string
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback to raise participant context menu.
|
* Callback to raise participant context menu.
|
||||||
|
@ -55,7 +63,16 @@ type Props = {
|
||||||
/**
|
/**
|
||||||
* Room reference.
|
* Room reference.
|
||||||
*/
|
*/
|
||||||
room: Object,
|
room: {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
participants: {
|
||||||
|
[jid: string]: {
|
||||||
|
displayName: string;
|
||||||
|
jid: string;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Participants search string.
|
* Participants search string.
|
||||||
|
@ -68,7 +85,7 @@ type Props = {
|
||||||
toggleParticipantMenu: Function
|
toggleParticipantMenu: Function
|
||||||
}
|
}
|
||||||
|
|
||||||
const useStyles = makeStyles(theme => {
|
const useStyles = makeStyles((theme: any) => {
|
||||||
return {
|
return {
|
||||||
container: {
|
container: {
|
||||||
boxShadow: 'none'
|
boxShadow: 'none'
|
||||||
|
@ -117,7 +134,7 @@ export const CollapsibleRoom = ({
|
||||||
const raiseMenu = useCallback(target => {
|
const raiseMenu = useCallback(target => {
|
||||||
onRaiseMenu(target);
|
onRaiseMenu(target);
|
||||||
}, [ onRaiseMenu ]);
|
}, [ onRaiseMenu ]);
|
||||||
const { defaultRemoteDisplayName } = useSelector(state => state['features/base/config']);
|
const { defaultRemoteDisplayName } = useSelector((state: IState) => state['features/base/config']);
|
||||||
const overflowDrawer = useSelector(showOverflowDrawer);
|
const overflowDrawer = useSelector(showOverflowDrawer);
|
||||||
const moderator = useSelector(isLocalParticipantModerator);
|
const moderator = useSelector(isLocalParticipantModerator);
|
||||||
|
|
||||||
|
@ -153,7 +170,7 @@ export const CollapsibleRoom = ({
|
||||||
textChildren = { roomName }
|
textChildren = { roomName }
|
||||||
trigger = { actionsTrigger } />
|
trigger = { actionsTrigger } />
|
||||||
{!collapsed && room?.participants
|
{!collapsed && room?.participants
|
||||||
&& Object.values(room?.participants || {}).map((p: Object) =>
|
&& Object.values(room?.participants || {}).map(p =>
|
||||||
participantMatchesSearch(p, searchString) && (
|
participantMatchesSearch(p, searchString) && (
|
||||||
<ParticipantItem
|
<ParticipantItem
|
||||||
actionsTrigger = { ACTION_TRIGGER.HOVER }
|
actionsTrigger = { ACTION_TRIGGER.HOVER }
|
||||||
|
@ -166,6 +183,7 @@ export const CollapsibleRoom = ({
|
||||||
participantID = { p.jid }>
|
participantID = { p.jid }>
|
||||||
{!overflowDrawer && moderator && (
|
{!overflowDrawer && moderator && (
|
||||||
<ParticipantActionEllipsis
|
<ParticipantActionEllipsis
|
||||||
|
accessibilityLabel = { t('breakoutRoom.more') }
|
||||||
onClick = { toggleParticipantMenu({ room,
|
onClick = { toggleParticipantMenu({ room,
|
||||||
jid: p.jid,
|
jid: p.jid,
|
||||||
participantName: p.displayName }) } />
|
participantName: p.displayName }) } />
|
|
@ -1,5 +1,4 @@
|
||||||
// @flow
|
/* eslint-disable lines-around-comment */
|
||||||
|
|
||||||
import { makeStyles } from '@material-ui/core/styles';
|
import { makeStyles } from '@material-ui/core/styles';
|
||||||
import React, { useCallback } from 'react';
|
import React, { useCallback } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
@ -10,32 +9,39 @@ import {
|
||||||
requestDisableVideoModeration,
|
requestDisableVideoModeration,
|
||||||
requestEnableAudioModeration,
|
requestEnableAudioModeration,
|
||||||
requestEnableVideoModeration
|
requestEnableVideoModeration
|
||||||
|
// @ts-ignore
|
||||||
} from '../../../av-moderation/actions';
|
} from '../../../av-moderation/actions';
|
||||||
import {
|
import {
|
||||||
isEnabled as isAvModerationEnabled,
|
isEnabled as isAvModerationEnabled,
|
||||||
isSupported as isAvModerationSupported
|
isSupported as isAvModerationSupported
|
||||||
|
// @ts-ignore
|
||||||
} from '../../../av-moderation/functions';
|
} from '../../../av-moderation/functions';
|
||||||
|
// @ts-ignore
|
||||||
import { ContextMenu, ContextMenuItemGroup } from '../../../base/components';
|
import { ContextMenu, ContextMenuItemGroup } from '../../../base/components';
|
||||||
|
// @ts-ignore
|
||||||
import { openDialog } from '../../../base/dialog';
|
import { openDialog } from '../../../base/dialog';
|
||||||
import {
|
import {
|
||||||
IconCheck,
|
IconCheck,
|
||||||
IconHorizontalPoints,
|
IconHorizontalPoints,
|
||||||
IconVideoOff
|
IconVideoOff
|
||||||
} from '../../../base/icons';
|
} from '../../../base/icons/svg';
|
||||||
import { MEDIA_TYPE } from '../../../base/media';
|
import { MEDIA_TYPE } from '../../../base/media/constants';
|
||||||
import {
|
import {
|
||||||
getParticipantCount,
|
getParticipantCount,
|
||||||
isEveryoneModerator
|
isEveryoneModerator
|
||||||
} from '../../../base/participants';
|
} from '../../../base/participants/functions';
|
||||||
|
// @ts-ignore
|
||||||
import { isInBreakoutRoom } from '../../../breakout-rooms/functions';
|
import { isInBreakoutRoom } from '../../../breakout-rooms/functions';
|
||||||
import {
|
import {
|
||||||
SETTINGS_TABS,
|
SETTINGS_TABS,
|
||||||
openSettingsDialog,
|
openSettingsDialog,
|
||||||
shouldShowModeratorSettings
|
shouldShowModeratorSettings
|
||||||
|
// @ts-ignore
|
||||||
} from '../../../settings';
|
} from '../../../settings';
|
||||||
|
// @ts-ignore
|
||||||
import { MuteEveryonesVideoDialog } from '../../../video-menu/components';
|
import { MuteEveryonesVideoDialog } from '../../../video-menu/components';
|
||||||
|
|
||||||
const useStyles = makeStyles(theme => {
|
const useStyles = makeStyles((theme: any) => {
|
||||||
return {
|
return {
|
||||||
contextMenu: {
|
contextMenu: {
|
||||||
bottom: 'auto',
|
bottom: 'auto',
|
|
@ -1,40 +1,45 @@
|
||||||
// @flow
|
/* eslint-disable lines-around-comment */
|
||||||
|
|
||||||
import { makeStyles } from '@material-ui/styles';
|
import { makeStyles } from '@material-ui/styles';
|
||||||
import React, { useCallback, useState, useRef } from 'react';
|
import React, { useCallback, useState, useRef } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useSelector } from 'react-redux';
|
import { useSelector } from 'react-redux';
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
import { ContextMenu, ContextMenuItemGroup } from '../../../base/components';
|
import { ContextMenu, ContextMenuItemGroup } from '../../../base/components';
|
||||||
import { IconChat, IconCloseCircle, IconHorizontalPoints } from '../../../base/icons';
|
import { IconChat, IconCloseCircle, IconHorizontalPoints } from '../../../base/icons/svg/index';
|
||||||
import { hasRaisedHand } from '../../../base/participants';
|
import { hasRaisedHand } from '../../../base/participants/functions';
|
||||||
|
import { Participant } from '../../../base/participants/reducer';
|
||||||
import Button from '../../../base/ui/components/web/Button';
|
import Button from '../../../base/ui/components/web/Button';
|
||||||
import { BUTTON_TYPES } from '../../../base/ui/constants';
|
import { BUTTON_TYPES } from '../../../base/ui/constants';
|
||||||
|
// @ts-ignore
|
||||||
import { showLobbyChatButton } from '../../../lobby/functions';
|
import { showLobbyChatButton } from '../../../lobby/functions';
|
||||||
|
// @ts-ignore
|
||||||
import { ACTION_TRIGGER, MEDIA_STATE } from '../../constants';
|
import { ACTION_TRIGGER, MEDIA_STATE } from '../../constants';
|
||||||
|
// @ts-ignore
|
||||||
import { useLobbyActions } from '../../hooks';
|
import { useLobbyActions } from '../../hooks';
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
import ParticipantItem from './ParticipantItem';
|
import ParticipantItem from './ParticipantItem';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
|
||||||
/**
|
|
||||||
* If an overflow drawer should be displayed.
|
|
||||||
*/
|
|
||||||
overflowDrawer: boolean,
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback used to open a drawer with admit/reject actions.
|
* Callback used to open a drawer with admit/reject actions.
|
||||||
*/
|
*/
|
||||||
openDrawerForParticipant: Function,
|
openDrawerForParticipant: Function,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If an overflow drawer should be displayed.
|
||||||
|
*/
|
||||||
|
overflowDrawer: boolean,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Participant reference.
|
* Participant reference.
|
||||||
*/
|
*/
|
||||||
participant: Object
|
participant: Participant
|
||||||
};
|
};
|
||||||
|
|
||||||
const useStyles = makeStyles(theme => {
|
const useStyles = makeStyles((theme: any) => {
|
||||||
return {
|
return {
|
||||||
button: {
|
button: {
|
||||||
marginRight: `${theme.spacing(2)}px`
|
marginRight: `${theme.spacing(2)}px`
|
||||||
|
@ -67,8 +72,8 @@ export const LobbyParticipantItem = ({
|
||||||
|
|
||||||
const moreButtonRef = useRef();
|
const moreButtonRef = useRef();
|
||||||
|
|
||||||
const openContextMenu = useCallback(() => setIsOpen(true));
|
const openContextMenu = useCallback(() => setIsOpen(true), []);
|
||||||
const closeContextMenu = useCallback(() => setIsOpen(false));
|
const closeContextMenu = useCallback(() => setIsOpen(false), []);
|
||||||
|
|
||||||
const renderAdmitButton = () => (
|
const renderAdmitButton = () => (
|
||||||
<Button
|
<Button
|
|
@ -1,22 +1,29 @@
|
||||||
// @flow
|
/* eslint-disable lines-around-comment */
|
||||||
|
|
||||||
import { makeStyles } from '@material-ui/core/styles';
|
import { makeStyles } from '@material-ui/core/styles';
|
||||||
import React, { useCallback } from 'react';
|
import React, { useCallback } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useSelector, useDispatch } from 'react-redux';
|
import { useSelector, useDispatch } from 'react-redux';
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
import { Avatar } from '../../../base/avatar';
|
import { Avatar } from '../../../base/avatar';
|
||||||
import { Icon, IconCheck, IconClose } from '../../../base/icons';
|
import Icon from '../../../base/icons/components/Icon';
|
||||||
|
import { IconCheck, IconClose } from '../../../base/icons/svg/index';
|
||||||
import { withPixelLineHeight } from '../../../base/styles/functions.web';
|
import { withPixelLineHeight } from '../../../base/styles/functions.web';
|
||||||
|
// @ts-ignore
|
||||||
import { admitMultiple } from '../../../lobby/actions.web';
|
import { admitMultiple } from '../../../lobby/actions.web';
|
||||||
|
// @ts-ignore
|
||||||
import { getLobbyEnabled, getKnockingParticipants } from '../../../lobby/functions';
|
import { getLobbyEnabled, getKnockingParticipants } from '../../../lobby/functions';
|
||||||
|
// @ts-ignore
|
||||||
import { Drawer, JitsiPortal } from '../../../toolbox/components/web';
|
import { Drawer, JitsiPortal } from '../../../toolbox/components/web';
|
||||||
|
// @ts-ignore
|
||||||
import { showOverflowDrawer } from '../../../toolbox/functions';
|
import { showOverflowDrawer } from '../../../toolbox/functions';
|
||||||
|
// @ts-ignore
|
||||||
import { useLobbyActions, useParticipantDrawer } from '../../hooks';
|
import { useLobbyActions, useParticipantDrawer } from '../../hooks';
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
import LobbyParticipantItems from './LobbyParticipantItems';
|
import LobbyParticipantItems from './LobbyParticipantItems';
|
||||||
|
|
||||||
const useStyles = makeStyles(theme => {
|
const useStyles = makeStyles((theme: any) => {
|
||||||
return {
|
return {
|
||||||
drawerActions: {
|
drawerActions: {
|
||||||
listStyleType: 'none',
|
listStyleType: 'none',
|
||||||
|
@ -67,7 +74,7 @@ const useStyles = makeStyles(theme => {
|
||||||
*/
|
*/
|
||||||
export default function LobbyParticipants() {
|
export default function LobbyParticipants() {
|
||||||
const lobbyEnabled = useSelector(getLobbyEnabled);
|
const lobbyEnabled = useSelector(getLobbyEnabled);
|
||||||
const participants = useSelector(getKnockingParticipants);
|
const participants: Array<Object> = useSelector(getKnockingParticipants);
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
|
@ -1,30 +1,40 @@
|
||||||
// @flow
|
/* eslint-disable lines-around-comment */
|
||||||
|
|
||||||
import { makeStyles } from '@material-ui/styles';
|
import { makeStyles } from '@material-ui/styles';
|
||||||
import React, { useCallback } from 'react';
|
import React, { useCallback } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useDispatch, useSelector } from 'react-redux';
|
import { useDispatch, useSelector } from 'react-redux';
|
||||||
|
|
||||||
|
import { IState } from '../../../app/types';
|
||||||
|
// @ts-ignore
|
||||||
import { rejectParticipantAudio } from '../../../av-moderation/actions';
|
import { rejectParticipantAudio } from '../../../av-moderation/actions';
|
||||||
|
// @ts-ignore
|
||||||
import useContextMenu from '../../../base/components/context-menu/useContextMenu';
|
import useContextMenu from '../../../base/components/context-menu/useContextMenu';
|
||||||
import participantsPaneTheme from '../../../base/components/themes/participantsPaneTheme.json';
|
import participantsPaneTheme from '../../../base/components/themes/participantsPaneTheme.json';
|
||||||
|
// @ts-ignore
|
||||||
import { isToolbarButtonEnabled } from '../../../base/config/functions.web';
|
import { isToolbarButtonEnabled } from '../../../base/config/functions.web';
|
||||||
import { MEDIA_TYPE } from '../../../base/media';
|
import { MEDIA_TYPE } from '../../../base/media/constants';
|
||||||
import { getParticipantById } from '../../../base/participants';
|
import { getParticipantById } from '../../../base/participants/functions';
|
||||||
import { connect } from '../../../base/redux';
|
import { connect } from '../../../base/redux/functions';
|
||||||
import Input from '../../../base/ui/components/web/Input';
|
import Input from '../../../base/ui/components/web/Input';
|
||||||
import { normalizeAccents } from '../../../base/util/strings';
|
import { normalizeAccents } from '../../../base/util/strings.web';
|
||||||
|
// @ts-ignore
|
||||||
import { getBreakoutRooms, getCurrentRoomId, isInBreakoutRoom } from '../../../breakout-rooms/functions';
|
import { getBreakoutRooms, getCurrentRoomId, isInBreakoutRoom } from '../../../breakout-rooms/functions';
|
||||||
|
// @ts-ignore
|
||||||
import { showOverflowDrawer } from '../../../toolbox/functions';
|
import { showOverflowDrawer } from '../../../toolbox/functions';
|
||||||
|
// @ts-ignore
|
||||||
import { muteRemote } from '../../../video-menu/actions.any';
|
import { muteRemote } from '../../../video-menu/actions.any';
|
||||||
|
// @ts-ignore
|
||||||
import { getSortedParticipantIds, shouldRenderInviteButton } from '../../functions';
|
import { getSortedParticipantIds, shouldRenderInviteButton } from '../../functions';
|
||||||
|
// @ts-ignore
|
||||||
import { useParticipantDrawer } from '../../hooks';
|
import { useParticipantDrawer } from '../../hooks';
|
||||||
|
|
||||||
import { InviteButton } from './InviteButton';
|
import { InviteButton } from './InviteButton';
|
||||||
|
// @ts-ignore
|
||||||
import MeetingParticipantContextMenu from './MeetingParticipantContextMenu';
|
import MeetingParticipantContextMenu from './MeetingParticipantContextMenu';
|
||||||
|
// @ts-ignore
|
||||||
import MeetingParticipantItems from './MeetingParticipantItems';
|
import MeetingParticipantItems from './MeetingParticipantItems';
|
||||||
|
|
||||||
const useStyles = makeStyles(theme => {
|
const useStyles = makeStyles((theme: any) => {
|
||||||
return {
|
return {
|
||||||
heading: {
|
heading: {
|
||||||
color: theme.palette.text02,
|
color: theme.palette.text02,
|
||||||
|
@ -48,13 +58,13 @@ const useStyles = makeStyles(theme => {
|
||||||
});
|
});
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
currentRoom: ?Object,
|
currentRoom?: {name: string},
|
||||||
participantsCount: number,
|
overflowDrawer?: boolean,
|
||||||
overflowDrawer: boolean,
|
participantsCount?: number,
|
||||||
searchString: string,
|
searchString: string,
|
||||||
setSearchString: Function,
|
setSearchString: (newValue: string) => void,
|
||||||
showInviteButton: boolean,
|
showInviteButton?: boolean,
|
||||||
sortedParticipantIds: Array<string>
|
sortedParticipantIds?: Array<string>
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -156,15 +166,15 @@ function MeetingParticipants({
|
||||||
* @private
|
* @private
|
||||||
* @returns {Props}
|
* @returns {Props}
|
||||||
*/
|
*/
|
||||||
function _mapStateToProps(state): Object {
|
function _mapStateToProps(state: IState): Object {
|
||||||
let sortedParticipantIds = getSortedParticipantIds(state);
|
let sortedParticipantIds: any = getSortedParticipantIds(state);
|
||||||
|
|
||||||
// Filter out the virtual screenshare participants since we do not want them to be displayed as separate
|
// Filter out the virtual screenshare participants since we do not want them to be displayed as separate
|
||||||
// participants in the participants pane.
|
// participants in the participants pane.
|
||||||
sortedParticipantIds = sortedParticipantIds.filter(id => {
|
sortedParticipantIds = sortedParticipantIds.filter((id: any) => {
|
||||||
const participant = getParticipantById(state, id);
|
const participant = getParticipantById(state, id);
|
||||||
|
|
||||||
return !participant.isVirtualScreenshareParticipant;
|
return !participant?.isVirtualScreenshareParticipant;
|
||||||
});
|
});
|
||||||
|
|
||||||
const participantsCount = sortedParticipantIds.length;
|
const participantsCount = sortedParticipantIds.length;
|
|
@ -1,10 +1,13 @@
|
||||||
// @flow
|
/* eslint-disable lines-around-comment */
|
||||||
|
|
||||||
import { makeStyles } from '@material-ui/styles';
|
import { makeStyles } from '@material-ui/styles';
|
||||||
import React, { type Node, useCallback } from 'react';
|
import React, { ReactElement, useCallback } from 'react';
|
||||||
|
import { WithTranslation } from 'react-i18next';
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
import { Avatar } from '../../../base/avatar';
|
import { Avatar } from '../../../base/avatar';
|
||||||
|
// @ts-ignore
|
||||||
import { ListItem } from '../../../base/components';
|
import { ListItem } from '../../../base/components';
|
||||||
|
// @ts-ignore
|
||||||
import { translate } from '../../../base/i18n';
|
import { translate } from '../../../base/i18n';
|
||||||
import {
|
import {
|
||||||
ACTION_TRIGGER,
|
ACTION_TRIGGER,
|
||||||
|
@ -13,11 +16,13 @@ import {
|
||||||
type ActionTrigger,
|
type ActionTrigger,
|
||||||
type MediaState,
|
type MediaState,
|
||||||
VideoStateIcons
|
VideoStateIcons
|
||||||
|
// @ts-ignore
|
||||||
} from '../../constants';
|
} from '../../constants';
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
import { RaisedHandIndicator } from './RaisedHandIndicator';
|
import { RaisedHandIndicator } from './RaisedHandIndicator';
|
||||||
|
|
||||||
type Props = {
|
interface Props extends WithTranslation {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Type of trigger for the participant actions.
|
* Type of trigger for the participant actions.
|
||||||
|
@ -32,7 +37,7 @@ type Props = {
|
||||||
/**
|
/**
|
||||||
* React children.
|
* React children.
|
||||||
*/
|
*/
|
||||||
children?: Node,
|
children?: ReactElement,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether or not to disable the moderator indicator.
|
* Whether or not to disable the moderator indicator.
|
||||||
|
@ -59,16 +64,16 @@ type Props = {
|
||||||
*/
|
*/
|
||||||
local: boolean,
|
local: boolean,
|
||||||
|
|
||||||
/**
|
|
||||||
* Opens a drawer with participant actions.
|
|
||||||
*/
|
|
||||||
openDrawerForParticipant?: Function,
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback for when the mouse leaves this component.
|
* Callback for when the mouse leaves this component.
|
||||||
*/
|
*/
|
||||||
onLeave?: Function,
|
onLeave?: Function,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens a drawer with participant actions.
|
||||||
|
*/
|
||||||
|
openDrawerForParticipant?: Function,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If an overflow drawer can be opened.
|
* If an overflow drawer can be opened.
|
||||||
*/
|
*/
|
||||||
|
@ -89,18 +94,13 @@ type Props = {
|
||||||
*/
|
*/
|
||||||
videoMediaState?: MediaState,
|
videoMediaState?: MediaState,
|
||||||
|
|
||||||
/**
|
|
||||||
* Invoked to obtain translated strings.
|
|
||||||
*/
|
|
||||||
t: Function,
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The translated "you" text.
|
* The translated "you" text.
|
||||||
*/
|
*/
|
||||||
youText?: string
|
youText?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
const useStyles = makeStyles(theme => {
|
const useStyles = makeStyles((theme: any) => {
|
||||||
return {
|
return {
|
||||||
nameContainer: {
|
nameContainer: {
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
|
@ -150,7 +150,7 @@ function ParticipantItem({
|
||||||
() => openDrawerForParticipant && openDrawerForParticipant({
|
() => openDrawerForParticipant && openDrawerForParticipant({
|
||||||
participantID,
|
participantID,
|
||||||
displayName
|
displayName
|
||||||
}));
|
}), []);
|
||||||
|
|
||||||
const styles = useStyles();
|
const styles = useStyles();
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
// @flow
|
|
||||||
|
|
||||||
import { makeStyles } from '@material-ui/styles';
|
import { makeStyles } from '@material-ui/styles';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { Icon, IconRaisedHandHollow } from '../../../base/icons';
|
import Icon from '../../../base/icons/components/Icon';
|
||||||
import BaseTheme from '../../../base/ui/components/BaseTheme';
|
import { IconRaisedHandHollow } from '../../../base/icons/svg/index';
|
||||||
|
import BaseTheme from '../../../base/ui/components/BaseTheme.web';
|
||||||
|
|
||||||
const useStyles = makeStyles(theme => {
|
const useStyles = makeStyles((theme: any) => {
|
||||||
return {
|
return {
|
||||||
indicator: {
|
indicator: {
|
||||||
backgroundColor: theme.palette.warning02,
|
backgroundColor: theme.palette.warning02,
|
|
@ -1,16 +1,14 @@
|
||||||
// @flow
|
|
||||||
|
|
||||||
import { withStyles } from '@material-ui/styles';
|
import { withStyles } from '@material-ui/styles';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { Icon } from '../../base/icons';
|
import Icon from '../../base/icons/components/Icon';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The css classes generated from theme.
|
* The css classes generated from theme.
|
||||||
*/
|
*/
|
||||||
classes: Object,
|
classes: any,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attribute used in automated testing.
|
* Attribute used in automated testing.
|
||||||
|
@ -20,7 +18,7 @@ type Props = {
|
||||||
/**
|
/**
|
||||||
* The button's icon.
|
* The button's icon.
|
||||||
*/
|
*/
|
||||||
icon: HTMLElement,
|
icon: Function,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The button's label.
|
* The button's label.
|
||||||
|
@ -30,17 +28,12 @@ type Props = {
|
||||||
/**
|
/**
|
||||||
* Function to be called when button is clicked.
|
* Function to be called when button is clicked.
|
||||||
*/
|
*/
|
||||||
onButtonClick: Function,
|
onButtonClick: (e?: React.MouseEvent) => void,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function to be called on key pressed.
|
* Function to be called on key pressed.
|
||||||
*/
|
*/
|
||||||
onKeyPressed: Function,
|
onKeyPressed: (e?: React.KeyboardEvent) => void
|
||||||
|
|
||||||
/**
|
|
||||||
* Used for translation.
|
|
||||||
*/
|
|
||||||
t: Function
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -50,7 +43,7 @@ type Props = {
|
||||||
*
|
*
|
||||||
* @returns {Object}
|
* @returns {Object}
|
||||||
*/
|
*/
|
||||||
const styles = theme => {
|
const styles = (theme: any) => {
|
||||||
return {
|
return {
|
||||||
prejoinPreviewDropdownBtn: {
|
prejoinPreviewDropdownBtn: {
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
|
@ -1,14 +1,17 @@
|
||||||
// @flow
|
/* eslint-disable lines-around-comment */
|
||||||
|
|
||||||
import { makeStyles } from '@material-ui/styles';
|
import { makeStyles } from '@material-ui/styles';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { WithTranslation } from 'react-i18next';
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
import { Avatar } from '../../../base/avatar';
|
import { Avatar } from '../../../base/avatar';
|
||||||
import { translate } from '../../../base/i18n';
|
import { translate } from '../../../base/i18n/functions';
|
||||||
import { Icon, IconClose } from '../../../base/icons';
|
import Icon from '../../../base/icons/components/Icon';
|
||||||
|
import { IconClose } from '../../../base/icons/svg/index';
|
||||||
|
// @ts-ignore
|
||||||
import Label from '../Label';
|
import Label from '../Label';
|
||||||
|
|
||||||
type Props = {
|
interface Props extends WithTranslation {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The phone number that is being called.
|
* The phone number that is being called.
|
||||||
|
@ -28,15 +31,10 @@ type Props = {
|
||||||
/**
|
/**
|
||||||
* The status of the call.
|
* The status of the call.
|
||||||
*/
|
*/
|
||||||
status: string,
|
status: string
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
const useStyles = makeStyles((theme: any) => {
|
||||||
* Used for translation.
|
|
||||||
*/
|
|
||||||
t: Function,
|
|
||||||
};
|
|
||||||
|
|
||||||
const useStyles = makeStyles(theme => {
|
|
||||||
return {
|
return {
|
||||||
callingDialog: {
|
callingDialog: {
|
||||||
padding: theme.spacing(3),
|
padding: theme.spacing(3),
|
|
@ -1,15 +1,19 @@
|
||||||
// @flow
|
/* eslint-disable lines-around-comment */
|
||||||
|
|
||||||
import { makeStyles } from '@material-ui/styles';
|
import { makeStyles } from '@material-ui/styles';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { WithTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import { translate } from '../../../base/i18n';
|
import { translate } from '../../../base/i18n/functions';
|
||||||
import { Icon, IconArrowLeft } from '../../../base/icons';
|
import Icon from '../../../base/icons/components/Icon';
|
||||||
|
import { IconArrowLeft } from '../../../base/icons/svg/index';
|
||||||
|
// @ts-ignore
|
||||||
import { ActionButton } from '../../../base/premeeting';
|
import { ActionButton } from '../../../base/premeeting';
|
||||||
|
// @ts-ignore
|
||||||
import { getCountryCodeFromPhone } from '../../utils';
|
import { getCountryCodeFromPhone } from '../../utils';
|
||||||
|
// @ts-ignore
|
||||||
import Label from '../Label';
|
import Label from '../Label';
|
||||||
|
|
||||||
type Props = {
|
interface Props extends WithTranslation {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The number to call in order to join the conference.
|
* The number to call in order to join the conference.
|
||||||
|
@ -21,11 +25,6 @@ type Props = {
|
||||||
*/
|
*/
|
||||||
onBack: Function,
|
onBack: Function,
|
||||||
|
|
||||||
/**
|
|
||||||
* Click handler for the text button.
|
|
||||||
*/
|
|
||||||
onTextButtonClick: Function,
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Click handler for primary button.
|
* Click handler for primary button.
|
||||||
*/
|
*/
|
||||||
|
@ -34,20 +33,20 @@ type Props = {
|
||||||
/**
|
/**
|
||||||
* Click handler for the small additional text.
|
* Click handler for the small additional text.
|
||||||
*/
|
*/
|
||||||
onSmallTextClick: Function,
|
onSmallTextClick: (e?: React.MouseEvent) => void,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Click handler for the text button.
|
||||||
|
*/
|
||||||
|
onTextButtonClick: (e?: React.MouseEvent) => void,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The passCode of the conference.
|
* The passCode of the conference.
|
||||||
*/
|
*/
|
||||||
passCode: string,
|
passCode: string
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
const useStyles = makeStyles((theme: any) => {
|
||||||
* Used for translation.
|
|
||||||
*/
|
|
||||||
t: Function,
|
|
||||||
};
|
|
||||||
|
|
||||||
const useStyles = makeStyles(theme => {
|
|
||||||
return {
|
return {
|
||||||
dialInDialog: {
|
dialInDialog: {
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
|
@ -1,15 +1,19 @@
|
||||||
// @flow
|
/* eslint-disable lines-around-comment */
|
||||||
|
|
||||||
import { makeStyles } from '@material-ui/styles';
|
import { makeStyles } from '@material-ui/styles';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { WithTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import { translate } from '../../../base/i18n';
|
import { translate } from '../../../base/i18n/functions';
|
||||||
import { Icon, IconClose } from '../../../base/icons';
|
import Icon from '../../../base/icons/components/Icon';
|
||||||
|
import { IconClose } from '../../../base/icons/svg/index';
|
||||||
|
// @ts-ignore
|
||||||
import { ActionButton } from '../../../base/premeeting';
|
import { ActionButton } from '../../../base/premeeting';
|
||||||
|
// @ts-ignore
|
||||||
import Label from '../Label';
|
import Label from '../Label';
|
||||||
|
// @ts-ignore
|
||||||
import CountryPicker from '../country-picker/CountryPicker';
|
import CountryPicker from '../country-picker/CountryPicker';
|
||||||
|
|
||||||
type Props = {
|
interface Props extends WithTranslation {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Closes a dialog.
|
* Closes a dialog.
|
||||||
|
@ -24,15 +28,10 @@ type Props = {
|
||||||
/**
|
/**
|
||||||
* Handler for text button.
|
* Handler for text button.
|
||||||
*/
|
*/
|
||||||
onTextButtonClick: Function,
|
onTextButtonClick: Function
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
const useStyles = makeStyles((theme: any) => {
|
||||||
* Used for translation.
|
|
||||||
*/
|
|
||||||
t: Function,
|
|
||||||
};
|
|
||||||
|
|
||||||
const useStyles = makeStyles(theme => {
|
|
||||||
return {
|
return {
|
||||||
dialOutDialog: {
|
dialOutDialog: {
|
||||||
padding: `${theme.spacing(3)}px`
|
padding: `${theme.spacing(3)}px`
|
|
@ -1,18 +1,21 @@
|
||||||
// @flow
|
|
||||||
|
|
||||||
import { makeStyles } from '@material-ui/styles';
|
import { makeStyles } from '@material-ui/styles';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { WithTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import { translate } from '../../../base/i18n';
|
import { IState } from '../../../app/types';
|
||||||
import { Icon, IconCheckSolid, IconExclamationTriangle } from '../../../base/icons';
|
import { translate } from '../../../base/i18n/functions';
|
||||||
import { connect } from '../../../base/redux';
|
import Icon from '../../../base/icons/components/Icon';
|
||||||
|
import { IconCheckSolid, IconExclamationTriangle } from '../../../base/icons/svg';
|
||||||
|
import { connect } from '../../../base/redux/functions';
|
||||||
import {
|
import {
|
||||||
getDeviceStatusType,
|
getDeviceStatusType,
|
||||||
getDeviceStatusText
|
getDeviceStatusText
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
} from '../../functions';
|
} from '../../functions';
|
||||||
|
|
||||||
export type Props = {
|
export interface Props extends WithTranslation {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The text to be displayed in relation to the status of the audio/video devices.
|
* The text to be displayed in relation to the status of the audio/video devices.
|
||||||
|
@ -23,15 +26,10 @@ export type Props = {
|
||||||
* The type of status for current devices, controlling the background color of the text.
|
* The type of status for current devices, controlling the background color of the text.
|
||||||
* Can be `ok` or `warning`.
|
* Can be `ok` or `warning`.
|
||||||
*/
|
*/
|
||||||
deviceStatusType: string,
|
deviceStatusType: string
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
const useStyles = makeStyles((theme: any) => {
|
||||||
* Used for translation.
|
|
||||||
*/
|
|
||||||
t: Function
|
|
||||||
};
|
|
||||||
|
|
||||||
const useStyles = makeStyles(theme => {
|
|
||||||
return {
|
return {
|
||||||
deviceStatus: {
|
deviceStatus: {
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
|
@ -87,7 +85,7 @@ const iconMap = {
|
||||||
*/
|
*/
|
||||||
function DeviceStatus({ deviceStatusType, deviceStatusText, t }: Props) {
|
function DeviceStatus({ deviceStatusType, deviceStatusText, t }: Props) {
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
const { src, className } = iconMap[deviceStatusType];
|
const { src, className } = iconMap[deviceStatusType as keyof typeof iconMap];
|
||||||
const hasError = deviceStatusType === 'warning';
|
const hasError = deviceStatusType === 'warning';
|
||||||
const containerClassName = clsx(classes.deviceStatus, { 'device-status-error': hasError });
|
const containerClassName = clsx(classes.deviceStatus, { 'device-status-error': hasError });
|
||||||
|
|
||||||
|
@ -113,7 +111,7 @@ function DeviceStatus({ deviceStatusType, deviceStatusText, t }: Props) {
|
||||||
* @param {Object} state - The redux state.
|
* @param {Object} state - The redux state.
|
||||||
* @returns {{ deviceStatusText: string, deviceStatusText: string }}
|
* @returns {{ deviceStatusText: string, deviceStatusText: string }}
|
||||||
*/
|
*/
|
||||||
function mapStateToProps(state) {
|
function mapStateToProps(state: IState) {
|
||||||
return {
|
return {
|
||||||
deviceStatusText: getDeviceStatusText(state),
|
deviceStatusText: getDeviceStatusText(state),
|
||||||
deviceStatusType: getDeviceStatusType(state)
|
deviceStatusType: getDeviceStatusType(state)
|
|
@ -1,21 +1,26 @@
|
||||||
// @flow
|
/* eslint-disable lines-around-comment */
|
||||||
|
|
||||||
import { withStyles } from '@material-ui/core';
|
import { withStyles } from '@material-ui/core';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
import { StartRecordingDialog } from '../..';
|
||||||
|
// @ts-ignore
|
||||||
import { openDialog } from '../../../../base/dialog';
|
import { openDialog } from '../../../../base/dialog';
|
||||||
import { translate } from '../../../../base/i18n';
|
import { translate } from '../../../../base/i18n/functions';
|
||||||
import { IconHighlight } from '../../../../base/icons';
|
import { IconHighlight } from '../../../../base/icons/svg';
|
||||||
|
// @ts-ignore
|
||||||
import { Label } from '../../../../base/label';
|
import { Label } from '../../../../base/label';
|
||||||
import { connect } from '../../../../base/redux';
|
import { connect } from '../../../../base/redux/functions';
|
||||||
|
// @ts-ignore
|
||||||
import { Tooltip } from '../../../../base/tooltip';
|
import { Tooltip } from '../../../../base/tooltip';
|
||||||
import BaseTheme from '../../../../base/ui/components/BaseTheme';
|
import BaseTheme from '../../../../base/ui/components/BaseTheme.web';
|
||||||
|
// @ts-ignore
|
||||||
import { maybeShowPremiumFeatureDialog } from '../../../../jaas/actions';
|
import { maybeShowPremiumFeatureDialog } from '../../../../jaas/actions';
|
||||||
import { FEATURES } from '../../../../jaas/constants';
|
import { FEATURES } from '../../../../jaas/constants';
|
||||||
import { StartRecordingDialog } from '../../../components';
|
|
||||||
import AbstractHighlightButton, {
|
import AbstractHighlightButton, {
|
||||||
_abstractMapStateToProps,
|
_abstractMapStateToProps,
|
||||||
type Props as AbstractProps
|
type Props as AbstractProps
|
||||||
|
// @ts-ignore
|
||||||
} from '../AbstractHighlightButton';
|
} from '../AbstractHighlightButton';
|
||||||
|
|
||||||
type Props = AbstractProps & {
|
type Props = AbstractProps & {
|
||||||
|
@ -35,7 +40,7 @@ type Props = AbstractProps & {
|
||||||
/**
|
/**
|
||||||
* The type of the React {@code Component} state of {@link HighlightButton}.
|
* The type of the React {@code Component} state of {@link HighlightButton}.
|
||||||
*/
|
*/
|
||||||
type State = {
|
type State = {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the notification which prompts for starting recording is open is not.
|
* Whether the notification which prompts for starting recording is open is not.
|
||||||
|
@ -50,7 +55,7 @@ type Props = AbstractProps & {
|
||||||
*
|
*
|
||||||
* @returns {Object}
|
* @returns {Object}
|
||||||
*/
|
*/
|
||||||
const styles = theme => {
|
const styles = (theme: any) => {
|
||||||
return {
|
return {
|
||||||
container: {
|
container: {
|
||||||
position: 'relative'
|
position: 'relative'
|
||||||
|
@ -100,6 +105,7 @@ export class HighlightButton extends AbstractHighlightButton<Props, State> {
|
||||||
constructor(props: Props) {
|
constructor(props: Props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
this.state = {
|
this.state = {
|
||||||
isNotificationOpen: false
|
isNotificationOpen: false
|
||||||
};
|
};
|
||||||
|
@ -132,6 +138,7 @@ export class HighlightButton extends AbstractHighlightButton<Props, State> {
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
async _onOpenDialog() {
|
async _onOpenDialog() {
|
||||||
|
// @ts-ignore
|
||||||
const { dispatch } = this.props;
|
const { dispatch } = this.props;
|
||||||
const dialogShown = await dispatch(maybeShowPremiumFeatureDialog(FEATURES.RECORDING));
|
const dialogShown = await dispatch(maybeShowPremiumFeatureDialog(FEATURES.RECORDING));
|
||||||
|
|
||||||
|
@ -147,12 +154,14 @@ export class HighlightButton extends AbstractHighlightButton<Props, State> {
|
||||||
* @param {Event} e - The click event.
|
* @param {Event} e - The click event.
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
_onClick(e) {
|
_onClick(e: React.MouseEvent) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
const { _disabled } = this.props;
|
const { _disabled } = this.props;
|
||||||
|
|
||||||
if (_disabled) {
|
if (_disabled) {
|
||||||
|
// @ts-ignore
|
||||||
this.setState({
|
this.setState({
|
||||||
isNotificationOpen: true
|
isNotificationOpen: true
|
||||||
});
|
});
|
||||||
|
@ -167,6 +176,7 @@ export class HighlightButton extends AbstractHighlightButton<Props, State> {
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
_onWindowClickListener() {
|
_onWindowClickListener() {
|
||||||
|
// @ts-ignore
|
||||||
this.setState({
|
this.setState({
|
||||||
isNotificationOpen: false
|
isNotificationOpen: false
|
||||||
});
|
});
|
||||||
|
@ -184,6 +194,7 @@ export class HighlightButton extends AbstractHighlightButton<Props, State> {
|
||||||
_visible,
|
_visible,
|
||||||
classes,
|
classes,
|
||||||
t
|
t
|
||||||
|
// @ts-ignore
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
|
|
||||||
|
@ -206,6 +217,7 @@ export class HighlightButton extends AbstractHighlightButton<Props, State> {
|
||||||
id = 'highlightMeetingLabel'
|
id = 'highlightMeetingLabel'
|
||||||
onClick = { this._onClick } />
|
onClick = { this._onClick } />
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
{/* @ts-ignore */}
|
||||||
{this.state.isNotificationOpen && (
|
{this.state.isNotificationOpen && (
|
||||||
<div className = { classes.highlightNotification }>
|
<div className = { classes.highlightNotification }>
|
||||||
{t('recording.highlightMomentDisabled')}
|
{t('recording.highlightMomentDisabled')}
|
||||||
|
@ -221,4 +233,5 @@ export class HighlightButton extends AbstractHighlightButton<Props, State> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
export default withStyles(styles)(translate(connect(_abstractMapStateToProps)(HighlightButton)));
|
export default withStyles(styles)(translate(connect(_abstractMapStateToProps)(HighlightButton)));
|
|
@ -1,14 +1,15 @@
|
||||||
// @flow
|
/* eslint-disable lines-around-comment */
|
||||||
|
|
||||||
import { withStyles } from '@material-ui/core/styles';
|
import { withStyles } from '@material-ui/core/styles';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { translate } from '../../../base/i18n';
|
import { translate } from '../../../base/i18n/functions';
|
||||||
|
// @ts-ignore
|
||||||
import { Label } from '../../../base/label';
|
import { Label } from '../../../base/label';
|
||||||
import { JitsiRecordingConstants } from '../../../base/lib-jitsi-meet';
|
import { JitsiRecordingConstants } from '../../../base/lib-jitsi-meet';
|
||||||
import { connect } from '../../../base/redux';
|
import { connect } from '../../../base/redux/functions';
|
||||||
import AbstractRecordingLabel, {
|
import AbstractRecordingLabel, {
|
||||||
_mapStateToProps
|
_mapStateToProps
|
||||||
|
// @ts-ignore
|
||||||
} from '../AbstractRecordingLabel';
|
} from '../AbstractRecordingLabel';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -18,7 +19,7 @@ import AbstractRecordingLabel, {
|
||||||
*
|
*
|
||||||
* @returns {Object}
|
* @returns {Object}
|
||||||
*/
|
*/
|
||||||
const styles = theme => {
|
const styles = (theme: any) => {
|
||||||
return {
|
return {
|
||||||
[JitsiRecordingConstants.mode.STREAM]: {
|
[JitsiRecordingConstants.mode.STREAM]: {
|
||||||
background: theme.palette.ui03
|
background: theme.palette.ui03
|
||||||
|
@ -42,24 +43,26 @@ class RecordingLabel extends AbstractRecordingLabel {
|
||||||
* @inheritdoc
|
* @inheritdoc
|
||||||
*/
|
*/
|
||||||
_renderLabel() {
|
_renderLabel() {
|
||||||
|
// @ts-ignore
|
||||||
if (this.props._status !== JitsiRecordingConstants.status.ON) {
|
if (this.props._status !== JitsiRecordingConstants.status.ON) {
|
||||||
// Since there are no expanded labels on web, we only render this
|
// Since there are no expanded labels on web, we only render this
|
||||||
// label when the recording status is ON.
|
// label when the recording status is ON.
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
const { classes, mode, t } = this.props;
|
const { classes, mode, t } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Label
|
<Label
|
||||||
className = { classes && classes[mode] }
|
className = { classes && classes[mode] }
|
||||||
|
// @ts-ignore
|
||||||
text = { t(this._getLabelKey()) } />
|
text = { t(this._getLabelKey()) } />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
_getLabelKey: () => ?string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
export default withStyles(styles)(translate(connect(_mapStateToProps)(RecordingLabel)));
|
export default withStyles(styles)(translate(connect(_mapStateToProps)(RecordingLabel)));
|
|
@ -1,8 +1,8 @@
|
||||||
// @flow
|
|
||||||
import { makeStyles } from '@material-ui/core';
|
import { makeStyles } from '@material-ui/core';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
import { RECORD_TYPE } from '../../constants';
|
import { RECORD_TYPE } from '../../constants';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -13,25 +13,25 @@ type Props = {
|
||||||
/**
|
/**
|
||||||
* The id of the record.
|
* The id of the record.
|
||||||
*/
|
*/
|
||||||
id: String,
|
id: string,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The name of the record.
|
* The name of the record.
|
||||||
*/
|
*/
|
||||||
name: String,
|
name: string,
|
||||||
|
|
||||||
/**
|
|
||||||
* The type of the record.
|
|
||||||
*/
|
|
||||||
type: String,
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The handler for the click event.
|
* The handler for the click event.
|
||||||
*/
|
*/
|
||||||
onClick: Function
|
onClick: (e?: React.MouseEvent) => void,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of the record.
|
||||||
|
*/
|
||||||
|
type: string
|
||||||
}
|
}
|
||||||
|
|
||||||
const useStyles = makeStyles(theme => {
|
const useStyles = makeStyles((theme: any) => {
|
||||||
return {
|
return {
|
||||||
recordItem: {
|
recordItem: {
|
||||||
display: 'flex',
|
display: 'flex',
|
|
@ -1,21 +1,26 @@
|
||||||
// @flow
|
/* eslint-disable lines-around-comment */
|
||||||
|
|
||||||
import Spinner from '@atlaskit/spinner';
|
import Spinner from '@atlaskit/spinner';
|
||||||
import { makeStyles } from '@material-ui/core';
|
import { makeStyles } from '@material-ui/core';
|
||||||
import React, { useCallback } from 'react';
|
import React, { useCallback } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useDispatch } from 'react-redux';
|
import { useDispatch } from 'react-redux';
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
import { Dialog, hideDialog } from '../../../base/dialog';
|
import { Dialog, hideDialog } from '../../../base/dialog';
|
||||||
import { Icon, IconSearch } from '../../../base/icons';
|
import Icon from '../../../base/icons/components/Icon';
|
||||||
|
import { IconSearch } from '../../../base/icons/svg/index';
|
||||||
|
// @ts-ignore
|
||||||
import { getFieldValue } from '../../../base/react';
|
import { getFieldValue } from '../../../base/react';
|
||||||
import BaseTheme from '../../../base/ui/components/BaseTheme';
|
import BaseTheme from '../../../base/ui/components/BaseTheme.web';
|
||||||
|
// @ts-ignore
|
||||||
import { NOTES_MAX_LENGTH } from '../../constants';
|
import { NOTES_MAX_LENGTH } from '../../constants';
|
||||||
|
// @ts-ignore
|
||||||
import { useSalesforceLinkDialog } from '../../useSalesforceLinkDialog';
|
import { useSalesforceLinkDialog } from '../../useSalesforceLinkDialog';
|
||||||
|
|
||||||
import { RecordItem } from './RecordItem';
|
import { RecordItem } from './RecordItem';
|
||||||
|
|
||||||
const useStyles = makeStyles(theme => {
|
// @ts-ignore
|
||||||
|
const useStyles = makeStyles((theme: any) => {
|
||||||
return {
|
return {
|
||||||
container: {
|
container: {
|
||||||
minHeight: '450px',
|
minHeight: '450px',
|
||||||
|
@ -136,7 +141,7 @@ function SalesforceLinkDialog() {
|
||||||
showSearchResults
|
showSearchResults
|
||||||
} = useSalesforceLinkDialog();
|
} = useSalesforceLinkDialog();
|
||||||
|
|
||||||
const handleChange = useCallback((event: Event) => {
|
const handleChange = useCallback((event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
const value = getFieldValue(event);
|
const value = getFieldValue(event);
|
||||||
|
|
||||||
setSearchTerm(value);
|
setSearchTerm(value);
|
||||||
|
@ -150,6 +155,7 @@ function SalesforceLinkDialog() {
|
||||||
const renderSpinner = () => (
|
const renderSpinner = () => (
|
||||||
<div className = { classes.spinner }>
|
<div className = { classes.spinner }>
|
||||||
<Spinner
|
<Spinner
|
||||||
|
// @ts-ignore
|
||||||
isCompleting = { false }
|
isCompleting = { false }
|
||||||
size = 'medium' />
|
size = 'medium' />
|
||||||
</div>
|
</div>
|
||||||
|
@ -176,7 +182,7 @@ function SalesforceLinkDialog() {
|
||||||
/* eslint-disable-next-line react/jsx-no-bind */
|
/* eslint-disable-next-line react/jsx-no-bind */
|
||||||
onChange = { e => setNotes(e.target.value) }
|
onChange = { e => setNotes(e.target.value) }
|
||||||
placeholder = { t('dialog.addMeetingNote') }
|
placeholder = { t('dialog.addMeetingNote') }
|
||||||
row = '4'
|
rows = { 4 }
|
||||||
value = { notes } />
|
value = { notes } />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -236,7 +242,7 @@ function SalesforceLinkDialog() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ul className = { classes.recordList }>
|
<ul className = { classes.recordList }>
|
||||||
{records.map(item => (
|
{records.map((item: any) => (
|
||||||
<RecordItem
|
<RecordItem
|
||||||
key = { `record-${item.id}` }
|
key = { `record-${item.id}` }
|
||||||
/* eslint-disable-next-line react/jsx-no-bind */
|
/* eslint-disable-next-line react/jsx-no-bind */
|
|
@ -1,38 +1,46 @@
|
||||||
// @flow
|
/* eslint-disable lines-around-comment */
|
||||||
|
|
||||||
import { withStyles } from '@material-ui/styles';
|
import { withStyles } from '@material-ui/styles';
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
|
|
||||||
|
import { IState } from '../../../app/types';
|
||||||
|
// @ts-ignore
|
||||||
import { getAvailableDevices } from '../../../base/devices';
|
import { getAvailableDevices } from '../../../base/devices';
|
||||||
|
// @ts-ignore
|
||||||
import { DialogWithTabs, hideDialog } from '../../../base/dialog';
|
import { DialogWithTabs, hideDialog } from '../../../base/dialog';
|
||||||
import { connect } from '../../../base/redux';
|
import { connect } from '../../../base/redux/functions';
|
||||||
|
// @ts-ignore
|
||||||
import { isCalendarEnabled } from '../../../calendar-sync';
|
import { isCalendarEnabled } from '../../../calendar-sync';
|
||||||
import {
|
import {
|
||||||
DeviceSelection,
|
DeviceSelection,
|
||||||
getDeviceSelectionDialogProps,
|
getDeviceSelectionDialogProps,
|
||||||
submitDeviceSelectionTab
|
submitDeviceSelectionTab
|
||||||
|
// @ts-ignore
|
||||||
} from '../../../device-selection';
|
} from '../../../device-selection';
|
||||||
import {
|
import {
|
||||||
submitModeratorTab,
|
submitModeratorTab,
|
||||||
submitMoreTab,
|
submitMoreTab,
|
||||||
submitProfileTab,
|
submitProfileTab,
|
||||||
submitSoundsTab
|
submitSoundsTab
|
||||||
|
// @ts-ignore
|
||||||
} from '../../actions';
|
} from '../../actions';
|
||||||
|
// @ts-ignore
|
||||||
import { SETTINGS_TABS } from '../../constants';
|
import { SETTINGS_TABS } from '../../constants';
|
||||||
import {
|
import {
|
||||||
getModeratorTabProps,
|
getModeratorTabProps,
|
||||||
getMoreTabProps,
|
getMoreTabProps,
|
||||||
getProfileTabProps,
|
getProfileTabProps,
|
||||||
getSoundsTabProps
|
getSoundsTabProps
|
||||||
|
// @ts-ignore
|
||||||
} from '../../functions';
|
} from '../../functions';
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
import CalendarTab from './CalendarTab';
|
import CalendarTab from './CalendarTab';
|
||||||
import ModeratorTab from './ModeratorTab';
|
import ModeratorTab from './ModeratorTab';
|
||||||
import MoreTab from './MoreTab';
|
import MoreTab from './MoreTab';
|
||||||
import ProfileTab from './ProfileTab';
|
import ProfileTab from './ProfileTab';
|
||||||
import SoundsTab from './SoundsTab';
|
import SoundsTab from './SoundsTab';
|
||||||
|
|
||||||
declare var interfaceConfig: Object;
|
declare let interfaceConfig: any;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The type of the React {@code Component} props of
|
* The type of the React {@code Component} props of
|
||||||
|
@ -40,6 +48,15 @@ declare var interfaceConfig: Object;
|
||||||
*/
|
*/
|
||||||
type Props = {
|
type Props = {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Information about the tabs to be rendered.
|
||||||
|
*/
|
||||||
|
_tabs: Array<{
|
||||||
|
name: string;
|
||||||
|
onMount: () => void;
|
||||||
|
submit: () => void;
|
||||||
|
}>,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An object containing the CSS classes.
|
* An object containing the CSS classes.
|
||||||
*/
|
*/
|
||||||
|
@ -51,11 +68,6 @@ type Props = {
|
||||||
*/
|
*/
|
||||||
defaultTab: string,
|
defaultTab: string,
|
||||||
|
|
||||||
/**
|
|
||||||
* Information about the tabs to be rendered.
|
|
||||||
*/
|
|
||||||
_tabs: Array<Object>,
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoked to save changed settings.
|
* Invoked to save changed settings.
|
||||||
*/
|
*/
|
||||||
|
@ -75,7 +87,7 @@ type Props = {
|
||||||
*
|
*
|
||||||
* @returns {Object}
|
* @returns {Object}
|
||||||
*/
|
*/
|
||||||
const styles = theme => {
|
const styles = (theme: any) => {
|
||||||
return {
|
return {
|
||||||
settingsDialog: {
|
settingsDialog: {
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
|
@ -110,6 +122,7 @@ const styles = theme => {
|
||||||
color: '#9FB0CC'
|
color: '#9FB0CC'
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
[[ '& .calendar-tab',
|
[[ '& .calendar-tab',
|
||||||
'& .more-tab',
|
'& .more-tab',
|
||||||
'& .box' ]]: {
|
'& .box' ]]: {
|
||||||
|
@ -225,9 +238,11 @@ class SettingsDialog extends Component<Props> {
|
||||||
return {
|
return {
|
||||||
...tab,
|
...tab,
|
||||||
onMount: tab.onMount
|
onMount: tab.onMount
|
||||||
? (...args) => dispatch(tab.onMount(...args))
|
// @ts-ignore
|
||||||
|
? (...args: any) => dispatch(tab.onMount(...args))
|
||||||
: undefined,
|
: undefined,
|
||||||
submit: (...args) => tab.submit
|
submit: (...args: any) => tab.submit
|
||||||
|
// @ts-ignore
|
||||||
&& dispatch(tab.submit(...args))
|
&& dispatch(tab.submit(...args))
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
@ -245,8 +260,6 @@ class SettingsDialog extends Component<Props> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
_closeDialog: () => void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback invoked to close the dialog without saving changes.
|
* Callback invoked to close the dialog without saving changes.
|
||||||
*
|
*
|
||||||
|
@ -269,7 +282,7 @@ class SettingsDialog extends Component<Props> {
|
||||||
* tabs: Array<Object>
|
* tabs: Array<Object>
|
||||||
* }}
|
* }}
|
||||||
*/
|
*/
|
||||||
function _mapStateToProps(state, ownProps) {
|
function _mapStateToProps(state: IState, ownProps: any) {
|
||||||
const { classes, isDisplayedOnWelcomePage } = ownProps;
|
const { classes, isDisplayedOnWelcomePage } = ownProps;
|
||||||
const configuredTabs = interfaceConfig.SETTINGS_SECTIONS || [];
|
const configuredTabs = interfaceConfig.SETTINGS_SECTIONS || [];
|
||||||
|
|
||||||
|
@ -293,7 +306,7 @@ function _mapStateToProps(state, ownProps) {
|
||||||
label: 'settings.devices',
|
label: 'settings.devices',
|
||||||
onMount: getAvailableDevices,
|
onMount: getAvailableDevices,
|
||||||
props: getDeviceSelectionDialogProps(state, isDisplayedOnWelcomePage),
|
props: getDeviceSelectionDialogProps(state, isDisplayedOnWelcomePage),
|
||||||
propsUpdateFunction: (tabState, newProps) => {
|
propsUpdateFunction: (tabState: any, newProps: any) => {
|
||||||
// Ensure the device selection tab gets updated when new devices
|
// Ensure the device selection tab gets updated when new devices
|
||||||
// are found by taking the new props and only preserving the
|
// are found by taking the new props and only preserving the
|
||||||
// current user selected devices. If this were not done, the
|
// current user selected devices. If this were not done, the
|
||||||
|
@ -308,7 +321,7 @@ function _mapStateToProps(state, ownProps) {
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
styles: `settings-pane ${classes.settingsDialog} devices-pane`,
|
styles: `settings-pane ${classes.settingsDialog} devices-pane`,
|
||||||
submit: newState => submitDeviceSelectionTab(newState, isDisplayedOnWelcomePage)
|
submit: (newState: any) => submitDeviceSelectionTab(newState, isDisplayedOnWelcomePage)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -329,7 +342,7 @@ function _mapStateToProps(state, ownProps) {
|
||||||
component: ModeratorTab,
|
component: ModeratorTab,
|
||||||
label: 'settings.moderator',
|
label: 'settings.moderator',
|
||||||
props: moderatorTabProps,
|
props: moderatorTabProps,
|
||||||
propsUpdateFunction: (tabState, newProps) => {
|
propsUpdateFunction: (tabState: any, newProps: any) => {
|
||||||
// Updates tab props, keeping users selection
|
// Updates tab props, keeping users selection
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -371,7 +384,7 @@ function _mapStateToProps(state, ownProps) {
|
||||||
component: MoreTab,
|
component: MoreTab,
|
||||||
label: 'settings.more',
|
label: 'settings.more',
|
||||||
props: moreTabProps,
|
props: moreTabProps,
|
||||||
propsUpdateFunction: (tabState, newProps) => {
|
propsUpdateFunction: (tabState: any, newProps: any) => {
|
||||||
// Updates tab props, keeping users selection
|
// Updates tab props, keeping users selection
|
||||||
|
|
||||||
return {
|
return {
|
|
@ -1,24 +1,30 @@
|
||||||
// @flow
|
/* eslint-disable lines-around-comment */
|
||||||
|
|
||||||
import { makeStyles } from '@material-ui/core/styles';
|
import { makeStyles } from '@material-ui/core/styles';
|
||||||
import React, { useCallback, useEffect } from 'react';
|
import React, { useCallback, useEffect } from 'react';
|
||||||
import { useSelector, useDispatch } from 'react-redux';
|
import { useSelector, useDispatch } from 'react-redux';
|
||||||
|
|
||||||
|
import { IState } from '../../../app/types';
|
||||||
|
// @ts-ignore
|
||||||
import { Dialog } from '../../../base/dialog';
|
import { Dialog } from '../../../base/dialog';
|
||||||
import { escapeRegexp } from '../../../base/util';
|
import { escapeRegexp } from '../../../base/util/helpers';
|
||||||
|
// @ts-ignore
|
||||||
import { resetSearchCriteria, toggleFaceExpressions, initSearch } from '../../actions';
|
import { resetSearchCriteria, toggleFaceExpressions, initSearch } from '../../actions';
|
||||||
import {
|
import {
|
||||||
DISPLAY_SWITCH_BREAKPOINT,
|
DISPLAY_SWITCH_BREAKPOINT,
|
||||||
MOBILE_BREAKPOINT,
|
MOBILE_BREAKPOINT,
|
||||||
RESIZE_SEARCH_SWITCH_CONTAINER_BREAKPOINT
|
RESIZE_SEARCH_SWITCH_CONTAINER_BREAKPOINT
|
||||||
|
// @ts-ignore
|
||||||
} from '../../constants';
|
} from '../../constants';
|
||||||
|
|
||||||
import FaceExpressionsSwitch from './FaceExpressionsSwitch';
|
import FaceExpressionsSwitch from './FaceExpressionsSwitch';
|
||||||
|
// @ts-ignore
|
||||||
import SpeakerStatsLabels from './SpeakerStatsLabels';
|
import SpeakerStatsLabels from './SpeakerStatsLabels';
|
||||||
|
// @ts-ignore
|
||||||
import SpeakerStatsList from './SpeakerStatsList';
|
import SpeakerStatsList from './SpeakerStatsList';
|
||||||
|
// @ts-ignore
|
||||||
import SpeakerStatsSearch from './SpeakerStatsSearch';
|
import SpeakerStatsSearch from './SpeakerStatsSearch';
|
||||||
|
|
||||||
const useStyles = makeStyles(theme => {
|
const useStyles = makeStyles((theme: any) => {
|
||||||
return {
|
return {
|
||||||
speakerStats: {
|
speakerStats: {
|
||||||
'& .row': {
|
'& .row': {
|
||||||
|
@ -88,9 +94,9 @@ const useStyles = makeStyles(theme => {
|
||||||
});
|
});
|
||||||
|
|
||||||
const SpeakerStats = () => {
|
const SpeakerStats = () => {
|
||||||
const { faceLandmarks } = useSelector(state => state['features/base/config']);
|
const { faceLandmarks } = useSelector((state: IState) => state['features/base/config']);
|
||||||
const { showFaceExpressions } = useSelector(state => state['features/speaker-stats']);
|
const { showFaceExpressions } = useSelector((state: any) => state['features/speaker-stats']);
|
||||||
const { clientWidth } = useSelector(state => state['features/base/responsive-ui']);
|
const { clientWidth } = useSelector((state: IState) => state['features/base/responsive-ui']);
|
||||||
const displaySwitch = faceLandmarks?.enableDisplayFaceExpressions && clientWidth > DISPLAY_SWITCH_BREAKPOINT;
|
const displaySwitch = faceLandmarks?.enableDisplayFaceExpressions && clientWidth > DISPLAY_SWITCH_BREAKPOINT;
|
||||||
const displayLabels = clientWidth > MOBILE_BREAKPOINT;
|
const displayLabels = clientWidth > MOBILE_BREAKPOINT;
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
|
@ -1,12 +1,12 @@
|
||||||
/* @flow */
|
|
||||||
import { makeStyles } from '@material-ui/core/styles';
|
import { makeStyles } from '@material-ui/core/styles';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
import { Tooltip } from '../../../base/tooltip';
|
import { Tooltip } from '../../../base/tooltip';
|
||||||
import { FACE_EXPRESSIONS_EMOJIS } from '../../../face-landmarks/constants';
|
import { FACE_EXPRESSIONS_EMOJIS } from '../../../face-landmarks/constants';
|
||||||
|
|
||||||
const useStyles = makeStyles(theme => {
|
const useStyles = makeStyles((theme: any) => {
|
||||||
return {
|
return {
|
||||||
labels: {
|
labels: {
|
||||||
padding: '22px 0 7px 0',
|
padding: '22px 0 7px 0',
|
||||||
|
@ -34,22 +34,6 @@ type Props = {
|
||||||
const SpeakerStatsLabels = (props: Props) => {
|
const SpeakerStatsLabels = (props: Props) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
const FaceExpressionsLabels = () => Object.keys(FACE_EXPRESSIONS_EMOJIS).map(
|
|
||||||
expression => (
|
|
||||||
<div
|
|
||||||
className = 'expression'
|
|
||||||
key = { expression }>
|
|
||||||
<Tooltip
|
|
||||||
content = { t(`speakerStats.${expression}`) }
|
|
||||||
position = { 'top' } >
|
|
||||||
<div>
|
|
||||||
{ FACE_EXPRESSIONS_EMOJIS[expression] }
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</Tooltip>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
);
|
|
||||||
const nameTimeClass = `name-time${
|
const nameTimeClass = `name-time${
|
||||||
props.showFaceExpressions ? ' name-time_expressions-on' : ''
|
props.showFaceExpressions ? ' name-time_expressions-on' : ''
|
||||||
}`;
|
}`;
|
||||||
|
@ -69,7 +53,22 @@ const SpeakerStatsLabels = (props: Props) => {
|
||||||
{
|
{
|
||||||
props.showFaceExpressions
|
props.showFaceExpressions
|
||||||
&& <div className = { `expressions ${classes.emojis}` }>
|
&& <div className = { `expressions ${classes.emojis}` }>
|
||||||
<FaceExpressionsLabels />
|
{Object.keys(FACE_EXPRESSIONS_EMOJIS).map(
|
||||||
|
expression => (
|
||||||
|
<div
|
||||||
|
className = 'expression'
|
||||||
|
key = { expression }>
|
||||||
|
<Tooltip
|
||||||
|
content = { t(`speakerStats.${expression}`) }
|
||||||
|
position = { 'top' } >
|
||||||
|
<div>
|
||||||
|
{FACE_EXPRESSIONS_EMOJIS[expression as keyof typeof FACE_EXPRESSIONS_EMOJIS]}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
|
@ -1,14 +1,16 @@
|
||||||
// @flow
|
/* eslint-disable lines-around-comment */
|
||||||
|
|
||||||
import { makeStyles } from '@material-ui/core/styles';
|
import { makeStyles } from '@material-ui/core/styles';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
import { MOBILE_BREAKPOINT } from '../../constants';
|
import { MOBILE_BREAKPOINT } from '../../constants';
|
||||||
|
// @ts-ignore
|
||||||
import abstractSpeakerStatsList from '../AbstractSpeakerStatsList';
|
import abstractSpeakerStatsList from '../AbstractSpeakerStatsList';
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
import SpeakerStatsItem from './SpeakerStatsItem';
|
import SpeakerStatsItem from './SpeakerStatsItem';
|
||||||
|
|
||||||
const useStyles = makeStyles(theme => {
|
const useStyles = makeStyles((theme: any) => {
|
||||||
return {
|
return {
|
||||||
list: {
|
list: {
|
||||||
marginTop: `${theme.spacing(3)}px`,
|
marginTop: `${theme.spacing(3)}px`,
|
|
@ -1,17 +1,20 @@
|
||||||
/* @flow */
|
/* eslint-disable lines-around-comment */
|
||||||
|
|
||||||
import { makeStyles } from '@material-ui/core/styles';
|
import { makeStyles } from '@material-ui/core/styles';
|
||||||
import React, { useCallback, useState } from 'react';
|
import React, { useCallback, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useSelector } from 'react-redux';
|
import { useSelector } from 'react-redux';
|
||||||
|
|
||||||
import { IconSearch, Icon } from '../../../base/icons';
|
import Icon from '../../../base/icons/components/Icon';
|
||||||
|
import { IconSearch } from '../../../base/icons/svg/index';
|
||||||
|
// @ts-ignore
|
||||||
import { getFieldValue } from '../../../base/react';
|
import { getFieldValue } from '../../../base/react';
|
||||||
import BaseTheme from '../../../base/ui/components/BaseTheme';
|
import BaseTheme from '../../../base/ui/components/BaseTheme.web';
|
||||||
|
// @ts-ignore
|
||||||
import { MOBILE_BREAKPOINT } from '../../constants';
|
import { MOBILE_BREAKPOINT } from '../../constants';
|
||||||
|
// @ts-ignore
|
||||||
import { isSpeakerStatsSearchDisabled } from '../../functions';
|
import { isSpeakerStatsSearchDisabled } from '../../functions';
|
||||||
|
|
||||||
const useStyles = makeStyles(theme => {
|
const useStyles = makeStyles((theme: any) => {
|
||||||
return {
|
return {
|
||||||
speakerStatsSearchContainer: {
|
speakerStatsSearchContainer: {
|
||||||
position: 'relative'
|
position: 'relative'
|
||||||
|
@ -83,13 +86,13 @@ function SpeakerStatsSearch({ onSearch }: Props) {
|
||||||
* @param {Object} evt - The static event.
|
* @param {Object} evt - The static event.
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
const onChange = useCallback((evt: Event) => {
|
const onChange = useCallback((evt: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
const value = getFieldValue(evt);
|
const value = getFieldValue(evt);
|
||||||
|
|
||||||
setSearchValue(value);
|
setSearchValue(value);
|
||||||
onSearch && onSearch(value);
|
onSearch && onSearch(value);
|
||||||
}, []);
|
}, []);
|
||||||
const preventDismiss = useCallback((evt: KeyboardEvent) => {
|
const preventDismiss = useCallback((evt: React.KeyboardEvent) => {
|
||||||
if (evt.key === 'Enter') {
|
if (evt.key === 'Enter') {
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
}
|
}
|
||||||
|
@ -103,7 +106,7 @@ function SpeakerStatsSearch({ onSearch }: Props) {
|
||||||
<div className = { classes.speakerStatsSearchContainer }>
|
<div className = { classes.speakerStatsSearchContainer }>
|
||||||
<Icon
|
<Icon
|
||||||
className = { classes.searchIcon }
|
className = { classes.searchIcon }
|
||||||
color = { BaseTheme.palette.surface07 }
|
color = { BaseTheme.palette.icon03 }
|
||||||
src = { IconSearch } />
|
src = { IconSearch } />
|
||||||
<input
|
<input
|
||||||
autoComplete = 'off'
|
autoComplete = 'off'
|
|
@ -1,22 +1,20 @@
|
||||||
// @flow
|
|
||||||
|
|
||||||
import { makeStyles } from '@material-ui/core';
|
import { makeStyles } from '@material-ui/core';
|
||||||
import React, { useCallback } from 'react';
|
import React, { ReactElement, useCallback } from 'react';
|
||||||
|
|
||||||
import { DRAWER_MAX_HEIGHT } from '../../constants';
|
import { DRAWER_MAX_HEIGHT } from '../../constants';
|
||||||
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
|
||||||
/**
|
|
||||||
* Class name for custom styles.
|
|
||||||
*/
|
|
||||||
className: string,
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The component(s) to be displayed within the drawer menu.
|
* The component(s) to be displayed within the drawer menu.
|
||||||
*/
|
*/
|
||||||
children: React$Node,
|
children: ReactElement,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class name for custom styles.
|
||||||
|
*/
|
||||||
|
className?: string,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the drawer should be shown or not.
|
* Whether the drawer should be shown or not.
|
||||||
|
@ -29,7 +27,7 @@ type Props = {
|
||||||
onClose: Function
|
onClose: Function
|
||||||
};
|
};
|
||||||
|
|
||||||
const useStyles = makeStyles(theme => {
|
const useStyles = makeStyles((theme: any) => {
|
||||||
return {
|
return {
|
||||||
drawer: {
|
drawer: {
|
||||||
backgroundColor: theme.palette.ui02,
|
backgroundColor: theme.palette.ui02,
|
|
@ -1,25 +1,30 @@
|
||||||
/* @flow */
|
/* eslint-disable lines-around-comment */
|
||||||
|
|
||||||
import InlineDialog from '@atlaskit/inline-dialog';
|
import InlineDialog from '@atlaskit/inline-dialog';
|
||||||
import { withStyles } from '@material-ui/styles';
|
import { withStyles } from '@material-ui/styles';
|
||||||
import React, { Component } from 'react';
|
import React, { Component, ReactElement } from 'react';
|
||||||
|
import { WithTranslation } from 'react-i18next';
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
import { createToolbarEvent, sendAnalytics } from '../../../analytics';
|
import { createToolbarEvent, sendAnalytics } from '../../../analytics';
|
||||||
import { translate } from '../../../base/i18n';
|
import { translate } from '../../../base/i18n/functions';
|
||||||
import { connect } from '../../../base/redux';
|
import { connect } from '../../../base/redux/functions';
|
||||||
|
// @ts-ignore
|
||||||
import { ReactionEmoji, ReactionsMenu } from '../../../reactions/components';
|
import { ReactionEmoji, ReactionsMenu } from '../../../reactions/components';
|
||||||
import { type ReactionEmojiProps, REACTIONS_MENU_HEIGHT } from '../../../reactions/constants';
|
import { type ReactionEmojiProps, REACTIONS_MENU_HEIGHT } from '../../../reactions/constants';
|
||||||
import { getReactionsQueue } from '../../../reactions/functions.any';
|
import { getReactionsQueue } from '../../../reactions/functions.any';
|
||||||
import { DRAWER_MAX_HEIGHT } from '../../constants';
|
import { DRAWER_MAX_HEIGHT } from '../../constants';
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
import Drawer from './Drawer';
|
import Drawer from './Drawer';
|
||||||
|
// @ts-ignore
|
||||||
import JitsiPortal from './JitsiPortal';
|
import JitsiPortal from './JitsiPortal';
|
||||||
|
// @ts-ignore
|
||||||
import OverflowToggleButton from './OverflowToggleButton';
|
import OverflowToggleButton from './OverflowToggleButton';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The type of the React {@code Component} props of {@link OverflowMenuButton}.
|
* The type of the React {@code Component} props of {@link OverflowMenuButton}.
|
||||||
*/
|
*/
|
||||||
type Props = {
|
interface Props extends WithTranslation {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ID of the menu that is controlled by this button.
|
* ID of the menu that is controlled by this button.
|
||||||
|
@ -29,12 +34,12 @@ type Props = {
|
||||||
/**
|
/**
|
||||||
* A child React Element to display within {@code InlineDialog}.
|
* A child React Element to display within {@code InlineDialog}.
|
||||||
*/
|
*/
|
||||||
children: React$Node,
|
children: ReactElement,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An object containing the CSS classes.
|
* An object containing the CSS classes.
|
||||||
*/
|
*/
|
||||||
classes: Object,
|
classes: any,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether or not the OverflowMenu popover should display.
|
* Whether or not the OverflowMenu popover should display.
|
||||||
|
@ -51,11 +56,6 @@ type Props = {
|
||||||
*/
|
*/
|
||||||
overflowDrawer: boolean,
|
overflowDrawer: boolean,
|
||||||
|
|
||||||
/**
|
|
||||||
* Invoked to obtain translated strings.
|
|
||||||
*/
|
|
||||||
t: Function,
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The array of reactions to be displayed.
|
* The array of reactions to be displayed.
|
||||||
*/
|
*/
|
||||||
|
@ -65,7 +65,7 @@ type Props = {
|
||||||
* Whether or not to display the reactions in the mobile menu.
|
* Whether or not to display the reactions in the mobile menu.
|
||||||
*/
|
*/
|
||||||
showMobileReactions: boolean
|
showMobileReactions: boolean
|
||||||
};
|
}
|
||||||
|
|
||||||
const styles = () => {
|
const styles = () => {
|
||||||
return {
|
return {
|
||||||
|
@ -98,15 +98,13 @@ class OverflowMenuButton extends Component<Props> {
|
||||||
this._onEscClick = this._onEscClick.bind(this);
|
this._onEscClick = this._onEscClick.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
_onEscClick: (KeyboardEvent) => void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Click handler for the more actions entries.
|
* Click handler for the more actions entries.
|
||||||
*
|
*
|
||||||
* @param {KeyboardEvent} event - Esc key click to close the popup.
|
* @param {KeyboardEvent} event - Esc key click to close the popup.
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
_onEscClick(event) {
|
_onEscClick(event: React.KeyboardEvent) {
|
||||||
if (event.key === 'Escape' && this.props.isOpen) {
|
if (event.key === 'Escape' && this.props.isOpen) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
|
@ -136,10 +134,12 @@ class OverflowMenuButton extends Component<Props> {
|
||||||
<Drawer
|
<Drawer
|
||||||
isOpen = { isOpen }
|
isOpen = { isOpen }
|
||||||
onClose = { this._onCloseDialog }>
|
onClose = { this._onCloseDialog }>
|
||||||
|
<>
|
||||||
<div className = { classes.overflowMenuDrawer }>
|
<div className = { classes.overflowMenuDrawer }>
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
{showMobileReactions && <ReactionsMenu overflowMenu = { true } />}
|
{showMobileReactions && <ReactionsMenu overflowMenu = { true } />}
|
||||||
|
</>
|
||||||
</Drawer>
|
</Drawer>
|
||||||
{showMobileReactions && <div className = 'reactions-animations-container'>
|
{showMobileReactions && <div className = 'reactions-animations-container'>
|
||||||
{reactionsQueue.map(({ reaction, uid }, index) => (<ReactionEmoji
|
{reactionsQueue.map(({ reaction, uid }, index) => (<ReactionEmoji
|
||||||
|
@ -167,8 +167,6 @@ class OverflowMenuButton extends Component<Props> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
_onCloseDialog: () => void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback invoked when {@code InlineDialog} signals that it should be
|
* Callback invoked when {@code InlineDialog} signals that it should be
|
||||||
* close.
|
* close.
|
||||||
|
@ -180,8 +178,6 @@ class OverflowMenuButton extends Component<Props> {
|
||||||
this.props.onVisibilityChange(false);
|
this.props.onVisibilityChange(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
_toggleDialogVisibility: () => void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback invoked to signal that an event has occurred that should change
|
* Callback invoked to signal that an event has occurred that should change
|
||||||
* the visibility of the {@code InlineDialog} component.
|
* the visibility of the {@code InlineDialog} component.
|
||||||
|
@ -203,7 +199,7 @@ class OverflowMenuButton extends Component<Props> {
|
||||||
* @param {Object} state - The Redux state.
|
* @param {Object} state - The Redux state.
|
||||||
* @returns {Props}
|
* @returns {Props}
|
||||||
*/
|
*/
|
||||||
function mapStateToProps(state) {
|
function mapStateToProps(state: any) {
|
||||||
const { overflowDrawer } = state['features/toolbox'];
|
const { overflowDrawer } = state['features/toolbox'];
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -212,4 +208,5 @@ function mapStateToProps(state) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
export default withStyles(styles)(translate(connect(mapStateToProps)(OverflowMenuButton)));
|
export default withStyles(styles)(translate(connect(mapStateToProps)(OverflowMenuButton)));
|
|
@ -1,76 +1,109 @@
|
||||||
// @flow
|
/* eslint-disable lines-around-comment */
|
||||||
|
|
||||||
import { withStyles } from '@material-ui/core/styles';
|
import { withStyles } from '@material-ui/core/styles';
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
|
import { WithTranslation } from 'react-i18next';
|
||||||
import { batch } from 'react-redux';
|
import { batch } from 'react-redux';
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
import keyboardShortcut from '../../../../../modules/keyboardshortcut/keyboardshortcut';
|
import keyboardShortcut from '../../../../../modules/keyboardshortcut/keyboardshortcut';
|
||||||
import {
|
import {
|
||||||
ACTION_SHORTCUT_TRIGGERED,
|
ACTION_SHORTCUT_TRIGGERED,
|
||||||
createShortcutEvent,
|
createShortcutEvent,
|
||||||
createToolbarEvent,
|
createToolbarEvent,
|
||||||
sendAnalytics
|
sendAnalytics
|
||||||
|
// @ts-ignore
|
||||||
} from '../../../analytics';
|
} from '../../../analytics';
|
||||||
|
// @ts-ignore
|
||||||
import { ContextMenu, ContextMenuItemGroup } from '../../../base/components';
|
import { ContextMenu, ContextMenuItemGroup } from '../../../base/components';
|
||||||
|
// @ts-ignore
|
||||||
import { getMultipleVideoSendingSupportFeatureFlag, getToolbarButtons } from '../../../base/config';
|
import { getMultipleVideoSendingSupportFeatureFlag, getToolbarButtons } from '../../../base/config';
|
||||||
|
// @ts-ignore
|
||||||
import { isToolbarButtonEnabled } from '../../../base/config/functions.web';
|
import { isToolbarButtonEnabled } from '../../../base/config/functions.web';
|
||||||
|
// @ts-ignore
|
||||||
import { openDialog, toggleDialog } from '../../../base/dialog';
|
import { openDialog, toggleDialog } from '../../../base/dialog';
|
||||||
import { isIosMobileBrowser, isMobileBrowser } from '../../../base/environment/utils';
|
import { isIosMobileBrowser, isMobileBrowser } from '../../../base/environment/utils';
|
||||||
import { translate } from '../../../base/i18n';
|
import { translate } from '../../../base/i18n/functions';
|
||||||
import JitsiMeetJS from '../../../base/lib-jitsi-meet';
|
import JitsiMeetJS from '../../../base/lib-jitsi-meet';
|
||||||
import {
|
import {
|
||||||
getLocalParticipant,
|
|
||||||
hasRaisedHand,
|
|
||||||
raiseHand
|
raiseHand
|
||||||
} from '../../../base/participants';
|
} from '../../../base/participants/actions';
|
||||||
import { connect } from '../../../base/redux';
|
import {
|
||||||
|
getLocalParticipant,
|
||||||
|
hasRaisedHand
|
||||||
|
} from '../../../base/participants/functions';
|
||||||
|
import { connect } from '../../../base/redux/functions';
|
||||||
|
// @ts-ignore
|
||||||
import { getLocalVideoTrack } from '../../../base/tracks';
|
import { getLocalVideoTrack } from '../../../base/tracks';
|
||||||
|
// @ts-ignore
|
||||||
import { toggleChat } from '../../../chat';
|
import { toggleChat } from '../../../chat';
|
||||||
|
// @ts-ignore
|
||||||
import { ChatButton } from '../../../chat/components';
|
import { ChatButton } from '../../../chat/components';
|
||||||
|
// @ts-ignore
|
||||||
import { EmbedMeetingButton } from '../../../embed-meeting';
|
import { EmbedMeetingButton } from '../../../embed-meeting';
|
||||||
|
// @ts-ignore
|
||||||
import { SharedDocumentButton } from '../../../etherpad';
|
import { SharedDocumentButton } from '../../../etherpad';
|
||||||
|
// @ts-ignore
|
||||||
import { FeedbackButton } from '../../../feedback';
|
import { FeedbackButton } from '../../../feedback';
|
||||||
|
// @ts-ignore
|
||||||
import { setGifMenuVisibility } from '../../../gifs/actions';
|
import { setGifMenuVisibility } from '../../../gifs/actions';
|
||||||
|
// @ts-ignore
|
||||||
import { isGifEnabled } from '../../../gifs/functions';
|
import { isGifEnabled } from '../../../gifs/functions';
|
||||||
|
// @ts-ignore
|
||||||
import { InviteButton } from '../../../invite/components/add-people-dialog';
|
import { InviteButton } from '../../../invite/components/add-people-dialog';
|
||||||
|
// @ts-ignore
|
||||||
import { isVpaasMeeting } from '../../../jaas/functions';
|
import { isVpaasMeeting } from '../../../jaas/functions';
|
||||||
|
// @ts-ignore
|
||||||
import { KeyboardShortcutsButton } from '../../../keyboard-shortcuts';
|
import { KeyboardShortcutsButton } from '../../../keyboard-shortcuts';
|
||||||
import { NoiseSuppressionButton } from '../../../noise-suppression/components';
|
import { NoiseSuppressionButton } from '../../../noise-suppression/components';
|
||||||
import {
|
import {
|
||||||
close as closeParticipantsPane,
|
close as closeParticipantsPane,
|
||||||
open as openParticipantsPane
|
open as openParticipantsPane
|
||||||
|
// @ts-ignore
|
||||||
} from '../../../participants-pane/actions';
|
} from '../../../participants-pane/actions';
|
||||||
|
// @ts-ignore
|
||||||
import { ParticipantsPaneButton } from '../../../participants-pane/components/web';
|
import { ParticipantsPaneButton } from '../../../participants-pane/components/web';
|
||||||
|
// @ts-ignore
|
||||||
import { getParticipantsPaneOpen } from '../../../participants-pane/functions';
|
import { getParticipantsPaneOpen } from '../../../participants-pane/functions';
|
||||||
import { addReactionToBuffer } from '../../../reactions/actions.any';
|
import { addReactionToBuffer } from '../../../reactions/actions.any';
|
||||||
import { toggleReactionsMenuVisibility } from '../../../reactions/actions.web';
|
import { toggleReactionsMenuVisibility } from '../../../reactions/actions.web';
|
||||||
import { ReactionsMenuButton } from '../../../reactions/components';
|
import ReactionsMenuButton from '../../../reactions/components/web/ReactionsMenuButton';
|
||||||
import { REACTIONS } from '../../../reactions/constants';
|
import { REACTIONS } from '../../../reactions/constants';
|
||||||
import { isReactionsEnabled } from '../../../reactions/functions.any';
|
import { isReactionsEnabled } from '../../../reactions/functions.any';
|
||||||
import {
|
import {
|
||||||
LiveStreamButton,
|
LiveStreamButton,
|
||||||
RecordButton
|
RecordButton
|
||||||
|
// @ts-ignore
|
||||||
} from '../../../recording';
|
} from '../../../recording';
|
||||||
|
// @ts-ignore
|
||||||
import { isSalesforceEnabled } from '../../../salesforce/functions';
|
import { isSalesforceEnabled } from '../../../salesforce/functions';
|
||||||
import {
|
import {
|
||||||
isScreenAudioSupported,
|
isScreenAudioSupported,
|
||||||
isScreenVideoShared,
|
isScreenVideoShared,
|
||||||
ShareAudioButton,
|
ShareAudioButton,
|
||||||
startScreenShareFlow
|
startScreenShareFlow
|
||||||
} from '../../../screen-share/';
|
// @ts-ignore
|
||||||
|
} from '../../../screen-share';
|
||||||
|
// @ts-ignore
|
||||||
import SecurityDialogButton from '../../../security/components/security-dialog/web/SecurityDialogButton';
|
import SecurityDialogButton from '../../../security/components/security-dialog/web/SecurityDialogButton';
|
||||||
|
// @ts-ignore
|
||||||
import { SettingsButton } from '../../../settings';
|
import { SettingsButton } from '../../../settings';
|
||||||
|
// @ts-ignore
|
||||||
import { SharedVideoButton } from '../../../shared-video/components';
|
import { SharedVideoButton } from '../../../shared-video/components';
|
||||||
|
// @ts-ignore
|
||||||
import { SpeakerStatsButton } from '../../../speaker-stats/components/web';
|
import { SpeakerStatsButton } from '../../../speaker-stats/components/web';
|
||||||
import {
|
import {
|
||||||
ClosedCaptionButton
|
ClosedCaptionButton
|
||||||
|
// @ts-ignore
|
||||||
} from '../../../subtitles';
|
} from '../../../subtitles';
|
||||||
import {
|
import {
|
||||||
TileViewButton,
|
TileViewButton,
|
||||||
shouldDisplayTileView,
|
shouldDisplayTileView,
|
||||||
toggleTileView
|
toggleTileView
|
||||||
|
// @ts-ignore
|
||||||
} from '../../../video-layout';
|
} from '../../../video-layout';
|
||||||
|
// @ts-ignore
|
||||||
import { VideoQualityDialog, VideoQualityButton } from '../../../video-quality/components';
|
import { VideoQualityDialog, VideoQualityButton } from '../../../video-quality/components';
|
||||||
|
// @ts-ignore
|
||||||
import { VideoBackgroundButton, toggleBackgroundEffect } from '../../../virtual-background';
|
import { VideoBackgroundButton, toggleBackgroundEffect } from '../../../virtual-background';
|
||||||
import { VIRTUAL_BACKGROUND_TYPE } from '../../../virtual-background/constants';
|
import { VIRTUAL_BACKGROUND_TYPE } from '../../../virtual-background/constants';
|
||||||
import {
|
import {
|
||||||
|
@ -78,29 +111,45 @@ import {
|
||||||
setOverflowMenuVisible,
|
setOverflowMenuVisible,
|
||||||
setToolbarHovered,
|
setToolbarHovered,
|
||||||
showToolbox
|
showToolbox
|
||||||
|
// @ts-ignore
|
||||||
} from '../../actions';
|
} from '../../actions';
|
||||||
import { THRESHOLDS, NOT_APPLICABLE, NOTIFY_CLICK_MODE } from '../../constants';
|
import { THRESHOLDS, NOT_APPLICABLE, NOTIFY_CLICK_MODE } from '../../constants';
|
||||||
|
// @ts-ignore
|
||||||
import { isDesktopShareButtonDisabled, isToolboxVisible } from '../../functions';
|
import { isDesktopShareButtonDisabled, isToolboxVisible } from '../../functions';
|
||||||
|
// @ts-ignore
|
||||||
import DownloadButton from '../DownloadButton';
|
import DownloadButton from '../DownloadButton';
|
||||||
|
// @ts-ignore
|
||||||
import HangupButton from '../HangupButton';
|
import HangupButton from '../HangupButton';
|
||||||
|
// @ts-ignore
|
||||||
import HelpButton from '../HelpButton';
|
import HelpButton from '../HelpButton';
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
import AudioSettingsButton from './AudioSettingsButton';
|
import AudioSettingsButton from './AudioSettingsButton';
|
||||||
|
// @ts-ignore
|
||||||
import DockIframeButton from './DockIframeButton';
|
import DockIframeButton from './DockIframeButton';
|
||||||
|
// @ts-ignore
|
||||||
import FullscreenButton from './FullscreenButton';
|
import FullscreenButton from './FullscreenButton';
|
||||||
|
// @ts-ignore
|
||||||
import LinkToSalesforceButton from './LinkToSalesforceButton';
|
import LinkToSalesforceButton from './LinkToSalesforceButton';
|
||||||
|
// @ts-ignore
|
||||||
import OverflowMenuButton from './OverflowMenuButton';
|
import OverflowMenuButton from './OverflowMenuButton';
|
||||||
|
// @ts-ignore
|
||||||
import ProfileButton from './ProfileButton';
|
import ProfileButton from './ProfileButton';
|
||||||
|
// @ts-ignore
|
||||||
import Separator from './Separator';
|
import Separator from './Separator';
|
||||||
|
// @ts-ignore
|
||||||
import ShareDesktopButton from './ShareDesktopButton';
|
import ShareDesktopButton from './ShareDesktopButton';
|
||||||
|
// @ts-ignore
|
||||||
import ToggleCameraButton from './ToggleCameraButton';
|
import ToggleCameraButton from './ToggleCameraButton';
|
||||||
|
// @ts-ignore
|
||||||
import UndockIframeButton from './UndockIframeButton';
|
import UndockIframeButton from './UndockIframeButton';
|
||||||
|
// @ts-ignore
|
||||||
import VideoSettingsButton from './VideoSettingsButton';
|
import VideoSettingsButton from './VideoSettingsButton';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The type of the React {@code Component} props of {@link Toolbox}.
|
* The type of the React {@code Component} props of {@link Toolbox}.
|
||||||
*/
|
*/
|
||||||
type Props = {
|
interface Props extends WithTranslation {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* String showing if the virtual background type is desktop-share.
|
* String showing if the virtual background type is desktop-share.
|
||||||
|
@ -110,7 +159,10 @@ type Props = {
|
||||||
/**
|
/**
|
||||||
* Toolbar buttons which have their click exposed through the API.
|
* Toolbar buttons which have their click exposed through the API.
|
||||||
*/
|
*/
|
||||||
_buttonsWithNotifyClick: Array<string | Object>,
|
_buttonsWithNotifyClick: Array<string | {
|
||||||
|
key: string;
|
||||||
|
preventExecution: boolean;
|
||||||
|
}>,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether or not the chat feature is currently displayed.
|
* Whether or not the chat feature is currently displayed.
|
||||||
|
@ -248,39 +300,33 @@ type Props = {
|
||||||
*/
|
*/
|
||||||
_toolbarButtons: Array<string>,
|
_toolbarButtons: Array<string>,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the selected virtual source object.
|
||||||
|
*/
|
||||||
|
_virtualSource: any,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Flag showing whether toolbar is visible.
|
* Flag showing whether toolbar is visible.
|
||||||
*/
|
*/
|
||||||
_visible: boolean,
|
_visible: boolean,
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the selected virtual source object.
|
|
||||||
*/
|
|
||||||
_virtualSource: Object,
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An object containing the CSS classes.
|
* An object containing the CSS classes.
|
||||||
*/
|
*/
|
||||||
classes: Object,
|
classes: any,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoked to active other features of the app.
|
* Invoked to active other features of the app.
|
||||||
*/
|
*/
|
||||||
dispatch: Function,
|
dispatch: Function,
|
||||||
|
|
||||||
/**
|
|
||||||
* Invoked to obtain translated strings.
|
|
||||||
*/
|
|
||||||
t: Function,
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Explicitly passed array with the buttons which this Toolbox should display.
|
* Explicitly passed array with the buttons which this Toolbox should display.
|
||||||
*/
|
*/
|
||||||
toolbarButtons: Array<string>,
|
toolbarButtons: Array<string>,
|
||||||
|
}
|
||||||
|
|
||||||
};
|
declare let APP: any;
|
||||||
|
|
||||||
declare var APP: Object;
|
|
||||||
|
|
||||||
const styles = () => {
|
const styles = () => {
|
||||||
return {
|
return {
|
||||||
|
@ -435,7 +481,7 @@ class Toolbox extends Component<Props> {
|
||||||
*
|
*
|
||||||
* @inheritdoc
|
* @inheritdoc
|
||||||
*/
|
*/
|
||||||
componentDidUpdate(prevProps) {
|
componentDidUpdate(prevProps: Props) {
|
||||||
const { _dialog, dispatch } = this.props;
|
const { _dialog, dispatch } = this.props;
|
||||||
|
|
||||||
|
|
||||||
|
@ -488,15 +534,13 @@ class Toolbox extends Component<Props> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
_onEscKey: (KeyboardEvent) => void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Key handler for overflow menu.
|
* Key handler for overflow menu.
|
||||||
*
|
*
|
||||||
* @param {KeyboardEvent} e - Esc key click to close the popup.
|
* @param {KeyboardEvent} e - Esc key click to close the popup.
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
_onEscKey(e) {
|
_onEscKey(e: React.KeyboardEvent) {
|
||||||
if (e.key === 'Escape') {
|
if (e.key === 'Escape') {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
this._closeOverflowMenuIfOpen();
|
this._closeOverflowMenuIfOpen();
|
||||||
|
@ -870,9 +914,9 @@ class Toolbox extends Component<Props> {
|
||||||
* @param {string} btnName - The toolbar button's name.
|
* @param {string} btnName - The toolbar button's name.
|
||||||
* @returns {string|undefined} - The button's notify mode.
|
* @returns {string|undefined} - The button's notify mode.
|
||||||
*/
|
*/
|
||||||
_getButtonNotifyMode(btnName) {
|
_getButtonNotifyMode(btnName: string) {
|
||||||
const notify = this.props._buttonsWithNotifyClick?.find(
|
const notify = this.props._buttonsWithNotifyClick?.find(
|
||||||
(btn: string | Object) =>
|
btn =>
|
||||||
(typeof btn === 'string' && btn === btnName)
|
(typeof btn === 'string' && btn === btnName)
|
||||||
|| (typeof btn === 'object' && btn.key === btnName)
|
|| (typeof btn === 'object' && btn.key === btnName)
|
||||||
);
|
);
|
||||||
|
@ -890,7 +934,7 @@ class Toolbox extends Component<Props> {
|
||||||
* @param {Object} buttons - The list of toolbar buttons.
|
* @param {Object} buttons - The list of toolbar buttons.
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
_setButtonsNotifyClickMode(buttons) {
|
_setButtonsNotifyClickMode(buttons: Object) {
|
||||||
if (typeof APP === 'undefined' || !this.props._buttonsWithNotifyClick?.length) {
|
if (typeof APP === 'undefined' || !this.props._buttonsWithNotifyClick?.length) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -926,7 +970,7 @@ class Toolbox extends Component<Props> {
|
||||||
const keys = Object.keys(buttons);
|
const keys = Object.keys(buttons);
|
||||||
|
|
||||||
const filtered = [
|
const filtered = [
|
||||||
...order.map(key => buttons[key]),
|
...order.map(key => buttons[key as keyof typeof buttons]),
|
||||||
...Object.values(buttons).filter((button, index) => !order.includes(keys[index]))
|
...Object.values(buttons).filter((button, index) => !order.includes(keys[index]))
|
||||||
].filter(Boolean).filter(({ key, alias = NOT_APPLICABLE }) =>
|
].filter(Boolean).filter(({ key, alias = NOT_APPLICABLE }) =>
|
||||||
isToolbarButtonEnabled(key, _toolbarButtons) || isToolbarButtonEnabled(alias, _toolbarButtons));
|
isToolbarButtonEnabled(key, _toolbarButtons) || isToolbarButtonEnabled(alias, _toolbarButtons));
|
||||||
|
@ -946,8 +990,6 @@ class Toolbox extends Component<Props> {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
_onMouseOut: () => void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dispatches an action signaling the toolbar is not being hovered.
|
* Dispatches an action signaling the toolbar is not being hovered.
|
||||||
*
|
*
|
||||||
|
@ -960,8 +1002,6 @@ class Toolbox extends Component<Props> {
|
||||||
!_overflowMenuVisible && dispatch(setToolbarHovered(false));
|
!_overflowMenuVisible && dispatch(setToolbarHovered(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
_onMouseOver: () => void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dispatches an action signaling the toolbar is being hovered.
|
* Dispatches an action signaling the toolbar is being hovered.
|
||||||
*
|
*
|
||||||
|
@ -972,9 +1012,6 @@ class Toolbox extends Component<Props> {
|
||||||
this.props.dispatch(setToolbarHovered(true));
|
this.props.dispatch(setToolbarHovered(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
_onSetOverflowVisible: (boolean) => void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the visibility of the overflow menu.
|
* Sets the visibility of the overflow menu.
|
||||||
*
|
*
|
||||||
|
@ -983,13 +1020,11 @@ class Toolbox extends Component<Props> {
|
||||||
* @private
|
* @private
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
_onSetOverflowVisible(visible) {
|
_onSetOverflowVisible(visible: boolean) {
|
||||||
this.props.dispatch(setOverflowMenuVisible(visible));
|
this.props.dispatch(setOverflowMenuVisible(visible));
|
||||||
this.props.dispatch(setToolbarHovered(visible));
|
this.props.dispatch(setToolbarHovered(visible));
|
||||||
}
|
}
|
||||||
|
|
||||||
_onShortcutToggleChat: () => void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an analytics keyboard shortcut event and dispatches an action for
|
* Creates an analytics keyboard shortcut event and dispatches an action for
|
||||||
* toggling the display of chat.
|
* toggling the display of chat.
|
||||||
|
@ -1007,15 +1042,13 @@ class Toolbox extends Component<Props> {
|
||||||
// Checks if there was any text selected by the user.
|
// Checks if there was any text selected by the user.
|
||||||
// Used for when we press simultaneously keys for copying
|
// Used for when we press simultaneously keys for copying
|
||||||
// text messages from the chat board
|
// text messages from the chat board
|
||||||
if (window.getSelection().toString() !== '') {
|
if (window.getSelection()?.toString() !== '') {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._doToggleChat();
|
this._doToggleChat();
|
||||||
}
|
}
|
||||||
|
|
||||||
_onShortcutToggleParticipantsPane: () => void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an analytics keyboard shortcut event and dispatches an action for
|
* Creates an analytics keyboard shortcut event and dispatches an action for
|
||||||
* toggling the display of the participants pane.
|
* toggling the display of the participants pane.
|
||||||
|
@ -1033,8 +1066,6 @@ class Toolbox extends Component<Props> {
|
||||||
this._onToolbarToggleParticipantsPane();
|
this._onToolbarToggleParticipantsPane();
|
||||||
}
|
}
|
||||||
|
|
||||||
_onShortcutToggleVideoQuality: () => void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an analytics keyboard shortcut event and dispatches an action for
|
* Creates an analytics keyboard shortcut event and dispatches an action for
|
||||||
* toggling the display of Video Quality.
|
* toggling the display of Video Quality.
|
||||||
|
@ -1048,8 +1079,6 @@ class Toolbox extends Component<Props> {
|
||||||
this._doToggleVideoQuality();
|
this._doToggleVideoQuality();
|
||||||
}
|
}
|
||||||
|
|
||||||
_onShortcutToggleTileView: () => void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dispatches an action for toggling the tile view.
|
* Dispatches an action for toggling the tile view.
|
||||||
*
|
*
|
||||||
|
@ -1066,8 +1095,6 @@ class Toolbox extends Component<Props> {
|
||||||
this._doToggleTileView();
|
this._doToggleTileView();
|
||||||
}
|
}
|
||||||
|
|
||||||
_onShortcutToggleFullScreen: () => void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an analytics keyboard shortcut event and dispatches an action for
|
* Creates an analytics keyboard shortcut event and dispatches an action for
|
||||||
* toggling full screen mode.
|
* toggling full screen mode.
|
||||||
|
@ -1085,8 +1112,6 @@ class Toolbox extends Component<Props> {
|
||||||
this._doToggleFullScreen();
|
this._doToggleFullScreen();
|
||||||
}
|
}
|
||||||
|
|
||||||
_onShortcutToggleRaiseHand: () => void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an analytics keyboard shortcut event and dispatches an action for
|
* Creates an analytics keyboard shortcut event and dispatches an action for
|
||||||
* toggling raise hand.
|
* toggling raise hand.
|
||||||
|
@ -1103,8 +1128,6 @@ class Toolbox extends Component<Props> {
|
||||||
this._doToggleRaiseHand();
|
this._doToggleRaiseHand();
|
||||||
}
|
}
|
||||||
|
|
||||||
_onShortcutToggleScreenshare: () => void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an analytics keyboard shortcut event and dispatches an action for
|
* Creates an analytics keyboard shortcut event and dispatches an action for
|
||||||
* toggling screensharing.
|
* toggling screensharing.
|
||||||
|
@ -1127,7 +1150,6 @@ class Toolbox extends Component<Props> {
|
||||||
this._doToggleScreenshare();
|
this._doToggleScreenshare();
|
||||||
}
|
}
|
||||||
|
|
||||||
_onTabIn: () => void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Toggle the toolbar visibility when tabbing into it.
|
* Toggle the toolbar visibility when tabbing into it.
|
||||||
|
@ -1139,7 +1161,6 @@ class Toolbox extends Component<Props> {
|
||||||
this.props.dispatch(showToolbox());
|
this.props.dispatch(showToolbox());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_onToolbarToggleParticipantsPane: () => void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dispatches an action for toggling the participants pane.
|
* Dispatches an action for toggling the participants pane.
|
||||||
|
@ -1157,8 +1178,6 @@ class Toolbox extends Component<Props> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_onToolbarOpenVideoQuality: () => void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an analytics toolbar event and dispatches an action for toggling
|
* Creates an analytics toolbar event and dispatches an action for toggling
|
||||||
* open the video quality dialog.
|
* open the video quality dialog.
|
||||||
|
@ -1172,8 +1191,6 @@ class Toolbox extends Component<Props> {
|
||||||
this._doOpenVideoQuality();
|
this._doOpenVideoQuality();
|
||||||
}
|
}
|
||||||
|
|
||||||
_onToolbarToggleChat: () => void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an analytics toolbar event and dispatches an action for toggling
|
* Creates an analytics toolbar event and dispatches an action for toggling
|
||||||
* the display of chat.
|
* the display of chat.
|
||||||
|
@ -1191,8 +1208,6 @@ class Toolbox extends Component<Props> {
|
||||||
this._doToggleChat();
|
this._doToggleChat();
|
||||||
}
|
}
|
||||||
|
|
||||||
_onToolbarToggleFullScreen: () => void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an analytics toolbar event and dispatches an action for toggling
|
* Creates an analytics toolbar event and dispatches an action for toggling
|
||||||
* full screen mode.
|
* full screen mode.
|
||||||
|
@ -1210,8 +1225,6 @@ class Toolbox extends Component<Props> {
|
||||||
this._doToggleFullScreen();
|
this._doToggleFullScreen();
|
||||||
}
|
}
|
||||||
|
|
||||||
_onToolbarToggleRaiseHand: () => void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an analytics toolbar event and dispatches an action for toggling
|
* Creates an analytics toolbar event and dispatches an action for toggling
|
||||||
* raise hand.
|
* raise hand.
|
||||||
|
@ -1227,8 +1240,6 @@ class Toolbox extends Component<Props> {
|
||||||
this._doToggleRaiseHand();
|
this._doToggleRaiseHand();
|
||||||
}
|
}
|
||||||
|
|
||||||
_onToolbarToggleScreenshare: () => void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an analytics toolbar event and dispatches an action for toggling
|
* Creates an analytics toolbar event and dispatches an action for toggling
|
||||||
* screensharing.
|
* screensharing.
|
||||||
|
@ -1357,9 +1368,9 @@ class Toolbox extends Component<Props> {
|
||||||
}
|
}
|
||||||
|
|
||||||
return acc;
|
return acc;
|
||||||
}, []).map(buttonGroup => (
|
}, []).map((buttonGroup: any) => (
|
||||||
<ContextMenuItemGroup key = { `group-${buttonGroup[0].group}` }>
|
<ContextMenuItemGroup key = { `group-${buttonGroup[0].group}` }>
|
||||||
{buttonGroup.map(({ key, Content, ...rest }) => (
|
{buttonGroup.map(({ key, Content, ...rest }: any) => (
|
||||||
key !== 'raisehand' || !_reactionsEnabled)
|
key !== 'raisehand' || !_reactionsEnabled)
|
||||||
&& <Content
|
&& <Content
|
||||||
{ ...rest }
|
{ ...rest }
|
||||||
|
@ -1394,7 +1405,7 @@ class Toolbox extends Component<Props> {
|
||||||
* @private
|
* @private
|
||||||
* @returns {{}}
|
* @returns {{}}
|
||||||
*/
|
*/
|
||||||
function _mapStateToProps(state, ownProps) {
|
function _mapStateToProps(state: any, ownProps: Partial<Props>) {
|
||||||
const { conference } = state['features/base/conference'];
|
const { conference } = state['features/base/conference'];
|
||||||
const {
|
const {
|
||||||
buttonsWithNotifyClick,
|
buttonsWithNotifyClick,
|
||||||
|
@ -1447,4 +1458,5 @@ function _mapStateToProps(state, ownProps) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
export default translate(connect(_mapStateToProps)(withStyles(styles)(Toolbox)));
|
export default translate(connect(_mapStateToProps)(withStyles(styles)(Toolbox)));
|
|
@ -1,28 +1,44 @@
|
||||||
// @flow
|
/* eslint-disable lines-around-comment */
|
||||||
|
|
||||||
import { makeStyles } from '@material-ui/styles';
|
import { makeStyles } from '@material-ui/styles';
|
||||||
import React, { useCallback } from 'react';
|
import React, { useCallback } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useDispatch, useSelector } from 'react-redux';
|
import { useDispatch, useSelector } from 'react-redux';
|
||||||
|
|
||||||
|
import { IState } from '../../../app/types';
|
||||||
|
// @ts-ignore
|
||||||
import { isSupported as isAvModerationSupported } from '../../../av-moderation/functions';
|
import { isSupported as isAvModerationSupported } from '../../../av-moderation/functions';
|
||||||
|
// @ts-ignore
|
||||||
import { Avatar } from '../../../base/avatar';
|
import { Avatar } from '../../../base/avatar';
|
||||||
|
// @ts-ignore
|
||||||
import ContextMenu from '../../../base/components/context-menu/ContextMenu';
|
import ContextMenu from '../../../base/components/context-menu/ContextMenu';
|
||||||
|
// @ts-ignore
|
||||||
import ContextMenuItemGroup from '../../../base/components/context-menu/ContextMenuItemGroup';
|
import ContextMenuItemGroup from '../../../base/components/context-menu/ContextMenuItemGroup';
|
||||||
import { isIosMobileBrowser, isMobileBrowser } from '../../../base/environment/utils';
|
import { isIosMobileBrowser, isMobileBrowser } from '../../../base/environment/utils';
|
||||||
import { IconShareVideo } from '../../../base/icons';
|
import { IconShareVideo } from '../../../base/icons/svg/index';
|
||||||
import { MEDIA_TYPE } from '../../../base/media';
|
import { MEDIA_TYPE } from '../../../base/media/constants';
|
||||||
import { getLocalParticipant, PARTICIPANT_ROLE } from '../../../base/participants';
|
import { PARTICIPANT_ROLE } from '../../../base/participants/constants';
|
||||||
|
import { getLocalParticipant } from '../../../base/participants/functions';
|
||||||
|
import { Participant } from '../../../base/participants/reducer';
|
||||||
|
// @ts-ignore
|
||||||
import { isParticipantAudioMuted } from '../../../base/tracks';
|
import { isParticipantAudioMuted } from '../../../base/tracks';
|
||||||
|
// @ts-ignore
|
||||||
import { getBreakoutRooms, getCurrentRoomId, isInBreakoutRoom } from '../../../breakout-rooms/functions';
|
import { getBreakoutRooms, getCurrentRoomId, isInBreakoutRoom } from '../../../breakout-rooms/functions';
|
||||||
|
// @ts-ignore
|
||||||
import { setVolume } from '../../../filmstrip/actions.web';
|
import { setVolume } from '../../../filmstrip/actions.web';
|
||||||
|
// @ts-ignore
|
||||||
import { isStageFilmstripAvailable } from '../../../filmstrip/functions.web';
|
import { isStageFilmstripAvailable } from '../../../filmstrip/functions.web';
|
||||||
|
// @ts-ignore
|
||||||
import { isForceMuted } from '../../../participants-pane/functions';
|
import { isForceMuted } from '../../../participants-pane/functions';
|
||||||
|
// @ts-ignore
|
||||||
import { requestRemoteControl, stopController } from '../../../remote-control';
|
import { requestRemoteControl, stopController } from '../../../remote-control';
|
||||||
|
// @ts-ignore
|
||||||
import { stopSharedVideo } from '../../../shared-video/actions.any';
|
import { stopSharedVideo } from '../../../shared-video/actions.any';
|
||||||
|
// @ts-ignore
|
||||||
import { showOverflowDrawer } from '../../../toolbox/functions.web';
|
import { showOverflowDrawer } from '../../../toolbox/functions.web';
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
import { REMOTE_CONTROL_MENU_STATES } from './RemoteControlButton';
|
import { REMOTE_CONTROL_MENU_STATES } from './RemoteControlButton';
|
||||||
|
// @ts-ignore
|
||||||
import SendToRoomButton from './SendToRoomButton';
|
import SendToRoomButton from './SendToRoomButton';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
@ -38,6 +54,7 @@ import {
|
||||||
RemoteControlButton,
|
RemoteControlButton,
|
||||||
TogglePinToStageButton,
|
TogglePinToStageButton,
|
||||||
VolumeSlider
|
VolumeSlider
|
||||||
|
// @ts-ignore
|
||||||
} from './';
|
} from './';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
@ -56,7 +73,10 @@ type Props = {
|
||||||
* The participant for which the drawer is open.
|
* The participant for which the drawer is open.
|
||||||
* It contains the displayName & participantID.
|
* It contains the displayName & participantID.
|
||||||
*/
|
*/
|
||||||
drawerParticipant?: Object,
|
drawerParticipant?: {
|
||||||
|
displayName: string;
|
||||||
|
participantID: string;
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shared video local participant owner.
|
* Shared video local participant owner.
|
||||||
|
@ -86,7 +106,7 @@ type Props = {
|
||||||
/**
|
/**
|
||||||
* Participant reference.
|
* Participant reference.
|
||||||
*/
|
*/
|
||||||
participant: Object,
|
participant: Participant,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The current state of the participant's remote control session.
|
* The current state of the participant's remote control session.
|
||||||
|
@ -96,10 +116,10 @@ type Props = {
|
||||||
/**
|
/**
|
||||||
* Whether or not the menu is displayed in the thumbnail remote video menu.
|
* Whether or not the menu is displayed in the thumbnail remote video menu.
|
||||||
*/
|
*/
|
||||||
thumbnailMenu: ?boolean
|
thumbnailMenu?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
const useStyles = makeStyles(theme => {
|
const useStyles = makeStyles((theme: any) => {
|
||||||
return {
|
return {
|
||||||
text: {
|
text: {
|
||||||
color: theme.palette.text02,
|
color: theme.palette.text02,
|
||||||
|
@ -139,9 +159,9 @@ const ParticipantContextMenu = ({
|
||||||
const _isAudioMuted = useSelector(state => isParticipantAudioMuted(participant, state));
|
const _isAudioMuted = useSelector(state => isParticipantAudioMuted(participant, state));
|
||||||
const _overflowDrawer = useSelector(showOverflowDrawer);
|
const _overflowDrawer = useSelector(showOverflowDrawer);
|
||||||
const { remoteVideoMenu = {}, disableRemoteMute, startSilent }
|
const { remoteVideoMenu = {}, disableRemoteMute, startSilent }
|
||||||
= useSelector(state => state['features/base/config']);
|
= useSelector((state: IState) => state['features/base/config']);
|
||||||
const { disableKick, disableGrantModerator, disablePrivateChat } = remoteVideoMenu;
|
const { disableKick, disableGrantModerator, disablePrivateChat } = remoteVideoMenu;
|
||||||
const { participantsVolume } = useSelector(state => state['features/filmstrip']);
|
const { participantsVolume } = useSelector((state: any) => state['features/filmstrip']);
|
||||||
const _volume = (participant?.local ?? true ? undefined
|
const _volume = (participant?.local ?? true ? undefined
|
||||||
: participant?.id ? participantsVolume[participant?.id] : undefined) ?? 1;
|
: participant?.id ? participantsVolume[participant?.id] : undefined) ?? 1;
|
||||||
const isBreakoutRoom = useSelector(isInBreakoutRoom);
|
const isBreakoutRoom = useSelector(isInBreakoutRoom);
|
||||||
|
@ -149,7 +169,7 @@ const ParticipantContextMenu = ({
|
||||||
const stageFilmstrip = useSelector(isStageFilmstripAvailable);
|
const stageFilmstrip = useSelector(isStageFilmstripAvailable);
|
||||||
|
|
||||||
const _currentRoomId = useSelector(getCurrentRoomId);
|
const _currentRoomId = useSelector(getCurrentRoomId);
|
||||||
const _rooms = Object.values(useSelector(getBreakoutRooms));
|
const _rooms: Array<{id: string}> = Object.values(useSelector(getBreakoutRooms));
|
||||||
|
|
||||||
const _onVolumeChange = useCallback(value => {
|
const _onVolumeChange = useCallback(value => {
|
||||||
dispatch(setVolume(participant.id, value));
|
dispatch(setVolume(participant.id, value));
|
||||||
|
@ -273,10 +293,10 @@ const ParticipantContextMenu = ({
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const breakoutRoomsButtons = [];
|
const breakoutRoomsButtons: any = [];
|
||||||
|
|
||||||
if (!thumbnailMenu && _isModerator) {
|
if (!thumbnailMenu && _isModerator) {
|
||||||
_rooms.forEach((room: Object) => {
|
_rooms.forEach(room => {
|
||||||
if (room.id !== _currentRoomId) {
|
if (room.id !== _currentRoomId) {
|
||||||
breakoutRoomsButtons.push(
|
breakoutRoomsButtons.push(
|
||||||
<SendToRoomButton
|
<SendToRoomButton
|
|
@ -9,6 +9,7 @@ import { isMobileBrowser } from '../../../base/environment/utils';
|
||||||
import { translate } from '../../../base/i18n';
|
import { translate } from '../../../base/i18n';
|
||||||
import { IconHorizontalPoints } from '../../../base/icons/svg/index';
|
import { IconHorizontalPoints } from '../../../base/icons/svg/index';
|
||||||
import { getParticipantById } from '../../../base/participants/functions';
|
import { getParticipantById } from '../../../base/participants/functions';
|
||||||
|
import { Participant } from '../../../base/participants/reducer';
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import { Popover } from '../../../base/popover';
|
import { Popover } from '../../../base/popover';
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
@ -57,7 +58,7 @@ interface Props extends WithTranslation {
|
||||||
/**
|
/**
|
||||||
* Participant reference.
|
* Participant reference.
|
||||||
*/
|
*/
|
||||||
_participant: Object,
|
_participant: Participant,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The ID for the participant on which the remote video menu will act.
|
* The ID for the participant on which the remote video menu will act.
|
||||||
|
|
|
@ -1,22 +1,24 @@
|
||||||
/* @flow */
|
/* eslint-disable lines-around-comment */
|
||||||
|
|
||||||
import { withStyles } from '@material-ui/styles';
|
import { withStyles } from '@material-ui/styles';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
|
import { WithTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import { translate } from '../../../base/i18n';
|
import { translate } from '../../../base/i18n/functions';
|
||||||
import { Icon, IconVolume } from '../../../base/icons';
|
import Icon from '../../../base/icons/components/Icon';
|
||||||
|
import { IconVolume } from '../../../base/icons/svg/index';
|
||||||
|
// @ts-ignore
|
||||||
import { VOLUME_SLIDER_SCALE } from '../../constants';
|
import { VOLUME_SLIDER_SCALE } from '../../constants';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The type of the React {@code Component} props of {@link VolumeSlider}.
|
* The type of the React {@code Component} props of {@link VolumeSlider}.
|
||||||
*/
|
*/
|
||||||
type Props = {
|
interface Props extends WithTranslation {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An object containing the CSS classes.
|
* An object containing the CSS classes.
|
||||||
*/
|
*/
|
||||||
classes: Object,
|
classes: any,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The value of the audio slider should display at when the component first
|
* The value of the audio slider should display at when the component first
|
||||||
|
@ -28,13 +30,8 @@ type Props = {
|
||||||
/**
|
/**
|
||||||
* The callback to invoke when the audio slider value changes.
|
* The callback to invoke when the audio slider value changes.
|
||||||
*/
|
*/
|
||||||
onChange: Function,
|
onChange: Function
|
||||||
|
}
|
||||||
/**
|
|
||||||
* Invoked to obtain translated strings.
|
|
||||||
*/
|
|
||||||
t: Function
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The type of the React {@code Component} state of {@link VolumeSlider}.
|
* The type of the React {@code Component} state of {@link VolumeSlider}.
|
||||||
|
@ -48,7 +45,7 @@ type State = {
|
||||||
volumeLevel: number
|
volumeLevel: number
|
||||||
};
|
};
|
||||||
|
|
||||||
const styles = theme => {
|
const styles = (theme: any) => {
|
||||||
return {
|
return {
|
||||||
container: {
|
container: {
|
||||||
minHeight: '40px',
|
minHeight: '40px',
|
||||||
|
@ -116,7 +113,7 @@ class VolumeSlider extends Component<Props, State> {
|
||||||
* @param {MouseEvent} e - Click event.
|
* @param {MouseEvent} e - Click event.
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
_onClick(e) {
|
_onClick(e: React.MouseEvent) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,8 +153,6 @@ class VolumeSlider extends Component<Props, State> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
_onVolumeChange: (Object) => void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the internal state of the volume level for the volume slider.
|
* Sets the internal state of the volume level for the volume slider.
|
||||||
* Invokes the prop onVolumeChange to notify of volume changes.
|
* Invokes the prop onVolumeChange to notify of volume changes.
|
||||||
|
@ -166,12 +161,13 @@ class VolumeSlider extends Component<Props, State> {
|
||||||
* @private
|
* @private
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
_onVolumeChange(event) {
|
_onVolumeChange(event: React.ChangeEvent<HTMLInputElement>) {
|
||||||
const volumeLevel = event.currentTarget.value;
|
const volumeLevel = Number(event.currentTarget.value);
|
||||||
|
|
||||||
this.props.onChange(volumeLevel / VOLUME_SLIDER_SCALE);
|
this.props.onChange(volumeLevel / VOLUME_SLIDER_SCALE);
|
||||||
this.setState({ volumeLevel });
|
this.setState({ volumeLevel });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
export default translate(withStyles(styles)(VolumeSlider));
|
export default translate(withStyles(styles)(VolumeSlider));
|
|
@ -1,4 +1,3 @@
|
||||||
// @flow
|
|
||||||
import { makeStyles } from '@material-ui/core/styles';
|
import { makeStyles } from '@material-ui/core/styles';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
@ -25,7 +24,7 @@ type Props = {
|
||||||
/**
|
/**
|
||||||
* Callback invoked on change.
|
* Callback invoked on change.
|
||||||
*/
|
*/
|
||||||
onChange: Function,
|
onChange: (e: React.ChangeEvent<HTMLInputElement>) => void,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The granularity that the value must adhere to.
|
* The granularity that the value must adhere to.
|
||||||
|
@ -38,7 +37,7 @@ type Props = {
|
||||||
value: number
|
value: number
|
||||||
}
|
}
|
||||||
|
|
||||||
const useStyles = makeStyles(theme => {
|
const useStyles = makeStyles((theme: any) => {
|
||||||
// keep the same height for all elements:
|
// keep the same height for all elements:
|
||||||
// input, input track & fake track(div)
|
// input, input track & fake track(div)
|
||||||
const height = 6;
|
const height = 6;
|
|
@ -2,7 +2,7 @@ import React, { Component } from 'react';
|
||||||
|
|
||||||
import { Dialog } from '../../base/dialog';
|
import { Dialog } from '../../base/dialog';
|
||||||
|
|
||||||
import VideoQualitySlider from './VideoQualitySlider';
|
import VideoQualitySlider from './VideoQualitySlider.web';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implements a React {@link Component} which displays the component
|
* Implements a React {@link Component} which displays the component
|
||||||
|
|
|
@ -1,17 +1,24 @@
|
||||||
// @flow
|
/* eslint-disable lines-around-comment */
|
||||||
import { withStyles } from '@material-ui/core/styles';
|
import { withStyles } from '@material-ui/core/styles';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
|
import { WithTranslation } from 'react-i18next';
|
||||||
import type { Dispatch } from 'redux';
|
import type { Dispatch } from 'redux';
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
import { createToolbarEvent, sendAnalytics } from '../../analytics';
|
import { createToolbarEvent, sendAnalytics } from '../../analytics';
|
||||||
|
// @ts-ignore
|
||||||
import { setAudioOnly } from '../../base/audio-only';
|
import { setAudioOnly } from '../../base/audio-only';
|
||||||
import { translate } from '../../base/i18n';
|
import { translate } from '../../base/i18n/functions';
|
||||||
|
// @ts-ignore
|
||||||
import { setLastN, getLastNForQualityLevel } from '../../base/lastn';
|
import { setLastN, getLastNForQualityLevel } from '../../base/lastn';
|
||||||
import { connect } from '../../base/redux';
|
import { connect } from '../../base/redux/functions';
|
||||||
import { withPixelLineHeight } from '../../base/styles/functions.web';
|
import { withPixelLineHeight } from '../../base/styles/functions.web';
|
||||||
|
// @ts-ignore
|
||||||
import { setPreferredVideoQuality } from '../actions';
|
import { setPreferredVideoQuality } from '../actions';
|
||||||
|
// @ts-ignore
|
||||||
import { DEFAULT_LAST_N, VIDEO_QUALITY_LEVELS } from '../constants';
|
import { DEFAULT_LAST_N, VIDEO_QUALITY_LEVELS } from '../constants';
|
||||||
|
// @ts-ignore
|
||||||
import logger from '../logger';
|
import logger from '../logger';
|
||||||
|
|
||||||
import Slider from './Slider';
|
import Slider from './Slider';
|
||||||
|
@ -31,7 +38,7 @@ const {
|
||||||
* @returns {Object} The event in a format suitable for sending via
|
* @returns {Object} The event in a format suitable for sending via
|
||||||
* sendAnalytics.
|
* sendAnalytics.
|
||||||
*/
|
*/
|
||||||
const createEvent = function(quality) {
|
const createEvent = function(quality: string) {
|
||||||
return createToolbarEvent(
|
return createToolbarEvent(
|
||||||
'video.quality',
|
'video.quality',
|
||||||
{
|
{
|
||||||
|
@ -42,7 +49,7 @@ const createEvent = function(quality) {
|
||||||
/**
|
/**
|
||||||
* The type of the React {@code Component} props of {@link VideoQualitySlider}.
|
* The type of the React {@code Component} props of {@link VideoQualitySlider}.
|
||||||
*/
|
*/
|
||||||
type Props = {
|
interface Props extends WithTranslation {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether or not the conference is in audio only mode.
|
* Whether or not the conference is in audio only mode.
|
||||||
|
@ -68,19 +75,13 @@ type Props = {
|
||||||
/**
|
/**
|
||||||
* An object containing the CSS classes.
|
* An object containing the CSS classes.
|
||||||
*/
|
*/
|
||||||
classes: Object,
|
classes: any,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoked to request toggling of audio only mode.
|
* Invoked to request toggling of audio only mode.
|
||||||
*/
|
*/
|
||||||
dispatch: Dispatch<any>,
|
dispatch: Dispatch<any>
|
||||||
|
}
|
||||||
/**
|
|
||||||
* Invoked to obtain translated strings.
|
|
||||||
*/
|
|
||||||
t: Function
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates the styles for the component.
|
* Creates the styles for the component.
|
||||||
|
@ -89,7 +90,7 @@ type Props = {
|
||||||
*
|
*
|
||||||
* @returns {Object}
|
* @returns {Object}
|
||||||
*/
|
*/
|
||||||
const styles = theme => {
|
const styles = (theme: any) => {
|
||||||
return {
|
return {
|
||||||
dialog: {
|
dialog: {
|
||||||
color: theme.palette.text01
|
color: theme.palette.text01
|
||||||
|
@ -128,7 +129,7 @@ class VideoQualitySlider extends Component<Props> {
|
||||||
* @param {Object} props - The read-only React Component props with which
|
* @param {Object} props - The read-only React Component props with which
|
||||||
* the new instance is to be initialized.
|
* the new instance is to be initialized.
|
||||||
*/
|
*/
|
||||||
constructor(props) {
|
constructor(props: Props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
// Bind event handlers so they are only bound once for every instance.
|
// Bind event handlers so they are only bound once for every instance.
|
||||||
|
@ -203,8 +204,6 @@ class VideoQualitySlider extends Component<Props> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
_enableAudioOnly: () => void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dispatches an action to enable audio only mode.
|
* Dispatches an action to enable audio only mode.
|
||||||
*
|
*
|
||||||
|
@ -217,8 +216,6 @@ class VideoQualitySlider extends Component<Props> {
|
||||||
this.props.dispatch(setAudioOnly(true));
|
this.props.dispatch(setAudioOnly(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
_enableHighDefinition: () => void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles the action of the high definition video being selected.
|
* Handles the action of the high definition video being selected.
|
||||||
* Dispatches an action to receive high quality video from remote
|
* Dispatches an action to receive high quality video from remote
|
||||||
|
@ -233,8 +230,6 @@ class VideoQualitySlider extends Component<Props> {
|
||||||
this._setPreferredVideoQuality(HIGH);
|
this._setPreferredVideoQuality(HIGH);
|
||||||
}
|
}
|
||||||
|
|
||||||
_enableLowDefinition: () => void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dispatches an action to receive low quality video from remote
|
* Dispatches an action to receive low quality video from remote
|
||||||
* participants.
|
* participants.
|
||||||
|
@ -248,8 +243,6 @@ class VideoQualitySlider extends Component<Props> {
|
||||||
this._setPreferredVideoQuality(LOW);
|
this._setPreferredVideoQuality(LOW);
|
||||||
}
|
}
|
||||||
|
|
||||||
_enableStandardDefinition: () => void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dispatches an action to receive standard quality video from remote
|
* Dispatches an action to receive standard quality video from remote
|
||||||
* participants.
|
* participants.
|
||||||
|
@ -263,8 +256,6 @@ class VideoQualitySlider extends Component<Props> {
|
||||||
this._setPreferredVideoQuality(STANDARD);
|
this._setPreferredVideoQuality(STANDARD);
|
||||||
}
|
}
|
||||||
|
|
||||||
_enableUltraHighDefinition: () => void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dispatches an action to receive ultra HD quality video from remote
|
* Dispatches an action to receive ultra HD quality video from remote
|
||||||
* participants.
|
* participants.
|
||||||
|
@ -291,12 +282,14 @@ class VideoQualitySlider extends Component<Props> {
|
||||||
|
|
||||||
if (_audioOnly) {
|
if (_audioOnly) {
|
||||||
const audioOnlyOption = _sliderOptions.find(
|
const audioOnlyOption = _sliderOptions.find(
|
||||||
({ audioOnly }) => audioOnly);
|
({ audioOnly }: any) => audioOnly);
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
return _sliderOptions.indexOf(audioOnlyOption);
|
return _sliderOptions.indexOf(audioOnlyOption);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 0; i < _sliderOptions.length; i++) {
|
for (let i = 0; i < _sliderOptions.length; i++) {
|
||||||
|
// @ts-ignore
|
||||||
if (_sliderOptions[i].videoQuality >= _sendrecvVideoQuality) {
|
if (_sliderOptions[i].videoQuality >= _sendrecvVideoQuality) {
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
@ -305,8 +298,6 @@ class VideoQualitySlider extends Component<Props> {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
_onSliderChange: () => void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invokes a callback when the selected video quality changes.
|
* Invokes a callback when the selected video quality changes.
|
||||||
*
|
*
|
||||||
|
@ -314,13 +305,16 @@ class VideoQualitySlider extends Component<Props> {
|
||||||
* @private
|
* @private
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
_onSliderChange(event) {
|
_onSliderChange(event: React.ChangeEvent<HTMLInputElement>) {
|
||||||
const { _audioOnly, _sendrecvVideoQuality } = this.props;
|
const { _audioOnly, _sendrecvVideoQuality } = this.props;
|
||||||
const {
|
const {
|
||||||
|
// @ts-ignore
|
||||||
audioOnly,
|
audioOnly,
|
||||||
|
// @ts-ignore
|
||||||
onSelect,
|
onSelect,
|
||||||
|
// @ts-ignore
|
||||||
videoQuality
|
videoQuality
|
||||||
} = this._sliderOptions[event.target.value];
|
} = this._sliderOptions[event.target.value as keyof typeof this._sliderOptions];
|
||||||
|
|
||||||
// Take no action if the newly chosen option does not change audio only
|
// Take no action if the newly chosen option does not change audio only
|
||||||
// or video quality state.
|
// or video quality state.
|
||||||
|
@ -341,7 +335,7 @@ class VideoQualitySlider extends Component<Props> {
|
||||||
* @private
|
* @private
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
_setPreferredVideoQuality(qualityLevel) {
|
_setPreferredVideoQuality(qualityLevel: number) {
|
||||||
this.props.dispatch(setPreferredVideoQuality(qualityLevel));
|
this.props.dispatch(setPreferredVideoQuality(qualityLevel));
|
||||||
if (this.props._audioOnly) {
|
if (this.props._audioOnly) {
|
||||||
this.props.dispatch(setAudioOnly(false));
|
this.props.dispatch(setAudioOnly(false));
|
||||||
|
@ -366,7 +360,7 @@ class VideoQualitySlider extends Component<Props> {
|
||||||
* @private
|
* @private
|
||||||
* @returns {Props}
|
* @returns {Props}
|
||||||
*/
|
*/
|
||||||
function _mapStateToProps(state) {
|
function _mapStateToProps(state: any) {
|
||||||
const { enabled: audioOnly } = state['features/base/audio-only'];
|
const { enabled: audioOnly } = state['features/base/audio-only'];
|
||||||
const { p2p } = state['features/base/conference'];
|
const { p2p } = state['features/base/conference'];
|
||||||
const { preferredVideoQuality } = state['features/video-quality'];
|
const { preferredVideoQuality } = state['features/video-quality'];
|
|
@ -1,16 +1,19 @@
|
||||||
// @flow
|
/* eslint-disable lines-around-comment */
|
||||||
|
|
||||||
import { makeStyles } from '@material-ui/styles';
|
import { makeStyles } from '@material-ui/styles';
|
||||||
import React, { useCallback, useRef } from 'react';
|
import React, { useCallback, useRef } from 'react';
|
||||||
|
import { WithTranslation } from 'react-i18next';
|
||||||
import { v4 as uuidv4 } from 'uuid';
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
|
|
||||||
import { translate } from '../../base/i18n';
|
import { translate } from '../../base/i18n/functions';
|
||||||
import { Icon, IconPlusCircle } from '../../base/icons';
|
import Icon from '../../base/icons/components/Icon';
|
||||||
|
import { IconPlusCircle } from '../../base/icons/svg/index';
|
||||||
import { VIRTUAL_BACKGROUND_TYPE, type Image } from '../constants';
|
import { VIRTUAL_BACKGROUND_TYPE, type Image } from '../constants';
|
||||||
|
// @ts-ignore
|
||||||
import { resizeImage } from '../functions';
|
import { resizeImage } from '../functions';
|
||||||
|
// @ts-ignore
|
||||||
import logger from '../logger';
|
import logger from '../logger';
|
||||||
|
|
||||||
type Props = {
|
interface Props extends WithTranslation {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback used to set the 'loading' state of the parent component.
|
* Callback used to set the 'loading' state of the parent component.
|
||||||
|
@ -27,23 +30,19 @@ type Props = {
|
||||||
*/
|
*/
|
||||||
setStoredImages: Function,
|
setStoredImages: Function,
|
||||||
|
|
||||||
/**
|
|
||||||
* A list of images locally stored.
|
|
||||||
*/
|
|
||||||
storedImages: Array<Image>,
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If a label should be displayed alongside the button.
|
* If a label should be displayed alongside the button.
|
||||||
*/
|
*/
|
||||||
showLabel: boolean,
|
showLabel: boolean,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used for translation.
|
* A list of images locally stored.
|
||||||
*/
|
*/
|
||||||
t: Function
|
storedImages: Array<Image>
|
||||||
}
|
}
|
||||||
|
|
||||||
const useStyles = makeStyles(theme => {
|
// @ts-ignore
|
||||||
|
const useStyles = makeStyles((theme: any) => {
|
||||||
return {
|
return {
|
||||||
addBackground: {
|
addBackground: {
|
||||||
marginRight: `${theme.spacing(2)}px`
|
marginRight: `${theme.spacing(2)}px`
|
||||||
|
@ -80,7 +79,7 @@ function UploadImageButton({
|
||||||
t
|
t
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
const uploadImageButton: Object = useRef(null);
|
const uploadImageButton = useRef<HTMLInputElement>(null);
|
||||||
const uploadImageKeyPress = useCallback(e => {
|
const uploadImageKeyPress = useCallback(e => {
|
||||||
if (uploadImageButton.current && (e.key === ' ' || e.key === 'Enter')) {
|
if (uploadImageButton.current && (e.key === ' ' || e.key === 'Enter')) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
|
@ -1,34 +1,49 @@
|
||||||
// @flow
|
/* eslint-disable lines-around-comment */
|
||||||
|
|
||||||
import Spinner from '@atlaskit/spinner';
|
import Spinner from '@atlaskit/spinner';
|
||||||
|
// @ts-ignore
|
||||||
import Bourne from '@hapi/bourne';
|
import Bourne from '@hapi/bourne';
|
||||||
|
// @ts-ignore
|
||||||
import { jitsiLocalStorage } from '@jitsi/js-utils/jitsi-local-storage';
|
import { jitsiLocalStorage } from '@jitsi/js-utils/jitsi-local-storage';
|
||||||
import { makeStyles } from '@material-ui/styles';
|
import { makeStyles } from '@material-ui/styles';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import React, { useState, useEffect, useCallback } from 'react';
|
import React, { useState, useEffect, useCallback } from 'react';
|
||||||
|
import { WithTranslation } from 'react-i18next';
|
||||||
import { useSelector } from 'react-redux';
|
import { useSelector } from 'react-redux';
|
||||||
|
|
||||||
|
import { IState } from '../../app/types';
|
||||||
|
// @ts-ignore
|
||||||
import { getMultipleVideoSendingSupportFeatureFlag } from '../../base/config';
|
import { getMultipleVideoSendingSupportFeatureFlag } from '../../base/config';
|
||||||
|
// @ts-ignore
|
||||||
import { Dialog, hideDialog, openDialog } from '../../base/dialog';
|
import { Dialog, hideDialog, openDialog } from '../../base/dialog';
|
||||||
import { translate } from '../../base/i18n';
|
import { translate } from '../../base/i18n/functions';
|
||||||
import { Icon, IconCloseSmall, IconShareDesktop } from '../../base/icons';
|
import Icon from '../../base/icons/components/Icon';
|
||||||
|
import { IconCloseSmall, IconShareDesktop } from '../../base/icons/svg/index';
|
||||||
import { browser, JitsiTrackErrors } from '../../base/lib-jitsi-meet';
|
import { browser, JitsiTrackErrors } from '../../base/lib-jitsi-meet';
|
||||||
|
// @ts-ignore
|
||||||
import { createLocalTrack } from '../../base/lib-jitsi-meet/functions';
|
import { createLocalTrack } from '../../base/lib-jitsi-meet/functions';
|
||||||
import { VIDEO_TYPE } from '../../base/media';
|
import { VIDEO_TYPE } from '../../base/media/constants';
|
||||||
import { connect } from '../../base/redux';
|
import { connect } from '../../base/redux/functions';
|
||||||
|
// @ts-ignore
|
||||||
import { updateSettings } from '../../base/settings';
|
import { updateSettings } from '../../base/settings';
|
||||||
|
// @ts-ignore
|
||||||
import { Tooltip } from '../../base/tooltip';
|
import { Tooltip } from '../../base/tooltip';
|
||||||
|
// @ts-ignore
|
||||||
import { getLocalVideoTrack } from '../../base/tracks';
|
import { getLocalVideoTrack } from '../../base/tracks';
|
||||||
|
// @ts-ignore
|
||||||
import { NOTIFICATION_TIMEOUT_TYPE, showErrorNotification } from '../../notifications';
|
import { NOTIFICATION_TIMEOUT_TYPE, showErrorNotification } from '../../notifications';
|
||||||
|
// @ts-ignore
|
||||||
import { toggleBackgroundEffect, virtualBackgroundTrackChanged } from '../actions';
|
import { toggleBackgroundEffect, virtualBackgroundTrackChanged } from '../actions';
|
||||||
import { IMAGES, BACKGROUNDS_LIMIT, VIRTUAL_BACKGROUND_TYPE, type Image } from '../constants';
|
import { IMAGES, BACKGROUNDS_LIMIT, VIRTUAL_BACKGROUND_TYPE, type Image } from '../constants';
|
||||||
|
// @ts-ignore
|
||||||
import { toDataURL } from '../functions';
|
import { toDataURL } from '../functions';
|
||||||
|
// @ts-ignore
|
||||||
import logger from '../logger';
|
import logger from '../logger';
|
||||||
|
|
||||||
import UploadImageButton from './UploadImageButton';
|
import UploadImageButton from './UploadImageButton';
|
||||||
|
// @ts-ignore
|
||||||
import VirtualBackgroundPreview from './VirtualBackgroundPreview';
|
import VirtualBackgroundPreview from './VirtualBackgroundPreview';
|
||||||
|
|
||||||
type Props = {
|
interface Props extends WithTranslation {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The list of Images to choose from.
|
* The list of Images to choose from.
|
||||||
|
@ -63,7 +78,7 @@ type Props = {
|
||||||
/**
|
/**
|
||||||
* Returns the selected virtual background object.
|
* Returns the selected virtual background object.
|
||||||
*/
|
*/
|
||||||
_virtualBackground: Object,
|
_virtualBackground: any,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The redux {@code dispatch} function.
|
* The redux {@code dispatch} function.
|
||||||
|
@ -76,15 +91,10 @@ type Props = {
|
||||||
* NOTE: currently used only for electron in order to open the dialog in the correct state after desktop sharing
|
* NOTE: currently used only for electron in order to open the dialog in the correct state after desktop sharing
|
||||||
* selection.
|
* selection.
|
||||||
*/
|
*/
|
||||||
initialOptions: Object,
|
initialOptions: Object
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
const onError = (event: any) => {
|
||||||
* Invoked to obtain translated strings.
|
|
||||||
*/
|
|
||||||
t: Function
|
|
||||||
};
|
|
||||||
|
|
||||||
const onError = event => {
|
|
||||||
event.target.style.display = 'none';
|
event.target.style.display = 'none';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -97,7 +107,7 @@ const onError = event => {
|
||||||
* @private
|
* @private
|
||||||
* @returns {{Props}}
|
* @returns {{Props}}
|
||||||
*/
|
*/
|
||||||
function _mapStateToProps(state): Object {
|
function _mapStateToProps(state: any): Object {
|
||||||
const { localFlipX } = state['features/base/settings'];
|
const { localFlipX } = state['features/base/settings'];
|
||||||
const dynamicBrandingImages = state['features/dynamic-branding'].virtualBackgrounds;
|
const dynamicBrandingImages = state['features/dynamic-branding'].virtualBackgrounds;
|
||||||
const hasBrandingImages = Boolean(dynamicBrandingImages.length);
|
const hasBrandingImages = Boolean(dynamicBrandingImages.length);
|
||||||
|
@ -115,7 +125,7 @@ function _mapStateToProps(state): Object {
|
||||||
|
|
||||||
const VirtualBackgroundDialog = translate(connect(_mapStateToProps)(VirtualBackground));
|
const VirtualBackgroundDialog = translate(connect(_mapStateToProps)(VirtualBackground));
|
||||||
|
|
||||||
const useStyles = makeStyles(theme => {
|
const useStyles = makeStyles((theme: any) => {
|
||||||
return {
|
return {
|
||||||
container: {
|
container: {
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
|
@ -131,6 +141,7 @@ const useStyles = makeStyles(theme => {
|
||||||
gridTemplateColumns: 'auto auto auto auto auto',
|
gridTemplateColumns: 'auto auto auto auto auto',
|
||||||
columnGap: '9px',
|
columnGap: '9px',
|
||||||
cursor: 'pointer',
|
cursor: 'pointer',
|
||||||
|
// @ts-ignore
|
||||||
[[ '& .desktop-share:hover',
|
[[ '& .desktop-share:hover',
|
||||||
'& .thumbnail:hover',
|
'& .thumbnail:hover',
|
||||||
'& .blur:hover',
|
'& .blur:hover',
|
||||||
|
@ -217,6 +228,7 @@ const useStyles = makeStyles(theme => {
|
||||||
gridTemplateColumns: 'auto auto auto auto auto',
|
gridTemplateColumns: 'auto auto auto auto auto',
|
||||||
fontSize: '1.5vw',
|
fontSize: '1.5vw',
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
[[ '& .desktop-share:hover',
|
[[ '& .desktop-share:hover',
|
||||||
'& .thumbnail:hover',
|
'& .thumbnail:hover',
|
||||||
'& .blur:hover',
|
'& .blur:hover',
|
||||||
|
@ -226,6 +238,7 @@ const useStyles = makeStyles(theme => {
|
||||||
width: '60px'
|
width: '60px'
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
[[ '& .desktop-share',
|
[[ '& .desktop-share',
|
||||||
'& .virtual-background-none,',
|
'& .virtual-background-none,',
|
||||||
'& .thumbnail,',
|
'& .thumbnail,',
|
||||||
|
@ -234,6 +247,7 @@ const useStyles = makeStyles(theme => {
|
||||||
height: '60px',
|
height: '60px',
|
||||||
width: '60px'
|
width: '60px'
|
||||||
},
|
},
|
||||||
|
// @ts-ignore
|
||||||
[[ '& .desktop-share-selected',
|
[[ '& .desktop-share-selected',
|
||||||
'& .thumbnail-selected',
|
'& .thumbnail-selected',
|
||||||
'& .none-selected',
|
'& .none-selected',
|
||||||
|
@ -282,11 +296,11 @@ function VirtualBackground({
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
const [ previewIsLoaded, setPreviewIsLoaded ] = useState(false);
|
const [ previewIsLoaded, setPreviewIsLoaded ] = useState(false);
|
||||||
const [ options, setOptions ] = useState({ ...initialOptions });
|
const [ options, setOptions ] = useState<any>({ ...initialOptions });
|
||||||
const localImages = jitsiLocalStorage.getItem('virtualBackgrounds');
|
const localImages = jitsiLocalStorage.getItem('virtualBackgrounds');
|
||||||
const [ storedImages, setStoredImages ] = useState<Array<Image>>((localImages && Bourne.parse(localImages)) || []);
|
const [ storedImages, setStoredImages ] = useState<Array<Image>>((localImages && Bourne.parse(localImages)) || []);
|
||||||
const [ loading, setLoading ] = useState(false);
|
const [ loading, setLoading ] = useState(false);
|
||||||
let { disableScreensharingVirtualBackground } = useSelector(state => state['features/base/config']);
|
let { disableScreensharingVirtualBackground } = useSelector((state: IState) => state['features/base/config']);
|
||||||
|
|
||||||
// Disable screenshare as virtual background in multi-stream mode.
|
// Disable screenshare as virtual background in multi-stream mode.
|
||||||
disableScreensharingVirtualBackground = disableScreensharingVirtualBackground || _multiStreamModeEnabled;
|
disableScreensharingVirtualBackground = disableScreensharingVirtualBackground || _multiStreamModeEnabled;
|
||||||
|
@ -369,7 +383,7 @@ function VirtualBackground({
|
||||||
|
|
||||||
try {
|
try {
|
||||||
url = await createLocalTrack('desktop', '');
|
url = await createLocalTrack('desktop', '');
|
||||||
} catch (e) {
|
} catch (e: any) {
|
||||||
if (e.name === JitsiTrackErrors.SCREENSHARING_USER_CANCELED) {
|
if (e.name === JitsiTrackErrors.SCREENSHARING_USER_CANCELED) {
|
||||||
isCancelled = true;
|
isCancelled = true;
|
||||||
} else {
|
} else {
|
||||||
|
@ -526,11 +540,11 @@ function VirtualBackground({
|
||||||
blurValue: initialVirtualBackground.blurValue
|
blurValue: initialVirtualBackground.blurValue
|
||||||
});
|
});
|
||||||
dispatch(hideDialog());
|
dispatch(hideDialog());
|
||||||
});
|
}, []);
|
||||||
|
|
||||||
const loadedPreviewState = useCallback(async loaded => {
|
const loadedPreviewState = useCallback(async loaded => {
|
||||||
await setPreviewIsLoaded(loaded);
|
await setPreviewIsLoaded(loaded);
|
||||||
});
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog
|
<Dialog
|
||||||
|
@ -546,6 +560,7 @@ function VirtualBackground({
|
||||||
{loading ? (
|
{loading ? (
|
||||||
<div className = { classes.virtualBackgroundLoading }>
|
<div className = { classes.virtualBackgroundLoading }>
|
||||||
<Spinner
|
<Spinner
|
||||||
|
// @ts-ignore
|
||||||
isCompleting = { false }
|
isCompleting = { false }
|
||||||
size = 'medium' />
|
size = 'medium' />
|
||||||
</div>
|
</div>
|
||||||
|
@ -561,7 +576,7 @@ function VirtualBackground({
|
||||||
<div
|
<div
|
||||||
className = { clsx(classes.dialog, { [classes.dialogMarginTop]: previewIsLoaded }) }
|
className = { clsx(classes.dialog, { [classes.dialogMarginTop]: previewIsLoaded }) }
|
||||||
role = 'radiogroup'
|
role = 'radiogroup'
|
||||||
tabIndex = '-1'>
|
tabIndex = { -1 }>
|
||||||
<Tooltip
|
<Tooltip
|
||||||
content = { t('virtualBackground.removeBackground') }
|
content = { t('virtualBackground.removeBackground') }
|
||||||
position = { 'top' }>
|
position = { 'top' }>
|
|
@ -1,21 +1,32 @@
|
||||||
// @flow
|
/* eslint-disable lines-around-comment */
|
||||||
|
|
||||||
import Spinner from '@atlaskit/spinner';
|
import Spinner from '@atlaskit/spinner';
|
||||||
import { withStyles } from '@material-ui/core/styles';
|
import { withStyles } from '@material-ui/core/styles';
|
||||||
import React, { PureComponent } from 'react';
|
import React, { PureComponent } from 'react';
|
||||||
|
import { WithTranslation } from 'react-i18next';
|
||||||
|
|
||||||
|
import { IState } from '../../app/types';
|
||||||
|
// @ts-ignore
|
||||||
import { hideDialog } from '../../base/dialog';
|
import { hideDialog } from '../../base/dialog';
|
||||||
|
// @ts-ignore
|
||||||
import { translate } from '../../base/i18n';
|
import { translate } from '../../base/i18n';
|
||||||
import { VIDEO_TYPE } from '../../base/media';
|
// @ts-ignore
|
||||||
import Video from '../../base/media/components/Video';
|
import Video from '../../base/media/components/Video';
|
||||||
import { connect, equals } from '../../base/redux';
|
import { VIDEO_TYPE } from '../../base/media/constants';
|
||||||
|
import { connect, equals } from '../../base/redux/functions';
|
||||||
|
// @ts-ignore
|
||||||
import { getCurrentCameraDeviceId } from '../../base/settings';
|
import { getCurrentCameraDeviceId } from '../../base/settings';
|
||||||
|
// @ts-ignore
|
||||||
import { createLocalTracksF } from '../../base/tracks/functions';
|
import { createLocalTracksF } from '../../base/tracks/functions';
|
||||||
|
// @ts-ignore
|
||||||
import { NOTIFICATION_TIMEOUT_TYPE } from '../../notifications';
|
import { NOTIFICATION_TIMEOUT_TYPE } from '../../notifications';
|
||||||
|
// @ts-ignore
|
||||||
import { showWarningNotification } from '../../notifications/actions';
|
import { showWarningNotification } from '../../notifications/actions';
|
||||||
|
// @ts-ignore
|
||||||
import { toggleBackgroundEffect } from '../actions';
|
import { toggleBackgroundEffect } from '../actions';
|
||||||
import { VIRTUAL_BACKGROUND_TYPE } from '../constants';
|
import { VIRTUAL_BACKGROUND_TYPE } from '../constants';
|
||||||
|
// @ts-ignore
|
||||||
import { localTrackStopped } from '../functions';
|
import { localTrackStopped } from '../functions';
|
||||||
|
// @ts-ignore
|
||||||
import logger from '../logger';
|
import logger from '../logger';
|
||||||
|
|
||||||
const videoClassName = 'video-preview-video';
|
const videoClassName = 'video-preview-video';
|
||||||
|
@ -23,7 +34,7 @@ const videoClassName = 'video-preview-video';
|
||||||
/**
|
/**
|
||||||
* The type of the React {@code PureComponent} props of {@link VirtualBackgroundPreview}.
|
* The type of the React {@code PureComponent} props of {@link VirtualBackgroundPreview}.
|
||||||
*/
|
*/
|
||||||
export type Props = {
|
export type Props = WithTranslation & {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The deviceId of the camera device currently being used.
|
* The deviceId of the camera device currently being used.
|
||||||
|
@ -33,7 +44,7 @@ export type Props = {
|
||||||
/**
|
/**
|
||||||
* An object containing the CSS classes.
|
* An object containing the CSS classes.
|
||||||
*/
|
*/
|
||||||
classes: Object,
|
classes: any,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The redux {@code dispatch} function.
|
* The redux {@code dispatch} function.
|
||||||
|
@ -48,12 +59,7 @@ export type Props = {
|
||||||
/**
|
/**
|
||||||
* Represents the virtual background set options.
|
* Represents the virtual background set options.
|
||||||
*/
|
*/
|
||||||
options: Object,
|
options: any
|
||||||
|
|
||||||
/**
|
|
||||||
* Invoked to obtain translated strings.
|
|
||||||
*/
|
|
||||||
t: Function
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -61,6 +67,11 @@ export type Props = {
|
||||||
*/
|
*/
|
||||||
type State = {
|
type State = {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Activate the selected device camera only.
|
||||||
|
*/
|
||||||
|
jitsiTrack: Object|null,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loader activated on setting virtual background.
|
* Loader activated on setting virtual background.
|
||||||
*/
|
*/
|
||||||
|
@ -69,12 +80,7 @@ type State = {
|
||||||
/**
|
/**
|
||||||
* Flag that indicates if the local track was loaded.
|
* Flag that indicates if the local track was loaded.
|
||||||
*/
|
*/
|
||||||
localTrackLoaded: boolean,
|
localTrackLoaded: boolean
|
||||||
|
|
||||||
/**
|
|
||||||
* Activate the selected device camera only.
|
|
||||||
*/
|
|
||||||
jitsiTrack: Object
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -84,7 +90,7 @@ type State = {
|
||||||
*
|
*
|
||||||
* @returns {Object}
|
* @returns {Object}
|
||||||
*/
|
*/
|
||||||
const styles = theme => {
|
const styles = (theme: any) => {
|
||||||
return {
|
return {
|
||||||
virtualBackgroundPreview: {
|
virtualBackgroundPreview: {
|
||||||
'& .video-preview': {
|
'& .video-preview': {
|
||||||
|
@ -141,7 +147,7 @@ class VirtualBackgroundPreview extends PureComponent<Props, State> {
|
||||||
* @param {Object} props - The read-only properties with which the new
|
* @param {Object} props - The read-only properties with which the new
|
||||||
* instance is to be initialized.
|
* instance is to be initialized.
|
||||||
*/
|
*/
|
||||||
constructor(props) {
|
constructor(props: Props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
|
@ -157,7 +163,7 @@ class VirtualBackgroundPreview extends PureComponent<Props, State> {
|
||||||
* @param {Object} jitsiTrack - The track that needs to be disposed.
|
* @param {Object} jitsiTrack - The track that needs to be disposed.
|
||||||
* @returns {Promise<void>}
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
_stopStream(jitsiTrack) {
|
_stopStream(jitsiTrack: any) {
|
||||||
if (jitsiTrack) {
|
if (jitsiTrack) {
|
||||||
jitsiTrack.dispose();
|
jitsiTrack.dispose();
|
||||||
}
|
}
|
||||||
|
@ -231,6 +237,7 @@ class VirtualBackgroundPreview extends PureComponent<Props, State> {
|
||||||
return (
|
return (
|
||||||
<div className = 'video-preview-loader'>
|
<div className = 'video-preview-loader'>
|
||||||
<Spinner
|
<Spinner
|
||||||
|
// @ts-ignore
|
||||||
invertColor = { true }
|
invertColor = { true }
|
||||||
isCompleting = { false }
|
isCompleting = { false }
|
||||||
size = { 'large' } />
|
size = { 'large' } />
|
||||||
|
@ -244,7 +251,7 @@ class VirtualBackgroundPreview extends PureComponent<Props, State> {
|
||||||
* @param {Object} data - The track data.
|
* @param {Object} data - The track data.
|
||||||
* @returns {React$Node}
|
* @returns {React$Node}
|
||||||
*/
|
*/
|
||||||
_renderPreviewEntry(data) {
|
_renderPreviewEntry(data: Object) {
|
||||||
const { t } = this.props;
|
const { t } = this.props;
|
||||||
const className = 'video-background-preview-entry';
|
const className = 'video-background-preview-entry';
|
||||||
|
|
||||||
|
@ -298,7 +305,7 @@ class VirtualBackgroundPreview extends PureComponent<Props, State> {
|
||||||
*
|
*
|
||||||
* @inheritdoc
|
* @inheritdoc
|
||||||
*/
|
*/
|
||||||
async componentDidUpdate(prevProps) {
|
async componentDidUpdate(prevProps: Props) {
|
||||||
if (!equals(this.props._currentCameraDeviceId, prevProps._currentCameraDeviceId)) {
|
if (!equals(this.props._currentCameraDeviceId, prevProps._currentCameraDeviceId)) {
|
||||||
this._setTracks();
|
this._setTracks();
|
||||||
}
|
}
|
||||||
|
@ -338,7 +345,7 @@ class VirtualBackgroundPreview extends PureComponent<Props, State> {
|
||||||
* @private
|
* @private
|
||||||
* @returns {{Props}}
|
* @returns {{Props}}
|
||||||
*/
|
*/
|
||||||
function _mapStateToProps(state): Object {
|
function _mapStateToProps(state: IState): Object {
|
||||||
return {
|
return {
|
||||||
_currentCameraDeviceId: getCurrentCameraDeviceId(state)
|
_currentCameraDeviceId: getCurrentCameraDeviceId(state)
|
||||||
};
|
};
|
Loading…
Reference in New Issue