From 177c86b6aba8730e890c388c0c1e83617f501373 Mon Sep 17 00:00:00 2001 From: Johnwz123 <112536096+Johnwz123@users.noreply.github.com> Date: Wed, 20 Mar 2024 01:19:55 +0800 Subject: [PATCH 1/4] Add a fullscreen button for the game div container --- src/pages/academy/game/Game.tsx | 76 ++++++++++++++++++++++++++++++++- src/styles/_game.scss | 6 +++ 2 files changed, 81 insertions(+), 1 deletion(-) diff --git a/src/pages/academy/game/Game.tsx b/src/pages/academy/game/Game.tsx index 65adf5495f..03cd633393 100644 --- a/src/pages/academy/game/Game.tsx +++ b/src/pages/academy/game/Game.tsx @@ -1,3 +1,4 @@ +import { Icon } from '@blueprintjs/core'; import React from 'react'; import { useDispatch } from 'react-redux'; import { useTypedSelector } from 'src/commons/utils/Hooks'; @@ -50,9 +51,82 @@ function Game() { } }, [session, achievements, goals]); + // Logic for the fullscreen button to toggle fullscreen. + // Entering fullscreen will also lock the screen orientation to landscape. + const [isFullScreen, setIsFullScreen] = React.useState(false); + const toggleFullScreen = () => { + const elem = document.getElementById('game-display') as HTMLElement; + + if (!isFullScreen) { + if (elem.requestFullscreen) { + elem.requestFullscreen().then(() => { + if (window.screen.orientation) { + window.screen.orientation.lock('landscape'); + } + }); + } + } else { + if (document.exitFullscreen) { + document.exitFullscreen().then(() => { + if (window.screen.orientation) { + window.screen.orientation.unlock(); + } + }); + } + } + setIsFullScreen(!isFullScreen); + }; + + // Logic for the fullscreen button to dynamically adjust its size, position and padding + // based on the size of the game display. + const [iconSize, setIconSize] = React.useState(0); + const [iconLeft, setIconLeft] = React.useState('0px'); + const [iconPadding, setIconPadding] = React.useState('0px'); + const gameDisplayRef = React.useRef(null); + + React.useEffect(() => { + const handleResize = () => { + if (gameDisplayRef.current) { + const aspectRatio = 16 / 9; + const height = gameDisplayRef.current.offsetHeight; + const width = gameDisplayRef.current.offsetWidth; + const size = height / 40; + const padding = height / 50; + const leftOffset = + isFullScreen || height * aspectRatio > width ? 0 : (width - height * aspectRatio) / 2; + setIconSize(size); + setIconPadding(`${padding}px`); + setIconLeft(`${leftOffset}px`); + } + }; + + // When exiting fullscreen, the browser might not have completed the transition + // at the time handleResize is called, so the height of gameDisplayRef.current + // is still the fullscreen height. + // To fix this, we delay handleResize by 100ms. + const delayedHandleResize = () => { + setTimeout(handleResize, 100); + }; + + window.addEventListener('resize', delayedHandleResize); + delayedHandleResize(); + + return () => window.removeEventListener('resize', delayedHandleResize); + }, [isFullScreen]); + return ( <> -
+
+ +
{isTestStudent && (