Merge pull request #18452 from KDSBrowne/bbb-18232
fix: Correct Slide Positioning After Zoom and Sync During Presentation Change
This commit is contained in:
commit
588bf5c2b9
@ -249,6 +249,7 @@ class ActionsDropdown extends PureComponent {
|
||||
presentations,
|
||||
setPresentation,
|
||||
podIds,
|
||||
setPresentationFitToWidth,
|
||||
} = this.props;
|
||||
|
||||
if (!podIds || podIds.length < 1) return [];
|
||||
@ -272,6 +273,7 @@ class ActionsDropdown extends PureComponent {
|
||||
description: "uploaded presentation file",
|
||||
key: `uploaded-presentation-${p.id}`,
|
||||
onClick: () => {
|
||||
setPresentationFitToWidth(false);
|
||||
setPresentation(p.id, podId);
|
||||
},
|
||||
}
|
||||
|
@ -39,6 +39,7 @@ class ActionsBar extends PureComponent {
|
||||
setMeetingLayout,
|
||||
showPushLayout,
|
||||
setPushLayout,
|
||||
setPresentationFitToWidth,
|
||||
} = this.props;
|
||||
|
||||
const shouldShowOptionsButton = (isPresentationEnabled() && isThereCurrentPresentation)
|
||||
@ -67,6 +68,7 @@ class ActionsBar extends PureComponent {
|
||||
setPushLayout,
|
||||
presentationIsOpen,
|
||||
showPushLayout,
|
||||
setPresentationFitToWidth,
|
||||
}}
|
||||
/>
|
||||
{isCaptionsAvailable
|
||||
|
@ -131,8 +131,10 @@ class App extends Component {
|
||||
super(props);
|
||||
this.state = {
|
||||
enableResize: !window.matchMedia(MOBILE_MEDIA).matches,
|
||||
presentationFitToWidth: false,
|
||||
};
|
||||
|
||||
this.setPresentationFitToWidth = this.setPresentationFitToWidth.bind(this);
|
||||
this.handleWindowResize = throttle(this.handleWindowResize).bind(this);
|
||||
this.shouldAriaHide = this.shouldAriaHide.bind(this);
|
||||
|
||||
@ -283,6 +285,10 @@ class App extends Component {
|
||||
ConnectionStatusService.stopRoundTripTime();
|
||||
}
|
||||
|
||||
setPresentationFitToWidth(presentationFitToWidth) {
|
||||
this.setState({ presentationFitToWidth });
|
||||
}
|
||||
|
||||
handleWindowResize() {
|
||||
const { enableResize } = this.state;
|
||||
const shouldEnableResize = !window.matchMedia(MOBILE_MEDIA).matches;
|
||||
@ -403,6 +409,7 @@ class App extends Component {
|
||||
setMeetingLayout={setMeetingLayout}
|
||||
showPushLayout={showPushLayoutButton && selectedLayout === 'custom'}
|
||||
presentationIsOpen={presentationIsOpen}
|
||||
setPresentationFitToWidth={this.setPresentationFitToWidth}
|
||||
/>
|
||||
</Styled.ActionsBar>
|
||||
);
|
||||
@ -517,6 +524,8 @@ class App extends Component {
|
||||
darkTheme,
|
||||
} = this.props;
|
||||
|
||||
const { presentationFitToWidth } = this.state;
|
||||
|
||||
return (
|
||||
<>
|
||||
<Notifications />
|
||||
@ -540,7 +549,7 @@ class App extends Component {
|
||||
<NavBarContainer main="new" />
|
||||
<NewWebcamContainer isLayoutSwapped={!presentationIsOpen} />
|
||||
<Styled.TextMeasure id="text-measure" />
|
||||
{shouldShowPresentation ? <PresentationAreaContainer darkTheme={darkTheme} presentationIsOpen={presentationIsOpen} /> : null}
|
||||
{shouldShowPresentation ? <PresentationAreaContainer setPresentationFitToWidth={this.setPresentationFitToWidth} fitToWidth={presentationFitToWidth} darkTheme={darkTheme} presentationIsOpen={presentationIsOpen} /> : null}
|
||||
{shouldShowScreenshare ? <ScreenshareContainer isLayoutSwapped={!presentationIsOpen} /> : null}
|
||||
{
|
||||
shouldShowExternalVideo
|
||||
|
@ -74,7 +74,6 @@ class Presentation extends PureComponent {
|
||||
presentationWidth: 0,
|
||||
presentationHeight: 0,
|
||||
zoom: 100,
|
||||
fitToWidth: false,
|
||||
isFullscreen: false,
|
||||
tldrawAPI: null,
|
||||
isPanning: false,
|
||||
@ -86,7 +85,6 @@ class Presentation extends PureComponent {
|
||||
this.currentPresentationToastId = null;
|
||||
|
||||
this.getSvgRef = this.getSvgRef.bind(this);
|
||||
this.setFitToWidth = this.setFitToWidth.bind(this);
|
||||
this.zoomChanger = debounce({ delay: 200 }, this.zoomChanger.bind(this));
|
||||
this.updateLocalPosition = this.updateLocalPosition.bind(this);
|
||||
this.panAndZoomChanger = this.panAndZoomChanger.bind(this);
|
||||
@ -207,13 +205,13 @@ class Presentation extends PureComponent {
|
||||
multiUser,
|
||||
numPages,
|
||||
currentPresentationId,
|
||||
fitToWidth,
|
||||
} = this.props;
|
||||
const {
|
||||
presentationWidth,
|
||||
presentationHeight,
|
||||
zoom,
|
||||
isPanning,
|
||||
fitToWidth,
|
||||
presentationId,
|
||||
hadPresentation,
|
||||
} = this.state;
|
||||
@ -505,19 +503,14 @@ class Presentation extends PureComponent {
|
||||
}
|
||||
}
|
||||
|
||||
setFitToWidth(fitToWidth) {
|
||||
this.setState({ fitToWidth });
|
||||
}
|
||||
|
||||
zoomChanger(zoom) {
|
||||
this.setState({ zoom });
|
||||
}
|
||||
|
||||
fitToWidthHandler() {
|
||||
const { fitToWidth } = this.state;
|
||||
|
||||
const { setPresentationFitToWidth, fitToWidth } = this.props;
|
||||
setPresentationFitToWidth(!fitToWidth)
|
||||
this.setState({
|
||||
fitToWidth: !fitToWidth,
|
||||
zoom: HUNDRED_PERCENT,
|
||||
});
|
||||
}
|
||||
@ -535,9 +528,9 @@ class Presentation extends PureComponent {
|
||||
}
|
||||
|
||||
calculateSize(viewBoxDimensions) {
|
||||
const { presentationHeight, presentationWidth, fitToWidth } = this.state;
|
||||
const { presentationHeight, presentationWidth } = this.state;
|
||||
|
||||
const { userIsPresenter, currentSlide, slidePosition } = this.props;
|
||||
const { userIsPresenter, currentSlide, slidePosition, fitToWidth } = this.props;
|
||||
|
||||
if (!currentSlide || !slidePosition) {
|
||||
return { width: 0, height: 0 };
|
||||
@ -605,8 +598,9 @@ class Presentation extends PureComponent {
|
||||
removeWhiteboardGlobalAccess,
|
||||
multiUserSize,
|
||||
multiUser,
|
||||
fitToWidth,
|
||||
} = this.props;
|
||||
const { zoom, fitToWidth, isPanning } = this.state;
|
||||
const { zoom, isPanning } = this.state;
|
||||
|
||||
if (!currentSlide) return null;
|
||||
|
||||
@ -733,12 +727,12 @@ class Presentation extends PureComponent {
|
||||
layoutContextDispatch,
|
||||
presentationIsOpen,
|
||||
darkTheme,
|
||||
fitToWidth,
|
||||
} = this.props;
|
||||
|
||||
const {
|
||||
isFullscreen,
|
||||
localPosition,
|
||||
fitToWidth,
|
||||
zoom,
|
||||
tldrawIsMounting,
|
||||
isPanning,
|
||||
|
@ -7,13 +7,15 @@ const PresentationArea = ({
|
||||
height,
|
||||
presentationIsOpen,
|
||||
darkTheme,
|
||||
setPresentationFitToWidth,
|
||||
fitToWidth,
|
||||
}) => {
|
||||
const presentationAreaSize = {
|
||||
presentationAreaWidth: width,
|
||||
presentationAreaHeight: height,
|
||||
};
|
||||
return (
|
||||
<PresentationPodsContainer {...{ presentationAreaSize, presentationIsOpen, darkTheme }} />
|
||||
<PresentationPodsContainer {...{ presentationAreaSize, presentationIsOpen, darkTheme, setPresentationFitToWidth, fitToWidth }} />
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -3,10 +3,10 @@ import PropTypes from 'prop-types';
|
||||
import { layoutSelectOutput } from '../../layout/context';
|
||||
import PresentationArea from './component';
|
||||
|
||||
const PresentationAreaContainer = ({ presentationIsOpen, darkTheme }) => {
|
||||
const PresentationAreaContainer = ({ presentationIsOpen, darkTheme, setPresentationFitToWidth, fitToWidth }) => {
|
||||
const presentation = layoutSelectOutput((i) => i.presentation);
|
||||
|
||||
return <PresentationArea {...{ ...presentation, presentationIsOpen, darkTheme }} />;
|
||||
return <PresentationArea {...{ ...presentation, presentationIsOpen, darkTheme, setPresentationFitToWidth, fitToWidth }} />;
|
||||
};
|
||||
|
||||
export default PresentationAreaContainer;
|
||||
|
@ -104,7 +104,6 @@ export default function Whiteboard(props) {
|
||||
const language = mapLanguage(Settings?.application?.locale?.toLowerCase() || 'en');
|
||||
const [currentTool, setCurrentTool] = React.useState(null);
|
||||
const [currentStyle, setCurrentStyle] = React.useState({});
|
||||
const [currentCameraPoint, setCurrentCameraPoint] = React.useState({});
|
||||
const [isMoving, setIsMoving] = React.useState(false);
|
||||
const [isPanning, setIsPanning] = React.useState(shortcutPanning);
|
||||
const [panSelected, setPanSelected] = React.useState(isPanning);
|
||||
@ -472,16 +471,12 @@ export default function Whiteboard(props) {
|
||||
}
|
||||
}, [tldrawAPI?.getPageState()?.camera, presentationWidth, presentationHeight]);
|
||||
|
||||
// change tldraw page when presentation page changes
|
||||
React.useEffect(() => {
|
||||
if (tldrawAPI && curPageId && slidePosition) {
|
||||
tldrawAPI.changePage(curPageId);
|
||||
const newZoom = prevSlidePosition
|
||||
? calculateZoom(prevSlidePosition.viewBoxWidth, prevSlidePosition.viewBoxHeight)
|
||||
: calculateZoom(slidePosition.viewBoxWidth, slidePosition.viewBoxHeight);
|
||||
tldrawAPI?.setCamera([slidePosition.x, slidePosition.y], newZoom, 'zoomed_previous_page');
|
||||
if (isPresenter && slidePosition) {
|
||||
const currentZoom = calculateZoom(slidePosition?.viewBoxWidth, slidePosition?.viewBoxHeight);
|
||||
tldrawAPI?.setCamera([slidePosition?.x, slidePosition?.y], currentZoom);
|
||||
}
|
||||
}, [curPageId]);
|
||||
}, [slidePosition?.viewBoxWidth, slidePosition?.viewBoxHeight]);
|
||||
|
||||
// change tldraw camera when slidePosition changes
|
||||
React.useEffect(() => {
|
||||
@ -812,10 +807,6 @@ export default function Whiteboard(props) {
|
||||
|
||||
if (reason && isPresenter && slidePosition && (reason.includes('zoomed') || reason.includes('panned'))) {
|
||||
const camera = tldrawAPI?.getPageState()?.camera;
|
||||
const isForcePanning = tldrawAPI?.isForcePanning;
|
||||
if (currentCameraPoint[curPageId] && !isPanning && !isForcePanning) {
|
||||
camera.point = currentCameraPoint[curPageId];
|
||||
}
|
||||
|
||||
// limit bounds
|
||||
if (tldrawAPI?.viewport.maxX > slidePosition.width) {
|
||||
@ -831,6 +822,11 @@ export default function Whiteboard(props) {
|
||||
camera.point[1] = 0;
|
||||
}
|
||||
|
||||
if (camera.point[0] === 0 && camera.point[1] === 0) {
|
||||
const newZoom = calculateZoom(slidePosition.viewBoxWidth, slidePosition.viewBoxHeight);
|
||||
e?.setCamera([slidePosition.x, slidePosition.y], newZoom);
|
||||
}
|
||||
|
||||
const zoomFitSlide = calculateZoom(slidePosition.width, slidePosition.height);
|
||||
if (camera.zoom < zoomFitSlide) {
|
||||
camera.zoom = zoomFitSlide;
|
||||
@ -854,20 +850,13 @@ export default function Whiteboard(props) {
|
||||
viewedRegionH = HUNDRED_PERCENT;
|
||||
}
|
||||
|
||||
if (e?.currentPageId == curPageId) {
|
||||
setCurrentCameraPoint({
|
||||
...currentCameraPoint,
|
||||
[e?.currentPageId]: camera?.point,
|
||||
})
|
||||
}
|
||||
|
||||
zoomSlide(
|
||||
parseInt(curPageId, 10),
|
||||
podId,
|
||||
viewedRegionW,
|
||||
viewedRegionH,
|
||||
currentCameraPoint[curPageId] ? currentCameraPoint[curPageId][0] : camera.point[0],
|
||||
currentCameraPoint[curPageId] ? currentCameraPoint[curPageId][1] : camera.point[1],
|
||||
camera.point[0],
|
||||
camera.point[1],
|
||||
);
|
||||
}
|
||||
// don't allow non-presenters to pan&zoom
|
||||
@ -1006,16 +995,6 @@ export default function Whiteboard(props) {
|
||||
setCurrentStyle({ ...currentStyle, ...command?.after?.appState?.currentStyle });
|
||||
}
|
||||
|
||||
if (command && command?.id?.includes('change_page')) {
|
||||
const camera = tldrawAPI?.getPageState()?.camera;
|
||||
if (currentCameraPoint[app?.currentPageId] && camera) {
|
||||
tldrawAPI?.setCamera(
|
||||
[currentCameraPoint[app?.currentPageId][0], currentCameraPoint[app?.currentPageId][1]],
|
||||
camera?.zoom
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const changedShapes = command.after?.document?.pages[app.currentPageId]?.shapes;
|
||||
if (!isMounting && app.currentPageId !== curPageId) {
|
||||
// can happen then the "move to page action" is called, or using undo after changing a page
|
||||
|
@ -52,11 +52,7 @@ test.describe.parallel('Presentation', () => {
|
||||
await presentation.hidePresentationToolbar();
|
||||
});
|
||||
|
||||
/**
|
||||
* temporally skipped because it's currently failing the screenshot comparisons
|
||||
* due to https://github.com/bigbluebutton/bigbluebutton/issues/18232
|
||||
*/
|
||||
test.skip('Zoom In, Zoom Out, Reset Zoom @ci', async ({ browser, context, page }) => {
|
||||
test('Zoom In, Zoom Out, Reset Zoom @ci', async ({ browser, context, page }) => {
|
||||
const presentation = new Presentation(browser, context);
|
||||
await presentation.initPages(page);
|
||||
await presentation.zoom();
|
||||
|
Loading…
Reference in New Issue
Block a user