Feat: Add live reloading of configuration file (#684)

* Add live reloading of configuration file

This also removes the need for a file with all the available
configuration and a shadow configuration file.

Additionally, added several improvements:
1. Reduce I/O on initial configuration loading by only reading file once
2. Remove unnecesary back and forth events when editing configuration

* Add missing return type

* Consistently reset on config changes and error if failed to initialize config

* Fix massive I/O load on startup by numerical options

* Use _findVal when monitoring config file

* Apply PR requested changes

Signed-off-by: davfsa <davfsa@gmail.com>

* Add missing =>

Signed-off-by: davfsa <davfsa@gmail.com>

* Fix reassignment to const, change to let.

---------

Signed-off-by: davfsa <davfsa@gmail.com>
Co-authored-by: Jas Singh <jaskiratpal.singh@outlook.com>
This commit is contained in:
davfsa
2025-03-16 10:39:25 +01:00
committed by GitHub
parent 50faa14621
commit a949b34632
8 changed files with 170 additions and 181 deletions

View File

@@ -272,32 +272,23 @@ export const importFiles = (themeOnly: boolean = false): void => {
iconName: icons.ui.info,
});
const tmpConfigFile = Gio.File.new_for_path(`${TMP}/config.json`);
const optionsConfigFile = Gio.File.new_for_path(CONFIG);
const [tmpSuccess, tmpContent] = tmpConfigFile.load_contents(null);
const [optionsSuccess, optionsContent] = optionsConfigFile.load_contents(null);
if (!tmpSuccess || !optionsSuccess) {
console.error('Failed to read existing configuration files.');
if (!optionsSuccess) {
console.error('Failed to read existing configuration file.');
dialog.destroy();
return;
}
let tmpConfig = JSON.parse(new TextDecoder('utf-8').decode(tmpContent));
let optionsConfig = JSON.parse(new TextDecoder('utf-8').decode(optionsContent));
if (themeOnly) {
const filteredConfig = filterConfigForThemeOnly(importedConfig);
tmpConfig = { ...tmpConfig, ...filteredConfig };
optionsConfig = { ...optionsConfig, ...filteredConfig };
} else {
const filteredConfig = filterConfigForNonTheme(importedConfig);
tmpConfig = { ...tmpConfig, ...filteredConfig };
optionsConfig = { ...optionsConfig, ...filteredConfig };
}
const filteredConfig = themeOnly
? filterConfigForThemeOnly(importedConfig)
: filterConfigForNonTheme(importedConfig);
optionsConfig = { ...optionsConfig, ...filteredConfig };
saveConfigToFile(tmpConfig, `${TMP}/config.json`);
saveConfigToFile(optionsConfig, CONFIG);
}
dialog.destroy();

View File

@@ -31,7 +31,6 @@ export const BooleanInputter = <T extends string | number | boolean | object>({
interface BooleanInputterProps<T> {
opt: Opt<T>;
isUnsaved?: Variable<boolean>;
disabledBinding?: Variable<boolean>;
dependencies?: string[];
}

View File

@@ -29,14 +29,18 @@ export const NumberInputter = <T extends string | number | boolean | object>({
})}
</box>
<SpinButton
onChanged={(self) => {
const currentText = self.value;
const optValue = opt.get();
isUnsaved.set(currentText !== optValue);
}}
onActivate={(self) => {
opt.set(self.value as T);
}}
setup={(self) => {
self.set_range(min, max);
self.set_increments(1 * increment, 5 * increment);
self.connect('value-changed', () => {
opt.set(self.value as T);
});
useHook(self, opt, () => {
self.set_value(opt.get() as number);
isUnsaved.set(Number(self.get_text()) !== opt.get());