mirror of
https://github.com/Vencord/Vesktop.git
synced 2025-02-23 13:45:09 +00:00
Improve SettingsStore, add disableMinSize listener
This commit is contained in:
parent
edfeca15ce
commit
0c77dbec92
5 changed files with 58 additions and 18 deletions
|
@ -39,8 +39,8 @@ ipcMain.on(IpcEvents.GET_VERSION, e => {
|
||||||
e.returnValue = app.getVersion();
|
e.returnValue = app.getVersion();
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcMain.handle(IpcEvents.SET_SETTINGS, (_, settings) => {
|
ipcMain.handle(IpcEvents.SET_SETTINGS, (_, settings: typeof Settings.store, path?: string) => {
|
||||||
Settings.setData(settings);
|
Settings.setData(settings, path);
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcMain.handle(IpcEvents.RELAUNCH, () => {
|
ipcMain.handle(IpcEvents.RELAUNCH, () => {
|
||||||
|
|
|
@ -212,6 +212,12 @@ function initWindowBoundsListeners(win: BrowserWindow) {
|
||||||
win.on("move", saveBounds);
|
win.on("move", saveBounds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function initSettingsListeners(win: BrowserWindow) {
|
||||||
|
Settings.addChangeListener("disableMinSize", disable => {
|
||||||
|
win.setMinimumSize(disable ? 1 : MIN_WIDTH, disable ? 1 : MIN_HEIGHT);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export function createMainWindow() {
|
export function createMainWindow() {
|
||||||
const win = (mainWin = new BrowserWindow({
|
const win = (mainWin = new BrowserWindow({
|
||||||
show: false,
|
show: false,
|
||||||
|
@ -241,6 +247,7 @@ export function createMainWindow() {
|
||||||
initTray(win);
|
initTray(win);
|
||||||
initMenuBar(win);
|
initMenuBar(win);
|
||||||
makeLinksOpenExternally(win);
|
makeLinksOpenExternally(win);
|
||||||
|
initSettingsListeners(win);
|
||||||
|
|
||||||
const subdomain =
|
const subdomain =
|
||||||
Settings.store.discordBranch === "canary" || Settings.store.discordBranch === "ptb"
|
Settings.store.discordBranch === "canary" || Settings.store.discordBranch === "ptb"
|
||||||
|
|
|
@ -29,7 +29,7 @@ export const VencordDesktopNative = {
|
||||||
},
|
},
|
||||||
settings: {
|
settings: {
|
||||||
get: () => sendSync<Settings>(IpcEvents.GET_SETTINGS),
|
get: () => sendSync<Settings>(IpcEvents.GET_SETTINGS),
|
||||||
set: (settings: Settings) => invoke<void>(IpcEvents.SET_SETTINGS, settings)
|
set: (settings: Settings, path?: string) => invoke<void>(IpcEvents.SET_SETTINGS, settings, path)
|
||||||
},
|
},
|
||||||
win: {
|
win: {
|
||||||
focus: () => invoke<void>(IpcEvents.FOCUS)
|
focus: () => invoke<void>(IpcEvents.FOCUS)
|
||||||
|
|
|
@ -11,6 +11,7 @@ import { Common } from "./vencord";
|
||||||
|
|
||||||
export const PlainSettings = VencordDesktopNative.settings.get() as TSettings;
|
export const PlainSettings = VencordDesktopNative.settings.get() as TSettings;
|
||||||
export const Settings = new SettingsStore(PlainSettings);
|
export const Settings = new SettingsStore(PlainSettings);
|
||||||
|
Settings.addGlobalChangeListener((o, p) => VencordDesktopNative.settings.set(o, p));
|
||||||
|
|
||||||
export function useSettings() {
|
export function useSettings() {
|
||||||
const [, update] = Common.React.useReducer(x => x + 1, 0);
|
const [, update] = Common.React.useReducer(x => x + 1, 0);
|
||||||
|
|
|
@ -4,13 +4,24 @@
|
||||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { LiteralUnion } from "type-fest";
|
||||||
|
|
||||||
|
// Resolves a possibly nested prop in the form of "some.nested.prop" to type of T.some.nested.prop
|
||||||
|
type ResolvePropDeep<T, P> = P extends `${infer Pre}.${infer Suf}`
|
||||||
|
? Pre extends keyof T
|
||||||
|
? ResolvePropDeep<T[Pre], Suf>
|
||||||
|
: any
|
||||||
|
: P extends keyof T
|
||||||
|
? T[P]
|
||||||
|
: any;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The SettingsStore allows you to easily create a mutable store that
|
* The SettingsStore allows you to easily create a mutable store that
|
||||||
* has support for global and path-based change listeners.
|
* has support for global and path-based change listeners.
|
||||||
*/
|
*/
|
||||||
export class SettingsStore<T extends object> {
|
export class SettingsStore<T extends object> {
|
||||||
private pathListeners = new Map<string, Set<(newData: unknown) => void>>();
|
private pathListeners = new Map<string, Set<(newData: any) => void>>();
|
||||||
private globalListeners = new Set<(newData: T) => void>();
|
private globalListeners = new Set<(newData: T, path: string) => void>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The store object. Making changes to this object will trigger the applicable change listeners
|
* The store object. Making changes to this object will trigger the applicable change listeners
|
||||||
|
@ -44,7 +55,7 @@ export class SettingsStore<T extends object> {
|
||||||
Reflect.set(target, key, value);
|
Reflect.set(target, key, value);
|
||||||
const setPath = `${path}${path && "."}${key}`;
|
const setPath = `${path}${path && "."}${key}`;
|
||||||
|
|
||||||
self.globalListeners.forEach(cb => cb(root));
|
self.globalListeners.forEach(cb => cb(root, setPath));
|
||||||
self.pathListeners.get(setPath)?.forEach(cb => cb(value));
|
self.pathListeners.get(setPath)?.forEach(cb => cb(value));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -56,20 +67,38 @@ export class SettingsStore<T extends object> {
|
||||||
* Set the data of the store.
|
* Set the data of the store.
|
||||||
* This will update this.store and this.plain (and old references to them will be stale! Avoid storing them in variables)
|
* This will update this.store and this.plain (and old references to them will be stale! Avoid storing them in variables)
|
||||||
*
|
*
|
||||||
* Additionally, all global listeners will be called with the new data
|
* Additionally, all global listeners (or those for pathToNotify, if specified) will be called with the new data
|
||||||
* @param value
|
* @param value New data
|
||||||
|
* @param pathToNotify Optional path to notify instead of globally. Used to transfer path via ipc
|
||||||
*/
|
*/
|
||||||
public setData(value: T) {
|
public setData(value: T, pathToNotify?: string) {
|
||||||
this.plain = value;
|
this.plain = value;
|
||||||
this.store = this.makeProxy(value);
|
this.store = this.makeProxy(value);
|
||||||
|
|
||||||
this.globalListeners.forEach(cb => cb(value));
|
if (pathToNotify) {
|
||||||
|
let v = value;
|
||||||
|
|
||||||
|
const path = pathToNotify.split(".");
|
||||||
|
for (const p of path) {
|
||||||
|
if (!v) {
|
||||||
|
console.warn(
|
||||||
|
`Settings#setData: Path ${pathToNotify} does not exist in new data. Not dispatching update`
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
v = v[p];
|
||||||
|
}
|
||||||
|
|
||||||
|
this.pathListeners.get(pathToNotify)?.forEach(cb => cb(v));
|
||||||
|
} else {
|
||||||
|
this.globalListeners.forEach(cb => cb(value, ""));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a global change listener, that will fire whenever any setting is changed
|
* Add a global change listener, that will fire whenever any setting is changed
|
||||||
*/
|
*/
|
||||||
public addGlobalChangeListener(cb: (store: T) => void) {
|
public addGlobalChangeListener(cb: (data: T, path: string) => void) {
|
||||||
this.globalListeners.add(cb);
|
this.globalListeners.add(cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,17 +116,20 @@ export class SettingsStore<T extends object> {
|
||||||
* @param path
|
* @param path
|
||||||
* @param cb
|
* @param cb
|
||||||
*/
|
*/
|
||||||
public addChangeListener(path: string, cb: (data: any) => void) {
|
public addChangeListener<P extends LiteralUnion<keyof T, string>>(
|
||||||
const listeners = this.pathListeners.get(path) ?? new Set();
|
path: P,
|
||||||
|
cb: (data: ResolvePropDeep<T, P>) => void
|
||||||
|
) {
|
||||||
|
const listeners = this.pathListeners.get(path as string) ?? new Set();
|
||||||
listeners.add(cb);
|
listeners.add(cb);
|
||||||
this.pathListeners.set(path, listeners);
|
this.pathListeners.set(path as string, listeners);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove a global listener
|
* Remove a global listener
|
||||||
* @see {@link addGlobalChangeListener}
|
* @see {@link addGlobalChangeListener}
|
||||||
*/
|
*/
|
||||||
public removeGlobalChangeListener(cb: (store: T) => void) {
|
public removeGlobalChangeListener(cb: (data: T, path: string) => void) {
|
||||||
this.globalListeners.delete(cb);
|
this.globalListeners.delete(cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,11 +137,11 @@ export class SettingsStore<T extends object> {
|
||||||
* Remove a scoped listener
|
* Remove a scoped listener
|
||||||
* @see {@link addChangeListener}
|
* @see {@link addChangeListener}
|
||||||
*/
|
*/
|
||||||
public removeChangeListener(path: string, cb: (data: any) => void) {
|
public removeChangeListener(path: LiteralUnion<keyof T, string>, cb: (data: any) => void) {
|
||||||
const listeners = this.pathListeners.get(path);
|
const listeners = this.pathListeners.get(path as string);
|
||||||
if (!listeners) return;
|
if (!listeners) return;
|
||||||
|
|
||||||
listeners.delete(cb);
|
listeners.delete(cb);
|
||||||
if (!listeners.size) this.pathListeners.delete(path);
|
if (!listeners.size) this.pathListeners.delete(path as string);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue