diff --git a/public/locales/de/translation.json b/public/locales/de/translation.json index 7a26f352..24559d4e 100644 --- a/public/locales/de/translation.json +++ b/public/locales/de/translation.json @@ -163,7 +163,9 @@ }, "presentBar": { "disableEditing": "Bearbeitung sperren", + "disableFullscreen": "Vollbildmodus verlassen", "enableEditing": "Bearbeitung freigeben", + "enableFullscreen": "Vollbildmodus betreten", "isPresenting": "präsentiert", "isPresentingUser": "{{displayName}} präsentiert", "startPresentation": "Präsentation starten", diff --git a/public/locales/en/translation.json b/public/locales/en/translation.json index 22263059..553522c5 100644 --- a/public/locales/en/translation.json +++ b/public/locales/en/translation.json @@ -163,7 +163,9 @@ }, "presentBar": { "disableEditing": "Disable editing", + "disableFullscreen": "Disable fullscreen", "enableEditing": "Enable editing", + "enableFullscreen": "Enable fullscreen", "isPresenting": "is presenting", "isPresentingUser": "{{displayName}} is presenting", "startPresentation": "Start presentation", diff --git a/src/components/Layout/useLayoutState.tsx b/src/components/Layout/useLayoutState.tsx index ad7d6f1c..28ce7be9 100644 --- a/src/components/Layout/useLayoutState.tsx +++ b/src/components/Layout/useLayoutState.tsx @@ -18,7 +18,9 @@ import { grey } from '@mui/material/colors'; import { createContext, PropsWithChildren, + useCallback, useContext, + useEffect, useMemo, useState, } from 'react'; @@ -39,12 +41,14 @@ type LayoutState = { isShowGrid: boolean; activeTool: ActiveTool; activeColor: string; + isFullscreen: boolean; setSlideOverviewVisible: (value: boolean) => void; setDeveloperToolsVisible: (value: boolean) => void; setShowCollaboratorsCursors: (value: boolean) => void; setShowGrid: (value: boolean) => void; setActiveTool: (tool: ActiveTool) => void; setActiveColor: (color: string) => void; + setFullscreen: (value: boolean) => void; }; const LayoutStateContext = createContext(undefined); @@ -59,6 +63,27 @@ export function LayoutStateProvider({ children }: PropsWithChildren<{}>) { const [isShowGrid, setShowGrid] = useState(true); const [activeTool, setActiveTool] = useState('select'); const [activeColor, setActiveColor] = useState(grey[500]); + const [isFullscreen, setFullscreenRaw] = useState(false); + + const setFullscreen = useCallback((value: boolean) => { + if (value && !document.fullscreenElement) { + document.documentElement.requestFullscreen(); + } else if (!value && document.fullscreenElement) { + document.exitFullscreen(); + } + }, []); + + useEffect(() => { + function listener(e: unknown) { + setFullscreenRaw(document.fullscreenElement !== null); + } + + document.addEventListener('fullscreenchange', listener); + + return () => { + document.removeEventListener('fullscreenchange', listener); + }; + }, [isFullscreen]); const value = useMemo( () => ({ @@ -68,20 +93,24 @@ export function LayoutStateProvider({ children }: PropsWithChildren<{}>) { isShowGrid, activeTool, activeColor, + isFullscreen, setSlideOverviewVisible, setDeveloperToolsVisible, setShowCollaboratorsCursors, setShowGrid, setActiveTool, setActiveColor, + setFullscreen, }), [ activeColor, activeTool, isDeveloperToolsVisible, + isFullscreen, isShowCollaboratorsCursors, isShowGrid, isSlideOverviewVisible, + setFullscreen, ] ); diff --git a/src/components/PresentBar/PresentBar.test.tsx b/src/components/PresentBar/PresentBar.test.tsx index ef7dc9a0..607a2527 100644 --- a/src/components/PresentBar/PresentBar.test.tsx +++ b/src/components/PresentBar/PresentBar.test.tsx @@ -25,6 +25,7 @@ import { } from '../../lib/testUtils/documentTestUtils'; import { mockRoomMember } from '../../lib/testUtils/matrixTestUtils'; import { WhiteboardInstance, WhiteboardManager } from '../../state'; +import { LayoutStateProvider } from '../Layout'; import { PresentBar } from './PresentBar'; let widgetApi: MockedWidgetApi; @@ -58,7 +59,7 @@ describe('', () => { whiteboardManager={whiteboardManager} widgetApi={widgetApi} > - {children} + {children} ); }); diff --git a/src/components/PresentBar/PresentBar.tsx b/src/components/PresentBar/PresentBar.tsx index 84f5f190..06f63679 100644 --- a/src/components/PresentBar/PresentBar.tsx +++ b/src/components/PresentBar/PresentBar.tsx @@ -16,6 +16,8 @@ import ArrowBackIosNewIcon from '@mui/icons-material/ArrowBackIosNew'; import ArrowForwardIosIcon from '@mui/icons-material/ArrowForwardIos'; +import FullscreenIcon from '@mui/icons-material/Fullscreen'; +import FullscreenExitIcon from '@mui/icons-material/FullscreenExit'; import LockOpenIcon from '@mui/icons-material/LockOpen'; import PresentToAllIcon from '@mui/icons-material/PresentToAll'; import { Box } from '@mui/material'; @@ -34,6 +36,7 @@ import { ToolbarButton, ToolbarToggle, } from '../common/Toolbar'; +import { useLayoutState } from '../Layout'; export function PresentBar() { const { t } = useTranslation(); @@ -41,6 +44,7 @@ export function PresentBar() { const { activeSlideId, isFirstSlideActive, isLastSlideActive } = useActiveSlide(); const { state, toggleEditMode, togglePresentation } = usePresentationMode(); + const { isFullscreen, setFullscreen } = useLayoutState(); const handleToNextSlideClick = useCallback(() => { if (activeSlideId) { @@ -58,6 +62,10 @@ export function PresentBar() { } }, [activeSlideId, whiteboardInstance]); + const toggleFullscreen = useCallback(() => { + setFullscreen(!isFullscreen); + }, [isFullscreen, setFullscreen]); + const isPresenting = state.type === 'presenting'; const isPresentingInEditMode = isPresenting && state.isEditMode; @@ -77,12 +85,24 @@ export function PresentBar() { ? t('presentBar.disableEditing', 'Disable editing') : t('presentBar.enableEditing', 'Enable editing'); + const fullScreenButtonTitle = isFullscreen + ? t('presentBar.disableFullscreen', 'Disable fullscreen') + : t('presentBar.enableFullscreen', 'Enable fullscreen'); + return ( + } + placement="bottom" + checkedIcon={} + /> {state.type !== 'presentation' && (