Settings: Implement plugin options defaults (#117)
This commit is contained in:
parent
287173458f
commit
b66903cf52
@ -2,6 +2,7 @@ import plugins from "plugins";
|
||||
import IpcEvents from "../utils/IpcEvents";
|
||||
import { React } from "../webpack/common";
|
||||
import { mergeDefaults } from "../utils/misc";
|
||||
import { OptionType } from "../utils/types";
|
||||
|
||||
export interface Settings {
|
||||
notifyAboutUpdates: boolean;
|
||||
@ -30,9 +31,6 @@ for (const plugin in plugins) {
|
||||
|
||||
try {
|
||||
var settings = JSON.parse(VencordNative.ipc.sendSync(IpcEvents.GET_SETTINGS)) as Settings;
|
||||
for (const key in DefaultSettings) {
|
||||
settings[key] ??= DefaultSettings[key];
|
||||
}
|
||||
mergeDefaults(settings, DefaultSettings);
|
||||
} catch (err) {
|
||||
console.error("Corrupt settings file. ", err);
|
||||
@ -42,24 +40,52 @@ try {
|
||||
type SubscriptionCallback = ((newValue: any, path: string) => void) & { _path?: string; };
|
||||
const subscriptions = new Set<SubscriptionCallback>();
|
||||
|
||||
// Wraps the passed settings object in a Proxy to nicely handle change listeners and default values
|
||||
function makeProxy(settings: Settings, root = settings, path = ""): Settings {
|
||||
return new Proxy(settings, {
|
||||
get(target, p: string) {
|
||||
const v = target[p];
|
||||
|
||||
// using "in" is important in the following cases to properly handle falsy or nullish values
|
||||
if (!(p in target)) {
|
||||
// Since the property is not set, check if this is a plugin's setting and if so, try to resolve
|
||||
// the default value.
|
||||
if (path.startsWith("plugins.")) {
|
||||
const plugin = path.slice("plugins.".length);
|
||||
if (plugin in plugins) {
|
||||
const setting = plugins[plugin].options?.[p];
|
||||
if (!setting) return v;
|
||||
if ("default" in setting)
|
||||
// normal setting with a default value
|
||||
return setting.default;
|
||||
if (setting.type === OptionType.SELECT)
|
||||
return setting.options.find(o => o.default)?.value;
|
||||
}
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
// Recursively proxy Objects with the updated property path
|
||||
if (typeof v === "object" && !Array.isArray(v) && v !== null)
|
||||
return makeProxy(v, root, `${path}${path && "."}${p}`);
|
||||
|
||||
// primitive or similar, no need to proxy further
|
||||
return v;
|
||||
},
|
||||
|
||||
set(target, p: string, v) {
|
||||
// avoid unnecessary updates to React Components and other listeners
|
||||
if (target[p] === v) return true;
|
||||
|
||||
target[p] = v;
|
||||
// Call any listeners that are listening to a setting of this path
|
||||
const setPath = `${path}${path && "."}${p}`;
|
||||
for (const subscription of subscriptions) {
|
||||
if (!subscription._path || subscription._path === setPath) {
|
||||
subscription(v, setPath);
|
||||
}
|
||||
}
|
||||
// And don't forget to persist the settings!
|
||||
VencordNative.ipc.invoke(IpcEvents.SET_SETTINGS, JSON.stringify(root, null, 4));
|
||||
return true;
|
||||
}
|
||||
@ -70,6 +96,9 @@ function makeProxy(settings: Settings, root = settings, path = ""): Settings {
|
||||
* Same as {@link Settings} but unproxied. You should treat this as readonly,
|
||||
* as modifying properties on this will not save to disk or call settings
|
||||
* listeners.
|
||||
* WARNING: default values specified in plugin.options will not be ensured here. In other words,
|
||||
* settings for which you specified a default value may be uninitialised. If you need proper
|
||||
* handling for default values, use {@link Settings}
|
||||
*/
|
||||
export const PlainSettings = settings;
|
||||
/**
|
||||
@ -78,6 +107,7 @@ export const PlainSettings = settings;
|
||||
* This recursively proxies objects. If you need the object non proxied, use {@link PlainSettings}
|
||||
*/
|
||||
export const Settings = makeProxy(settings);
|
||||
|
||||
/**
|
||||
* Settings hook for React components. Returns a smart settings
|
||||
* object that automagically triggers a rerender if any properties
|
||||
|
Loading…
x
Reference in New Issue
Block a user