From 9d4a6df139455e297a4205eb97958563017614c2 Mon Sep 17 00:00:00 2001 From: ran Date: Tue, 23 Jan 2024 22:59:43 +0800 Subject: [PATCH] Remove MobileContext and use PreferencesContext instead --- client/src/app.tsx | 33 ++--------------- client/src/components/app_bar.tsx | 6 +-- client/src/components/infoview/context.ts | 12 +----- client/src/components/infoview/main.tsx | 4 +- client/src/components/level.tsx | 10 ++--- client/src/components/popup/preferences.tsx | 2 +- client/src/components/welcome.tsx | 6 +-- client/src/components/world_tree.tsx | 4 +- client/src/state/hooks/use_preferences.ts | 41 +++++++++++++++++++++ client/src/state/preferences.ts | 4 +- 10 files changed, 65 insertions(+), 57 deletions(-) create mode 100644 client/src/state/hooks/use_preferences.ts diff --git a/client/src/app.tsx b/client/src/app.tsx index 653286f..64e5004 100644 --- a/client/src/app.tsx +++ b/client/src/app.tsx @@ -8,49 +8,24 @@ import '@fontsource/roboto/700.css'; import './css/reset.css'; import './css/app.css'; -import { MobileContext, PreferencesContext} from './components/infoview/context'; -import { AUTO_SWITCH_THRESHOLD, getWindowDimensions, setLayout, setisSavePreferences, PreferencesState} from './state/preferences'; -import { useAppDispatch, useAppSelector } from './hooks'; +import { PreferencesContext} from './components/infoview/context'; +import UsePreferences from "./state/hooks/use_preferences" export const GameIdContext = React.createContext(undefined); function App() { - const dispatch = useAppDispatch() const params = useParams() const gameId = "g/" + params.owner + "/" + params.repo - // TODO: Modifying setMobile will not change 'layout', and the setMobile function may not exist in the future. - const [mobile, setMobile] = React.useState() - const layout = useAppSelector((state) => state.preferences.layout); - const changeLayout = (layout: PreferencesState["layout"]) => dispatch(setLayout(layout)) - const isSavePreferences = useAppSelector((state) => state.preferences.isSavePreferences); - const changeIsSavePreferences = (isSave: boolean) => dispatch(setisSavePreferences(isSave)) - - const automaticallyAdjustLayout = () => { - const {width} = getWindowDimensions() - setMobile(width < AUTO_SWITCH_THRESHOLD) - } - - React.useEffect(()=>{ - if (layout === "auto"){ - void automaticallyAdjustLayout() - window.addEventListener('resize', automaticallyAdjustLayout) - - return () => window.removeEventListener('resize', automaticallyAdjustLayout) - } else { - setMobile(layout === "mobile") - } - }, [layout]) + const {mobile, layout, isSavePreferences, setLayout, setIsSavePreferences} = UsePreferences() return (
- - + -
) diff --git a/client/src/components/app_bar.tsx b/client/src/components/app_bar.tsx index ced97d5..f8a171f 100644 --- a/client/src/components/app_bar.tsx +++ b/client/src/components/app_bar.tsx @@ -7,7 +7,7 @@ import { faDownload, faUpload, faEraser, faBook, faBookOpen, faGlobe, faHome, faArrowRight, faArrowLeft, faXmark, faBars, faCode, faCircleInfo, faTerminal, faMobileScreenButton, faDesktop, faGear } from '@fortawesome/free-solid-svg-icons' import { GameIdContext } from "../app" -import { InputModeContext, MobileContext, WorldLevelIdContext } from "./infoview/context" +import { InputModeContext, PreferencesContext, WorldLevelIdContext } from "./infoview/context" import { GameInfo, useGetGameInfoQuery } from '../state/api' import { changedOpenedIntro, selectCompleted, selectDifficulty, selectProgress } from '../state/progress' import { useAppDispatch, useAppSelector } from '../hooks' @@ -162,7 +162,7 @@ export function WelcomeAppBar({pageNumber, setPageNumber, gameInfo, toggleImpres }) { const gameId = React.useContext(GameIdContext) const gameProgress = useAppSelector(selectProgress(gameId)) - const {mobile, setMobile} = React.useContext(MobileContext) + const {mobile} = React.useContext(PreferencesContext) const [navOpen, setNavOpen] = React.useState(false) return
@@ -212,7 +212,7 @@ export function LevelAppBar({isLoading, levelTitle, toggleImpressum, pageNumber= }) { const gameId = React.useContext(GameIdContext) const {worldId, levelId} = React.useContext(WorldLevelIdContext) - const {mobile} = React.useContext(MobileContext) + const {mobile} = React.useContext(PreferencesContext) const [navOpen, setNavOpen] = React.useState(false) const gameInfo = useGetGameInfoQuery({game: gameId}) const completed = useAppSelector(selectCompleted(gameId, worldId, levelId)) diff --git a/client/src/components/infoview/context.ts b/client/src/components/infoview/context.ts index 948473b..e425749 100644 --- a/client/src/components/infoview/context.ts +++ b/client/src/components/infoview/context.ts @@ -64,27 +64,19 @@ export const ProofStateContext = React.createContext<{ }) export interface IPreferencesContext extends PreferencesState{ + mobile: boolean, // The variables that actually control the page 'layout' can only be changed through layout. setLayout: React.Dispatch>; setIsSavePreferences: React.Dispatch>; } export const PreferencesContext = React.createContext({ + mobile: false, layout: "auto", isSavePreferences: false, setLayout: () => {}, setIsSavePreferences: () => {} }) -export interface IMobileContext { - mobile : boolean, - setMobile: React.Dispatch>, -} - -export const MobileContext = React.createContext({ - mobile: false, - setMobile: () => {}, -}) - export const WorldLevelIdContext = React.createContext<{ worldId : string, levelId: number diff --git a/client/src/components/infoview/main.tsx b/client/src/components/infoview/main.tsx index c90eba8..956d2f6 100644 --- a/client/src/components/infoview/main.tsx +++ b/client/src/components/infoview/main.tsx @@ -27,7 +27,7 @@ import Markdown from '../markdown'; import { Infos } from './infos'; import { AllMessages, Errors, WithLspDiagnosticsContext } from './messages'; import { Goal } from './goals'; -import { DeletedChatContext, InputModeContext, MobileContext, MonacoEditorContext, ProofContext, ProofStep, SelectionContext, WorldLevelIdContext } from './context'; +import { DeletedChatContext, InputModeContext, PreferencesContext, MonacoEditorContext, ProofContext, ProofStep, SelectionContext, WorldLevelIdContext } from './context'; import { Typewriter, hasErrors, hasInteractiveErrors } from './typewriter'; import { InteractiveDiagnostic } from '@leanprover/infoview/*'; import { Button } from '../button'; @@ -349,7 +349,7 @@ export function TypewriterInterface({props}) { const [disableInput, setDisableInput] = React.useState(false) const [loadingProgress, setLoadingProgress] = React.useState(0) const { setDeletedChat, showHelp, setShowHelp } = React.useContext(DeletedChatContext) - const {mobile} = React.useContext(MobileContext) + const {mobile} = React.useContext(PreferencesContext) const { proof } = React.useContext(ProofContext) const { setTypewriterInput } = React.useContext(InputModeContext) const { selectedStep, setSelectedStep } = React.useContext(SelectionContext) diff --git a/client/src/components/level.tsx b/client/src/components/level.tsx index 4b5a53d..dbd62a5 100644 --- a/client/src/components/level.tsx +++ b/client/src/components/level.tsx @@ -27,7 +27,7 @@ import { Button } from './button' import Markdown from './markdown' import {InventoryPanel} from './inventory' import { hasInteractiveErrors } from './infoview/typewriter' -import { DeletedChatContext, InputModeContext, MobileContext, MonacoEditorContext, +import { DeletedChatContext, InputModeContext, PreferencesContext, MonacoEditorContext, ProofContext, ProofStep, SelectionContext, WorldLevelIdContext } from './infoview/context' import { DualEditor } from './infoview/main' import { GameHint } from './infoview/rpc_api' @@ -74,7 +74,7 @@ function Level() { function ChatPanel({lastLevel}) { const chatRef = useRef(null) - const {mobile} = useContext(MobileContext) + const {mobile} = useContext(PreferencesContext) const gameId = useContext(GameIdContext) const {worldId, levelId} = useContext(WorldLevelIdContext) const level = useLoadLevelQuery({game: gameId, world: worldId, level: levelId}) @@ -215,7 +215,7 @@ function PlayableLevel({impressum, setImpressum}) { const codeviewRef = useRef(null) const gameId = React.useContext(GameIdContext) const {worldId, levelId} = useContext(WorldLevelIdContext) - const {mobile} = React.useContext(MobileContext) + const {mobile} = React.useContext(PreferencesContext) const dispatch = useAppDispatch() @@ -441,7 +441,7 @@ function PlayableLevel({impressum, setImpressum}) { function IntroductionPanel({gameInfo}) { const gameId = React.useContext(GameIdContext) const {worldId} = useContext(WorldLevelIdContext) - const {mobile} = React.useContext(MobileContext) + const {mobile} = React.useContext(PreferencesContext) let text: Array = gameInfo.data?.worlds.nodes[worldId].introduction.split(/\n(\s*\n)+/) @@ -468,7 +468,7 @@ export default Level /** The site with the introduction text of a world */ function Introduction({impressum, setImpressum}) { const gameId = React.useContext(GameIdContext) - const {mobile} = useContext(MobileContext) + const {mobile} = useContext(PreferencesContext) const inventory = useLoadInventoryOverviewQuery({game: gameId}) diff --git a/client/src/components/popup/preferences.tsx b/client/src/components/popup/preferences.tsx index 2b6d29b..aadc319 100644 --- a/client/src/components/popup/preferences.tsx +++ b/client/src/components/popup/preferences.tsx @@ -9,7 +9,7 @@ import FormControlLabel from '@mui/material/FormControlLabel'; import { IPreferencesContext } from "../infoview/context" -interface PreferencesPopupProps extends IPreferencesContext { +interface PreferencesPopupProps extends Omit { handleClose: () => void } diff --git a/client/src/components/welcome.tsx b/client/src/components/welcome.tsx index 18f9f9d..5d4b3de 100644 --- a/client/src/components/welcome.tsx +++ b/client/src/components/welcome.tsx @@ -10,7 +10,7 @@ import { useAppDispatch, useAppSelector } from '../hooks' import { changedOpenedIntro, selectOpenedIntro } from '../state/progress' import { useGetGameInfoQuery, useLoadInventoryOverviewQuery } from '../state/api' import { Button } from './button' -import { MobileContext, PreferencesContext } from './infoview/context' +import { PreferencesContext } from './infoview/context' import { InventoryPanel } from './inventory' import { ErasePopup } from './popup/erase' import { InfoPopup } from './popup/game_info' @@ -27,7 +27,7 @@ import { Hint } from './hints' /** the panel showing the game's introduction text */ function IntroductionPanel({introduction, setPageNumber}: {introduction: string, setPageNumber}) { - const {mobile} = React.useContext(MobileContext) + const {mobile} = React.useContext(PreferencesContext) const gameId = React.useContext(GameIdContext) const dispatch = useAppDispatch() @@ -64,7 +64,7 @@ function IntroductionPanel({introduction, setPageNumber}: {introduction: string, /** main page of the game showing among others the tree of worlds/levels */ function Welcome() { const gameId = React.useContext(GameIdContext) - const {mobile, setMobile} = React.useContext(MobileContext) + const {mobile} = React.useContext(PreferencesContext) const {layout, isSavePreferences, setLayout, setIsSavePreferences} = React.useContext(PreferencesContext) const gameInfo = useGetGameInfoQuery({game: gameId}) diff --git a/client/src/components/world_tree.tsx b/client/src/components/world_tree.tsx index 76cf5fb..65fcc8a 100644 --- a/client/src/components/world_tree.tsx +++ b/client/src/components/world_tree.tsx @@ -16,7 +16,7 @@ import { selectDifficulty, changedDifficulty, selectCompleted } from '../state/p import { store } from '../state/store' import '../css/world_tree.css' -import { MobileContext } from './infoview/context' +import { PreferencesContext } from './infoview/context' // Settings for the world tree cytoscape.use( klay ) @@ -198,7 +198,7 @@ export function WorldSelectionMenu({rulesHelp, setRulesHelp}) { const gameId = React.useContext(GameIdContext) const difficulty = useSelector(selectDifficulty(gameId)) const dispatch = useAppDispatch() - const { mobile } = React.useContext(MobileContext) + const { mobile } = React.useContext(PreferencesContext) function label(x : number) { diff --git a/client/src/state/hooks/use_preferences.ts b/client/src/state/hooks/use_preferences.ts new file mode 100644 index 0000000..3b4f66c --- /dev/null +++ b/client/src/state/hooks/use_preferences.ts @@ -0,0 +1,41 @@ +import React, { useState } from "react"; +import { useAppDispatch, useAppSelector } from "../../hooks"; +import { + PreferencesState, + setLayout as setPreferencesLayout, + setIsSavePreferences as setPreferencesIsSavePreferences, + getWindowDimensions, + AUTO_SWITCH_THRESHOLD +} from "../preferences"; + + +const UsePreferences = () => { + const dispatch = useAppDispatch() + const [mobile, setMobile] = React.useState() + + const layout = useAppSelector((state) => state.preferences.layout); + const setLayout = (layout: PreferencesState["layout"]) => dispatch(setPreferencesLayout(layout)) + + const isSavePreferences = useAppSelector((state) => state.preferences.isSavePreferences); + const setIsSavePreferences = (isSave: boolean) => dispatch(setPreferencesIsSavePreferences(isSave)) + + const automaticallyAdjustLayout = () => { + const {width} = getWindowDimensions() + setMobile(width < AUTO_SWITCH_THRESHOLD) + } + + React.useEffect(()=>{ + if (layout === "auto"){ + void automaticallyAdjustLayout() + window.addEventListener('resize', automaticallyAdjustLayout) + + return () => window.removeEventListener('resize', automaticallyAdjustLayout) + } else { + setMobile(layout === "mobile") + } + }, [layout]) + + return {mobile, layout, isSavePreferences, setLayout, setIsSavePreferences} +} + +export default UsePreferences; \ No newline at end of file diff --git a/client/src/state/preferences.ts b/client/src/state/preferences.ts index f3c3fbb..7ccbe30 100644 --- a/client/src/state/preferences.ts +++ b/client/src/state/preferences.ts @@ -26,10 +26,10 @@ export const preferencesSlice = createSlice({ setLayout: (state, action) => { state.layout = action.payload; }, - setisSavePreferences: (state, action) => { + setIsSavePreferences: (state, action) => { state.isSavePreferences = action.payload; }, }, }); -export const { setLayout, setisSavePreferences } = preferencesSlice.actions; +export const { setLayout, setIsSavePreferences } = preferencesSlice.actions;