From aa00e359c40df646958ddd2933c5d68df09f6785 Mon Sep 17 00:00:00 2001 From: ran Date: Thu, 7 Dec 2023 15:06:58 +0800 Subject: [PATCH 1/4] Add the function of caching typewriterMode --- client/src/components/app_bar.tsx | 1 + client/src/components/infoview/main.tsx | 2 +- client/src/components/level.tsx | 9 +++++---- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/client/src/components/app_bar.tsx b/client/src/components/app_bar.tsx index 2c65a81..c1d1a10 100644 --- a/client/src/components/app_bar.tsx +++ b/client/src/components/app_bar.tsx @@ -103,6 +103,7 @@ function InputModeButton({setNavOpen, isDropdown}) { /** toggle input mode if allowed */ function toggleInputMode(ev: React.MouseEvent) { if (!lockInputMode){ + localStorage.setItem("lean4game:typewriterMode", JSON.stringify(!typewriterMode)) setTypewriterMode(!typewriterMode) setNavOpen(false) } diff --git a/client/src/components/infoview/main.tsx b/client/src/components/infoview/main.tsx index ab670a1..88dbbc9 100644 --- a/client/src/components/infoview/main.tsx +++ b/client/src/components/infoview/main.tsx @@ -156,7 +156,7 @@ export function Main(props: { world: string, level: number, data: LevelInfo}) { const completed = useAppSelector(selectCompleted(gameId, props.world, props.level)) - console.debug(`template: ${props.data.template}`) + console.debug(`template: ${props.data?.template}`) // React.useEffect (() => { // if (props.data.template) { diff --git a/client/src/components/level.tsx b/client/src/components/level.tsx index 806082d..c77b354 100644 --- a/client/src/components/level.tsx +++ b/client/src/components/level.tsx @@ -221,7 +221,10 @@ function PlayableLevel({impressum, setImpressum}) { const [showHelp, setShowHelp] = useState>(new Set()) // Only for mobile layout const [pageNumber, setPageNumber] = useState(0) - const [typewriterMode, setTypewriterMode] = useState(true) + const [typewriterMode, setTypewriterMode] = useState(()=>{ + const savedMode = localStorage.getItem('lean4game:typewriterMode'); + return savedMode !== null ? JSON.parse(savedMode) : true; + }) // set to true to prevent switching between typewriter and editor const [lockInputMode, setLockInputMode] = useState(false) const [typewriterInput, setTypewriterInput] = useState("") @@ -320,8 +323,6 @@ function PlayableLevel({impressum, setImpressum}) { console.debug(`not inserting template.`) } } - } else { - setTypewriterMode(true) } }, [level, levelId, worldId, gameId, editor]) @@ -336,7 +337,7 @@ function PlayableLevel({impressum, setImpressum}) { }, [gameId, worldId, levelId]) useEffect(() => { - if (!typewriterMode) { + if (!typewriterMode && editor) { // Delete last input attempt from command line editor.executeEdits("typewriter", [{ range: editor.getSelection(), From 088711b5d1b5457dc6c9a68d04b31dd0c94a5ca0 Mon Sep 17 00:00:00 2001 From: ran Date: Thu, 7 Dec 2023 21:38:15 +0800 Subject: [PATCH 2/4] Use 'progress' to construct the processing flow of typewriterMode --- client/src/components/app_bar.tsx | 1 - client/src/components/level.tsx | 15 ++++++++------- client/src/state/progress.ts | 21 +++++++++++++++++---- 3 files changed, 25 insertions(+), 12 deletions(-) diff --git a/client/src/components/app_bar.tsx b/client/src/components/app_bar.tsx index c1d1a10..2c65a81 100644 --- a/client/src/components/app_bar.tsx +++ b/client/src/components/app_bar.tsx @@ -103,7 +103,6 @@ function InputModeButton({setNavOpen, isDropdown}) { /** toggle input mode if allowed */ function toggleInputMode(ev: React.MouseEvent) { if (!lockInputMode){ - localStorage.setItem("lean4game:typewriterMode", JSON.stringify(!typewriterMode)) setTypewriterMode(!typewriterMode) setNavOpen(false) } diff --git a/client/src/components/level.tsx b/client/src/components/level.tsx index c77b354..ccfbf17 100644 --- a/client/src/components/level.tsx +++ b/client/src/components/level.tsx @@ -22,7 +22,7 @@ import { ConnectionContext, connection, useLeanClient } from '../connection' import { useAppDispatch, useAppSelector } from '../hooks' import { useGetGameInfoQuery, useLoadInventoryOverviewQuery, useLoadLevelQuery } from '../state/api' import { changedSelection, codeEdited, selectCode, selectSelections, selectCompleted, helpEdited, - selectHelp, selectDifficulty, selectInventory } from '../state/progress' + selectHelp, selectDifficulty, selectInventory, selectTypewriterMode, changeTypewriterMode } from '../state/progress' import { store } from '../state/store' import { Button } from './button' import Markdown from './markdown' @@ -204,12 +204,17 @@ function PlayableLevel({impressum, setImpressum}) { const {worldId, levelId} = useContext(WorldLevelIdContext) const {mobile} = React.useContext(MobileContext) + const dispatch = useAppDispatch() + const difficulty = useSelector(selectDifficulty(gameId)) const initialCode = useAppSelector(selectCode(gameId, worldId, levelId)) const initialSelections = useAppSelector(selectSelections(gameId, worldId, levelId)) const inventory: Array = useSelector(selectInventory(gameId)) - const gameInfo = useGetGameInfoQuery({game: gameId}) + const typewriterMode = useSelector(selectTypewriterMode(gameId)) + const setTypewriterMode = (newTypewriterMode: boolean) => dispatch(changeTypewriterMode({game: gameId, typewriterMode: newTypewriterMode})) + + const gameInfo = useGetGameInfoQuery({game: gameId}) const level = useLoadLevelQuery({game: gameId, world: worldId, level: levelId}) // The state variables for the `ProofContext` @@ -221,15 +226,11 @@ function PlayableLevel({impressum, setImpressum}) { const [showHelp, setShowHelp] = useState>(new Set()) // Only for mobile layout const [pageNumber, setPageNumber] = useState(0) - const [typewriterMode, setTypewriterMode] = useState(()=>{ - const savedMode = localStorage.getItem('lean4game:typewriterMode'); - return savedMode !== null ? JSON.parse(savedMode) : true; - }) + // set to true to prevent switching between typewriter and editor const [lockInputMode, setLockInputMode] = useState(false) const [typewriterInput, setTypewriterInput] = useState("") const lastLevel = levelId >= gameInfo.data?.worldSize[worldId] - const dispatch = useAppDispatch() // impressum pop-up function toggleImpressum() {setImpressum(!impressum)} diff --git a/client/src/state/progress.ts b/client/src/state/progress.ts index f553159..d622703 100644 --- a/client/src/state/progress.ts +++ b/client/src/state/progress.ts @@ -26,7 +26,8 @@ export interface GameProgressState { inventory: string[], difficulty: number, openedIntro: boolean, - data: WorldProgressState + data: WorldProgressState, + typewriterMode: boolean } /** @@ -53,7 +54,7 @@ const initalLevelProgressState: LevelProgressState = {code: "", completed: false /** Add an empty skeleton with progress for the current game */ function addGameProgress (state: ProgressState, action: PayloadAction<{game: string}>) { if (!state.games[action.payload.game]) { - state.games[action.payload.game] = {inventory: [], openedIntro: true, data: {}, difficulty: DEFAULT_DIFFICULTY} + state.games[action.payload.game] = {inventory: [], openedIntro: true, data: {}, difficulty: DEFAULT_DIFFICULTY, typewriterMode: true} } if (!state.games[action.payload.game].data) { state.games[action.payload.game].data = {} @@ -99,7 +100,7 @@ export const progressSlice = createSlice({ }, /** delete all progress for this game */ deleteProgress(state: ProgressState, action: PayloadAction<{game: string}>) { - state.games[action.payload.game] = {inventory: [], data: {}, openedIntro: true, difficulty: DEFAULT_DIFFICULTY} + state.games[action.payload.game] = {inventory: [], data: {}, openedIntro: true, difficulty: DEFAULT_DIFFICULTY, typewriterMode: true} }, /** delete progress for this level */ deleteLevelProgress(state: ProgressState, action: PayloadAction<{game: string, world: string, level: number}>) { @@ -126,6 +127,10 @@ export const progressSlice = createSlice({ addGameProgress(state, action) state.games[action.payload.game].openedIntro = action.payload.openedIntro }, + changeTypewriterMode(state: ProgressState, action: PayloadAction<{game: string, typewriterMode: boolean}>) { + addGameProgress(state, action) + state.games[action.payload.game].typewriterMode = action.payload.typewriterMode + } } }) @@ -196,7 +201,15 @@ export function selectOpenedIntro(game: string) { } } +/** return whether the intro has been read */ +export function selectTypewriterMode(game: string) { + return (state) => { + return state.progress.games[game] ? state.progress.games[game].typewriterMode : true + } +} + + /** Export actions to modify the progress */ export const { changedSelection, codeEdited, levelCompleted, deleteProgress, deleteLevelProgress, loadProgress, helpEdited, changedInventory, changedOpenedIntro, - changedDifficulty } = progressSlice.actions + changedDifficulty, changeTypewriterMode} = progressSlice.actions From 0c4ae9285679494ce1c2ebf135a9edceeef810e1 Mon Sep 17 00:00:00 2001 From: ran Date: Thu, 7 Dec 2023 21:43:50 +0800 Subject: [PATCH 3/4] Optimize the typewriterMode code logic about the game --- client/src/state/progress.ts | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/client/src/state/progress.ts b/client/src/state/progress.ts index d622703..bee0d90 100644 --- a/client/src/state/progress.ts +++ b/client/src/state/progress.ts @@ -27,7 +27,7 @@ export interface GameProgressState { difficulty: number, openedIntro: boolean, data: WorldProgressState, - typewriterMode: boolean + typewriterMode?: boolean } /** @@ -54,7 +54,7 @@ const initalLevelProgressState: LevelProgressState = {code: "", completed: false /** Add an empty skeleton with progress for the current game */ function addGameProgress (state: ProgressState, action: PayloadAction<{game: string}>) { if (!state.games[action.payload.game]) { - state.games[action.payload.game] = {inventory: [], openedIntro: true, data: {}, difficulty: DEFAULT_DIFFICULTY, typewriterMode: true} + state.games[action.payload.game] = {inventory: [], openedIntro: true, data: {}, difficulty: DEFAULT_DIFFICULTY} } if (!state.games[action.payload.game].data) { state.games[action.payload.game].data = {} @@ -100,7 +100,7 @@ export const progressSlice = createSlice({ }, /** delete all progress for this game */ deleteProgress(state: ProgressState, action: PayloadAction<{game: string}>) { - state.games[action.payload.game] = {inventory: [], data: {}, openedIntro: true, difficulty: DEFAULT_DIFFICULTY, typewriterMode: true} + state.games[action.payload.game] = {inventory: [], data: {}, openedIntro: true, difficulty: DEFAULT_DIFFICULTY} }, /** delete progress for this level */ deleteLevelProgress(state: ProgressState, action: PayloadAction<{game: string, world: string, level: number}>) { @@ -127,6 +127,7 @@ export const progressSlice = createSlice({ addGameProgress(state, action) state.games[action.payload.game].openedIntro = action.payload.openedIntro }, + /** set the typewriter mode */ changeTypewriterMode(state: ProgressState, action: PayloadAction<{game: string, typewriterMode: boolean}>) { addGameProgress(state, action) state.games[action.payload.game].typewriterMode = action.payload.typewriterMode @@ -201,10 +202,10 @@ export function selectOpenedIntro(game: string) { } } -/** return whether the intro has been read */ +/** return typewriter mode for the current game if it exists */ export function selectTypewriterMode(game: string) { return (state) => { - return state.progress.games[game] ? state.progress.games[game].typewriterMode : true + return state.progress.games[game]?.typewriterMode ?? true } } From b17c8fc4cb1d2b649cec6394de90cfab35ed47ff Mon Sep 17 00:00:00 2001 From: ran Date: Thu, 7 Dec 2023 21:45:47 +0800 Subject: [PATCH 4/4] remove \n in progress.ts 211 line --- client/src/state/progress.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/client/src/state/progress.ts b/client/src/state/progress.ts index bee0d90..c8c4242 100644 --- a/client/src/state/progress.ts +++ b/client/src/state/progress.ts @@ -209,7 +209,6 @@ export function selectTypewriterMode(game: string) { } } - /** Export actions to modify the progress */ export const { changedSelection, codeEdited, levelCompleted, deleteProgress, deleteLevelProgress, loadProgress, helpEdited, changedInventory, changedOpenedIntro,