Skip to content

Commit 5eda2f5

Browse files
author
Oskar Widmark
committed
feat: add persistent settings
1 parent a3e4b5c commit 5eda2f5

File tree

4 files changed

+138
-94
lines changed

4 files changed

+138
-94
lines changed

src/App.tsx

Lines changed: 100 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,9 @@ import {
2121
} from './utils';
2222
import { SideDrawer } from './SideDrawer';
2323
import {
24-
INIT_COLUMN_NUMBER,
25-
INIT_SWAP_TIME,
26-
INIT_COMPARE_TIME,
27-
DEFAULT_ALGORITHM_OPTIONS,
28-
DEFAULT_COLUMN_COLOR,
29-
DEFAULT_BACKGROUND_COLOR,
30-
DEFAULT_HIGHLIGHT_COLOR,
3124
RAINBOW_BACKGROUND_COLOR,
25+
INIT_STATE,
26+
INIT_SETTINGS,
3227
} from './constants';
3328
import { SortAppBar } from './AppBar';
3429
import { CanvasController } from './canvas-controller';
@@ -48,74 +43,89 @@ class App extends React.Component<Props> {
4843
state: {
4944
isSorting: boolean;
5045
areSettingsOpen: boolean;
51-
chosenSortAlg: SortName;
52-
columnNbr: number;
53-
compareTime: number;
54-
swapTime: number;
5546
canDraw: boolean;
47+
shouldPlaySound: boolean;
5648
nbrOfSwaps: number;
5749
nbrOfComparisons: number;
58-
resetPreset: ResetPreset;
59-
shouldHighlightSwaps: boolean;
60-
shouldHighlightComparisons: boolean;
61-
shouldPlaySound: boolean;
62-
algorithmOptions: AlgorithmOptions;
63-
colorPreset: ColorPreset;
64-
columnColor: string;
65-
backgroundColor: string;
66-
highlightColor: string;
50+
settings: {
51+
chosenSortAlg: SortName;
52+
columnNbr: number;
53+
swapTime: number;
54+
compareTime: number;
55+
resetPreset: ResetPreset;
56+
algorithmOptions: AlgorithmOptions;
57+
colorPreset: ColorPreset;
58+
columnColor: string;
59+
backgroundColor: string;
60+
highlightColor: string;
61+
};
6762
};
6863
canvasController: CanvasController;
6964

7065
constructor(public props: Props) {
7166
super(props);
7267

68+
const storedSettings = localStorage.getItem('settings');
69+
this.state = {
70+
...INIT_STATE,
71+
settings: {
72+
...INIT_SETTINGS,
73+
...(storedSettings ? JSON.parse(storedSettings) : {}),
74+
},
75+
};
76+
7377
this.sortingAlgorithms = new SortingAlgorithms(
74-
INIT_COLUMN_NUMBER,
78+
this.state.settings.columnNbr,
7579
this.compare,
7680
this.drawAndSwap,
7781
);
7882

79-
this.arr = createArr(INIT_COLUMN_NUMBER);
80-
shuffleArray(this.arr);
81-
this.state = {
82-
isSorting: false,
83-
areSettingsOpen: false,
84-
chosenSortAlg: SortName.InsertionSort,
85-
columnNbr: INIT_COLUMN_NUMBER,
86-
swapTime: INIT_SWAP_TIME,
87-
compareTime: INIT_COMPARE_TIME,
88-
canDraw: false,
89-
nbrOfSwaps: 0,
90-
nbrOfComparisons: 0,
91-
resetPreset: ResetPreset.Shuffle,
92-
shouldHighlightSwaps: true,
93-
shouldHighlightComparisons: false,
94-
shouldPlaySound: false,
95-
algorithmOptions: DEFAULT_ALGORITHM_OPTIONS,
96-
colorPreset: ColorPreset.Rainbow,
97-
columnColor: DEFAULT_COLUMN_COLOR,
98-
backgroundColor: DEFAULT_BACKGROUND_COLOR,
99-
highlightColor: DEFAULT_HIGHLIGHT_COLOR,
100-
};
101-
10283
this.resetPresets = {
10384
[ResetPreset.Shuffle]: () => shuffleArray(this.arr),
10485
[ResetPreset.Sorted]: () => this.arr.sort((a, b) => a.value - b.value),
10586
[ResetPreset.ReverseSorted]: () =>
10687
this.arr.sort((a, b) => b.value - a.value),
10788
};
10889

90+
this.arr = createArr(this.state.settings.columnNbr);
91+
this.resetPresets[this.state.settings.resetPreset]();
92+
10993
const ref = React.createRef<HTMLCanvasElement>();
11094
this.canvasController = new CanvasController(
11195
ref as React.RefObject<HTMLCanvasElement>,
112-
INIT_COLUMN_NUMBER,
113-
this.state.colorPreset,
114-
this.state.columnColor,
115-
this.state.highlightColor,
96+
this.state.settings.columnNbr,
97+
this.state.settings.colorPreset,
98+
this.state.settings.columnColor,
99+
this.state.settings.highlightColor,
116100
);
117101
}
118102

103+
setSettings = (
104+
settings:
105+
| Partial<typeof this.state.settings>
106+
| ((
107+
prevSettings: typeof this.state.settings,
108+
) => Partial<typeof this.state.settings>),
109+
callback?: () => Promise<void> | void,
110+
) => {
111+
this.setState(
112+
(prevState: typeof this.state) => {
113+
const newSettings =
114+
settings instanceof Function
115+
? settings(prevState.settings)
116+
: settings;
117+
return {
118+
...prevState,
119+
settings: { ...prevState.settings, ...newSettings },
120+
};
121+
},
122+
async () => {
123+
await callback?.();
124+
localStorage.setItem('settings', JSON.stringify(this.state.settings));
125+
},
126+
);
127+
};
128+
119129
resizeCanvas = () => {
120130
this.canvasController.resizeCanvas(this.arr);
121131
};
@@ -161,8 +171,8 @@ class App extends React.Component<Props> {
161171
async () => {
162172
try {
163173
await this.sortingAlgorithms.getSortingAlgorithm(
164-
this.state.chosenSortAlg,
165-
)(arr, this.state.algorithmOptions);
174+
this.state.settings.chosenSortAlg,
175+
)(arr, this.state.settings.algorithmOptions);
166176
} catch (e) {
167177
console.error('Sorting interrupted! Reason: ', e);
168178
}
@@ -190,14 +200,14 @@ class App extends React.Component<Props> {
190200
this.swap(arr, i1, i2);
191201
this.canvasController.redrawColumns(arr, [i1, i2]);
192202
this.nbrOfSwaps++;
193-
if (this.state.swapTime) {
203+
if (this.state.settings.swapTime) {
194204
// With a zero swapTime, maximum update depth will be exceeded
195205
// when updating state too often
196206
this.setState((prevState: typeof this.state) => ({
197207
nbrOfSwaps: prevState.nbrOfSwaps + 1,
198208
}));
199209
this.canvasController.highlightColumns(arr, [i1, i2]);
200-
await sleep(this.state.swapTime);
210+
await sleep(this.state.settings.swapTime);
201211
}
202212
};
203213

@@ -209,17 +219,20 @@ class App extends React.Component<Props> {
209219
): Promise<boolean> => {
210220
if (!this.state.isSorting) throw Error('isSorting is false!');
211221
this.nbrOfComparisons++;
212-
if (this.state.compareTime) {
222+
if (this.state.settings.compareTime) {
213223
// With a zero compareTime, maximum update depth will be exceeded
214224
// when updating state too often
215225
this.setState((prevState: typeof this.state) => ({
216226
nbrOfComparisons: prevState.nbrOfComparisons + 1,
217227
}));
218228
this.canvasController.highlightColumns(arr, [i1, i2]);
219-
await sleep(this.state.compareTime);
229+
await sleep(this.state.settings.compareTime);
220230
}
221231

222-
if (sortNameToSortType[this.state.chosenSortAlg] === SortType.Comparison) {
232+
if (
233+
sortNameToSortType[this.state.settings.chosenSortAlg] ===
234+
SortType.Comparison
235+
) {
223236
this.playSoundForColumn(arr, i1);
224237
}
225238

@@ -239,7 +252,8 @@ class App extends React.Component<Props> {
239252
if (!this.state.isSorting) throw Error('isSorting is false!');
240253

241254
if (
242-
sortNameToSortType[this.state.chosenSortAlg] === SortType.Distribution
255+
sortNameToSortType[this.state.settings.chosenSortAlg] ===
256+
SortType.Distribution
243257
) {
244258
this.playSoundForColumn(arr, i1);
245259
}
@@ -250,7 +264,9 @@ class App extends React.Component<Props> {
250264
playSoundForColumn = (arr: SortValue[], i: number) => {
251265
if (!this.state.shouldPlaySound) return;
252266

253-
this.props.setSoundPitch((arr[i].value * 7) / this.state.columnNbr + 3);
267+
this.props.setSoundPitch(
268+
(arr[i].value * 7) / this.state.settings.columnNbr + 3,
269+
);
254270
this.props.playSound();
255271
};
256272

@@ -265,37 +281,37 @@ class App extends React.Component<Props> {
265281
chooseSortAlg = (event: SelectChangeEvent<SortName>) => {
266282
this.stopSorting();
267283

268-
this.setState({ chosenSortAlg: event.target.value });
284+
this.setSettings({ chosenSortAlg: event.target.value as SortName });
269285
};
270286

271287
chooseResetPreset = (event: SelectChangeEvent<ResetPreset>) => {
272-
this.setState({ resetPreset: event.target.value });
288+
this.setSettings({ resetPreset: event.target.value as ResetPreset });
273289
};
274290

275291
changeColumnNbr = (_: unknown, value: number | number[]) => {
276292
const columnNbr = value instanceof Array ? value[0] : value;
277293
this.sortingAlgorithms.columnNbr = columnNbr;
278294
this.canvasController.columnNbr = columnNbr;
279-
this.setState({ columnNbr }, () => this.resetAndDraw());
295+
this.setSettings({ columnNbr }, () => this.resetAndDraw());
280296
};
281297

282298
changeSwapTime = (_: unknown, value: number | number[]) => {
283-
this.setState({
299+
this.setSettings({
284300
swapTime: timeScale(value instanceof Array ? value[0] : value),
285301
});
286302
};
287303

288304
changeCompareTime = (_: unknown, value: number | number[]) => {
289-
this.setState({
305+
this.setSettings({
290306
compareTime: timeScale(value instanceof Array ? value[0] : value),
291307
});
292308
};
293309

294310
resetAndDraw = () => {
295311
this.stopSorting();
296312
this.resetCounters();
297-
this.arr = createArr(this.state.columnNbr);
298-
this.resetPresets[this.state.resetPreset]();
313+
this.arr = createArr(this.state.settings.columnNbr);
314+
this.resetPresets[this.state.settings.resetPreset]();
299315
this.canvasController.redraw(this.arr);
300316
};
301317

@@ -337,42 +353,42 @@ class App extends React.Component<Props> {
337353
key: keyof AlgorithmOptions,
338354
value: AlgorithmOptions[typeof key],
339355
) => {
340-
this.setState((prevState: typeof this.state) => ({
341-
algorithmOptions: { ...prevState.algorithmOptions, [key]: value },
356+
this.setSettings((prevSettings) => ({
357+
algorithmOptions: { ...prevSettings.algorithmOptions, [key]: value },
342358
}));
343359
};
344360

345361
setColorPreset = (colorPreset: ColorPreset) => {
346-
this.setState({ colorPreset });
362+
this.setSettings({ colorPreset });
347363
this.canvasController.colorPreset = colorPreset;
348364
this.stopSorting();
349365
this.canvasController.redraw(this.arr);
350366
};
351367

352368
setColumnColor = (columnColor: string) => {
353-
this.setState({ columnColor });
369+
this.setSettings({ columnColor });
354370
this.canvasController.columnColor = columnColor;
355371
this.stopSorting();
356372
this.canvasController.redraw(this.arr);
357373
};
358374

359375
setBackgroundColor = (backgroundColor: string) => {
360-
this.setState({ backgroundColor });
376+
this.setSettings({ backgroundColor });
361377
};
362378

363379
setHighlightColor = (highlightColor: string) => {
364-
this.setState({ highlightColor });
380+
this.setSettings({ highlightColor });
365381
this.canvasController.highlightColor = highlightColor;
366382
this.stopSorting();
367383
this.canvasController.redraw(this.arr);
368384
};
369385

370386
getBackgroundColor = () => {
371-
switch (this.state.colorPreset) {
387+
switch (this.state.settings.colorPreset) {
372388
case ColorPreset.Rainbow:
373389
return RAINBOW_BACKGROUND_COLOR;
374390
case ColorPreset.Custom:
375-
return this.state.backgroundColor;
391+
return this.state.settings.backgroundColor;
376392
}
377393
};
378394

@@ -385,8 +401,8 @@ class App extends React.Component<Props> {
385401
<div className="App-header">
386402
<SortAppBar
387403
arr={this.arr}
388-
swapTime={this.state.swapTime}
389-
compareTime={this.state.compareTime}
404+
swapTime={this.state.settings.swapTime}
405+
compareTime={this.state.settings.compareTime}
390406
canDraw={this.state.canDraw}
391407
isSorting={this.state.isSorting}
392408
nbrOfSwaps={this.state.nbrOfSwaps}
@@ -415,21 +431,23 @@ class App extends React.Component<Props> {
415431
</div>
416432
<SideDrawer
417433
areSettingsOpen={this.state.areSettingsOpen}
418-
resetPreset={this.state.resetPreset}
419-
chosenSortAlg={this.state.chosenSortAlg}
434+
resetPreset={this.state.settings.resetPreset}
435+
chosenSortAlg={this.state.settings.chosenSortAlg}
420436
toggleDisplaySettings={this.toggleDisplaySettings}
421437
chooseSortAlg={this.chooseSortAlg}
422438
chooseResetPreset={this.chooseResetPreset}
423439
changeColumnNbr={this.changeColumnNbr}
424440
changeSwapTime={this.changeSwapTime}
425441
changeCompareTime={this.changeCompareTime}
426-
columnNbr={this.state.columnNbr}
427-
algorithmOptions={this.state.algorithmOptions}
442+
columnNbr={this.state.settings.columnNbr}
443+
swapTime={this.state.settings.swapTime}
444+
compareTime={this.state.settings.compareTime}
445+
algorithmOptions={this.state.settings.algorithmOptions}
428446
setAlgorithmOption={this.setAlgorithmOption}
429-
colorPreset={this.state.colorPreset}
430-
columnColor={this.state.columnColor}
431-
backgroundColor={this.state.backgroundColor}
432-
highlightColor={this.state.highlightColor}
447+
colorPreset={this.state.settings.colorPreset}
448+
columnColor={this.state.settings.columnColor}
449+
backgroundColor={this.state.settings.backgroundColor}
450+
highlightColor={this.state.settings.highlightColor}
433451
setColorPreset={this.setColorPreset}
434452
setColumnColor={this.setColumnColor}
435453
setBackgroundColor={this.setBackgroundColor}

0 commit comments

Comments
 (0)