Detect aspect ratio to autochange webcams placement #8504

This commit is contained in:
Vitor Mateus 2020-01-17 10:20:03 -03:00
parent 822e11fdae
commit 1ae6324392
5 changed files with 118 additions and 18 deletions

View File

@ -11,12 +11,12 @@ import AudioManager from '/imports/ui/services/audio-manager';
import logger from '/imports/startup/client/logger';
import Users from '/imports/api/users';
import { Session } from 'meteor/session';
import { FormattedMessage } from 'react-intl';
import IntlStartup from './intl';
import Meetings, { RecordMeetings } from '../../api/meetings';
import AppService from '/imports/ui/components/app/service';
import Breakouts from '/imports/api/breakouts';
import AudioService from '/imports/ui/components/audio/service';
import { FormattedMessage } from 'react-intl';
import { notify } from '/imports/ui/services/notification';
const BREAKOUT_END_NOTIFY_DELAY = 50;

View File

@ -21,6 +21,7 @@ import LockNotifier from '/imports/ui/components/lock-viewers/notify/container';
import PingPongContainer from '/imports/ui/components/ping-pong/container';
import MediaService from '/imports/ui/components/media/service';
import ManyWebcamsNotifier from '/imports/ui/components/video-provider/many-users-notify/container';
import { withDraggableContext } from '../media/webcam-draggable-overlay/context';
import { styles } from './styles';
const MOBILE_MEDIA = 'only screen and (max-width: 40em)';
@ -103,6 +104,7 @@ class App extends Component {
this.handleWindowResize = throttle(this.handleWindowResize).bind(this);
this.shouldAriaHide = this.shouldAriaHide.bind(this);
this.renderMedia = withDraggableContext(this.renderMedia.bind(this));
}
componentDidMount() {

View File

@ -1,16 +1,15 @@
import React, { Component, Fragment } from 'react';
import React, { PureComponent, Fragment } from 'react';
import Draggable from 'react-draggable';
import cx from 'classnames';
import _ from 'lodash';
import PropTypes from 'prop-types';
import Resizable from 're-resizable';
import { isMobile, isIPad13 } from 'react-device-detect';
import { withDraggableContext } from './context';
import { withDraggableConsumer } from './context';
import VideoProviderContainer from '/imports/ui/components/video-provider/container';
import { styles } from '../styles.scss';
import Storage from '../../../services/storage/session';
const { webcamsDefaultPlacement } = Meteor.settings.public.layout;
const BROWSER_ISMOBILE = isMobile || isIPad13;
const propTypes = {
@ -32,7 +31,7 @@ const defaultProps = {
};
const dispatchResizeEvent = () => window.dispatchEvent(new Event('resize'));
class WebcamDraggable extends Component {
class WebcamDraggable extends PureComponent {
constructor(props) {
super(props);
@ -58,17 +57,34 @@ class WebcamDraggable extends Component {
}
componentDidUpdate(prevProps) {
const { swapLayout, webcamDraggableState } = this.props;
const { placement } = webcamDraggableState;
const { swapLayout, webcamDraggableState, webcamDraggableDispatch } = this.props;
const {
placement: statePlacement,
orientation,
lastPlacementLandscape,
lastPlacementPortrait,
} = webcamDraggableState;
const { webcamDraggableState: prevWebcamDraggableState } = prevProps;
const { placement: prevPlacement } = prevWebcamDraggableState;
const { placement: prevPlacement, orientation: prevOrientation } = prevWebcamDraggableState;
if (prevProps.swapLayout !== swapLayout) {
setTimeout(() => this.forceUpdate(), 500);
}
if (prevPlacement !== placement) {
if (prevPlacement !== statePlacement) {
setTimeout(() => this.forceUpdate(), 200);
setTimeout(() => window.dispatchEvent(new Event('resize')), 500);
}
if (prevOrientation !== orientation) {
const storagePlacement = Storage.getItem('webcamPlacement');
if ((prevOrientation == null || prevOrientation === 'portrait') && orientation === 'landscape') {
if (storagePlacement !== lastPlacementLandscape && lastPlacementLandscape === 'top') webcamDraggableDispatch({ type: 'setplacementToTop' });
if (storagePlacement !== lastPlacementLandscape && lastPlacementLandscape === 'bottom') webcamDraggableDispatch({ type: 'setplacementToBottom' });
}
if ((prevOrientation == null || prevOrientation === 'landscape') && orientation === 'portrait') {
if (storagePlacement !== lastPlacementPortrait && lastPlacementPortrait === 'left') webcamDraggableDispatch({ type: 'setplacementToLeft' });
if (storagePlacement !== lastPlacementPortrait && lastPlacementPortrait === 'right') webcamDraggableDispatch({ type: 'setplacementToRight' });
}
}
}
componentWillUnmount() {
@ -227,12 +243,16 @@ class WebcamDraggable extends Component {
if (targetClassname) {
if (targetClassname.includes('Top')) {
webcamDraggableDispatch({ type: 'setplacementToTop' });
webcamDraggableDispatch({ type: 'setLastPlacementLandscapeToTop' });
} else if (targetClassname.includes('Right')) {
webcamDraggableDispatch({ type: 'setplacementToRight' });
webcamDraggableDispatch({ type: 'setLastPlacementPortraitToRight' });
} else if (targetClassname.includes('Bottom')) {
webcamDraggableDispatch({ type: 'setplacementToBottom' });
webcamDraggableDispatch({ type: 'setLastPlacementLandscapeToBottom' });
} else if (targetClassname.includes('Left')) {
webcamDraggableDispatch({ type: 'setplacementToLeft' });
webcamDraggableDispatch({ type: 'setLastPlacementPortraitToLeft' });
}
}
webcamDraggableDispatch({ type: 'dragEnd' });
@ -261,12 +281,12 @@ class WebcamDraggable extends Component {
videoListSize,
optimalGrid,
} = webcamDraggableState;
let placement = Storage.getItem('webcamPlacement');
const placement = Storage.getItem('webcamPlacement');
const lastPosition = Storage.getItem('webcamLastPosition') || { x: 0, y: 0 };
let position = lastPosition;
if (!placement) {
placement = webcamsDefaultPlacement;
}
if (dragging) {
position = webcamDraggableState.tempPosition;
@ -537,4 +557,4 @@ class WebcamDraggable extends Component {
WebcamDraggable.propTypes = propTypes;
WebcamDraggable.defaultProps = defaultProps;
export default withDraggableContext(WebcamDraggable);
export default withDraggableConsumer(WebcamDraggable);

View File

@ -1,10 +1,15 @@
import React, { createContext, useReducer, useEffect } from 'react';
import Storage from '../../../services/storage/session';
const { webcamsDefaultPlacement } = Meteor.settings.public.layout;
export const WebcamDraggableContext = createContext();
const initialState = {
placement: 'top',
placement: webcamsDefaultPlacement,
lastPlacementLandscape: 'top',
lastPlacementPortrait: 'left',
orientation: null,
mediaSize: {
width: 0,
height: 0,
@ -58,12 +63,48 @@ const reducer = (state, action) => {
placement: 'left',
};
}
case 'setLastPlacementPortraitToLeft': {
return {
...state,
lastPlacementPortrait: 'left',
};
}
case 'setLastPlacementPortraitToRight': {
return {
...state,
lastPlacementPortrait: 'right',
};
}
case 'setLastPlacementLandscapeToTop': {
return {
...state,
lastPlacementLandscape: 'top',
};
}
case 'setLastPlacementLandscapeToBottom': {
return {
...state,
lastPlacementLandscape: 'bottom',
};
}
case 'setplacementToFloating': {
return {
...state,
placement: 'floating',
};
}
case 'setOrientationToLandscape': {
return {
...state,
orientation: 'landscape',
};
}
case 'setOrientationToPortrait': {
return {
...state,
orientation: 'portrait',
};
}
case 'setMediaSize': {
return {
...state,
@ -165,13 +206,22 @@ const ContextConsumer = Component => props => (
const ContextProvider = (props) => {
const [webcamDraggableState, webcamDraggableDispatch] = useReducer(reducer, initialState);
const { placement, lastPosition } = webcamDraggableState;
const {
placement,
lastPosition,
lastPlacementLandscape,
lastPlacementPortrait,
} = webcamDraggableState;
const { children } = props;
useEffect(() => {
Storage.setItem('webcamPlacement', placement);
Storage.setItem('webcamLastPlacementLandscape', lastPlacementLandscape);
Storage.setItem('webcamlastPlacementPortrait', lastPlacementPortrait);
Storage.setItem('webcamLastPosition', lastPosition);
}, [
placement,
lastPlacementLandscape,
lastPlacementPortrait,
lastPosition,
]);

View File

@ -15,6 +15,7 @@ import PresentationCloseButton from './presentation-close-button/component';
import DownloadPresentationButton from './download-presentation-button/component';
import FullscreenService from '../fullscreen-button/service';
import FullscreenButtonContainer from '../fullscreen-button/container';
import { withDraggableContext, withDraggableConsumer } from '../media/webcam-draggable-overlay/context';
const intlMessages = defineMessages({
presentationLabel: {
@ -81,10 +82,25 @@ class PresentationArea extends PureComponent {
window.addEventListener('resize', this.onResize);
this.getInitialPresentationSizes();
this.refPresentationContainer.addEventListener('fullscreenchange', this.onFullscreenChange);
const { slidePosition, webcamDraggableDispatch } = this.props;
const { width: currWidth, height: currHeight } = slidePosition;
if (currWidth > currHeight || currWidth === currHeight) {
webcamDraggableDispatch({ type: 'setOrientationToLandscape' });
}
if (currHeight > currWidth) {
webcamDraggableDispatch({ type: 'setOrientationToPortrait' });
}
}
componentDidUpdate(prevProps) {
const { currentPresentation, notify, intl } = this.props;
const {
currentPresentation,
notify,
intl,
slidePosition,
webcamDraggableDispatch,
} = this.props;
if (prevProps.currentPresentation.name !== currentPresentation.name) {
notify(
@ -93,6 +109,18 @@ class PresentationArea extends PureComponent {
'presentation',
);
}
const { width: prevWidth, height: prevHeight } = prevProps.slidePosition;
const { width: currWidth, height: currHeight } = slidePosition;
if (prevWidth !== currWidth || prevHeight !== currHeight) {
if (currWidth > currHeight || currWidth === currHeight) {
webcamDraggableDispatch({ type: 'setOrientationToLandscape' });
}
if (currHeight > currWidth) {
webcamDraggableDispatch({ type: 'setOrientationToPortrait' });
}
}
}
componentWillUnmount() {
@ -654,7 +682,7 @@ class PresentationArea extends PureComponent {
}
}
export default injectIntl(PresentationArea);
export default injectIntl(withDraggableConsumer(PresentationArea));
PresentationArea.propTypes = {
intl: intlShape.isRequired,