bigbluebutton-Github/bigbluebutton-html5/imports/ui/components/webcam/component.jsx

282 lines
9.7 KiB
React
Raw Normal View History

import React, { useState, useEffect } from 'react';
import Resizable from 're-resizable';
import Draggable from 'react-draggable';
2021-11-03 19:51:56 +08:00
import Styled from './styles';
import { ACTIONS, CAMERADOCK_POSITION } from '../layout/enums';
import DropAreaContainer from './drop-areas/container';
import VideoProviderContainer from '/imports/ui/components/video-provider/container';
2021-07-14 00:52:20 +08:00
import Storage from '/imports/ui/services/storage/session';
import { colorContentBackground } from '/imports/ui/stylesheets/styled-components/palette';
2023-09-12 21:42:55 +08:00
import { defineMessages } from 'react-intl';
import {
isPresenter,
} from '/imports/ui/components/settings/service';
const intlMessages = defineMessages({
layoutToastLabelAuto: {
id: 'app.layout.modal.layoutToastLabelAuto',
description: 'Layout toast label',
},
});
const WebcamComponent = ({
cameraDock,
swapLayout,
focusedId,
2021-08-05 19:03:24 +08:00
layoutContextDispatch,
fullscreen,
isPresenter,
displayPresentation,
2021-08-07 01:23:46 +08:00
cameraOptimalGridSize: cameraSize,
isRTL,
2023-05-12 04:20:26 +08:00
isGridEnabled,
}) => {
const [isResizing, setIsResizing] = useState(false);
const [isDragging, setIsDragging] = useState(false);
const [isFullscreen, setIsFullScreen] = useState(false);
const [resizeStart, setResizeStart] = useState({ width: 0, height: 0 });
const [cameraMaxWidth, setCameraMaxWidth] = useState(0);
const [draggedAtLeastOneTime, setDraggedAtLeastOneTime] = useState(false);
2021-07-14 00:52:20 +08:00
const lastSize = Storage.getItem('webcamSize') || { width: 0, height: 0 };
const { width: lastWidth, height: lastHeight } = lastSize;
const isCameraTopOrBottom = cameraDock.position === CAMERADOCK_POSITION.CONTENT_TOP
|| cameraDock.position === CAMERADOCK_POSITION.CONTENT_BOTTOM;
const isCameraLeftOrRight = cameraDock.position === CAMERADOCK_POSITION.CONTENT_LEFT
|| cameraDock.position === CAMERADOCK_POSITION.CONTENT_RIGHT;
2021-08-07 01:23:46 +08:00
const isCameraSidebar = cameraDock.position === CAMERADOCK_POSITION.SIDEBAR_CONTENT_BOTTOM;
2021-07-14 00:52:20 +08:00
useEffect(() => {
const handleVisibility = () => {
if (document.hidden) {
document.dispatchEvent(new MouseEvent('mouseup', { bubbles: true }));
}
};
document.addEventListener('visibilitychange', handleVisibility);
return () => {
document.removeEventListener('visibilitychange', handleVisibility);
};
}, []);
useEffect(() => {
setIsFullScreen(fullscreen.group === 'webcams');
}, [fullscreen]);
useEffect(() => {
2021-08-07 01:23:46 +08:00
const newCameraMaxWidth = (isPresenter && cameraDock.presenterMaxWidth) ? cameraDock.presenterMaxWidth : cameraDock.maxWidth;
setCameraMaxWidth(newCameraMaxWidth);
if (isCameraLeftOrRight && cameraDock.width > newCameraMaxWidth) {
layoutContextDispatch(
{
type: ACTIONS.SET_CAMERA_DOCK_SIZE,
value: {
width: newCameraMaxWidth,
height: cameraDock.height,
browserWidth: window.innerWidth,
browserHeight: window.innerHeight,
},
},
);
Storage.setItem('webcamSize', { width: newCameraMaxWidth, height: lastHeight });
}
const cams = document.getElementById('cameraDock');
cams?.setAttribute("data-position", cameraDock.position);
}, [cameraDock.position, cameraDock.maxWidth, isPresenter, displayPresentation]);
const handleVideoFocus = (id) => {
layoutContextDispatch({
type: ACTIONS.SET_FOCUSED_CAMERA_ID,
value: focusedId !== id ? id : false,
});
}
const onResizeHandle = (deltaWidth, deltaHeight) => {
if (cameraDock.resizableEdge.top || cameraDock.resizableEdge.bottom) {
2021-08-05 19:03:24 +08:00
layoutContextDispatch(
{
type: ACTIONS.SET_CAMERA_DOCK_SIZE,
value: {
width: cameraDock.width,
height: resizeStart.height + deltaHeight,
browserWidth: window.innerWidth,
browserHeight: window.innerHeight,
},
},
);
}
if (cameraDock.resizableEdge.left || cameraDock.resizableEdge.right) {
2021-08-05 19:03:24 +08:00
layoutContextDispatch(
{
type: ACTIONS.SET_CAMERA_DOCK_SIZE,
value: {
width: resizeStart.width + deltaWidth,
height: cameraDock.height,
browserWidth: window.innerWidth,
browserHeight: window.innerHeight,
},
},
);
}
};
const handleWebcamDragStart = () => {
setIsDragging(true);
document.body.style.overflow = 'hidden';
2021-08-05 19:03:24 +08:00
layoutContextDispatch({
type: ACTIONS.SET_CAMERA_DOCK_IS_DRAGGING,
value: true,
});
};
const handleWebcamDragStop = (e) => {
setIsDragging(false);
setDraggedAtLeastOneTime(false);
document.body.style.overflow = 'auto';
if (Object.values(CAMERADOCK_POSITION).includes(e.target.id) && draggedAtLeastOneTime) {
2022-09-27 04:15:48 +08:00
const layout = document.getElementById('layout');
layout?.setAttribute("data-cam-position", e?.target?.id);
2021-08-05 19:03:24 +08:00
layoutContextDispatch({
type: ACTIONS.SET_CAMERA_DOCK_POSITION,
value: e.target.id,
});
}
2021-08-05 19:03:24 +08:00
layoutContextDispatch({
type: ACTIONS.SET_CAMERA_DOCK_IS_DRAGGING,
value: false,
});
};
2021-08-07 01:23:46 +08:00
let draggableOffset = {
left: isDragging && (isCameraTopOrBottom || isCameraSidebar)
? ((cameraDock.width - cameraSize.width) / 2)
: 0,
top: isDragging && isCameraLeftOrRight
? ((cameraDock.height - cameraSize.height) / 2)
: 0,
};
if (isRTL) {
draggableOffset.left = draggableOffset.left * -1;
}
2023-04-26 22:28:59 +08:00
const isIphone = !!(navigator.userAgent.match(/iPhone/i));
2021-08-07 01:23:46 +08:00
2023-04-26 22:28:59 +08:00
const mobileWidth = `${isDragging ? cameraSize.width : cameraDock.width}pt`;
const mobileHeight = `${isDragging ? cameraSize.height : cameraDock.height}pt`;
const isDesktopWidth = isDragging ? cameraSize.width : cameraDock.width;
const isDesktopHeight = isDragging ? cameraSize.height : cameraDock.height;
const camOpacity = isDragging ? 0.5 : undefined;
return (
<>
{isDragging ? <DropAreaContainer /> : null}
2021-11-03 19:51:56 +08:00
<Styled.ResizableWrapper
horizontal={cameraDock.position === CAMERADOCK_POSITION.CONTENT_TOP
|| cameraDock.position === CAMERADOCK_POSITION.CONTENT_BOTTOM}
vertical={cameraDock.position === CAMERADOCK_POSITION.CONTENT_LEFT
|| cameraDock.position === CAMERADOCK_POSITION.CONTENT_RIGHT}
>
2021-11-03 19:51:56 +08:00
<Draggable
handle="video"
bounds="html"
onStart={handleWebcamDragStart}
onDrag={() => {
if (!draggedAtLeastOneTime) {
setDraggedAtLeastOneTime(true);
}
}}
2021-11-03 19:51:56 +08:00
onStop={handleWebcamDragStop}
onMouseDown={
cameraDock.isDraggable ? (e) => e.preventDefault() : undefined
}
disabled={!cameraDock.isDraggable || isResizing || isFullscreen}
position={
{
x: cameraDock.left - cameraDock.right + draggableOffset.left,
y: cameraDock.top + draggableOffset.top,
2021-07-14 00:52:20 +08:00
}
2021-11-03 19:51:56 +08:00
}
>
2021-11-03 19:51:56 +08:00
<Resizable
minWidth={isDragging ? cameraSize.width : cameraDock.minWidth}
minHeight={isDragging ? cameraSize.height : cameraDock.minHeight}
maxWidth={isDragging ? cameraSize.width : cameraMaxWidth}
maxHeight={isDragging ? cameraSize.height : cameraDock.maxHeight}
2021-11-03 19:51:56 +08:00
size={{
2021-08-07 01:23:46 +08:00
width: isDragging ? cameraSize.width : cameraDock.width,
height: isDragging ? cameraSize.height : cameraDock.height,
2021-11-03 19:51:56 +08:00
}}
onResizeStart={() => {
setIsResizing(true);
setResizeStart({ width: cameraDock.width, height: cameraDock.height });
onResizeHandle(cameraDock.width, cameraDock.height);
2021-11-03 19:51:56 +08:00
layoutContextDispatch({
type: ACTIONS.SET_CAMERA_DOCK_IS_RESIZING,
value: true,
});
}}
onResize={(e, direction, ref, d) => {
onResizeHandle(d.width, d.height);
}}
onResizeStop={() => {
setResizeStart({ width: 0, height: 0 });
setTimeout(() => setIsResizing(false), 500);
layoutContextDispatch({
type: ACTIONS.SET_CAMERA_DOCK_IS_RESIZING,
value: false,
});
}}
enable={{
top: !isFullscreen && !isDragging && !swapLayout && cameraDock.resizableEdge.top,
bottom: !isFullscreen && !isDragging && !swapLayout
&& cameraDock.resizableEdge.bottom,
2021-11-03 19:51:56 +08:00
left: !isFullscreen && !isDragging && !swapLayout && cameraDock.resizableEdge.left,
right: !isFullscreen && !isDragging && !swapLayout && cameraDock.resizableEdge.right,
topLeft: false,
topRight: false,
bottomLeft: false,
bottomRight: false,
}}
style={{
position: 'absolute',
zIndex: isCameraSidebar && !isDragging ? 0 : cameraDock.zIndex,
}}
>
2021-11-03 19:51:56 +08:00
<Styled.Draggable
isDraggable={cameraDock.isDraggable && !isFullscreen && !isDragging}
isDragging={isDragging}
id="cameraDock"
role="region"
2021-11-03 19:51:56 +08:00
draggable={cameraDock.isDraggable && !isFullscreen ? 'true' : undefined}
style={{
2023-04-26 22:28:59 +08:00
width: isIphone ? mobileWidth : isDesktopWidth,
height: isIphone ? mobileHeight : isDesktopHeight,
opacity: camOpacity,
background: null,
}}
2021-11-03 19:51:56 +08:00
>
<VideoProviderContainer
{...{
swapLayout,
cameraDock,
focusedId,
handleVideoFocus,
2023-05-12 04:20:26 +08:00
isGridEnabled,
2021-11-03 19:51:56 +08:00
}}
/>
</Styled.Draggable>
</Resizable>
</Draggable>
</Styled.ResizableWrapper>
</>
);
};
2023-04-24 05:03:38 +08:00
export default WebcamComponent;