make preferences work #179

pull/205/head
Jon Eugster 2 years ago
parent 27c661f08f
commit 8d0493acb5

@ -36,7 +36,7 @@ module.exports = {
},
lngs: ['en','de'],
ns: [],
defaultLng: 'en',
defaultLng: 'en-GB',
defaultNs: 'translation',
defaultValue: (lng, ns, key) => {
if (lng === 'en') {

@ -1,4 +1,5 @@
{
"Tactics": "Taktiken",
"Lean Game Server": "Lean-Spieleserver",
"<p>Game rules determine if it is allowed to skip levels and if the games runs checks to only allow unlocked tactics and theorems in proofs.</p><1>Note: \"Unlocked\" tactics (or theorems) are determined by two things: The set of minimal tactics needed to solve a level, plus any tactics you unlocked in another level. That means if you unlock <1>simp</1> in a level, you can use it henceforth in any level.</1><p>The options are:</p>": "<p>Die Spielregeln bestimmen ob es erlaubt ist, Levels zu überspringen und ob das Spiel überprüft welche Taktiken und Theoreme freigeschaltet sind und nur diese im Beweis akzeptiert.</p><1>Bemerkung: \"Freigeschaltete\" Taktiken (und Theoreme) werden durch zwei Faktoren bestimmt: The Menge der Taktiken die minimal notwending sind um den Level zu lösen und dazu die Menge aller Taktiken, die in einem anderen Level freigeschaltet wurden. Das bedeutet wenn <1>simp</1> in einem Level freigeschaltet wird, kann diese Taktik danach in jeglichen Levels verwendet werden.",
"Game Rules": "Spielregeln",
@ -7,5 +8,5 @@
"regular": "regulär",
"relaxed": "relaxed",
"none": "keine",
"Rules": "Regend"
"Rules": "Regeln"
}

@ -1,4 +1,5 @@
{
"Tactics": "Tactics",
"Lean Game Server": "Lean Game Server",
"<p>Game rules determine if it is allowed to skip levels and if the games runs checks to only allow unlocked tactics and theorems in proofs.</p><1>Note: \"Unlocked\" tactics (or theorems) are determined by two things: The set of minimal tactics needed to solve a level, plus any tactics you unlocked in another level. That means if you unlock <1>simp</1> in a level, you can use it henceforth in any level.</1><p>The options are:</p>": "<p>Game rules determine if it is allowed to skip levels and if the games runs checks to only allow unlocked tactics and theorems in proofs.</p><1>Note: \"Unlocked\" tactics (or theorems) are determined by two things: The set of minimal tactics needed to solve a level, plus any tactics you unlocked in another level. That means if you unlock <1>simp</1> in a level, you can use it henceforth in any level.</1><p>The options are:</p>",
"Game Rules": "Game Rules",

@ -10,6 +10,7 @@ import './css/reset.css';
import './css/app.css';
import { PreferencesContext} from './components/infoview/context';
import UsePreferences from "./state/hooks/use_preferences"
import i18n from './i18n';
export const GameIdContext = React.createContext<string>(undefined);
@ -18,12 +19,16 @@ function App() {
const params = useParams()
const gameId = "g/" + params.owner + "/" + params.repo
const {mobile, layout, isSavePreferences, setLayout, setIsSavePreferences} = UsePreferences()
const {mobile, layout, isSavePreferences, language, setLayout, setIsSavePreferences, setLanguage} = UsePreferences()
React.useEffect(() => {
i18n.changeLanguage(language)
}, [language])
return (
<div className="app">
<GameIdContext.Provider value={gameId}>
<PreferencesContext.Provider value={{mobile, layout, isSavePreferences, setLayout, setIsSavePreferences}}>
<PreferencesContext.Provider value={{mobile, layout, isSavePreferences, language, setLayout, setIsSavePreferences, setLanguage}}>
<React.Suspense>
<Outlet />
</React.Suspense>

@ -14,6 +14,7 @@ import { useAppDispatch, useAppSelector } from '../hooks'
import { Button } from './button'
import { downloadProgress } from './popup/erase'
import ReactCountryFlag from "react-country-flag"
import { t } from 'i18next'
/** navigation buttons for mobile welcome page to switch between intro/tree/inventory. */
function MobileNavButtons({pageNumber, setPageNumber}:
@ -119,28 +120,46 @@ function InputModeButton({setNavOpen, isDropdown}) {
</Button>
}
/** button to toggle iimpressum popup */
/** button to toggle iimpressum popup
*
* Note: Do not translate "Impressum"!
*/
function ImpressumButton({setNavOpen, toggleImpressum, isDropdown}) {
return <Button className="btn btn-inverted toggle-width"
return <Button className="btn btn-inverted"
title="information, Impressum, privacy policy" inverted="true" to="" onClick={(ev) => {toggleImpressum(ev); setNavOpen(false)}}>
<FontAwesomeIcon icon={faCircleInfo} />
{isDropdown && <>&nbsp;Info &amp; Impressum</>}
{isDropdown && <>&nbsp;Impressum</>}
</Button>
}
/** button to toggle iimpressum popup */
function LanguageButton({setNavOpen, toggleLangNav, isDropdown}) {
return <Button className="btn btn-inverted language-btn"
title="language" inverted="true" to="" onClick={(ev) => {toggleLangNav(ev); setNavOpen(false)}}>
<ReactCountryFlag countryCode="GB"
className="emojiFlag"
style={{
height: '1.3em',
width: '1.6em',
}}
title="English"
/>
{isDropdown && <>&nbsp;Language</>}
function PreferencesButton({setNavOpen, togglePreferencesPopup}) {
return <Button title="Preferences" inverted="true" to="" onClick={() => {togglePreferencesPopup(); setNavOpen(false)}}>
<FontAwesomeIcon icon={faGear} />&nbsp;{t("Preferences")}
</Button>
}
function GameInfoButton({setNavOpen, toggleInfo}) {
return <Button className="btn btn-inverted"
title="Game Info & Credits" inverted="true" to="" onClick={() => {toggleInfo(); setNavOpen(false)}}>
<FontAwesomeIcon icon={faCircleInfo} />&nbsp;Game Info
</Button>
}
function EraseButton ({setNavOpen, toggleEraseMenu}) {
return <Button title="Clear Progress" inverted="true" to="" onClick={() => {toggleEraseMenu(); setNavOpen(false)}}>
<FontAwesomeIcon icon={faEraser} />&nbsp;Erase
</Button>
}
function DownloadButton ({setNavOpen, gameId, gameProgress}) {
return <Button title="Download Progress" inverted="true" to="" onClick={(ev) => {downloadProgress(gameId, gameProgress, ev); setNavOpen(false)}}>
<FontAwesomeIcon icon={faDownload} />&nbsp;Download
</Button>
}
function UploadButton ({setNavOpen, toggleUploadMenu}) {
return <Button title="Load Progress from JSON" inverted="true" to="" onClick={() => {toggleUploadMenu(); setNavOpen(false)}}>
<FontAwesomeIcon icon={faUpload} />&nbsp;Upload
</Button>
}
@ -153,6 +172,12 @@ function HomeButton({isDropdown}) {
</Button>
}
function LandingPageButton() {
return <Button inverted="false" title="back to games selection" to="/">
<FontAwesomeIcon icon={faArrowLeft} />&nbsp;<FontAwesomeIcon icon={faGlobe} />
</Button>
}
/** button in mobile level to toggle inventory.
* only displays a button if `setPageNumber` is set.
*/
@ -184,9 +209,7 @@ export function WelcomeAppBar({pageNumber, setPageNumber, gameInfo, toggleImpres
return <div className="app-bar">
<div className='app-bar-left'>
<Button inverted="false" title="back to games selection" to="/">
<FontAwesomeIcon icon={faArrowLeft} />&nbsp;<FontAwesomeIcon icon={faGlobe} />
</Button>
<LandingPageButton />
<span className="app-bar-title"></span>
</div>
<div>
@ -197,33 +220,23 @@ export function WelcomeAppBar({pageNumber, setPageNumber, gameInfo, toggleImpres
<MenuButton navOpen={navOpen} setNavOpen={setNavOpen} />
</div>
<div className={'menu dropdown' + (navOpen ? '' : ' hidden')}>
<Button title="Game Info & Credits" inverted="true" to="" onClick={() => {toggleInfo(); setNavOpen(false)}}>
<FontAwesomeIcon icon={faCircleInfo} />&nbsp;Game Info
</Button>
<Button title="Clear Progress" inverted="true" to="" onClick={() => {toggleEraseMenu(); setNavOpen(false)}}>
<FontAwesomeIcon icon={faEraser} />&nbsp;Erase
</Button>
<Button title="Download Progress" inverted="true" to="" onClick={(ev) => {downloadProgress(gameId, gameProgress, ev); setNavOpen(false)}}>
<FontAwesomeIcon icon={faDownload} />&nbsp;Download
</Button>
<Button title="Load Progress from JSON" inverted="true" to="" onClick={() => {toggleUploadMenu(); setNavOpen(false)}}>
<FontAwesomeIcon icon={faUpload} />&nbsp;Upload
</Button>
<Button title="Impressum, privacy policy" inverted="true" to="" onClick={() => {toggleImpressum(); setNavOpen(false)}}>
<FontAwesomeIcon icon={faCircleInfo} />&nbsp;Impressum
</Button>
<Button title="Preferences" inverted="true" to="" onClick={() => {togglePreferencesPopup(); setNavOpen(false)}}>
<FontAwesomeIcon icon={faGear} />&nbsp;Preferences
</Button>
<GameInfoButton setNavOpen={setNavOpen} toggleInfo={toggleInfo}/>
<EraseButton setNavOpen={setNavOpen} toggleEraseMenu={toggleEraseMenu}/>
<DownloadButton setNavOpen={setNavOpen} gameId={gameId} gameProgress={gameProgress}/>
<UploadButton setNavOpen={setNavOpen} toggleUploadMenu={toggleUploadMenu}/>
<ImpressumButton setNavOpen={setNavOpen} toggleImpressum={toggleImpressum} isDropdown={true} />
<PreferencesButton setNavOpen={setNavOpen} togglePreferencesPopup={togglePreferencesPopup}/>
</div>
</div>
}
/** the navigation bar in a level */
export function LevelAppBar({isLoading, levelTitle, toggleImpressum, pageNumber=undefined, setPageNumber=undefined} : {
export function LevelAppBar({isLoading, levelTitle, toggleImpressum, toggleInfo, togglePreferencesPopup, pageNumber=undefined, setPageNumber=undefined} : {
isLoading: boolean,
levelTitle: string,
toggleImpressum: any,
toggleInfo: any,
togglePreferencesPopup: any,
pageNumber?: number,
setPageNumber?: any,
}) {
@ -253,15 +266,16 @@ export function LevelAppBar({isLoading, levelTitle, toggleImpressum, pageNumber=
<PreviousButton setNavOpen={setNavOpen} />
<HomeButton isDropdown={true} />
<InputModeButton setNavOpen={setNavOpen} isDropdown={true}/>
<GameInfoButton setNavOpen={setNavOpen} toggleInfo={toggleInfo}/>
<ImpressumButton setNavOpen={setNavOpen} toggleImpressum={toggleImpressum} isDropdown={true} />
<LanguageButton setNavOpen={setNavOpen} toggleLangNav={() => {}} isDropdown={true} />
<PreferencesButton setNavOpen={setNavOpen} togglePreferencesPopup={togglePreferencesPopup}/>
</div>
</> :
<>
{/* DESKTOP VERSION */}
<div className='app-bar-left'>
<HomeButton isDropdown={false} />
<span className="app-bar-title">{worldTitle && `World: ${worldTitle}`}</span>
<span className="app-bar-title">{worldTitle && `${t("World")}: ${worldTitle}`}</span>
</div>
<div>
<span className="app-bar-title">{levelTitle}</span>
@ -270,8 +284,12 @@ export function LevelAppBar({isLoading, levelTitle, toggleImpressum, pageNumber=
<PreviousButton setNavOpen={setNavOpen} />
<NextButton worldSize={gameInfo.data?.worldSize[worldId]} difficulty={difficulty} completed={completed} setNavOpen={setNavOpen} />
<InputModeButton setNavOpen={setNavOpen} isDropdown={false}/>
<ImpressumButton setNavOpen={setNavOpen} toggleImpressum={toggleImpressum} isDropdown={false} />
<LanguageButton setNavOpen={setNavOpen} toggleLangNav={() => {}} isDropdown={false} />
<MenuButton navOpen={navOpen} setNavOpen={setNavOpen}/>
</div>
<div className={'menu dropdown' + (navOpen ? '' : ' hidden')}>
<GameInfoButton setNavOpen={setNavOpen} toggleInfo={toggleInfo}/>
<ImpressumButton setNavOpen={setNavOpen} toggleImpressum={toggleImpressum} isDropdown={true} />
<PreferencesButton setNavOpen={setNavOpen} togglePreferencesPopup={togglePreferencesPopup}/>
</div>
</>
}

@ -79,15 +79,18 @@ export interface ProofStateProps {
export interface IPreferencesContext extends PreferencesState{
mobile: boolean, // The variables that actually control the page 'layout' can only be changed through layout.
setLayout: React.Dispatch<React.SetStateAction<PreferencesState["layout"]>>;
setIsSavePreferences: React.Dispatch<React.SetStateAction<Boolean>>;
setIsSavePreferences: React.Dispatch<React.SetStateAction<PreferencesState["isSavePreferences"]>>;
setLanguage: React.Dispatch<React.SetStateAction<PreferencesState["language"]>>;
}
export const PreferencesContext = React.createContext<IPreferencesContext>({
mobile: false,
layout: "auto",
isSavePreferences: false,
language: "en",
setLayout: () => {},
setIsSavePreferences: () => {}
setIsSavePreferences: () => {},
setLanguage: () => {},
})
export const WorldLevelIdContext = React.createContext<{

@ -10,6 +10,7 @@ import { useLoadDocQuery, InventoryTile, LevelInfo, InventoryOverview, useLoadIn
import { selectDifficulty, selectInventory } from '../state/progress';
import { store } from '../state/store';
import { useSelector } from 'react-redux';
import { t } from 'i18next';
export function Inventory({levelInfo, openDoc, lemmaTab, setLemmaTab, enableAll=false} :
{
@ -24,7 +25,7 @@ export function Inventory({levelInfo, openDoc, lemmaTab, setLemmaTab, enableAll=
<div className="inventory">
{/* TODO: Click on Tactic: show info
TODO: click on paste icon -> paste into command line */}
<h2>Tactics</h2>
<h2>{t("Tactics")}</h2>
{levelInfo?.tactics &&
<InventoryList items={levelInfo?.tactics} docType="Tactic" openDoc={openDoc} enableAll={enableAll}/>
}

@ -51,6 +51,8 @@ import { IConnectionProvider } from 'monaco-languageclient'
import { monacoSetup } from 'lean4web/client/src/monacoSetup'
import { onigasmH } from 'onigasm/lib/onigasmH'
import { isLastStepWithErrors, lastStepHasErrors } from './infoview/goals'
import { InfoPopup } from './popup/game_info'
import { PreferencesPopup } from './popup/preferences'
monacoSetup()
@ -60,17 +62,29 @@ function Level() {
const levelId = parseInt(params.levelId)
const worldId = params.worldId
const {layout, isSavePreferences, language, setLayout, setIsSavePreferences, setLanguage} = React.useContext(PreferencesContext)
const gameId = React.useContext(GameIdContext)
const gameInfo = useGetGameInfoQuery({game: gameId})
// pop-ups
const [impressum, setImpressum] = React.useState(false)
const [info, setInfo] = React.useState(false)
const [preferencesPopup, setPreferencesPopup] = React.useState(false)
const closeImpressum = () => {
setImpressum(false)
}
function closeImpressum() {setImpressum(false)}
function closeInfo() {setInfo(false)}
function closePreferencesPopup() {setPreferencesPopup(false)}
function toggleImpressum() {setImpressum(!impressum)}
function toggleInfo() {setInfo(!info)}
function togglePreferencesPopup() {setPreferencesPopup(!preferencesPopup)}
return <WorldLevelIdContext.Provider value={{worldId, levelId}}>
{levelId == 0 ?
<Introduction impressum={impressum} setImpressum={setImpressum} /> :
<PlayableLevel key={`${worldId}/${levelId}`} impressum={impressum} setImpressum={setImpressum} />}
<Introduction impressum={impressum} setImpressum={setImpressum} toggleInfo={toggleInfo} togglePreferencesPopup={togglePreferencesPopup} /> :
<PlayableLevel key={`${worldId}/${levelId}`} impressum={impressum} setImpressum={setImpressum} toggleInfo={toggleInfo} togglePreferencesPopup={togglePreferencesPopup}/>}
{impressum ? <PrivacyPolicyPopup handleClose={closeImpressum} /> : null}
{info ? <InfoPopup info={gameInfo.data?.info} handleClose={closeInfo}/> : null}
{preferencesPopup ? <PreferencesPopup layout={layout} isSavePreferences={isSavePreferences} setLayout={setLayout} setIsSavePreferences={setIsSavePreferences} handleClose={closePreferencesPopup} language={language} setLanguage={setLanguage}/> : null}
</WorldLevelIdContext.Provider>
}
@ -190,7 +204,7 @@ function ExercisePanel({codeviewRef, visible=true}: {codeviewRef: React.MutableR
</div>
}
function PlayableLevel({impressum, setImpressum}) {
function PlayableLevel({impressum, setImpressum, toggleInfo, togglePreferencesPopup}) {
const codeviewRef = useRef<HTMLDivElement>(null)
const gameId = React.useContext(GameIdContext)
const {worldId, levelId} = useContext(WorldLevelIdContext)
@ -396,7 +410,10 @@ function PlayableLevel({impressum, setImpressum}) {
isLoading={level.isLoading}
levelTitle={`${mobile ? '' : 'Level '}${levelId} / ${gameInfo.data?.worldSize[worldId]}` +
(level?.data?.title && ` : ${level?.data?.title}`)}
toggleImpressum={toggleImpressum} />
toggleImpressum={toggleImpressum}
toggleInfo={toggleInfo}
togglePreferencesPopup={togglePreferencesPopup}
/>
{mobile?
// TODO: This is copied from the `Split` component below...
<>
@ -452,7 +469,7 @@ function IntroductionPanel({gameInfo}) {
export default Level
/** The site with the introduction text of a world */
function Introduction({impressum, setImpressum}) {
function Introduction({impressum, setImpressum, toggleInfo, togglePreferencesPopup}) {
const gameId = React.useContext(GameIdContext)
const {mobile} = useContext(PreferencesContext)
@ -470,7 +487,7 @@ function Introduction({impressum, setImpressum}) {
}
return <>
<LevelAppBar isLoading={gameInfo.isLoading} levelTitle="Introduction" toggleImpressum={toggleImpressum}/>
<LevelAppBar isLoading={gameInfo.isLoading} levelTitle="Introduction" toggleImpressum={toggleImpressum} toggleInfo={toggleInfo} togglePreferencesPopup={togglePreferencesPopup}/>
{gameInfo.isLoading ?
<div className="app-content loading"><CircularProgress /></div>
: mobile ?

@ -0,0 +1,14 @@
{
"languages": [
{
"iso": "en",
"flag": "GB",
"name": "English"
},
{
"iso": "de",
"flag": "DE",
"name": "Deutsch"
}
]
}

@ -1,9 +1,10 @@
import * as React from 'react'
import { Input, MenuItem, Select, Typography } from '@mui/material'
import { Input, MenuItem, Select, SelectChangeEvent, Typography } from '@mui/material'
import Markdown from '../markdown'
import { Switch, Button, ButtonGroup } from '@mui/material';
import Box from '@mui/material/Box';
import Slider from '@mui/material/Slider';
import supportedLanguages from './language_config.json'
import FormControlLabel from '@mui/material/FormControlLabel';
@ -11,102 +12,105 @@ import { IPreferencesContext } from "../infoview/context"
import ReactCountryFlag from 'react-country-flag';
interface PreferencesPopupProps extends Omit<IPreferencesContext, 'mobile'> {
handleClose: () => void
handleClose: () => void
}
export function PreferencesPopup({ layout, setLayout, isSavePreferences, setIsSavePreferences, handleClose }: PreferencesPopupProps) {
export function PreferencesPopup({ layout, setLayout, isSavePreferences, language, setIsSavePreferences, handleClose, setLanguage }: PreferencesPopupProps) {
const marks = [
{
value: 0,
label: 'Mobile',
key: "mobile"
},
{
value: 1,
label: 'Auto',
key: "auto"
},
{
value: 2,
label: 'Desktop',
key: "desktop"
},
];
const marks = [
{
value: 0,
label: 'Mobile',
key: "mobile"
},
{
value: 1,
label: 'Auto',
key: "auto"
},
{
value: 2,
label: 'Desktop',
key: "desktop"
},
];
const handlerChangeLayout = (_: Event, value: number) => {
setLayout(marks[value].key as IPreferencesContext["layout"])
}
const handlerChangeLayout = (_: Event, value: number) => {
setLayout(marks[value].key as IPreferencesContext["layout"])
}
return <div className="modal-wrapper">
<div className="modal-backdrop" onClick={handleClose} />
<div className="modal">
<div className="codicon codicon-close modal-close" onClick={handleClose}></div>
<Typography variant="body1" component="div" className="settings">
<div className='preferences-category'>
<div className='category-title'>
<h3>Language</h3>
</div>
<div className='preferences-item first leave-left-gap'>
<FormControlLabel
control={
<Box sx={{ width: 300 }}>
<Select
value={'GB'}
label={"Language"}>
<MenuItem value={'GB'}>
<ReactCountryFlag countryCode="GB"/>&nbsp;English
</MenuItem>
</Select>
</Box>
}
label=""
/>
</div>
</div>
<div className='preferences-category'>
<div className='category-title'>
<h3>Layout</h3>
</div>
<div className='preferences-item first leave-left-gap'>
<FormControlLabel
control={
<Box sx={{ width: 300 }}>
<Slider
aria-label="Always visible"
value={marks.find(item => item.key === layout).value}
step={1}
marks={marks}
max={2}
sx={{
'& .MuiSlider-track': { display: 'none', },
}}
onChange={handlerChangeLayout}
/>
</Box>
}
label=""
/>
</div>
</div>
const handlerChangeLanguage = (ev: SelectChangeEvent<string>) => {
setLanguage(ev.target.value as IPreferencesContext["language"])
}
<div className='preferences-category tail-category'>
<div className='preferences-item'>
<FormControlLabel
control={
<Switch
checked={isSavePreferences}
onChange={() => setIsSavePreferences(!isSavePreferences)}
name="checked"
color="primary"
/>
}
label="Save my settings (in the browser store)"
labelPlacement="end"
/>
</div>
</div>
</Typography>
return <div className="modal-wrapper">
<div className="modal-backdrop" onClick={handleClose} />
<div className="modal">
<div className="codicon codicon-close modal-close" onClick={handleClose}></div>
<Typography variant="body1" component="div" className="settings">
<div className='preferences-category'>
<div className='category-title'>
<h3>Language</h3>
</div>
<div className='preferences-item first leave-left-gap'>
<FormControlLabel
control={
<Box sx={{ width: 300 }}>
<Select
value={language}
label={"Language"}
onChange={handlerChangeLanguage}>
{supportedLanguages.languages.map(lang => {return <MenuItem key={`menu-item-lang-${lang.iso}`} value={lang.iso}><ReactCountryFlag countryCode={lang.flag}/>&nbsp;{lang.name}</MenuItem>})}
</Select>
</Box>
}
label=""
/>
</div>
</div>
<div className='preferences-category'>
<div className='category-title'>
<h3>Layout</h3>
</div>
<div className='preferences-item first leave-left-gap'>
<FormControlLabel
control={
<Box sx={{ width: 300 }}>
<Slider
aria-label="Always visible"
value={marks.find(item => item.key === layout).value}
step={1}
marks={marks}
max={2}
sx={{
'& .MuiSlider-track': { display: 'none', },
}}
onChange={handlerChangeLayout}
/>
</Box>
}
label=""
/>
</div>
</div>
<div className='preferences-category tail-category'>
<div className='preferences-item'>
<FormControlLabel
control={
<Switch
checked={isSavePreferences}
onChange={() => setIsSavePreferences(!isSavePreferences)}
name="checked"
color="primary"
/>
}
label="Save my settings (in the browser store)"
labelPlacement="end"
/>
</div>
</div>
</Typography>
</div>
</div>
}

@ -65,7 +65,7 @@ function IntroductionPanel({introduction, setPageNumber}: {introduction: string,
function Welcome() {
const gameId = React.useContext(GameIdContext)
const {mobile} = React.useContext(PreferencesContext)
const {layout, isSavePreferences, setLayout, setIsSavePreferences} = React.useContext(PreferencesContext)
const {layout, isSavePreferences, language, setLayout, setIsSavePreferences, setLanguage} = React.useContext(PreferencesContext)
const gameInfo = useGetGameInfoQuery({game: gameId})
const inventory = useLoadInventoryOverviewQuery({game: gameId})
@ -135,7 +135,7 @@ function Welcome() {
{eraseMenu? <ErasePopup handleClose={closeEraseMenu}/> : null}
{uploadMenu? <UploadPopup handleClose={closeUploadMenu}/> : null}
{info ? <InfoPopup info={gameInfo.data?.info} handleClose={closeInfo}/> : null}
{preferencesPopup ? <PreferencesPopup layout={layout} isSavePreferences={isSavePreferences} setLayout={setLayout} setIsSavePreferences={setIsSavePreferences} handleClose={closePreferencesPopup}/> : null}
{preferencesPopup ? <PreferencesPopup layout={layout} isSavePreferences={isSavePreferences} setLayout={setLayout} setIsSavePreferences={setIsSavePreferences} handleClose={closePreferencesPopup} language={language} setLanguage={setLanguage}/> : null}
</>
}

@ -4,6 +4,7 @@ import {
PreferencesState,
setLayout as setPreferencesLayout,
setIsSavePreferences as setPreferencesIsSavePreferences,
setLanguage as setLanguagePreferences,
getWindowDimensions,
AUTO_SWITCH_THRESHOLD
} from "../preferences";
@ -19,6 +20,9 @@ const UsePreferences = () => {
const isSavePreferences = useAppSelector((state) => state.preferences.isSavePreferences);
const setIsSavePreferences = (isSave: boolean) => dispatch(setPreferencesIsSavePreferences(isSave))
const language = useAppSelector((state) => state.preferences.language);
const setLanguage = (lang: string) => dispatch(setLanguagePreferences(lang))
const automaticallyAdjustLayout = () => {
const {width} = getWindowDimensions()
setMobile(width < AUTO_SWITCH_THRESHOLD)
@ -35,7 +39,7 @@ const UsePreferences = () => {
}
}, [layout])
return {mobile, layout, isSavePreferences, setLayout, setIsSavePreferences}
return {mobile, layout, isSavePreferences, language, setLayout, setIsSavePreferences, setLanguage}
}
export default UsePreferences;

@ -5,6 +5,7 @@ import { loadPreferences, removePreferences, savePreferences } from "./local_sto
export interface PreferencesState {
layout: "mobile" | "auto" | "desktop";
isSavePreferences: boolean;
language: string;
}
export function getWindowDimensions() {
@ -16,7 +17,8 @@ export const AUTO_SWITCH_THRESHOLD = 800
const initialState: PreferencesState = loadPreferences() ??{
layout: "auto",
isSavePreferences: false
isSavePreferences: false,
language: "en",
}
export const preferencesSlice = createSlice({
@ -29,7 +31,10 @@ export const preferencesSlice = createSlice({
setIsSavePreferences: (state, action) => {
state.isSavePreferences = action.payload;
},
setLanguage: (state, action) => {
state.language = action.payload;
},
},
});
export const { setLayout, setIsSavePreferences } = preferencesSlice.actions;
export const { setLayout, setIsSavePreferences, setLanguage } = preferencesSlice.actions;

Loading…
Cancel
Save