2022-09-03 02:18:17 +08:00
|
|
|
import React from 'react';
|
|
|
|
import PropTypes from 'prop-types';
|
|
|
|
import getFromUserSettings from '/imports/ui/services/users-settings';
|
2024-05-29 21:26:11 +08:00
|
|
|
import { getSettingsSingletonInstance } from '/imports/ui/services/settings';
|
2022-09-03 02:18:17 +08:00
|
|
|
import MediaService from '/imports/ui/components/media/service';
|
|
|
|
import { LAYOUT_TYPE, ACTIONS } from '../enums';
|
|
|
|
import { isMobile } from '../utils';
|
|
|
|
import { updateSettings } from '/imports/ui/components/settings/service';
|
2023-04-19 20:41:30 +08:00
|
|
|
import { Session } from 'meteor/session';
|
2022-09-03 02:18:17 +08:00
|
|
|
|
|
|
|
const equalDouble = (n1, n2) => {
|
|
|
|
const precision = 0.01;
|
|
|
|
|
|
|
|
return Math.abs(n1 - n2) <= precision;
|
|
|
|
};
|
|
|
|
|
|
|
|
const propTypes = {
|
|
|
|
cameraWidth: PropTypes.number,
|
|
|
|
cameraHeight: PropTypes.number,
|
|
|
|
cameraIsResizing: PropTypes.bool,
|
|
|
|
cameraPosition: PropTypes.string,
|
|
|
|
focusedCamera: PropTypes.string,
|
2022-09-15 23:01:31 +08:00
|
|
|
horizontalPosition: PropTypes.bool,
|
2022-10-10 21:32:19 +08:00
|
|
|
isMeetingLayoutResizing: PropTypes.bool,
|
2022-09-03 02:18:17 +08:00
|
|
|
isPresenter: PropTypes.bool,
|
|
|
|
isModerator: PropTypes.bool,
|
|
|
|
layoutContextDispatch: PropTypes.func,
|
|
|
|
meetingLayout: PropTypes.string,
|
|
|
|
meetingLayoutCameraPosition: PropTypes.string,
|
|
|
|
meetingLayoutFocusedCamera: PropTypes.string,
|
|
|
|
meetingLayoutVideoRate: PropTypes.number,
|
|
|
|
meetingPresentationIsOpen: PropTypes.bool,
|
|
|
|
meetingLayoutUpdatedAt: PropTypes.number,
|
|
|
|
presentationIsOpen: PropTypes.bool,
|
|
|
|
presentationVideoRate: PropTypes.number,
|
|
|
|
pushLayout: PropTypes.bool,
|
|
|
|
pushLayoutMeeting: PropTypes.bool,
|
|
|
|
selectedLayout: PropTypes.string,
|
|
|
|
setMeetingLayout: PropTypes.func,
|
2023-03-04 05:59:47 +08:00
|
|
|
setPushLayout: PropTypes.func,
|
2022-09-03 02:18:17 +08:00
|
|
|
shouldShowScreenshare: PropTypes.bool,
|
|
|
|
shouldShowExternalVideo: PropTypes.bool,
|
2023-11-23 01:21:07 +08:00
|
|
|
enforceLayout: PropTypes.string,
|
2024-01-30 21:03:11 +08:00
|
|
|
setLocalSettings: PropTypes.func.isRequired,
|
2022-09-03 02:18:17 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
class PushLayoutEngine extends React.Component {
|
|
|
|
constructor(props) {
|
|
|
|
super(props);
|
|
|
|
}
|
|
|
|
|
|
|
|
componentDidMount() {
|
|
|
|
const {
|
|
|
|
cameraWidth,
|
|
|
|
cameraHeight,
|
|
|
|
horizontalPosition,
|
|
|
|
layoutContextDispatch,
|
|
|
|
meetingLayout,
|
|
|
|
meetingLayoutCameraPosition,
|
|
|
|
meetingLayoutFocusedCamera,
|
|
|
|
meetingLayoutVideoRate,
|
|
|
|
meetingPresentationIsOpen,
|
|
|
|
shouldShowScreenshare,
|
|
|
|
shouldShowExternalVideo,
|
2023-11-23 01:21:07 +08:00
|
|
|
enforceLayout,
|
2024-01-30 21:03:11 +08:00
|
|
|
setLocalSettings,
|
2024-02-15 22:58:30 +08:00
|
|
|
pushLayoutMeeting,
|
2022-09-03 02:18:17 +08:00
|
|
|
} = this.props;
|
|
|
|
|
2024-05-29 21:26:11 +08:00
|
|
|
const Settings = getSettingsSingletonInstance();
|
|
|
|
|
2024-03-19 04:42:03 +08:00
|
|
|
const changeLayout = LAYOUT_TYPE[getFromUserSettings('bbb_change_layout', null)];
|
|
|
|
const defaultLayout = LAYOUT_TYPE[getFromUserSettings('bbb_default_layout', null)];
|
2024-05-10 21:35:25 +08:00
|
|
|
const enforcedLayout = LAYOUT_TYPE[enforceLayout] || null;
|
2022-09-03 02:18:17 +08:00
|
|
|
|
2024-05-10 21:35:25 +08:00
|
|
|
Settings.application.selectedLayout = enforcedLayout
|
2024-03-19 04:42:03 +08:00
|
|
|
|| changeLayout
|
|
|
|
|| defaultLayout
|
|
|
|
|| meetingLayout;
|
|
|
|
|
|
|
|
let { selectedLayout } = Settings.application;
|
2022-09-03 02:18:17 +08:00
|
|
|
if (isMobile()) {
|
|
|
|
selectedLayout = selectedLayout === 'custom' ? 'smart' : selectedLayout;
|
|
|
|
Settings.application.selectedLayout = selectedLayout;
|
|
|
|
}
|
2023-07-26 00:20:45 +08:00
|
|
|
Session.set('isGridEnabled', selectedLayout === LAYOUT_TYPE.VIDEO_FOCUS);
|
|
|
|
|
2024-01-30 21:03:11 +08:00
|
|
|
Settings.save(setLocalSettings);
|
2022-09-03 02:18:17 +08:00
|
|
|
|
2024-05-29 21:26:11 +08:00
|
|
|
const HIDE_PRESENTATION = window.meetingClientSettings.public.layout.hidePresentationOnJoin;
|
|
|
|
|
2024-02-15 22:58:30 +08:00
|
|
|
const shouldOpenPresentation = shouldShowScreenshare || shouldShowExternalVideo;
|
|
|
|
let presentationIsOpen = !getFromUserSettings('bbb_hide_presentation_on_join', HIDE_PRESENTATION);
|
|
|
|
presentationIsOpen = pushLayoutMeeting ? meetingPresentationIsOpen : presentationIsOpen;
|
|
|
|
presentationIsOpen = shouldOpenPresentation || presentationIsOpen;
|
|
|
|
MediaService.setPresentationIsOpen(layoutContextDispatch, presentationIsOpen);
|
|
|
|
Session.set('presentationLastState', presentationIsOpen);
|
2022-09-03 02:18:17 +08:00
|
|
|
|
|
|
|
if (selectedLayout === 'custom') {
|
|
|
|
setTimeout(() => {
|
|
|
|
layoutContextDispatch({
|
|
|
|
type: ACTIONS.SET_FOCUSED_CAMERA_ID,
|
|
|
|
value: meetingLayoutFocusedCamera,
|
|
|
|
});
|
|
|
|
|
|
|
|
layoutContextDispatch({
|
|
|
|
type: ACTIONS.SET_CAMERA_DOCK_POSITION,
|
2024-04-02 02:48:15 +08:00
|
|
|
value: meetingLayoutCameraPosition || 'contentTop',
|
2022-09-03 02:18:17 +08:00
|
|
|
});
|
|
|
|
|
|
|
|
if (!equalDouble(meetingLayoutVideoRate, 0)) {
|
|
|
|
let w, h;
|
|
|
|
if (horizontalPosition) {
|
|
|
|
w = window.innerWidth * meetingLayoutVideoRate;
|
|
|
|
h = cameraHeight;
|
|
|
|
} else {
|
|
|
|
w = cameraWidth;
|
|
|
|
h = window.innerHeight * meetingLayoutVideoRate;
|
|
|
|
}
|
|
|
|
|
|
|
|
layoutContextDispatch({
|
|
|
|
type: ACTIONS.SET_CAMERA_DOCK_SIZE,
|
|
|
|
value: {
|
|
|
|
width: w,
|
|
|
|
height: h,
|
|
|
|
browserWidth: window.innerWidth,
|
|
|
|
browserHeight: window.innerHeight,
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
componentDidUpdate(prevProps) {
|
|
|
|
const {
|
|
|
|
cameraWidth,
|
|
|
|
cameraHeight,
|
|
|
|
cameraIsResizing,
|
|
|
|
cameraPosition,
|
|
|
|
focusedCamera,
|
|
|
|
horizontalPosition,
|
2022-10-10 21:32:19 +08:00
|
|
|
isMeetingLayoutResizing,
|
2022-09-03 02:18:17 +08:00
|
|
|
isModerator,
|
|
|
|
isPresenter,
|
|
|
|
layoutContextDispatch,
|
|
|
|
meetingLayout,
|
|
|
|
meetingLayoutUpdatedAt,
|
|
|
|
meetingPresentationIsOpen,
|
|
|
|
meetingLayoutCameraPosition,
|
|
|
|
meetingLayoutFocusedCamera,
|
|
|
|
meetingLayoutVideoRate,
|
|
|
|
presentationIsOpen,
|
|
|
|
presentationVideoRate,
|
|
|
|
pushLayout,
|
|
|
|
pushLayoutMeeting,
|
|
|
|
selectedLayout,
|
|
|
|
setMeetingLayout,
|
2023-03-04 05:59:47 +08:00
|
|
|
setPushLayout,
|
2023-11-23 01:21:07 +08:00
|
|
|
enforceLayout,
|
2024-01-30 21:03:11 +08:00
|
|
|
setLocalSettings,
|
2022-09-03 02:18:17 +08:00
|
|
|
} = this.props;
|
|
|
|
|
|
|
|
const meetingLayoutDidChange = meetingLayout !== prevProps.meetingLayout;
|
|
|
|
const pushLayoutMeetingDidChange = pushLayoutMeeting !== prevProps.pushLayoutMeeting;
|
2023-11-23 01:21:07 +08:00
|
|
|
const enforceLayoutDidChange = enforceLayout !== prevProps.enforceLayout;
|
2022-09-03 02:18:17 +08:00
|
|
|
const shouldSwitchLayout = isPresenter
|
2023-11-23 01:21:07 +08:00
|
|
|
? meetingLayoutDidChange || enforceLayoutDidChange
|
|
|
|
: ((meetingLayoutDidChange || pushLayoutMeetingDidChange) && pushLayoutMeeting) || enforceLayoutDidChange;
|
2024-05-29 21:26:11 +08:00
|
|
|
const Settings = getSettingsSingletonInstance();
|
2022-09-03 02:18:17 +08:00
|
|
|
|
|
|
|
if (shouldSwitchLayout) {
|
2023-11-23 01:21:07 +08:00
|
|
|
let contextLayout = enforceLayout || meetingLayout;
|
2022-09-03 02:18:17 +08:00
|
|
|
if (isMobile()) {
|
2023-11-23 01:21:07 +08:00
|
|
|
if (contextLayout === 'custom') {
|
|
|
|
contextLayout = 'smart';
|
|
|
|
}
|
2022-09-03 02:18:17 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
layoutContextDispatch({
|
|
|
|
type: ACTIONS.SET_LAYOUT_TYPE,
|
|
|
|
value: contextLayout,
|
|
|
|
});
|
|
|
|
|
|
|
|
updateSettings({
|
|
|
|
application: {
|
|
|
|
...Settings.application,
|
|
|
|
selectedLayout: contextLayout,
|
|
|
|
},
|
2024-01-30 21:03:11 +08:00
|
|
|
}, null, setLocalSettings);
|
2022-09-03 02:18:17 +08:00
|
|
|
}
|
|
|
|
|
2023-11-23 01:21:07 +08:00
|
|
|
if (!enforceLayout && pushLayoutMeetingDidChange) {
|
2022-09-03 02:18:17 +08:00
|
|
|
updateSettings({
|
|
|
|
application: {
|
|
|
|
...Settings.application,
|
|
|
|
pushLayout: pushLayoutMeeting,
|
|
|
|
},
|
2024-01-30 21:03:11 +08:00
|
|
|
}, null, setLocalSettings);
|
2022-09-03 02:18:17 +08:00
|
|
|
}
|
|
|
|
|
2023-03-17 20:37:45 +08:00
|
|
|
if (meetingLayout === "custom" && selectedLayout === "custom" && !isPresenter) {
|
2022-09-03 02:18:17 +08:00
|
|
|
|
|
|
|
if (meetingLayoutFocusedCamera !== prevProps.meetingLayoutFocusedCamera
|
|
|
|
|| meetingLayoutUpdatedAt !== prevProps.meetingLayoutUpdatedAt) {
|
|
|
|
|
|
|
|
layoutContextDispatch({
|
|
|
|
type: ACTIONS.SET_FOCUSED_CAMERA_ID,
|
|
|
|
value: meetingLayoutFocusedCamera,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
if (meetingLayoutCameraPosition !== prevProps.meetingLayoutCameraPosition
|
|
|
|
|| meetingLayoutUpdatedAt !== prevProps.meetingLayoutUpdatedAt) {
|
|
|
|
|
|
|
|
layoutContextDispatch({
|
|
|
|
type: ACTIONS.SET_CAMERA_DOCK_POSITION,
|
|
|
|
value: meetingLayoutCameraPosition,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!equalDouble(meetingLayoutVideoRate, prevProps.meetingLayoutVideoRate)
|
|
|
|
|| meetingLayoutUpdatedAt !== prevProps.meetingLayoutUpdatedAt) {
|
|
|
|
|
|
|
|
let w, h;
|
|
|
|
if (horizontalPosition) {
|
|
|
|
w = window.innerWidth * meetingLayoutVideoRate;
|
|
|
|
h = cameraHeight;
|
|
|
|
} else {
|
|
|
|
w = cameraWidth;
|
|
|
|
h = window.innerHeight * meetingLayoutVideoRate;
|
|
|
|
}
|
|
|
|
|
2022-10-10 21:32:19 +08:00
|
|
|
if (isMeetingLayoutResizing !== prevProps.isMeetingLayoutResizing) {
|
2022-09-03 02:18:17 +08:00
|
|
|
layoutContextDispatch({
|
|
|
|
type: ACTIONS.SET_CAMERA_DOCK_IS_RESIZING,
|
2022-10-10 21:32:19 +08:00
|
|
|
value: isMeetingLayoutResizing,
|
2022-09-03 02:18:17 +08:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
layoutContextDispatch({
|
|
|
|
type: ACTIONS.SET_CAMERA_DOCK_SIZE,
|
|
|
|
value: {
|
|
|
|
width: w,
|
|
|
|
height: h,
|
|
|
|
browserWidth: window.innerWidth,
|
|
|
|
browserHeight: window.innerHeight,
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
if (meetingPresentationIsOpen !== prevProps.meetingPresentationIsOpen
|
|
|
|
|| meetingLayoutUpdatedAt !== prevProps.meetingLayoutUpdatedAt) {
|
|
|
|
|
|
|
|
layoutContextDispatch({
|
|
|
|
type: ACTIONS.SET_PRESENTATION_IS_OPEN,
|
|
|
|
value: meetingPresentationIsOpen,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const layoutChanged = presentationIsOpen !== prevProps.presentationIsOpen
|
|
|
|
|| selectedLayout !== prevProps.selectedLayout
|
|
|
|
|| cameraIsResizing !== prevProps.cameraIsResizing
|
|
|
|
|| cameraPosition !== prevProps.cameraPosition
|
|
|
|
|| focusedCamera !== prevProps.focusedCamera
|
2023-11-23 01:21:07 +08:00
|
|
|
|| enforceLayout !== prevProps.enforceLayout
|
2022-09-03 02:18:17 +08:00
|
|
|
|| !equalDouble(presentationVideoRate, prevProps.presentationVideoRate);
|
|
|
|
|
2023-03-04 05:59:47 +08:00
|
|
|
if (pushLayout !== prevProps.pushLayout) { // push layout once after presenter toggles / special case where we set pushLayout to false in all viewers
|
2023-03-07 05:08:25 +08:00
|
|
|
if (isModerator) {
|
2023-03-04 05:59:47 +08:00
|
|
|
setPushLayout(pushLayout);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-03-07 05:08:25 +08:00
|
|
|
if (pushLayout && layoutChanged || pushLayout !== prevProps.pushLayout) { // change layout sizes / states
|
2022-09-03 02:18:17 +08:00
|
|
|
if (isPresenter) {
|
|
|
|
setMeetingLayout();
|
|
|
|
}
|
|
|
|
}
|
2023-07-26 00:20:45 +08:00
|
|
|
|
|
|
|
if (selectedLayout !== prevProps.selectedLayout) {
|
|
|
|
Session.set('isGridEnabled', selectedLayout === LAYOUT_TYPE.VIDEO_FOCUS);
|
|
|
|
}
|
2022-09-03 02:18:17 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
render() {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
PushLayoutEngine.propTypes = propTypes;
|
|
|
|
|
|
|
|
export default PushLayoutEngine;
|