Rewrite settings proxy to proper store
This commit is contained in:
parent
ddebb6563a
commit
c2eaa9d35a
8 changed files with 90 additions and 58 deletions
|
@ -17,7 +17,8 @@
|
|||
"start": "pnpm build && electron .",
|
||||
"start:dev": "pnpm build --dev && electron .",
|
||||
"start:watch": "tsx scripts/startWatch.mts",
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"test": "pnpm lint && pnpm testTypes",
|
||||
"testTypes": "tsc --noEmit",
|
||||
"watch": "pnpm build --watch"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
@ -63,7 +63,7 @@ async function createWindows() {
|
|||
splash.destroy();
|
||||
mainWin!.show();
|
||||
|
||||
if (Settings.maximized) {
|
||||
if (Settings.store.maximized) {
|
||||
mainWin!.maximize();
|
||||
}
|
||||
});
|
||||
|
|
|
@ -13,7 +13,7 @@ import { debounce } from "shared/utils/debounce";
|
|||
import { IpcEvents } from "../shared/IpcEvents";
|
||||
import { VENCORD_FILES_DIR, VENCORD_QUICKCSS_FILE } from "./constants";
|
||||
import { mainWin } from "./mainWindow";
|
||||
import { PlainSettings, setSettings } from "./settings";
|
||||
import { Settings } from "./settings";
|
||||
|
||||
ipcMain.on(IpcEvents.GET_VENCORD_PRELOAD_FILE, e => {
|
||||
e.returnValue = join(VENCORD_FILES_DIR, "preload.js");
|
||||
|
@ -32,7 +32,7 @@ ipcMain.on(IpcEvents.GET_RENDERER_CSS_FILE, e => {
|
|||
});
|
||||
|
||||
ipcMain.on(IpcEvents.GET_SETTINGS, e => {
|
||||
e.returnValue = PlainSettings;
|
||||
e.returnValue = Settings.plain;
|
||||
});
|
||||
|
||||
ipcMain.on(IpcEvents.GET_VERSION, e => {
|
||||
|
@ -40,7 +40,7 @@ ipcMain.on(IpcEvents.GET_VERSION, e => {
|
|||
});
|
||||
|
||||
ipcMain.handle(IpcEvents.SET_SETTINGS, (_, settings) => {
|
||||
setSettings(settings);
|
||||
Settings.setData(settings);
|
||||
});
|
||||
|
||||
ipcMain.handle(IpcEvents.RELAUNCH, () => {
|
||||
|
|
|
@ -78,7 +78,7 @@ function initTray(win: BrowserWindow) {
|
|||
|
||||
function initMenuBar(win: BrowserWindow) {
|
||||
const isWindows = process.platform === "win32";
|
||||
const wantCtrlQ = !isWindows || VencordSettings.winCtrlQ;
|
||||
const wantCtrlQ = !isWindows || VencordSettings.store.winCtrlQ;
|
||||
|
||||
const menu = Menu.buildFromTemplate([
|
||||
{
|
||||
|
@ -174,7 +174,7 @@ function initMenuBar(win: BrowserWindow) {
|
|||
}
|
||||
|
||||
function getWindowBoundsOptions(): BrowserWindowConstructorOptions {
|
||||
const { x, y, width, height } = Settings.windowBounds ?? {};
|
||||
const { x, y, width, height } = Settings.store.windowBounds ?? {};
|
||||
|
||||
const options = {
|
||||
width: width ?? DEFAULT_WIDTH,
|
||||
|
@ -186,7 +186,7 @@ function getWindowBoundsOptions(): BrowserWindowConstructorOptions {
|
|||
options.y = y;
|
||||
}
|
||||
|
||||
if (!Settings.disableMinSize) {
|
||||
if (!Settings.store.disableMinSize) {
|
||||
options.minWidth = MIN_WIDTH;
|
||||
options.minHeight = MIN_HEIGHT;
|
||||
}
|
||||
|
@ -196,8 +196,8 @@ function getWindowBoundsOptions(): BrowserWindowConstructorOptions {
|
|||
|
||||
function initWindowBoundsListeners(win: BrowserWindow) {
|
||||
const saveState = () => {
|
||||
Settings.maximized = win.isMaximized();
|
||||
Settings.minimized = win.isMinimized();
|
||||
Settings.store.maximized = win.isMaximized();
|
||||
Settings.store.minimized = win.isMinimized();
|
||||
};
|
||||
|
||||
win.on("maximize", saveState);
|
||||
|
@ -205,7 +205,7 @@ function initWindowBoundsListeners(win: BrowserWindow) {
|
|||
win.on("unmaximize", saveState);
|
||||
|
||||
const saveBounds = () => {
|
||||
Settings.windowBounds = win.getBounds();
|
||||
Settings.store.windowBounds = win.getBounds();
|
||||
};
|
||||
|
||||
win.on("resize", saveBounds);
|
||||
|
@ -224,12 +224,12 @@ export function createMainWindow() {
|
|||
preload: join(__dirname, "preload.js")
|
||||
},
|
||||
icon: ICON_PATH,
|
||||
frame: VencordSettings.frameless !== true,
|
||||
frame: VencordSettings.store.frameless !== true,
|
||||
...getWindowBoundsOptions()
|
||||
}));
|
||||
|
||||
win.on("close", e => {
|
||||
if (isQuitting || Settings.minimizeToTray === false) return;
|
||||
if (isQuitting || Settings.store.minimizeToTray === false) return;
|
||||
|
||||
e.preventDefault();
|
||||
win.hide();
|
||||
|
@ -243,7 +243,9 @@ export function createMainWindow() {
|
|||
makeLinksOpenExternally(win);
|
||||
|
||||
const subdomain =
|
||||
Settings.discordBranch === "canary" || Settings.discordBranch === "ptb" ? `${Settings.discordBranch}.` : "";
|
||||
Settings.store.discordBranch === "canary" || Settings.store.discordBranch === "ptb"
|
||||
? `${Settings.store.discordBranch}.`
|
||||
: "";
|
||||
|
||||
win.loadURL(`https://${subdomain}discord.com/app`);
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
import { readFileSync, writeFileSync } from "fs";
|
||||
import { join } from "path";
|
||||
import type { Settings as TSettings } from "shared/settings";
|
||||
import { makeChangeListenerProxy } from "shared/utils/makeChangeListenerProxy";
|
||||
import { SettingsStore } from "shared/utils/makeChangeListenerProxy";
|
||||
|
||||
import { DATA_DIR, VENCORD_SETTINGS_FILE } from "./constants";
|
||||
|
||||
|
@ -24,23 +24,11 @@ function loadSettings<T extends object = any>(file: string, name: string) {
|
|||
}
|
||||
} catch {}
|
||||
|
||||
const makeSettingsProxy = (settings: T) =>
|
||||
makeChangeListenerProxy(settings, target => writeFileSync(file, JSON.stringify(target, null, 4)));
|
||||
const store = new SettingsStore(settings);
|
||||
store.addGlobalChangeListener(o => writeFileSync(file, JSON.stringify(o, null, 4)));
|
||||
|
||||
return [settings, makeSettingsProxy] as const;
|
||||
return store;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line prefer-const
|
||||
let [PlainSettings, makeSettingsProxy] = loadSettings<TSettings>(SETTINGS_FILE, "VencordDesktop");
|
||||
export let Settings = makeSettingsProxy(PlainSettings);
|
||||
|
||||
const [PlainVencordSettings, makeVencordSettingsProxy] = loadSettings<any>(VENCORD_SETTINGS_FILE, "Vencord");
|
||||
export const VencordSettings = makeVencordSettingsProxy(PlainVencordSettings);
|
||||
|
||||
export function setSettings(settings: TSettings) {
|
||||
writeFileSync(SETTINGS_FILE, JSON.stringify(settings, null, 4));
|
||||
PlainSettings = settings;
|
||||
Settings = makeSettingsProxy(settings);
|
||||
}
|
||||
|
||||
export { PlainSettings, PlainVencordSettings };
|
||||
export const Settings = loadSettings<TSettings>(SETTINGS_FILE, "Vencord Desktop");
|
||||
export const VencordSettings = loadSettings<any>(VENCORD_SETTINGS_FILE, "Vencord");
|
||||
|
|
|
@ -25,7 +25,7 @@ export function makeLinksOpenExternally(win: BrowserWindow) {
|
|||
switch (protocol) {
|
||||
case "http:":
|
||||
case "https:":
|
||||
if (Settings.openLinksWithElectron) {
|
||||
if (Settings.store.openLinksWithElectron) {
|
||||
return { action: "allow" };
|
||||
}
|
||||
// eslint-disable-next-line no-fallthrough
|
||||
|
|
|
@ -5,26 +5,23 @@
|
|||
*/
|
||||
|
||||
import type { Settings as TSettings } from "shared/settings";
|
||||
import { makeChangeListenerProxy } from "shared/utils/makeChangeListenerProxy";
|
||||
import { SettingsStore } from "shared/utils/makeChangeListenerProxy";
|
||||
|
||||
import { Common } from "./vencord";
|
||||
|
||||
const signals = new Set<() => void>();
|
||||
|
||||
export const PlainSettings = VencordDesktopNative.settings.get() as TSettings;
|
||||
export const Settings = makeChangeListenerProxy(PlainSettings, s => {
|
||||
VencordDesktopNative.settings.set(s);
|
||||
signals.forEach(fn => fn());
|
||||
});
|
||||
export const Settings = new SettingsStore(PlainSettings);
|
||||
|
||||
export function useSettings() {
|
||||
const [, update] = Common.React.useReducer(x => x + 1, 0);
|
||||
|
||||
Common.React.useEffect(() => {
|
||||
signals.add(update);
|
||||
return () => signals.delete(update);
|
||||
Settings.addGlobalChangeListener(update);
|
||||
|
||||
return () => Settings.removeGlobalChangeListener(update);
|
||||
}, []);
|
||||
|
||||
return Settings;
|
||||
return Settings.store;
|
||||
}
|
||||
|
||||
export function getValueAndOnChange(key: keyof TSettings) {
|
||||
|
|
|
@ -4,23 +4,67 @@
|
|||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
export function makeChangeListenerProxy<T extends object>(object: T, onChange: (object: T) => void, _root = object): T {
|
||||
return new Proxy(object, {
|
||||
get(target, key) {
|
||||
const v = target[key];
|
||||
if (typeof v === "object" && !Array.isArray(v) && v !== null)
|
||||
return makeChangeListenerProxy(v, onChange, _root);
|
||||
export class SettingsStore<T extends object> {
|
||||
public declare store: T;
|
||||
private globalListeners = new Set<(newData: T) => void>();
|
||||
private pathListeners = new Map<string, Set<(newData: unknown) => void>>();
|
||||
|
||||
return v;
|
||||
},
|
||||
public constructor(public plain: T) {
|
||||
this.store = this.makeProxy(plain);
|
||||
}
|
||||
|
||||
set(target, key, value) {
|
||||
if (target[key] === value) return true;
|
||||
private makeProxy(object: any, root: T = object, path: string = "") {
|
||||
const self = this;
|
||||
|
||||
Reflect.set(target, key, value);
|
||||
onChange(_root);
|
||||
return new Proxy(object, {
|
||||
get(target, key: string) {
|
||||
const v = target[key];
|
||||
|
||||
return true;
|
||||
}
|
||||
});
|
||||
if (typeof v === "object" && v !== null && !Array.isArray(v))
|
||||
return self.makeProxy(v, root, `${path}${path && "."}${key}`);
|
||||
|
||||
return v;
|
||||
},
|
||||
set(target, key: string, value) {
|
||||
if (target[key] === value) return true;
|
||||
|
||||
Reflect.set(target, key, value);
|
||||
const setPath = `${path}${path && "."}${key}`;
|
||||
|
||||
self.globalListeners.forEach(cb => cb(root));
|
||||
self.pathListeners.get(setPath)?.forEach(cb => cb(value));
|
||||
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public setData(value: T) {
|
||||
this.plain = value;
|
||||
this.store = this.makeProxy(value);
|
||||
|
||||
this.globalListeners.forEach(cb => cb(value));
|
||||
}
|
||||
|
||||
public addGlobalChangeListener(cb: (store: T) => void) {
|
||||
this.globalListeners.add(cb);
|
||||
}
|
||||
|
||||
public addChangeListener(path: string, cb: (data: any) => void) {
|
||||
const listeners = this.pathListeners.get(path) ?? new Set();
|
||||
listeners.add(cb);
|
||||
this.pathListeners.set(path, listeners);
|
||||
}
|
||||
|
||||
public removeGlobalChangeListener(cb: (store: T) => void) {
|
||||
this.globalListeners.delete(cb);
|
||||
}
|
||||
|
||||
public removeChangeListener(path: string, cb: (data: any) => void) {
|
||||
const listeners = this.pathListeners.get(path);
|
||||
if (!listeners) return;
|
||||
|
||||
listeners.delete(cb);
|
||||
if (!listeners.size) this.pathListeners.delete(path);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue