Skip to content

Commit c919402

Browse files
authored
[Fix] multiple settings writes (#1464)
* Fix multiple settings saves * Fix linter (??) * Move type hint to the state instead of the prop
1 parent 35af57f commit c919402

File tree

3 files changed

+165
-92
lines changed

3 files changed

+165
-92
lines changed

electron/main.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -721,6 +721,12 @@ ipcMain.on('toggleVKD3D', (event, [{ winePrefix, winePath }, action]) => {
721721
})
722722

723723
ipcMain.handle('writeConfig', (event, [appName, config]) => {
724+
logInfo(
725+
`Writing config for ${appName === 'default' ? 'Heroic' : appName}`,
726+
LogPrefix.Backend
727+
)
728+
// use 2 spaces for pretty print
729+
logInfo(JSON.stringify(config, null, 2), LogPrefix.Backend)
724730
if (appName === 'default') {
725731
GlobalConfig.get().config = config
726732
GlobalConfig.get().flush()

src/screens/Settings/components/AdvancedSettings/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ export const AdvancedSettings = ({
216216
isSuccess: isCopiedToClipboard
217217
})}
218218
onClick={() => {
219-
clipboard.writeText(JSON.stringify({ ...settingsToSave }))
219+
clipboard.writeText(JSON.stringify({ ...settingsToSave }, null, 2))
220220
setCopiedToClipboard(true)
221221
}}
222222
>

src/screens/Settings/index.tsx

Lines changed: 158 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,11 @@ function Settings() {
181181
const [autoSyncSaves, setAutoSyncSaves] = useState(false)
182182
const [altWine, setAltWine] = useState([] as WineInstallation[])
183183

184+
const [configLoaded, setConfigLoaded] = useState(false)
185+
const [settingsToSave, setSettingsToSave] = useState<AppSettings>(
186+
{} as AppSettings
187+
)
188+
184189
const { appName = '', type = '' } = useParams()
185190
const isDefault = appName === 'default'
186191
const isGeneralSettings = type === 'general'
@@ -190,79 +195,162 @@ function Settings() {
190195
const isLogSettings = type === 'log'
191196
const isAdvancedSetting = type === 'advanced' && isDefault
192197

198+
// Load Heroic's or game's config, only if not loaded already
193199
useEffect(() => {
194200
const getSettings = async () => {
195-
const config: AppSettings = await ipcRenderer.invoke(
196-
'requestSettings',
197-
appName
198-
)
199-
setAutoSyncSaves(config.autoSyncSaves)
200-
setUseGameMode(config.useGameMode)
201-
setShowFps(config.showFps)
202-
setShowOffline(config.offlineMode)
203-
setAudioFix(config.audioFix)
204-
setShowMangoHud(config.showMangohud)
205-
setDefaultInstallPath(config.defaultInstallPath)
206-
setWineVersion(config.wineVersion)
207-
setWinePrefix(config.winePrefix)
208-
setWineCrossoverBottle(config.wineCrossoverBottle)
209-
setOtherOptions(config.otherOptions)
210-
setLauncherArgs(config.launcherArgs)
211-
setUseNvidiaPrime(config.nvidiaPrime)
212-
setEgsLinkedPath(config.egsLinkedPath || '')
213-
setEgsPath(config.egsLinkedPath || '')
214-
setExitToTray(config.exitToTray)
215-
setStartInTray(config.startInTray)
216-
setMinimizeOnLaunch(config.minimizeOnLaunch)
217-
setDarkTrayIcon(config.darkTrayIcon)
218-
setDiscordRPC(config.discordRPC)
219-
setAutoInstallDxvk(config.autoInstallDxvk)
220-
setAutoInstallVkd3d(config.autoInstallVkd3d)
221-
setEnableEsync(config.enableEsync)
222-
setEnableFsync(config.enableFsync)
223-
setEnableFSR(config.enableFSR)
224-
setFsrSharpness(config.maxSharpness || 2)
225-
setResizableBar(config.enableResizableBar)
226-
setSavesPath(config.savesPath || '')
227-
setMaxWorkers(config.maxWorkers ?? 0)
228-
setMaxRecentGames(config.maxRecentGames ?? 5)
229-
setCustomWinePaths(config.customWinePaths || [])
230-
setAddDesktopShortcuts(config.addDesktopShortcuts)
231-
setAddGamesToStartMenu(config.addStartMenuShortcuts)
232-
setCustomWinePaths(config.customWinePaths || [])
233-
setTargetExe(config.targetExe || '')
234-
setAltLegendaryBin(config.altLegendaryBin || '')
235-
setAltGogdlBin(config.altGogdlBin || '')
236-
setShowUnrealMarket(config.showUnrealMarket)
237-
setDefaultWinePrefix(config.defaultWinePrefix)
238-
setUseSteamRuntime(config.useSteamRuntime)
239-
setDisableController(config.disableController || false)
201+
if (!configLoaded) {
202+
const config: AppSettings = await ipcRenderer.invoke(
203+
'requestSettings',
204+
appName
205+
)
206+
setAutoSyncSaves(config.autoSyncSaves)
207+
setUseGameMode(config.useGameMode)
208+
setShowFps(config.showFps)
209+
setShowOffline(config.offlineMode)
210+
setAudioFix(config.audioFix)
211+
setShowMangoHud(config.showMangohud)
212+
setDefaultInstallPath(config.defaultInstallPath)
213+
setWineVersion(config.wineVersion)
214+
setWinePrefix(config.winePrefix)
215+
setWineCrossoverBottle(config.wineCrossoverBottle)
216+
setOtherOptions(config.otherOptions)
217+
setLauncherArgs(config.launcherArgs)
218+
setUseNvidiaPrime(config.nvidiaPrime)
219+
setEgsLinkedPath(config.egsLinkedPath || '')
220+
setEgsPath(config.egsLinkedPath || '')
221+
setExitToTray(config.exitToTray)
222+
setStartInTray(config.startInTray)
223+
setMinimizeOnLaunch(config.minimizeOnLaunch)
224+
setDarkTrayIcon(config.darkTrayIcon)
225+
setDiscordRPC(config.discordRPC)
226+
setAutoInstallDxvk(config.autoInstallDxvk)
227+
setAutoInstallVkd3d(config.autoInstallVkd3d)
228+
setEnableEsync(config.enableEsync)
229+
setEnableFsync(config.enableFsync)
230+
setEnableFSR(config.enableFSR)
231+
setFsrSharpness(config.maxSharpness || 2)
232+
setResizableBar(config.enableResizableBar)
233+
setSavesPath(config.savesPath || '')
234+
setMaxWorkers(config.maxWorkers ?? 0)
235+
setMaxRecentGames(config.maxRecentGames ?? 5)
236+
setCustomWinePaths(config.customWinePaths || [])
237+
setAddDesktopShortcuts(config.addDesktopShortcuts)
238+
setAddGamesToStartMenu(config.addStartMenuShortcuts)
239+
setCustomWinePaths(config.customWinePaths || [])
240+
setTargetExe(config.targetExe || '')
241+
setAltLegendaryBin(config.altLegendaryBin || '')
242+
setAltGogdlBin(config.altGogdlBin || '')
243+
setShowUnrealMarket(config.showUnrealMarket)
244+
setDefaultWinePrefix(config.defaultWinePrefix)
245+
setUseSteamRuntime(config.useSteamRuntime)
246+
setDisableController(config.disableController || false)
247+
248+
if (!isDefault) {
249+
setLanguageCode(config.language)
250+
const { title: gameTitle, canRunOffline: can_run_offline } =
251+
await getGameInfo(appName, runner)
252+
setCanRunOffline(can_run_offline)
253+
setTitle(gameTitle)
254+
} else {
255+
setTitle(t('globalSettings', 'Global Settings'))
256+
}
240257

241-
if (!isDefault) {
242-
setLanguageCode(config.language)
243-
const { title: gameTitle, canRunOffline: can_run_offline } =
244-
await getGameInfo(appName, runner)
245-
setCanRunOffline(can_run_offline)
246-
setTitle(gameTitle)
247-
} else {
248-
setTitle(t('globalSettings', 'Global Settings'))
258+
setSettingsToSaveState()
249259
}
250260
}
251261
getSettings()
262+
}, [appName, type, isDefault, i18n.language])
263+
264+
let returnPath = '/'
252265

253-
return () => {
254-
ipcRenderer.removeAllListeners('requestSettings')
266+
if (!fromGameCard) {
267+
returnPath = `/gamepage/${appName}`
268+
if (returnPath === '/gamepage/default') {
269+
returnPath = '/'
255270
}
256-
}, [appName, type, isDefault, i18n.language])
271+
}
272+
273+
// Helper function to update the `settingsToSave` state
274+
const setSettingsToSaveState = () => {
275+
const GlobalSettings = {
276+
altLegendaryBin,
277+
altGogdlBin,
278+
addDesktopShortcuts,
279+
addStartMenuShortcuts,
280+
audioFix,
281+
autoInstallDxvk,
282+
autoInstallVkd3d,
283+
customWinePaths,
284+
darkTrayIcon,
285+
defaultInstallPath,
286+
defaultWinePrefix,
287+
disableController,
288+
discordRPC,
289+
egsLinkedPath,
290+
enableEsync,
291+
enableFsync,
292+
exitToTray,
293+
maxRecentGames,
294+
maxWorkers,
295+
minimizeOnLaunch,
296+
nvidiaPrime,
297+
otherOptions,
298+
showFps,
299+
showMangohud,
300+
showUnrealMarket,
301+
startInTray,
302+
useGameMode,
303+
wineCrossoverBottle,
304+
winePrefix,
305+
wineVersion,
306+
enableFSR,
307+
enableResizableBar
308+
} as AppSettings
309+
310+
const GameSettings = {
311+
audioFix,
312+
autoInstallDxvk,
313+
autoInstallVkd3d,
314+
autoSyncSaves,
315+
enableEsync,
316+
enableFSR,
317+
enableFsync,
318+
maxSharpness,
319+
enableResizableBar,
320+
language: languageCode,
321+
launcherArgs,
322+
nvidiaPrime,
323+
offlineMode,
324+
otherOptions,
325+
savesPath,
326+
showFps,
327+
showMangohud,
328+
targetExe,
329+
useGameMode,
330+
wineCrossoverBottle,
331+
winePrefix,
332+
wineVersion,
333+
useSteamRuntime
334+
} as AppSettings
257335

258-
const GlobalSettings = {
336+
setSettingsToSave(isDefault ? GlobalSettings : GameSettings)
337+
}
338+
339+
// update the settingsToSave state when any of the configurations changes
340+
// but only after the configuration was loaded
341+
useEffect(() => {
342+
if (configLoaded) {
343+
setSettingsToSaveState()
344+
}
345+
}, [
259346
altLegendaryBin,
260347
altGogdlBin,
261348
addDesktopShortcuts,
262349
addStartMenuShortcuts,
263350
audioFix,
264351
autoInstallDxvk,
265352
autoInstallVkd3d,
353+
autoSyncSaves,
266354
customWinePaths,
267355
darkTrayIcon,
268356
defaultInstallPath,
@@ -275,6 +363,7 @@ function Settings() {
275363
exitToTray,
276364
maxRecentGames,
277365
maxWorkers,
366+
maxSharpness,
278367
minimizeOnLaunch,
279368
nvidiaPrime,
280369
otherOptions,
@@ -287,48 +376,26 @@ function Settings() {
287376
winePrefix,
288377
wineVersion,
289378
enableFSR,
290-
enableResizableBar
291-
} as AppSettings
292-
293-
const GameSettings = {
294-
audioFix,
295-
autoInstallDxvk,
296-
autoInstallVkd3d,
297-
autoSyncSaves,
298-
enableEsync,
299-
enableFSR,
300-
enableFsync,
301-
maxSharpness,
302379
enableResizableBar,
303-
language: languageCode,
380+
languageCode,
304381
launcherArgs,
305-
nvidiaPrime,
306382
offlineMode,
307-
otherOptions,
308383
savesPath,
309-
showFps,
310-
showMangohud,
311384
targetExe,
312-
useGameMode,
313-
wineCrossoverBottle,
314-
winePrefix,
315-
wineVersion,
316385
useSteamRuntime
317-
} as AppSettings
318-
319-
const settingsToSave = isDefault ? GlobalSettings : GameSettings
320-
let returnPath = '/'
321-
322-
if (!fromGameCard) {
323-
returnPath = `/gamepage/${appName}`
324-
if (returnPath === '/gamepage/default') {
325-
returnPath = '/'
326-
}
327-
}
386+
])
328387

388+
// when the settingsToSave state changes:
389+
// - write the config if it completed loading before
390+
// - set the `configLoaded` state to ensure it can only be written after loaded
329391
useEffect(() => {
330-
writeConfig([appName, settingsToSave])
331-
}, [GlobalSettings, GameSettings, appName])
392+
if (configLoaded) {
393+
writeConfig([appName, settingsToSave])
394+
} else {
395+
// initial state is {}, consider loaded when the object has keys in it
396+
setConfigLoaded(Object.keys(settingsToSave).length > 0)
397+
}
398+
}, [settingsToSave])
332399

333400
if (!title) {
334401
return <UpdateComponent />

0 commit comments

Comments
 (0)