This commit is contained in:
Nuckyz 2024-09-19 05:03:26 +00:00 committed by GitHub
commit 7161e2eed8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
155 changed files with 3479 additions and 2408 deletions

View file

@ -90,7 +90,13 @@ export default tseslint.config(
"no-invalid-regexp": "error",
"no-constant-condition": ["error", { "checkLoops": false }],
"no-duplicate-imports": "error",
"dot-notation": "error",
"@typescript-eslint/dot-notation": [
"error",
{
"allowPrivateClassPropertyAccess": true,
"allowProtectedClassPropertyAccess": true
}
],
"no-useless-escape": [
"error",
{

View file

@ -312,7 +312,7 @@ export const commonOpts = {
logLevel: "info",
bundle: true,
watch,
minify: !watch,
minify: !watch && !IS_REPORTER,
sourcemap: watch ? "inline" : "",
legalComments: "linked",
banner,

View file

@ -26,7 +26,7 @@
import { readFileSync } from "fs";
import pup, { JSHandle } from "puppeteer-core";
for (const variable of ["DISCORD_TOKEN", "CHROMIUM_BIN"]) {
for (const variable of ["CHROMIUM_BIN"]) {
if (!process.env[variable]) {
console.error(`Missing environment variable ${variable}`);
process.exit(1);
@ -214,7 +214,7 @@ page.on("console", async e => {
switch (tag) {
case "WebpackInterceptor:":
const patchFailMatch = message.match(/Patch by (.+?) (had no effect|errored|found no module) \(Module id is (.+?)\): (.+)/)!;
const patchFailMatch = message.match(/Patch by (.+?) (had no effect|errored|found no module|took [\d.]+?ms) \(Module id is (.+?)\): (.+)/)!;
if (!patchFailMatch) break;
console.error(await getText());
@ -225,7 +225,7 @@ page.on("console", async e => {
plugin,
type,
id,
match: regex.replace(/\[A-Za-z_\$\]\[\\w\$\]\*/g, "\\i"),
match: regex,
error: await maybeGetError(e.args()[3])
});
@ -291,7 +291,7 @@ page.on("error", e => console.error("[Error]", e.message));
page.on("pageerror", e => {
if (e.message.includes("Sentry successfully disabled")) return;
if (!e.message.startsWith("Object") && !e.message.includes("Cannot find module")) {
if (!e.message.startsWith("Object") && !e.message.includes("Cannot find module") && !/^.{1,2}$/.test(e.message)) {
console.error("[Page Error]", e.message);
report.otherErrors.push(e.message);
} else {
@ -299,20 +299,9 @@ page.on("pageerror", e => {
}
});
async function reporterRuntime(token: string) {
Vencord.Webpack.waitFor(
"loginToken",
m => {
console.log("[PUP_DEBUG]", "Logging in with token...");
m.loginToken(token);
}
);
}
await page.evaluateOnNewDocument(`
if (location.host.endsWith("discord.com")) {
${readFileSync("./dist/browser.js", "utf-8")};
(${reporterRuntime.toString()})(${JSON.stringify(process.env.DISCORD_TOKEN)});
}
`);

View file

@ -23,10 +23,10 @@ export * as Util from "./utils";
export * as QuickCss from "./utils/quickCss";
export * as Updater from "./utils/updater";
export * as Webpack from "./webpack";
export * as WebpackPatcher from "./webpack/patchWebpack";
export { PlainSettings, Settings };
import "./utils/quickCss";
import "./webpack/patchWebpack";
import { openUpdaterModal } from "@components/VencordSettings/UpdaterTab";
import { StartAt } from "@utils/types";
@ -39,7 +39,7 @@ import { localStorage } from "./utils/localStorage";
import { relaunch } from "./utils/native";
import { getCloudSettings, putCloudSettings } from "./utils/settingsSync";
import { checkForUpdates, update, UpdateLogger } from "./utils/updater";
import { onceReady } from "./webpack";
import { onceDiscordLoaded } from "./webpack";
import { SettingsRouter } from "./webpack/common";
if (IS_REPORTER) {
@ -86,7 +86,7 @@ async function syncSettings() {
}
async function init() {
await onceReady;
await onceDiscordLoaded;
startAllPlugins(StartAt.WebpackReady);
syncSettings();
@ -125,7 +125,7 @@ async function init() {
const pendingPatches = patches.filter(p => !p.all && p.predicate?.() !== false);
if (pendingPatches.length)
PMLogger.warn(
"Webpack has finished initialising, but some patches haven't been applied yet.",
"Webpack has finished initializing, but some patches haven't been applied yet.",
"This might be expected since some Modules are lazy loaded, but please verify",
"that all plugins are working as intended.",
"You are seeing this warning because this is a Development build of Vencord.",

View file

@ -17,7 +17,6 @@
*/
import ErrorBoundary from "@components/ErrorBoundary";
import { ComponentType, HTMLProps } from "react";
import Plugins from "~plugins";
@ -30,7 +29,7 @@ export interface ProfileBadge {
/** The tooltip to show on hover. Required for image badges */
description?: string;
/** Custom component for the badge (tooltip not included) */
component?: ComponentType<ProfileBadge & BadgeUserArgs>;
component?: React.ComponentType<ProfileBadge & BadgeUserArgs>;
/** The custom image to use */
image?: string;
link?: string;
@ -39,7 +38,7 @@ export interface ProfileBadge {
/** Should the user display this badge? */
shouldShow?(userInfo: BadgeUserArgs): boolean;
/** Optional props (e.g. style) for the badge, ignored for component badges */
props?: HTMLProps<HTMLImageElement>;
props?: React.ComponentPropsWithoutRef<"img">;
/** Insert at start or end? */
position?: BadgePosition;
/** The badge name to display, Discord uses this. Required for component badges */

View file

@ -8,13 +8,12 @@ import "./ChatButton.css";
import ErrorBoundary from "@components/ErrorBoundary";
import { Logger } from "@utils/Logger";
import { waitFor } from "@webpack";
import { findByProps } from "@webpack";
import { Button, ButtonLooks, ButtonWrapperClasses, Tooltip } from "@webpack/common";
import { Channel } from "discord-types/general";
import { HTMLProps, MouseEventHandler, ReactNode } from "react";
let ChannelTextAreaClasses: Record<"button" | "buttonContainer", string>;
waitFor(["buttonContainer", "channelTextArea"], m => ChannelTextAreaClasses = m);
const ChannelTextAreaClasses = findByProps<Record<"button" | "buttonContainer", string>>("buttonContainer", "channelTextArea");
export interface ChatBarProps {
channel: Channel;

View file

@ -17,14 +17,14 @@
*/
import { mergeDefaults } from "@utils/mergeDefaults";
import { findByCodeLazy } from "@webpack";
import { findByCode } from "@webpack";
import { MessageActions, SnowflakeUtils } from "@webpack/common";
import { Message } from "discord-types/general";
import type { PartialDeep } from "type-fest";
import { Argument } from "./types";
const createBotMessage = findByCodeLazy('username:"Clyde"');
const createBotMessage = findByCode('username:"Clyde"');
export function generateId() {
return `-${SnowflakeUtils.fromTimestamp(Date.now())}`;

View file

@ -19,18 +19,17 @@
import ErrorBoundary from "@components/ErrorBoundary";
import { Logger } from "@utils/Logger";
import { Channel, Message } from "discord-types/general";
import type { ComponentType, MouseEventHandler } from "react";
const logger = new Logger("MessagePopover");
export interface ButtonItem {
key?: string,
label: string,
icon: ComponentType<any>,
icon: React.ComponentType<AnyRecord>,
message: Message,
channel: Channel,
onClick?: MouseEventHandler<HTMLButtonElement>,
onContextMenu?: MouseEventHandler<HTMLButtonElement>;
onClick?: React.MouseEventHandler<HTMLButtonElement>,
onContextMenu?: React.MouseEventHandler<HTMLButtonElement>;
}
export type getButtonItem = (message: Message) => ButtonItem | null;

View file

@ -16,23 +16,22 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import { waitFor } from "@webpack";
import { find } from "@webpack";
let NoticesModule: any;
waitFor(m => m.show && m.dismiss && !m.suppressAll, m => NoticesModule = m);
const Notices = find(m => m.show && m.dismiss && !m.suppressAll);
export const noticesQueue = [] as any[];
export let currentNotice: any = null;
export function popNotice() {
NoticesModule.dismiss();
Notices.dismiss();
}
export function nextNotice() {
currentNotice = noticesQueue.shift();
if (currentNotice) {
NoticesModule.show(...currentNotice, "VencordNotice");
Notices.show(...currentNotice, "VencordNotice");
}
}

View file

@ -32,9 +32,10 @@ export interface Settings {
autoUpdate: boolean;
autoUpdateNotification: boolean,
useQuickCss: boolean;
enableReactDevtools: boolean;
themeLinks: string[];
eagerPatches: boolean;
enabledThemes: string[];
enableReactDevtools: boolean;
frameless: boolean;
transparent: boolean;
winCtrlQ: boolean;
@ -81,6 +82,7 @@ const DefaultSettings: Settings = {
autoUpdateNotification: true,
useQuickCss: true,
themeLinks: [],
eagerPatches: IS_REPORTER,
enabledThemes: [],
enableReactDevtools: false,
frameless: false,
@ -116,7 +118,6 @@ const saveSettingsOnFrequentAction = debounce(async () => {
}
}, 60_000);
export const SettingsStore = new SettingsStoreClass(settings, {
readOnly: true,
getDefaultValue({

View file

@ -89,8 +89,8 @@ export const isStyleEnabled = (name: string) => requireStyle(name).dom?.isConnec
* // -- plugin.ts --
* import pluginStyle from "./plugin.css?managed";
* import { setStyleVars } from "@api/Styles";
* import { findByPropsLazy } from "@webpack";
* const classNames = findByPropsLazy("thin", "scrollerBase"); // { thin: "thin-31rlnD scrollerBase-_bVAAt", ... }
* import { findByProps } from "@webpack";
* const classNames = findByProps("thin", "scrollerBase"); // { thin: "thin-31rlnD scrollerBase-_bVAAt", ... }
*
* // Inside some plugin method like "start()"
* setStyleClassNames(pluginStyle, classNames);

View file

@ -17,8 +17,7 @@
*/
import { proxyLazy } from "@utils/lazy";
import { Logger } from "@utils/Logger";
import { findModuleId, proxyLazyWebpack, wreq } from "@webpack";
import { findByFactoryCode } from "@webpack";
interface UserSettingDefinition<T> {
/**
@ -43,12 +42,7 @@ interface UserSettingDefinition<T> {
userSettingsAPIName: string;
}
export const UserSettings: Record<PropertyKey, UserSettingDefinition<any>> | undefined = proxyLazyWebpack(() => {
const modId = findModuleId('"textAndImages","renderSpoilers"');
if (modId == null) return new Logger("UserSettingsAPI ").error("Didn't find settings module.");
return wreq(modId as any);
});
export const UserSettings = findByFactoryCode<Record<PropertyKey, UserSettingDefinition<any>>>('"textAndImages","renderSpoilers"');
/**
* Get the setting with the given setting group and name.
@ -56,7 +50,7 @@ export const UserSettings: Record<PropertyKey, UserSettingDefinition<any>> | und
* @param group The setting group
* @param name The name of the setting
*/
export function getUserSetting<T = any>(group: string, name: string): UserSettingDefinition<T> | undefined {
export function getUserSetting<T = any>(group: string, name: string): UserSettingDefinition<T> {
if (!Vencord.Plugins.isPluginEnabled("UserSettingsAPI")) throw new Error("Cannot use UserSettingsAPI without setting as dependency.");
for (const key in UserSettings) {
@ -66,10 +60,12 @@ export function getUserSetting<T = any>(group: string, name: string): UserSettin
return userSetting;
}
}
throw new Error(`UserSettingsAPI: Setting ${group}.${name} not found.`);
}
/**
* {@link getUserSettingDefinition}, lazy.
* Lazy version of {@link getUserSetting}
*
* Get the setting with the given setting group and name.
*

View file

@ -4,10 +4,10 @@
* SPDX-License-Identifier: GPL-3.0-or-later
*/
import { findByPropsLazy } from "@webpack";
import { findByProps } from "@webpack";
import { Parser } from "@webpack/common";
const CodeContainerClasses = findByPropsLazy("markup", "codeContainer");
const CodeContainerClasses = findByProps("markup", "codeContainer");
/**
* Renders code in a Discord codeblock

View file

@ -18,7 +18,7 @@
import { Logger } from "@utils/Logger";
import { Margins } from "@utils/margins";
import { LazyComponent } from "@utils/react";
import { LazyComponent, LazyComponentType } from "@utils/react";
import { React } from "@webpack/common";
import { ErrorCard } from "./ErrorCard";
@ -104,8 +104,8 @@ const ErrorBoundary = LazyComponent(() => {
}
};
}) as
React.ComponentType<React.PropsWithChildren<Props>> & {
wrap<T extends object = any>(Component: React.ComponentType<T>, errorBoundaryProps?: Omit<Props<T>, "wrappedProps">): React.FunctionComponent<T>;
LazyComponentType<React.PropsWithChildren<Props>> & {
wrap<T extends AnyRecord>(Component: React.ComponentType<T>, errorBoundaryProps?: Omit<Props<T>, "wrappedProps">): React.FunctionComponent<T>;
};
ErrorBoundary.wrap = (Component, errorBoundaryProps) => props => (

View file

@ -24,13 +24,12 @@ import { classNameFactory } from "@api/Styles";
import ErrorBoundary from "@components/ErrorBoundary";
import { Flex } from "@components/Flex";
import { gitRemote } from "@shared/vencordUserAgent";
import { proxyLazy } from "@utils/lazy";
import { Margins } from "@utils/margins";
import { classes, isObjectEmpty } from "@utils/misc";
import { ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalProps, ModalRoot, ModalSize, openModal } from "@utils/modal";
import { OptionType, Plugin } from "@utils/types";
import { findByPropsLazy, findComponentByCodeLazy } from "@webpack";
import { Button, Clickable, FluxDispatcher, Forms, React, Text, Tooltip, UserStore, UserUtils } from "@webpack/common";
import { find, findByProps, findComponentByCode } from "@webpack";
import { Button, Clickable, FluxDispatcher, Forms, React, Text, Tooltip, UserUtils } from "@webpack/common";
import { User } from "discord-types/general";
import { Constructor } from "type-fest";
@ -50,9 +49,9 @@ import { GithubButton, WebsiteButton } from "./LinkIconButton";
const cl = classNameFactory("vc-plugin-modal-");
const UserSummaryItem = findComponentByCodeLazy("defaultRenderUser", "showDefaultAvatarsForNullUsers");
const AvatarStyles = findByPropsLazy("moreUsers", "emptyUser", "avatarContainer", "clickableAvatar");
const UserRecord: Constructor<Partial<User>> = proxyLazy(() => UserStore.getCurrentUser().constructor) as any;
const UserSummaryItem = findComponentByCode("defaultRenderUser", "showDefaultAvatarsForNullUsers");
const AvatarStyles = findByProps("moreUsers", "emptyUser", "avatarContainer", "clickableAvatar");
const UserRecord = find<Constructor<Partial<User>>>(m => m?.prototype?.getAvatarURL && m?.prototype?.hasHadPremium);
interface PluginModalProps extends ModalProps {
plugin: Plugin;

View file

@ -33,19 +33,19 @@ import { Margins } from "@utils/margins";
import { classes, isObjectEmpty } from "@utils/misc";
import { useAwaiter } from "@utils/react";
import { Plugin } from "@utils/types";
import { findByPropsLazy } from "@webpack";
import { findByProps } from "@webpack";
import { Alerts, Button, Card, Forms, lodash, Parser, React, Select, Text, TextInput, Toasts, Tooltip, useMemo } from "@webpack/common";
import Plugins, { ExcludedPlugins } from "~plugins";
// Avoid circular dependency
const { startDependenciesRecursive, startPlugin, stopPlugin } = proxyLazy(() => require("../../plugins"));
const PluginManager = proxyLazy(() => require("../../plugins")) as typeof import("../../plugins");
const cl = classNameFactory("vc-plugins-");
const logger = new Logger("PluginSettings", "#a6d189");
const InputStyles = findByPropsLazy("inputWrapper", "inputDefault", "error");
const ButtonClasses = findByPropsLazy("button", "disabled", "enabled");
const InputStyles = findByProps("inputWrapper", "inputDefault", "error");
const ButtonClasses = findByProps("button", "disabled", "enabled");
function showErrorToast(message: string) {
@ -100,7 +100,7 @@ export function PluginCard({ plugin, disabled, onRestartNeeded, onMouseEnter, on
// If we're enabling a plugin, make sure all deps are enabled recursively.
if (!wasEnabled) {
const { restartNeeded, failures } = startDependenciesRecursive(plugin);
const { restartNeeded, failures } = PluginManager.startDependenciesRecursive(plugin);
if (failures.length) {
logger.error(`Failed to start dependencies for ${plugin.name}: ${failures.join(", ")}`);
showNotice("Failed to start dependencies: " + failures.join(", "), "Close", () => null);
@ -126,7 +126,7 @@ export function PluginCard({ plugin, disabled, onRestartNeeded, onMouseEnter, on
return;
}
const result = wasEnabled ? stopPlugin(plugin) : startPlugin(plugin);
const result = wasEnabled ? PluginManager.stopPlugin(plugin) : PluginManager.startPlugin(plugin);
if (!result) {
settings.enabled = false;

View file

@ -19,7 +19,7 @@
import "./Switch.css";
import { classes } from "@utils/misc";
import { findByPropsLazy } from "@webpack";
import { findByProps } from "@webpack";
interface SwitchProps {
checked: boolean;
@ -29,7 +29,7 @@ interface SwitchProps {
const SWITCH_ON = "var(--green-360)";
const SWITCH_OFF = "var(--primary-400)";
const SwitchClasses = findByPropsLazy("slider", "input", "container");
const SwitchClasses = findByProps("slider", "input", "container");
export function Switch({ checked, onChange, disabled }: SwitchProps) {
return (

View file

@ -22,7 +22,7 @@ import { Margins } from "@utils/margins";
import { canonicalizeMatch, canonicalizeReplace } from "@utils/patches";
import { makeCodeblock } from "@utils/text";
import { Patch, ReplaceFn } from "@utils/types";
import { search } from "@webpack";
import { searchFactories } from "@webpack";
import { Button, Clipboard, Forms, Parser, React, Switch, TextArea, TextInput } from "@webpack/common";
import { SettingsTab, wrapTab } from "./shared";
@ -33,7 +33,7 @@ if (IS_DEV) {
}
const findCandidates = debounce(function ({ find, setModule, setError }) {
const candidates = search(find);
const candidates = searchFactories(find);
const keys = Object.keys(candidates);
const len = keys.length;
if (len === 0)
@ -56,7 +56,7 @@ function ReplacementComponent({ module, match, replacement, setReplacementError
const [compileResult, setCompileResult] = React.useState<[boolean, string]>();
const [patchedCode, matchResult, diff] = React.useMemo(() => {
const src: string = fact.toString().replaceAll("\n", "");
const src = String(fact).replaceAll("\n", "");
try {
new RegExp(match);

View file

@ -16,7 +16,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import { Settings, useSettings } from "@api/Settings";
import { useSettings } from "@api/Settings";
import { classNameFactory } from "@api/Styles";
import { Flex } from "@components/Flex";
import { DeleteIcon, FolderIcon, PaintbrushIcon, PencilIcon, PlusIcon, RestartIcon } from "@components/Icons";
@ -27,9 +27,9 @@ import { openInviteModal } from "@utils/discord";
import { Margins } from "@utils/margins";
import { showItemInFolder } from "@utils/native";
import { useAwaiter } from "@utils/react";
import { findLazy } from "@webpack";
import { findComponentByFields } from "@webpack";
import { Card, Forms, React, showToast, TabBar, TextArea, useEffect, useRef, useState } from "@webpack/common";
import type { ComponentType, Ref, SyntheticEvent } from "react";
import type { Ref, SyntheticEvent } from "react";
import Plugins from "~plugins";
@ -37,14 +37,14 @@ import { AddonCard } from "./AddonCard";
import { QuickAction, QuickActionCard } from "./quickActions";
import { SettingsTab, wrapTab } from "./shared";
type FileInput = ComponentType<{
type FileInputProps = {
ref: Ref<HTMLInputElement>;
onChange: (e: SyntheticEvent<HTMLInputElement>) => void;
multiple?: boolean;
filters?: { name?: string; extensions: string[]; }[];
}>;
};
const FileInput: FileInput = findLazy(m => m.prototype?.activateUploadDialogue && m.prototype.setRef);
const FileInput = findComponentByFields<FileInputProps>("activateUploadDialogue", "setRef");
const cl = classNameFactory("vc-settings-theme-");
@ -257,7 +257,7 @@ function ThemesTab() {
Icon={PaintbrushIcon}
/>
{Settings.plugins.ClientTheme.enabled && (
{Vencord.Plugins.isPluginEnabled("ClientTheme") && (
<QuickAction
text="Edit ClientTheme"
action={() => openPluginModal(Plugins.ClientTheme)}

View file

@ -8,13 +8,12 @@ import "./quickActions.css";
import { classNameFactory } from "@api/Styles";
import { Card } from "@webpack/common";
import type { ComponentType, PropsWithChildren, ReactNode } from "react";
const cl = classNameFactory("vc-settings-quickActions-");
export interface QuickActionProps {
Icon: ComponentType<{ className?: string; }>;
text: ReactNode;
Icon: React.ComponentType<{ className?: string; }>;
text: React.ReactNode;
action?: () => void;
disabled?: boolean;
}
@ -30,7 +29,7 @@ export function QuickAction(props: QuickActionProps) {
);
}
export function QuickActionCard(props: PropsWithChildren) {
export function QuickActionCard(props: React.PropsWithChildren) {
return (
<Card className={cl("card")}>
{props.children}

View file

@ -24,9 +24,8 @@ import { handleComponentFailed } from "@components/handleComponentFailed";
import { Margins } from "@utils/margins";
import { onlyOnce } from "@utils/onlyOnce";
import { Forms, Text } from "@webpack/common";
import type { ComponentType, PropsWithChildren } from "react";
export function SettingsTab({ title, children }: PropsWithChildren<{ title: string; }>) {
export function SettingsTab({ title, children }: React.PropsWithChildren<{ title: string; }>) {
return (
<Forms.FormSection>
<Text
@ -44,7 +43,7 @@ export function SettingsTab({ title, children }: PropsWithChildren<{ title: stri
export const handleSettingsTabError = onlyOnce(handleComponentFailed);
export function wrapTab(component: ComponentType<any>, tab: string) {
export function wrapTab<P extends AnyRecord>(component: React.ComponentType<P>, tab: string) {
return ErrorBoundary.wrap(component, {
message: `Failed to render the ${tab} tab. If this issue persists, try using the installer to reinstall!`,
onError: handleSettingsTabError,

View file

@ -23,35 +23,61 @@ if (IS_DEV || IS_REPORTER) {
var logger = new Logger("Tracer", "#FFD166");
}
const noop = function () { };
export const beginTrace = !(IS_DEV || IS_REPORTER) ? noop :
export const beginTrace = !(IS_DEV || IS_REPORTER) ? () => { } :
function beginTrace(name: string, ...args: any[]) {
if (name in traces)
if (name in traces) {
throw new Error(`Trace ${name} already exists!`);
}
traces[name] = [performance.now(), args];
};
export const finishTrace = !(IS_DEV || IS_REPORTER) ? noop : function finishTrace(name: string) {
export const finishTrace = !(IS_DEV || IS_REPORTER) ? () => 0 :
function finishTrace(name: string) {
const end = performance.now();
const [start, args] = traces[name];
delete traces[name];
logger.debug(`${name} took ${end - start}ms`, args);
};
const totalTime = end - start;
logger.debug(`${name} took ${totalTime}ms`, args);
return totalTime;
};
type Func = (...args: any[]) => any;
type TraceNameMapper<F extends Func> = (...args: Parameters<F>) => string;
const noopTracer =
<F extends Func>(name: string, f: F, mapper?: TraceNameMapper<F>) => f;
function noopTracerWithResults<F extends Func>(name: string, f: F, mapper?: TraceNameMapper<F>) {
return function (this: unknown, ...args: Parameters<F>): [ReturnType<F>, number] {
return [f.apply(this, args), 0];
};
}
function noopTracer<F extends Func>(name: string, f: F, mapper?: TraceNameMapper<F>) {
return f;
}
export const traceFunctionWithResults = !(IS_DEV || IS_REPORTER)
? noopTracerWithResults
: function traceFunctionWithResults<F extends Func>(name: string, f: F, mapper?: TraceNameMapper<F>): (this: unknown, ...args: Parameters<F>) => [ReturnType<F>, number] {
return function (this: unknown, ...args: Parameters<F>) {
const traceName = mapper?.(...args) ?? name;
beginTrace(traceName, ...arguments);
try {
return [f.apply(this, args), finishTrace(traceName)];
} catch (e) {
finishTrace(traceName);
throw e;
}
};
};
export const traceFunction = !(IS_DEV || IS_REPORTER)
? noopTracer
: function traceFunction<F extends Func>(name: string, f: F, mapper?: TraceNameMapper<F>): F {
return function (this: any, ...args: Parameters<F>) {
return function (this: unknown, ...args: Parameters<F>) {
const traceName = mapper?.(...args) ?? name;
beginTrace(traceName, ...arguments);

View file

@ -8,10 +8,11 @@ import { Logger } from "@utils/Logger";
import { canonicalizeMatch } from "@utils/patches";
import * as Webpack from "@webpack";
import { wreq } from "@webpack";
const LazyChunkLoaderLogger = new Logger("LazyChunkLoader");
import { AnyModuleFactory, ModuleFactory } from "webpack";
export async function loadLazyChunks() {
const LazyChunkLoaderLogger = new Logger("LazyChunkLoader");
try {
LazyChunkLoaderLogger.log("Loading all chunks...");
@ -25,16 +26,12 @@ export async function loadLazyChunks() {
// True if resolved, false otherwise
const chunksSearchPromises = [] as Array<() => boolean>;
const LazyChunkRegex = canonicalizeMatch(/(?:(?:Promise\.all\(\[)?(\i\.e\("?[^)]+?"?\)[^\]]*?)(?:\]\))?)\.then\(\i\.bind\(\i,"?([^)]+?)"?\)\)/g);
const LazyChunkRegex = canonicalizeMatch(/(?:(?:Promise\.all\(\[)?(\i\.e\("?[^)]+?"?\)[^\]]*?)(?:\]\))?)\.then\(\i(?:\.\i)?\.bind\(\i,"?([^)]+?)"?(?:,[^)]+?)?\)\)/g);
async function searchAndLoadLazyChunks(factoryCode: string) {
const lazyChunks = factoryCode.matchAll(LazyChunkRegex);
const validChunkGroups = new Set<[chunkIds: number[], entryPoint: number]>();
// Workaround for a chunk that depends on the ChannelMessage component but may be be force loaded before
// the chunk containing the component
const shouldForceDefer = factoryCode.includes(".Messages.GUILD_FEED_UNFEATURE_BUTTON_TEXT");
await Promise.all(Array.from(lazyChunks).map(async ([, rawChunkIds, entryPoint]) => {
const chunkIds = rawChunkIds ? Array.from(rawChunkIds.matchAll(Webpack.ChunkIdsRegex)).map(m => Number(m[1])) : [];
@ -69,19 +66,14 @@ export async function loadLazyChunks() {
await Promise.all(
Array.from(validChunkGroups)
.map(([chunkIds]) =>
Promise.all(chunkIds.map(id => wreq.e(id as any).catch(() => { })))
Promise.all(chunkIds.map(id => wreq.e(id)))
)
);
// Requires the entry points for all valid chunk groups
for (const [, entryPoint] of validChunkGroups) {
try {
if (shouldForceDefer) {
deferredRequires.add(entryPoint);
continue;
}
if (wreq.m[entryPoint]) wreq(entryPoint as any);
if (wreq.m[entryPoint]) wreq(entryPoint);
} catch (err) {
console.error(err);
}
@ -109,32 +101,33 @@ export async function loadLazyChunks() {
}, 0);
}
Webpack.factoryListeners.add(factory => {
function factoryListener(factory: AnyModuleFactory | ModuleFactory) {
let isResolved = false;
searchAndLoadLazyChunks(factory.toString()).then(() => isResolved = true);
chunksSearchPromises.push(() => isResolved);
});
for (const factoryId in wreq.m) {
let isResolved = false;
searchAndLoadLazyChunks(wreq.m[factoryId].toString()).then(() => isResolved = true);
searchAndLoadLazyChunks(String(factory))
.then(() => isResolved = true)
.catch(() => isResolved = true);
chunksSearchPromises.push(() => isResolved);
}
Webpack.factoryListeners.add(factoryListener);
for (const factoryId in wreq.m) {
factoryListener(wreq.m[factoryId]);
}
await chunksSearchingDone;
Webpack.factoryListeners.delete(factoryListener);
// Require deferred entry points
for (const deferredRequire of deferredRequires) {
wreq!(deferredRequire as any);
wreq(deferredRequire);
}
// All chunks Discord has mapped to asset files, even if they are not used anymore
const allChunks = [] as number[];
// Matches "id" or id:
for (const currentMatch of wreq!.u.toString().matchAll(/(?:"([\deE]+?)"(?![,}]))|(?:([\deE]+?):)/g)) {
for (const currentMatch of String(wreq.u).matchAll(/(?:"([\deE]+?)"(?![,}]))|(?:([\deE]+?):)/g)) {
const id = currentMatch[1] ?? currentMatch[2];
if (id == null) continue;
@ -143,7 +136,8 @@ export async function loadLazyChunks() {
if (allChunks.length === 0) throw new Error("Failed to get all chunks");
// Chunks that are not loaded (not used) by Discord code anymore
// Chunks which our regex could not catch to load
// It will always contain WebWorker assets, and also currently contains some language packs which are loaded differently
const chunksLeft = allChunks.filter(id => {
return !(validChunks.has(id) || invalidChunks.has(id));
});
@ -153,12 +147,9 @@ export async function loadLazyChunks() {
.then(r => r.text())
.then(t => t.includes("importScripts("));
// Loads and requires a chunk
// Loads the chunk. Currently this only happens with the language packs which are loaded differently
if (!isWorkerAsset) {
await wreq.e(id as any);
// Technically, the id of the chunk does not match the entry point
// But, still try it because we have no way to get the actual entry point
if (wreq.m[id]) wreq(id as any);
await wreq.e(id);
}
}));

View file

@ -4,22 +4,39 @@
* SPDX-License-Identifier: GPL-3.0-or-later
*/
import { SYM_LAZY_COMPONENT_INNER } from "@utils/lazyReact";
import { Logger } from "@utils/Logger";
import { SYM_PROXY_INNER_GET, SYM_PROXY_INNER_VALUE } from "@utils/proxyInner";
import * as Webpack from "@webpack";
import { patches } from "plugins";
import { addPatch, patches } from "plugins";
import { loadLazyChunks } from "./loadLazyChunks";
const ReporterLogger = new Logger("Reporter");
async function runReporter() {
const ReporterLogger = new Logger("Reporter");
try {
ReporterLogger.log("Starting test...");
let loadLazyChunksResolve: (value: void | PromiseLike<void>) => void;
let loadLazyChunksResolve: (value: void) => void;
const loadLazyChunksDone = new Promise<void>(r => loadLazyChunksResolve = r);
Webpack.beforeInitListeners.add(() => loadLazyChunks().then((loadLazyChunksResolve)));
// The main patch for starting the reporter chunk loading
addPatch({
find: '"Could not find app-mount"',
replacement: {
match: /(?<="use strict";)/,
replace: "Vencord.Webpack._initReporter();"
}
}, "Vencord Reporter");
// @ts-ignore
Vencord.Webpack._initReporter = function () {
// initReporter is called in the patched entry point of Discord
// setImmediate to only start searching for lazy chunks after Discord initialized the app
setTimeout(() => loadLazyChunks().then(loadLazyChunksResolve), 0);
};
await loadLazyChunksDone;
for (const patch of patches) {
@ -28,52 +45,158 @@ async function runReporter() {
}
}
for (const [searchType, args] of Webpack.lazyWebpackSearchHistory) {
let method = searchType;
if (searchType === "findComponent") method = "find";
if (searchType === "findExportedComponent") method = "findByProps";
if (searchType === "waitFor" || searchType === "waitForComponent") {
if (typeof args[0] === "string") method = "findByProps";
else method = "find";
for (const [plugin, moduleId, match, totalTime] of Vencord.WebpackPatcher.patchTimings) {
if (totalTime > 3) {
new Logger("WebpackInterceptor").warn(`Patch by ${plugin} took ${totalTime}ms (Module id is ${String(moduleId)}): ${match}`);
}
}
if (searchType === "waitForStore") method = "findStore";
let result: any;
await Promise.all(Webpack.webpackSearchHistory.map(async ([searchType, args]) => {
args = [...args];
let result = null as any;
try {
if (method === "proxyLazyWebpack" || method === "LazyComponentWebpack") {
switch (searchType) {
case "webpackDependantLazy":
case "webpackDependantLazyComponent": {
const [factory] = args;
result = factory();
} else if (method === "extractAndLoadChunks") {
const [code, matcher] = args;
break;
}
case "extractAndLoadChunks": {
const extractAndLoadChunks = args.shift();
result = await Webpack.extractAndLoadChunks(code, matcher);
if (result === false) result = null;
} else if (method === "mapMangledModule") {
const [code, mapper] = args;
result = Webpack.mapMangledModule(code, mapper);
if (Object.keys(result).length !== Object.keys(mapper).length) throw new Error("Webpack Find Fail");
} else {
// @ts-ignore
result = Webpack[method](...args);
result = await extractAndLoadChunks();
if (result === false) {
result = null;
}
if (result == null || (result.$$vencordInternal != null && result.$$vencordInternal() == null)) throw new Error("Webpack Find Fail");
break;
}
default: {
const findResult = args.shift();
if (findResult != null) {
if (findResult.$$vencordCallbackCalled != null && findResult.$$vencordCallbackCalled()) {
result = findResult;
break;
}
if (findResult[SYM_PROXY_INNER_GET] != null) {
result = findResult[SYM_PROXY_INNER_VALUE];
break;
}
if (findResult[SYM_LAZY_COMPONENT_INNER] != null) {
result = findResult[SYM_LAZY_COMPONENT_INNER]();
break;
}
if (searchType === "mapMangledModule") {
result = findResult;
for (const innerMap in result) {
if (
(result[innerMap][SYM_PROXY_INNER_GET] != null && result[innerMap][SYM_PROXY_INNER_VALUE] == null) ||
(result[innerMap][SYM_LAZY_COMPONENT_INNER] != null && result[innerMap][SYM_LAZY_COMPONENT_INNER]() == null)
) {
throw new Error("Webpack Find Fail");
}
}
break;
}
// This can happen if a `find` was immediately found
result = findResult;
}
break;
}
}
if (result == null) {
throw new Error("Webpack Find Fail");
}
} catch (e) {
let logMessage = searchType;
if (method === "find" || method === "proxyLazyWebpack" || method === "LazyComponentWebpack") logMessage += `(${args[0].toString().slice(0, 147)}...)`;
else if (method === "extractAndLoadChunks") logMessage += `([${args[0].map(arg => `"${arg}"`).join(", ")}], ${args[1].toString()})`;
else if (method === "mapMangledModule") {
const failedMappings = Object.keys(args[1]).filter(key => result?.[key] == null);
logMessage += `("${args[0]}", {\n${failedMappings.map(mapping => `\t${mapping}: ${args[1][mapping].toString().slice(0, 147)}...`).join(",\n")}\n})`;
let filterName = "";
let parsedArgs = args;
if (args[0].$$vencordProps != null) {
if (["find", "findComponent", "waitFor"].includes(searchType)) {
filterName = args[0].$$vencordProps[0];
parsedArgs = args[0].$$vencordProps.slice(1);
} else {
parsedArgs = args[0].$$vencordProps;
}
}
function stringifyFilter(code: Webpack.CodeFilterWithSingle) {
if (Array.isArray(code)) {
return `[${code.map(arg => arg instanceof RegExp ? String(arg) : JSON.stringify(arg)).join(", ")}]`;
}
return code instanceof RegExp ? String(code) : JSON.stringify(code);
}
// if parsedArgs is the same as args, it means vencordProps of the filter was not available (like in normal filter functions),
// so log the filter function instead
if (
parsedArgs === args &&
["waitFor", "find", "findComponent", "webpackDependantLazy", "webpackDependantLazyComponent"].includes(searchType)
) {
let filter = String(parsedArgs[0]);
if (filter.length > 150) {
filter = filter.slice(0, 147) + "...";
}
logMessage += `(${filter})`;
} else if (searchType === "extractAndLoadChunks") {
const [code, matcher] = parsedArgs;
let regexStr: string;
if (matcher === Webpack.DefaultExtractAndLoadChunksRegex) {
regexStr = "DefaultExtractAndLoadChunksRegex";
} else {
regexStr = String(matcher);
}
logMessage += `(${stringifyFilter(code)}, ${regexStr})`;
} else if (searchType === "mapMangledModule") {
const [code, mappers] = parsedArgs;
const parsedFailedMappers = Object.entries<any>(mappers)
.filter(([key]) =>
result == null ||
(result[key]?.[SYM_PROXY_INNER_GET] != null && result[key][SYM_PROXY_INNER_VALUE] == null) ||
(result[key]?.[SYM_LAZY_COMPONENT_INNER] != null && result[key][SYM_LAZY_COMPONENT_INNER]() == null)
)
.map(([key, filter]) => {
let parsedFilter: string;
if (filter.$$vencordProps != null) {
const filterName = filter.$$vencordProps[0];
parsedFilter = `${filterName}(${filter.$$vencordProps.slice(1).map((arg: any) => arg instanceof RegExp ? String(arg) : JSON.stringify(arg)).join(", ")})`;
} else {
parsedFilter = String(filter);
if (parsedFilter.length > 150) {
parsedFilter = parsedFilter.slice(0, 147) + "...";
}
}
return [key, parsedFilter];
});
logMessage += `(${stringifyFilter(code)}, {\n${parsedFailedMappers.map(([key, parsedFilter]) => `\t${key}: ${parsedFilter}`).join(",\n")}\n})`;
} else {
logMessage += `(${filterName.length ? `${filterName}(` : ""}${parsedArgs.map(stringifyFilter).join(", ")})${filterName.length ? ")" : ""}`;
}
else logMessage += `(${args.map(arg => `"${arg}"`).join(", ")})`;
ReporterLogger.log("Webpack Find Fail:", logMessage);
}
}
}));
ReporterLogger.log("Finished test");
} catch (e) {
@ -81,4 +204,5 @@ async function runReporter() {
}
}
runReporter();
// Run after the Vencord object has been created
setTimeout(runReporter, 0);

11
src/globals.d.ts vendored
View file

@ -19,6 +19,10 @@
import { LoDashStatic } from "lodash";
declare global {
type AnyRecord = Record<PropertyKey, any>;
type AnyComponentType<P extends AnyRecord = AnyRecord> = React.ComponentType<P & AnyRecord> & AnyRecord;
type AnyComponentTypeWithChildren<P extends AnyRecord = AnyRecord> = AnyComponentType<React.PropsWithChildren<P>>;
/**
* This exists only at build time, so references to it in patches should insert it
* via String interpolation OR use different replacement code based on this
@ -64,13 +68,8 @@ declare global {
export var Vesktop: any;
export var VesktopNative: any;
interface Window {
webpackChunkdiscord_app: {
push(chunk: any): any;
pop(): any;
};
interface Window extends AnyRecord {
_: LoDashStatic;
[k: string]: any;
}
}

View file

@ -20,6 +20,7 @@ import { definePluginSettings } from "@api/Settings";
import { Devs } from "@utils/constants";
import { Logger } from "@utils/Logger";
import definePlugin, { OptionType, StartAt } from "@utils/types";
import { WebpackRequire } from "webpack";
const settings = definePluginSettings({
disableAnalytics: {
@ -81,9 +82,9 @@ export default definePlugin({
Object.defineProperty(Function.prototype, "g", {
configurable: true,
set(v: any) {
set(this: WebpackRequire, globalObj: WebpackRequire["g"]) {
Object.defineProperty(this, "g", {
value: v,
value: globalObj,
configurable: true,
enumerable: true,
writable: true
@ -92,11 +93,11 @@ export default definePlugin({
// Ensure this is most likely the Sentry WebpackInstance.
// Function.g is a very generic property and is not uncommon for another WebpackInstance (or even a React component: <g></g>) to include it
const { stack } = new Error();
if (!(stack?.includes("discord.com") || stack?.includes("discordapp.com")) || !String(this).includes("exports:{}") || this.c != null) {
if (this.c != null || !stack?.includes("http") || !String(this).includes("exports:{}")) {
return;
}
const assetPath = stack?.match(/\/assets\/.+?\.js/)?.[0];
const assetPath = stack.match(/http.+?(?=:\d+?:\d+?$)/m)?.[0];
if (!assetPath) {
return;
}
@ -106,7 +107,8 @@ export default definePlugin({
srcRequest.send();
// Final condition to see if this is the Sentry WebpackInstance
if (!srcRequest.responseText.includes("window.DiscordSentry=")) {
// This is matching window.DiscordSentry=, but without `window` to avoid issues on some proxies
if (!srcRequest.responseText.includes(".DiscordSentry=")) {
return;
}

View file

@ -16,7 +16,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import { Settings } from "@api/Settings";
import { definePluginSettings } from "@api/Settings";
import BackupAndRestoreTab from "@components/VencordSettings/BackupAndRestoreTab";
import CloudTab from "@components/VencordSettings/CloudTab";
import PatchHelperTab from "@components/VencordSettings/PatchHelperTab";
@ -33,11 +33,27 @@ import gitHash from "~git-hash";
type SectionType = "HEADER" | "DIVIDER" | "CUSTOM";
type SectionTypes = Record<SectionType, SectionType>;
const settings = definePluginSettings({
settingsLocation: {
type: OptionType.SELECT,
description: "Where to put the Vencord settings section",
options: [
{ label: "At the very top", value: "top" },
{ label: "Above the Nitro section", value: "aboveNitro", default: true },
{ label: "Below the Nitro section", value: "belowNitro" },
{ label: "Above Activity Settings", value: "aboveActivity" },
{ label: "Below Activity Settings", value: "belowActivity" },
{ label: "At the very bottom", value: "bottom" },
]
}
});
export default definePlugin({
name: "Settings",
description: "Adds Settings UI and debug info",
authors: [Devs.Ven, Devs.Megu],
required: true,
settings,
patches: [
{
@ -136,12 +152,12 @@ export default definePlugin({
].filter(Boolean);
},
isRightSpot({ header, settings }: { header?: string; settings?: string[]; }) {
const firstChild = settings?.[0];
isRightSpot({ header, settingsChilds }: { header?: string; settingsChilds?: string[]; }) {
const firstChild = settingsChilds?.[0];
// lowest two elements... sanity backup
if (firstChild === "LOGOUT" || firstChild === "SOCIAL_LINKS") return true;
const { settingsLocation } = Settings.plugins.Settings;
const { settingsLocation } = settings.store;
if (settingsLocation === "bottom") return firstChild === "LOGOUT";
if (settingsLocation === "belowActivity") return firstChild === "CHANGELOG";
@ -181,21 +197,6 @@ export default definePlugin({
};
},
options: {
settingsLocation: {
type: OptionType.SELECT,
description: "Where to put the Vencord settings section",
options: [
{ label: "At the very top", value: "top" },
{ label: "Above the Nitro section", value: "aboveNitro", default: true },
{ label: "Below the Nitro section", value: "belowNitro" },
{ label: "Above Activity Settings", value: "aboveActivity" },
{ label: "Below Activity Settings", value: "belowActivity" },
{ label: "At the very bottom", value: "bottom" },
]
},
},
get electronVersion() {
return VencordNative.native.getVersions().electron || window.armcord?.electron || null;
},

View file

@ -59,7 +59,7 @@ const TrustedRolesIds = [
const AsyncFunction = async function () { }.constructor;
const ShowCurrentGame = getUserSettingLazy<boolean>("status", "showCurrentGame")!;
const ShowCurrentGame = getUserSettingLazy<boolean>("status", "showCurrentGame");
async function forceUpdate() {
const outdated = await checkForUpdates();

View file

@ -9,7 +9,7 @@ import ErrorBoundary from "@components/ErrorBoundary";
import { Devs } from "@utils/constants";
import { getCurrentChannel } from "@utils/discord";
import definePlugin, { OptionType } from "@utils/types";
import { findByPropsLazy, findComponentByCodeLazy } from "@webpack";
import { findByProps, findComponentByCode } from "@webpack";
import { ContextMenuApi, Menu, useEffect, useRef } from "@webpack/common";
import { User } from "discord-types/general";
@ -19,11 +19,11 @@ interface UserProfileProps {
originalPopout: () => React.ReactNode;
}
const UserProfile = findComponentByCodeLazy("UserProfilePopoutWrapper: user cannot be undefined");
const styles = findByPropsLazy("accountProfilePopoutWrapper");
const UserProfile = findComponentByCode("UserProfilePopoutWrapper: user cannot be undefined");
const styles = findByProps("accountProfilePopoutWrapper");
let openAlternatePopout = false;
let accountPanelRef: React.MutableRefObject<Record<PropertyKey, any> | null> = { current: null };
let accountPanelRef: React.MutableRefObject<AnyRecord | null> = { current: null };
const AccountPanelContextMenu = ErrorBoundary.wrap(() => {
const { prioritizeServerProfile } = settings.use(["prioritizeServerProfile"]);

View file

@ -21,12 +21,12 @@ import { definePluginSettings } from "@api/Settings";
import ErrorBoundary from "@components/ErrorBoundary";
import { Devs } from "@utils/constants";
import definePlugin, { OptionType } from "@utils/types";
import { findByCodeLazy, findByPropsLazy } from "@webpack";
import { findByProps, findComponentByCode } from "@webpack";
type AnonUpload = Upload & { anonymise?: boolean; };
const ActionBarIcon = findByCodeLazy(".actionBarIcon)");
const UploadDraft = findByPropsLazy("popFirstFile", "update");
const ActionBarIcon = findComponentByCode(".actionBarIcon)");
const UploadDraft = findByProps("popFirstFile", "update");
const enum Methods {
Random,

View file

@ -20,10 +20,10 @@ import { popNotice, showNotice } from "@api/Notices";
import { Link } from "@components/Link";
import { Devs } from "@utils/constants";
import definePlugin, { ReporterTestable } from "@utils/types";
import { findByCodeLazy } from "@webpack";
import { findByCode } from "@webpack";
import { ApplicationAssetUtils, FluxDispatcher, Forms, Toasts } from "@webpack/common";
const fetchApplicationsRPC = findByCodeLazy("APPLICATION_RPC(", "Client ID");
const fetchApplicationsRPC = findByCode("APPLICATION_RPC(", "Client ID");
async function lookupAsset(applicationId: string, key: string): Promise<string> {
return (await ApplicationAssetUtils.fetchAssetIds(applicationId, [key]))[0];

View file

@ -17,15 +17,15 @@
*/
import ErrorBoundary from "@components/ErrorBoundary";
import { findByPropsLazy, findComponentByCodeLazy, findStoreLazy } from "@webpack";
import { findByProps, findComponentByCode, findStore } from "@webpack";
import { useStateFromStores } from "@webpack/common";
import type { CSSProperties } from "react";
import { ExpandedGuildFolderStore, settings } from ".";
const ChannelRTCStore = findStoreLazy("ChannelRTCStore");
const Animations = findByPropsLazy("a", "animated", "useTransition");
const GuildsBar = findComponentByCodeLazy('("guildsnav")');
const ChannelRTCStore = findStore("ChannelRTCStore");
const Animations = findByProps("a", "animated", "useTransition");
const GuildsBar = findComponentByCode('("guildsnav")');
export default ErrorBoundary.wrap(guildsBarProps => {
const expandedFolders = useStateFromStores([ExpandedGuildFolderStore], () => ExpandedGuildFolderStore.getExpandedFolders());

View file

@ -19,7 +19,7 @@
import { definePluginSettings } from "@api/Settings";
import { Devs } from "@utils/constants";
import definePlugin, { OptionType } from "@utils/types";
import { findByPropsLazy, findLazy, findStoreLazy } from "@webpack";
import { find, findByProps, findStore } from "@webpack";
import { FluxDispatcher, i18n, useMemo } from "@webpack/common";
import FolderSideBar from "./FolderSideBar";
@ -30,10 +30,10 @@ enum FolderIconDisplay {
MoreThanOneFolderExpanded
}
export const ExpandedGuildFolderStore = findStoreLazy("ExpandedGuildFolderStore");
const SortedGuildStore = findStoreLazy("SortedGuildStore");
const GuildsTree = findLazy(m => m.prototype?.moveNextTo);
const FolderUtils = findByPropsLazy("move", "toggleGuildFolderExpand");
export const ExpandedGuildFolderStore = findStore("ExpandedGuildFolderStore");
const SortedGuildStore = findStore("SortedGuildStore");
const GuildsTree = find(m => m.prototype?.moveNextTo);
const FolderUtils = findByProps("move", "toggleGuildFolderExpand");
let lastGuildId = null as string | null;
let dispatchingFoldersClose = false;

View file

@ -16,7 +16,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import { definePluginSettings, Settings } from "@api/Settings";
import { definePluginSettings } from "@api/Settings";
import { Devs } from "@utils/constants";
import { canonicalizeMatch } from "@utils/patches";
import definePlugin, { OptionType } from "@utils/types";
@ -31,7 +31,7 @@ const settings = definePluginSettings({
noSpellCheck: {
type: OptionType.BOOLEAN,
description: "Disable spellcheck in notes",
disabled: () => Settings.plugins.BetterNotesBox.hide,
disabled: () => settings.store.hide,
default: false
}
});

View file

@ -10,12 +10,12 @@ import { ImageIcon } from "@components/Icons";
import { Devs } from "@utils/constants";
import { getCurrentGuild, openImageModal } from "@utils/discord";
import definePlugin, { OptionType } from "@utils/types";
import { findByPropsLazy } from "@webpack";
import { findByProps } from "@webpack";
import { Clipboard, GuildStore, Menu, PermissionStore } from "@webpack/common";
const GuildSettingsActions = findByPropsLazy("open", "selectRole", "updateGuild");
const GuildSettingsActions = findByProps("open", "selectRole", "updateGuild");
const DeveloperMode = getUserSettingLazy("appearance", "developerMode")!;
const DeveloperMode = getUserSettingLazy("appearance", "developerMode");
function PencilIcon() {
return (

View file

@ -16,16 +16,32 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import { Settings } from "@api/Settings";
import { definePluginSettings } from "@api/Settings";
import { Devs } from "@utils/constants";
import definePlugin, { OptionType } from "@utils/types";
import { Clipboard, Toasts } from "@webpack/common";
const settings = definePluginSettings({
bothStyles: {
type: OptionType.BOOLEAN,
description: "Show both role dot and coloured names",
restartNeeded: true,
default: false,
},
copyRoleColorInProfilePopout: {
type: OptionType.BOOLEAN,
description: "Allow click on role dot in profile popout to copy role color",
restartNeeded: true,
default: false
}
});
export default definePlugin({
name: "BetterRoleDot",
authors: [Devs.Ven, Devs.AutumnVN],
description:
"Copy role colour on RoleDot (accessibility setting) click. Also allows using both RoleDot and coloured names simultaneously",
settings,
patches: [
{
@ -39,7 +55,7 @@ export default definePlugin({
find: '"dot"===',
all: true,
noWarn: true,
predicate: () => Settings.plugins.BetterRoleDot.bothStyles,
predicate: () => settings.store.bothStyles,
replacement: {
match: /"(?:username|dot)"===\i(?!\.\i)/g,
replace: "true",
@ -49,7 +65,7 @@ export default definePlugin({
{
find: ".ADD_ROLE_A11Y_LABEL",
all: true,
predicate: () => Settings.plugins.BetterRoleDot.copyRoleColorInProfilePopout && !Settings.plugins.BetterRoleDot.bothStyles,
predicate: () => settings.store.copyRoleColorInProfilePopout && !settings.store.bothStyles,
noWarn: true,
replacement: {
match: /"dot"===\i/,
@ -59,7 +75,7 @@ export default definePlugin({
{
find: ".roleVerifiedIcon",
all: true,
predicate: () => Settings.plugins.BetterRoleDot.copyRoleColorInProfilePopout && !Settings.plugins.BetterRoleDot.bothStyles,
predicate: () => settings.store.copyRoleColorInProfilePopout && !settings.store.bothStyles,
noWarn: true,
replacement: {
match: /"dot"===\i/,
@ -68,21 +84,6 @@ export default definePlugin({
}
],
options: {
bothStyles: {
type: OptionType.BOOLEAN,
description: "Show both role dot and coloured names",
restartNeeded: true,
default: false,
},
copyRoleColorInProfilePopout: {
type: OptionType.BOOLEAN,
description: "Allow click on role dot in profile popout to copy role color",
restartNeeded: true,
default: false
}
},
copyToClipBoard(color: string) {
Clipboard.copy(color);
Toasts.show({

View file

@ -21,20 +21,20 @@ import { definePluginSettings } from "@api/Settings";
import ErrorBoundary from "@components/ErrorBoundary";
import { Devs } from "@utils/constants";
import definePlugin, { OptionType } from "@utils/types";
import { findByPropsLazy, findExportedComponentLazy, findStoreLazy } from "@webpack";
import { findByProps, findExportedComponent, findStore } from "@webpack";
import { Constants, React, RestAPI, Tooltip } from "@webpack/common";
import { RenameButton } from "./components/RenameButton";
import { Session, SessionInfo } from "./types";
import { fetchNamesFromDataStore, getDefaultName, GetOsColor, GetPlatformIcon, savedSessionsCache, saveSessionsToDataStore } from "./utils";
const AuthSessionsStore = findStoreLazy("AuthSessionsStore");
const UserSettingsModal = findByPropsLazy("saveAccountChanges", "open");
const AuthSessionsStore = findStore("AuthSessionsStore");
const UserSettingsModal = findByProps("saveAccountChanges", "open");
const TimestampClasses = findByPropsLazy("timestampTooltip", "blockquoteContainer");
const SessionIconClasses = findByPropsLazy("sessionIcon");
const TimestampClasses = findByProps("timestampTooltip", "blockquoteContainer");
const SessionIconClasses = findByProps("sessionIcon");
const BlobMask = findExportedComponentLazy("BlobMask");
const BlobMask = findExportedComponent("BlobMask");
const settings = definePluginSettings({
backgroundCheck: {

View file

@ -8,8 +8,10 @@ import { definePluginSettings } from "@api/Settings";
import { classNameFactory } from "@api/Styles";
import { Devs } from "@utils/constants";
import { Logger } from "@utils/Logger";
import { SYM_PROXY_INNER_VALUE } from "@utils/proxyInner";
import { NoopComponent } from "@utils/react";
import definePlugin, { OptionType } from "@utils/types";
import { waitFor } from "@webpack";
import { findByProps } from "@webpack";
import { ComponentDispatch, FocusLock, i18n, Menu, useEffect, useRef } from "@webpack/common";
import type { HTMLAttributes, ReactElement } from "react";
@ -18,8 +20,7 @@ import PluginsSubmenu from "./PluginsSubmenu";
type SettingsEntry = { section: string, label: string; };
const cl = classNameFactory("");
let Classes: Record<string, string>;
waitFor(["animating", "baseLayer", "bg", "layer", "layers"], m => Classes = m);
const Classes = findByProps("animating", "baseLayer", "bg", "layer", "layers");
const settings = definePluginSettings({
disableFade: {
@ -142,7 +143,7 @@ export default definePlugin({
// try catch will only catch errors in the Layer function (hence why it's called as a plain function rather than a component), but
// not in children
Layer(props: LayerProps) {
if (!FocusLock || !ComponentDispatch || !Classes) {
if (FocusLock === NoopComponent || ComponentDispatch[SYM_PROXY_INNER_VALUE] == null || Classes[SYM_PROXY_INNER_VALUE] == null) {
new Logger("BetterSettings").error("Failed to find some components");
return props.children;
}

View file

@ -16,9 +16,9 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import { findStoreLazy } from "@webpack";
import { findStore } from "@webpack";
import * as t from "./types/stores";
export const ApplicationStreamPreviewStore: t.ApplicationStreamPreviewStore = findStoreLazy("ApplicationStreamPreviewStore");
export const ApplicationStreamingStore: t.ApplicationStreamingStore = findStoreLazy("ApplicationStreamingStore");
export const ApplicationStreamPreviewStore: t.ApplicationStreamPreviewStore = findStore("ApplicationStreamPreviewStore");
export const ApplicationStreamingStore: t.ApplicationStreamingStore = findStore("ApplicationStreamingStore");

View file

@ -16,7 +16,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import { Settings } from "@api/Settings";
import { definePluginSettings } from "@api/Settings";
import { Devs } from "@utils/constants";
import definePlugin, { OptionType } from "@utils/types";
@ -26,7 +26,7 @@ function setCss() {
style.textContent = `
.vc-nsfw-img [class^=imageWrapper] img,
.vc-nsfw-img [class^=wrapperPaused] video {
filter: blur(${Settings.plugins.BlurNSFW.blurAmount}px);
filter: blur(${settings.store.blurAmount}px);
transition: filter 0.2s;
}
.vc-nsfw-img [class^=imageWrapper]:hover img,
@ -36,10 +36,20 @@ function setCss() {
`;
}
const settings = definePluginSettings({
blurAmount: {
type: OptionType.NUMBER,
description: "Blur Amount",
default: 10,
onChange: setCss
}
});
export default definePlugin({
name: "BlurNSFW",
description: "Blur attachments in NSFW channels until hovered",
authors: [Devs.Ven],
settings,
patches: [
{
@ -51,15 +61,6 @@ export default definePlugin({
}
],
options: {
blurAmount: {
type: OptionType.NUMBER,
description: "Blur Amount",
default: 10,
onChange: setCss
}
},
start() {
style = document.createElement("style");
style.id = "VcBlurNsfw";

View file

@ -16,7 +16,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import { Settings } from "@api/Settings";
import { definePluginSettings } from "@api/Settings";
import ErrorBoundary from "@components/ErrorBoundary";
import { Devs } from "@utils/constants";
import { useTimer } from "@utils/react";
@ -25,7 +25,7 @@ import { React } from "@webpack/common";
function formatDuration(ms: number) {
// here be dragons (moment fucking sucks)
const human = Settings.plugins.CallTimer.format === "human";
const human = settings.store.format === "human";
const format = (n: number) => human ? n : n.toString().padStart(2, "0");
const unit = (s: string) => human ? s : "";
@ -46,15 +46,7 @@ function formatDuration(ms: number) {
return res;
}
export default definePlugin({
name: "CallTimer",
description: "Adds a timer to vcs",
authors: [Devs.Ven],
startTime: 0,
interval: void 0 as NodeJS.Timeout | undefined,
options: {
const settings = definePluginSettings({
format: {
type: OptionType.SELECT,
description: "The timer format. This can be any valid moment.js format",
@ -70,7 +62,16 @@ export default definePlugin({
}
]
}
},
});
export default definePlugin({
name: "CallTimer",
description: "Adds a timer to vcs",
authors: [Devs.Ven],
settings,
startTime: 0,
interval: void 0 as NodeJS.Timeout | undefined,
patches: [{
find: "renderConnectionStatus(){",

View file

@ -11,10 +11,10 @@ import { Devs } from "@utils/constants";
import { Margins } from "@utils/margins";
import { classes } from "@utils/misc";
import definePlugin, { OptionType, StartAt } from "@utils/types";
import { findByCodeLazy, findComponentByCodeLazy, findStoreLazy } from "@webpack";
import { findByCode, findComponentByCode, findStore } from "@webpack";
import { Button, Forms, ThemeStore, useStateFromStores } from "@webpack/common";
const ColorPicker = findComponentByCodeLazy(".Messages.USER_SETTINGS_PROFILE_COLOR_SELECT_COLOR", ".BACKGROUND_PRIMARY)");
const ColorPicker = findComponentByCode(".Messages.USER_SETTINGS_PROFILE_COLOR_SELECT_COLOR", ".BACKGROUND_PRIMARY)");
const colorPresets = [
"#1E1514", "#172019", "#13171B", "#1C1C28", "#402D2D",
@ -30,20 +30,20 @@ function onPickColor(color: number) {
updateColorVars(hexColor);
}
const saveClientTheme = findByCodeLazy('type:"UNSYNCED_USER_SETTINGS_UPDATE', '"system"===');
const saveClientTheme = findByCode('type:"UNSYNCED_USER_SETTINGS_UPDATE', '"system"===');
function setTheme(theme: string) {
saveClientTheme({ theme });
}
const NitroThemeStore = findStoreLazy("ClientThemesBackgroundStore");
const ClientThemesBackgroundStore = findStore("ClientThemesBackgroundStore");
function ThemeSettings() {
const theme = useStateFromStores([ThemeStore], () => ThemeStore.theme);
const isLightTheme = theme === "light";
const oppositeTheme = isLightTheme ? "dark" : "light";
const nitroTheme = useStateFromStores([NitroThemeStore], () => NitroThemeStore.gradientPreset);
const nitroTheme = useStateFromStores([ClientThemesBackgroundStore], () => ClientThemesBackgroundStore.gradientPreset);
const nitroThemeEnabled = nitroTheme !== undefined;
const selectedLuminance = relativeLuminance(settings.store.color);

View file

@ -19,40 +19,43 @@
import { Devs } from "@utils/constants";
import { getCurrentChannel, getCurrentGuild } from "@utils/discord";
import { SYM_LAZY_CACHED, SYM_LAZY_GET } from "@utils/lazy";
import { SYM_LAZY_COMPONENT_INNER } from "@utils/lazyReact";
import { relaunch } from "@utils/native";
import { canonicalizeMatch, canonicalizeReplace, canonicalizeReplacement } from "@utils/patches";
import { SYM_PROXY_INNER_GET, SYM_PROXY_INNER_VALUE } from "@utils/proxyInner";
import definePlugin, { PluginNative, StartAt } from "@utils/types";
import * as Webpack from "@webpack";
import { extract, filters, findAll, findModuleId, search } from "@webpack";
import { cacheFindAll, cacheFindModuleId, extract, filters, searchFactories } from "@webpack";
import * as Common from "@webpack/common";
import { loadLazyChunks } from "debug/loadLazyChunks";
import type { ComponentType } from "react";
const DESKTOP_ONLY = (f: string) => () => {
throw new Error(`'${f}' is Discord Desktop only.`);
};
const define: typeof Object.defineProperty =
(obj, prop, desc) => {
if (Object.hasOwn(desc, "value"))
desc.writable = true;
return Object.defineProperty(obj, prop, {
type Define = typeof Object.defineProperty;
const define: Define = (target, p, attributes) => {
if (Object.hasOwn(attributes, "value")) {
attributes.writable = true;
}
return Object.defineProperty(target, p, {
configurable: true,
enumerable: true,
...desc
...attributes
});
};
};
function makeShortcuts() {
function newFindWrapper(filterFactory: (...props: any[]) => Webpack.FilterFn) {
function newFindWrapper(filterFactory: (...props: any[]) => Webpack.FilterFn, shouldReturnFactory = false) {
const cache = new Map<string, unknown>();
return function (...filterProps: unknown[]) {
const cacheKey = String(filterProps);
if (cache.has(cacheKey)) return cache.get(cacheKey);
const matches = findAll(filterFactory(...filterProps));
const matches = cacheFindAll(filterFactory(...filterProps), shouldReturnFactory);
const result = (() => {
switch (matches.length) {
@ -60,51 +63,72 @@ function makeShortcuts() {
case 1: return matches[0];
default:
const uniqueMatches = [...new Set(matches)];
if (uniqueMatches.length > 1)
if (uniqueMatches.length > 1) {
console.warn(`Warning: This filter matches ${matches.length} modules. Make it more specific!\n`, uniqueMatches);
}
return matches[0];
return uniqueMatches[0];
}
})();
if (result && cacheKey) cache.set(cacheKey, result);
return result;
};
}
let fakeRenderWin: WeakRef<Window> | undefined;
const find = newFindWrapper(f => f);
const findByProps = newFindWrapper(filters.byProps);
return {
...Object.fromEntries(Object.keys(Common).map(key => [key, { getter: () => Common[key] }])),
wp: Webpack,
wpc: { getter: () => Webpack.cache },
wreq: { getter: () => Webpack.wreq },
wpsearch: search,
wpex: extract,
wpexs: (code: string) => extract(findModuleId(code)!),
WebpackInstances: { getter: () => Vencord.WebpackPatcher.allWebpackInstances },
loadLazyChunks: IS_DEV ? loadLazyChunks : () => { throw new Error("loadLazyChunks is dev only."); },
wpsearch: searchFactories,
wpex: extract,
wpexs: (...code: Webpack.CodeFilter) => extract(cacheFindModuleId(...code)!),
filters,
find,
findAll: findAll,
findByProps,
findAllByProps: (...props: string[]) => findAll(filters.byProps(...props)),
findByCode: newFindWrapper(filters.byCode),
findAllByCode: (code: string) => findAll(filters.byCode(code)),
findAll: cacheFindAll,
findComponent: find,
findAllComponents: cacheFindAll,
findExportedComponent: (...props: Webpack.PropsFilter) => findByProps(...props)[props[0]],
findComponentByCode: newFindWrapper(filters.componentByCode),
findAllComponentsByCode: (...code: string[]) => findAll(filters.componentByCode(...code)),
findExportedComponent: (...props: string[]) => findByProps(...props)[props[0]],
findAllComponentsByCode: (...code: Webpack.PropsFilter) => cacheFindAll(filters.componentByCode(...code)),
findComponentByFields: newFindWrapper(filters.componentByFields),
findAllComponentsByFields: (...fields: Webpack.PropsFilter) => cacheFindAll(filters.componentByFields(...fields)),
findByProps,
findAllByProps: (...props: Webpack.PropsFilter) => cacheFindAll(filters.byProps(...props)),
findProp: (...props: Webpack.PropsFilter) => findByProps(...props)[props[0]],
findByCode: newFindWrapper(filters.byCode),
findAllByCode: (code: Webpack.CodeFilter) => cacheFindAll(filters.byCode(...code)),
findStore: newFindWrapper(filters.byStoreName),
PluginsApi: { getter: () => Vencord.Plugins },
findByFactoryCode: newFindWrapper(filters.byFactoryCode),
findAllByFactoryCode: (...code: Webpack.CodeFilter) => cacheFindAll(filters.byFactoryCode(...code)),
findModuleFactory: newFindWrapper(filters.byFactoryCode, true),
findAllModuleFactories: (...code: Webpack.CodeFilter) => cacheFindAll(filters.byFactoryCode(...code), true),
plugins: { getter: () => Vencord.Plugins.plugins },
PluginsApi: { getter: () => Vencord.Plugins },
Settings: { getter: () => Vencord.Settings },
Api: { getter: () => Vencord.Api },
Util: { getter: () => Vencord.Util },
reload: () => location.reload(),
restart: IS_WEB ? DESKTOP_ONLY("restart") : relaunch,
canonicalizeMatch,
canonicalizeReplace,
canonicalizeReplacement,
fakeRender: (component: ComponentType, props: any) => {
preEnable: (plugin: string) => (Vencord.Settings.plugins[plugin] ??= { enabled: true }).enabled = true,
fakeRender: (component: React.ComponentType<AnyRecord>, props: any) => {
const prevWin = fakeRenderWin?.deref();
const win = prevWin?.closed === false
? prevWin
@ -133,8 +157,6 @@ function makeShortcuts() {
Common.ReactDOM.render(Common.React.createElement(component, props), doc.body.appendChild(document.createElement("div")));
},
preEnable: (plugin: string) => (Vencord.Settings.plugins[plugin] ??= { enabled: true }).enabled = true,
channel: { getter: () => getCurrentChannel(), preload: false },
channelId: { getter: () => Common.SelectedChannelStore.getChannelId(), preload: false },
guild: { getter: () => getCurrentGuild(), preload: false },
@ -143,6 +165,7 @@ function makeShortcuts() {
meId: { getter: () => Common.UserStore.getCurrentUser().id, preload: false },
messages: { getter: () => Common.MessageStore.getMessages(Common.SelectedChannelStore.getChannelId()), preload: false },
...Object.fromEntries(Object.keys(Common).map(key => [key, { getter: () => Common[key] }])),
Stores: {
getter: () => Object.fromEntries(
Common.Flux.Store.getAll()
@ -157,11 +180,39 @@ function loadAndCacheShortcut(key: string, val: any, forceLoad: boolean) {
const currentVal = val.getter();
if (!currentVal || val.preload === false) return currentVal;
const value = currentVal[SYM_LAZY_GET]
? forceLoad ? currentVal[SYM_LAZY_GET]() : currentVal[SYM_LAZY_CACHED]
: currentVal;
function unwrapProxy(value: any) {
if (value[SYM_LAZY_GET]) {
return forceLoad ? value[SYM_LAZY_GET]() : value[SYM_LAZY_CACHED];
} else if (value[SYM_PROXY_INNER_GET]) {
return forceLoad ? value[SYM_PROXY_INNER_GET]() : value[SYM_PROXY_INNER_VALUE];
} else if (value[SYM_LAZY_COMPONENT_INNER]) {
return value[SYM_LAZY_COMPONENT_INNER]() != null ? value[SYM_LAZY_COMPONENT_INNER]() : value;
}
if (value) define(window.shortcutList, key, { value });
return value;
}
const value = unwrapProxy(currentVal);
if (value != null && typeof value === "object") {
const descriptors = Object.getOwnPropertyDescriptors(value);
for (const propKey in descriptors) {
if (value[propKey] == null) continue;
const descriptor = descriptors[propKey];
if (descriptor.writable === true || descriptor.set != null) {
const currentValue = value[propKey];
const newValue = unwrapProxy(currentValue);
if (newValue != null && currentValue !== newValue) {
value[propKey] = newValue;
}
}
}
}
if (value != null) {
define(window.shortcutList, key, { value });
}
return value;
}
@ -176,8 +227,10 @@ export default definePlugin({
const shortcuts = makeShortcuts();
window.shortcutList = {};
for (const [key, val] of Object.entries(shortcuts)) {
if ("getter" in val) {
for (const key in shortcuts) {
const val = shortcuts[key];
if (Object.hasOwn(val, "getter")) {
define(window.shortcutList, key, {
get: () => loadAndCacheShortcut(key, val, true)
});
@ -191,8 +244,8 @@ export default definePlugin({
}
}
// unproxy loaded modules
Webpack.onceReady.then(() => {
// Unproxy loaded modules
Webpack.onceDiscordLoaded.then(() => {
setTimeout(() => this.eagerLoad(false), 1000);
if (!IS_WEB) {
@ -203,13 +256,13 @@ export default definePlugin({
},
async eagerLoad(forceLoad: boolean) {
await Webpack.onceReady;
await Webpack.onceDiscordLoaded;
const shortcuts = makeShortcuts();
for (const key in shortcuts) {
const val = shortcuts[key];
for (const [key, val] of Object.entries(shortcuts)) {
if (!Object.hasOwn(val, "getter") || (val as any).preload === false) continue;
if (!Object.hasOwn(val, "getter") || val.preload === false) continue;
try {
loadAndCacheShortcut(key, val, forceLoad);
} catch { } // swallow not found errors in DEV

View file

@ -8,10 +8,10 @@ import { definePluginSettings } from "@api/Settings";
import { Devs } from "@utils/constants";
import { copyWithToast } from "@utils/misc";
import definePlugin, { OptionType } from "@utils/types";
import { findByPropsLazy } from "@webpack";
import { findProp } from "@webpack";
import { Menu } from "@webpack/common";
const { convertNameToSurrogate } = findByPropsLazy("convertNameToSurrogate");
const convertNameToSurrogate = findProp("convertNameToSurrogate");
interface Emoji {
type: string;
@ -55,7 +55,7 @@ export default definePlugin({
settings,
contextMenus: {
"expression-picker"(children, { target }: { target: Target }) {
"expression-picker"(children, { target }: { target: Target; }) {
if (target.dataset.type !== "emoji") return;
children.push(

View file

@ -23,22 +23,12 @@ import { Logger } from "@utils/Logger";
import { closeAllModals } from "@utils/modal";
import definePlugin, { OptionType } from "@utils/types";
import { maybePromptToUpdate } from "@utils/updater";
import { filters, findBulk, proxyLazyWebpack } from "@webpack";
import { findByProps } from "@webpack";
import { DraftType, ExpressionPickerStore, FluxDispatcher, NavigationRouter, SelectedChannelStore } from "@webpack/common";
const CrashHandlerLogger = new Logger("CrashHandler");
const { ModalStack, DraftManager } = proxyLazyWebpack(() => {
const [ModalStack, DraftManager] = findBulk(
filters.byProps("pushLazy", "popAll"),
filters.byProps("clearDraft", "saveDraft"),
);
return {
ModalStack,
DraftManager
};
});
const ModalStack = findByProps("pushLazy", "popAll");
const DraftManager = findByProps("clearDraft", "saveDraft");
const settings = definePluginSettings({
attemptToPreventCrashes: {

View file

@ -16,7 +16,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import { definePluginSettings, Settings } from "@api/Settings";
import { definePluginSettings } from "@api/Settings";
import { getUserSettingLazy } from "@api/UserSettings";
import { ErrorCard } from "@components/ErrorCard";
import { Link } from "@components/Link";
@ -26,13 +26,13 @@ import { Margins } from "@utils/margins";
import { classes } from "@utils/misc";
import { useAwaiter } from "@utils/react";
import definePlugin, { OptionType } from "@utils/types";
import { findByCodeLazy, findComponentByCodeLazy } from "@webpack";
import { findByCode, findComponentByCode } from "@webpack";
import { ApplicationAssetUtils, Button, FluxDispatcher, Forms, GuildStore, React, SelectedChannelStore, SelectedGuildStore, UserStore } from "@webpack/common";
const useProfileThemeStyle = findByCodeLazy("profileThemeStyle:", "--profile-gradient-primary-color");
const ActivityComponent = findComponentByCodeLazy("onOpenGameProfile");
const useProfileThemeStyle = findByCode("profileThemeStyle:", "--profile-gradient-primary-color");
const ActivityComponent = findComponentByCode("onOpenGameProfile");
const ShowCurrentGame = getUserSettingLazy<boolean>("status", "showCurrentGame")!;
const ShowCurrentGame = getUserSettingLazy<boolean>("status", "showCurrentGame");
async function getApplicationAsset(key: string): Promise<string> {
if (/https?:\/\/(cdn|media)\.discordapp\.(com|net)\/attachments\//.test(key)) return "mp:" + key.replace(/https?:\/\/(cdn|media)\.discordapp\.(com|net)\//, "");
@ -260,7 +260,7 @@ const settings = definePluginSettings({
function onChange() {
setRpc(true);
if (Settings.plugins.CustomRPC.enabled) setRpc();
if (Vencord.Plugins.isPluginEnabled("CustomRPC")) setRpc();
}
function isStreamLinkDisabled() {

View file

@ -5,7 +5,7 @@
*/
import { Flex } from "@components/Flex";
import { findByCodeLazy } from "@webpack";
import { findComponentByCode } from "@webpack";
import { Button, useEffect } from "@webpack/common";
import { useAuthorizationStore } from "../../lib/stores/AuthorizationStore";
@ -13,7 +13,7 @@ import { useCurrentUserDecorationsStore } from "../../lib/stores/CurrentUserDeco
import { cl } from "../";
import { openChangeDecorationModal } from "../modals/ChangeDecorationModal";
const CustomizationSection = findByCodeLazy(".customizationSectionBackground");
const CustomizationSection = findComponentByCode(".customizationSectionBackground");
export interface DecorSectionProps {
hideTitle?: boolean;

View file

@ -5,13 +5,13 @@
*/
import { classes } from "@utils/misc";
import { findByPropsLazy } from "@webpack";
import { findByProps } from "@webpack";
import { React } from "@webpack/common";
import { cl } from "../";
import Grid, { GridProps } from "./Grid";
const ScrollerClasses = findByPropsLazy("managedReactiveScroller");
const ScrollerClasses = findByProps("managedReactiveScroller");
type Section<SectionT, ItemT> = SectionT & {
items: Array<ItemT>;

View file

@ -4,30 +4,27 @@
* SPDX-License-Identifier: GPL-3.0-or-later
*/
import { findComponentByCode, LazyComponentWebpack } from "@webpack";
import { NoopComponent } from "@utils/react";
import { findComponentByCode } from "@webpack";
import { React } from "@webpack/common";
import type { ComponentType, HTMLProps, PropsWithChildren } from "react";
import { AvatarDecoration } from "../..";
type DecorationGridItemComponent = ComponentType<PropsWithChildren<HTMLProps<HTMLDivElement>> & {
type DecorationGridItemComponent = AnyComponentTypeWithChildren<React.ComponentPropsWithoutRef<"div"> & {
onSelect: () => void,
isSelected: boolean,
}>;
export let DecorationGridItem: DecorationGridItemComponent;
export let DecorationGridItem: DecorationGridItemComponent = NoopComponent;
export const setDecorationGridItem = v => DecorationGridItem = v;
export const AvatarDecorationModalPreview = LazyComponentWebpack(() => {
const component = findComponentByCode(".shopPreviewBanner");
return React.memo(component);
});
export const AvatarDecorationModalPreview = findComponentByCode(".shopPreviewBanner", component => React.memo(component));
type DecorationGridDecorationComponent = React.ComponentType<HTMLProps<HTMLDivElement> & {
type DecorationGridDecorationComponent = AnyComponentType<React.ComponentPropsWithoutRef<"div"> & {
avatarDecoration: AvatarDecoration;
onSelect: () => void,
isSelected: boolean,
}>;
export let DecorationGridDecoration: DecorationGridDecorationComponent;
export let DecorationGridDecoration: DecorationGridDecorationComponent = NoopComponent;
export const setDecorationGridDecoration = v => DecorationGridDecoration = v;

View file

@ -5,10 +5,10 @@
*/
import { classNameFactory } from "@api/Styles";
import { extractAndLoadChunksLazy, findByPropsLazy } from "@webpack";
import { extractAndLoadChunksLazy, findByProps } from "@webpack";
export const cl = classNameFactory("vc-decor-");
export const DecorationModalStyles = findByPropsLazy("modalFooterShopButton");
export const DecorationModalStyles = findByProps("modalFooterShopButton");
export const requireAvatarDecorationModal = extractAndLoadChunksLazy([".COLLECTIBLES_SHOP_FULLSCREEN&&"]);
export const requireCreateStickerModal = extractAndLoadChunksLazy(["stickerInspected]:"]);
export const requireAvatarDecorationModal = extractAndLoadChunksLazy(".COLLECTIBLES_SHOP_FULLSCREEN&&");
export const requireCreateStickerModal = extractAndLoadChunksLazy("stickerInspected]:");

View file

@ -10,7 +10,7 @@ import { openInviteModal } from "@utils/discord";
import { Margins } from "@utils/margins";
import { classes, copyWithToast } from "@utils/misc";
import { closeAllModals, ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalProps, ModalRoot, ModalSize, openModal } from "@utils/modal";
import { findComponentByCodeLazy } from "@webpack";
import { findComponentByCode } from "@webpack";
import { Alerts, Button, FluxDispatcher, Forms, GuildStore, NavigationRouter, Parser, Text, Tooltip, useEffect, UserStore, UserUtils, useState } from "@webpack/common";
import { User } from "discord-types/general";
@ -29,7 +29,7 @@ import SectionedGridList from "../components/SectionedGridList";
import { openCreateDecorationModal } from "./CreateDecorationModal";
import { openGuidelinesModal } from "./GuidelinesModal";
const UserSummaryItem = findComponentByCodeLazy("defaultRenderUser", "showDefaultAvatarsForNullUsers");
const UserSummaryItem = findComponentByCode("defaultRenderUser", "showDefaultAvatarsForNullUsers");
function usePresets() {
const [presets, setPresets] = useState<Preset[]>([]);

View file

@ -9,7 +9,7 @@ import { Link } from "@components/Link";
import { openInviteModal } from "@utils/discord";
import { Margins } from "@utils/margins";
import { closeAllModals, ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalProps, ModalRoot, ModalSize, openModal } from "@utils/modal";
import { filters, findComponentByCodeLazy, mapMangledModuleLazy } from "@webpack";
import { filters, findComponentByCode, mapMangledModule } from "@webpack";
import { Button, FluxDispatcher, Forms, GuildStore, NavigationRouter, Text, TextInput, useEffect, useMemo, UserStore, useState } from "@webpack/common";
import { GUILD_ID, INVITE_KEY, RAW_SKU_ID } from "../../lib/constants";
@ -17,11 +17,11 @@ import { useCurrentUserDecorationsStore } from "../../lib/stores/CurrentUserDeco
import { cl, DecorationModalStyles, requireAvatarDecorationModal, requireCreateStickerModal } from "../";
import { AvatarDecorationModalPreview } from "../components";
const FileUpload = findComponentByCodeLazy("fileUploadInput,");
const FileUpload = findComponentByCode("fileUploadInput,");
const { HelpMessage, HelpMessageTypes } = mapMangledModuleLazy('POSITIVE=3]="POSITIVE', {
const { HelpMessage, HelpMessageTypes } = mapMangledModule('POSITIVE=3]="POSITIVE', {
HelpMessage: filters.componentByCode(".iconDiv,", "messageType"),
HelpMessageTypes: filters.byProps("POSITIVE", "WARNING"),
HelpMessage: filters.byCode(".iconDiv")
});
function useObjectURL(object: Blob | MediaSource | null) {

View file

@ -22,7 +22,7 @@ import { Devs } from "@utils/constants";
import { Logger } from "@utils/Logger";
import { canonicalizeMatch, canonicalizeReplace } from "@utils/patches";
import definePlugin, { OptionType, ReporterTestable } from "@utils/types";
import { filters, findAll, search } from "@webpack";
import { cacheFindAll, filters, searchFactories } from "@webpack";
const PORT = 8485;
const NAV_ID = "dev-companion-reconnect";
@ -154,13 +154,13 @@ function initWs(isManual = false) {
case "testPatch": {
const { find, replacement } = data as PatchData;
const candidates = search(find);
const candidates = searchFactories(find);
const keys = Object.keys(candidates);
if (keys.length !== 1)
return reply("Expected exactly one 'find' matches, found " + keys.length);
const mod = candidates[keys[0]];
let src = String(mod.original ?? mod).replaceAll("\n", "");
let src = String(mod).replaceAll("\n", "");
if (src.startsWith("function(")) {
src = "0," + src;
@ -201,22 +201,22 @@ function initWs(isManual = false) {
let results: any[];
switch (type.replace("find", "").replace("Lazy", "")) {
case "":
results = findAll(parsedArgs[0]);
results = cacheFindAll(parsedArgs[0]);
break;
case "ByProps":
results = findAll(filters.byProps(...parsedArgs));
results = cacheFindAll(filters.byProps(...parsedArgs));
break;
case "Store":
results = findAll(filters.byStoreName(parsedArgs[0]));
results = cacheFindAll(filters.byStoreName(parsedArgs[0]));
break;
case "ByCode":
results = findAll(filters.byCode(...parsedArgs));
results = cacheFindAll(filters.byCode(...parsedArgs));
break;
case "ModuleId":
results = Object.keys(search(parsedArgs[0]));
results = Object.keys(searchFactories(parsedArgs[0]));
break;
case "ComponentByCode":
results = findAll(filters.componentByCode(...parsedArgs));
results = cacheFindAll(filters.componentByCode(...parsedArgs));
break;
default:
return reply("Unknown Find Type " + type);

View file

@ -23,12 +23,12 @@ import { Logger } from "@utils/Logger";
import { Margins } from "@utils/margins";
import { ModalContent, ModalHeader, ModalRoot, openModalLazy } from "@utils/modal";
import definePlugin from "@utils/types";
import { findByCodeLazy, findStoreLazy } from "@webpack";
import { findByCode, findStore } from "@webpack";
import { Constants, EmojiStore, FluxDispatcher, Forms, GuildStore, Menu, PermissionsBits, PermissionStore, React, RestAPI, Toasts, Tooltip, UserStore } from "@webpack/common";
import { Promisable } from "type-fest";
const StickersStore = findStoreLazy("StickersStore");
const uploadEmoji = findByCodeLazy(".GUILD_EMOJIS(", "EMOJI_UPLOAD_START");
const StickersStore = findStore("StickersStore");
const uploadEmoji = findByCode(".GUILD_EMOJIS(", "EMOJI_UPLOAD_START");
interface Sticker {
t: "Sticker";

View file

@ -23,13 +23,13 @@ import { ErrorCard } from "@components/ErrorCard";
import { Devs } from "@utils/constants";
import { Margins } from "@utils/margins";
import definePlugin, { OptionType } from "@utils/types";
import { findByPropsLazy, findLazy } from "@webpack";
import { find, findByProps } from "@webpack";
import { Forms, React } from "@webpack/common";
import hideBugReport from "./hideBugReport.css?managed";
const KbdStyles = findByPropsLazy("key", "combo");
const BugReporterExperiment = findLazy(m => m?.definition?.id === "2024-09_bug_reporter");
const KbdStyles = findByProps("key", "combo");
const BugReporterExperiment = find(m => m?.definition?.id === "2024-09_bug_reporter");
const settings = definePluginSettings({
toolbarDevMenu: {

View file

@ -23,36 +23,36 @@ import { ApngBlendOp, ApngDisposeOp, importApngJs } from "@utils/dependencies";
import { getCurrentGuild } from "@utils/discord";
import { Logger } from "@utils/Logger";
import definePlugin, { OptionType } from "@utils/types";
import { findByCodeLazy, findByPropsLazy, findStoreLazy, proxyLazyWebpack } from "@webpack";
import { findByCode, findByProps, findStore, webpackDependantLazy } from "@webpack";
import { Alerts, ChannelStore, DraftType, EmojiStore, FluxDispatcher, Forms, GuildMemberStore, IconUtils, lodash, Parser, PermissionsBits, PermissionStore, UploadHandler, UserSettingsActionCreators, UserStore } from "@webpack/common";
import type { Emoji } from "@webpack/types";
import type { Message } from "discord-types/general";
import { applyPalette, GIFEncoder, quantize } from "gifenc";
import type { ReactElement, ReactNode } from "react";
const StickerStore = findStoreLazy("StickersStore") as {
const StickersStore = findStore("StickersStore") as {
getPremiumPacks(): StickerPack[];
getAllGuildStickers(): Map<string, Sticker[]>;
getStickerById(id: string): Sticker | undefined;
};
const UserSettingsProtoStore = findStoreLazy("UserSettingsProtoStore");
const UserSettingsProtoStore = findStore("UserSettingsProtoStore");
const BINARY_READ_OPTIONS = findByPropsLazy("readerFactory");
const BINARY_READ_OPTIONS = findByProps("readerFactory");
function searchProtoClassField(localName: string, protoClass: any) {
const field = protoClass?.fields?.find((field: any) => field.localName === localName);
if (!field) return;
const fieldGetter = Object.values(field).find(value => typeof value === "function") as any;
const fieldGetter = Object.values<any>(field).find(value => typeof value === "function");
return fieldGetter?.();
}
const PreloadedUserSettingsActionCreators = proxyLazyWebpack(() => UserSettingsActionCreators.PreloadedUserSettingsActionCreators);
const AppearanceSettingsActionCreators = proxyLazyWebpack(() => searchProtoClassField("appearance", PreloadedUserSettingsActionCreators.ProtoClass));
const ClientThemeSettingsActionsCreators = proxyLazyWebpack(() => searchProtoClassField("clientThemeSettings", AppearanceSettingsActionCreators));
const PreloadedUserSettingsActionCreators = webpackDependantLazy(() => UserSettingsActionCreators.PreloadedUserSettingsActionCreators);
const AppearanceSettingsActionCreators = webpackDependantLazy(() => searchProtoClassField("appearance", PreloadedUserSettingsActionCreators.ProtoClass));
const ClientThemeSettingsActionsCreators = webpackDependantLazy(() => searchProtoClassField("clientThemeSettings", AppearanceSettingsActionCreators));
const isUnusableRoleSubscriptionEmoji = findByCodeLazy(".getUserIsAdmin(");
const isUnusableRoleSubscriptionEmoji = findByCode(".getUserIsAdmin(");
const enum EmojiIntentions {
REACTION,
@ -566,8 +566,8 @@ export default definePlugin({
const gifMatch = child.props.href.match(fakeNitroGifStickerRegex);
if (gifMatch) {
// There is no way to differentiate a regular gif attachment from a fake nitro animated sticker, so we check if the StickerStore contains the id of the fake sticker
if (StickerStore.getStickerById(gifMatch[1])) return null;
// There is no way to differentiate a regular gif attachment from a fake nitro animated sticker, so we check if the StickersStore contains the id of the fake sticker
if (StickersStore.getStickerById(gifMatch[1])) return null;
}
}
@ -655,7 +655,7 @@ export default definePlugin({
url = new URL(item);
} catch { }
const stickerName = StickerStore.getStickerById(imgMatch[1])?.name ?? url?.searchParams.get("name") ?? "FakeNitroSticker";
const stickerName = StickersStore.getStickerById(imgMatch[1])?.name ?? url?.searchParams.get("name") ?? "FakeNitroSticker";
stickers.push({
format_type: 1,
id: imgMatch[1],
@ -668,9 +668,9 @@ export default definePlugin({
const gifMatch = item.match(fakeNitroGifStickerRegex);
if (gifMatch) {
if (!StickerStore.getStickerById(gifMatch[1])) continue;
if (!StickersStore.getStickerById(gifMatch[1])) continue;
const stickerName = StickerStore.getStickerById(gifMatch[1])?.name ?? "FakeNitroSticker";
const stickerName = StickersStore.getStickerById(gifMatch[1])?.name ?? "FakeNitroSticker";
stickers.push({
format_type: 2,
id: gifMatch[1],
@ -703,8 +703,8 @@ export default definePlugin({
const gifMatch = embed.url!.match(fakeNitroGifStickerRegex);
if (gifMatch) {
// There is no way to differentiate a regular gif attachment from a fake nitro animated sticker, so we check if the StickerStore contains the id of the fake sticker
if (StickerStore.getStickerById(gifMatch[1])) return true;
// There is no way to differentiate a regular gif attachment from a fake nitro animated sticker, so we check if the StickersStore contains the id of the fake sticker
if (StickersStore.getStickerById(gifMatch[1])) return true;
}
}
@ -721,8 +721,8 @@ export default definePlugin({
const match = attachment.url.match(fakeNitroGifStickerRegex);
if (match) {
// There is no way to differentiate a regular gif attachment from a fake nitro animated sticker, so we check if the StickerStore contains the id of the fake sticker
if (StickerStore.getStickerById(match[1])) return false;
// There is no way to differentiate a regular gif attachment from a fake nitro animated sticker, so we check if the StickersStore contains the id of the fake sticker
if (StickersStore.getStickerById(match[1])) return false;
}
return true;
@ -878,7 +878,7 @@ export default definePlugin({
if (!s.enableStickerBypass)
break stickerBypass;
const sticker = StickerStore.getStickerById(extra.stickers?.[0]!);
const sticker = StickersStore.getStickerById(extra.stickers?.[0]!);
if (!sticker)
break stickerBypass;

View file

@ -26,7 +26,7 @@ import { Margins } from "@utils/margins";
import { classes, copyWithToast } from "@utils/misc";
import { useAwaiter } from "@utils/react";
import definePlugin, { OptionType } from "@utils/types";
import { extractAndLoadChunksLazy, findComponentByCodeLazy } from "@webpack";
import { extractAndLoadChunksLazy, findComponentByCode } from "@webpack";
import { Button, Flex, Forms, React, Text, UserProfileStore, UserStore, useState } from "@webpack/common";
import { User } from "discord-types/general";
import virtualMerge from "virtual-merge";
@ -108,10 +108,10 @@ interface ProfileModalProps {
isTryItOutFlow: boolean;
}
const ColorPicker = findComponentByCodeLazy<ColorPickerProps>(".Messages.USER_SETTINGS_PROFILE_COLOR_SELECT_COLOR", ".BACKGROUND_PRIMARY)");
const ProfileModal = findComponentByCodeLazy<ProfileModalProps>("isTryItOutFlow:", "pendingThemeColors:", "pendingAvatarDecoration:", "EDIT_PROFILE_BANNER");
const ColorPicker = findComponentByCode<ColorPickerProps>(".Messages.USER_SETTINGS_PROFILE_COLOR_SELECT_COLOR", ".BACKGROUND_PRIMARY)");
const ProfileModal = findComponentByCode<ProfileModalProps>("isTryItOutFlow:", "pendingThemeColors:", "pendingAvatarDecoration:", "EDIT_PROFILE_BANNER");
const requireColorPicker = extractAndLoadChunksLazy(["USER_SETTINGS_PROFILE_COLOR_DEFAULT_BUTTON.format"], /createPromise:\(\)=>\i\.\i(\("?.+?"?\)).then\(\i\.bind\(\i,"?(.+?)"?\)\)/);
const requireColorPicker = extractAndLoadChunksLazy("USER_SETTINGS_PROFILE_COLOR_DEFAULT_BUTTON.format");
export default definePlugin({
name: "FakeProfileThemes",

View file

@ -20,7 +20,7 @@ import { definePluginSettings } from "@api/Settings";
import ErrorBoundary from "@components/ErrorBoundary";
import { Devs } from "@utils/constants";
import definePlugin, { OptionType } from "@utils/types";
import { findByPropsLazy } from "@webpack";
import { findByProps } from "@webpack";
import { useCallback, useEffect, useRef, useState } from "@webpack/common";
interface SearchBarComponentProps {
@ -35,7 +35,7 @@ interface SearchBarComponentProps {
}
type TSearchBarComponent =
React.FC<SearchBarComponentProps> & { Sizes: Record<"SMALL" | "MEDIUM" | "LARGE", string>; };
React.ComponentType<SearchBarComponentProps> & { Sizes: Record<"SMALL" | "MEDIUM" | "LARGE", string>; };
interface Gif {
format: number;
@ -60,7 +60,7 @@ interface Instance {
}
const containerClasses: { searchBar: string; } = findByPropsLazy("searchBar", "searchBarFullRow");
const containerClasses: { searchBar: string; } = findByProps("searchBar", "searchBarFullRow");
export const settings = definePluginSettings({
searchOption: {

View file

@ -19,9 +19,9 @@
import { ApplicationCommandInputType, sendBotMessage } from "@api/Commands";
import { Devs } from "@utils/constants";
import definePlugin from "@utils/types";
import { findByPropsLazy } from "@webpack";
import { findByProps } from "@webpack";
const FriendInvites = findByPropsLazy("createFriendInvite");
const FriendInvites = findByProps("createFriendInvite");
export default definePlugin({
name: "FriendInvites",

View file

@ -8,14 +8,14 @@ import ErrorBoundary from "@components/ErrorBoundary";
import { Devs } from "@utils/constants";
import { getCurrentChannel } from "@utils/discord";
import definePlugin from "@utils/types";
import { findByCodeLazy, findByPropsLazy, findComponentByCodeLazy } from "@webpack";
import { findByCode, findByProps, findComponentByCode } from "@webpack";
import { RelationshipStore, Text } from "@webpack/common";
const containerWrapper = findByPropsLazy("memberSinceWrapper");
const container = findByPropsLazy("memberSince");
const getCreatedAtDate = findByCodeLazy('month:"short",day:"numeric"');
const locale = findByPropsLazy("getLocale");
const Section = findComponentByCodeLazy('"auto":"smooth"', ".section");
const containerWrapper = findByProps("memberSinceWrapper");
const container = findByProps("memberSince");
const getCreatedAtDate = findByCode('month:"short",day:"numeric"');
const locale = findByProps("getLocale");
const Section = findComponentByCode('"auto":"smooth"', ".section");
export default definePlugin({
name: "FriendsSince",

View file

@ -19,12 +19,11 @@
import { migratePluginSettings } from "@api/Settings";
import { Devs } from "@utils/constants";
import definePlugin from "@utils/types";
import { findByPropsLazy } from "@webpack";
import { findProp } from "@webpack";
import { ChannelStore, ContextMenuApi, i18n, UserStore } from "@webpack/common";
import { Message } from "discord-types/general";
import type { MouseEvent } from "react";
const { useMessageMenu } = findByPropsLazy("useMessageMenu");
const useMessageMenu = findProp("useMessageMenu");
function MessageMenu({ message, channel, onHeightUpdate }) {
const canReport = message.author &&
@ -65,7 +64,7 @@ export default definePlugin({
}
}],
handleContextMenu(event: MouseEvent, message: Message) {
handleContextMenu(event: React.MouseEvent, message: Message) {
const channel = ChannelStore.getChannel(message.channel_id);
if (!channel) return;

View file

@ -22,13 +22,13 @@ import { getUserSettingLazy } from "@api/UserSettings";
import ErrorBoundary from "@components/ErrorBoundary";
import { Devs } from "@utils/constants";
import definePlugin, { OptionType } from "@utils/types";
import { findComponentByCodeLazy } from "@webpack";
import { findComponentByCode } from "@webpack";
import style from "./style.css?managed";
const Button = findComponentByCodeLazy("Button.Sizes.NONE,disabled:");
const Button = findComponentByCode("Button.Sizes.NONE,disabled:");
const ShowCurrentGame = getUserSettingLazy<boolean>("status", "showCurrentGame")!;
const ShowCurrentGame = getUserSettingLazy<boolean>("status", "showCurrentGame");
function makeIcon(showCurrentGame?: boolean) {
const { oldIcon } = settings.use(["oldIcon"]);

View file

@ -19,7 +19,7 @@
import { definePluginSettings } from "@api/Settings";
import { Devs } from "@utils/constants";
import definePlugin, { OptionType } from "@utils/types";
import { findLazy } from "@webpack";
import { find } from "@webpack";
import { ContextMenuApi, FluxDispatcher, Menu, MessageActions } from "@webpack/common";
import { Channel, Message } from "discord-types/general";
@ -49,7 +49,7 @@ const settings = definePluginSettings({
unholyMultiGreetEnabled?: boolean;
}>();
const WELCOME_STICKERS = findLazy(m => Array.isArray(m) && m[0]?.name === "Wave");
const WELCOME_STICKERS = find(m => Array.isArray(m) && m[0]?.name === "Wave");
function greet(channel: Channel, message: Message, stickers: string[]) {
const options = MessageActions.getSendMessageOptionsForReply({

View file

@ -12,7 +12,7 @@ import { Flex } from "@components/Flex";
import { Devs } from "@utils/constants";
import { Margins } from "@utils/margins";
import definePlugin, { OptionType } from "@utils/types";
import { findStoreLazy } from "@webpack";
import { findStore } from "@webpack";
import { Button, Forms, showToast, TextInput, Toasts, Tooltip, useEffect, useState } from "webpack/common";
const enum ActivitiesTypes {
@ -31,9 +31,9 @@ const enum FilterMode {
Blacklist
}
const RunningGameStore = findStoreLazy("RunningGameStore");
const RunningGameStore = findStore("RunningGameStore");
const ShowCurrentGame = getUserSettingLazy("status", "showCurrentGame")!;
const ShowCurrentGame = getUserSettingLazy("status", "showCurrentGame");
function ToggleIcon(activity: IgnoredActivity, tooltipText: string, path: string, fill: string) {
return (

View file

@ -26,7 +26,7 @@ import definePlugin, { OptionType } from "@utils/types";
import { Menu, ReactDOM } from "@webpack/common";
import type { Root } from "react-dom/client";
import { Magnifier, MagnifierProps } from "./components/Magnifier";
import { Magnifier } from "./components/Magnifier";
import { ELEMENT_ID } from "./constants";
import styles from "./styles.css?managed";
@ -201,7 +201,7 @@ export default definePlugin({
},
// to stop from rendering twice /shrug
currentMagnifierElement: null as React.FunctionComponentElement<MagnifierProps & JSX.IntrinsicAttributes> | null,
currentMagnifierElement: null as React.ReactNode,
element: null as HTMLDivElement | null,
Magnifier,

View file

@ -19,16 +19,26 @@
import { definePluginSettings } from "@api/Settings";
import { Devs } from "@utils/constants";
import definePlugin, { OptionType } from "@utils/types";
import { findStoreLazy } from "@webpack";
import { findStore } from "@webpack";
import { ChannelStore, Constants, FluxDispatcher, GuildStore, RelationshipStore, SnowflakeUtils, UserStore } from "@webpack/common";
import { Settings } from "Vencord";
const UserAffinitiesStore = findStoreLazy("UserAffinitiesStore");
const UserAffinitiesStore = findStore("UserAffinitiesStore");
const settings = definePluginSettings({
sortByAffinity: {
type: OptionType.BOOLEAN,
default: true,
description: "Whether to sort implicit relationships by their affinity to you.",
restartNeeded: true
}
});
export default definePlugin({
name: "ImplicitRelationships",
description: "Shows your implicit relationships in the Friends tab.",
authors: [Devs.Dolfies],
settings,
patches: [
// Counts header
{
@ -75,7 +85,7 @@ export default definePlugin({
{
find: "getRelationshipCounts(){",
replacement: {
predicate: () => Settings.plugins.ImplicitRelationships.sortByAffinity,
predicate: () => settings.store.sortByAffinity,
match: /\}\)\.sortBy\((.+?)\)\.value\(\)/,
replace: "}).sortBy(row => $self.wrapSort(($1), row)).value()"
}
@ -104,16 +114,6 @@ export default definePlugin({
},
}
],
settings: definePluginSettings(
{
sortByAffinity: {
type: OptionType.BOOLEAN,
default: true,
description: "Whether to sort implicit relationships by their affinity to you.",
restartNeeded: true
},
}
),
wrapSort(comparator: Function, row: any) {
return row.type === 5

View file

@ -20,7 +20,7 @@ import { registerCommand, unregisterCommand } from "@api/Commands";
import { addContextMenuPatch, removeContextMenuPatch } from "@api/ContextMenu";
import { Settings } from "@api/Settings";
import { Logger } from "@utils/Logger";
import { canonicalizeFind } from "@utils/patches";
import { canonicalizeFind, canonicalizeReplacement } from "@utils/patches";
import { Patch, Plugin, ReporterTestable, StartAt } from "@utils/types";
import { FluxDispatcher } from "@webpack/common";
import { FluxEvents } from "@webpack/types";
@ -66,10 +66,12 @@ export function addPatch(newPatch: Omit<Patch, "plugin">, pluginName: string) {
patch.replacement = [patch.replacement];
}
for (const replacement of patch.replacement) {
canonicalizeReplacement(replacement, pluginName);
if (IS_REPORTER) {
patch.replacement.forEach(r => {
delete r.predicate;
});
delete replacement.predicate;
}
}
patch.replacement = patch.replacement.filter(({ predicate }) => !predicate || predicate());

View file

@ -21,7 +21,7 @@ import { Link } from "@components/Link";
import { Devs } from "@utils/constants";
import { Logger } from "@utils/Logger";
import definePlugin, { OptionType } from "@utils/types";
import { findByPropsLazy } from "@webpack";
import { findStore } from "@webpack";
import { ApplicationAssetUtils, FluxDispatcher, Forms } from "@webpack/common";
interface ActivityAssets {
@ -86,7 +86,7 @@ const placeholderId = "2a96cbd8b46e442fc41c2b86b821562f";
const logger = new Logger("LastFMRichPresence");
const presenceStore = findByPropsLazy("getLocalPresence");
const SelfPresenceStore = findStore("SelfPresenceStore");
async function getApplicationAsset(key: string): Promise<string> {
return (await ApplicationAssetUtils.fetchAssetIds(applicationId, [key]))[0];
@ -275,7 +275,7 @@ export default definePlugin({
async getActivity(): Promise<Activity | null> {
if (settings.store.hideWithSpotify) {
for (const activity of presenceStore.getActivities()) {
for (const activity of SelfPresenceStore.getActivities()) {
if (activity.type === ActivityType.LISTENING && activity.application_id !== applicationId) {
// there is already music status because of Spotify or richerCider (probably more)
return null;

View file

@ -23,20 +23,19 @@ import { classNameFactory } from "@api/Styles";
import ErrorBoundary from "@components/ErrorBoundary";
import { Devs } from "@utils/constants";
import definePlugin, { OptionType } from "@utils/types";
import { findStoreLazy } from "@webpack";
import { findStore } from "@webpack";
import { FluxStore } from "@webpack/types";
import { MemberCount } from "./MemberCount";
export const GuildMemberCountStore = findStoreLazy("GuildMemberCountStore") as FluxStore & { getMemberCount(guildId?: string): number | null; };
export const ChannelMemberStore = findStoreLazy("ChannelMemberStore") as FluxStore & {
export const GuildMemberCountStore = findStore("GuildMemberCountStore") as FluxStore & { getMemberCount(guildId?: string): number | null; };
export const ChannelMemberStore = findStore("ChannelMemberStore") as FluxStore & {
getProps(guildId?: string, channelId?: string): { groups: { count: number; id: string; }[]; };
};
export const ThreadMemberListStore = findStoreLazy("ThreadMemberListStore") as FluxStore & {
export const ThreadMemberListStore = findStore("ThreadMemberListStore") as FluxStore & {
getMemberListSections(channelId?: string): { [sectionId: string]: { sectionId: string; userIds: string[]; }; };
};
const settings = definePluginSettings({
toolTip: {
type: OptionType.BOOLEAN,

View file

@ -20,11 +20,11 @@ import { addClickListener, removeClickListener } from "@api/MessageEvents";
import { definePluginSettings } from "@api/Settings";
import { Devs } from "@utils/constants";
import definePlugin, { OptionType } from "@utils/types";
import { findByPropsLazy } from "@webpack";
import { findByProps, findStore } from "@webpack";
import { FluxDispatcher, PermissionsBits, PermissionStore, UserStore } from "@webpack/common";
const MessageActions = findByPropsLazy("deleteMessage", "startEditMessage");
const EditStore = findByPropsLazy("isEditing", "isEditingAny");
const MessageActions = findByProps("deleteMessage", "startEditMessage");
const EditMessageStore = findStore("EditMessageStore");
let isDeletePressed = false;
const keydown = (e: KeyboardEvent) => e.key === "Backspace" && (isDeletePressed = true);
@ -74,7 +74,7 @@ export default definePlugin({
if (msg.deleted === true) return;
if (isMe) {
if (!settings.store.enableDoubleClickToEdit || EditStore.isEditing(channel.id, msg.id)) return;
if (!settings.store.enableDoubleClickToEdit || EditMessageStore.isEditing(channel.id, msg.id)) return;
MessageActions.startEditMessage(channel.id, msg.id, msg.content);
event.preventDefault();

View file

@ -9,7 +9,7 @@ import ErrorBoundary from "@components/ErrorBoundary";
import { Devs } from "@utils/constants";
import { isNonNullish } from "@utils/guards";
import definePlugin, { OptionType } from "@utils/types";
import { findExportedComponentLazy } from "@webpack";
import { findExportedComponent } from "@webpack";
import { SnowflakeUtils, Tooltip } from "@webpack/common";
import { Message } from "discord-types/general";
@ -26,7 +26,7 @@ interface Diff {
}
const DISCORD_KT_DELAY = 1471228928;
const HiddenVisually = findExportedComponentLazy("HiddenVisually");
const HiddenVisually = findExportedComponent("HiddenVisually");
export default definePlugin({
name: "MessageLatency",

View file

@ -25,7 +25,7 @@ import { Devs } from "@utils/constants.js";
import { classes } from "@utils/misc";
import { Queue } from "@utils/Queue";
import definePlugin, { OptionType } from "@utils/types";
import { findByPropsLazy, findComponentByCodeLazy } from "@webpack";
import { findByProps, findComponentByCode } from "@webpack";
import {
Button,
ChannelStore,
@ -47,14 +47,14 @@ const messageCache = new Map<string, {
fetched: boolean;
}>();
const Embed = findComponentByCodeLazy(".inlineMediaEmbed");
const AutoModEmbed = findComponentByCodeLazy(".withFooter]:", "childrenMessageContent:");
const ChannelMessage = findComponentByCodeLazy("childrenExecutedCommand:", ".hideAccessories");
const Embed = findComponentByCode(".inlineMediaEmbed");
const AutoModEmbed = findComponentByCode(".withFooter]:", "childrenMessageContent:");
const ChannelMessage = findComponentByCode("childrenExecutedCommand:", ".hideAccessories");
const SearchResultClasses = findByPropsLazy("message", "searchResult");
const EmbedClasses = findByPropsLazy("embedAuthorIcon", "embedAuthor", "embedAuthor");
const SearchResultClasses = findByProps("message", "searchResult");
const EmbedClasses = findByProps("embedAuthorIcon", "embedAuthor", "embedAuthor");
const MessageDisplayCompact = getUserSettingLazy("textAndImages", "messageDisplayCompact")!;
const MessageDisplayCompact = getUserSettingLazy("textAndImages", "messageDisplayCompact");
const messageLinkRegex = /(?<!<)https?:\/\/(?:\w+\.)?discord(?:app)?\.com\/channels\/(?:\d{17,20}|@me)\/(\d{17,20})\/(\d{17,20})/g;
const tenorRegex = /^https:\/\/(?:www\.)?tenor\.com\//;
@ -215,10 +215,9 @@ function computeWidthAndHeight(width: number, height: number) {
function withEmbeddedBy(message: Message, embeddedBy: string[]) {
return new Proxy(message, {
get(_, prop) {
get(target, prop, receiver) {
if (prop === "vencordEmbeddedBy") return embeddedBy;
// @ts-ignore ts so bad
return Reflect.get(...arguments);
return Reflect.get(target, prop, receiver);
}
});
}

View file

@ -9,13 +9,13 @@ import ErrorBoundary from "@components/ErrorBoundary";
import { Margins } from "@utils/margins";
import { classes } from "@utils/misc";
import { ModalCloseButton, ModalContent, ModalHeader, ModalProps, ModalRoot, ModalSize, openModal } from "@utils/modal";
import { findByPropsLazy } from "@webpack";
import { findByProps } from "@webpack";
import { TabBar, Text, Timestamp, TooltipContainer, useState } from "@webpack/common";
import { parseEditContent } from ".";
const CodeContainerClasses = findByPropsLazy("markup", "codeContainer");
const MiscClasses = findByPropsLazy("messageContent", "markupRtl");
const CodeContainerClasses = findByProps("markup", "codeContainer");
const MiscClasses = findByProps("messageContent", "markupRtl");
const cl = classNameFactory("vc-ml-modal-");

View file

@ -20,7 +20,7 @@ import "./messageLogger.css";
import { findGroupChildrenByChildId, NavContextMenuPatchCallback } from "@api/ContextMenu";
import { updateMessage } from "@api/MessageUpdater";
import { Settings } from "@api/Settings";
import { definePluginSettings } from "@api/Settings";
import { disableStyle, enableStyle } from "@api/Styles";
import ErrorBoundary from "@components/ErrorBoundary";
import { Devs } from "@utils/constants";
@ -28,7 +28,7 @@ import { proxyLazy } from "@utils/lazy";
import { Logger } from "@utils/Logger";
import { classes } from "@utils/misc";
import definePlugin, { OptionType } from "@utils/types";
import { findByCodeLazy, findByPropsLazy } from "@webpack";
import { findByCode, findByProps } from "@webpack";
import { ChannelStore, FluxDispatcher, i18n, Menu, MessageStore, Parser, SelectedChannelStore, Timestamp, UserStore, useStateFromStores } from "@webpack/common";
import { Message } from "discord-types/general";
@ -42,11 +42,11 @@ interface MLMessage extends Message {
firstEditTimestamp?: Date;
}
const styles = findByPropsLazy("edited", "communicationDisabled", "isSystemMessage");
const getMessage = findByCodeLazy('replace(/^\\n+|\\n+$/g,"")');
const styles = findByProps("edited", "communicationDisabled", "isSystemMessage");
const getMessage = findByCode('replace(/^\\n+|\\n+$/g,"")');
function addDeleteStyle() {
if (Settings.plugins.MessageLogger.deleteStyle === "text") {
if (settings.store.deleteStyle === "text") {
enableStyle(textStyle);
disableStyle(overlayStyle);
} else {
@ -142,58 +142,7 @@ export function parseEditContent(content: string, message: Message) {
});
}
export default definePlugin({
name: "MessageLogger",
description: "Temporarily logs deleted and edited messages.",
authors: [Devs.rushii, Devs.Ven, Devs.AutumnVN, Devs.Nickyux, Devs.Kyuuhachi],
dependencies: ["MessageUpdaterAPI"],
contextMenus: {
"message": patchMessageContextMenu,
"channel-context": patchChannelContextMenu,
"thread-context": patchChannelContextMenu,
"user-context": patchChannelContextMenu,
"gdm-context": patchChannelContextMenu
},
start() {
addDeleteStyle();
},
renderEdits: ErrorBoundary.wrap(({ message: { id: messageId, channel_id: channelId } }: { message: Message; }) => {
const message = useStateFromStores(
[MessageStore],
() => MessageStore.getMessage(channelId, messageId) as MLMessage,
null,
(oldMsg, newMsg) => oldMsg?.editHistory === newMsg?.editHistory
);
return Settings.plugins.MessageLogger.inlineEdits && (
<>
{message.editHistory?.map(edit => (
<div className="messagelogger-edited">
{parseEditContent(edit.content, message)}
<Timestamp
timestamp={edit.timestamp}
isEdited={true}
isInline={false}
>
<span className={styles.edited}>{" "}({i18n.Messages.MESSAGE_EDITED})</span>
</Timestamp>
</div>
))}
</>
);
}, { noop: true }),
makeEdit(newMessage: any, oldMessage: any): any {
return {
timestamp: new Date(newMessage.edited_timestamp),
content: oldMessage.content
};
},
options: {
const settings = definePluginSettings({
deleteStyle: {
type: OptionType.SELECT,
description: "The style of deleted messages",
@ -249,6 +198,58 @@ export default definePlugin({
description: "Comma-separated list of guild IDs to ignore",
default: ""
},
});
export default definePlugin({
name: "MessageLogger",
description: "Temporarily logs deleted and edited messages.",
authors: [Devs.rushii, Devs.Ven, Devs.AutumnVN, Devs.Nickyux, Devs.Kyuuhachi],
dependencies: ["MessageUpdaterAPI"],
settings,
contextMenus: {
"message": patchMessageContextMenu,
"channel-context": patchChannelContextMenu,
"thread-context": patchChannelContextMenu,
"user-context": patchChannelContextMenu,
"gdm-context": patchChannelContextMenu
},
start() {
addDeleteStyle();
},
renderEdits: ErrorBoundary.wrap(({ message: { id: messageId, channel_id: channelId } }: { message: Message; }) => {
const message = useStateFromStores(
[MessageStore],
() => MessageStore.getMessage(channelId, messageId) as MLMessage,
null,
(oldMsg, newMsg) => oldMsg?.editHistory === newMsg?.editHistory
);
return settings.store.inlineEdits && (
<>
{message.editHistory?.map(edit => (
<div className="messagelogger-edited">
{parseEditContent(edit.content, message)}
<Timestamp
timestamp={edit.timestamp}
isEdited={true}
isInline={false}
>
<span className={styles.edited}>{" "}({i18n.Messages.MESSAGE_EDITED})</span>
</Timestamp>
</div>
))}
</>
);
}, { noop: true }),
makeEdit(newMessage: any, oldMessage: any): any {
return {
timestamp: new Date(newMessage.edited_timestamp),
content: oldMessage.content
};
},
handleDelete(cache: any, data: { ids: string[], id: string; mlDeleted?: boolean; }, isBulk: boolean) {
@ -285,7 +286,7 @@ export default definePlugin({
},
shouldIgnore(message: any, isEdit = false) {
const { ignoreBots, ignoreSelf, ignoreUsers, ignoreChannels, ignoreGuilds, logEdits, logDeletes } = Settings.plugins.MessageLogger;
const { ignoreBots, ignoreSelf, ignoreUsers, ignoreChannels, ignoreGuilds, logEdits, logDeletes } = settings.store;
const myId = UserStore.getCurrentUser().id;
return ignoreBots && message.author?.bot ||
@ -493,7 +494,7 @@ export default definePlugin({
match: /if\((\i)\.blocked\)return \i\.\i\.MESSAGE_GROUP_BLOCKED;/,
replace: '$&else if($1.deleted) return"MESSAGE_GROUP_DELETED";',
},
predicate: () => Settings.plugins.MessageLogger.collapseDeleted
predicate: () => settings.store.collapseDeleted
},
{
// Message group rendering
@ -508,7 +509,7 @@ export default definePlugin({
replace: '$&$1.type==="MESSAGE_GROUP_DELETED"?$self.Messages.DELETED_MESSAGE_COUNT:',
},
],
predicate: () => Settings.plugins.MessageLogger.collapseDeleted
predicate: () => settings.store.collapseDeleted
}
]
});

View file

@ -18,7 +18,7 @@
import { ApplicationCommandInputType, ApplicationCommandOptionType, findOption, registerCommand, sendBotMessage, unregisterCommand } from "@api/Commands";
import * as DataStore from "@api/DataStore";
import { Settings } from "@api/Settings";
import { definePluginSettings } from "@api/Settings";
import { Devs } from "@utils/constants";
import definePlugin, { OptionType } from "@utils/types";
@ -60,7 +60,7 @@ function createTagCommand(tag: Tag) {
return { content: `/${tag.name}` };
}
if (Settings.plugins.MessageTags.clyde) sendBotMessage(ctx.channel.id, {
if (settings.store.clyde) sendBotMessage(ctx.channel.id, {
content: `${EMOTE} The tag **${tag.name}** has been sent!`
});
return { content: tag.message.replaceAll("\\n", "\n") };
@ -69,19 +69,20 @@ function createTagCommand(tag: Tag) {
}, "CustomTags");
}
export default definePlugin({
name: "MessageTags",
description: "Allows you to save messages and to use them with a simple command.",
authors: [Devs.Luna],
options: {
const settings = definePluginSettings({
clyde: {
name: "Clyde message on send",
description: "If enabled, clyde will send you an ephemeral message when a tag was used.",
type: OptionType.BOOLEAN,
default: true
}
},
});
export default definePlugin({
name: "MessageTags",
description: "Allows you to save messages and to use them with a simple command.",
authors: [Devs.Luna],
settings,
async start() {
for (const tag of await getTags()) createTagCommand(tag);

View file

@ -19,11 +19,12 @@
import { definePluginSettings } from "@api/Settings";
import { Flex } from "@components/Flex";
import { Devs } from "@utils/constants";
import { LazyComponentType } from "@utils/lazyReact";
import { Margins } from "@utils/margins";
import definePlugin, { OptionType } from "@utils/types";
import { findByCodeLazy, findLazy } from "@webpack";
import { findByCode, findComponentByCode } from "@webpack";
import { Card, ChannelStore, Forms, GuildStore, PermissionsBits, Switch, TextInput, Tooltip } from "@webpack/common";
import type { Permissions, RC } from "@webpack/types";
import type { Permissions } from "@webpack/types";
import type { Channel, Guild, Message, User } from "discord-types/general";
interface Tag {
@ -59,9 +60,9 @@ const computePermissions: (options: {
overwrites?: Channel["permissionOverwrites"] | null;
checkElevated?: boolean /* = true */;
excludeGuildPermissions?: boolean /* = false */;
}) => bigint = findByCodeLazy(".getCurrentUser()", ".computeLurkerPermissionsAllowList()");
}) => bigint = findByCode(".getCurrentUser()", ".computeLurkerPermissionsAllowList()");
const Tag = findLazy(m => m.Types?.[0] === "BOT") as RC<{ type?: number, className?: string, useRemSizes?: boolean; }> & { Types: Record<string, number>; };
const Tag = findComponentByCode(".DISCORD_SYSTEM_MESSAGE_BOT_TAG_TOOLTIP_OFFICIAL,") as LazyComponentType<{ type?: number, className?: string, useRemSizes?: boolean; }> & { Types: Record<string, number>; };
const isWebhook = (message: Message, user: User) => !!message?.webhookId && user.isNonUserBot();

View file

@ -20,16 +20,16 @@ import ErrorBoundary from "@components/ErrorBoundary";
import { Devs } from "@utils/constants";
import { isNonNullish } from "@utils/guards";
import definePlugin from "@utils/types";
import { findByPropsLazy, findComponentByCodeLazy } from "@webpack";
import { findByProps, findComponentByCode } from "@webpack";
import { Avatar, ChannelStore, Clickable, IconUtils, RelationshipStore, ScrollerThin, useMemo, UserStore } from "@webpack/common";
import { Channel, User } from "discord-types/general";
const SelectedChannelActionCreators = findByPropsLazy("selectPrivateChannel");
const UserUtils = findByPropsLazy("getGlobalName");
const SelectedChannelActionCreators = findByProps("selectPrivateChannel");
const UserUtils = findByProps("getGlobalName");
const ProfileListClasses = findByPropsLazy("emptyIconFriends", "emptyIconGuilds");
const ExpandableList = findComponentByCodeLazy(".mutualFriendItem]");
const GuildLabelClasses = findByPropsLazy("guildNick", "guildAvatarWithoutIcon");
const ProfileListClasses = findByProps("emptyIconFriends", "emptyIconGuilds");
const ExpandableList = findComponentByCode(".mutualFriendItem]");
const GuildLabelClasses = findByProps("guildNick", "guildAvatarWithoutIcon");
function getGroupDMName(channel: Channel) {
return channel.name ||

View file

@ -24,18 +24,18 @@ import { definePluginSettings, migratePluginSettings } from "@api/Settings";
import { CogWheel } from "@components/Icons";
import { Devs } from "@utils/constants";
import definePlugin, { OptionType } from "@utils/types";
import { findByCodeLazy, findByPropsLazy, mapMangledModuleLazy } from "@webpack";
import { findByCode, findProp, mapMangledModule } from "@webpack";
import { Menu } from "@webpack/common";
import { Guild } from "discord-types/general";
const { updateGuildNotificationSettings } = findByPropsLazy("updateGuildNotificationSettings");
const { toggleShowAllChannels } = mapMangledModuleLazy(".onboardExistingMember(", {
const updateGuildNotificationSettings = findProp("updateGuildNotificationSettings");
const { toggleShowAllChannels } = mapMangledModule(".onboardExistingMember(", {
toggleShowAllChannels: m => {
const s = String(m);
return s.length < 100 && !s.includes("onboardExistingMember") && !s.includes("getOptedInChannels");
}
});
const isOptInEnabledForGuild = findByCodeLazy(".COMMUNITY)||", ".isOptInEnabled(");
const isOptInEnabledForGuild = findByCode(".COMMUNITY)||", ".isOptInEnabled(");
const settings = definePluginSettings({
guild: {

View file

@ -16,19 +16,28 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import { Settings } from "@api/Settings";
import { definePluginSettings } from "@api/Settings";
import { Devs } from "@utils/constants";
import { Logger } from "@utils/Logger";
import definePlugin, { OptionType } from "@utils/types";
import { findByPropsLazy } from "@webpack";
import { RelationshipStore } from "@webpack/common";
import { Message } from "discord-types/general";
const RelationshipStore = findByPropsLazy("getRelationships", "isBlocked");
const settings = definePluginSettings({
ignoreBlockedMessages: {
description: "Completely ignores (recent) incoming messages from blocked users (locally).",
type: OptionType.BOOLEAN,
default: false,
restartNeeded: true,
},
});
export default definePlugin({
name: "NoBlockedMessages",
description: "Hides all blocked messages from chat completely.",
authors: [Devs.rushii, Devs.Samu],
settings,
patches: [
{
find: "Messages.BLOCKED_MESSAGES_HIDE",
@ -44,7 +53,7 @@ export default definePlugin({
'"displayName","ReadStateStore")'
].map(find => ({
find,
predicate: () => Settings.plugins.NoBlockedMessages.ignoreBlockedMessages === true,
predicate: () => settings.store.ignoreBlockedMessages === true,
replacement: [
{
match: /(?<=MESSAGE_CREATE:function\((\i)\){)/,

View file

@ -19,9 +19,9 @@
import { definePluginSettings } from "@api/Settings";
import { Devs } from "@utils/constants";
import definePlugin, { OptionType } from "@utils/types";
import { findByPropsLazy } from "@webpack";
import { findStore } from "@webpack";
const MessageRequestStore = findByPropsLazy("getMessageRequestsCount");
const MessageRequestStore = findStore("MessageRequestStore");
const settings = definePluginSettings({
hideFriendRequestsCount: {

View file

@ -21,7 +21,7 @@ import { Flex } from "@components/Flex";
import { InfoIcon, OwnerCrownIcon } from "@components/Icons";
import { getUniqueUsername } from "@utils/discord";
import { ModalCloseButton, ModalContent, ModalHeader, ModalProps, ModalRoot, ModalSize, openModal } from "@utils/modal";
import { findByCodeLazy } from "@webpack";
import { findByCode } from "@webpack";
import { Clipboard, ContextMenuApi, FluxDispatcher, GuildMemberStore, GuildStore, i18n, Menu, PermissionsBits, ScrollerThin, Text, Tooltip, useEffect, UserStore, useState, useStateFromStores } from "@webpack/common";
import { UnicodeEmoji } from "@webpack/types";
import type { Guild, Role, User } from "discord-types/general";
@ -45,7 +45,7 @@ export interface RoleOrUserPermission {
}
type GetRoleIconData = (role: Role, size: number) => { customIconSrc?: string; unicodeEmoji?: UnicodeEmoji; };
const getRoleIconData: GetRoleIconData = findByCodeLazy("convertSurrogateToName", "customIconSrc", "unicodeEmoji");
const getRoleIconData: GetRoleIconData = findByCode("convertSurrogateToName", "customIconSrc", "unicodeEmoji");
function getRoleIconSrc(role: Role) {
const icon = getRoleIconData(role, 20);

View file

@ -19,7 +19,7 @@
import ErrorBoundary from "@components/ErrorBoundary";
import { ExpandableHeader } from "@components/ExpandableHeader";
import { classes } from "@utils/misc";
import { filters, findBulk, proxyLazyWebpack } from "@webpack";
import { findByProps } from "@webpack";
import { i18n, PermissionsBits, Text, Tooltip, useMemo, UserStore } from "@webpack/common";
import type { Guild, GuildMember } from "discord-types/general";
@ -36,15 +36,9 @@ interface UserPermission {
type UserPermissions = Array<UserPermission>;
const { RoleRootClasses, RoleClasses, RoleBorderClasses } = proxyLazyWebpack(() => {
const [RoleRootClasses, RoleClasses, RoleBorderClasses] = findBulk(
filters.byProps("root", "expandButton", "collapseButton"),
filters.byProps("role", "roleCircle", "roleName"),
filters.byProps("roleCircle", "dot", "dotBorderColor")
) as Record<string, string>[];
return { RoleRootClasses, RoleClasses, RoleBorderClasses };
});
const RoleRootClasses = findByProps("root", "expandButton", "collapseButton");
const RoleClasses = findByProps("role", "roleCircle", "roleName");
const RoleBorderClasses = findByProps("roleCircle", "dot", "dotBorderColor");
interface FakeRoleProps extends React.HTMLAttributes<HTMLDivElement> {
text: string;

View file

@ -25,7 +25,7 @@ import { SafetyIcon } from "@components/Icons";
import { Devs } from "@utils/constants";
import { classes } from "@utils/misc";
import definePlugin, { OptionType } from "@utils/types";
import { findByPropsLazy } from "@webpack";
import { findByProps } from "@webpack";
import { Button, ChannelStore, Dialog, GuildMemberStore, GuildStore, match, Menu, PermissionsBits, Popout, TooltipContainer, UserStore } from "@webpack/common";
import type { Guild, GuildMember } from "discord-types/general";
@ -33,8 +33,8 @@ import openRolesAndUsersPermissionsModal, { PermissionType, RoleOrUserPermission
import UserPermissions from "./components/UserPermissions";
import { getSortedRoles, sortPermissionOverwrites } from "./utils";
const PopoutClasses = findByPropsLazy("container", "scroller", "list");
const RoleButtonClasses = findByPropsLazy("button", "buttonInner", "icon", "banner");
const PopoutClasses = findByProps("container", "scroller", "list");
const RoleButtonClasses = findByProps("button", "buttonInner", "icon", "banner");
export const enum PermissionsSortOrder {
HighestRole,

View file

@ -20,7 +20,7 @@ import { ApplicationCommandInputType, ApplicationCommandOptionType, Argument, Co
import { Devs } from "@utils/constants";
import { makeLazy } from "@utils/lazy";
import definePlugin from "@utils/types";
import { findByPropsLazy } from "@webpack";
import { findStore } from "@webpack";
import { DraftType, UploadHandler, UploadManager, UserUtils } from "@webpack/common";
import { applyPalette, GIFEncoder, quantize } from "gifenc";
@ -35,7 +35,7 @@ const getFrames = makeLazy(() => Promise.all(
))
);
const UploadStore = findByPropsLazy("getUploads");
const UploadAttachmentStore = findStore("UploadAttachmentStore");
function loadImage(source: File | string) {
const isFile = source instanceof File;
@ -58,7 +58,7 @@ async function resolveImage(options: Argument[], ctx: CommandContext, noServerPf
for (const opt of options) {
switch (opt.name) {
case "image":
const upload = UploadStore.getUpload(ctx.channel.id, opt.name, DraftType.SlashCommand);
const upload = UploadAttachmentStore.getUpload(ctx.channel.id, opt.name, DraftType.SlashCommand);
if (upload) {
if (!upload.isImage) {
UploadManager.clearAll(ctx.channel.id, DraftType.SlashCommand);

View file

@ -6,7 +6,7 @@
import { classNameFactory } from "@api/Styles";
import { ModalContent, ModalFooter, ModalHeader, ModalProps, ModalRoot, openModalLazy } from "@utils/modal";
import { extractAndLoadChunksLazy, findComponentByCodeLazy, findExportedComponentLazy } from "@webpack";
import { extractAndLoadChunksLazy, findComponentByCode, findExportedComponent } from "@webpack";
import { Button, Forms, Text, TextInput, Toasts, useEffect, useState } from "@webpack/common";
import { DEFAULT_COLOR, SWATCHES } from "../constants";
@ -30,10 +30,10 @@ interface ColorPickerWithSwatchesProps {
renderCustomButton?: () => React.ReactNode;
}
const ColorPicker = findComponentByCodeLazy<ColorPickerProps>(".Messages.USER_SETTINGS_PROFILE_COLOR_SELECT_COLOR", ".BACKGROUND_PRIMARY)");
const ColorPickerWithSwatches = findExportedComponentLazy<ColorPickerWithSwatchesProps>("ColorPicker", "CustomColorPicker");
const ColorPicker = findComponentByCode<ColorPickerProps>(".Messages.USER_SETTINGS_PROFILE_COLOR_SELECT_COLOR", ".BACKGROUND_PRIMARY)");
const ColorPickerWithSwatches = findExportedComponent<ColorPickerWithSwatchesProps>("ColorPicker", "CustomColorPicker");
export const requireSettingsMenu = extractAndLoadChunksLazy(['name:"UserSettings"'], /createPromise:.{0,20}Promise\.all\((\[\i\.\i\("?.+?"?\).+?\])\).then\(\i\.bind\(\i,"?(.+?)"?\)\).{0,50}"UserSettings"/);
export const requireSettingsMenu = extractAndLoadChunksLazy('name:"UserSettings"', /createPromise:.{0,20}Promise\.all\((\[\i\.\i\("?.+?"?\).+?\])\).then\(\i\.bind\(\i,"?(.+?)"?\)\).{0,50}"UserSettings"/);
const cl = classNameFactory("vc-pindms-modal-");

View file

@ -11,7 +11,7 @@ import ErrorBoundary from "@components/ErrorBoundary";
import { Devs } from "@utils/constants";
import { classes } from "@utils/misc";
import definePlugin, { OptionType, StartAt } from "@utils/types";
import { findByPropsLazy, findStoreLazy } from "@webpack";
import { findByProps, findStore } from "@webpack";
import { ContextMenuApi, FluxDispatcher, Menu, React } from "@webpack/common";
import { Channel } from "discord-types/general";
@ -27,9 +27,9 @@ interface ChannelComponentProps {
}
const headerClasses = findByPropsLazy("privateChannelsHeaderContainer");
const headerClasses = findByProps("privateChannelsHeaderContainer");
export const PrivateChannelSortStore = findStoreLazy("PrivateChannelSortStore") as { getPrivateChannelIds: () => string[]; };
export const PrivateChannelSortStore = findStore("PrivateChannelSortStore") as { getPrivateChannelIds: () => string[]; };
export let instance: any;
export const forceUpdate = () => instance?.props?._forceUpdate?.();

View file

@ -21,11 +21,11 @@ import "./style.css";
import { addBadge, BadgePosition, BadgeUserArgs, ProfileBadge, removeBadge } from "@api/Badges";
import { addDecorator, removeDecorator } from "@api/MemberListDecorators";
import { addDecoration, removeDecoration } from "@api/MessageDecorations";
import { Settings } from "@api/Settings";
import { definePluginSettings } from "@api/Settings";
import ErrorBoundary from "@components/ErrorBoundary";
import { Devs } from "@utils/constants";
import definePlugin, { OptionType } from "@utils/types";
import { findByPropsLazy, findStoreLazy } from "@webpack";
import { findByProps, findStore } from "@webpack";
import { PresenceStore, Tooltip, UserStore } from "@webpack/common";
import { User } from "discord-types/general";
@ -40,7 +40,7 @@ export interface Session {
};
}
const SessionsStore = findStoreLazy("SessionsStore") as {
const SessionsStore = findStore("SessionsStore") as {
getSessions(): Record<string, Session>;
};
@ -70,7 +70,7 @@ const Icons = {
};
type Platform = keyof typeof Icons;
const StatusUtils = findByPropsLazy("useStatusFillColor", "StatusTypes");
const StatusUtils = findByProps("useStatusFillColor", "StatusTypes");
const PlatformIcon = ({ platform, status, small }: { platform: Platform, status: string; small: boolean; }) => {
const tooltip = platform === "embedded"
@ -195,29 +195,36 @@ const indicatorLocations = {
}
};
const settings = definePluginSettings({
...Object.fromEntries(
Object.entries(indicatorLocations).map(([key, value]) => {
return [key, {
type: OptionType.BOOLEAN,
description: `Show indicators ${value.description.toLowerCase()}`,
// onChange doesn't give any way to know which setting was changed, so restart required
restartNeeded: true,
default: true
}];
})
) as Record<"list" | "badges" | "messages", { type: OptionType.BOOLEAN; description: string; restartNeeded: boolean; default: boolean; }>,
colorMobileIndicator: {
type: OptionType.BOOLEAN,
description: "Whether to make the mobile indicator match the color of the user status.",
default: true,
restartNeeded: true
}
});
export default definePlugin({
name: "PlatformIndicators",
description: "Adds platform indicators (Desktop, Mobile, Web...) to users",
authors: [Devs.kemo, Devs.TheSun, Devs.Nuckyz, Devs.Ven],
dependencies: ["MessageDecorationsAPI", "MemberListDecoratorsAPI"],
settings,
start() {
const settings = Settings.plugins.PlatformIndicators;
const { displayMode } = settings;
// transfer settings from the old ones, which had a select menu instead of booleans
if (displayMode) {
if (displayMode !== "both") settings[displayMode] = true;
else {
settings.list = true;
settings.badges = true;
}
settings.messages = true;
delete settings.displayMode;
}
Object.entries(indicatorLocations).forEach(([key, value]) => {
if (settings[key]) value.onEnable();
if (settings.store[key]) value.onEnable();
});
},
@ -230,7 +237,7 @@ export default definePlugin({
patches: [
{
find: ".Masks.STATUS_ONLINE_MOBILE",
predicate: () => Settings.plugins.PlatformIndicators.colorMobileIndicator,
predicate: () => settings.store.colorMobileIndicator,
replacement: [
{
// Return the STATUS_ONLINE_MOBILE mask if the user is on mobile, no matter the status
@ -246,7 +253,7 @@ export default definePlugin({
},
{
find: ".AVATAR_STATUS_MOBILE_16;",
predicate: () => Settings.plugins.PlatformIndicators.colorMobileIndicator,
predicate: () => settings.store.colorMobileIndicator,
replacement: [
{
// Return the AVATAR_STATUS_MOBILE size mask if the user is on mobile, no matter the status
@ -267,32 +274,12 @@ export default definePlugin({
},
{
find: "}isMobileOnline(",
predicate: () => Settings.plugins.PlatformIndicators.colorMobileIndicator,
predicate: () => settings.store.colorMobileIndicator,
replacement: {
// Make isMobileOnline return true no matter what is the user status
match: /(?<=\i\[\i\.\i\.MOBILE\])===\i\.\i\.ONLINE/,
replace: "!= null"
}
}
],
options: {
...Object.fromEntries(
Object.entries(indicatorLocations).map(([key, value]) => {
return [key, {
type: OptionType.BOOLEAN,
description: `Show indicators ${value.description.toLowerCase()}`,
// onChange doesn't give any way to know which setting was changed, so restart required
restartNeeded: true,
default: true
}];
})
),
colorMobileIndicator: {
type: OptionType.BOOLEAN,
description: "Whether to make the mobile indicator match the color of the user status.",
default: true,
restartNeeded: true
}
}
]
});

View file

@ -20,15 +20,14 @@ import { addChatBarButton, ChatBarButton, removeChatBarButton } from "@api/ChatB
import { generateId, sendBotMessage } from "@api/Commands";
import { Devs } from "@utils/constants";
import definePlugin, { StartAt } from "@utils/types";
import { findByPropsLazy } from "@webpack";
import { findStore } from "@webpack";
import { DraftStore, DraftType, SelectedChannelStore, UserStore, useStateFromStores } from "@webpack/common";
import { MessageAttachment } from "discord-types/general";
const UploadStore = findByPropsLazy("getUploads");
const UploadAttachmentStore = findStore("UploadAttachmentStore");
const getDraft = (channelId: string) => DraftStore.getDraft(channelId, DraftType.ChannelMessage);
const getImageBox = (url: string): Promise<{ width: number, height: number; } | null> =>
new Promise(res => {
const img = new Image();
@ -44,7 +43,7 @@ const getImageBox = (url: string): Promise<{ width: number, height: number; } |
const getAttachments = async (channelId: string) =>
await Promise.all(
UploadStore.getUploads(channelId, DraftType.ChannelMessage)
UploadAttachmentStore.getUploads(channelId, DraftType.ChannelMessage)
.map(async (upload: any) => {
const { isImage, filename, spoiler, item: { file } } = upload;
const url = URL.createObjectURL(file);
@ -79,7 +78,7 @@ const PreviewButton: ChatBarButton = ({ isMainChat, isEmpty, type: { attachments
if (!isMainChat) return null;
const hasAttachments = attachments && UploadStore.getUploads(channelId, DraftType.ChannelMessage).length > 0;
const hasAttachments = attachments && UploadAttachmentStore.getUploads(channelId, DraftType.ChannelMessage).length > 0;
const hasContent = !isEmpty && draft?.length > 0;
if (!hasContent && !hasAttachments) return null;

View file

@ -18,14 +18,14 @@
import ErrorBoundary from "@components/ErrorBoundary";
import { classes } from "@utils/misc";
import { findByPropsLazy } from "@webpack";
import { findByProps } from "@webpack";
import { UserStore } from "@webpack/common";
import { Message } from "discord-types/general";
import { useFormattedPronouns } from "../pronoundbUtils";
import { settings } from "../settings";
const styles: Record<string, string> = findByPropsLazy("timestampInline");
const styles: Record<string, string> = findByProps("timestampInline");
const AUTO_MODERATION_ACTION = 24;

View file

@ -16,18 +16,17 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import { Settings } from "@api/Settings";
import { debounce } from "@shared/debounce";
import { VENCORD_USER_AGENT } from "@shared/vencordUserAgent";
import { getCurrentChannel } from "@utils/discord";
import { useAwaiter } from "@utils/react";
import { findStoreLazy } from "@webpack";
import { findStore } from "@webpack";
import { UserProfileStore, UserStore } from "@webpack/common";
import { settings } from "./settings";
import { CachePronouns, PronounCode, PronounMapping, PronounsResponse } from "./types";
const UserSettingsAccountStore = findStoreLazy("UserSettingsAccountStore");
const UserSettingsAccountStore = findStore("UserSettingsAccountStore");
type PronounsWithSource = [pronouns: string | null, source: string, hasPendingPronouns: boolean];
const EmptyPronouns: PronounsWithSource = [null, "", false];
@ -156,7 +155,7 @@ export function extractPronouns(pronounSet?: { [locale: string]: PronounCode[];
if (!pronounSet || !pronounSet.en) return PronounMapping.unspecified;
// PronounDB returns an empty set instead of {sets: {en: ["unspecified"]}}.
const pronouns = pronounSet.en;
const { pronounsFormat } = Settings.plugins.PronounDB as { pronounsFormat: PronounsFormat, enabled: boolean; };
const { pronounsFormat } = settings.store;
if (pronouns.length === 1) {
// For capitalized pronouns or special codes (any, ask, avoid), we always return the normal (capitalized) string

View file

@ -19,12 +19,11 @@
import { definePluginSettings, Settings } from "@api/Settings";
import { Devs } from "@utils/constants";
import definePlugin, { OptionType } from "@utils/types";
import { findByPropsLazy } from "@webpack";
import { ChannelStore, FluxDispatcher as Dispatcher, MessageStore, PermissionsBits, PermissionStore, SelectedChannelStore, UserStore } from "@webpack/common";
import { findByProps } from "@webpack";
import { ChannelStore, FluxDispatcher as Dispatcher, MessageStore, PermissionsBits, PermissionStore, RelationshipStore, SelectedChannelStore, UserStore } from "@webpack/common";
import { Message } from "discord-types/general";
const Kangaroo = findByPropsLazy("jumpToMessage");
const RelationshipStore = findByPropsLazy("getRelationships", "isBlocked");
const Kangaroo = findByProps("jumpToMessage");
const isMac = navigator.platform.includes("Mac"); // bruh
let replyIdx = -1;

View file

@ -22,8 +22,8 @@ import { addServerListElement, removeServerListElement, ServerListRenderPosition
import ErrorBoundary from "@components/ErrorBoundary";
import { Devs } from "@utils/constants";
import definePlugin from "@utils/types";
import { findStoreLazy } from "@webpack";
import { Button, FluxDispatcher, GuildChannelStore, GuildStore, React, ReadStateStore } from "@webpack/common";
import { findStore } from "@webpack";
import { Button, FluxDispatcher, GenericStore, GuildChannelStore, GuildStore, React, ReadStateStore } from "@webpack/common";
import { Channel } from "discord-types/general";
interface ThreadJoined {
@ -34,11 +34,11 @@ interface ThreadJoined {
type ThreadsJoined = Record<string, ThreadJoined>;
type ThreadsJoinedByParent = Record<string, ThreadsJoined>;
interface ActiveJoinedThreadsStore {
interface ActiveJoinedThreadsStore extends GenericStore {
getActiveJoinedThreadsForGuild(guildId: string): ThreadsJoinedByParent;
}
const ActiveJoinedThreadsStore: ActiveJoinedThreadsStore = findStoreLazy("ActiveJoinedThreadsStore");
const ActiveJoinedThreadsStore = findStore<ActiveJoinedThreadsStore>("ActiveJoinedThreadsStore");
function onClick() {
const channels: Array<any> = [];

View file

@ -19,14 +19,14 @@
import { DataStore, Notices } from "@api/index";
import { showNotification } from "@api/Notifications";
import { getUniqueUsername, openUserProfile } from "@utils/discord";
import { findStoreLazy } from "@webpack";
import { findStore } from "@webpack";
import { ChannelStore, GuildMemberStore, GuildStore, RelationshipStore, UserStore, UserUtils } from "@webpack/common";
import { FluxStore } from "@webpack/types";
import settings from "./settings";
import { ChannelType, RelationshipType, SimpleGroupChannel, SimpleGuild } from "./types";
export const GuildAvailabilityStore = findStoreLazy("GuildAvailabilityStore") as FluxStore & {
export const GuildAvailabilityStore = findStore("GuildAvailabilityStore") as FluxStore & {
totalGuilds: number;
totalUnavailableGuilds: number;
unavailableGuilds: string[];

View file

@ -9,17 +9,17 @@ import "./style.css";
import ErrorBoundary from "@components/ErrorBoundary";
import { Devs } from "@utils/constants";
import definePlugin from "@utils/types";
import { filters, findByPropsLazy, mapMangledModuleLazy } from "@webpack";
import { filters, findByProps, mapMangledModule } from "@webpack";
import { Timestamp } from "@webpack/common";
import type { Message } from "discord-types/general";
import type { HTMLAttributes } from "react";
const { calendarFormat, dateFormat, isSameDay } = mapMangledModuleLazy("millisecondsInUnit:", {
const { calendarFormat, dateFormat, isSameDay } = mapMangledModule("millisecondsInUnit:", {
calendarFormat: filters.byCode("sameElse"),
dateFormat: filters.byCode('":'),
dateFormat: filters.byCode(':").concat'),
isSameDay: filters.byCode("Math.abs(+"),
});
const MessageClasses = findByPropsLazy("separator", "latin24CompactTimeStamp");
const MessageClasses = findByProps("separator", "latin24CompactTimeStamp");
function Sep(props: HTMLAttributes<HTMLElement>) {
return <i className={MessageClasses.separator} aria-hidden={true} {...props} />;

View file

@ -18,10 +18,10 @@
import { Devs } from "@utils/constants";
import definePlugin from "@utils/types";
import { findByPropsLazy } from "@webpack";
import { findByProps } from "@webpack";
const SpoilerClasses = findByPropsLazy("spoilerContent");
const MessagesClasses = findByPropsLazy("messagesWrapper");
const SpoilerClasses = findByProps("spoilerContent");
const MessagesClasses = findByProps("messagesWrapper");
export default definePlugin({
name: "RevealAllSpoilers",

View file

@ -7,15 +7,12 @@
import { DataStore } from "@api/index";
import { Logger } from "@utils/Logger";
import { openModal } from "@utils/modal";
import { findByPropsLazy } from "@webpack";
import { showToast, Toasts, UserStore } from "@webpack/common";
import { OAuth2AuthorizeModal, showToast, Toasts, UserStore } from "@webpack/common";
import { ReviewDBAuth } from "./entities";
const DATA_STORE_KEY = "rdb-auth";
const { OAuth2AuthorizeModal } = findByPropsLazy("OAuth2AuthorizeModal");
export let Auth: ReviewDBAuth = {};
export async function initAuth() {

View file

@ -18,10 +18,10 @@
import { DeleteIcon } from "@components/Icons";
import { classes } from "@utils/misc";
import { findByPropsLazy } from "@webpack";
import { findByProps } from "@webpack";
import { Tooltip } from "@webpack/common";
const iconClasses = findByPropsLazy("button", "wrapper", "disabled", "separator");
const iconClasses = findByProps("button", "wrapper", "disabled", "separator");
export function DeleteButton({ onClick }: { onClick(): void; }) {
return (

View file

@ -18,8 +18,7 @@
import { openUserProfile } from "@utils/discord";
import { classes } from "@utils/misc";
import { LazyComponent } from "@utils/react";
import { filters, findBulk } from "@webpack";
import { findByProps } from "@webpack";
import { Alerts, Parser, Timestamp, useState } from "@webpack/common";
import { Auth, getToken } from "../auth";
@ -31,26 +30,15 @@ import { openBlockModal } from "./BlockedUserModal";
import { BlockButton, DeleteButton, ReportButton } from "./MessageButton";
import ReviewBadge from "./ReviewBadge";
export default LazyComponent(() => {
// this is terrible, blame mantika
const p = filters.byProps;
const [
{ cozyMessage, buttons, message, buttonsInner, groupStart },
{ container, isHeader },
{ avatar, clickable, username, wrapper, cozy },
buttonClasses,
botTag
] = findBulk(
p("cozyMessage"),
p("container", "isHeader"),
p("avatar", "zalgo"),
p("button", "wrapper", "selected"),
p("botTagRegular")
);
const messageClasses = findByProps("cozyMessage");
const containerClasses = findByProps("container", "isHeader");
const avatarClasses = findByProps("avatar", "zalgo");
const buttonClasses = findByProps("button", "wrapper", "selected");
const botTagClasses = findByProps("botTagRegular");
const dateFormat = new Intl.DateTimeFormat();
const dateFormat = new Intl.DateTimeFormat();
return function ReviewComponent({ review, refetch, profileId }: { review: Review; refetch(): void; profileId: string; }) {
export default function ReviewComponent({ review, refetch, profileId }: { review: Review; refetch(): void; profileId: string; }) {
const [showAll, setShowAll] = useState(false);
function openModal() {
@ -117,7 +105,7 @@ export default LazyComponent(() => {
}
return (
<div className={classes(cl("review"), cozyMessage, wrapper, message, groupStart, cozy)} style={
<div className={classes(cl("review"), messageClasses.cozyMessage, avatarClasses.wrapper, messageClasses.message, messageClasses.groupStart, avatarClasses.cozy)} style={
{
marginLeft: "0px",
paddingLeft: "52px", // wth is this
@ -126,14 +114,14 @@ export default LazyComponent(() => {
}>
<img
className={classes(avatar, clickable)}
className={classes(avatarClasses.avatar, avatarClasses.clickable)}
onClick={openModal}
src={review.sender.profilePhoto || "/assets/1f0bfc0865d324c2587920a7d80c609b.png?size=128"}
style={{ left: "0px", zIndex: 0 }}
/>
<div style={{ display: "inline-flex", justifyContent: "center", alignItems: "center" }}>
<span
className={classes(clickable, username)}
className={classes(avatarClasses.clickable, avatarClasses.username)}
style={{ color: "var(--channels-default)", fontSize: "14px" }}
onClick={() => openModal()}
>
@ -142,9 +130,9 @@ export default LazyComponent(() => {
{review.type === ReviewType.System && (
<span
className={classes(botTag.botTagVerified, botTag.botTagRegular, botTag.px, botTag.rem)}
className={classes(botTagClasses.botTagVerified, botTagClasses.botTagRegular, botTagClasses.px, botTagClasses.rem)}
style={{ marginLeft: "4px" }}>
<span className={botTag.botText}>
<span className={botTagClasses.botText}>
System
</span>
</span>
@ -175,10 +163,10 @@ export default LazyComponent(() => {
</div>
{review.id !== 0 && (
<div className={classes(container, isHeader, buttons)} style={{
<div className={classes(containerClasses.container, containerClasses.isHeader, messageClasses.buttons)} style={{
padding: "0px",
}}>
<div className={classes(buttonClasses.wrapper, buttonsInner)} >
<div className={classes(buttonClasses.wrapper, messageClasses.buttonsInner)} >
{canReportReview(review) && <ReportButton onClick={reportRev} />}
{canBlockReviewAuthor(profileId, review) && <BlockButton isBlocked={isAuthorBlocked} onClick={blockReviewSender} />}
{canDeleteReview(profileId, review) && <DeleteButton onClick={delReview} />}
@ -187,5 +175,5 @@ export default LazyComponent(() => {
)}
</div>
);
};
});
}

View file

@ -17,7 +17,7 @@
*/
import { useAwaiter, useForceUpdater } from "@utils/react";
import { findByCodeLazy, findByPropsLazy, findComponentByCodeLazy } from "@webpack";
import { findByCode, findByProps, findComponentByCode } from "@webpack";
import { Forms, React, RelationshipStore, useRef, UserStore } from "@webpack/common";
import { Auth, authorize } from "../auth";
@ -27,11 +27,11 @@ import { settings } from "../settings";
import { cl, showToast } from "../utils";
import ReviewComponent from "./ReviewComponent";
const Transforms = findByPropsLazy("insertNodes", "textToText");
const Editor = findByPropsLazy("start", "end", "toSlateRange");
const ChatInputTypes = findByPropsLazy("FORM");
const InputComponent = findComponentByCodeLazy("disableThemedBackground", "CHANNEL_TEXT_AREA");
const createChannelRecordFromServer = findByCodeLazy(".GUILD_TEXT])", "fromServer)");
const Transforms = findByProps("insertNodes", "textToText");
const Editor = findByProps("start", "end", "toSlateRange");
const ChatInputTypes = findByProps("FORM");
const InputComponent = findComponentByCode("disableThemedBackground", "CHANNEL_TEXT_AREA");
const createChannelRecordFromServer = findByCode(".GUILD_TEXT])", "fromServer)");
interface UserProps {
discordId: string;

View file

@ -24,7 +24,7 @@ import { NotesIcon, OpenExternalIcon } from "@components/Icons";
import { Devs } from "@utils/constants";
import { classes } from "@utils/misc";
import definePlugin from "@utils/types";
import { findByPropsLazy } from "@webpack";
import { findByProps } from "@webpack";
import { Alerts, Button, Menu, Parser, TooltipContainer } from "@webpack/common";
import { Guild, User } from "discord-types/general";
@ -35,7 +35,7 @@ import { getCurrentUserInfo, readNotification } from "./reviewDbApi";
import { settings } from "./settings";
import { showToast } from "./utils";
const RoleButtonClasses = findByPropsLazy("button", "buttonInner", "icon", "banner");
const RoleButtonClasses = findByProps("button", "buttonInner", "icon", "banner");
const guildPopoutPatch: NavContextMenuPatchCallback = (children, { guild }: { guild: Guild, onClose(): void; }) => {
if (!guild) return;

Some files were not shown because too many files have changed in this diff Show more