feat(video-picker) Redesign (#12902)
Convert some files to TS Implement redesign Add Virtual background and Flip video to picker menu
This commit is contained in:
parent
3cb0df579c
commit
27b8794d8c
|
@ -4,7 +4,7 @@
|
||||||
&-content {
|
&-content {
|
||||||
position: relative;
|
position: relative;
|
||||||
right: auto;
|
right: auto;
|
||||||
margin-bottom: 8px;
|
margin-bottom: 4px;
|
||||||
max-height: 456px;
|
max-height: 456px;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
width: 300px;
|
width: 300px;
|
||||||
|
|
|
@ -3,49 +3,38 @@
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
|
||||||
&-container {
|
&-container {
|
||||||
max-height: 344px;
|
max-height: 456px;
|
||||||
background: $menuBG;
|
|
||||||
border-radius: 3px;
|
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
padding: 8px;
|
margin-bottom: 4px;
|
||||||
margin-bottom: 8px;
|
position: relative;
|
||||||
|
right: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
&-entry {
|
&-entry {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
height: 168px;
|
height: 138px;
|
||||||
margin-bottom: 8px;
|
width: 244px;
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 284px;
|
margin: 0 7px 4px;
|
||||||
|
border-radius: 6px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
&:last-child {
|
&:last-child {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
&--selected {
|
&--selected {
|
||||||
border: 3px solid #31B76A;
|
border: 2px solid #4687ED;
|
||||||
border-radius: 3px;
|
|
||||||
cursor: default;
|
|
||||||
height: 162px;
|
|
||||||
width: 278px;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&-video {
|
&-video {
|
||||||
border-radius: 3px;
|
|
||||||
height: 100%;
|
height: 100%;
|
||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
&-overlay {
|
|
||||||
background: rgba(42, 58, 75, 0.6);
|
|
||||||
height: 100%;
|
|
||||||
position: absolute;
|
|
||||||
width: 100%;
|
|
||||||
z-index: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-error {
|
&-error {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -56,23 +45,22 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
&-label {
|
&-label {
|
||||||
bottom: 8px;
|
|
||||||
color: #fff;
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 100%;
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
max-width: 100%;
|
||||||
|
padding: 8px;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
|
|
||||||
&-container {
|
|
||||||
margin: 0 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-text {
|
&-text {
|
||||||
background-color: #131519;
|
background-color: rgba(0, 0, 0, 0.7);
|
||||||
border-radius: 3px;
|
border-radius: 4px;
|
||||||
padding: 2px 8px;
|
padding: 4px 8px;
|
||||||
font-size: 13px;
|
color: #fff;
|
||||||
line-height: 20px;
|
font-size: 12px;
|
||||||
margin: 0 auto;
|
line-height: 16px;
|
||||||
|
font-weight: 600;
|
||||||
max-width: calc(100% - 16px);
|
max-width: calc(100% - 16px);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
|
@ -80,8 +68,8 @@
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Override @atlaskit/InlineDialog container which is made with styled components
|
|
||||||
& > div:nth-child(2) {
|
&-checkbox-container {
|
||||||
padding: 0;
|
padding: 10px 14px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1286,6 +1286,7 @@
|
||||||
"grantModerator": "Grant Moderator Rights",
|
"grantModerator": "Grant Moderator Rights",
|
||||||
"hideSelfView": "Hide self view",
|
"hideSelfView": "Hide self view",
|
||||||
"kick": "Kick out",
|
"kick": "Kick out",
|
||||||
|
"mirrorVideo": "Mirror my video",
|
||||||
"moderator": "Moderator",
|
"moderator": "Moderator",
|
||||||
"mute": "Participant is muted",
|
"mute": "Participant is muted",
|
||||||
"muted": "Muted",
|
"muted": "Muted",
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
// @flow
|
// @ts-ignore
|
||||||
|
|
||||||
import Video from './web/Video';
|
import Video from './web/Video';
|
||||||
|
|
||||||
export default Video;
|
export default Video;
|
|
@ -34,6 +34,9 @@ const getComputedOuterHeight = (element: HTMLElement) => {
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ARIA attributes.
|
||||||
|
*/
|
||||||
[key: `aria-${string}`]: string;
|
[key: `aria-${string}`]: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -106,6 +109,11 @@ interface IProps {
|
||||||
*/
|
*/
|
||||||
onMouseLeave?: (e?: React.MouseEvent) => void;
|
onMouseLeave?: (e?: React.MouseEvent) => void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Container role.
|
||||||
|
*/
|
||||||
|
role?: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tab index for the menu.
|
* Tab index for the menu.
|
||||||
*/
|
*/
|
||||||
|
@ -167,7 +175,9 @@ const ContextMenu = ({
|
||||||
onDrawerClose,
|
onDrawerClose,
|
||||||
onMouseEnter,
|
onMouseEnter,
|
||||||
onMouseLeave,
|
onMouseLeave,
|
||||||
tabIndex
|
role,
|
||||||
|
tabIndex,
|
||||||
|
...aria
|
||||||
}: IProps) => {
|
}: IProps) => {
|
||||||
const [ isHidden, setIsHidden ] = useState(true);
|
const [ isHidden, setIsHidden ] = useState(true);
|
||||||
const containerRef = useRef<HTMLDivElement | null>(null);
|
const containerRef = useRef<HTMLDivElement | null>(null);
|
||||||
|
@ -225,6 +235,7 @@ const ContextMenu = ({
|
||||||
</Drawer>
|
</Drawer>
|
||||||
</JitsiPortal>
|
</JitsiPortal>
|
||||||
: <div
|
: <div
|
||||||
|
{ ...aria }
|
||||||
aria-label = { accessibilityLabel }
|
aria-label = { accessibilityLabel }
|
||||||
className = { cx(participantsPaneTheme.ignoredChildClassName,
|
className = { cx(participantsPaneTheme.ignoredChildClassName,
|
||||||
styles.contextMenu,
|
styles.contextMenu,
|
||||||
|
@ -237,7 +248,7 @@ const ContextMenu = ({
|
||||||
onMouseEnter = { onMouseEnter }
|
onMouseEnter = { onMouseEnter }
|
||||||
onMouseLeave = { onMouseLeave }
|
onMouseLeave = { onMouseLeave }
|
||||||
ref = { containerRef }
|
ref = { containerRef }
|
||||||
role = 'menu'
|
role = { role ?? 'menu' }
|
||||||
tabIndex = { tabIndex }>
|
tabIndex = { tabIndex }>
|
||||||
{children}
|
{children}
|
||||||
</div>;
|
</div>;
|
||||||
|
|
|
@ -1,45 +1,63 @@
|
||||||
// @flow
|
|
||||||
|
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
|
import { WithTranslation } from 'react-i18next';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
import { translate } from '../../../../base/i18n';
|
import { IReduxState, IStore } from '../../../../app/types';
|
||||||
import Video from '../../../../base/media/components/Video';
|
import { openDialog } from '../../../../base/dialog/actions';
|
||||||
import { equals } from '../../../../base/redux';
|
import { translate } from '../../../../base/i18n/functions';
|
||||||
import { createLocalVideoTracks } from '../../../functions';
|
import { IconImage } from '../../../../base/icons/svg';
|
||||||
|
import Video from '../../../../base/media/components/Video.web';
|
||||||
|
import { equals } from '../../../../base/redux/functions';
|
||||||
|
import { updateSettings } from '../../../../base/settings/actions';
|
||||||
|
import Checkbox from '../../../../base/ui/components/web/Checkbox';
|
||||||
|
import ContextMenu from '../../../../base/ui/components/web/ContextMenu';
|
||||||
|
import ContextMenuItem from '../../../../base/ui/components/web/ContextMenuItem';
|
||||||
|
import ContextMenuItemGroup from '../../../../base/ui/components/web/ContextMenuItemGroup';
|
||||||
|
import VirtualBackgroundDialog from '../../../../virtual-background/components/VirtualBackgroundDialog';
|
||||||
|
import { createLocalVideoTracks } from '../../../functions.web';
|
||||||
|
|
||||||
const videoClassName = 'video-preview-video flipVideoX';
|
const videoClassName = 'video-preview-video flipVideoX';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The type of the React {@code Component} props of {@link VideoSettingsContent}.
|
* The type of the React {@code Component} props of {@link VideoSettingsContent}.
|
||||||
*/
|
*/
|
||||||
export type Props = {
|
export interface IProps extends WithTranslation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback to change the flip state.
|
||||||
|
*/
|
||||||
|
changeFlip: (flip: boolean) => void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The deviceId of the camera device currently being used.
|
* The deviceId of the camera device currently being used.
|
||||||
*/
|
*/
|
||||||
currentCameraDeviceId: string,
|
currentCameraDeviceId: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not the local video is flipped.
|
||||||
|
*/
|
||||||
|
localFlipX: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open virtual background dialog.
|
||||||
|
*/
|
||||||
|
selectBackground: () => void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback invoked to change current camera.
|
* Callback invoked to change current camera.
|
||||||
*/
|
*/
|
||||||
setVideoInputDevice: Function,
|
setVideoInputDevice: Function;
|
||||||
|
|
||||||
/**
|
|
||||||
* Invoked to obtain translated strings.
|
|
||||||
*/
|
|
||||||
t: Function,
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback invoked to toggle the settings popup visibility.
|
* Callback invoked to toggle the settings popup visibility.
|
||||||
*/
|
*/
|
||||||
toggleVideoSettings: Function,
|
toggleVideoSettings: Function;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All the camera device ids currently connected.
|
* All the camera device ids currently connected.
|
||||||
*/
|
*/
|
||||||
videoDeviceIds: string[],
|
videoDeviceIds: string[];
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The type of the React {@code Component} state of {@link VideoSettingsContent}.
|
* The type of the React {@code Component} state of {@link VideoSettingsContent}.
|
||||||
|
@ -49,7 +67,7 @@ type State = {
|
||||||
/**
|
/**
|
||||||
* An array of all the jitsiTracks and eventual errors.
|
* An array of all the jitsiTracks and eventual errors.
|
||||||
*/
|
*/
|
||||||
trackData: Object[],
|
trackData: { deviceId: string; error?: string; jitsiTrack: any | null; }[];
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -58,9 +76,8 @@ type State = {
|
||||||
*
|
*
|
||||||
* @augments Component
|
* @augments Component
|
||||||
*/
|
*/
|
||||||
class VideoSettingsContent extends Component<Props, State> {
|
class VideoSettingsContent extends Component<IProps, State> {
|
||||||
_componentWasUnmounted: boolean;
|
_componentWasUnmounted: boolean;
|
||||||
_videoContentRef: Object;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes a new {@code VideoSettingsContent} instance.
|
* Initializes a new {@code VideoSettingsContent} instance.
|
||||||
|
@ -68,10 +85,9 @@ class VideoSettingsContent extends Component<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: IProps) {
|
||||||
super(props);
|
super(props);
|
||||||
this._onEscClick = this._onEscClick.bind(this);
|
this._onToggleFlip = this._onToggleFlip.bind(this);
|
||||||
this._videoContentRef = React.createRef();
|
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
trackData: new Array(props.videoDeviceIds.length).fill({
|
trackData: new Array(props.videoDeviceIds.length).fill({
|
||||||
|
@ -79,20 +95,16 @@ class VideoSettingsContent extends Component<Props, State> {
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
_onEscClick: (KeyboardEvent) => void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Click handler for the video entries.
|
* Toggles local video flip state.
|
||||||
*
|
*
|
||||||
* @param {KeyboardEvent} event - Esc key click to close the popup.
|
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
_onEscClick(event) {
|
_onToggleFlip() {
|
||||||
if (event.key === 'Escape') {
|
const { localFlipX, changeFlip } = this.props;
|
||||||
event.preventDefault();
|
|
||||||
event.stopPropagation();
|
changeFlip(!localFlipX);
|
||||||
this._videoContentRef.current.style.display = 'none';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -122,9 +134,9 @@ class VideoSettingsContent extends Component<Props, State> {
|
||||||
* @param {Object[]} trackData - An array of tracks that are to be disposed.
|
* @param {Object[]} trackData - An array of tracks that are to be disposed.
|
||||||
* @returns {Promise<void>}
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
_disposeTracks(trackData) {
|
_disposeTracks(trackData: { jitsiTrack: any; }[]) {
|
||||||
trackData.forEach(({ jitsiTrack }) => {
|
trackData.forEach(({ jitsiTrack }) => {
|
||||||
jitsiTrack && jitsiTrack.dispose();
|
jitsiTrack?.dispose();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,7 +146,7 @@ class VideoSettingsContent extends Component<Props, State> {
|
||||||
* @param {string} deviceId - The id of the camera device.
|
* @param {string} deviceId - The id of the camera device.
|
||||||
* @returns {Function}
|
* @returns {Function}
|
||||||
*/
|
*/
|
||||||
_onEntryClick(deviceId) {
|
_onEntryClick(deviceId: string) {
|
||||||
return () => {
|
return () => {
|
||||||
this.props.setVideoInputDevice(deviceId);
|
this.props.setVideoInputDevice(deviceId);
|
||||||
this.props.toggleVideoSettings();
|
this.props.toggleVideoSettings();
|
||||||
|
@ -148,7 +160,7 @@ class VideoSettingsContent extends Component<Props, State> {
|
||||||
* @param {number} index - The index of the entry.
|
* @param {number} index - The index of the entry.
|
||||||
* @returns {React$Node}
|
* @returns {React$Node}
|
||||||
*/
|
*/
|
||||||
_renderPreviewEntry(data, index) {
|
_renderPreviewEntry(data: { deviceId: string; error?: string; jitsiTrack: any | null; }, index: number) {
|
||||||
const { error, jitsiTrack, deviceId } = data;
|
const { error, jitsiTrack, deviceId } = data;
|
||||||
const { currentCameraDeviceId, t } = this.props;
|
const { currentCameraDeviceId, t } = this.props;
|
||||||
const isSelected = deviceId === currentCameraDeviceId;
|
const isSelected = deviceId === currentCameraDeviceId;
|
||||||
|
@ -167,19 +179,19 @@ class VideoSettingsContent extends Component<Props, State> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const props: Object = {
|
const props: any = {
|
||||||
className,
|
className,
|
||||||
key,
|
key,
|
||||||
tabIndex
|
tabIndex
|
||||||
};
|
};
|
||||||
const label = jitsiTrack && jitsiTrack.getTrackLabel();
|
const label = jitsiTrack?.getTrackLabel();
|
||||||
|
|
||||||
if (isSelected) {
|
if (isSelected) {
|
||||||
props['aria-checked'] = true;
|
props['aria-checked'] = true;
|
||||||
props.className = `${className} video-preview-entry--selected`;
|
props.className = `${className} video-preview-entry--selected`;
|
||||||
} else {
|
} else {
|
||||||
props.onClick = this._onEntryClick(deviceId);
|
props.onClick = this._onEntryClick(deviceId);
|
||||||
props.onKeyPress = e => {
|
props.onKeyPress = (e: React.KeyboardEvent) => {
|
||||||
if (e.key === ' ' || e.key === 'Enter') {
|
if (e.key === ' ' || e.key === 'Enter') {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
props.onClick();
|
props.onClick();
|
||||||
|
@ -192,12 +204,10 @@ class VideoSettingsContent extends Component<Props, State> {
|
||||||
{ ...props }
|
{ ...props }
|
||||||
role = 'radio'>
|
role = 'radio'>
|
||||||
<div className = 'video-preview-label'>
|
<div className = 'video-preview-label'>
|
||||||
{label && <div className = 'video-preview-label-container'>
|
{label && <div className = 'video-preview-label-text'>
|
||||||
<div className = 'video-preview-label-text'>
|
<span>{label}</span>
|
||||||
<span>{label}</span></div>
|
|
||||||
</div>}
|
</div>}
|
||||||
</div>
|
</div>
|
||||||
<div className = 'video-preview-overlay' />
|
|
||||||
<Video
|
<Video
|
||||||
className = { videoClassName }
|
className = { videoClassName }
|
||||||
playsinline = { true }
|
playsinline = { true }
|
||||||
|
@ -230,7 +240,7 @@ class VideoSettingsContent extends Component<Props, State> {
|
||||||
*
|
*
|
||||||
* @inheritdoc
|
* @inheritdoc
|
||||||
*/
|
*/
|
||||||
componentDidUpdate(prevProps) {
|
componentDidUpdate(prevProps: IProps) {
|
||||||
if (!equals(this.props.videoDeviceIds, prevProps.videoDeviceIds)) {
|
if (!equals(this.props.videoDeviceIds, prevProps.videoDeviceIds)) {
|
||||||
this._setTracks();
|
this._setTracks();
|
||||||
}
|
}
|
||||||
|
@ -243,21 +253,57 @@ class VideoSettingsContent extends Component<Props, State> {
|
||||||
*/
|
*/
|
||||||
render() {
|
render() {
|
||||||
const { trackData } = this.state;
|
const { trackData } = this.state;
|
||||||
|
const { selectBackground, t, localFlipX } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<ContextMenu
|
||||||
aria-labelledby = 'video-settings-button'
|
aria-labelledby = 'video-settings-button'
|
||||||
className = 'video-preview-container'
|
className = 'video-preview-container'
|
||||||
|
hidden = { false }
|
||||||
id = 'video-settings-dialog'
|
id = 'video-settings-dialog'
|
||||||
onKeyDown = { this._onEscClick }
|
|
||||||
ref = { this._videoContentRef }
|
|
||||||
role = 'radiogroup'
|
role = 'radiogroup'
|
||||||
tabIndex = '-1'>
|
tabIndex = { -1 }>
|
||||||
{trackData.map((data, i) => this._renderPreviewEntry(data, i))}
|
<ContextMenuItemGroup>
|
||||||
</div>
|
{trackData.map((data, i) => this._renderPreviewEntry(data, i))}
|
||||||
|
</ContextMenuItemGroup>
|
||||||
|
<ContextMenuItemGroup>
|
||||||
|
<ContextMenuItem
|
||||||
|
accessibilityLabel = 'virtualBackground.title'
|
||||||
|
icon = { IconImage }
|
||||||
|
onClick = { selectBackground }
|
||||||
|
text = { t('virtualBackground.title') } />
|
||||||
|
<div
|
||||||
|
className = 'video-preview-checkbox-container'
|
||||||
|
// eslint-disable-next-line react/jsx-no-bind
|
||||||
|
onClick = { e => e.stopPropagation() }>
|
||||||
|
<Checkbox
|
||||||
|
checked = { localFlipX }
|
||||||
|
label = { t('videothumbnail.mirrorVideo') }
|
||||||
|
onChange = { this._onToggleFlip } />
|
||||||
|
</div>
|
||||||
|
</ContextMenuItemGroup>
|
||||||
|
</ContextMenu>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const mapStateToProps = (state: IReduxState) => {
|
||||||
|
const { localFlipX } = state['features/base/settings'];
|
||||||
|
|
||||||
export default translate(VideoSettingsContent);
|
return {
|
||||||
|
localFlipX: Boolean(localFlipX)
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const mapDispatchToProps = (dispatch: IStore['dispatch']) => {
|
||||||
|
return {
|
||||||
|
selectBackground: () => dispatch(openDialog(VirtualBackgroundDialog)),
|
||||||
|
changeFlip: (flip: boolean) => {
|
||||||
|
dispatch(updateSettings({
|
||||||
|
localFlipX: flip
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default translate(connect(mapStateToProps, mapDispatchToProps)(VideoSettingsContent));
|
|
@ -1,7 +1,7 @@
|
||||||
// @flow
|
import React, { ReactNode } from 'react';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
import React from 'react';
|
|
||||||
|
|
||||||
|
import { IReduxState } from '../../../../app/types';
|
||||||
import {
|
import {
|
||||||
setVideoInputDeviceAndUpdateSettings
|
setVideoInputDeviceAndUpdateSettings
|
||||||
} from '../../../../base/devices/actions.web';
|
} from '../../../../base/devices/actions.web';
|
||||||
|
@ -9,36 +9,35 @@ import {
|
||||||
getVideoDeviceIds
|
getVideoDeviceIds
|
||||||
} from '../../../../base/devices/functions.web';
|
} from '../../../../base/devices/functions.web';
|
||||||
import Popover from '../../../../base/popover/components/Popover.web';
|
import Popover from '../../../../base/popover/components/Popover.web';
|
||||||
import { connect } from '../../../../base/redux';
|
|
||||||
import { SMALL_MOBILE_WIDTH } from '../../../../base/responsive-ui/constants';
|
import { SMALL_MOBILE_WIDTH } from '../../../../base/responsive-ui/constants';
|
||||||
import { getCurrentCameraDeviceId } from '../../../../base/settings';
|
import { getCurrentCameraDeviceId } from '../../../../base/settings/functions.web';
|
||||||
import { toggleVideoSettings } from '../../../actions';
|
import { toggleVideoSettings } from '../../../actions';
|
||||||
import { getVideoSettingsVisibility } from '../../../functions';
|
import { getVideoSettingsVisibility } from '../../../functions.web';
|
||||||
|
|
||||||
import VideoSettingsContent, { type Props as VideoSettingsProps } from './VideoSettingsContent';
|
import VideoSettingsContent, { type IProps as VideoSettingsProps } from './VideoSettingsContent';
|
||||||
|
|
||||||
|
|
||||||
type Props = VideoSettingsProps & {
|
interface IProps extends VideoSettingsProps {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component children (the Video button).
|
* Component children (the Video button).
|
||||||
*/
|
*/
|
||||||
children: React$Node,
|
children: ReactNode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Flag controlling the visibility of the popup.
|
* Flag controlling the visibility of the popup.
|
||||||
*/
|
*/
|
||||||
isOpen: boolean,
|
isOpen: boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback executed when the popup closes.
|
* Callback executed when the popup closes.
|
||||||
*/
|
*/
|
||||||
onClose: Function,
|
onClose: Function;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The popup placement enum value.
|
* The popup placement enum value.
|
||||||
*/
|
*/
|
||||||
popupPlacement: string
|
popupPlacement: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -54,7 +53,7 @@ function VideoSettingsPopup({
|
||||||
popupPlacement,
|
popupPlacement,
|
||||||
setVideoInputDevice,
|
setVideoInputDevice,
|
||||||
videoDeviceIds
|
videoDeviceIds
|
||||||
}: Props) {
|
}: IProps) {
|
||||||
return (
|
return (
|
||||||
<div className = 'video-preview'>
|
<div className = 'video-preview'>
|
||||||
<Popover
|
<Popover
|
||||||
|
@ -80,14 +79,14 @@ function VideoSettingsPopup({
|
||||||
* @param {Object} state - Redux state.
|
* @param {Object} state - Redux state.
|
||||||
* @returns {Object}
|
* @returns {Object}
|
||||||
*/
|
*/
|
||||||
function mapStateToProps(state) {
|
function mapStateToProps(state: IReduxState) {
|
||||||
const { clientWidth } = state['features/base/responsive-ui'];
|
const { clientWidth } = state['features/base/responsive-ui'];
|
||||||
|
|
||||||
return {
|
return {
|
||||||
currentCameraDeviceId: getCurrentCameraDeviceId(state),
|
currentCameraDeviceId: getCurrentCameraDeviceId(state),
|
||||||
isOpen: getVideoSettingsVisibility(state),
|
isOpen: Boolean(getVideoSettingsVisibility(state)),
|
||||||
popupPlacement: clientWidth <= SMALL_MOBILE_WIDTH ? 'auto' : 'top-end',
|
popupPlacement: clientWidth <= Number(SMALL_MOBILE_WIDTH) ? 'auto' : 'top-end',
|
||||||
videoDeviceIds: getVideoDeviceIds(state)
|
videoDeviceIds: getVideoDeviceIds(state) ?? []
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -377,7 +377,7 @@ const styles = () => {
|
||||||
rowGap: '8px',
|
rowGap: '8px',
|
||||||
margin: 0,
|
margin: 0,
|
||||||
padding: '16px',
|
padding: '16px',
|
||||||
marginBottom: '8px'
|
marginBottom: '4px'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue