aboutsummaryrefslogtreecommitdiff
path: root/src/utils
diff options
context:
space:
mode:
authorVendicated <vendicated@riseup.net>2023-05-06 01:36:00 +0200
committerVendicated <vendicated@riseup.net>2023-05-06 01:36:00 +0200
commit0d5e2d0696da494aee2126b4cadbca7e07066b89 (patch)
tree4a8159ba43f5f283e28101eb3d92e1f4f0b52035 /src/utils
parent2834bed518a1fc1c384a93d599cc1b03555177c7 (diff)
downloadVencord-0d5e2d0696da494aee2126b4cadbca7e07066b89.tar.gz
Vencord-0d5e2d0696da494aee2126b4cadbca7e07066b89.tar.bz2
Vencord-0d5e2d0696da494aee2126b4cadbca7e07066b89.zip
[skip ci] Refactor utils
Diffstat (limited to 'src/utils')
-rw-r--r--src/utils/Logger.ts2
-rw-r--r--src/utils/cloud.tsx4
-rw-r--r--src/utils/constants.ts5
-rw-r--r--src/utils/dependencies.ts2
-rw-r--r--src/utils/index.ts13
-rw-r--r--src/utils/lazy.ts (renamed from src/utils/proxyLazy.ts)7
-rw-r--r--src/utils/misc.tsx110
-rw-r--r--src/utils/modal.tsx2
-rw-r--r--src/utils/quickCss.ts2
-rw-r--r--src/utils/react.ts62
-rw-r--r--src/utils/react.tsx128
-rw-r--r--src/utils/settingsSync.ts4
-rw-r--r--src/utils/text.ts39
-rw-r--r--src/utils/updater.ts2
14 files changed, 196 insertions, 186 deletions
diff --git a/src/utils/Logger.ts b/src/utils/Logger.ts
index 88ebb43..1ae4762 100644
--- a/src/utils/Logger.ts
+++ b/src/utils/Logger.ts
@@ -16,7 +16,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
-export default class Logger {
+export class Logger {
/**
* Returns the console format args for a title with the specified background colour and black text
* @param color Background colour
diff --git a/src/utils/cloud.tsx b/src/utils/cloud.tsx
index b31091f..5f853bd 100644
--- a/src/utils/cloud.tsx
+++ b/src/utils/cloud.tsx
@@ -18,11 +18,11 @@
import * as DataStore from "@api/DataStore";
import { showNotification } from "@api/Notifications";
-import { Settings } from "@api/settings";
+import { Settings } from "@api/Settings";
import { findByProps } from "@webpack";
import { UserStore } from "@webpack/common";
-import Logger from "./Logger";
+import { Logger } from "./Logger";
import { openModal } from "./modal";
export const cloudLogger = new Logger("Cloud", "#39b7e0");
diff --git a/src/utils/constants.ts b/src/utils/constants.ts
index 69eb604..a10a0a5 100644
--- a/src/utils/constants.ts
+++ b/src/utils/constants.ts
@@ -19,6 +19,11 @@
import gitHash from "~git-hash";
import gitRemote from "~git-remote";
+export {
+ gitHash,
+ gitRemote
+};
+
export const WEBPACK_CHUNK = "webpackChunkdiscord_app";
export const REACT_GLOBAL = "Vencord.Webpack.Common.React";
export const VENCORD_USER_AGENT = `Vencord/${gitHash}${gitRemote ? ` (https://github.com/${gitRemote})` : ""}`;
diff --git a/src/utils/dependencies.ts b/src/utils/dependencies.ts
index a09a87b..67bf502 100644
--- a/src/utils/dependencies.ts
+++ b/src/utils/dependencies.ts
@@ -16,7 +16,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
-import { makeLazy } from "./misc";
+import { makeLazy } from "./lazy";
/*
Add dynamically loaded dependencies for plugins here.
diff --git a/src/utils/index.ts b/src/utils/index.ts
index 6723a70..fd15f3d 100644
--- a/src/utils/index.ts
+++ b/src/utils/index.ts
@@ -17,15 +17,18 @@
*/
export * from "./ChangeList";
-export * as Constants from "./constants";
+export * from "./constants";
export * from "./debounce";
-export * as Discord from "./discord";
-export { default as Logger } from "./Logger";
+export * from "./discord";
+export * from "./guards";
+export * from "./lazy";
+export * from "./localStorage";
+export * from "./Logger";
export * from "./margins";
export * from "./misc";
-export * as Modals from "./modal";
+export * from "./modal";
export * from "./onceDefined";
export * from "./onlyOnce";
-export * from "./proxyLazy";
+export * from "./patches";
export * from "./Queue";
export * from "./text";
diff --git a/src/utils/proxyLazy.ts b/src/utils/lazy.ts
index b1fca6e..1e1dd5f 100644
--- a/src/utils/proxyLazy.ts
+++ b/src/utils/lazy.ts
@@ -16,6 +16,11 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
+export function makeLazy<T>(factory: () => T): () => T {
+ let cache: T;
+ return () => cache ?? (cache = factory());
+}
+
// Proxies demand that these properties be unmodified, so proxyLazy
// will always return the function default for them.
const unconfigurable = ["arguments", "caller", "prototype"];
@@ -73,7 +78,7 @@ handler.getOwnPropertyDescriptor = (target, p) => {
* @example const mod = proxyLazy(() => findByProps("blah")); console.log(mod.blah);
*/
export function proxyLazy<T>(factory: () => T): T {
- const proxyDummy: { (): void; [CACHED_KEY]?: T; [GET_KEY](): T; } = Object.assign(function () { }, {
+ const proxyDummy: { (): void;[CACHED_KEY]?: T;[GET_KEY](): T; } = Object.assign(function () { }, {
[CACHED_KEY]: void 0,
[GET_KEY]: () => proxyDummy[CACHED_KEY] ??= factory(),
});
diff --git a/src/utils/misc.tsx b/src/utils/misc.tsx
index b6a6423..59475cb 100644
--- a/src/utils/misc.tsx
+++ b/src/utils/misc.tsx
@@ -16,79 +16,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
-import { Clipboard, React, Toasts, useEffect, useState } from "@webpack/common";
-
-/**
- * Makes a lazy function. On first call, the value is computed.
- * On subsequent calls, the same computed value will be returned
- * @param factory Factory function
- */
-export function makeLazy<T>(factory: () => T): () => T {
- let cache: T;
- return () => cache ?? (cache = factory());
-}
-
-type AwaiterRes<T> = [T, any, boolean];
-interface AwaiterOpts<T> {
- fallbackValue: T,
- deps?: unknown[],
- onError?(e: any): void,
-}
-/**
- * Await a promise
- * @param factory Factory
- * @param fallbackValue The fallback value that will be used until the promise resolved
- * @returns [value, error, isPending]
- */
-export function useAwaiter<T>(factory: () => Promise<T>): AwaiterRes<T | null>;
-export function useAwaiter<T>(factory: () => Promise<T>, providedOpts: AwaiterOpts<T>): AwaiterRes<T>;
-export function useAwaiter<T>(factory: () => Promise<T>, providedOpts?: AwaiterOpts<T | null>): AwaiterRes<T | null> {
- const opts: Required<AwaiterOpts<T | null>> = Object.assign({
- fallbackValue: null,
- deps: [],
- onError: null,
- }, providedOpts);
- const [state, setState] = useState({
- value: opts.fallbackValue,
- error: null,
- pending: true
- });
-
- useEffect(() => {
- let isAlive = true;
- if (!state.pending) setState({ ...state, pending: true });
-
- factory()
- .then(value => isAlive && setState({ value, error: null, pending: false }))
- .catch(error => isAlive && (setState({ value: null, error, pending: false }), opts.onError?.(error)));
-
- return () => void (isAlive = false);
- }, opts.deps);
-
- return [state.value, state.error, state.pending];
-}
-
-/**
- * Returns a function that can be used to force rerender react components
- */
-export function useForceUpdater() {
- const [, set] = useState(0);
- return () => set(s => s + 1);
-}
-
-/**
- * A lazy component. The factory method is called on first render. For example useful
- * for const Component = LazyComponent(() => findByDisplayName("...").default)
- * @param factory Function returning a Component
- * @returns Result of factory function
- */
-export function LazyComponent<T = any>(factory: () => React.ComponentType<T>) {
- const get = makeLazy(factory);
- return (props: T & JSX.IntrinsicAttributes) => {
- const Component = get();
- return <Component {...props} />;
- };
-}
+import { Clipboard, Toasts } from "@webpack/common";
/**
* Recursively merges defaults into an object and returns the same object
@@ -109,34 +37,6 @@ export function mergeDefaults<T>(obj: T, defaults: T): T {
return obj;
}
-
-/**
- * Join an array of strings in a human readable way (1, 2 and 3)
- * @param elements Elements
- */
-export function humanFriendlyJoin(elements: string[]): string;
-/**
- * Join an array of strings in a human readable way (1, 2 and 3)
- * @param elements Elements
- * @param mapper Function that converts elements to a string
- */
-export function humanFriendlyJoin<T>(elements: T[], mapper: (e: T) => string): string;
-export function humanFriendlyJoin(elements: any[], mapper: (e: any) => string = s => s): string {
- const { length } = elements;
- if (length === 0) return "";
- if (length === 1) return mapper(elements[0]);
-
- let s = "";
-
- for (let i = 0; i < length; i++) {
- s += mapper(elements[i]);
- if (length - i > 2) s += ", ";
- else if (length - i > 1) s += " and ";
- }
-
- return s;
-}
-
/**
* Calls .join(" ") on the arguments
* classes("one", "two") => "one two"
@@ -152,14 +52,6 @@ export function sleep(ms: number): Promise<void> {
return new Promise(r => setTimeout(r, ms));
}
-/**
- * Wrap the text in ``` with an optional language
- */
-export function makeCodeblock(text: string, language?: string) {
- const chars = "```";
- return `${chars}${language || ""}\n${text.replaceAll("```", "\\`\\`\\`")}\n${chars}`;
-}
-
export function copyWithToast(text: string, toastMessage = "Copied to clipboard!") {
if (Clipboard.SUPPORTS_COPY) {
Clipboard.copy(text);
diff --git a/src/utils/modal.tsx b/src/utils/modal.tsx
index 35aaaf8..1738623 100644
--- a/src/utils/modal.tsx
+++ b/src/utils/modal.tsx
@@ -19,7 +19,7 @@
import { filters, mapMangledModuleLazy } from "@webpack";
import type { ComponentType, PropsWithChildren, ReactNode, Ref } from "react";
-import { LazyComponent } from "./misc";
+import { LazyComponent } from "./react";
export enum ModalSize {
SMALL = "small",
diff --git a/src/utils/quickCss.ts b/src/utils/quickCss.ts
index 1b3f78d..fe35a3c 100644
--- a/src/utils/quickCss.ts
+++ b/src/utils/quickCss.ts
@@ -16,7 +16,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
-import { addSettingsListener, Settings } from "@api/settings";
+import { addSettingsListener, Settings } from "@api/Settings";
let style: HTMLStyleElement;
diff --git a/src/utils/react.ts b/src/utils/react.ts
deleted file mode 100644
index e5e1f67..0000000
--- a/src/utils/react.ts
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Vencord, a modification for Discord's desktop app
- * Copyright (c) 2022 Vendicated and contributors
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
-*/
-
-import { React, useState } from "@webpack/common";
-
-import { checkIntersecting } from "./misc";
-
-/**
- * Check if an element is on screen
- * @param intersectOnly If `true`, will only update the state when the element comes into view
- * @returns [refCallback, isIntersecting]
- */
-export const useIntersection = (intersectOnly = false): [
- refCallback: React.RefCallback<Element>,
- isIntersecting: boolean,
-] => {
- const observerRef = React.useRef<IntersectionObserver | null>(null);
- const [isIntersecting, setIntersecting] = useState(false);
-
- const refCallback = (element: Element | null) => {
- observerRef.current?.disconnect();
- observerRef.current = null;
-
- if (!element) return;
-
- if (checkIntersecting(element)) {
- setIntersecting(true);
- if (intersectOnly) return;
- }
-
- observerRef.current = new IntersectionObserver(entries => {
- for (const entry of entries) {
- if (entry.target !== element) continue;
- if (entry.isIntersecting && intersectOnly) {
- setIntersecting(true);
- observerRef.current?.disconnect();
- observerRef.current = null;
- } else {
- setIntersecting(entry.isIntersecting);
- }
- }
- });
- observerRef.current.observe(element);
- };
-
- return [refCallback, isIntersecting];
-};
diff --git a/src/utils/react.tsx b/src/utils/react.tsx
new file mode 100644
index 0000000..69c1df2
--- /dev/null
+++ b/src/utils/react.tsx
@@ -0,0 +1,128 @@
+/*
+ * Vencord, a modification for Discord's desktop app
+ * Copyright (c) 2022 Vendicated and contributors
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+*/
+
+import { React, useEffect, useReducer, useState } from "@webpack/common";
+
+import { makeLazy } from "./lazy";
+import { checkIntersecting } from "./misc";
+
+/**
+ * Check if an element is on screen
+ * @param intersectOnly If `true`, will only update the state when the element comes into view
+ * @returns [refCallback, isIntersecting]
+ */
+export const useIntersection = (intersectOnly = false): [
+ refCallback: React.RefCallback<Element>,
+ isIntersecting: boolean,
+] => {
+ const observerRef = React.useRef<IntersectionObserver | null>(null);
+ const [isIntersecting, setIntersecting] = useState(false);
+
+ const refCallback = (element: Element | null) => {
+ observerRef.current?.disconnect();
+ observerRef.current = null;
+
+ if (!element) return;
+
+ if (checkIntersecting(element)) {
+ setIntersecting(true);
+ if (intersectOnly) return;
+ }
+
+ observerRef.current = new IntersectionObserver(entries => {
+ for (const entry of entries) {
+ if (entry.target !== element) continue;
+ if (entry.isIntersecting && intersectOnly) {
+ setIntersecting(true);
+ observerRef.current?.disconnect();
+ observerRef.current = null;
+ } else {
+ setIntersecting(entry.isIntersecting);
+ }
+ }
+ });
+ observerRef.current.observe(element);
+ };
+
+ return [refCallback, isIntersecting];
+};
+
+type AwaiterRes<T> = [T, any, boolean];
+interface AwaiterOpts<T> {
+ fallbackValue: T;
+ deps?: unknown[];
+ onError?(e: any): void;
+}
+/**
+ * Await a promise
+ * @param factory Factory
+ * @param fallbackValue The fallback value that will be used until the promise resolved
+ * @returns [value, error, isPending]
+ */
+
+export function useAwaiter<T>(factory: () => Promise<T>): AwaiterRes<T | null>;
+export function useAwaiter<T>(factory: () => Promise<T>, providedOpts: AwaiterOpts<T>): AwaiterRes<T>;
+export function useAwaiter<T>(factory: () => Promise<T>, providedOpts?: AwaiterOpts<T | null>): AwaiterRes<T | null> {
+ const opts: Required<AwaiterOpts<T | null>> = Object.assign({
+ fallbackValue: null,
+ deps: [],
+ onError: null,
+ }, providedOpts);
+ const [state, setState] = useState({
+ value: opts.fallbackValue,
+ error: null,
+ pending: true
+ });
+
+ useEffect(() => {
+ let isAlive = true;
+ if (!state.pending) setState({ ...state, pending: true });
+
+ factory()
+ .then(value => isAlive && setState({ value, error: null, pending: false }))
+ .catch(error => isAlive && (setState({ value: null, error, pending: false }), opts.onError?.(error)));
+
+ return () => void (isAlive = false);
+ }, opts.deps);
+
+ return [state.value, state.error, state.pending];
+}
+/**
+ * Returns a function that can be used to force rerender react components
+ */
+
+export function useForceUpdater(): () => void;
+export function useForceUpdater(withDep: true): [unknown, () => void];
+export function useForceUpdater(withDep?: true) {
+ const r = useReducer(x => x + 1, 0);
+ return withDep ? r : r[1];
+}
+/**
+ * A lazy component. The factory method is called on first render. For example useful
+ * for const Component = LazyComponent(() => findByDisplayName("...").default)
+ * @param factory Function returning a Component
+ * @returns Result of factory function
+ */
+
+export function LazyComponent<T extends object = any>(factory: () => React.ComponentType<T>) {
+ const get = makeLazy(factory);
+ return (props: T) => {
+ const Component = get();
+ return <Component {...props} />;
+ };
+}
diff --git a/src/utils/settingsSync.ts b/src/utils/settingsSync.ts
index 3ec2d43..ef04391 100644
--- a/src/utils/settingsSync.ts
+++ b/src/utils/settingsSync.ts
@@ -17,12 +17,12 @@
*/
import { showNotification } from "@api/Notifications";
-import { PlainSettings, Settings } from "@api/settings";
+import { PlainSettings, Settings } from "@api/Settings";
import { Toasts } from "@webpack/common";
import { deflateSync, inflateSync } from "fflate";
import { getCloudAuth, getCloudUrl } from "./cloud";
-import Logger from "./Logger";
+import { Logger } from "./Logger";
import { saveFile } from "./web";
export async function importSettings(data: string) {
diff --git a/src/utils/text.ts b/src/utils/text.ts
index 115b3e2..63f6007 100644
--- a/src/utils/text.ts
+++ b/src/utils/text.ts
@@ -92,3 +92,42 @@ export function formatDuration(time: number, unit: Units, short: boolean = false
return res.length ? res : `0 ${getUnitStr(unit, false, short)}`;
}
+
+/**
+ * Join an array of strings in a human readable way (1, 2 and 3)
+ * @param elements Elements
+ */
+export function humanFriendlyJoin(elements: string[]): string;
+/**
+ * Join an array of strings in a human readable way (1, 2 and 3)
+ * @param elements Elements
+ * @param mapper Function that converts elements to a string
+ */
+export function humanFriendlyJoin<T>(elements: T[], mapper: (e: T) => string): string;
+export function humanFriendlyJoin(elements: any[], mapper: (e: any) => string = s => s): string {
+ const { length } = elements;
+ if (length === 0)
+ return "";
+ if (length === 1)
+ return mapper(elements[0]);
+
+ let s = "";
+
+ for (let i = 0; i < length; i++) {
+ s += mapper(elements[i]);
+ if (length - i > 2)
+ s += ", ";
+ else if (length - i > 1)
+ s += " and ";
+ }
+
+ return s;
+}
+
+/**
+ * Wrap the text in ``` with an optional language
+ */
+export function makeCodeblock(text: string, language?: string) {
+ const chars = "```";
+ return `${chars}${language || ""}\n${text.replaceAll("```", "\\`\\`\\`")}\n${chars}`;
+}
diff --git a/src/utils/updater.ts b/src/utils/updater.ts
index ce99aa4..2e2bfe1 100644
--- a/src/utils/updater.ts
+++ b/src/utils/updater.ts
@@ -18,7 +18,7 @@
import gitHash from "~git-hash";
-import Logger from "./Logger";
+import { Logger } from "./Logger";
import { relaunch } from "./native";
import { IpcRes } from "./types";