diff --git a/packages/webgal/src/UI/Menu/Options/Display/Display.tsx b/packages/webgal/src/UI/Menu/Options/Display/Display.tsx index 41931d59f..b7bc13045 100644 --- a/packages/webgal/src/UI/Menu/Options/Display/Display.tsx +++ b/packages/webgal/src/UI/Menu/Options/Display/Display.tsx @@ -19,14 +19,14 @@ export function Display() {
{ - dispatch(setOptionData({ key: 'fullScreen', value: fullScreenOption.yes })); + dispatch(setOptionData({ key: 'fullScreen', value: fullScreenOption.on })); setStorage(); }, () => { - dispatch(setOptionData({ key: 'fullScreen', value: fullScreenOption.no })); + dispatch(setOptionData({ key: 'fullScreen', value: fullScreenOption.off })); setStorage(); }, ]} diff --git a/packages/webgal/src/UI/Title/Title.tsx b/packages/webgal/src/UI/Title/Title.tsx index 3365375a1..0bed4af1a 100644 --- a/packages/webgal/src/UI/Title/Title.tsx +++ b/packages/webgal/src/UI/Title/Title.tsx @@ -41,7 +41,7 @@ const Title: FC = () => { onClick={() => { playBgm(GUIState.titleBgm); dispatch(setVisibility({ component: 'isEnterGame', visibility: true })); - if (fullScreen === fullScreenOption.yes) document.documentElement.requestFullscreen(); + if (fullScreen === fullScreenOption.on) document.documentElement.requestFullscreen(); }} onMouseEnter={playSeEnter} /> diff --git a/packages/webgal/src/hooks/useFullScreen.ts b/packages/webgal/src/hooks/useFullScreen.ts index c8e1d5431..bc7f6b699 100644 --- a/packages/webgal/src/hooks/useFullScreen.ts +++ b/packages/webgal/src/hooks/useFullScreen.ts @@ -1,23 +1,27 @@ +import { setStorage } from '@/Core/controller/storage/storageController'; import { RootState } from '@/store/store'; import { fullScreenOption } from '@/store/userDataInterface'; +import { setOptionData } from '@/store/userDataReducer'; import { useEffect } from 'react'; -import { useSelector } from 'react-redux'; +import { useDispatch, useSelector } from 'react-redux'; export function useFullScreen() { const userDataState = useSelector((state: RootState) => state.userData); const GUIState = useSelector((state: RootState) => state.GUI); + const dispatch = useDispatch(); const fullScreen = userDataState.optionData.fullScreen; const isEnterGame = GUIState.isEnterGame; + let currentWindowHeight = window.innerHeight; useEffect(() => { switch (fullScreen) { - case fullScreenOption.yes: { + case fullScreenOption.on: { if (isEnterGame) { document.documentElement.requestFullscreen(); }; break; } - case fullScreenOption.no: { + case fullScreenOption.off: { if (document.fullscreenElement) { document.exitFullscreen(); }; @@ -25,4 +29,21 @@ export function useFullScreen() { } } }, [fullScreen]); + + /** + * 通过窗口高度变化判断是否退出全屏,并更改全屏状态 + */ + useEffect(() => { + const isExitingFullScreen = () => { + if (fullScreen === fullScreenOption.on && isEnterGame && currentWindowHeight >= window.innerHeight) { + dispatch(setOptionData({ key: 'fullScreen', value: fullScreenOption.off })); + setStorage(); + } + currentWindowHeight = window.innerHeight; + }; + window.addEventListener('resize', isExitingFullScreen); + return () => { + window.removeEventListener('resize', isExitingFullScreen); + }; + }, [fullScreen, currentWindowHeight]); }; diff --git a/packages/webgal/src/hooks/useHotkey.tsx b/packages/webgal/src/hooks/useHotkey.tsx index d97601dfd..d39d21eea 100644 --- a/packages/webgal/src/hooks/useHotkey.tsx +++ b/packages/webgal/src/hooks/useHotkey.tsx @@ -1,16 +1,19 @@ import { useGenSyncRef } from '@/hooks/useGenSyncRef'; import { RootState } from '@/store/store'; import { useMounted, useUnMounted, useUpdated } from '@/hooks/useLifeCycle'; -import { useCallback, useRef } from 'react'; +import { useCallback, useEffect, useRef } from 'react'; import { componentsVisibility, MenuPanelTag } from '@/store/guiInterface'; import { setVisibility } from '@/store/GUIReducer'; -import { useDispatch } from 'react-redux'; +import { useDispatch, useSelector } from 'react-redux'; import { startFast, stopAll, stopFast } from '@/Core/controller/gamePlay/fastSkip'; import { nextSentence } from '@/Core/controller/gamePlay/nextSentence'; import styles from '@/UI/Backlog/backlog.module.scss'; import throttle from 'lodash/throttle'; import { fastSaveGame } from '@/Core/controller/storage/fastSaveLoad'; import { WebGAL } from '@/Core/WebGAL'; +import { setOptionData } from '@/store/userDataReducer'; +import { setStorage } from '@/Core/controller/storage/storageController'; +import { fullScreenOption } from '@/store/userDataInterface'; // options备用 export interface HotKeyType { @@ -36,6 +39,7 @@ export function useHotkey(opt?: HotKeyType) { usePanic(); useFastSaveBeforeUnloadPage(); useSpaceAndEnter(); + useToggleFullScreen(); } /** @@ -364,3 +368,30 @@ function hasScrollToBottom(dom: Element) { const { scrollTop, clientHeight, scrollHeight } = dom; return scrollTop === 0; } + +/** + * F11 进入全屏 + */ +function useToggleFullScreen() { + const userDataState = useSelector((state: RootState) => state.userData); + const dispatch = useDispatch(); + const fullScreen = userDataState.optionData.fullScreen; + useEffect(() => { + const handleKeyDown = (e: KeyboardEvent) => { + if (e.code === 'F11') { + e.preventDefault(); + if (fullScreen !== fullScreenOption.on) { + dispatch(setOptionData({ key: 'fullScreen', value: fullScreenOption.on })); + setStorage(); + } else { + dispatch(setOptionData({ key: 'fullScreen', value: fullScreenOption.off })); + setStorage(); + } + } + }; + document.addEventListener('keydown', handleKeyDown); + return () => { + document.removeEventListener('keydown', handleKeyDown); + }; + }, [fullScreen]); +} diff --git a/packages/webgal/src/store/userDataInterface.ts b/packages/webgal/src/store/userDataInterface.ts index 374f2bf31..57f9a5f43 100644 --- a/packages/webgal/src/store/userDataInterface.ts +++ b/packages/webgal/src/store/userDataInterface.ts @@ -30,8 +30,8 @@ export enum voiceOption { } export enum fullScreenOption { - yes, - no, + on, + off, } /** diff --git a/packages/webgal/src/store/userDataReducer.ts b/packages/webgal/src/store/userDataReducer.ts index 755563932..a910dcc76 100644 --- a/packages/webgal/src/store/userDataReducer.ts +++ b/packages/webgal/src/store/userDataReducer.ts @@ -35,7 +35,7 @@ const initialOptionSet: IOptionData = { textboxOpacity: 75, language: language.zhCn, voiceInterruption: voiceOption.yes, - fullScreen: fullScreenOption.no, + fullScreen: fullScreenOption.off, }; // 初始化用户数据 diff --git a/packages/webgal/src/translations/en.ts b/packages/webgal/src/translations/en.ts index b72425e24..466a8e6df 100644 --- a/packages/webgal/src/translations/en.ts +++ b/packages/webgal/src/translations/en.ts @@ -64,10 +64,10 @@ const en = { title: 'Display', options: { fullScreen: { - title: 'Auto Full Screen', + title: 'Full Screen', options: { - yes: 'YES', - no: 'NO', + on: 'ON', + off: 'OFF', }, }, textSpeed: { diff --git a/packages/webgal/src/translations/zh-cn.ts b/packages/webgal/src/translations/zh-cn.ts index 3bbcac6ac..471b2a547 100644 --- a/packages/webgal/src/translations/zh-cn.ts +++ b/packages/webgal/src/translations/zh-cn.ts @@ -64,10 +64,10 @@ const zhCn = { title: '显示', options: { fullScreen: { - title: '自动全屏', + title: '全屏模式', options: { - yes: '是', - no: '否', + on: '开启', + off: '关闭', }, }, textSpeed: {