Skip to content

Commit 7da54be

Browse files
committed
SettingsModal: GeneralTab: use components to handle state
1 parent ca638e3 commit 7da54be

3 files changed

Lines changed: 84 additions & 83 deletions

File tree

fission/src/ui/components/Checkbox.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { SoundPlayer } from "@/systems/sound/SoundPlayer"
44
import Label from "./Label"
55
import { LabelWithTooltip } from "./StyledComponents"
66

7-
type CheckboxProps = {
7+
export type CheckboxProps = {
88
/**
99
* The label text that will be on the right of the checkbox.
1010
*/

fission/src/ui/components/StatefulSlider.tsx

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@ import { Slider, Stack, Tooltip, Typography } from "@mui/material"
22
import Label from "./Label"
33
import { useEffect, useState } from "react"
44

5-
const StatefulSlider: React.FC<
6-
Omit<Parameters<typeof Slider>[0], "value" | "onChange"> & {
7-
label: string
8-
defaultValue: number
9-
onChange: (val: number) => void
10-
tooltip?: string
11-
showValue?: boolean
12-
}
13-
> = props => {
5+
export type StatefulSliderProps = Omit<Parameters<typeof Slider>[0], "value" | "onChange"> & {
6+
label: string
7+
defaultValue: number
8+
onChange: (val: number) => void
9+
tooltip?: string
10+
showValue?: boolean
11+
}
12+
13+
const StatefulSlider: React.FC<StatefulSliderProps> = props => {
1414
const [value, setValue] = useState(props.defaultValue)
1515

1616
useEffect(() => {

fission/src/ui/modals/configuring/SettingsModal.tsx

Lines changed: 74 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
import { Box, Stack, Tab, Tabs, TextField } from "@mui/material"
22
import type React from "react"
3-
import { useCallback, useEffect, useReducer, useState } from "react"
3+
import { useCallback, useEffect, useState } from "react"
44
import { globalAddToast, globalOpenModal } from "@/components/GlobalUIControls.ts"
55
import PreferencesSystem from "@/systems/preferences/PreferencesSystem"
6-
import type { UserPreference, UserPreferences } from "@/systems/preferences/PreferenceTypes"
6+
import type { UserPreferences } from "@/systems/preferences/PreferenceTypes"
77
import { SoundPlayer } from "@/systems/sound/SoundPlayer"
88
import World from "@/systems/World"
9-
import Checkbox from "@/ui/components/Checkbox"
9+
import Checkbox, { type CheckboxProps } from "@/ui/components/Checkbox"
1010
import Label from "@/ui/components/Label"
1111
import type { ModalImplProps } from "@/ui/components/Modal"
12-
import StatefulSlider from "@/ui/components/StatefulSlider"
12+
import StatefulSlider, { type StatefulSliderProps } from "@/ui/components/StatefulSlider"
1313
import { Button, Spacer, SynthesisIcons } from "@/ui/components/StyledComponents"
1414
import { useThemeContext } from "@/ui/helpers/ThemeProviderHelpers"
1515
import { useUIContext } from "@/ui/helpers/UIProviderHelpers"
@@ -52,10 +52,6 @@ type ThemeEditorTabActions = {
5252
reset: () => void
5353
}
5454

55-
type GeneralTabProps = {
56-
writePreference: <K extends UserPreference>(pref: K, value: UserPreferences[K]) => void
57-
}
58-
5955
type GraphicsTabProps = {
6056
onActionsChange?: (actions: GraphicsTabActions) => void
6157
}
@@ -71,7 +67,7 @@ interface TabConfigBase {
7167

7268
interface GeneralTabConfig extends TabConfigBase {
7369
key: "general"
74-
component: React.ComponentType<GeneralTabProps>
70+
component: React.ComponentType
7571
}
7672

7773
interface GraphicsTabConfig extends TabConfigBase {
@@ -113,112 +109,123 @@ const ColorEditor: React.FC<{
113109
)
114110
}
115111

116-
const GeneralTab: React.FC<GeneralTabProps> = ({ writePreference }) => (
112+
type TypedPreferenceKey<T> = {
113+
[K in keyof UserPreferences]: UserPreferences[K] extends T ? K : never
114+
}[keyof UserPreferences]
115+
116+
const GeneralTabSlider = ({
117+
preference,
118+
label,
119+
...props
120+
}: Omit<StatefulSliderProps, "defaultValue" | "onChange"> & { preference: TypedPreferenceKey<number> }) => {
121+
const [pref, setPref] = useState(PreferencesSystem.getUserPreference(preference))
122+
useEffect(() => {
123+
PreferencesSystem.setUserPreference(preference, pref)
124+
}, [pref])
125+
126+
return <StatefulSlider {...props} label={label} defaultValue={pref} onChange={setPref} />
127+
}
128+
129+
const GeneralTabCheckbox = ({
130+
preference,
131+
label,
132+
...props
133+
}: Omit<CheckboxProps, "checked" | "onClick"> & { preference: TypedPreferenceKey<boolean> }) => {
134+
const [pref, setPref] = useState(PreferencesSystem.getUserPreference(preference))
135+
useEffect(() => {
136+
PreferencesSystem.setUserPreference(preference, pref)
137+
}, [pref])
138+
139+
return <Checkbox {...props} label={label} checked={pref} onClick={setPref} />
140+
}
141+
142+
const GeneralTab: React.FC = () => (
117143
<Stack direction="column" gap={2}>
118144
<Spacer height={5} />
119145
<Label size="sm">Camera Settings</Label>
120-
<StatefulSlider
146+
<GeneralTabSlider
147+
preference="SceneRotationSensitivity"
148+
label="Scene Rotation Sensitivity"
149+
tooltip="Controls how fast the scene rotates when dragging with the mouse."
150+
showValue={false}
121151
min={0.1}
122152
max={2.0}
123-
defaultValue={PreferencesSystem.getUserPreference("SceneRotationSensitivity")}
124-
label={"Scene Rotation Sensitivity"}
125-
onChange={value => writePreference("SceneRotationSensitivity", value)}
126153
step={0.1}
127-
tooltip="Controls how fast the scene rotates when dragging with the mouse."
128-
showValue={false}
129154
/>
130155
<Spacer height={5} />
131-
<StatefulSlider
156+
<GeneralTabSlider
157+
preference="ScenePanSensitivity"
158+
label="Scene Pan Sensitivity"
159+
tooltip="Controls how fast the scene pans when dragging with the right mouse button."
160+
showValue={false}
132161
min={0.1}
133162
max={3.0}
134-
defaultValue={PreferencesSystem.getUserPreference("ScenePanSensitivity")}
135-
label={"Scene Pan Sensitivity"}
136-
onChange={value => writePreference("ScenePanSensitivity", value)}
137163
step={0.1}
138-
tooltip="Controls how fast the scene pans when dragging with the right mouse button."
139-
showValue={false}
140164
/>
141165
<Spacer height={5} />
142-
<StatefulSlider
166+
<GeneralTabSlider
167+
preference="ViewCubeRotationSensitivity"
168+
label="ViewCube Rotation Sensitivity"
169+
tooltip="Controls how fast the view changes when dragging on the view cube."
170+
showValue={false}
143171
min={0.06}
144172
max={6.0}
145-
defaultValue={PreferencesSystem.getUserPreference("ViewCubeRotationSensitivity")}
146-
label={"ViewCube Rotation Sensitivity"}
147-
onChange={value => writePreference("ViewCubeRotationSensitivity", value)}
148173
step={0.06}
149-
tooltip="Controls how fast the view changes when dragging on the view cube."
150-
showValue={false}
151174
/>
152-
<Checkbox
175+
<GeneralTabCheckbox
176+
preference="ShowViewCube"
153177
label="Show View Cube"
154-
checked={PreferencesSystem.getUserPreference("ShowViewCube")}
155-
onClick={checked => writePreference("ShowViewCube", checked)}
156178
tooltip="Show the view cube in the top-right corner for quick camera orientation changes."
157179
/>
158180
<Spacer height={10} />
159181
<Label size="md" sx={{ fontWeight: 600 }}>
160182
Preferences
161183
</Label>
162184
<Stack direction="column">
163-
<Checkbox
185+
<GeneralTabCheckbox
186+
preference="ReportAnalytics"
164187
label="Report Analytics"
165-
checked={PreferencesSystem.getUserPreference("ReportAnalytics")}
166-
onClick={checked => writePreference("ReportAnalytics", checked)}
167188
tooltip="Record user data such as what robots are spawned and how they are configured. No personal data will be collected."
168189
/>
169-
<Checkbox
190+
<GeneralTabCheckbox
191+
preference="SubsystemGravity"
170192
label="Realistic Subsystem Gravity"
171-
checked={PreferencesSystem.getUserPreference("SubsystemGravity")}
172-
onClick={checked => writePreference("SubsystemGravity", checked)}
173193
tooltip="Allows you to set a target torque or force for subsystems and joints. If not properly configured, joints may not be able to resist gravity or may not behave as intended."
174194
/>
175-
<Checkbox
195+
<GeneralTabCheckbox
196+
preference="RenderScoringZones"
176197
label="Show Score Zones"
177-
checked={PreferencesSystem.getUserPreference("RenderScoringZones")}
178-
onClick={checked => writePreference("RenderScoringZones", checked)}
179198
tooltip="If disabled, scoring zones will not be visible but will continue to function the same."
180199
/>
181-
<Checkbox
200+
<GeneralTabCheckbox
201+
preference="RenderProtectedZones"
182202
label="Show Protected Zones"
183-
checked={PreferencesSystem.getUserPreference("RenderProtectedZones")}
184-
onClick={checked => writePreference("RenderProtectedZones", checked)}
185203
tooltip="If disabled, protected zones will not be visible but will continue to function the same."
186204
/>
187-
<Checkbox
205+
<GeneralTabCheckbox
206+
preference="RenderSceneTags"
188207
label="Show Scene Tags"
189-
checked={PreferencesSystem.getUserPreference("RenderSceneTags")}
190-
onClick={checked => writePreference("RenderSceneTags", checked)}
191208
tooltip="Name tags above robot."
192209
/>
193-
<Checkbox
210+
<GeneralTabCheckbox
211+
preference="RenderScoreboard"
194212
label="Show Scoreboard"
195-
checked={PreferencesSystem.getUserPreference("RenderScoreboard")}
196-
onClick={checked => {
197-
writePreference("RenderScoreboard", checked)
198-
if (checked) {
199-
// TODO: figure out scoreboard - I think it should be its own component and not a panel
200-
// openPanel("scoreboard");
201-
}
202-
}}
203213
/>
204-
<Checkbox
214+
<GeneralTabCheckbox
215+
preference="ShowCenterOfMassIndicators"
205216
label="Show Centers of Mass"
206-
checked={PreferencesSystem.getUserPreference("ShowCenterOfMassIndicators")}
207-
onClick={checked => writePreference("ShowCenterOfMassIndicators", checked)}
208217
tooltip="Show a purple dot to indicate the center of mass of each robot in frame"
209218
/>
210-
<Checkbox
219+
<GeneralTabCheckbox
220+
preference="MuteAllSound"
211221
label="Mute All Sound"
212-
checked={PreferencesSystem.getUserPreference("MuteAllSound")}
213-
onClick={checked => writePreference("MuteAllSound", checked)}
214222
/>
215-
<StatefulSlider
223+
<GeneralTabSlider
224+
preference="SFXVolume"
225+
label="SFX Volume"
226+
tooltip="Volume of sound effects (%)."
216227
min={0}
217228
max={100}
218-
defaultValue={PreferencesSystem.getUserPreference("SFXVolume")}
219-
label={"SFX Volume"}
220-
onChange={value => writePreference("SFXVolume", value)}
221-
tooltip="Volume of sound effects (%)."
222229
/>
223230
</Stack>
224231
</Stack>
@@ -539,7 +546,6 @@ interface SettingsModalCustomProps {
539546

540547
const SettingsModal: React.FC<ModalImplProps<void, SettingsModalCustomProps | undefined>> = ({ modal }) => {
541548
const { configureScreen } = useUIContext()
542-
const [_, refresh] = useReducer(x => !x, false)
543549
const [activeTab, setActiveTab] = useState<string>(modal?.props.custom?.initialTab || "general")
544550

545551
const [graphicsActions, setGraphicsActions] = useState<GraphicsTabActions | null>(null)
@@ -552,11 +558,6 @@ const SettingsModal: React.FC<ModalImplProps<void, SettingsModalCustomProps | un
552558
{ key: "theme", label: "Theme Editor", component: ThemeEditorTab },
553559
]
554560

555-
const writePreference = <K extends UserPreference>(pref: K, value: UserPreferences[K]) => {
556-
PreferencesSystem.setUserPreference(pref, value)
557-
refresh()
558-
}
559-
560561
const save = useCallback(() => {
561562
if (graphicsActions) {
562563
graphicsActions.save()
@@ -595,7 +596,7 @@ const SettingsModal: React.FC<ModalImplProps<void, SettingsModalCustomProps | un
595596
switch (currentTab.key) {
596597
case "general": {
597598
const GeneralComponent = currentTab.component
598-
return <GeneralComponent writePreference={writePreference} />
599+
return <GeneralComponent />
599600
}
600601
case "graphics": {
601602
const GraphicsComponent = currentTab.component

0 commit comments

Comments
 (0)