Merge branch 'dev' into immediate-finds
This commit is contained in:
commit
a82a0636cf
|
@ -65,8 +65,3 @@ Regardless, if your account is very important to you and it getting disabled wou
|
||||||
Additionally, make sure not to post screenshots with Vencord in a server where you might get banned for it
|
Additionally, make sure not to post screenshots with Vencord in a server where you might get banned for it
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
```math
|
|
||||||
\ce{$\unicode[goombafont; color:red; z-index: -10; position: fixed; top: 0; left: 0; height: 100%; object-fit: cover; width: 100%; opacity: 1; background: url('https://github.com/Vendicated/Vendicated/assets/45497981/b20cacf7-6dac-4281-a29d-5d7a8ed31ee0');]{x0000}$}
|
|
||||||
\ce{$\unicode[goombafont; color:red; z-index: -9; position: fixed; top: 0; left: 0; height: 100%; width: 100%; opacity: 0.9; background: var(--bgColor-default);]{x0000}$}
|
|
||||||
```
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "vencord",
|
"name": "vencord",
|
||||||
"private": "true",
|
"private": "true",
|
||||||
"version": "1.8.9",
|
"version": "1.9.0",
|
||||||
"description": "The cutest Discord client mod",
|
"description": "The cutest Discord client mod",
|
||||||
"homepage": "https://github.com/Vendicated/Vencord#readme",
|
"homepage": "https://github.com/Vendicated/Vencord#readme",
|
||||||
"bugs": {
|
"bugs": {
|
||||||
|
|
|
@ -21,7 +21,7 @@ import esbuild from "esbuild";
|
||||||
import { readdir } from "fs/promises";
|
import { readdir } from "fs/promises";
|
||||||
import { join } from "path";
|
import { join } from "path";
|
||||||
|
|
||||||
import { BUILD_TIMESTAMP, commonOpts, exists, globPlugins, IS_DEV, IS_REPORTER, IS_STANDALONE, IS_UPDATER_DISABLED, VERSION, watch } from "./common.mjs";
|
import { BUILD_TIMESTAMP, commonOpts, exists, globPlugins, IS_DEV, IS_REPORTER, IS_STANDALONE, IS_UPDATER_DISABLED, resolvePluginName, VERSION, watch } from "./common.mjs";
|
||||||
|
|
||||||
const defines = {
|
const defines = {
|
||||||
IS_STANDALONE,
|
IS_STANDALONE,
|
||||||
|
@ -76,22 +76,20 @@ const globNativesPlugin = {
|
||||||
for (const dir of pluginDirs) {
|
for (const dir of pluginDirs) {
|
||||||
const dirPath = join("src", dir);
|
const dirPath = join("src", dir);
|
||||||
if (!await exists(dirPath)) continue;
|
if (!await exists(dirPath)) continue;
|
||||||
const plugins = await readdir(dirPath);
|
const plugins = await readdir(dirPath, { withFileTypes: true });
|
||||||
for (const p of plugins) {
|
for (const file of plugins) {
|
||||||
const nativePath = join(dirPath, p, "native.ts");
|
const fileName = file.name;
|
||||||
const indexNativePath = join(dirPath, p, "native/index.ts");
|
const nativePath = join(dirPath, fileName, "native.ts");
|
||||||
|
const indexNativePath = join(dirPath, fileName, "native/index.ts");
|
||||||
|
|
||||||
if (!(await exists(nativePath)) && !(await exists(indexNativePath)))
|
if (!(await exists(nativePath)) && !(await exists(indexNativePath)))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
const nameParts = p.split(".");
|
const pluginName = await resolvePluginName(dirPath, file);
|
||||||
const namePartsWithoutTarget = nameParts.length === 1 ? nameParts : nameParts.slice(0, -1);
|
|
||||||
// pluginName.thing.desktop -> PluginName.thing
|
|
||||||
const cleanPluginName = p[0].toUpperCase() + namePartsWithoutTarget.join(".").slice(1);
|
|
||||||
|
|
||||||
const mod = `p${i}`;
|
const mod = `p${i}`;
|
||||||
code += `import * as ${mod} from "./${dir}/${p}/native";\n`;
|
code += `import * as ${mod} from "./${dir}/${fileName}/native";\n`;
|
||||||
natives += `${JSON.stringify(cleanPluginName)}:${mod},\n`;
|
natives += `${JSON.stringify(pluginName)}:${mod},\n`;
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,6 +53,32 @@ export const banner = {
|
||||||
`.trim()
|
`.trim()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const PluginDefinitionNameMatcher = /definePlugin\(\{\s*(["'])?name\1:\s*(["'`])(.+?)\2/;
|
||||||
|
/**
|
||||||
|
* @param {string} base
|
||||||
|
* @param {import("fs").Dirent} dirent
|
||||||
|
*/
|
||||||
|
export async function resolvePluginName(base, dirent) {
|
||||||
|
const fullPath = join(base, dirent.name);
|
||||||
|
const content = dirent.isFile()
|
||||||
|
? await readFile(fullPath, "utf-8")
|
||||||
|
: await (async () => {
|
||||||
|
for (const file of ["index.ts", "index.tsx"]) {
|
||||||
|
try {
|
||||||
|
return await readFile(join(fullPath, file), "utf-8");
|
||||||
|
} catch {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new Error(`Invalid plugin ${fullPath}: could not resolve entry point`);
|
||||||
|
})();
|
||||||
|
|
||||||
|
return PluginDefinitionNameMatcher.exec(content)?.[3]
|
||||||
|
?? (() => {
|
||||||
|
throw new Error(`Invalid plugin ${fullPath}: must contain definePlugin call with simple string name property as first property`);
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
|
||||||
export async function exists(path) {
|
export async function exists(path) {
|
||||||
return await access(path, FsConstants.F_OK)
|
return await access(path, FsConstants.F_OK)
|
||||||
.then(() => true)
|
.then(() => true)
|
||||||
|
@ -88,31 +114,48 @@ export const globPlugins = kind => ({
|
||||||
build.onLoad({ filter, namespace: "import-plugins" }, async () => {
|
build.onLoad({ filter, namespace: "import-plugins" }, async () => {
|
||||||
const pluginDirs = ["plugins/_api", "plugins/_core", "plugins", "userplugins"];
|
const pluginDirs = ["plugins/_api", "plugins/_core", "plugins", "userplugins"];
|
||||||
let code = "";
|
let code = "";
|
||||||
let plugins = "\n";
|
let pluginsCode = "\n";
|
||||||
|
let metaCode = "\n";
|
||||||
|
let excludedCode = "\n";
|
||||||
let i = 0;
|
let i = 0;
|
||||||
for (const dir of pluginDirs) {
|
for (const dir of pluginDirs) {
|
||||||
if (!await exists(`./src/${dir}`)) continue;
|
const userPlugin = dir === "userplugins";
|
||||||
const files = await readdir(`./src/${dir}`);
|
|
||||||
for (const file of files) {
|
const fullDir = `./src/${dir}`;
|
||||||
if (file.startsWith("_") || file.startsWith(".")) continue;
|
if (!await exists(fullDir)) continue;
|
||||||
if (file === "index.ts") continue;
|
const files = await readdir(fullDir, { withFileTypes: true });
|
||||||
|
for (const file of files) {
|
||||||
|
const fileName = file.name;
|
||||||
|
if (fileName.startsWith("_") || fileName.startsWith(".")) continue;
|
||||||
|
if (fileName === "index.ts") continue;
|
||||||
|
|
||||||
|
const target = getPluginTarget(fileName);
|
||||||
|
|
||||||
const target = getPluginTarget(file);
|
|
||||||
if (target && !IS_REPORTER) {
|
if (target && !IS_REPORTER) {
|
||||||
if (target === "dev" && !watch) continue;
|
const excluded =
|
||||||
if (target === "web" && kind === "discordDesktop") continue;
|
(target === "dev" && !IS_DEV) ||
|
||||||
if (target === "desktop" && kind === "web") continue;
|
(target === "web" && kind === "discordDesktop") ||
|
||||||
if (target === "discordDesktop" && kind !== "discordDesktop") continue;
|
(target === "desktop" && kind === "web") ||
|
||||||
if (target === "vencordDesktop" && kind !== "vencordDesktop") continue;
|
(target === "discordDesktop" && kind !== "discordDesktop") ||
|
||||||
|
(target === "vencordDesktop" && kind !== "vencordDesktop");
|
||||||
|
|
||||||
|
if (excluded) {
|
||||||
|
const name = await resolvePluginName(fullDir, file);
|
||||||
|
excludedCode += `${JSON.stringify(name)}:${JSON.stringify(target)},\n`;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const folderName = `src/${dir}/${fileName}`.replace(/^src\/plugins\//, "");
|
||||||
|
|
||||||
const mod = `p${i}`;
|
const mod = `p${i}`;
|
||||||
code += `import ${mod} from "./${dir}/${file.replace(/\.tsx?$/, "")}";\n`;
|
code += `import ${mod} from "./${dir}/${fileName.replace(/\.tsx?$/, "")}";\n`;
|
||||||
plugins += `[${mod}.name]:${mod},\n`;
|
pluginsCode += `[${mod}.name]:${mod},\n`;
|
||||||
|
metaCode += `[${mod}.name]:${JSON.stringify({ folderName, userPlugin })},\n`; // TODO: add excluded plugins to display in the UI?
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
code += `export default {${plugins}};`;
|
code += `export default {${pluginsCode}};export const PluginMeta={${metaCode}};export const ExcludedPlugins={${excludedCode}};`;
|
||||||
return {
|
return {
|
||||||
contents: code,
|
contents: code,
|
||||||
resolveDir: "./src"
|
resolveDir: "./src"
|
||||||
|
|
|
@ -39,7 +39,7 @@ interface PluginData {
|
||||||
hasCommands: boolean;
|
hasCommands: boolean;
|
||||||
required: boolean;
|
required: boolean;
|
||||||
enabledByDefault: boolean;
|
enabledByDefault: boolean;
|
||||||
target: "discordDesktop" | "vencordDesktop" | "web" | "dev";
|
target: "discordDesktop" | "vencordDesktop" | "desktop" | "web" | "dev";
|
||||||
filePath: string;
|
filePath: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -46,7 +46,8 @@ await page.setBypassCSP(true);
|
||||||
|
|
||||||
async function maybeGetError(handle: JSHandle): Promise<string | undefined> {
|
async function maybeGetError(handle: JSHandle): Promise<string | undefined> {
|
||||||
return await (handle as JSHandle<Error>)?.getProperty("message")
|
return await (handle as JSHandle<Error>)?.getProperty("message")
|
||||||
.then(m => m?.jsonValue());
|
.then(m => m?.jsonValue())
|
||||||
|
.catch(() => undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
const report = {
|
const report = {
|
||||||
|
|
|
@ -17,14 +17,14 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { mergeDefaults } from "@utils/mergeDefaults";
|
import { mergeDefaults } from "@utils/mergeDefaults";
|
||||||
import { findByProps } from "@webpack";
|
import { findByCode } from "@webpack";
|
||||||
import { MessageActions, SnowflakeUtils } from "@webpack/common";
|
import { MessageActions, SnowflakeUtils } from "@webpack/common";
|
||||||
import { Message } from "discord-types/general";
|
import { Message } from "discord-types/general";
|
||||||
import type { PartialDeep } from "type-fest";
|
import type { PartialDeep } from "type-fest";
|
||||||
|
|
||||||
import { Argument } from "./types";
|
import { Argument } from "./types";
|
||||||
|
|
||||||
const MessageCreator = findByProps("createBotMessage");
|
const createBotMessage = findByCode('username:"Clyde"');
|
||||||
|
|
||||||
export function generateId() {
|
export function generateId() {
|
||||||
return `-${SnowflakeUtils.fromTimestamp(Date.now())}`;
|
return `-${SnowflakeUtils.fromTimestamp(Date.now())}`;
|
||||||
|
@ -37,7 +37,7 @@ export function generateId() {
|
||||||
* @returns {Message}
|
* @returns {Message}
|
||||||
*/
|
*/
|
||||||
export function sendBotMessage(channelId: string, message: PartialDeep<Message>): Message {
|
export function sendBotMessage(channelId: string, message: PartialDeep<Message>): Message {
|
||||||
const botMessage = MessageCreator.createBotMessage({ channelId, content: "", embeds: [] });
|
const botMessage = createBotMessage({ channelId, content: "", embeds: [] });
|
||||||
|
|
||||||
MessageActions.receiveMessage(channelId, mergeDefaults(message, botMessage));
|
MessageActions.receiveMessage(channelId, mergeDefaults(message, botMessage));
|
||||||
|
|
||||||
|
|
77
src/api/UserSettingDefinitions.ts
Normal file
77
src/api/UserSettingDefinitions.ts
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
/*
|
||||||
|
* Vencord, a modification for Discord's desktop app
|
||||||
|
* Copyright (c) 2023 Vendicated and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { proxyLazy } from "@utils/lazy";
|
||||||
|
import { findByFactoryCode } from "@webpack";
|
||||||
|
|
||||||
|
import { Settings } from "./Settings";
|
||||||
|
|
||||||
|
interface UserSettingDefinition<T> {
|
||||||
|
/**
|
||||||
|
* Get the setting value
|
||||||
|
*/
|
||||||
|
getSetting(): T;
|
||||||
|
/**
|
||||||
|
* Update the setting value
|
||||||
|
* @param value The new value
|
||||||
|
*/
|
||||||
|
updateSetting(value: T): Promise<void>;
|
||||||
|
/**
|
||||||
|
* Update the setting value
|
||||||
|
* @param value A callback that accepts the old value as the first argument, and returns the new value
|
||||||
|
*/
|
||||||
|
updateSetting(value: (old: T) => T): Promise<void>;
|
||||||
|
/**
|
||||||
|
* Stateful React hook for this setting value
|
||||||
|
*/
|
||||||
|
useSetting(): T;
|
||||||
|
userSettingDefinitionsAPIGroup: string;
|
||||||
|
userSettingDefinitionsAPIName: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const UserSettingsDefinitions = findByFactoryCode<Record<PropertyKey, UserSettingDefinition<any>>>('"textAndImages","renderSpoilers"');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the definition for a setting.
|
||||||
|
*
|
||||||
|
* @param group The setting group
|
||||||
|
* @param name The name of the setting
|
||||||
|
*/
|
||||||
|
export function getUserSettingDefinition<T = any>(group: string, name: string): UserSettingDefinition<T> | undefined {
|
||||||
|
if (!Settings.plugins.UserSettingDefinitionsAPI.enabled) throw new Error("Cannot use UserSettingDefinitionsAPI without setting as dependency.");
|
||||||
|
|
||||||
|
for (const key in UserSettingsDefinitions) {
|
||||||
|
const userSettingDefinition = UserSettingsDefinitions[key];
|
||||||
|
|
||||||
|
if (userSettingDefinition.userSettingDefinitionsAPIGroup === group && userSettingDefinition.userSettingDefinitionsAPIName === name) {
|
||||||
|
return userSettingDefinition;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link getUserSettingDefinition}, lazy.
|
||||||
|
*
|
||||||
|
* Get the definition for a setting.
|
||||||
|
*
|
||||||
|
* @param group The setting group
|
||||||
|
* @param name The name of the setting
|
||||||
|
*/
|
||||||
|
export function getUserSettingDefinitionLazy<T = any>(group: string, name: string) {
|
||||||
|
return proxyLazy(() => getUserSettingDefinition<T>(group, name));
|
||||||
|
}
|
|
@ -32,6 +32,7 @@ import * as $Notifications from "./Notifications";
|
||||||
import * as $ServerList from "./ServerList";
|
import * as $ServerList from "./ServerList";
|
||||||
import * as $Settings from "./Settings";
|
import * as $Settings from "./Settings";
|
||||||
import * as $Styles from "./Styles";
|
import * as $Styles from "./Styles";
|
||||||
|
import * as $UserSettingDefinitions from "./UserSettingDefinitions";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An API allowing you to listen to Message Clicks or run your own logic
|
* An API allowing you to listen to Message Clicks or run your own logic
|
||||||
|
@ -116,3 +117,8 @@ export const ChatButtons = $ChatButtons;
|
||||||
* An API allowing you to update and re-render messages
|
* An API allowing you to update and re-render messages
|
||||||
*/
|
*/
|
||||||
export const MessageUpdater = $MessageUpdater;
|
export const MessageUpdater = $MessageUpdater;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An API allowing you to get the definition for an user setting
|
||||||
|
*/
|
||||||
|
export const UserSettingDefinitions = $UserSettingDefinitions;
|
||||||
|
|
|
@ -11,20 +11,16 @@ import { classNameFactory } from "@api/Styles";
|
||||||
import ErrorBoundary from "@components/ErrorBoundary";
|
import ErrorBoundary from "@components/ErrorBoundary";
|
||||||
import { Link } from "@components/Link";
|
import { Link } from "@components/Link";
|
||||||
import { DevsById } from "@utils/constants";
|
import { DevsById } from "@utils/constants";
|
||||||
import { fetchUserProfile, getTheme, Theme } from "@utils/discord";
|
import { fetchUserProfile } from "@utils/discord";
|
||||||
import { pluralise } from "@utils/misc";
|
import { classes, pluralise } from "@utils/misc";
|
||||||
import { ModalContent, ModalRoot, openModal } from "@utils/modal";
|
import { ModalContent, ModalRoot, openModal } from "@utils/modal";
|
||||||
import { Forms, MaskedLink, showToast, Tooltip, useEffect, useMemo, UserProfileStore, useStateFromStores } from "@webpack/common";
|
import { Forms, showToast, useEffect, useMemo, UserProfileStore, useStateFromStores } from "@webpack/common";
|
||||||
import { User } from "discord-types/general";
|
import { User } from "discord-types/general";
|
||||||
|
|
||||||
import Plugins from "~plugins";
|
import Plugins from "~plugins";
|
||||||
|
|
||||||
import { PluginCard } from ".";
|
import { PluginCard } from ".";
|
||||||
|
import { GithubButton, WebsiteButton } from "./LinkIconButton";
|
||||||
const WebsiteIconDark = "/assets/e1e96d89e192de1997f73730db26e94f.svg";
|
|
||||||
const WebsiteIconLight = "/assets/730f58bcfd5a57a5e22460c445a0c6cf.svg";
|
|
||||||
const GithubIconLight = "/assets/3ff98ad75ac94fa883af5ed62d17c459.svg";
|
|
||||||
const GithubIconDark = "/assets/6a853b4c87fce386cbfef4a2efbacb09.svg";
|
|
||||||
|
|
||||||
const cl = classNameFactory("vc-author-modal-");
|
const cl = classNameFactory("vc-author-modal-");
|
||||||
|
|
||||||
|
@ -40,16 +36,6 @@ export function openContributorModal(user: User) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function GithubIcon() {
|
|
||||||
const src = getTheme() === Theme.Light ? GithubIconLight : GithubIconDark;
|
|
||||||
return <img src={src} alt="GitHub" />;
|
|
||||||
}
|
|
||||||
|
|
||||||
function WebsiteIcon() {
|
|
||||||
const src = getTheme() === Theme.Light ? WebsiteIconLight : WebsiteIconDark;
|
|
||||||
return <img src={src} alt="Website" />;
|
|
||||||
}
|
|
||||||
|
|
||||||
function ContributorModal({ user }: { user: User; }) {
|
function ContributorModal({ user }: { user: User; }) {
|
||||||
useSettings();
|
useSettings();
|
||||||
|
|
||||||
|
@ -86,24 +72,18 @@ function ContributorModal({ user }: { user: User; }) {
|
||||||
/>
|
/>
|
||||||
<Forms.FormTitle tag="h2" className={cl("name")}>{user.username}</Forms.FormTitle>
|
<Forms.FormTitle tag="h2" className={cl("name")}>{user.username}</Forms.FormTitle>
|
||||||
|
|
||||||
<div className={cl("links")}>
|
<div className={classes("vc-settings-modal-links", cl("links"))}>
|
||||||
{website && (
|
{website && (
|
||||||
<Tooltip text={website}>
|
<WebsiteButton
|
||||||
{props => (
|
text={website}
|
||||||
<MaskedLink {...props} href={"https://" + website}>
|
href={`https://${website}`}
|
||||||
<WebsiteIcon />
|
/>
|
||||||
</MaskedLink>
|
|
||||||
)}
|
|
||||||
</Tooltip>
|
|
||||||
)}
|
)}
|
||||||
{githubName && (
|
{githubName && (
|
||||||
<Tooltip text={githubName}>
|
<GithubButton
|
||||||
{props => (
|
text={githubName}
|
||||||
<MaskedLink {...props} href={`https://github.com/${githubName}`}>
|
href={`https://github.com/${githubName}`}
|
||||||
<GithubIcon />
|
/>
|
||||||
</MaskedLink>
|
|
||||||
)}
|
|
||||||
</Tooltip>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
12
src/components/PluginSettings/LinkIconButton.css
Normal file
12
src/components/PluginSettings/LinkIconButton.css
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
.vc-settings-modal-link-icon {
|
||||||
|
height: 32px;
|
||||||
|
width: 32px;
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 4px solid var(--background-tertiary);
|
||||||
|
box-sizing: border-box
|
||||||
|
}
|
||||||
|
|
||||||
|
.vc-settings-modal-links {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.2em;
|
||||||
|
}
|
45
src/components/PluginSettings/LinkIconButton.tsx
Normal file
45
src/components/PluginSettings/LinkIconButton.tsx
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
/*
|
||||||
|
* Vencord, a Discord client mod
|
||||||
|
* Copyright (c) 2024 Vendicated and contributors
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
import "./LinkIconButton.css";
|
||||||
|
|
||||||
|
import { getTheme, Theme } from "@utils/discord";
|
||||||
|
import { MaskedLink, Tooltip } from "@webpack/common";
|
||||||
|
|
||||||
|
const WebsiteIconDark = "/assets/e1e96d89e192de1997f73730db26e94f.svg";
|
||||||
|
const WebsiteIconLight = "/assets/730f58bcfd5a57a5e22460c445a0c6cf.svg";
|
||||||
|
const GithubIconLight = "/assets/3ff98ad75ac94fa883af5ed62d17c459.svg";
|
||||||
|
const GithubIconDark = "/assets/6a853b4c87fce386cbfef4a2efbacb09.svg";
|
||||||
|
|
||||||
|
export function GithubIcon() {
|
||||||
|
const src = getTheme() === Theme.Light ? GithubIconLight : GithubIconDark;
|
||||||
|
return <img src={src} aria-hidden className={"vc-settings-modal-link-icon"} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function WebsiteIcon() {
|
||||||
|
const src = getTheme() === Theme.Light ? WebsiteIconLight : WebsiteIconDark;
|
||||||
|
return <img src={src} aria-hidden className={"vc-settings-modal-link-icon"} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
text: string;
|
||||||
|
href: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
function LinkIcon({ text, href, Icon }: Props & { Icon: React.ComponentType; }) {
|
||||||
|
return (
|
||||||
|
<Tooltip text={text}>
|
||||||
|
{props => (
|
||||||
|
<MaskedLink {...props} href={href}>
|
||||||
|
<Icon />
|
||||||
|
</MaskedLink>
|
||||||
|
)}
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const WebsiteButton = (props: Props) => <LinkIcon {...props} Icon={WebsiteIcon} />;
|
||||||
|
export const GithubButton = (props: Props) => <LinkIcon {...props} Icon={GithubIcon} />;
|
7
src/components/PluginSettings/PluginModal.css
Normal file
7
src/components/PluginSettings/PluginModal.css
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
.vc-plugin-modal-info {
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vc-plugin-modal-description {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
|
@ -16,10 +16,14 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import "./PluginModal.css";
|
||||||
|
|
||||||
import { generateId } from "@api/Commands";
|
import { generateId } from "@api/Commands";
|
||||||
import { useSettings } from "@api/Settings";
|
import { useSettings } from "@api/Settings";
|
||||||
|
import { classNameFactory } from "@api/Styles";
|
||||||
import ErrorBoundary from "@components/ErrorBoundary";
|
import ErrorBoundary from "@components/ErrorBoundary";
|
||||||
import { Flex } from "@components/Flex";
|
import { Flex } from "@components/Flex";
|
||||||
|
import { gitRemote } from "@shared/vencordUserAgent";
|
||||||
import { proxyLazy } from "@utils/lazy";
|
import { proxyLazy } from "@utils/lazy";
|
||||||
import { Margins } from "@utils/margins";
|
import { Margins } from "@utils/margins";
|
||||||
import { classes, isObjectEmpty } from "@utils/misc";
|
import { classes, isObjectEmpty } from "@utils/misc";
|
||||||
|
@ -30,6 +34,8 @@ import { Button, Clickable, FluxDispatcher, Forms, React, Text, Tooltip, UserSto
|
||||||
import { User } from "discord-types/general";
|
import { User } from "discord-types/general";
|
||||||
import { Constructor } from "type-fest";
|
import { Constructor } from "type-fest";
|
||||||
|
|
||||||
|
import { PluginMeta } from "~plugins";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ISettingElementProps,
|
ISettingElementProps,
|
||||||
SettingBooleanComponent,
|
SettingBooleanComponent,
|
||||||
|
@ -40,6 +46,9 @@ import {
|
||||||
SettingTextComponent
|
SettingTextComponent
|
||||||
} from "./components";
|
} from "./components";
|
||||||
import { openContributorModal } from "./ContributorModal";
|
import { openContributorModal } from "./ContributorModal";
|
||||||
|
import { GithubButton, WebsiteButton } from "./LinkIconButton";
|
||||||
|
|
||||||
|
const cl = classNameFactory("vc-plugin-modal-");
|
||||||
|
|
||||||
const UserSummaryItem = findComponentByCode("defaultRenderUser", "showDefaultAvatarsForNullUsers");
|
const UserSummaryItem = findComponentByCode("defaultRenderUser", "showDefaultAvatarsForNullUsers");
|
||||||
const AvatarStyles = findByProps("moreUsers", "emptyUser", "avatarContainer", "clickableAvatar");
|
const AvatarStyles = findByProps("moreUsers", "emptyUser", "avatarContainer", "clickableAvatar");
|
||||||
|
@ -180,16 +189,54 @@ export default function PluginModal({ plugin, onRestartNeeded, onClose, transiti
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
function switchToPopout() {
|
||||||
|
onClose();
|
||||||
|
|
||||||
|
const PopoutKey = `DISCORD_VENCORD_PLUGIN_SETTINGS_MODAL_${plugin.name}`;
|
||||||
|
PopoutActions.open(
|
||||||
|
PopoutKey,
|
||||||
|
() => <PluginModal
|
||||||
|
transitionState={transitionState}
|
||||||
|
plugin={plugin}
|
||||||
|
onRestartNeeded={onRestartNeeded}
|
||||||
|
onClose={() => PopoutActions.close(PopoutKey)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
const pluginMeta = PluginMeta[plugin.name];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ModalRoot transitionState={transitionState} size={ModalSize.MEDIUM} className="vc-text-selectable">
|
<ModalRoot transitionState={transitionState} size={ModalSize.MEDIUM} className="vc-text-selectable">
|
||||||
<ModalHeader separator={false}>
|
<ModalHeader separator={false}>
|
||||||
<Text variant="heading-lg/semibold" style={{ flexGrow: 1 }}>{plugin.name}</Text>
|
<Text variant="heading-lg/semibold" style={{ flexGrow: 1 }}>{plugin.name}</Text>
|
||||||
|
|
||||||
|
{/*
|
||||||
|
<Button look={Button.Looks.BLANK} onClick={switchToPopout}>
|
||||||
|
<OpenExternalIcon aria-label="Open in Popout" />
|
||||||
|
</Button>
|
||||||
|
*/}
|
||||||
<ModalCloseButton onClick={onClose} />
|
<ModalCloseButton onClick={onClose} />
|
||||||
</ModalHeader>
|
</ModalHeader>
|
||||||
<ModalContent>
|
<ModalContent>
|
||||||
<Forms.FormSection>
|
<Forms.FormSection>
|
||||||
<Forms.FormTitle tag="h3">About {plugin.name}</Forms.FormTitle>
|
<Flex className={cl("info")}>
|
||||||
<Forms.FormText>{plugin.description}</Forms.FormText>
|
<Forms.FormText className={cl("description")}>{plugin.description}</Forms.FormText>
|
||||||
|
{!pluginMeta.userPlugin && (
|
||||||
|
<div className="vc-settings-modal-links">
|
||||||
|
<WebsiteButton
|
||||||
|
text="View more info"
|
||||||
|
href={`https://vencord.dev/plugins/${plugin.name}`}
|
||||||
|
/>
|
||||||
|
<GithubButton
|
||||||
|
text="View source code"
|
||||||
|
href={`https://github.com/${gitRemote}/tree/main/src/plugins/${pluginMeta.folderName}`}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</Flex>
|
||||||
<Forms.FormTitle tag="h3" style={{ marginTop: 8, marginBottom: 0 }}>Authors</Forms.FormTitle>
|
<Forms.FormTitle tag="h3" style={{ marginTop: 8, marginBottom: 0 }}>Authors</Forms.FormTitle>
|
||||||
<div style={{ width: "fit-content", marginBottom: 8 }}>
|
<div style={{ width: "fit-content", marginBottom: 8 }}>
|
||||||
<UserSummaryItem
|
<UserSummaryItem
|
||||||
|
|
|
@ -42,16 +42,6 @@
|
||||||
|
|
||||||
.vc-author-modal-links {
|
.vc-author-modal-links {
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
display: flex;
|
|
||||||
gap: 0.2em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vc-author-modal-links img {
|
|
||||||
height: 32px;
|
|
||||||
width: 32px;
|
|
||||||
border-radius: 50%;
|
|
||||||
border: 4px solid var(--background-tertiary);
|
|
||||||
box-sizing: border-box
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.vc-author-modal-plugins {
|
.vc-author-modal-plugins {
|
||||||
|
|
|
@ -35,9 +35,9 @@ import { openModalLazy } from "@utils/modal";
|
||||||
import { useAwaiter } from "@utils/react";
|
import { useAwaiter } from "@utils/react";
|
||||||
import { Plugin } from "@utils/types";
|
import { Plugin } from "@utils/types";
|
||||||
import { findByProps } from "@webpack";
|
import { findByProps } from "@webpack";
|
||||||
import { Alerts, Button, Card, Forms, lodash, Parser, React, Select, Text, TextInput, Toasts, Tooltip } from "@webpack/common";
|
import { Alerts, Button, Card, Forms, lodash, Parser, React, Select, Text, TextInput, Toasts, Tooltip, useMemo } from "@webpack/common";
|
||||||
|
|
||||||
import Plugins from "~plugins";
|
import Plugins, { ExcludedPlugins } from "~plugins";
|
||||||
|
|
||||||
// Avoid circular dependency
|
// Avoid circular dependency
|
||||||
const { startDependenciesRecursive, startPlugin, stopPlugin } = proxyLazy(() => require("../../plugins")) as typeof import("../../plugins");
|
const { startDependenciesRecursive, startPlugin, stopPlugin } = proxyLazy(() => require("../../plugins")) as typeof import("../../plugins");
|
||||||
|
@ -177,6 +177,37 @@ const enum SearchStatus {
|
||||||
NEW
|
NEW
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function ExcludedPluginsList({ search }: { search: string; }) {
|
||||||
|
const matchingExcludedPlugins = Object.entries(ExcludedPlugins)
|
||||||
|
.filter(([name]) => name.toLowerCase().includes(search));
|
||||||
|
|
||||||
|
const ExcludedReasons: Record<"web" | "discordDesktop" | "vencordDesktop" | "desktop" | "dev", string> = {
|
||||||
|
desktop: "Discord Desktop app or Vesktop",
|
||||||
|
discordDesktop: "Discord Desktop app",
|
||||||
|
vencordDesktop: "Vesktop app",
|
||||||
|
web: "Vesktop app and the Web version of Discord",
|
||||||
|
dev: "Developer version of Vencord"
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Text variant="text-md/normal" className={Margins.top16}>
|
||||||
|
{matchingExcludedPlugins.length
|
||||||
|
? <>
|
||||||
|
<Forms.FormText>Are you looking for:</Forms.FormText>
|
||||||
|
<ul>
|
||||||
|
{matchingExcludedPlugins.map(([name, reason]) => (
|
||||||
|
<li key={name}>
|
||||||
|
<b>{name}</b>: Only available on the {ExcludedReasons[reason]}
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</>
|
||||||
|
: "No plugins meet the search criteria."
|
||||||
|
}
|
||||||
|
</Text>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export default function PluginSettings() {
|
export default function PluginSettings() {
|
||||||
const settings = useSettings();
|
const settings = useSettings();
|
||||||
const changes = React.useMemo(() => new ChangeList<string>(), []);
|
const changes = React.useMemo(() => new ChangeList<string>(), []);
|
||||||
|
@ -215,26 +246,27 @@ export default function PluginSettings() {
|
||||||
return o;
|
return o;
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const sortedPlugins = React.useMemo(() => Object.values(Plugins)
|
const sortedPlugins = useMemo(() => Object.values(Plugins)
|
||||||
.sort((a, b) => a.name.localeCompare(b.name)), []);
|
.sort((a, b) => a.name.localeCompare(b.name)), []);
|
||||||
|
|
||||||
const [searchValue, setSearchValue] = React.useState({ value: "", status: SearchStatus.ALL });
|
const [searchValue, setSearchValue] = React.useState({ value: "", status: SearchStatus.ALL });
|
||||||
|
|
||||||
|
const search = searchValue.value.toLowerCase();
|
||||||
const onSearch = (query: string) => setSearchValue(prev => ({ ...prev, value: query }));
|
const onSearch = (query: string) => setSearchValue(prev => ({ ...prev, value: query }));
|
||||||
const onStatusChange = (status: SearchStatus) => setSearchValue(prev => ({ ...prev, status }));
|
const onStatusChange = (status: SearchStatus) => setSearchValue(prev => ({ ...prev, status }));
|
||||||
|
|
||||||
const pluginFilter = (plugin: typeof Plugins[keyof typeof Plugins]) => {
|
const pluginFilter = (plugin: typeof Plugins[keyof typeof Plugins]) => {
|
||||||
const enabled = settings.plugins[plugin.name]?.enabled;
|
const { status } = searchValue;
|
||||||
if (enabled && searchValue.status === SearchStatus.DISABLED) return false;
|
const enabled = Vencord.Plugins.isPluginEnabled(plugin.name);
|
||||||
if (!enabled && searchValue.status === SearchStatus.ENABLED) return false;
|
if (enabled && status === SearchStatus.DISABLED) return false;
|
||||||
if (searchValue.status === SearchStatus.NEW && !newPlugins?.includes(plugin.name)) return false;
|
if (!enabled && status === SearchStatus.ENABLED) return false;
|
||||||
if (!searchValue.value.length) return true;
|
if (status === SearchStatus.NEW && !newPlugins?.includes(plugin.name)) return false;
|
||||||
|
if (!search.length) return true;
|
||||||
|
|
||||||
const v = searchValue.value.toLowerCase();
|
|
||||||
return (
|
return (
|
||||||
plugin.name.toLowerCase().includes(v) ||
|
plugin.name.toLowerCase().includes(search) ||
|
||||||
plugin.description.toLowerCase().includes(v) ||
|
plugin.description.toLowerCase().includes(search) ||
|
||||||
plugin.tags?.some(t => t.toLowerCase().includes(v))
|
plugin.tags?.some(t => t.toLowerCase().includes(search))
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -255,54 +287,48 @@ export default function PluginSettings() {
|
||||||
return lodash.isEqual(newPlugins, sortedPluginNames) ? [] : newPlugins;
|
return lodash.isEqual(newPlugins, sortedPluginNames) ? [] : newPlugins;
|
||||||
}));
|
}));
|
||||||
|
|
||||||
type P = JSX.Element | JSX.Element[];
|
const plugins = [] as JSX.Element[];
|
||||||
let plugins: P, requiredPlugins: P;
|
const requiredPlugins = [] as JSX.Element[];
|
||||||
if (sortedPlugins?.length) {
|
|
||||||
plugins = [];
|
|
||||||
requiredPlugins = [];
|
|
||||||
|
|
||||||
const showApi = searchValue.value === "API";
|
const showApi = searchValue.value.includes("API");
|
||||||
for (const p of sortedPlugins) {
|
for (const p of sortedPlugins) {
|
||||||
if (p.hidden || (!p.options && p.name.endsWith("API") && !showApi))
|
if (p.hidden || (!p.options && p.name.endsWith("API") && !showApi))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!pluginFilter(p)) continue;
|
if (!pluginFilter(p)) continue;
|
||||||
|
|
||||||
const isRequired = p.required || depMap[p.name]?.some(d => settings.plugins[d].enabled);
|
const isRequired = p.required || depMap[p.name]?.some(d => settings.plugins[d].enabled);
|
||||||
|
|
||||||
if (isRequired) {
|
if (isRequired) {
|
||||||
const tooltipText = p.required
|
const tooltipText = p.required
|
||||||
? "This plugin is required for Vencord to function."
|
? "This plugin is required for Vencord to function."
|
||||||
: makeDependencyList(depMap[p.name]?.filter(d => settings.plugins[d].enabled));
|
: makeDependencyList(depMap[p.name]?.filter(d => settings.plugins[d].enabled));
|
||||||
|
|
||||||
requiredPlugins.push(
|
|
||||||
<Tooltip text={tooltipText} key={p.name}>
|
|
||||||
{({ onMouseLeave, onMouseEnter }) => (
|
|
||||||
<PluginCard
|
|
||||||
onMouseLeave={onMouseLeave}
|
|
||||||
onMouseEnter={onMouseEnter}
|
|
||||||
onRestartNeeded={name => changes.handleChange(name)}
|
|
||||||
disabled={true}
|
|
||||||
plugin={p}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</Tooltip>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
plugins.push(
|
|
||||||
<PluginCard
|
|
||||||
onRestartNeeded={name => changes.handleChange(name)}
|
|
||||||
disabled={false}
|
|
||||||
plugin={p}
|
|
||||||
isNew={newPlugins?.includes(p.name)}
|
|
||||||
key={p.name}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
requiredPlugins.push(
|
||||||
|
<Tooltip text={tooltipText} key={p.name}>
|
||||||
|
{({ onMouseLeave, onMouseEnter }) => (
|
||||||
|
<PluginCard
|
||||||
|
onMouseLeave={onMouseLeave}
|
||||||
|
onMouseEnter={onMouseEnter}
|
||||||
|
onRestartNeeded={name => changes.handleChange(name)}
|
||||||
|
disabled={true}
|
||||||
|
plugin={p}
|
||||||
|
key={p.name}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
plugins.push(
|
||||||
|
<PluginCard
|
||||||
|
onRestartNeeded={name => changes.handleChange(name)}
|
||||||
|
disabled={false}
|
||||||
|
plugin={p}
|
||||||
|
isNew={newPlugins?.includes(p.name)}
|
||||||
|
key={p.name}
|
||||||
|
/>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
plugins = requiredPlugins = <Text variant="text-md/normal">No plugins meet search criteria.</Text>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -333,9 +359,18 @@ export default function PluginSettings() {
|
||||||
|
|
||||||
<Forms.FormTitle className={Margins.top20}>Plugins</Forms.FormTitle>
|
<Forms.FormTitle className={Margins.top20}>Plugins</Forms.FormTitle>
|
||||||
|
|
||||||
<div className={cl("grid")}>
|
{plugins.length || requiredPlugins.length
|
||||||
{plugins}
|
? (
|
||||||
</div>
|
<div className={cl("grid")}>
|
||||||
|
{plugins.length
|
||||||
|
? plugins
|
||||||
|
: <Text variant="text-md/normal">No plugins meet the search criteria.</Text>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
: <ExcludedPluginsList search={search} />
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
<Forms.FormDivider className={Margins.top20} />
|
<Forms.FormDivider className={Margins.top20} />
|
||||||
|
|
||||||
|
@ -343,7 +378,10 @@ export default function PluginSettings() {
|
||||||
Required Plugins
|
Required Plugins
|
||||||
</Forms.FormTitle>
|
</Forms.FormTitle>
|
||||||
<div className={cl("grid")}>
|
<div className={cl("grid")}>
|
||||||
{requiredPlugins}
|
{requiredPlugins.length
|
||||||
|
? requiredPlugins
|
||||||
|
: <Text variant="text-md/normal">No plugins meet the search criteria.</Text>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
</SettingsTab >
|
</SettingsTab >
|
||||||
);
|
);
|
||||||
|
|
|
@ -25,7 +25,7 @@ export async function loadLazyChunks() {
|
||||||
// True if resolved, false otherwise
|
// True if resolved, false otherwise
|
||||||
const chunksSearchPromises = [] as Array<() => boolean>;
|
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\.bind\(\i,"?([^)]+?)"?\)\)/g);
|
||||||
|
|
||||||
async function searchAndLoadLazyChunks(factoryCode: string) {
|
async function searchAndLoadLazyChunks(factoryCode: string) {
|
||||||
const lazyChunks = factoryCode.matchAll(LazyChunkRegex);
|
const lazyChunks = factoryCode.matchAll(LazyChunkRegex);
|
||||||
|
|
|
@ -33,6 +33,7 @@ async function runReporter() {
|
||||||
await Promise.all(Webpack.webpackSearchHistory.map(async ([searchType, args]) => {
|
await Promise.all(Webpack.webpackSearchHistory.map(async ([searchType, args]) => {
|
||||||
args = [...args];
|
args = [...args];
|
||||||
|
|
||||||
|
let result: any;
|
||||||
try {
|
try {
|
||||||
let result = null as any;
|
let result = null as any;
|
||||||
|
|
||||||
|
@ -45,11 +46,12 @@ async function runReporter() {
|
||||||
}
|
}
|
||||||
case "extractAndLoadChunks": {
|
case "extractAndLoadChunks": {
|
||||||
const [code, matcher] = args;
|
const [code, matcher] = args;
|
||||||
|
result = true;
|
||||||
|
|
||||||
result = await Webpack.extractAndLoadChunks(code, matcher);
|
/* result = await Webpack.extractAndLoadChunks(code, matcher);
|
||||||
if (result === false) {
|
if (result === false) {
|
||||||
result = null;
|
result = null;
|
||||||
}
|
} */
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
5
src/modules.d.ts
vendored
5
src/modules.d.ts
vendored
|
@ -22,6 +22,11 @@
|
||||||
declare module "~plugins" {
|
declare module "~plugins" {
|
||||||
const plugins: Record<string, import("./utils/types").Plugin>;
|
const plugins: Record<string, import("./utils/types").Plugin>;
|
||||||
export default plugins;
|
export default plugins;
|
||||||
|
export const PluginMeta: Record<string, {
|
||||||
|
folderName: string;
|
||||||
|
userPlugin: boolean;
|
||||||
|
}>;
|
||||||
|
export const ExcludedPlugins: Record<string, "web" | "discordDesktop" | "vencordDesktop" | "desktop" | "dev">;
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module "~pluginNatives" {
|
declare module "~pluginNatives" {
|
||||||
|
|
|
@ -93,7 +93,7 @@ export default definePlugin({
|
||||||
{
|
{
|
||||||
find: ".PANEL]:14",
|
find: ".PANEL]:14",
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /(?<=(\i)=\(0,\i\.default\)\(\i\);)return 0===\i.length\?/,
|
match: /(?<=(\i)=\(0,\i\.\i\)\(\i\);)return 0===\i.length\?/,
|
||||||
replace: "$1.unshift(...$self.getBadges(arguments[0].displayProfile));$&"
|
replace: "$1.unshift(...$self.getBadges(arguments[0].displayProfile));$&"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -15,8 +15,8 @@ export default definePlugin({
|
||||||
patches: [{
|
patches: [{
|
||||||
find: '"sticker")',
|
find: '"sticker")',
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /!\i\.isMobile(?=.+?(\i)\.push\(.{0,50}"gift")/,
|
match: /return\(!\i\.\i&&(?=\(\i\.isDM.+?(\i)\.push\(.{0,50}"gift")/,
|
||||||
replace: "$& &&(Vencord.Api.ChatButtons._injectButtons($1,arguments[0]),true)"
|
replace: "$&(Vencord.Api.ChatButtons._injectButtons($1,arguments[0]),true)&&"
|
||||||
}
|
}
|
||||||
}]
|
}]
|
||||||
});
|
});
|
||||||
|
|
|
@ -35,7 +35,7 @@ export default definePlugin({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
find: ".handleSendMessage",
|
find: ".handleSendMessage,onResize",
|
||||||
replacement: {
|
replacement: {
|
||||||
// props.chatInputType...then((function(isMessageValid)... var parsedMessage = b.c.parse(channel,... var replyOptions = f.g.getSendMessageOptionsForReply(pendingReply);
|
// props.chatInputType...then((function(isMessageValid)... var parsedMessage = b.c.parse(channel,... var replyOptions = f.g.getSendMessageOptionsForReply(pendingReply);
|
||||||
// Lookbehind: validateMessage)({openWarningPopout:..., type: i.props.chatInputType, content: t, stickers: r, ...}).then((function(isMessageValid)
|
// Lookbehind: validateMessage)({openWarningPopout:..., type: i.props.chatInputType, content: t, stickers: r, ...}).then((function(isMessageValid)
|
||||||
|
|
50
src/plugins/_api/userSettingsDefinitions.ts
Normal file
50
src/plugins/_api/userSettingsDefinitions.ts
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
* Vencord, a modification for Discord's desktop app
|
||||||
|
* Copyright (c) 2022 Vendicated and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Devs } from "@utils/constants";
|
||||||
|
import definePlugin from "@utils/types";
|
||||||
|
|
||||||
|
export default definePlugin({
|
||||||
|
name: "UserSettingDefinitionsAPI",
|
||||||
|
description: "Patches Discord's UserSettingDefinitions to expose their group and name.",
|
||||||
|
authors: [Devs.Nuckyz],
|
||||||
|
|
||||||
|
patches: [
|
||||||
|
{
|
||||||
|
find: ",updateSetting:",
|
||||||
|
replacement: [
|
||||||
|
// Main setting definition
|
||||||
|
{
|
||||||
|
match: /(?<=INFREQUENT_USER_ACTION.{0,20},)useSetting:/,
|
||||||
|
replace: "userSettingDefinitionsAPIGroup:arguments[0],userSettingDefinitionsAPIName:arguments[1],$&"
|
||||||
|
},
|
||||||
|
// Selective wrapper
|
||||||
|
{
|
||||||
|
match: /updateSetting:.{0,100}SELECTIVELY_SYNCED_USER_SETTINGS_UPDATE/,
|
||||||
|
replace: "userSettingDefinitionsAPIGroup:arguments[0].userSettingDefinitionsAPIGroup,userSettingDefinitionsAPIName:arguments[0].userSettingDefinitionsAPIName,$&"
|
||||||
|
},
|
||||||
|
// Override wrapper
|
||||||
|
{
|
||||||
|
match: /updateSetting:.{0,60}USER_SETTINGS_OVERRIDE_CLEAR/,
|
||||||
|
replace: "userSettingDefinitionsAPIGroup:arguments[0].userSettingDefinitionsAPIGroup,userSettingDefinitionsAPIName:arguments[0].userSettingDefinitionsAPIName,$&"
|
||||||
|
}
|
||||||
|
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
|
@ -72,46 +72,24 @@ export default definePlugin({
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
// Discord Stable
|
|
||||||
// FIXME: remove once change merged to stable
|
|
||||||
{
|
{
|
||||||
find: "Messages.ACTIVITY_SETTINGS",
|
find: "Messages.ACTIVITY_SETTINGS",
|
||||||
noWarn: true,
|
replacement: [
|
||||||
replacement: {
|
{
|
||||||
get match() {
|
match: /(?<=section:(.{0,50})\.DIVIDER\}\))([,;])(?=.{0,200}(\i)\.push.{0,100}label:(\i)\.header)/,
|
||||||
switch (settings.store.settingsLocation) {
|
replace: (_, sectionTypes, commaOrSemi, elements, element) => `${commaOrSemi} $self.addSettings(${elements}, ${element}, ${sectionTypes}) ${commaOrSemi}`
|
||||||
case "top": return /\{section:(\i\.\i)\.HEADER,\s*label:(\i)\.\i\.Messages\.USER_SETTINGS/;
|
|
||||||
case "aboveNitro": return /\{section:(\i\.\i)\.HEADER,\s*label:(\i)\.\i\.Messages\.BILLING_SETTINGS/;
|
|
||||||
case "belowNitro": return /\{section:(\i\.\i)\.HEADER,\s*label:(\i)\.\i\.Messages\.APP_SETTINGS/;
|
|
||||||
case "belowActivity": return /(?<=\{section:(\i\.\i)\.DIVIDER},)\{section:"changelog"/;
|
|
||||||
case "bottom": return /\{section:(\i\.\i)\.CUSTOM,\s*element:.+?}/;
|
|
||||||
case "aboveActivity":
|
|
||||||
default:
|
|
||||||
return /\{section:(\i\.\i)\.HEADER,\s*label:(\i)\.\i\.Messages\.ACTIVITY_SETTINGS/;
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
replace: "...$self.makeSettingsCategories($1),$&"
|
{
|
||||||
}
|
match: /({(?=.+?function (\i).{0,120}(\i)=\i\.useMemo.{0,30}return \i\.useMemo\(\(\)=>\i\(\3).+?function\(\){return )\2(?=})/,
|
||||||
},
|
replace: (_, rest, settingsHook) => `${rest}$self.wrapSettingsHook(${settingsHook})`
|
||||||
{
|
}
|
||||||
find: "Messages.ACTIVITY_SETTINGS",
|
]
|
||||||
replacement: {
|
|
||||||
match: /(?<=section:(.{0,50})\.DIVIDER\}\))([,;])(?=.{0,200}(\i)\.push.{0,100}label:(\i)\.header)/,
|
|
||||||
replace: (_, sectionTypes, commaOrSemi, elements, element) => `${commaOrSemi} $self.addSettings(${elements}, ${element}, ${sectionTypes}) ${commaOrSemi}`
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
find: "useDefaultUserSettingsSections:function",
|
|
||||||
replacement: {
|
|
||||||
match: /(?<=useDefaultUserSettingsSections:function\(\){return )(\i)\}/,
|
|
||||||
replace: "$self.wrapSettingsHook($1)}"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
find: "Messages.USER_SETTINGS_ACTIONS_MENU_LABEL",
|
find: "Messages.USER_SETTINGS_ACTIONS_MENU_LABEL",
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /(?<=function\((\i),\i\)\{)(?=let \i=Object.values\(\i.UserSettingsSections\).*?(\i)\.default\.open\()/,
|
match: /(?<=function\((\i),\i\)\{)(?=let \i=Object.values\(\i.\i\).*?(\i\.\i)\.open\()/,
|
||||||
replace: "$2.default.open($1);return;"
|
replace: "$2.open($1);return;"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
@ -198,7 +176,7 @@ export default definePlugin({
|
||||||
patchedSettings: new WeakSet(),
|
patchedSettings: new WeakSet(),
|
||||||
|
|
||||||
addSettings(elements: any[], element: { header?: string; settings: string[]; }, sectionTypes: SectionTypes) {
|
addSettings(elements: any[], element: { header?: string; settings: string[]; }, sectionTypes: SectionTypes) {
|
||||||
if (this.patchedSettings.has(elements)) return;
|
if (this.patchedSettings.has(elements) || !this.isRightSpot(element)) return;
|
||||||
|
|
||||||
this.patchedSettings.add(elements);
|
this.patchedSettings.add(elements);
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,7 @@ export default definePlugin({
|
||||||
predicate: () => settings.store.domain
|
predicate: () => settings.store.domain
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
find: "isSuspiciousDownload:",
|
find: "bitbucket.org",
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /function \i\(\i\){(?=.{0,60}\.parse\(\i\))/,
|
match: /function \i\(\i\){(?=.{0,60}\.parse\(\i\))/,
|
||||||
replace: "$&return null;"
|
replace: "$&return null;"
|
||||||
|
|
|
@ -9,7 +9,7 @@ import { Devs } from "@utils/constants";
|
||||||
import definePlugin, { OptionType, PluginNative, ReporterTestable } from "@utils/types";
|
import definePlugin, { OptionType, PluginNative, ReporterTestable } from "@utils/types";
|
||||||
import { ApplicationAssetUtils, FluxDispatcher, Forms } from "@webpack/common";
|
import { ApplicationAssetUtils, FluxDispatcher, Forms } from "@webpack/common";
|
||||||
|
|
||||||
const Native = VencordNative.pluginHelpers.AppleMusic as PluginNative<typeof import("./native")>;
|
const Native = VencordNative.pluginHelpers.AppleMusicRichPresence as PluginNative<typeof import("./native")>;
|
||||||
|
|
||||||
interface ActivityAssets {
|
interface ActivityAssets {
|
||||||
large_image?: string;
|
large_image?: string;
|
||||||
|
|
|
@ -20,10 +20,10 @@ import { popNotice, showNotice } from "@api/Notices";
|
||||||
import { Link } from "@components/Link";
|
import { Link } from "@components/Link";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
import definePlugin, { ReporterTestable } from "@utils/types";
|
import definePlugin, { ReporterTestable } from "@utils/types";
|
||||||
import { findByProps } from "@webpack";
|
import { findByCode } from "@webpack";
|
||||||
import { ApplicationAssetUtils, FluxDispatcher, Forms, Toasts } from "@webpack/common";
|
import { ApplicationAssetUtils, FluxDispatcher, Forms, Toasts } from "@webpack/common";
|
||||||
|
|
||||||
const RpcUtils = findByProps("fetchApplicationsRPC", "getRemoteIconURL");
|
const fetchApplicationsRPC = findByCode("APPLICATION_RPC(", "Client ID");
|
||||||
|
|
||||||
async function lookupAsset(applicationId: string, key: string): Promise<string> {
|
async function lookupAsset(applicationId: string, key: string): Promise<string> {
|
||||||
return (await ApplicationAssetUtils.fetchAssetIds(applicationId, [key]))[0];
|
return (await ApplicationAssetUtils.fetchAssetIds(applicationId, [key]))[0];
|
||||||
|
@ -32,7 +32,7 @@ async function lookupAsset(applicationId: string, key: string): Promise<string>
|
||||||
const apps: any = {};
|
const apps: any = {};
|
||||||
async function lookupApp(applicationId: string): Promise<string> {
|
async function lookupApp(applicationId: string): Promise<string> {
|
||||||
const socket: any = {};
|
const socket: any = {};
|
||||||
await RpcUtils.fetchApplicationsRPC(socket, applicationId);
|
await fetchApplicationsRPC(socket, applicationId);
|
||||||
return socket.application;
|
return socket.application;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,8 +28,8 @@ export default definePlugin({
|
||||||
{
|
{
|
||||||
find: "BAN_CONFIRM_TITLE.",
|
find: "BAN_CONFIRM_TITLE.",
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /src:\i\("\d+"\)/g,
|
match: /src:\i\("?\d+"?\)/g,
|
||||||
replace: "src: $self.settings.store.source"
|
replace: "src: Vencord.Settings.plugins.BANger.source"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
import { definePluginSettings } from "@api/Settings";
|
import { definePluginSettings } from "@api/Settings";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
import definePlugin, { OptionType } from "@utils/types";
|
import definePlugin, { OptionType } from "@utils/types";
|
||||||
import { findByProps, findStore } from "@webpack";
|
import { find, findByProps, findStore } from "@webpack";
|
||||||
import { FluxDispatcher, i18n, useMemo } from "@webpack/common";
|
import { FluxDispatcher, i18n, useMemo } from "@webpack/common";
|
||||||
|
|
||||||
import FolderSideBar from "./FolderSideBar";
|
import FolderSideBar from "./FolderSideBar";
|
||||||
|
@ -30,7 +30,7 @@ enum FolderIconDisplay {
|
||||||
MoreThanOneFolderExpanded
|
MoreThanOneFolderExpanded
|
||||||
}
|
}
|
||||||
|
|
||||||
const { GuildsTree } = findByProps("GuildsTree");
|
const GuildsTree = find(m => m.prototype?.moveNextTo);
|
||||||
const SortedGuildStore = findStore("SortedGuildStore");
|
const SortedGuildStore = findStore("SortedGuildStore");
|
||||||
export const ExpandedGuildFolderStore = findStore("ExpandedGuildFolderStore");
|
export const ExpandedGuildFolderStore = findStore("ExpandedGuildFolderStore");
|
||||||
const FolderUtils = findByProps("move", "toggleGuildFolderExpand");
|
const FolderUtils = findByProps("move", "toggleGuildFolderExpand");
|
||||||
|
@ -117,7 +117,7 @@ export default definePlugin({
|
||||||
},
|
},
|
||||||
// If we are rendering the Better Folders sidebar, we filter out guilds that are not in folders and unexpanded folders
|
// If we are rendering the Better Folders sidebar, we filter out guilds that are not in folders and unexpanded folders
|
||||||
{
|
{
|
||||||
match: /\[(\i)\]=(\(0,\i\.useStateFromStoresArray\).{0,40}getGuildsTree\(\).+?}\))(?=,)/,
|
match: /\[(\i)\]=(\(0,\i\.\i\).{0,40}getGuildsTree\(\).+?}\))(?=,)/,
|
||||||
replace: (_, originalTreeVar, rest) => `[betterFoldersOriginalTree]=${rest},${originalTreeVar}=$self.getGuildTree(!!arguments[0].isBetterFolders,betterFoldersOriginalTree,arguments[0].betterFoldersExpandedIds)`
|
replace: (_, originalTreeVar, rest) => `[betterFoldersOriginalTree]=${rest},${originalTreeVar}=$self.getGuildTree(!!arguments[0].isBetterFolders,betterFoldersOriginalTree,arguments[0].betterFoldersExpandedIds)`
|
||||||
},
|
},
|
||||||
// If we are rendering the Better Folders sidebar, we filter out everything but the servers and folders from the GuildsBar Guild List children
|
// If we are rendering the Better Folders sidebar, we filter out everything but the servers and folders from the GuildsBar Guild List children
|
||||||
|
@ -139,13 +139,13 @@ export default definePlugin({
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// This is the parent folder component
|
// This is the parent folder component
|
||||||
find: ".MAX_GUILD_FOLDER_NAME_LENGTH,",
|
find: ".toggleGuildFolderExpand(",
|
||||||
predicate: () => settings.store.sidebar && settings.store.showFolderIcon !== FolderIconDisplay.Always,
|
predicate: () => settings.store.sidebar && settings.store.showFolderIcon !== FolderIconDisplay.Always,
|
||||||
replacement: [
|
replacement: [
|
||||||
{
|
{
|
||||||
// Modify the expanded state to instead return the list of expanded folders
|
// Modify the expanded state to instead return the list of expanded folders
|
||||||
match: /(useStateFromStores\).{0,20}=>)(\i\.\i)\.isFolderExpanded\(\i\)/,
|
match: /(\],\(\)=>)(\i\.\i)\.isFolderExpanded\(\i\)\)/,
|
||||||
replace: (_, rest, ExpandedGuildFolderStore) => `${rest}${ExpandedGuildFolderStore}.getExpandedFolders()`,
|
replace: (_, rest, ExpandedGuildFolderStore) => `${rest}${ExpandedGuildFolderStore}.getExpandedFolders())`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// Modify the expanded prop to use the boolean if the above patch fails, or check if the folder is expanded from the list if it succeeds
|
// Modify the expanded prop to use the boolean if the above patch fails, or check if the folder is expanded from the list if it succeeds
|
||||||
|
@ -196,7 +196,7 @@ export default definePlugin({
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
find: "APPLICATION_LIBRARY,render",
|
find: "APPLICATION_LIBRARY,render:",
|
||||||
predicate: () => settings.store.sidebar,
|
predicate: () => settings.store.sidebar,
|
||||||
replacement: {
|
replacement: {
|
||||||
// Render the Better Folders sidebar
|
// Render the Better Folders sidebar
|
||||||
|
|
|
@ -36,7 +36,7 @@ export default definePlugin({
|
||||||
{
|
{
|
||||||
find: ".Messages.GIF,",
|
find: ".Messages.GIF,",
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /alt:(\i)=(\i\.default\.Messages\.GIF)(?=,[^}]*\}=(\i))/,
|
match: /alt:(\i)=(\i\.\i\.Messages\.GIF)(?=,[^}]*\}=(\i))/,
|
||||||
replace:
|
replace:
|
||||||
// rename prop so we can always use default value
|
// rename prop so we can always use default value
|
||||||
"alt_$$:$1=$self.altify($3)||$2",
|
"alt_$$:$1=$self.altify($3)||$2",
|
||||||
|
|
|
@ -13,7 +13,7 @@ export default definePlugin({
|
||||||
authors: [Devs.Samwich],
|
authors: [Devs.Samwich],
|
||||||
patches: [
|
patches: [
|
||||||
{
|
{
|
||||||
find: ".GIFPickerResultTypes.SEARCH",
|
find: '"state",{resultType:',
|
||||||
replacement: [{
|
replacement: [{
|
||||||
match: /(?<="state",{resultType:)null/,
|
match: /(?<="state",{resultType:)null/,
|
||||||
replace: '"Favorites"'
|
replace: '"Favorites"'
|
||||||
|
|
|
@ -5,15 +5,18 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { definePluginSettings } from "@api/Settings";
|
import { definePluginSettings } from "@api/Settings";
|
||||||
|
import { getUserSettingDefinitionLazy } from "@api/UserSettingDefinitions";
|
||||||
import { ImageIcon } from "@components/Icons";
|
import { ImageIcon } from "@components/Icons";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
import { getCurrentGuild, openImageModal } from "@utils/discord";
|
import { getCurrentGuild, openImageModal } from "@utils/discord";
|
||||||
import definePlugin, { OptionType } from "@utils/types";
|
import definePlugin, { OptionType } from "@utils/types";
|
||||||
import { findByProps } from "@webpack";
|
import { findByProps } from "@webpack";
|
||||||
import { Clipboard, GuildStore, Menu, PermissionStore, TextAndImagesSettingsStores } from "@webpack/common";
|
import { Clipboard, GuildStore, Menu, PermissionStore } from "@webpack/common";
|
||||||
|
|
||||||
const GuildSettingsActions = findByProps("open", "selectRole", "updateGuild");
|
const GuildSettingsActions = findByProps("open", "selectRole", "updateGuild");
|
||||||
|
|
||||||
|
const DeveloperMode = getUserSettingDefinitionLazy("appearance", "developerMode")!;
|
||||||
|
|
||||||
function PencilIcon() {
|
function PencilIcon() {
|
||||||
return (
|
return (
|
||||||
<svg
|
<svg
|
||||||
|
@ -62,12 +65,13 @@ export default definePlugin({
|
||||||
name: "BetterRoleContext",
|
name: "BetterRoleContext",
|
||||||
description: "Adds options to copy role color / edit role / view role icon when right clicking roles in the user profile",
|
description: "Adds options to copy role color / edit role / view role icon when right clicking roles in the user profile",
|
||||||
authors: [Devs.Ven, Devs.goodbee],
|
authors: [Devs.Ven, Devs.goodbee],
|
||||||
|
dependencies: ["UserSettingDefinitionsAPI"],
|
||||||
|
|
||||||
settings,
|
settings,
|
||||||
|
|
||||||
start() {
|
start() {
|
||||||
// DeveloperMode needs to be enabled for the context menu to be shown
|
// DeveloperMode needs to be enabled for the context menu to be shown
|
||||||
TextAndImagesSettingsStores.DeveloperMode.updateSetting(true);
|
DeveloperMode.updateSetting(true);
|
||||||
},
|
},
|
||||||
|
|
||||||
contextMenus: {
|
contextMenus: {
|
||||||
|
|
|
@ -77,15 +77,6 @@ export default definePlugin({
|
||||||
replace: "$& $self.renderIcon({ ...arguments[0], DeviceIcon: $1 }), false &&"
|
replace: "$& $self.renderIcon({ ...arguments[0], DeviceIcon: $1 }), false &&"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
|
||||||
{
|
|
||||||
// Add the ability to change BlobMask's lower badge height
|
|
||||||
// (it allows changing width so we can mirror that logic)
|
|
||||||
find: "this.getBadgePositionInterpolation(",
|
|
||||||
replacement: {
|
|
||||||
match: /(\i\.animated\.rect,{id:\i,x:48-\(\i\+8\)\+4,y:)28(,width:\i\+8,height:)24,/,
|
|
||||||
replace: (_, leftPart, rightPart) => `${leftPart} 48 - ((this.props.lowerBadgeHeight ?? 16) + 8) + 4 ${rightPart} (this.props.lowerBadgeHeight ?? 16) + 8,`
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
||||||
|
@ -153,14 +144,16 @@ export default definePlugin({
|
||||||
<PlatformIcon width={14} height={14} />
|
<PlatformIcon width={14} height={14} />
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
lowerBadgeWidth={20}
|
lowerBadgeSize={{
|
||||||
lowerBadgeHeight={20}
|
width: 20,
|
||||||
|
height: 20
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className={SessionIconClasses.sessionIcon}
|
className={SessionIconClasses.sessionIcon}
|
||||||
style={{ backgroundColor: GetOsColor(session.client_info.os) }}
|
style={{ backgroundColor: GetOsColor(session.client_info.os) }}
|
||||||
>
|
>
|
||||||
<DeviceIcon width={28} height={28} />
|
<DeviceIcon width={28} height={28} color="currentColor" />
|
||||||
</div>
|
</div>
|
||||||
</BlobMask>
|
</BlobMask>
|
||||||
);
|
);
|
||||||
|
|
|
@ -84,19 +84,19 @@ export default definePlugin({
|
||||||
find: "this.renderArtisanalHack()",
|
find: "this.renderArtisanalHack()",
|
||||||
replacement: [
|
replacement: [
|
||||||
{ // Fade in on layer
|
{ // Fade in on layer
|
||||||
match: /(?<=\((\i),"contextType",\i\.AccessibilityPreferencesContext\);)/,
|
match: /(?<=\((\i),"contextType",\i\.\i\);)/,
|
||||||
replace: "$1=$self.Layer;",
|
replace: "$1=$self.Layer;",
|
||||||
predicate: () => settings.store.disableFade
|
predicate: () => settings.store.disableFade
|
||||||
},
|
},
|
||||||
{ // Lazy-load contents
|
{ // Lazy-load contents
|
||||||
match: /createPromise:\(\)=>([^:}]*?),webpackId:"\d+",name:(?!="CollectiblesShop")"[^"]+"/g,
|
match: /createPromise:\(\)=>([^:}]*?),webpackId:"?\d+"?,name:(?!="CollectiblesShop")"[^"]+"/g,
|
||||||
replace: "$&,_:$1",
|
replace: "$&,_:$1",
|
||||||
predicate: () => settings.store.eagerLoad
|
predicate: () => settings.store.eagerLoad
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{ // For some reason standardSidebarView also has a small fade-in
|
{ // For some reason standardSidebarView also has a small fade-in
|
||||||
find: "DefaultCustomContentScroller:function()",
|
find: 'minimal:"contentColumnMinimal"',
|
||||||
replacement: [
|
replacement: [
|
||||||
{
|
{
|
||||||
match: /\(0,\i\.useTransition\)\((\i)/,
|
match: /\(0,\i\.useTransition\)\((\i)/,
|
||||||
|
@ -112,7 +112,7 @@ export default definePlugin({
|
||||||
{ // Load menu TOC eagerly
|
{ // Load menu TOC eagerly
|
||||||
find: "Messages.USER_SETTINGS_WITH_BUILD_OVERRIDE.format",
|
find: "Messages.USER_SETTINGS_WITH_BUILD_OVERRIDE.format",
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /(\i)\(this,"handleOpenSettingsContextMenu",.{0,100}?openContextMenuLazy.{0,100}?(await Promise\.all[^};]*?\)\)).*?,(?=\1\(this)/,
|
match: /(\i)\(this,"handleOpenSettingsContextMenu",.{0,100}?null!=\i&&.{0,100}?(await Promise\.all[^};]*?\)\)).*?,(?=\1\(this)/,
|
||||||
replace: "$&(async ()=>$2)(),"
|
replace: "$&(async ()=>$2)(),"
|
||||||
},
|
},
|
||||||
predicate: () => settings.store.eagerLoad
|
predicate: () => settings.store.eagerLoad
|
||||||
|
@ -120,8 +120,8 @@ export default definePlugin({
|
||||||
{ // Settings cog context menu
|
{ // Settings cog context menu
|
||||||
find: "Messages.USER_SETTINGS_ACTIONS_MENU_LABEL",
|
find: "Messages.USER_SETTINGS_ACTIONS_MENU_LABEL",
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /\(0,\i.useDefaultUserSettingsSections\)\(\)(?=\.filter\(\i=>\{let\{section:\i\}=)/,
|
match: /(EXPERIMENTS:.+?)(\(0,\i.\i\)\(\))(?=\.filter\(\i=>\{let\{section:\i\}=)/,
|
||||||
replace: "$self.wrapMenu($&)"
|
replace: "$1$self.wrapMenu($2)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
|
@ -11,7 +11,7 @@ import { Devs } from "@utils/constants";
|
||||||
import { Margins } from "@utils/margins";
|
import { Margins } from "@utils/margins";
|
||||||
import { classes } from "@utils/misc";
|
import { classes } from "@utils/misc";
|
||||||
import definePlugin, { OptionType, StartAt } from "@utils/types";
|
import definePlugin, { OptionType, StartAt } from "@utils/types";
|
||||||
import { findByProps, findComponentByCode, findStore } from "@webpack";
|
import { findByCode, findComponentByCode, findStore } from "@webpack";
|
||||||
import { Button, Forms, useStateFromStores } from "@webpack/common";
|
import { Button, Forms, useStateFromStores } from "@webpack/common";
|
||||||
|
|
||||||
const ColorPicker = findComponentByCode(".Messages.USER_SETTINGS_PROFILE_COLOR_SELECT_COLOR", ".BACKGROUND_PRIMARY)");
|
const ColorPicker = findComponentByCode(".Messages.USER_SETTINGS_PROFILE_COLOR_SELECT_COLOR", ".BACKGROUND_PRIMARY)");
|
||||||
|
@ -30,7 +30,7 @@ function onPickColor(color: number) {
|
||||||
updateColorVars(hexColor);
|
updateColorVars(hexColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
const { saveClientTheme } = findByProps("saveClientTheme");
|
const saveClientTheme = findByCode('type:"UNSYNCED_USER_SETTINGS_UPDATE",settings:{useSystemTheme:"system"===');
|
||||||
|
|
||||||
function setTheme(theme: string) {
|
function setTheme(theme: string) {
|
||||||
saveClientTheme({ theme });
|
saveClientTheme({ theme });
|
||||||
|
|
|
@ -24,12 +24,11 @@ import { closeAllModals } from "@utils/modal";
|
||||||
import definePlugin, { OptionType } from "@utils/types";
|
import definePlugin, { OptionType } from "@utils/types";
|
||||||
import { maybePromptToUpdate } from "@utils/updater";
|
import { maybePromptToUpdate } from "@utils/updater";
|
||||||
import { findByProps } from "@webpack";
|
import { findByProps } from "@webpack";
|
||||||
import { DraftType, FluxDispatcher, NavigationRouter, SelectedChannelStore } from "@webpack/common";
|
import { DraftType, ExpressionPickerStore, FluxDispatcher, NavigationRouter, SelectedChannelStore } from "@webpack/common";
|
||||||
|
|
||||||
const CrashHandlerLogger = new Logger("CrashHandler");
|
const CrashHandlerLogger = new Logger("CrashHandler");
|
||||||
const ModalStack = findByProps("pushLazy", "popAll");
|
const ModalStack = findByProps("pushLazy", "popAll");
|
||||||
const DraftManager = findByProps("clearDraft", "saveDraft");
|
const DraftManager = findByProps("clearDraft", "saveDraft");
|
||||||
const { closeExpressionPicker } = findByProps("closeExpressionPicker", "openExpressionPicker");
|
|
||||||
|
|
||||||
const settings = definePluginSettings({
|
const settings = definePluginSettings({
|
||||||
attemptToPreventCrashes: {
|
attemptToPreventCrashes: {
|
||||||
|
@ -134,7 +133,7 @@ export default definePlugin({
|
||||||
CrashHandlerLogger.debug("Failed to clear drafts.", err);
|
CrashHandlerLogger.debug("Failed to clear drafts.", err);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
closeExpressionPicker();
|
ExpressionPickerStore.closeExpressionPicker();
|
||||||
}
|
}
|
||||||
catch (err) {
|
catch (err) {
|
||||||
CrashHandlerLogger.debug("Failed to close expression picker.", err);
|
CrashHandlerLogger.debug("Failed to close expression picker.", err);
|
||||||
|
|
|
@ -40,9 +40,9 @@ export default definePlugin({
|
||||||
}),
|
}),
|
||||||
patches: [
|
patches: [
|
||||||
{
|
{
|
||||||
find: "KeyboardKeys.ENTER&&(!",
|
find: ".ENTER&&(!",
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /(?<=(\i)\.which===\i\.KeyboardKeys.ENTER&&).{0,100}(\(0,\i\.hasOpenPlainTextCodeBlock\)\(\i\)).{0,100}(?=&&\(\i\.preventDefault)/,
|
match: /(?<=(\i)\.which===\i\.\i.ENTER&&).{0,100}(\(0,\i\.\i\)\(\i\)).{0,100}(?=&&\(\i\.preventDefault)/,
|
||||||
replace: "$self.shouldSubmit($1, $2)"
|
replace: "$self.shouldSubmit($1, $2)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { definePluginSettings } from "@api/Settings";
|
import { definePluginSettings } from "@api/Settings";
|
||||||
|
import { getUserSettingDefinitionLazy } from "@api/UserSettingDefinitions";
|
||||||
import { ErrorCard } from "@components/ErrorCard";
|
import { ErrorCard } from "@components/ErrorCard";
|
||||||
import { Link } from "@components/Link";
|
import { Link } from "@components/Link";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
|
@ -26,12 +27,14 @@ import { classes } from "@utils/misc";
|
||||||
import { useAwaiter } from "@utils/react";
|
import { useAwaiter } from "@utils/react";
|
||||||
import definePlugin, { OptionType } from "@utils/types";
|
import definePlugin, { OptionType } from "@utils/types";
|
||||||
import { findByCode, findByProps, findComponentByCode } from "@webpack";
|
import { findByCode, findByProps, findComponentByCode } from "@webpack";
|
||||||
import { ApplicationAssetUtils, Button, FluxDispatcher, Forms, GuildStore, React, SelectedChannelStore, SelectedGuildStore, StatusSettingsStores, UserStore } from "@webpack/common";
|
import { ApplicationAssetUtils, Button, FluxDispatcher, Forms, GuildStore, React, SelectedChannelStore, SelectedGuildStore, UserStore } from "@webpack/common";
|
||||||
|
|
||||||
const useProfileThemeStyle = findByCode("profileThemeStyle:", "--profile-gradient-primary-color");
|
const useProfileThemeStyle = findByCode("profileThemeStyle:", "--profile-gradient-primary-color");
|
||||||
const ActivityComponent = findComponentByCode("onOpenGameProfile");
|
const ActivityComponent = findComponentByCode("onOpenGameProfile");
|
||||||
const ActivityClassName = findByProps("activity", "buttonColor");
|
const ActivityClassName = findByProps("activity", "buttonColor");
|
||||||
|
|
||||||
|
const ShowCurrentGame = getUserSettingDefinitionLazy<boolean>("status", "showCurrentGame")!;
|
||||||
|
|
||||||
async function getApplicationAsset(key: string): Promise<string> {
|
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)\//, "");
|
if (/https?:\/\/(cdn|media)\.discordapp\.(com|net)\/attachments\//.test(key)) return "mp:" + key.replace(/https?:\/\/(cdn|media)\.discordapp\.(com|net)\//, "");
|
||||||
return (await ApplicationAssetUtils.fetchAssetIds(settings.store.appID!, [key]))[0];
|
return (await ApplicationAssetUtils.fetchAssetIds(settings.store.appID!, [key]))[0];
|
||||||
|
@ -390,13 +393,14 @@ export default definePlugin({
|
||||||
name: "CustomRPC",
|
name: "CustomRPC",
|
||||||
description: "Allows you to set a custom rich presence.",
|
description: "Allows you to set a custom rich presence.",
|
||||||
authors: [Devs.captain, Devs.AutumnVN, Devs.nin0dev],
|
authors: [Devs.captain, Devs.AutumnVN, Devs.nin0dev],
|
||||||
|
dependencies: ["UserSettingDefinitionsAPI"],
|
||||||
start: setRpc,
|
start: setRpc,
|
||||||
stop: () => setRpc(true),
|
stop: () => setRpc(true),
|
||||||
settings,
|
settings,
|
||||||
|
|
||||||
settingsAboutComponent: () => {
|
settingsAboutComponent: () => {
|
||||||
const activity = useAwaiter(createActivity);
|
const activity = useAwaiter(createActivity);
|
||||||
const gameActivityEnabled = StatusSettingsStores.ShowCurrentGame.useSetting();
|
const gameActivityEnabled = ShowCurrentGame.useSetting();
|
||||||
const { profileThemeStyle } = useProfileThemeStyle({});
|
const { profileThemeStyle } = useProfileThemeStyle({});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -412,7 +416,7 @@ export default definePlugin({
|
||||||
<Button
|
<Button
|
||||||
color={Button.Colors.TRANSPARENT}
|
color={Button.Colors.TRANSPARENT}
|
||||||
className={Margins.top8}
|
className={Margins.top8}
|
||||||
onClick={() => StatusSettingsStores.ShowCurrentGame.updateSetting(true)}
|
onClick={() => ShowCurrentGame.updateSetting(true)}
|
||||||
>
|
>
|
||||||
Enable
|
Enable
|
||||||
</Button>
|
</Button>
|
||||||
|
|
|
@ -33,26 +33,23 @@ export default definePlugin({
|
||||||
authors: [Devs.newwares],
|
authors: [Devs.newwares],
|
||||||
settings,
|
settings,
|
||||||
patches: [
|
patches: [
|
||||||
{
|
|
||||||
find: "IDLE_DURATION:function(){return",
|
|
||||||
replacement: {
|
|
||||||
match: /(IDLE_DURATION:function\(\){return )\i/,
|
|
||||||
replace: "$1$self.getIdleTimeout()"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
find: 'type:"IDLE",idle:',
|
find: 'type:"IDLE",idle:',
|
||||||
replacement: [
|
replacement: [
|
||||||
{
|
{
|
||||||
match: /Math\.min\((\i\.AfkTimeout\.getSetting\(\)\*\i\.default\.Millis\.SECOND),\i\.IDLE_DURATION\)/,
|
match: /(?<=Date\.now\(\)-\i>)\i\.\i/,
|
||||||
|
replace: "$self.getIdleTimeout()"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
match: /Math\.min\((\i\.\i\.getSetting\(\)\*\i\.\i\.\i\.SECOND),\i\.\i\)/,
|
||||||
replace: "$1" // Decouple idle from afk (phone notifications will remain at user setting or 10 min maximum)
|
replace: "$1" // Decouple idle from afk (phone notifications will remain at user setting or 10 min maximum)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
match: /\i\.default\.dispatch\({type:"IDLE",idle:!1}\)/,
|
match: /\i\.\i\.dispatch\({type:"IDLE",idle:!1}\)/,
|
||||||
replace: "$self.handleOnline()"
|
replace: "$self.handleOnline()"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
match: /(setInterval\(\i,\.25\*)\i\.IDLE_DURATION/,
|
match: /(setInterval\(\i,\.25\*)\i\.\i/,
|
||||||
replace: "$1$self.getIntervalDelay()" // For web installs
|
replace: "$1$self.getIntervalDelay()" // For web installs
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
@ -9,7 +9,6 @@ import "./ui/styles.css";
|
||||||
import ErrorBoundary from "@components/ErrorBoundary";
|
import ErrorBoundary from "@components/ErrorBoundary";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
import definePlugin from "@utils/types";
|
import definePlugin from "@utils/types";
|
||||||
import { findByProps } from "@webpack";
|
|
||||||
import { UserStore } from "@webpack/common";
|
import { UserStore } from "@webpack/common";
|
||||||
|
|
||||||
import { CDN_URL, RAW_SKU_ID, SKU_ID } from "./lib/constants";
|
import { CDN_URL, RAW_SKU_ID, SKU_ID } from "./lib/constants";
|
||||||
|
@ -20,7 +19,6 @@ import { settings } from "./settings";
|
||||||
import { setDecorationGridDecoration, setDecorationGridItem } from "./ui/components";
|
import { setDecorationGridDecoration, setDecorationGridItem } from "./ui/components";
|
||||||
import DecorSection from "./ui/components/DecorSection";
|
import DecorSection from "./ui/components/DecorSection";
|
||||||
|
|
||||||
const { isAnimatedAvatarDecoration } = findByProps("isAnimatedAvatarDecoration");
|
|
||||||
export interface AvatarDecoration {
|
export interface AvatarDecoration {
|
||||||
asset: string;
|
asset: string;
|
||||||
skuId: string;
|
skuId: string;
|
||||||
|
@ -61,7 +59,7 @@ export default definePlugin({
|
||||||
},
|
},
|
||||||
// Remove NEW label from decor avatar decorations
|
// Remove NEW label from decor avatar decorations
|
||||||
{
|
{
|
||||||
match: /(?<=\.Section\.PREMIUM_PURCHASE&&\i)(?<=avatarDecoration:(\i).+?)/,
|
match: /(?<=\.\i\.PREMIUM_PURCHASE&&\i)(?<=avatarDecoration:(\i).+?)/,
|
||||||
replace: "||$1.skuId===$self.SKU_ID"
|
replace: "||$1.skuId===$self.SKU_ID"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -93,7 +91,7 @@ export default definePlugin({
|
||||||
replacement: [
|
replacement: [
|
||||||
// Use Decor avatar decoration hook
|
// Use Decor avatar decoration hook
|
||||||
{
|
{
|
||||||
match: /(?<=getAvatarDecorationURL\)\({avatarDecoration:)(\i).avatarDecoration(?=,)/,
|
match: /(?<=\i\)\({avatarDecoration:)(\i).avatarDecoration(?=,)/,
|
||||||
replace: "$self.useUserDecorAvatarDecoration($1)??$&"
|
replace: "$self.useUserDecorAvatarDecoration($1)??$&"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -133,7 +131,7 @@ export default definePlugin({
|
||||||
if (avatarDecoration?.skuId === SKU_ID) {
|
if (avatarDecoration?.skuId === SKU_ID) {
|
||||||
const parts = avatarDecoration.asset.split("_");
|
const parts = avatarDecoration.asset.split("_");
|
||||||
// Remove a_ prefix if it's animated and animation is disabled
|
// Remove a_ prefix if it's animated and animation is disabled
|
||||||
if (isAnimatedAvatarDecoration(avatarDecoration.asset) && !canAnimate) parts.shift();
|
if (avatarDecoration.asset.startsWith("a_") && !canAnimate) parts.shift();
|
||||||
return `${CDN_URL}/${parts.join("_")}.png`;
|
return `${CDN_URL}/${parts.join("_")}.png`;
|
||||||
} else if (avatarDecoration?.skuId === RAW_SKU_ID) {
|
} else if (avatarDecoration?.skuId === RAW_SKU_ID) {
|
||||||
return avatarDecoration.asset;
|
return avatarDecoration.asset;
|
||||||
|
|
|
@ -10,5 +10,5 @@ import { extractAndLoadChunksLazy, findByProps } from "@webpack";
|
||||||
export const cl = classNameFactory("vc-decor-");
|
export const cl = classNameFactory("vc-decor-");
|
||||||
export const DecorationModalStyles = findByProps("modalFooterShopButton");
|
export const DecorationModalStyles = findByProps("modalFooterShopButton");
|
||||||
|
|
||||||
export const requireAvatarDecorationModal = extractAndLoadChunksLazy(["openAvatarDecorationModal:"]);
|
export const requireAvatarDecorationModal = extractAndLoadChunksLazy([".COLLECTIBLES_SHOP_FULLSCREEN&&"]);
|
||||||
export const requireCreateStickerModal = extractAndLoadChunksLazy(["stickerInspected]:"]);
|
export const requireCreateStickerModal = extractAndLoadChunksLazy(["stickerInspected]:"]);
|
||||||
|
|
|
@ -9,7 +9,7 @@ import { Link } from "@components/Link";
|
||||||
import { openInviteModal } from "@utils/discord";
|
import { openInviteModal } from "@utils/discord";
|
||||||
import { Margins } from "@utils/margins";
|
import { Margins } from "@utils/margins";
|
||||||
import { closeAllModals, ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalProps, ModalRoot, ModalSize, openModal } from "@utils/modal";
|
import { closeAllModals, ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalProps, ModalRoot, ModalSize, openModal } from "@utils/modal";
|
||||||
import { findByProps, findComponentByCode } from "@webpack";
|
import { filters, findComponentByCode, mapMangledModule } from "@webpack";
|
||||||
import { Button, FluxDispatcher, Forms, GuildStore, NavigationRouter, Text, TextInput, useEffect, useMemo, UserStore, useState } from "@webpack/common";
|
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";
|
import { GUILD_ID, INVITE_KEY, RAW_SKU_ID } from "../../lib/constants";
|
||||||
|
@ -19,7 +19,10 @@ import { AvatarDecorationModalPreview } from "../components";
|
||||||
|
|
||||||
const FileUpload = findComponentByCode("fileUploadInput,");
|
const FileUpload = findComponentByCode("fileUploadInput,");
|
||||||
|
|
||||||
const { default: HelpMessage, HelpMessageTypes } = findByProps("HelpMessageTypes");
|
const { HelpMessage, HelpMessageTypes } = mapMangledModule('POSITIVE=3]="POSITIVE', {
|
||||||
|
HelpMessageTypes: filters.byProps("POSITIVE", "WARNING"),
|
||||||
|
HelpMessage: filters.byCode(".iconDiv")
|
||||||
|
});
|
||||||
|
|
||||||
function useObjectURL(object: Blob | MediaSource | null) {
|
function useObjectURL(object: Blob | MediaSource | null) {
|
||||||
const [url, setUrl] = useState<string | null>(null);
|
const [url, setUrl] = useState<string | null>(null);
|
||||||
|
|
|
@ -29,7 +29,7 @@ export default definePlugin({
|
||||||
{
|
{
|
||||||
find: ".Messages.BOT_CALL_IDLE_DISCONNECT",
|
find: ".Messages.BOT_CALL_IDLE_DISCONNECT",
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /,?(?=\i\(this,"idleTimeout",new \i\.Timeout\))/,
|
match: /,?(?=\i\(this,"idleTimeout",new \i\.\i\))/,
|
||||||
replace: ";return;"
|
replace: ";return;"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -23,12 +23,12 @@ import { Logger } from "@utils/Logger";
|
||||||
import { Margins } from "@utils/margins";
|
import { Margins } from "@utils/margins";
|
||||||
import { ModalContent, ModalHeader, ModalRoot, openModalLazy } from "@utils/modal";
|
import { ModalContent, ModalHeader, ModalRoot, openModalLazy } from "@utils/modal";
|
||||||
import definePlugin from "@utils/types";
|
import definePlugin from "@utils/types";
|
||||||
import { findByProps, findStore } 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 { Constants, EmojiStore, FluxDispatcher, Forms, GuildStore, Menu, PermissionsBits, PermissionStore, React, RestAPI, Toasts, Tooltip, UserStore } from "@webpack/common";
|
||||||
import { Promisable } from "type-fest";
|
import { Promisable } from "type-fest";
|
||||||
|
|
||||||
const StickersStore = findStore("StickersStore");
|
const StickersStore = findStore("StickersStore");
|
||||||
const EmojiManager = findByProps("fetchEmoji", "uploadEmoji", "deleteEmoji");
|
const uploadEmoji = findByCode(".GUILD_EMOJIS(", "EMOJI_UPLOAD_START");
|
||||||
|
|
||||||
interface Sticker {
|
interface Sticker {
|
||||||
t: "Sticker";
|
t: "Sticker";
|
||||||
|
@ -106,7 +106,7 @@ async function cloneEmoji(guildId: string, emoji: Emoji) {
|
||||||
reader.readAsDataURL(data);
|
reader.readAsDataURL(data);
|
||||||
});
|
});
|
||||||
|
|
||||||
return EmojiManager.uploadEmoji({
|
return uploadEmoji({
|
||||||
guildId,
|
guildId,
|
||||||
name: emoji.name.split("~")[0],
|
name: emoji.name.split("~")[0],
|
||||||
image: dataUrl
|
image: dataUrl
|
||||||
|
|
|
@ -28,7 +28,7 @@ import { Forms, React } from "@webpack/common";
|
||||||
|
|
||||||
import hideBugReport from "./hideBugReport.css?managed";
|
import hideBugReport from "./hideBugReport.css?managed";
|
||||||
|
|
||||||
const KbdStyles = findByProps("key", "removeBuildOverride");
|
const KbdStyles = findByProps("key", "combo");
|
||||||
|
|
||||||
const settings = definePluginSettings({
|
const settings = definePluginSettings({
|
||||||
toolbarDevMenu: {
|
toolbarDevMenu: {
|
||||||
|
@ -106,9 +106,11 @@ export default definePlugin({
|
||||||
<Forms.FormTitle tag="h3">More Information</Forms.FormTitle>
|
<Forms.FormTitle tag="h3">More Information</Forms.FormTitle>
|
||||||
<Forms.FormText variant="text-md/normal">
|
<Forms.FormText variant="text-md/normal">
|
||||||
You can open Discord's DevTools via {" "}
|
You can open Discord's DevTools via {" "}
|
||||||
<kbd className={KbdStyles.key}>{modKey}</kbd> +{" "}
|
<div className={KbdStyles.combo} style={{ display: "inline-flex" }}>
|
||||||
<kbd className={KbdStyles.key}>{altKey}</kbd> +{" "}
|
<kbd className={KbdStyles.key}>{modKey}</kbd> +{" "}
|
||||||
<kbd className={KbdStyles.key}>O</kbd>{" "}
|
<kbd className={KbdStyles.key}>{altKey}</kbd> +{" "}
|
||||||
|
<kbd className={KbdStyles.key}>O</kbd>{" "}
|
||||||
|
</div>
|
||||||
</Forms.FormText>
|
</Forms.FormText>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
|
|
|
@ -23,7 +23,7 @@ import { ApngBlendOp, ApngDisposeOp, importApngJs } from "@utils/dependencies";
|
||||||
import { getCurrentGuild } from "@utils/discord";
|
import { getCurrentGuild } from "@utils/discord";
|
||||||
import { Logger } from "@utils/Logger";
|
import { Logger } from "@utils/Logger";
|
||||||
import definePlugin, { OptionType } from "@utils/types";
|
import definePlugin, { OptionType } from "@utils/types";
|
||||||
import { findByProps, findStore, webpackDependantLazy } from "@webpack";
|
import { findByCode, findByProps, findStore, webpackDependantLazy } from "@webpack";
|
||||||
import { Alerts, ChannelStore, DraftType, EmojiStore, FluxDispatcher, Forms, IconUtils, lodash, Parser, PermissionsBits, PermissionStore, UploadHandler, UserSettingsActionCreators, UserStore } from "@webpack/common";
|
import { Alerts, ChannelStore, DraftType, EmojiStore, FluxDispatcher, Forms, IconUtils, lodash, Parser, PermissionsBits, PermissionStore, UploadHandler, UserSettingsActionCreators, UserStore } from "@webpack/common";
|
||||||
import type { Emoji } from "@webpack/types";
|
import type { Emoji } from "@webpack/types";
|
||||||
import type { Message } from "discord-types/general";
|
import type { Message } from "discord-types/general";
|
||||||
|
@ -37,8 +37,8 @@ const StickerStore = findStore("StickersStore") as {
|
||||||
};
|
};
|
||||||
|
|
||||||
const UserSettingsProtoStore = findStore("UserSettingsProtoStore");
|
const UserSettingsProtoStore = findStore("UserSettingsProtoStore");
|
||||||
const ProtoUtils = findByProps("BINARY_READ_OPTIONS");
|
|
||||||
const RoleSubscriptionEmojiUtils = findByProps("isUnusableRoleSubscriptionEmoji");
|
const BINARY_READ_OPTIONS = findByProps("readerFactory");
|
||||||
|
|
||||||
function searchProtoClassField(localName: string, protoClass: any) {
|
function searchProtoClassField(localName: string, protoClass: any) {
|
||||||
const field = protoClass?.fields?.find((field: any) => field.localName === localName);
|
const field = protoClass?.fields?.find((field: any) => field.localName === localName);
|
||||||
|
@ -52,6 +52,8 @@ const PreloadedUserSettingsActionCreators = webpackDependantLazy(() => UserSetti
|
||||||
const AppearanceSettingsActionCreators = webpackDependantLazy(() => searchProtoClassField("appearance", PreloadedUserSettingsActionCreators.ProtoClass));
|
const AppearanceSettingsActionCreators = webpackDependantLazy(() => searchProtoClassField("appearance", PreloadedUserSettingsActionCreators.ProtoClass));
|
||||||
const ClientThemeSettingsActionsCreators = webpackDependantLazy(() => searchProtoClassField("clientThemeSettings", AppearanceSettingsActionCreators));
|
const ClientThemeSettingsActionsCreators = webpackDependantLazy(() => searchProtoClassField("clientThemeSettings", AppearanceSettingsActionCreators));
|
||||||
|
|
||||||
|
const isUnusableRoleSubscriptionEmoji = findByCode(".getUserIsAdmin(");
|
||||||
|
|
||||||
const enum EmojiIntentions {
|
const enum EmojiIntentions {
|
||||||
REACTION,
|
REACTION,
|
||||||
STATUS,
|
STATUS,
|
||||||
|
@ -235,11 +237,10 @@ export default definePlugin({
|
||||||
},
|
},
|
||||||
// Allows the usage of subscription-locked emojis
|
// Allows the usage of subscription-locked emojis
|
||||||
{
|
{
|
||||||
find: "isUnusableRoleSubscriptionEmoji:function",
|
find: ".getUserIsAdmin(",
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /isUnusableRoleSubscriptionEmoji:function/,
|
match: /(function \i\(\i,\i)\){(.{0,250}.getUserIsAdmin\(.+?return!1})/,
|
||||||
// Replace the original export with a func that always returns false and alias the original
|
replace: (_, rest1, rest2) => `${rest1},fakeNitroOriginal){if(!fakeNitroOriginal)return false;${rest2}`
|
||||||
replace: "isUnusableRoleSubscriptionEmoji:()=>()=>false,isUnusableRoleSubscriptionEmojiOriginal:function"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// Allow stickers to be sent everywhere
|
// Allow stickers to be sent everywhere
|
||||||
|
@ -360,7 +361,7 @@ export default definePlugin({
|
||||||
replacement: [
|
replacement: [
|
||||||
{
|
{
|
||||||
// Export the renderable sticker to be used in the fake nitro sticker notice
|
// Export the renderable sticker to be used in the fake nitro sticker notice
|
||||||
match: /let{renderableSticker:(\i).{0,250}isGuildSticker.+?channel:\i,/,
|
match: /let{renderableSticker:(\i).{0,270}sticker:\i,channel:\i,/,
|
||||||
replace: (m, renderableSticker) => `${m}fakeNitroRenderableSticker:${renderableSticker},`
|
replace: (m, renderableSticker) => `${m}fakeNitroRenderableSticker:${renderableSticker},`
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -398,7 +399,7 @@ export default definePlugin({
|
||||||
},
|
},
|
||||||
// Separate patch for allowing using custom app icons
|
// Separate patch for allowing using custom app icons
|
||||||
{
|
{
|
||||||
find: ".FreemiumAppIconIds.DEFAULT&&(",
|
find: /\.getCurrentDesktopIcon.{0,25}\.isPremium/,
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /\i\.\i\.isPremium\(\i\.\i\.getCurrentUser\(\)\)/,
|
match: /\i\.\i\.isPremium\(\i\.\i\.getCurrentUser\(\)\)/,
|
||||||
replace: "true"
|
replace: "true"
|
||||||
|
@ -471,12 +472,12 @@ export default definePlugin({
|
||||||
const premiumType = UserStore?.getCurrentUser()?.premiumType ?? 0;
|
const premiumType = UserStore?.getCurrentUser()?.premiumType ?? 0;
|
||||||
if (premiumType === 2 || backgroundGradientPresetId == null) return original();
|
if (premiumType === 2 || backgroundGradientPresetId == null) return original();
|
||||||
|
|
||||||
if (!PreloadedUserSettingsActionCreators || !AppearanceSettingsActionCreators || !ClientThemeSettingsActionsCreators || !ProtoUtils) return;
|
if (!PreloadedUserSettingsActionCreators || !AppearanceSettingsActionCreators || !ClientThemeSettingsActionsCreators || !BINARY_READ_OPTIONS) return;
|
||||||
|
|
||||||
const currentAppearanceSettings = PreloadedUserSettingsActionCreators.getCurrentValue().appearance;
|
const currentAppearanceSettings = PreloadedUserSettingsActionCreators.getCurrentValue().appearance;
|
||||||
|
|
||||||
const newAppearanceProto = currentAppearanceSettings != null
|
const newAppearanceProto = currentAppearanceSettings != null
|
||||||
? AppearanceSettingsActionCreators.fromBinary(AppearanceSettingsActionCreators.toBinary(currentAppearanceSettings), ProtoUtils.BINARY_READ_OPTIONS)
|
? AppearanceSettingsActionCreators.fromBinary(AppearanceSettingsActionCreators.toBinary(currentAppearanceSettings), BINARY_READ_OPTIONS)
|
||||||
: AppearanceSettingsActionCreators.create();
|
: AppearanceSettingsActionCreators.create();
|
||||||
|
|
||||||
newAppearanceProto.theme = theme;
|
newAppearanceProto.theme = theme;
|
||||||
|
@ -815,8 +816,7 @@ export default definePlugin({
|
||||||
if (e.type === 0) return true;
|
if (e.type === 0) return true;
|
||||||
if (e.available === false) return false;
|
if (e.available === false) return false;
|
||||||
|
|
||||||
const isUnusableRoleSubEmoji = RoleSubscriptionEmojiUtils.isUnusableRoleSubscriptionEmojiOriginal ?? RoleSubscriptionEmojiUtils.isUnusableRoleSubscriptionEmoji;
|
if (isUnusableRoleSubscriptionEmoji(e, this.guildId, true)) return false;
|
||||||
if (isUnusableRoleSubEmoji(e, this.guildId)) return false;
|
|
||||||
|
|
||||||
if (this.canUseEmotes)
|
if (this.canUseEmotes)
|
||||||
return e.guildId === this.guildId || hasExternalEmojiPerms(channelId);
|
return e.guildId === this.guildId || hasExternalEmojiPerms(channelId);
|
||||||
|
|
|
@ -111,7 +111,7 @@ interface ProfileModalProps {
|
||||||
const ColorPicker = findComponentByCode<ColorPickerProps>(".Messages.USER_SETTINGS_PROFILE_COLOR_SELECT_COLOR", ".BACKGROUND_PRIMARY)");
|
const ColorPicker = findComponentByCode<ColorPickerProps>(".Messages.USER_SETTINGS_PROFILE_COLOR_SELECT_COLOR", ".BACKGROUND_PRIMARY)");
|
||||||
const ProfileModal = findComponentByCode<ProfileModalProps>('"ProfileCustomizationPreview"');
|
const ProfileModal = findComponentByCode<ProfileModalProps>('"ProfileCustomizationPreview"');
|
||||||
|
|
||||||
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"], /createPromise:\(\)=>\i\.\i\("?(.+?)"?\).then\(\i\.bind\(\i,"?(.+?)"?\)\)/);
|
||||||
|
|
||||||
export default definePlugin({
|
export default definePlugin({
|
||||||
name: "FakeProfileThemes",
|
name: "FakeProfileThemes",
|
||||||
|
|
|
@ -50,7 +50,7 @@ export default definePlugin({
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
find: "MAX_AUTOCOMPLETE_RESULTS+",
|
find: "numLockedEmojiResults:",
|
||||||
replacement: [
|
replacement: [
|
||||||
// set maxCount to Infinity so our sortEmojis callback gets the entire list, not just the first 10
|
// set maxCount to Infinity so our sortEmojis callback gets the entire list, not just the first 10
|
||||||
// and remove Discord's emojiResult slice, storing the endIndex on the array for us to use later
|
// and remove Discord's emojiResult slice, storing the endIndex on the array for us to use later
|
||||||
|
|
|
@ -27,7 +27,7 @@ export default definePlugin({
|
||||||
authors: [Devs.D3SOX, Devs.Nickyux],
|
authors: [Devs.D3SOX, Devs.Nickyux],
|
||||||
patches: [
|
patches: [
|
||||||
{
|
{
|
||||||
find: "AVATAR_DECORATION_PADDING:",
|
find: ".PREMIUM_GUILD_SUBSCRIPTION_TOOLTIP",
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /,isOwner:(\i),/,
|
match: /,isOwner:(\i),/,
|
||||||
replace: ",_isOwner:$1=$self.isGuildOwner(e),"
|
replace: ",_isOwner:$1=$self.isGuildOwner(e),"
|
||||||
|
|
|
@ -16,14 +16,12 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { ApplicationCommandInputType, ApplicationCommandOptionType, findOption, sendBotMessage } from "@api/Commands";
|
import { ApplicationCommandInputType, sendBotMessage } from "@api/Commands";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
import definePlugin from "@utils/types";
|
import definePlugin from "@utils/types";
|
||||||
import { findByProps } from "@webpack";
|
import { findByProps } from "@webpack";
|
||||||
import { Constants, RestAPI, UserStore } from "@webpack/common";
|
|
||||||
|
|
||||||
const FriendInvites = findByProps("createFriendInvite");
|
const FriendInvites = findByProps("createFriendInvite");
|
||||||
const { uuid4 } = findByProps("uuid4");
|
|
||||||
|
|
||||||
export default definePlugin({
|
export default definePlugin({
|
||||||
name: "FriendInvites",
|
name: "FriendInvites",
|
||||||
|
@ -35,47 +33,9 @@ export default definePlugin({
|
||||||
name: "create friend invite",
|
name: "create friend invite",
|
||||||
description: "Generates a friend invite link.",
|
description: "Generates a friend invite link.",
|
||||||
inputType: ApplicationCommandInputType.BOT,
|
inputType: ApplicationCommandInputType.BOT,
|
||||||
options: [{
|
|
||||||
name: "Uses",
|
|
||||||
description: "How many uses?",
|
|
||||||
choices: [
|
|
||||||
{ label: "1", name: "1", value: "1" },
|
|
||||||
{ label: "5", name: "5", value: "5" }
|
|
||||||
],
|
|
||||||
required: false,
|
|
||||||
type: ApplicationCommandOptionType.INTEGER
|
|
||||||
}],
|
|
||||||
|
|
||||||
execute: async (args, ctx) => {
|
execute: async (args, ctx) => {
|
||||||
const uses = findOption<number>(args, "Uses", 5);
|
const invite = await FriendInvites.createFriendInvite();
|
||||||
|
|
||||||
if (uses === 1 && !UserStore.getCurrentUser().phone)
|
|
||||||
return sendBotMessage(ctx.channel.id, {
|
|
||||||
content: "You need to have a phone number connected to your account to create a friend invite with 1 use!"
|
|
||||||
});
|
|
||||||
|
|
||||||
let invite: any;
|
|
||||||
if (uses === 1) {
|
|
||||||
const random = uuid4();
|
|
||||||
const { body: { invite_suggestions } } = await RestAPI.post({
|
|
||||||
url: Constants.Endpoints.FRIEND_FINDER,
|
|
||||||
body: {
|
|
||||||
modified_contacts: {
|
|
||||||
[random]: [1, "", ""]
|
|
||||||
},
|
|
||||||
phone_contact_methods_count: 1
|
|
||||||
}
|
|
||||||
});
|
|
||||||
invite = await FriendInvites.createFriendInvite({
|
|
||||||
code: invite_suggestions[0][3],
|
|
||||||
recipient_phone_number_or_email: random,
|
|
||||||
contact_visibility: 1,
|
|
||||||
filter_visibilities: [],
|
|
||||||
filtered_invite_suggestions_index: 1
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
invite = await FriendInvites.createFriendInvite();
|
|
||||||
}
|
|
||||||
|
|
||||||
sendBotMessage(ctx.channel.id, {
|
sendBotMessage(ctx.channel.id, {
|
||||||
content: `
|
content: `
|
||||||
|
|
|
@ -4,21 +4,23 @@
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { classNameFactory } from "@api/Styles";
|
||||||
import ErrorBoundary from "@components/ErrorBoundary";
|
import ErrorBoundary from "@components/ErrorBoundary";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
import { getCurrentChannel } from "@utils/discord";
|
import { getCurrentChannel } from "@utils/discord";
|
||||||
import { Logger } from "@utils/Logger";
|
import { Logger } from "@utils/Logger";
|
||||||
import { classes } from "@utils/misc";
|
import { classes } from "@utils/misc";
|
||||||
import definePlugin from "@utils/types";
|
import definePlugin from "@utils/types";
|
||||||
import { findByProps } from "@webpack";
|
import { findByCode, findByProps } from "@webpack";
|
||||||
import { Heading, React, RelationshipStore, Text } from "@webpack/common";
|
import { Heading, React, RelationshipStore, Text } from "@webpack/common";
|
||||||
|
|
||||||
const container = findByProps("memberSinceWrapper");
|
const container = findByProps("memberSinceWrapper");
|
||||||
const { getCreatedAtDate } = findByProps("getCreatedAtDate");
|
const getCreatedAtDate = findByCode('month:"short",day:"numeric"');
|
||||||
const clydeMoreInfo = findByProps("clydeMoreInfo");
|
|
||||||
const locale = findByProps("getLocale");
|
const locale = findByProps("getLocale");
|
||||||
const lastSection = findByProps("lastSection");
|
const lastSection = findByProps("lastSection");
|
||||||
|
|
||||||
|
const cl = classNameFactory("vc-friendssince-");
|
||||||
|
|
||||||
export default definePlugin({
|
export default definePlugin({
|
||||||
name: "FriendsSince",
|
name: "FriendsSince",
|
||||||
description: "Shows when you became friends with someone in the user popout",
|
description: "Shows when you became friends with someone in the user popout",
|
||||||
|
@ -26,17 +28,17 @@ export default definePlugin({
|
||||||
patches: [
|
patches: [
|
||||||
// User popup
|
// User popup
|
||||||
{
|
{
|
||||||
find: ".AnalyticsSections.USER_PROFILE}",
|
find: ".USER_PROFILE}};return",
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /\i.default,\{userId:(\i.id).{0,30}}\)/,
|
match: /,{userId:(\i.id).{0,30}}\)/,
|
||||||
replace: "$&,$self.friendsSince({ userId: $1 })"
|
replace: "$&,$self.friendsSince({ userId: $1 })"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// User DMs "User Profile" popup in the right
|
// User DMs "User Profile" popup in the right
|
||||||
{
|
{
|
||||||
find: ".UserPopoutUpsellSource.PROFILE_PANEL,",
|
find: ".PROFILE_PANEL,",
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /\i.default,\{userId:([^,]+?)}\)/,
|
match: /,{userId:([^,]+?)}\)/,
|
||||||
replace: "$&,$self.friendsSince({ userId: $1 })"
|
replace: "$&,$self.friendsSince({ userId: $1 })"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -69,7 +71,7 @@ export default definePlugin({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={lastSection.section}>
|
<div className={lastSection.section}>
|
||||||
<Heading variant="eyebrow" className={clydeMoreInfo.title}>
|
<Heading variant="eyebrow" className={cl("title")}>
|
||||||
Friends Since
|
Friends Since
|
||||||
</Heading>
|
</Heading>
|
||||||
|
|
||||||
|
@ -86,7 +88,7 @@ export default definePlugin({
|
||||||
<path d="M3 5v-.75C3 3.56 3.56 3 4.25 3s1.24.56 1.33 1.25C6.12 8.65 9.46 12 13 12h1a8 8 0 0 1 8 8 2 2 0 0 1-2 2 .21.21 0 0 1-.2-.15 7.65 7.65 0 0 0-1.32-2.3c-.15-.2-.42-.06-.39.17l.25 2c.02.15-.1.28-.25.28H9a2 2 0 0 1-2-2v-2.22c0-1.57-.67-3.05-1.53-4.37A15.85 15.85 0 0 1 3 5Z" />
|
<path d="M3 5v-.75C3 3.56 3.56 3 4.25 3s1.24.56 1.33 1.25C6.12 8.65 9.46 12 13 12h1a8 8 0 0 1 8 8 2 2 0 0 1-2 2 .21.21 0 0 1-.2-.15 7.65 7.65 0 0 0-1.32-2.3c-.15-.2-.42-.06-.39.17l.25 2c.02.15-.1.28-.25.28H9a2 2 0 0 1-2-2v-2.22c0-1.57-.67-3.05-1.53-4.37A15.85 15.85 0 0 1 3 5Z" />
|
||||||
</svg>
|
</svg>
|
||||||
)}
|
)}
|
||||||
<Text variant="text-sm/normal" className={classes(clydeMoreInfo.body, textClassName)}>
|
<Text variant="text-sm/normal" className={classes(cl("body"), textClassName)}>
|
||||||
{getCreatedAtDate(friendsSince, locale.getLocale())}
|
{getCreatedAtDate(friendsSince, locale.getLocale())}
|
||||||
</Text>
|
</Text>
|
||||||
</div>
|
</div>
|
||||||
|
|
12
src/plugins/friendsSince/styles.css
Normal file
12
src/plugins/friendsSince/styles.css
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
/* copy pasted from discord */
|
||||||
|
|
||||||
|
.vc-friendssince-title {
|
||||||
|
display: flex;
|
||||||
|
font-weight: 700;
|
||||||
|
margin-bottom: 6px
|
||||||
|
}
|
||||||
|
|
||||||
|
.vc-friendssince-body {
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 18px
|
||||||
|
}
|
|
@ -18,16 +18,18 @@
|
||||||
|
|
||||||
import { definePluginSettings } from "@api/Settings";
|
import { definePluginSettings } from "@api/Settings";
|
||||||
import { disableStyle, enableStyle } from "@api/Styles";
|
import { disableStyle, enableStyle } from "@api/Styles";
|
||||||
|
import { getUserSettingDefinitionLazy } from "@api/UserSettingDefinitions";
|
||||||
import ErrorBoundary from "@components/ErrorBoundary";
|
import ErrorBoundary from "@components/ErrorBoundary";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
import definePlugin, { OptionType } from "@utils/types";
|
import definePlugin, { OptionType } from "@utils/types";
|
||||||
import { findComponentByCode } from "@webpack";
|
import { findComponentByCode } from "@webpack";
|
||||||
import { StatusSettingsStores } from "@webpack/common";
|
|
||||||
|
|
||||||
import style from "./style.css?managed";
|
import style from "./style.css?managed";
|
||||||
|
|
||||||
const Button = findComponentByCode("Button.Sizes.NONE,disabled:");
|
const Button = findComponentByCode("Button.Sizes.NONE,disabled:");
|
||||||
|
|
||||||
|
const ShowCurrentGame = getUserSettingDefinitionLazy<boolean>("status", "showCurrentGame")!;
|
||||||
|
|
||||||
function makeIcon(showCurrentGame?: boolean) {
|
function makeIcon(showCurrentGame?: boolean) {
|
||||||
const { oldIcon } = settings.use(["oldIcon"]);
|
const { oldIcon } = settings.use(["oldIcon"]);
|
||||||
|
|
||||||
|
@ -60,7 +62,7 @@ function makeIcon(showCurrentGame?: boolean) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function GameActivityToggleButton() {
|
function GameActivityToggleButton() {
|
||||||
const showCurrentGame = StatusSettingsStores.ShowCurrentGame.useSetting();
|
const showCurrentGame = ShowCurrentGame.useSetting();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
|
@ -68,7 +70,7 @@ function GameActivityToggleButton() {
|
||||||
icon={makeIcon(showCurrentGame)}
|
icon={makeIcon(showCurrentGame)}
|
||||||
role="switch"
|
role="switch"
|
||||||
aria-checked={!showCurrentGame}
|
aria-checked={!showCurrentGame}
|
||||||
onClick={() => StatusSettingsStores.ShowCurrentGame.updateSetting(old => !old)}
|
onClick={() => ShowCurrentGame.updateSetting(old => !old)}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -85,6 +87,7 @@ export default definePlugin({
|
||||||
name: "GameActivityToggle",
|
name: "GameActivityToggle",
|
||||||
description: "Adds a button next to the mic and deafen button to toggle game activity.",
|
description: "Adds a button next to the mic and deafen button to toggle game activity.",
|
||||||
authors: [Devs.Nuckyz, Devs.RuukuLada],
|
authors: [Devs.Nuckyz, Devs.RuukuLada],
|
||||||
|
dependencies: ["UserSettingDefinitionsAPI"],
|
||||||
settings,
|
settings,
|
||||||
|
|
||||||
patches: [
|
patches: [
|
||||||
|
|
|
@ -19,9 +19,7 @@
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
import { insertTextIntoChatInputBox } from "@utils/discord";
|
import { insertTextIntoChatInputBox } from "@utils/discord";
|
||||||
import definePlugin from "@utils/types";
|
import definePlugin from "@utils/types";
|
||||||
import { findByProps } from "@webpack";
|
import { ExpressionPickerStore } from "@webpack/common";
|
||||||
|
|
||||||
const { closeExpressionPicker } = findByProps("closeExpressionPicker");
|
|
||||||
|
|
||||||
export default definePlugin({
|
export default definePlugin({
|
||||||
name: "GifPaste",
|
name: "GifPaste",
|
||||||
|
@ -39,7 +37,7 @@ export default definePlugin({
|
||||||
handleSelect(gif?: { url: string; }) {
|
handleSelect(gif?: { url: string; }) {
|
||||||
if (gif) {
|
if (gif) {
|
||||||
insertTextIntoChatInputBox(gif.url + " ");
|
insertTextIntoChatInputBox(gif.url + " ");
|
||||||
closeExpressionPicker();
|
ExpressionPickerStore.closeExpressionPicker();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
import { definePluginSettings } from "@api/Settings";
|
import { definePluginSettings } from "@api/Settings";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
import definePlugin, { OptionType } from "@utils/types";
|
import definePlugin, { OptionType } from "@utils/types";
|
||||||
import { findByProps } from "@webpack";
|
import { find } from "@webpack";
|
||||||
import { ContextMenuApi, FluxDispatcher, Menu, MessageActions } from "@webpack/common";
|
import { ContextMenuApi, FluxDispatcher, Menu, MessageActions } from "@webpack/common";
|
||||||
import { Channel, Message } from "discord-types/general";
|
import { Channel, Message } from "discord-types/general";
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ const settings = definePluginSettings({
|
||||||
unholyMultiGreetEnabled?: boolean;
|
unholyMultiGreetEnabled?: boolean;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const { WELCOME_STICKERS } = findByProps("WELCOME_STICKERS");
|
const WELCOME_STICKERS = find(m => Array.isArray(m) && m[0]?.name === "Wave");
|
||||||
|
|
||||||
function greet(channel: Channel, message: Message, stickers: string[]) {
|
function greet(channel: Channel, message: Message, stickers: string[]) {
|
||||||
const options = MessageActions.getSendMessageOptionsForReply({
|
const options = MessageActions.getSendMessageOptionsForReply({
|
||||||
|
|
|
@ -6,13 +6,14 @@
|
||||||
|
|
||||||
import * as DataStore from "@api/DataStore";
|
import * as DataStore from "@api/DataStore";
|
||||||
import { definePluginSettings, Settings } from "@api/Settings";
|
import { definePluginSettings, Settings } from "@api/Settings";
|
||||||
|
import { getUserSettingDefinitionLazy } from "@api/UserSettingDefinitions";
|
||||||
import ErrorBoundary from "@components/ErrorBoundary";
|
import ErrorBoundary from "@components/ErrorBoundary";
|
||||||
import { Flex } from "@components/Flex";
|
import { Flex } from "@components/Flex";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
import { Margins } from "@utils/margins";
|
import { Margins } from "@utils/margins";
|
||||||
import definePlugin, { OptionType } from "@utils/types";
|
import definePlugin, { OptionType } from "@utils/types";
|
||||||
import { findStore } from "@webpack";
|
import { findStore } from "@webpack";
|
||||||
import { Button, Forms, showToast, StatusSettingsStores, TextInput, Toasts, Tooltip, useEffect, useState } from "webpack/common";
|
import { Button, Forms, showToast, TextInput, Toasts, Tooltip, useEffect, useState } from "webpack/common";
|
||||||
|
|
||||||
const enum ActivitiesTypes {
|
const enum ActivitiesTypes {
|
||||||
Game,
|
Game,
|
||||||
|
@ -27,6 +28,8 @@ interface IgnoredActivity {
|
||||||
|
|
||||||
const RunningGameStore = findStore("RunningGameStore");
|
const RunningGameStore = findStore("RunningGameStore");
|
||||||
|
|
||||||
|
const ShowCurrentGame = getUserSettingDefinitionLazy("status", "showCurrentGame")!;
|
||||||
|
|
||||||
function ToggleIcon(activity: IgnoredActivity, tooltipText: string, path: string, fill: string) {
|
function ToggleIcon(activity: IgnoredActivity, tooltipText: string, path: string, fill: string) {
|
||||||
return (
|
return (
|
||||||
<Tooltip text={tooltipText}>
|
<Tooltip text={tooltipText}>
|
||||||
|
@ -68,7 +71,7 @@ function handleActivityToggle(e: React.MouseEvent<HTMLButtonElement, MouseEvent>
|
||||||
else settings.store.ignoredActivities = getIgnoredActivities().filter((_, index) => index !== ignoredActivityIndex);
|
else settings.store.ignoredActivities = getIgnoredActivities().filter((_, index) => index !== ignoredActivityIndex);
|
||||||
|
|
||||||
// Trigger activities recalculation
|
// Trigger activities recalculation
|
||||||
StatusSettingsStores.ShowCurrentGame.updateSetting(old => old);
|
ShowCurrentGame.updateSetting(old => old);
|
||||||
}
|
}
|
||||||
|
|
||||||
function ImportCustomRPCComponent() {
|
function ImportCustomRPCComponent() {
|
||||||
|
@ -205,6 +208,7 @@ export default definePlugin({
|
||||||
name: "IgnoreActivities",
|
name: "IgnoreActivities",
|
||||||
authors: [Devs.Nuckyz],
|
authors: [Devs.Nuckyz],
|
||||||
description: "Ignore activities from showing up on your status ONLY. You can configure which ones are specifically ignored from the Registered Games and Activities tabs, or use the general settings below.",
|
description: "Ignore activities from showing up on your status ONLY. You can configure which ones are specifically ignored from the Registered Games and Activities tabs, or use the general settings below.",
|
||||||
|
dependencies: ["UserSettingDefinitionsAPI"],
|
||||||
|
|
||||||
settings,
|
settings,
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,8 @@ export default definePlugin({
|
||||||
{
|
{
|
||||||
find: "unknownUserMentionPlaceholder:",
|
find: "unknownUserMentionPlaceholder:",
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /\(0,\i\.isEmbedInline\)\(\i\)/,
|
// SimpleEmbedTypes.has(embed.type) && isEmbedInline(embed)
|
||||||
|
match: /\i\.has\(\i\.type\)&&\(0,\i\.\i\)\(\i\)/,
|
||||||
replace: "false",
|
replace: "false",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,11 +19,10 @@
|
||||||
import { definePluginSettings } from "@api/Settings";
|
import { definePluginSettings } from "@api/Settings";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
import definePlugin, { OptionType } from "@utils/types";
|
import definePlugin, { OptionType } from "@utils/types";
|
||||||
import { findByProps, findStore } from "@webpack";
|
import { findStore } from "@webpack";
|
||||||
import { ChannelStore, FluxDispatcher, GuildStore, RelationshipStore, SnowflakeUtils, UserStore } from "@webpack/common";
|
import { ChannelStore, Constants, FluxDispatcher, GuildStore, RelationshipStore, SnowflakeUtils, UserStore } from "@webpack/common";
|
||||||
|
|
||||||
const UserAffinitiesStore = findStore("UserAffinitiesStore");
|
const UserAffinitiesStore = findStore("UserAffinitiesStore");
|
||||||
const { FriendsSections } = findByProps("FriendsSections");
|
|
||||||
|
|
||||||
const settings = definePluginSettings({
|
const settings = definePluginSettings({
|
||||||
sortByAffinity: {
|
sortByAffinity: {
|
||||||
|
@ -75,7 +74,7 @@ export default definePlugin({
|
||||||
},
|
},
|
||||||
// Piggyback relationship fetch
|
// Piggyback relationship fetch
|
||||||
{
|
{
|
||||||
find: ".fetchRelationships()",
|
find: '"FriendsStore',
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /(\i\.\i)\.fetchRelationships\(\)/,
|
match: /(\i\.\i)\.fetchRelationships\(\)/,
|
||||||
// This relationship fetch is actually completely useless, but whatevs
|
// This relationship fetch is actually completely useless, but whatevs
|
||||||
|
@ -177,6 +176,6 @@ export default definePlugin({
|
||||||
},
|
},
|
||||||
|
|
||||||
start() {
|
start() {
|
||||||
FriendsSections.IMPLICIT = "IMPLICIT";
|
Constants.FriendsSections.IMPLICIT = "IMPLICIT";
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
import { registerCommand, unregisterCommand } from "@api/Commands";
|
import { registerCommand, unregisterCommand } from "@api/Commands";
|
||||||
import { addContextMenuPatch, removeContextMenuPatch } from "@api/ContextMenu";
|
import { addContextMenuPatch, removeContextMenuPatch } from "@api/ContextMenu";
|
||||||
import { Settings } from "@api/Settings";
|
import { Settings } from "@api/Settings";
|
||||||
import { onceDefined } from "@shared/onceDefined";
|
|
||||||
import { Logger } from "@utils/Logger";
|
import { Logger } from "@utils/Logger";
|
||||||
import { canonicalizeFind } from "@utils/patches";
|
import { canonicalizeFind } from "@utils/patches";
|
||||||
import { Patch, Plugin, ReporterTestable, StartAt } from "@utils/types";
|
import { Patch, Plugin, ReporterTestable, StartAt } from "@utils/types";
|
||||||
|
@ -34,7 +33,7 @@ const logger = new Logger("PluginManager", "#a6d189");
|
||||||
|
|
||||||
export const PMLogger = logger;
|
export const PMLogger = logger;
|
||||||
export const plugins = Plugins;
|
export const plugins = Plugins;
|
||||||
export let patches = [] as Patch[];
|
export const patches = [] as Patch[];
|
||||||
|
|
||||||
/** Whether we have subscribed to flux events of all the enabled plugins when FluxDispatcher was ready */
|
/** Whether we have subscribed to flux events of all the enabled plugins when FluxDispatcher was ready */
|
||||||
let enabledPluginsSubscribedFlux = false;
|
let enabledPluginsSubscribedFlux = false;
|
||||||
|
@ -43,16 +42,6 @@ const subscribedFluxEventsPlugins = new Set<string>();
|
||||||
const pluginsValues = Object.values(Plugins);
|
const pluginsValues = Object.values(Plugins);
|
||||||
const settings = Settings.plugins;
|
const settings = Settings.plugins;
|
||||||
|
|
||||||
const forceDisabled = new Set([
|
|
||||||
"MessageLogger",
|
|
||||||
"ShowHiddenChannels",
|
|
||||||
"MoreUserTags",
|
|
||||||
"Decor",
|
|
||||||
"IgnoreActivities",
|
|
||||||
"NoBlockedMessages",
|
|
||||||
"BetterFolders",
|
|
||||||
"NoPendingCount"
|
|
||||||
]);
|
|
||||||
export function isPluginEnabled(p: string) {
|
export function isPluginEnabled(p: string) {
|
||||||
return (
|
return (
|
||||||
Plugins[p]?.required ||
|
Plugins[p]?.required ||
|
||||||
|
@ -133,17 +122,9 @@ for (const p of pluginsValues) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onceDefined(window, "GLOBAL_ENV", v => {
|
|
||||||
if (v.SENTRY_TAGS.buildId !== "366c746173a6ca0a801e9f4a4d7b6745e6de45d4") {
|
|
||||||
patches = patches.filter(p => !forceDisabled.has(p.plugin));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export const startAllPlugins = traceFunction("startAllPlugins", function startAllPlugins(target: StartAt) {
|
export const startAllPlugins = traceFunction("startAllPlugins", function startAllPlugins(target: StartAt) {
|
||||||
logger.info(`Starting plugins (stage ${target})`);
|
logger.info(`Starting plugins (stage ${target})`);
|
||||||
for (const name in Plugins) {
|
for (const name in Plugins) {
|
||||||
if (window.GLOBAL_ENV?.SENTRY_TAGS.buildId !== "366c746173a6ca0a801e9f4a4d7b6745e6de45d4" && forceDisabled.has(name)) continue;
|
|
||||||
|
|
||||||
if (isPluginEnabled(name) && (!IS_REPORTER || isReporterTestable(Plugins[name], ReporterTestable.Start))) {
|
if (isPluginEnabled(name) && (!IS_REPORTER || isReporterTestable(Plugins[name], ReporterTestable.Start))) {
|
||||||
const p = Plugins[name];
|
const p = Plugins[name];
|
||||||
|
|
||||||
|
@ -214,7 +195,7 @@ export function subscribeAllPluginsFluxEvents(fluxDispatcher: typeof FluxDispatc
|
||||||
}
|
}
|
||||||
|
|
||||||
export const startPlugin = traceFunction("startPlugin", function startPlugin(p: Plugin) {
|
export const startPlugin = traceFunction("startPlugin", function startPlugin(p: Plugin) {
|
||||||
const { name, commands, flux, contextMenus } = p;
|
const { name, commands, contextMenus } = p;
|
||||||
|
|
||||||
if (p.start) {
|
if (p.start) {
|
||||||
logger.info("Starting plugin", name);
|
logger.info("Starting plugin", name);
|
||||||
|
@ -260,7 +241,7 @@ export const startPlugin = traceFunction("startPlugin", function startPlugin(p:
|
||||||
}, p => `startPlugin ${p.name}`);
|
}, p => `startPlugin ${p.name}`);
|
||||||
|
|
||||||
export const stopPlugin = traceFunction("stopPlugin", function stopPlugin(p: Plugin) {
|
export const stopPlugin = traceFunction("stopPlugin", function stopPlugin(p: Plugin) {
|
||||||
const { name, commands, flux, contextMenus } = p;
|
const { name, commands, contextMenus } = p;
|
||||||
|
|
||||||
if (p.stop) {
|
if (p.stop) {
|
||||||
logger.info("Stopping plugin", name);
|
logger.info("Stopping plugin", name);
|
||||||
|
|
|
@ -10,19 +10,21 @@ import { findByProps } from "@webpack";
|
||||||
|
|
||||||
const linkRegex = /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)/;
|
const linkRegex = /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)/;
|
||||||
|
|
||||||
const { SlateTransforms } = findByProps("SlateTransforms");
|
const SlateTransforms = findByProps("insertText", "selectCommandOption");
|
||||||
|
|
||||||
export default definePlugin({
|
export default definePlugin({
|
||||||
name: "MaskedLinkPaste",
|
name: "MaskedLinkPaste",
|
||||||
authors: [Devs.TheSun],
|
authors: [Devs.TheSun],
|
||||||
description: "Pasting a link while having text selected will paste a hyperlink",
|
description: "Pasting a link while having text selected will paste a hyperlink",
|
||||||
patches: [{
|
patches: [
|
||||||
find: ".selection,preventEmojiSurrogates:",
|
{
|
||||||
replacement: {
|
find: ".selection,preventEmojiSurrogates:",
|
||||||
match: /(?<=SlateTransforms.delete.{0,50})(\i)\.insertText\((\i)\)/,
|
replacement: {
|
||||||
replace: "$self.handlePaste($1, $2, () => $&)"
|
match: /(?<=\i.delete.{0,50})(\i)\.insertText\((\i)\)/,
|
||||||
|
replace: "$self.handlePaste($1, $2, () => $&)"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}],
|
],
|
||||||
|
|
||||||
handlePaste(editor, content: string, originalBehavior: () => void) {
|
handlePaste(editor, content: string, originalBehavior: () => void) {
|
||||||
if (content && linkRegex.test(content) && editor.operations?.[0]?.type === "remove_text") {
|
if (content && linkRegex.test(content) && editor.operations?.[0]?.type === "remove_text") {
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
import { addAccessory, removeAccessory } from "@api/MessageAccessories";
|
import { addAccessory, removeAccessory } from "@api/MessageAccessories";
|
||||||
import { updateMessage } from "@api/MessageUpdater";
|
import { updateMessage } from "@api/MessageUpdater";
|
||||||
import { definePluginSettings } from "@api/Settings";
|
import { definePluginSettings } from "@api/Settings";
|
||||||
|
import { getUserSettingDefinitionLazy } from "@api/UserSettingDefinitions";
|
||||||
import ErrorBoundary from "@components/ErrorBoundary";
|
import ErrorBoundary from "@components/ErrorBoundary";
|
||||||
import { Devs } from "@utils/constants.js";
|
import { Devs } from "@utils/constants.js";
|
||||||
import { classes } from "@utils/misc";
|
import { classes } from "@utils/misc";
|
||||||
|
@ -37,7 +38,6 @@ import {
|
||||||
PermissionStore,
|
PermissionStore,
|
||||||
RestAPI,
|
RestAPI,
|
||||||
Text,
|
Text,
|
||||||
TextAndImagesSettingsStores,
|
|
||||||
UserStore
|
UserStore
|
||||||
} from "@webpack/common";
|
} from "@webpack/common";
|
||||||
import { Channel, Message } from "discord-types/general";
|
import { Channel, Message } from "discord-types/general";
|
||||||
|
@ -49,11 +49,13 @@ const messageCache = new Map<string, {
|
||||||
|
|
||||||
const Embed = findComponentByCode(".inlineMediaEmbed");
|
const Embed = findComponentByCode(".inlineMediaEmbed");
|
||||||
const AutoModEmbed = findComponentByCode(".withFooter]:", "childrenMessageContent:");
|
const AutoModEmbed = findComponentByCode(".withFooter]:", "childrenMessageContent:");
|
||||||
const ChannelMessage = findComponentByCode("renderSimpleAccessories)");
|
const ChannelMessage = findComponentByCode("childrenExecutedCommand:", ".hideAccessories");
|
||||||
|
|
||||||
const SearchResultClasses = findByProps("message", "searchResult");
|
const SearchResultClasses = findByProps("message", "searchResult");
|
||||||
const EmbedClasses = findByProps("embedAuthorIcon", "embedAuthor", "embedAuthor");
|
const EmbedClasses = findByProps("embedAuthorIcon", "embedAuthor", "embedAuthor");
|
||||||
|
|
||||||
|
const MessageDisplayCompact = getUserSettingDefinitionLazy("textAndImages", "messageDisplayCompact")!;
|
||||||
|
|
||||||
const messageLinkRegex = /(?<!<)https?:\/\/(?:\w+\.)?discord(?:app)?\.com\/channels\/(?:\d{17,20}|@me)\/(\d{17,20})\/(\d{17,20})/g;
|
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\//;
|
const tenorRegex = /^https:\/\/(?:www\.)?tenor\.com\//;
|
||||||
|
|
||||||
|
@ -280,7 +282,7 @@ function getChannelLabelAndIconUrl(channel: Channel) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function ChannelMessageEmbedAccessory({ message, channel }: MessageEmbedProps): JSX.Element | null {
|
function ChannelMessageEmbedAccessory({ message, channel }: MessageEmbedProps): JSX.Element | null {
|
||||||
const compact = TextAndImagesSettingsStores.MessageDisplayCompact.useSetting();
|
const compact = MessageDisplayCompact.useSetting();
|
||||||
|
|
||||||
const dmReceiver = UserStore.getUser(ChannelStore.getChannel(channel.id).recipients?.[0]);
|
const dmReceiver = UserStore.getUser(ChannelStore.getChannel(channel.id).recipients?.[0]);
|
||||||
|
|
||||||
|
@ -316,7 +318,7 @@ function ChannelMessageEmbedAccessory({ message, channel }: MessageEmbedProps):
|
||||||
|
|
||||||
function AutomodEmbedAccessory(props: MessageEmbedProps): JSX.Element | null {
|
function AutomodEmbedAccessory(props: MessageEmbedProps): JSX.Element | null {
|
||||||
const { message, channel } = props;
|
const { message, channel } = props;
|
||||||
const compact = TextAndImagesSettingsStores.MessageDisplayCompact.useSetting();
|
const compact = MessageDisplayCompact.useSetting();
|
||||||
const images = getImages(message);
|
const images = getImages(message);
|
||||||
const { parse } = Parser;
|
const { parse } = Parser;
|
||||||
|
|
||||||
|
@ -363,7 +365,7 @@ export default definePlugin({
|
||||||
name: "MessageLinkEmbeds",
|
name: "MessageLinkEmbeds",
|
||||||
description: "Adds a preview to messages that link another message",
|
description: "Adds a preview to messages that link another message",
|
||||||
authors: [Devs.TheSun, Devs.Ven, Devs.RyanCaoDev],
|
authors: [Devs.TheSun, Devs.Ven, Devs.RyanCaoDev],
|
||||||
dependencies: ["MessageAccessoriesAPI", "MessageUpdaterAPI"],
|
dependencies: ["MessageAccessoriesAPI", "MessageUpdaterAPI", "UserSettingDefinitionsAPI"],
|
||||||
|
|
||||||
settings,
|
settings,
|
||||||
|
|
||||||
|
|
|
@ -22,9 +22,10 @@ import { Devs } from "@utils/constants";
|
||||||
import { LazyComponentType } from "@utils/lazyReact";
|
import { LazyComponentType } from "@utils/lazyReact";
|
||||||
import { Margins } from "@utils/margins";
|
import { Margins } from "@utils/margins";
|
||||||
import definePlugin, { OptionType } from "@utils/types";
|
import definePlugin, { OptionType } from "@utils/types";
|
||||||
import { findByProps, findComponentByCode } from "@webpack";
|
import { findByCode, findComponentByCode } from "@webpack";
|
||||||
import { Card, ChannelStore, Forms, GuildStore, PermissionsBits, Switch, TextInput, Tooltip, useState, UtilTypes } from "@webpack/common";
|
import { Card, ChannelStore, Forms, GuildStore, PermissionsBits, Switch, TextInput, Tooltip, useState } from "@webpack/common";
|
||||||
import { Channel, Message, User } from "discord-types/general";
|
import type { Permissions } from "@webpack/types";
|
||||||
|
import type { Channel, Guild, Message, User } from "discord-types/general";
|
||||||
|
|
||||||
interface Tag {
|
interface Tag {
|
||||||
// name used for identifying, must be alphanumeric + underscores
|
// name used for identifying, must be alphanumeric + underscores
|
||||||
|
@ -32,7 +33,7 @@ interface Tag {
|
||||||
// name shown on the tag itself, can be anything probably; automatically uppercase'd
|
// name shown on the tag itself, can be anything probably; automatically uppercase'd
|
||||||
displayName: string;
|
displayName: string;
|
||||||
description: string;
|
description: string;
|
||||||
permissions?: UtilTypes.Permissions[];
|
permissions?: Permissions[];
|
||||||
condition?(message: Message | null, user: User, channel: Channel): boolean;
|
condition?(message: Message | null, user: User, channel: Channel): boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,10 +53,14 @@ interface TagSettings {
|
||||||
[k: string]: TagSetting;
|
[k: string]: TagSetting;
|
||||||
}
|
}
|
||||||
|
|
||||||
// PermissionStore.computePermissions is not the same function and doesn't work here
|
// PermissionStore.computePermissions will not work here since it only gets permissions for the current user
|
||||||
const PermissionUtil = findByProps("computePermissions", "canEveryoneRole") as {
|
const computePermissions: (options: {
|
||||||
computePermissions({ ...args }): bigint;
|
user?: { id: string; } | string | null;
|
||||||
};
|
context?: Guild | Channel | null;
|
||||||
|
overwrites?: Channel["permissionOverwrites"] | null;
|
||||||
|
checkElevated?: boolean /* = true */;
|
||||||
|
excludeGuildPermissions?: boolean /* = false */;
|
||||||
|
}) => bigint = findByCode(".getCurrentUser()", ".computeLurkerPermissionsAllowList()");
|
||||||
|
|
||||||
const Tag = findComponentByCode(".DISCORD_SYSTEM_MESSAGE_BOT_TAG_TOOLTIP_OFFICIAL,") as LazyComponentType<{ 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>; };
|
||||||
|
|
||||||
|
@ -191,7 +196,7 @@ export default definePlugin({
|
||||||
patches: [
|
patches: [
|
||||||
// add tags to the tag list
|
// add tags to the tag list
|
||||||
{
|
{
|
||||||
find: "BotTagTypes:",
|
find: ".ORIGINAL_POSTER=",
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /\((\i)=\{\}\)\)\[(\i)\.BOT/,
|
match: /\((\i)=\{\}\)\)\[(\i)\.BOT/,
|
||||||
replace: "($1=$self.getTagTypes()))[$2.BOT"
|
replace: "($1=$self.getTagTypes()))[$2.BOT"
|
||||||
|
@ -220,7 +225,7 @@ export default definePlugin({
|
||||||
},
|
},
|
||||||
// in messages
|
// in messages
|
||||||
{
|
{
|
||||||
find: "renderSystemTag:",
|
find: ".Types.ORIGINAL_POSTER",
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /;return\((\(null==\i\?void 0:\i\.isSystemDM\(\).+?.Types.ORIGINAL_POSTER\)),null==(\i)\)/,
|
match: /;return\((\(null==\i\?void 0:\i\.isSystemDM\(\).+?.Types.ORIGINAL_POSTER\)),null==(\i)\)/,
|
||||||
replace: ";$1;$2=$self.getTag({...arguments[0],origType:$2,location:'chat'});return $2 == null"
|
replace: ";$1;$2=$self.getTag({...arguments[0],origType:$2,location:'chat'});return $2 == null"
|
||||||
|
@ -281,7 +286,7 @@ export default definePlugin({
|
||||||
const guild = GuildStore.getGuild(channel?.guild_id);
|
const guild = GuildStore.getGuild(channel?.guild_id);
|
||||||
if (!guild) return [];
|
if (!guild) return [];
|
||||||
|
|
||||||
const permissions = PermissionUtil.computePermissions({ user, context: guild, overwrites: channel.permissionOverwrites });
|
const permissions = computePermissions({ user, context: guild, overwrites: channel.permissionOverwrites });
|
||||||
return Object.entries(PermissionsBits)
|
return Object.entries(PermissionsBits)
|
||||||
.map(([perm, permInt]) =>
|
.map(([perm, permInt]) =>
|
||||||
permissions & permInt ? perm : ""
|
permissions & permInt ? perm : ""
|
||||||
|
@ -328,7 +333,7 @@ export default definePlugin({
|
||||||
}: {
|
}: {
|
||||||
message?: Message,
|
message?: Message,
|
||||||
user: User & { isClyde(): boolean; },
|
user: User & { isClyde(): boolean; },
|
||||||
channel?: Channel & { isForumPost(): boolean; },
|
channel?: Channel & { isForumPost(): boolean; isMediaPost(): boolean; },
|
||||||
channelId?: string;
|
channelId?: string;
|
||||||
origType?: number;
|
origType?: number;
|
||||||
location: "chat" | "not-chat";
|
location: "chat" | "not-chat";
|
||||||
|
@ -365,7 +370,7 @@ export default definePlugin({
|
||||||
tag.permissions?.some(perm => perms.includes(perm)) ||
|
tag.permissions?.some(perm => perms.includes(perm)) ||
|
||||||
(tag.condition?.(message!, user, channel))
|
(tag.condition?.(message!, user, channel))
|
||||||
) {
|
) {
|
||||||
if (channel.isForumPost() && channel.ownerId === user.id)
|
if ((channel.isForumPost() || channel.isMediaPost()) && channel.ownerId === user.id)
|
||||||
type = Tag.Types[`${tag.name}-OP`];
|
type = Tag.Types[`${tag.name}-OP`];
|
||||||
else if (user.bot && !isWebhook(message!, user) && !settings.dontShowBotTag)
|
else if (user.bot && !isWebhook(message!, user) && !settings.dontShowBotTag)
|
||||||
type = Tag.Types[`${tag.name}-BOT`];
|
type = Tag.Types[`${tag.name}-BOT`];
|
||||||
|
|
|
@ -53,7 +53,7 @@ export default definePlugin({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
find: ".UserProfileSections.USER_INFO_CONNECTIONS:",
|
find: ".USER_INFO_CONNECTIONS:case",
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /(?<={user:(\i),onClose:(\i)}\);)(?=case \i\.\i\.MUTUAL_FRIENDS)/,
|
match: /(?<={user:(\i),onClose:(\i)}\);)(?=case \i\.\i\.MUTUAL_FRIENDS)/,
|
||||||
replace: "case \"MUTUAL_GDMS\":return $self.renderMutualGDMs({user: $1, onClose: $2});"
|
replace: "case \"MUTUAL_GDMS\":return $self.renderMutualGDMs({user: $1, onClose: $2});"
|
||||||
|
|
|
@ -19,11 +19,16 @@
|
||||||
import { definePluginSettings, migratePluginSettings } from "@api/Settings";
|
import { definePluginSettings, migratePluginSettings } from "@api/Settings";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
import definePlugin, { OptionType } from "@utils/types";
|
import definePlugin, { OptionType } from "@utils/types";
|
||||||
import { findByProps } from "@webpack";
|
import { findByCode, findByProps, mapMangledModule } from "@webpack";
|
||||||
|
|
||||||
const { updateGuildNotificationSettings } = findByProps("updateGuildNotificationSettings");
|
const { updateGuildNotificationSettings } = findByProps("updateGuildNotificationSettings");
|
||||||
const { toggleShowAllChannels } = findByProps("toggleShowAllChannels");
|
const { toggleShowAllChannels } = mapMangledModule(".onboardExistingMember(", {
|
||||||
const { isOptInEnabledForGuild } = findByProps("isOptInEnabledForGuild");
|
toggleShowAllChannels: m => {
|
||||||
|
const s = String(m);
|
||||||
|
return s.length < 100 && !s.includes("onboardExistingMember") && !s.includes("getOptedInChannels");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const isOptInEnabledForGuild = findByCode(".COMMUNITY)||", ".isOptInEnabled(");
|
||||||
|
|
||||||
const settings = definePluginSettings({
|
const settings = definePluginSettings({
|
||||||
guild: {
|
guild: {
|
||||||
|
|
|
@ -18,8 +18,10 @@
|
||||||
|
|
||||||
import { definePluginSettings } from "@api/Settings";
|
import { definePluginSettings } from "@api/Settings";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
|
import { Logger } from "@utils/Logger";
|
||||||
import definePlugin, { OptionType } from "@utils/types";
|
import definePlugin, { OptionType } from "@utils/types";
|
||||||
import { findByProps } from "@webpack";
|
import { findByProps } from "@webpack";
|
||||||
|
import { Message } from "discord-types/general";
|
||||||
|
|
||||||
const RelationshipStore = findByProps("getRelationships", "isBlocked");
|
const RelationshipStore = findByProps("getRelationships", "isBlocked");
|
||||||
|
|
||||||
|
@ -62,6 +64,20 @@ export default definePlugin({
|
||||||
]
|
]
|
||||||
}))
|
}))
|
||||||
],
|
],
|
||||||
isBlocked: message =>
|
options: {
|
||||||
RelationshipStore.isBlocked(message.author.id)
|
ignoreBlockedMessages: {
|
||||||
|
description: "Completely ignores (recent) incoming messages from blocked users (locally).",
|
||||||
|
type: OptionType.BOOLEAN,
|
||||||
|
default: false,
|
||||||
|
restartNeeded: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
isBlocked(message: Message) {
|
||||||
|
try {
|
||||||
|
return RelationshipStore.isBlocked(message.author.id);
|
||||||
|
} catch (e) {
|
||||||
|
new Logger("NoBlockedMessages").error("Failed to check if user is blocked:", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -14,7 +14,7 @@ export default definePlugin({
|
||||||
|
|
||||||
patches: [
|
patches: [
|
||||||
{
|
{
|
||||||
find: "HangStatusTypes.CHILLING)",
|
find: ".CHILLING)",
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /{enableHangStatus:(\i),/,
|
match: /{enableHangStatus:(\i),/,
|
||||||
replace: "{_enableHangStatus:$1=false,"
|
replace: "{_enableHangStatus:$1=false,"
|
||||||
|
|
|
@ -27,7 +27,7 @@ export default definePlugin({
|
||||||
|
|
||||||
patches: [
|
patches: [
|
||||||
{
|
{
|
||||||
find: "isGroupableMedia:function()",
|
find: '=>"IMAGE"===',
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /=>"IMAGE"===\i\|\|"VIDEO"===\i;/,
|
match: /=>"IMAGE"===\i\|\|"VIDEO"===\i;/,
|
||||||
replace: "=>false;"
|
replace: "=>false;"
|
||||||
|
|
|
@ -64,7 +64,7 @@ export default definePlugin({
|
||||||
},
|
},
|
||||||
// New message requests hook
|
// New message requests hook
|
||||||
{
|
{
|
||||||
find: "useNewMessageRequestsCount:",
|
find: 'location:"use-message-requests-count"',
|
||||||
predicate: () => settings.store.hideMessageRequestsCount,
|
predicate: () => settings.store.hideMessageRequestsCount,
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /getNonChannelAckId\(\i\.\i\.MESSAGE_REQUESTS\).+?return /,
|
match: /getNonChannelAckId\(\i\.\i\.MESSAGE_REQUESTS\).+?return /,
|
||||||
|
|
|
@ -63,8 +63,8 @@ export default definePlugin({
|
||||||
{
|
{
|
||||||
find: "trackAnnouncementMessageLinkClicked({",
|
find: "trackAnnouncementMessageLinkClicked({",
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /(?<=handleClick:function\(\)\{return (\i)\}.+?)function \1\(.+?\)\{/,
|
match: /function (\i\(\i,\i\)\{)(?=.{0,100}trusted:)/,
|
||||||
replace: "async $& if(await $self.handleLink(...arguments)) return;"
|
replace: "async function $1 if(await $self.handleLink(...arguments)) return;"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// Make Spotify profile activity links open in app on web
|
// Make Spotify profile activity links open in app on web
|
||||||
|
|
|
@ -19,10 +19,10 @@
|
||||||
import ErrorBoundary from "@components/ErrorBoundary";
|
import ErrorBoundary from "@components/ErrorBoundary";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
import definePlugin from "@utils/types";
|
import definePlugin from "@utils/types";
|
||||||
import { findByProps } from "@webpack";
|
import { find } from "@webpack";
|
||||||
import { Constants, GuildStore, i18n, RestAPI } from "@webpack/common";
|
import { Constants, GuildStore, i18n, RestAPI } from "@webpack/common";
|
||||||
|
|
||||||
const { InvitesDisabledExperiment } = findByProps("InvitesDisabledExperiment");
|
const InvitesDisabledExperiment = find(m => m.definition?.id === "2022-07_invites_disabled");
|
||||||
|
|
||||||
function showDisableInvites(guildId: string) {
|
function showDisableInvites(guildId: string) {
|
||||||
// Once the experiment is removed, this should keep working
|
// Once the experiment is removed, this should keep working
|
||||||
|
@ -56,8 +56,8 @@ export default definePlugin({
|
||||||
replace: "children: $self.renderInvitesLabel({guildId:arguments[0].guildId,setChecked})",
|
replace: "children: $self.renderInvitesLabel({guildId:arguments[0].guildId,setChecked})",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
match: /(\i\.hasDMsDisabled\)\(\i\),\[\i,(\i)\]=\i\.useState\(\i\))/,
|
match: /\.INVITES_DISABLED\)(?=.+?\.Messages\.INVITES_PERMANENTLY_DISABLED_TIP.+?checked:(\i)).+?\[\1,(\i)\]=\i.useState\(\i\)/,
|
||||||
replace: "$1,setChecked=$2"
|
replace: "$&,setChecked=$2"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
import { definePluginSettings } from "@api/Settings";
|
import { definePluginSettings } from "@api/Settings";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
|
import { canonicalizeMatch } from "@utils/patches";
|
||||||
import definePlugin, { OptionType } from "@utils/types";
|
import definePlugin, { OptionType } from "@utils/types";
|
||||||
|
|
||||||
const settings = definePluginSettings({
|
const settings = definePluginSettings({
|
||||||
|
@ -31,7 +32,7 @@ export default definePlugin({
|
||||||
patches: [
|
patches: [
|
||||||
// Permission lockout, just set the check to true
|
// Permission lockout, just set the check to true
|
||||||
{
|
{
|
||||||
find: ".showPermissionLockoutModal(",
|
find: ".STAGE_CHANNEL_CANNOT_OVERWRITE_PERMISSION",
|
||||||
replacement: [
|
replacement: [
|
||||||
{
|
{
|
||||||
match: /case"DENY":.{0,50}if\((?=\i\.\i\.can)/,
|
match: /case"DENY":.{0,50}if\((?=\i\.\i\.can)/,
|
||||||
|
@ -45,9 +46,8 @@ export default definePlugin({
|
||||||
find: ".ONBOARDING_CHANNEL_THRESHOLD_WARNING",
|
find: ".ONBOARDING_CHANNEL_THRESHOLD_WARNING",
|
||||||
replacement: [
|
replacement: [
|
||||||
{
|
{
|
||||||
// are we java yet?
|
match: /{(\i:function\(\){return \i},?){2}}/,
|
||||||
match: /(?<=(?:isDefaultChannelThresholdMetAfterDelete|checkDefaultChannelThresholdMetAfterChannelPermissionDeny):function\(\)\{)return \i(?=\})/g,
|
replace: m => m.replaceAll(canonicalizeMatch(/return \i/g), "return ()=>Promise.resolve(true)")
|
||||||
replace: "return () => true"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
predicate: () => settings.store.onboarding
|
predicate: () => settings.store.onboarding
|
||||||
|
|
|
@ -33,7 +33,7 @@ interface ColorPickerWithSwatchesProps {
|
||||||
const ColorPicker = findComponentByCode<ColorPickerProps>(".Messages.USER_SETTINGS_PROFILE_COLOR_SELECT_COLOR", ".BACKGROUND_PRIMARY)");
|
const ColorPicker = findComponentByCode<ColorPickerProps>(".Messages.USER_SETTINGS_PROFILE_COLOR_SELECT_COLOR", ".BACKGROUND_PRIMARY)");
|
||||||
const ColorPickerWithSwatches = findExportedComponent<ColorPickerWithSwatchesProps>("ColorPicker", "CustomColorPicker");
|
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-");
|
const cl = classNameFactory("vc-pindms-modal-");
|
||||||
|
|
||||||
|
|
|
@ -82,7 +82,7 @@ export default definePlugin({
|
||||||
|
|
||||||
// Rendering
|
// Rendering
|
||||||
{
|
{
|
||||||
match: /"renderRow",(\i)=>{(?<="renderDM",.+?(\i\.default),\{channel:.+?)/,
|
match: /"renderRow",(\i)=>{(?<="renderDM",.+?(\i\.\i),\{channel:.+?)/,
|
||||||
replace: "$&if($self.isChannelIndex($1.section, $1.row))return $self.renderChannel($1.section,$1.row,$2)();"
|
replace: "$&if($self.isChannelIndex($1.section, $1.row))return $self.renderChannel($1.section,$1.row,$2)();"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -131,7 +131,7 @@ export default definePlugin({
|
||||||
|
|
||||||
// Fix Alt Up/Down navigation
|
// Fix Alt Up/Down navigation
|
||||||
{
|
{
|
||||||
find: ".Routes.APPLICATION_STORE&&",
|
find: ".APPLICATION_STORE&&",
|
||||||
replacement: {
|
replacement: {
|
||||||
// channelIds = __OVERLAY__ ? stuff : [...getStaticPaths(),...channelIds)]
|
// channelIds = __OVERLAY__ ? stuff : [...getStaticPaths(),...channelIds)]
|
||||||
match: /(?<=\i=__OVERLAY__\?\i:\[\.\.\.\i\(\),\.\.\.)\i/,
|
match: /(?<=\i=__OVERLAY__\?\i:\[\.\.\.\i\(\),\.\.\.)\i/,
|
||||||
|
|
|
@ -9,13 +9,16 @@ import "./style.css";
|
||||||
import ErrorBoundary from "@components/ErrorBoundary";
|
import ErrorBoundary from "@components/ErrorBoundary";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
import definePlugin from "@utils/types";
|
import definePlugin from "@utils/types";
|
||||||
import { findByProps } from "@webpack";
|
import { filters, findByProps, mapMangledModule } from "@webpack";
|
||||||
import { Timestamp } from "@webpack/common";
|
import { Timestamp } from "@webpack/common";
|
||||||
import type { Message } from "discord-types/general";
|
import type { Message } from "discord-types/general";
|
||||||
import type { HTMLAttributes } from "react";
|
import type { HTMLAttributes } from "react";
|
||||||
|
|
||||||
const { getMessageTimestampId } = findByProps("getMessageTimestampId");
|
const { calendarFormat, dateFormat, isSameDay } = mapMangledModule("millisecondsInUnit:", {
|
||||||
const { calendarFormat, dateFormat, isSameDay } = findByProps("calendarFormat", "dateFormat", "isSameDay", "accessibilityLabelCalendarFormat");
|
calendarFormat: filters.byCode("sameElse"),
|
||||||
|
dateFormat: filters.byCode('":'),
|
||||||
|
isSameDay: filters.byCode("Math.abs(+"),
|
||||||
|
});
|
||||||
const MessageClasses = findByProps("separator", "latin24CompactTimeStamp");
|
const MessageClasses = findByProps("separator", "latin24CompactTimeStamp");
|
||||||
|
|
||||||
function Sep(props: HTMLAttributes<HTMLElement>) {
|
function Sep(props: HTMLAttributes<HTMLElement>) {
|
||||||
|
@ -42,7 +45,6 @@ function ReplyTimestamp({
|
||||||
const baseTimestamp = baseMessage.timestamp as any;
|
const baseTimestamp = baseMessage.timestamp as any;
|
||||||
return (
|
return (
|
||||||
<Timestamp
|
<Timestamp
|
||||||
id={getMessageTimestampId(referencedMessage.message)}
|
|
||||||
className="vc-reply-timestamp"
|
className="vc-reply-timestamp"
|
||||||
compact={isSameDay(refTimestamp, baseTimestamp)}
|
compact={isSameDay(refTimestamp, baseTimestamp)}
|
||||||
timestamp={refTimestamp}
|
timestamp={refTimestamp}
|
||||||
|
@ -65,7 +67,7 @@ export default definePlugin({
|
||||||
|
|
||||||
patches: [
|
patches: [
|
||||||
{
|
{
|
||||||
find: "renderSingleLineMessage:function()",
|
find: ".REPLY_QUOTE_MESSAGE_BLOCKED",
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /(?<="aria-label":\i,children:\[)(?=\i,\i,\i\])/,
|
match: /(?<="aria-label":\i,children:\[)(?=\i,\i,\i\])/,
|
||||||
replace: "$self.ReplyTimestamp(arguments[0]),"
|
replace: "$self.ReplyTimestamp(arguments[0]),"
|
||||||
|
|
|
@ -21,7 +21,7 @@ import definePlugin from "@utils/types";
|
||||||
import { findByProps } from "@webpack";
|
import { findByProps } from "@webpack";
|
||||||
|
|
||||||
const SpoilerClasses = findByProps("spoilerContent");
|
const SpoilerClasses = findByProps("spoilerContent");
|
||||||
const MessagesClasses = findByProps("messagesWrapper", "messages");
|
const MessagesClasses = findByProps("messagesWrapper");
|
||||||
|
|
||||||
export default definePlugin({
|
export default definePlugin({
|
||||||
name: "RevealAllSpoilers",
|
name: "RevealAllSpoilers",
|
||||||
|
|
|
@ -34,7 +34,7 @@ const messageClasses = findByProps("cozyMessage");
|
||||||
const containerClasses = findByProps("container", "isHeader");
|
const containerClasses = findByProps("container", "isHeader");
|
||||||
const avatarClasses = findByProps("avatar", "zalgo");
|
const avatarClasses = findByProps("avatar", "zalgo");
|
||||||
const buttonClasses = findByProps("button", "wrapper", "selected");
|
const buttonClasses = findByProps("button", "wrapper", "selected");
|
||||||
const botTagClasses = findByProps("botTag", "botTagRegular");
|
const botTagClasses = findByProps("botTagRegular");
|
||||||
|
|
||||||
const dateFormat = new Intl.DateTimeFormat();
|
const dateFormat = new Intl.DateTimeFormat();
|
||||||
|
|
||||||
|
@ -130,7 +130,7 @@ export default function ReviewComponent({ review, refetch, profileId }: { review
|
||||||
|
|
||||||
{review.type === ReviewType.System && (
|
{review.type === ReviewType.System && (
|
||||||
<span
|
<span
|
||||||
className={classes(botTagClasses.botTagVerified, botTagClasses.botTagRegular, botTagClasses.botTag, botTagClasses.px, botTagClasses.rem)}
|
className={classes(botTagClasses.botTagVerified, botTagClasses.botTagRegular, botTagClasses.px, botTagClasses.rem)}
|
||||||
style={{ marginLeft: "4px" }}>
|
style={{ marginLeft: "4px" }}>
|
||||||
<span className={botTagClasses.botText}>
|
<span className={botTagClasses.botText}>
|
||||||
System
|
System
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { useAwaiter, useForceUpdater } from "@utils/react";
|
import { useAwaiter, useForceUpdater } from "@utils/react";
|
||||||
import { findByProps, findComponentByCode } from "@webpack";
|
import { findByCode, findByProps, findComponentByCode } from "@webpack";
|
||||||
import { Forms, React, RelationshipStore, useRef, UserStore } from "@webpack/common";
|
import { Forms, React, RelationshipStore, useRef, UserStore } from "@webpack/common";
|
||||||
|
|
||||||
import { Auth, authorize } from "../auth";
|
import { Auth, authorize } from "../auth";
|
||||||
|
@ -27,12 +27,11 @@ import { settings } from "../settings";
|
||||||
import { cl, showToast } from "../utils";
|
import { cl, showToast } from "../utils";
|
||||||
import ReviewComponent from "./ReviewComponent";
|
import ReviewComponent from "./ReviewComponent";
|
||||||
|
|
||||||
|
const Transforms = findByProps("insertNodes", "textToText");
|
||||||
const { Editor, Transforms } = findByProps("Editor", "Transforms");
|
const Editor = findByProps("start", "end", "toSlateRange");
|
||||||
const { ChatInputTypes } = findByProps("ChatInputTypes");
|
const ChatInputTypes = findByProps("FORM");
|
||||||
|
const InputComponent = findComponentByCode("disableThemedBackground", "CHANNEL_TEXT_AREA");
|
||||||
const InputComponent = findComponentByCode("default.CHANNEL_TEXT_AREA", "input");
|
const createChannelRecordFromServer = findByCode(".GUILD_TEXT])", "fromServer)");
|
||||||
const { createChannelRecordFromServer } = findByProps("createChannelRecordFromServer");
|
|
||||||
|
|
||||||
interface UserProps {
|
interface UserProps {
|
||||||
discordId: string;
|
discordId: string;
|
||||||
|
|
|
@ -71,7 +71,7 @@ export default definePlugin({
|
||||||
find: ".userTooltip,children",
|
find: ".userTooltip,children",
|
||||||
replacement: [
|
replacement: [
|
||||||
{
|
{
|
||||||
match: /let\{id:(\i),guildId:(\i)[^}]*\}.*?\.default,{(?=children)/,
|
match: /let\{id:(\i),guildId:(\i)[^}]*\}.*?\.\i,{(?=children)/,
|
||||||
replace: "$&color:$self.getUserColor($1,{guildId:$2}),"
|
replace: "$&color:$self.getUserColor($1,{guildId:$2}),"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
@ -110,7 +110,7 @@ export default definePlugin({
|
||||||
{
|
{
|
||||||
find: ".reactorDefault",
|
find: ".reactorDefault",
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /\.openUserContextMenu\)\((\i),(\i),\i\).{0,250}tag:"strong"/,
|
match: /,onContextMenu:e=>.{0,15}\((\i),(\i),(\i)\).{0,250}tag:"strong"/,
|
||||||
replace: "$&,style:{color:$self.getColor($2?.id,$1)}"
|
replace: "$&,style:{color:$self.getColor($2?.id,$1)}"
|
||||||
},
|
},
|
||||||
predicate: () => settings.store.reactorsList,
|
predicate: () => settings.store.reactorsList,
|
||||||
|
|
|
@ -20,12 +20,11 @@ import { findGroupChildrenByChildId, NavContextMenuPatchCallback } from "@api/Co
|
||||||
import { ReplyIcon } from "@components/Icons";
|
import { ReplyIcon } from "@components/Icons";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
import definePlugin from "@utils/types";
|
import definePlugin from "@utils/types";
|
||||||
import { findByProps } from "@webpack";
|
import { findByCode } from "@webpack";
|
||||||
import { ChannelStore, i18n, Menu, PermissionsBits, PermissionStore, SelectedChannelStore } from "@webpack/common";
|
import { ChannelStore, i18n, Menu, PermissionsBits, PermissionStore, SelectedChannelStore } from "@webpack/common";
|
||||||
import { Message } from "discord-types/general";
|
import { Message } from "discord-types/general";
|
||||||
|
|
||||||
|
const replyToMessage = findByCode(".TEXTAREA_FOCUS)", "showMentionToggle:");
|
||||||
const messageUtils = findByProps("replyToMessage");
|
|
||||||
|
|
||||||
const messageContextMenuPatch: NavContextMenuPatchCallback = (children, { message }: { message: Message; }) => {
|
const messageContextMenuPatch: NavContextMenuPatchCallback = (children, { message }: { message: Message; }) => {
|
||||||
// make sure the message is in the selected channel
|
// make sure the message is in the selected channel
|
||||||
|
@ -43,7 +42,7 @@ const messageContextMenuPatch: NavContextMenuPatchCallback = (children, { messag
|
||||||
id="reply"
|
id="reply"
|
||||||
label={i18n.Messages.MESSAGE_ACTION_REPLY}
|
label={i18n.Messages.MESSAGE_ACTION_REPLY}
|
||||||
icon={ReplyIcon}
|
icon={ReplyIcon}
|
||||||
action={(e: React.MouseEvent) => messageUtils.replyToMessage(channel, message, e)}
|
action={(e: React.MouseEvent) => replyToMessage(channel, message, e)}
|
||||||
/>
|
/>
|
||||||
));
|
));
|
||||||
return;
|
return;
|
||||||
|
@ -57,7 +56,7 @@ const messageContextMenuPatch: NavContextMenuPatchCallback = (children, { messag
|
||||||
id="reply"
|
id="reply"
|
||||||
label={i18n.Messages.MESSAGE_ACTION_REPLY}
|
label={i18n.Messages.MESSAGE_ACTION_REPLY}
|
||||||
icon={ReplyIcon}
|
icon={ReplyIcon}
|
||||||
action={(e: React.MouseEvent) => messageUtils.replyToMessage(channel, message, e)}
|
action={(e: React.MouseEvent) => replyToMessage(channel, message, e)}
|
||||||
/>
|
/>
|
||||||
));
|
));
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -8,11 +8,11 @@ import { DataStore } from "@api/index";
|
||||||
import { definePluginSettings } from "@api/Settings";
|
import { definePluginSettings } from "@api/Settings";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
import definePlugin, { OptionType } from "@utils/types";
|
import definePlugin, { OptionType } from "@utils/types";
|
||||||
import { findByProps } from "@webpack";
|
import { findByCode, findByProps } from "@webpack";
|
||||||
import { ChannelStore, GuildStore } from "@webpack/common";
|
import { ChannelStore, GuildStore } from "@webpack/common";
|
||||||
|
|
||||||
const SummaryStore = findByProps("allSummaries", "findSummary");
|
const SummaryStore = findByProps("allSummaries", "findSummary");
|
||||||
const { createSummaryFromServer } = findByProps("createSummaryFromServer");
|
const createSummaryFromServer = findByCode(".people)),startId:");
|
||||||
|
|
||||||
const settings = definePluginSettings({
|
const settings = definePluginSettings({
|
||||||
summaryExpiryThresholdDays: {
|
summaryExpiryThresholdDays: {
|
||||||
|
@ -55,9 +55,9 @@ export default definePlugin({
|
||||||
settings,
|
settings,
|
||||||
patches: [
|
patches: [
|
||||||
{
|
{
|
||||||
find: "ChannelTypesSets.SUMMARIZEABLE.has",
|
find: "SUMMARIZEABLE.has",
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /\i\.hasFeature\(\i\.GuildFeatures\.SUMMARIES_ENABLED\w+?\)/g,
|
match: /\i\.hasFeature\(\i\.\i\.SUMMARIES_ENABLED\w+?\)/g,
|
||||||
replace: "true"
|
replace: "true"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -11,12 +11,12 @@ import { openImageModal, openUserProfile } from "@utils/discord";
|
||||||
import { classes } from "@utils/misc";
|
import { classes } from "@utils/misc";
|
||||||
import { ModalRoot, ModalSize, openModal } from "@utils/modal";
|
import { ModalRoot, ModalSize, openModal } from "@utils/modal";
|
||||||
import { useAwaiter } from "@utils/react";
|
import { useAwaiter } from "@utils/react";
|
||||||
import { findByProps, findExportedComponent } from "@webpack";
|
import { findByProps, findComponentByCode } from "@webpack";
|
||||||
import { FluxDispatcher, Forms, GuildChannelStore, GuildMemberStore, GuildStore, IconUtils, Parser, PresenceStore, RelationshipStore, ScrollerThin, SnowflakeUtils, TabBar, Timestamp, useEffect, UserStore, UserUtils, useState, useStateFromStores } from "@webpack/common";
|
import { FluxDispatcher, Forms, GuildChannelStore, GuildMemberStore, GuildStore, IconUtils, Parser, PresenceStore, RelationshipStore, ScrollerThin, SnowflakeUtils, TabBar, Timestamp, useEffect, UserStore, UserUtils, useState, useStateFromStores } from "@webpack/common";
|
||||||
import { Guild, User } from "discord-types/general";
|
import { Guild, User } from "discord-types/general";
|
||||||
|
|
||||||
const IconClasses = findByProps("icon", "acronym", "childWrapper");
|
const IconClasses = findByProps("icon", "acronym", "childWrapper");
|
||||||
const FriendRow = findExportedComponent("FriendRow");
|
const FriendRow = findComponentByCode(".listName,discriminatorClass");
|
||||||
|
|
||||||
const cl = classNameFactory("vc-gp-");
|
const cl = classNameFactory("vc-gp-");
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,8 @@ import { VerifiedIcon } from "./VerifiedIcon";
|
||||||
|
|
||||||
const Section = findComponentByCode(".lastSection", "children:");
|
const Section = findComponentByCode(".lastSection", "children:");
|
||||||
const ThemeStore = findStore("ThemeStore");
|
const ThemeStore = findStore("ThemeStore");
|
||||||
const platformHooks: { useLegacyPlatformType(platform: string): string; } = findByProps("useLegacyPlatformType");
|
|
||||||
|
const useLegacyPlatformType: (platform: string) => string = findByCode(".TWITTER_LEGACY:");
|
||||||
const platforms: { get(type: string): ConnectionPlatform; } = findByProps("isSupported", "getByUrl");
|
const platforms: { get(type: string): ConnectionPlatform; } = findByProps("isSupported", "getByUrl");
|
||||||
const getProfileThemeProps = findByCode(".getPreviewThemeColors", "primaryColor:");
|
const getProfileThemeProps = findByCode(".getPreviewThemeColors", "primaryColor:");
|
||||||
|
|
||||||
|
@ -132,7 +133,7 @@ function ConnectionsComponent({ id, theme, simplified }: { id: string, theme: st
|
||||||
}
|
}
|
||||||
|
|
||||||
function CompactConnectionComponent({ connection, theme }: { connection: Connection, theme: string; }) {
|
function CompactConnectionComponent({ connection, theme }: { connection: Connection, theme: string; }) {
|
||||||
const platform = platforms.get(platformHooks.useLegacyPlatformType(connection.type));
|
const platform = platforms.get(useLegacyPlatformType(connection.type));
|
||||||
const url = platform.getPlatformUserUrl?.(connection);
|
const url = platform.getPlatformUserUrl?.(connection);
|
||||||
|
|
||||||
const img = (
|
const img = (
|
||||||
|
@ -202,7 +203,7 @@ export default definePlugin({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
find: ".UserPopoutUpsellSource.PROFILE_PANEL,",
|
find: ".PROFILE_PANEL,",
|
||||||
replacement: {
|
replacement: {
|
||||||
// createElement(Divider, {}), createElement(NoteComponent)
|
// createElement(Divider, {}), createElement(NoteComponent)
|
||||||
match: /\(0,\i\.jsx\)\(\i\.\i,\{\}\).{0,100}setNote:(?=.+?channelId:(\i).id)/,
|
match: /\(0,\i\.jsx\)\(\i\.\i,\{\}\).{0,100}setNote:(?=.+?channelId:(\i).id)/,
|
||||||
|
@ -210,7 +211,7 @@ export default definePlugin({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
find: ".UserProfileTypes.BITE_SIZE,onOpenProfile",
|
find: ".BITE_SIZE,onOpenProfile",
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /currentUser:\i,guild:\i,onOpenProfile:.+?}\)(?=])(?<=user:(\i),bio:null==(\i)\?.+?)/,
|
match: /currentUser:\i,guild:\i,onOpenProfile:.+?}\)(?=])(?<=user:(\i),bio:null==(\i)\?.+?)/,
|
||||||
replace: "$&,$self.profilePopoutComponent({ user: $1, displayProfile: $2, simplified: true })"
|
replace: "$&,$self.profilePopoutComponent({ user: $1, displayProfile: $2, simplified: true })"
|
||||||
|
|
|
@ -77,7 +77,7 @@ const enum ChannelFlags {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const ChatScrollClasses = findByProps("auto", "content", "scrollerBase");
|
const ChatScrollClasses = findByProps("auto", "managedReactiveScroller");
|
||||||
const ChatClasses = findByProps("chat", "content", "noChat", "chatContent");
|
const ChatClasses = findByProps("chat", "content", "noChat", "chatContent");
|
||||||
const ChannelBeginHeader = findComponentByCode(".Messages.ROLE_REQUIRED_SINGLE_USER_MESSAGE");
|
const ChannelBeginHeader = findComponentByCode(".Messages.ROLE_REQUIRED_SINGLE_USER_MESSAGE");
|
||||||
const TagComponent = findComponentByCode(".Messages.FORUM_TAG_A11Y_FILTER_BY_TAG");
|
const TagComponent = findComponentByCode(".Messages.FORUM_TAG_A11Y_FILTER_BY_TAG");
|
||||||
|
|
|
@ -116,14 +116,14 @@ export default definePlugin({
|
||||||
},
|
},
|
||||||
// Prevent Discord from trying to connect to hidden stage channels
|
// Prevent Discord from trying to connect to hidden stage channels
|
||||||
{
|
{
|
||||||
find: ".MAX_STAGE_VOICE_USER_LIMIT})",
|
find: ".AUDIENCE),{isSubscriptionGated",
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /!(\i)\.isRoleSubscriptionTemplatePreviewChannel\(\)/,
|
match: /!(\i)\.isRoleSubscriptionTemplatePreviewChannel\(\)/,
|
||||||
replace: (m, channel) => `${m}&&!$self.isHiddenChannel(${channel})`
|
replace: (m, channel) => `${m}&&!$self.isHiddenChannel(${channel})`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
find: "ChannelItemEditButton:function(){",
|
find: 'tutorialId:"instant-invite"',
|
||||||
replacement: [
|
replacement: [
|
||||||
// Render null instead of the buttons if the channel is hidden
|
// Render null instead of the buttons if the channel is hidden
|
||||||
...[
|
...[
|
||||||
|
@ -195,7 +195,7 @@ export default definePlugin({
|
||||||
// Hide the new version of unreads box for hidden channels
|
// Hide the new version of unreads box for hidden channels
|
||||||
find: '="ChannelListUnreadsStore",',
|
find: '="ChannelListUnreadsStore",',
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /(?=&&\(0,\i\.getHasImportantUnread\)\((\i)\))/g, // Global because Discord has multiple methods like that in the same module
|
match: /(?<=\.id\)\))(?=&&\(0,\i\.\i\)\((\i)\))/,
|
||||||
replace: (_, channel) => `&&!$self.isHiddenChannel(${channel})`
|
replace: (_, channel) => `&&!$self.isHiddenChannel(${channel})`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -203,15 +203,15 @@ export default definePlugin({
|
||||||
// Make the old version of unreads box not visible for hidden channels
|
// Make the old version of unreads box not visible for hidden channels
|
||||||
find: "renderBottomUnread(){",
|
find: "renderBottomUnread(){",
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /(?=&&\(0,\i\.getHasImportantUnread\)\((\i\.record)\))/,
|
match: /(?<=!0\))(?=&&\(0,\i\.\i\)\((\i\.record)\))/,
|
||||||
replace: "&&!$self.isHiddenChannel($1)"
|
replace: "&&!$self.isHiddenChannel($1)"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// Make the state of the old version of unreads box not include hidden channels
|
// Make the state of the old version of unreads box not include hidden channels
|
||||||
find: ".useFlattenedChannelIdListWithThreads)",
|
find: "ignoreRecents:!0",
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /(?=&&\(0,\i\.getHasImportantUnread\)\((\i)\))/,
|
match: /(?<=\.id\)\))(?=&&\(0,\i\.\i\)\((\i)\))/,
|
||||||
replace: "&&!$self.isHiddenChannel($1)"
|
replace: "&&!$self.isHiddenChannel($1)"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -257,7 +257,7 @@ export default definePlugin({
|
||||||
{
|
{
|
||||||
find: '"alt+shift+down"',
|
find: '"alt+shift+down"',
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /(?<=getChannel\(\i\);return null!=(\i))(?=.{0,150}?getHasImportantUnread\)\(\i\))/,
|
match: /(?<=getChannel\(\i\);return null!=(\i))(?=.{0,150}?>0\)&&\(0,\i\.\i\)\(\i\))/,
|
||||||
replace: (_, channel) => `&&!$self.isHiddenChannel(${channel})`
|
replace: (_, channel) => `&&!$self.isHiddenChannel(${channel})`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -289,7 +289,7 @@ export default definePlugin({
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// If the @everyone role has the required permissions, make the array only contain it
|
// If the @everyone role has the required permissions, make the array only contain it
|
||||||
match: /computePermissionsForRoles.+?.value\(\)(?<=channel:(\i).+?)/,
|
match: /forceRoles:.+?.value\(\)(?<=channel:(\i).+?)/,
|
||||||
replace: (m, channel) => `${m}.reduce(...$self.makeAllowedRolesReduce(${channel}.guild_id))`
|
replace: (m, channel) => `${m}.reduce(...$self.makeAllowedRolesReduce(${channel}.guild_id))`
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -422,7 +422,7 @@ export default definePlugin({
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// Avoid filtering out hidden channels from the channel list
|
// Avoid filtering out hidden channels from the channel list
|
||||||
match: /(?<=queryChannels\(\i\){.+?isGuildChannelType\)\((\i)\.type\))(?=&&!\i\.\i\.can\()/,
|
match: /(?<=queryChannels\(\i\){.+?\)\((\i)\.type\))(?=&&!\i\.\i\.can\()/,
|
||||||
replace: "&&!$self.isHiddenChannel($1)"
|
replace: "&&!$self.isHiddenChannel($1)"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
@ -64,18 +64,18 @@ export default definePlugin({
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
find: "useShouldShowInvitesDisabledNotif:",
|
find: "2022-07_invites_disabled",
|
||||||
predicate: () => settings.store.showInvitesPaused,
|
predicate: () => settings.store.showInvitesPaused,
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /\i\.\i\.can\(\i\.Permissions.MANAGE_GUILD,\i\)/,
|
match: /\i\.\i\.can\(\i\.\i.MANAGE_GUILD,\i\)/,
|
||||||
replace: "true",
|
replace: "true",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
find: "canAccessGuildMemberModViewWithExperiment:",
|
find: /context:\i,checkElevated:!1\}\),\i\.\i.{0,200}autoTrackExposure/,
|
||||||
predicate: () => settings.store.showModView,
|
predicate: () => settings.store.showModView,
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /return \i\.hasAny\(\i\.computePermissions\(\{user:\i,context:\i,checkElevated:!1\}\),\i\.MemberSafetyPagePermissions\)/,
|
match: /return \i\.\i\(\i\.\i\(\{user:\i,context:\i,checkElevated:!1\}\),\i\.\i\)/,
|
||||||
replace: "return true",
|
replace: "return true",
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -87,28 +87,31 @@ export default definePlugin({
|
||||||
replace: "{}"
|
replace: "{}"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
// remove the 200 server minimum
|
||||||
{
|
{
|
||||||
find: "MINIMUM_MEMBER_COUNT:",
|
find: '">200"',
|
||||||
predicate: () => settings.store.disableDiscoveryFilters,
|
predicate: () => settings.store.disableDiscoveryFilters,
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /MINIMUM_MEMBER_COUNT:function\(\)\{return \i}/,
|
match: '">200"',
|
||||||
replace: "MINIMUM_MEMBER_COUNT:() => \">0\""
|
replace: '">0"'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
// empty word filter (why would anyone search "horny" in fucking server discovery... please... why are we patching this again??)
|
||||||
{
|
{
|
||||||
find: "DiscoveryBannedSearchWords.includes",
|
find: '"horny","fart"',
|
||||||
predicate: () => settings.store.disableDisallowedDiscoveryFilters,
|
predicate: () => settings.store.disableDisallowedDiscoveryFilters,
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /(?<=function\(\){)(?=.{0,130}DiscoveryBannedSearchWords\.includes)/,
|
match: /=\["egirl",.+?\]/,
|
||||||
replace: "return false;"
|
replace: "=[]"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
// patch request that queries if term is allowed
|
||||||
{
|
{
|
||||||
find: "Endpoints.GUILD_DISCOVERY_VALID_TERM",
|
find: ".GUILD_DISCOVERY_VALID_TERM",
|
||||||
predicate: () => settings.store.disableDisallowedDiscoveryFilters,
|
predicate: () => settings.store.disableDisallowedDiscoveryFilters,
|
||||||
all: true,
|
all: true,
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /\i\.HTTP\.get\(\{url:\i\.Endpoints\.GUILD_DISCOVERY_VALID_TERM,query:\{term:\i\},oldFormErrors:!0\}\);/g,
|
match: /\i\.\i\.get\(\{url:\i\.\i\.GUILD_DISCOVERY_VALID_TERM,query:\{term:\i\},oldFormErrors:!0\}\);/g,
|
||||||
replace: "Promise.resolve({ body: { valid: true } });"
|
replace: "Promise.resolve({ body: { valid: true } });"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,7 +48,7 @@ export default definePlugin({
|
||||||
authors: [Devs.Rini, Devs.TheKodeToad],
|
authors: [Devs.Rini, Devs.TheKodeToad],
|
||||||
patches: [
|
patches: [
|
||||||
{
|
{
|
||||||
find: ".useCanSeeRemixBadge)",
|
find: '?"@":"")',
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /(?<=onContextMenu:\i,children:).*?\)}/,
|
match: /(?<=onContextMenu:\i,children:).*?\)}/,
|
||||||
replace: "$self.renderUsername(arguments[0])}"
|
replace: "$self.renderUsername(arguments[0])}"
|
||||||
|
|
|
@ -68,7 +68,7 @@ interface Device {
|
||||||
type Repeat = "off" | "track" | "context";
|
type Repeat = "off" | "track" | "context";
|
||||||
|
|
||||||
const SpotifySocket = findByProps("getActiveSocketAndDevice");
|
const SpotifySocket = findByProps("getActiveSocketAndDevice");
|
||||||
const SpotifyUtils = findByProps("SpotifyAPI");
|
const SpotifyAPI = findByProps("vcSpotifyMarker");
|
||||||
|
|
||||||
// Don't wanna run before Flux and Dispatcher are ready!
|
// Don't wanna run before Flux and Dispatcher are ready!
|
||||||
export const SpotifyStore = webpackDependantLazy(() => {
|
export const SpotifyStore = webpackDependantLazy(() => {
|
||||||
|
@ -171,7 +171,7 @@ export const SpotifyStore = webpackDependantLazy(() => {
|
||||||
(data.query ??= {}).device_id = this.device.id;
|
(data.query ??= {}).device_id = this.device.id;
|
||||||
|
|
||||||
const { socket } = SpotifySocket.getActiveSocketAndDevice();
|
const { socket } = SpotifySocket.getActiveSocketAndDevice();
|
||||||
return SpotifyUtils.SpotifyAPI[method](socket.accountId, socket.accessToken, {
|
return SpotifyAPI[method](socket.accountId, socket.accessToken, {
|
||||||
url: API_BASE + route,
|
url: API_BASE + route,
|
||||||
...data
|
...data
|
||||||
});
|
});
|
||||||
|
|
|
@ -64,7 +64,7 @@ export default definePlugin({
|
||||||
replacement: [{
|
replacement: [{
|
||||||
// Adds POST and a Marker to the SpotifyAPI (so we can easily find it)
|
// Adds POST and a Marker to the SpotifyAPI (so we can easily find it)
|
||||||
match: /get:(\i)\.bind\(null,(\i\.\i)\.get\)/,
|
match: /get:(\i)\.bind\(null,(\i\.\i)\.get\)/,
|
||||||
replace: "post:$1.bind(null,$2.post),$&"
|
replace: "post:$1.bind(null,$2.post),vcSpotifyMarker:1,$&"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// Spotify Connect API returns status 202 instead of 204 when skipping tracks.
|
// Spotify Connect API returns status 202 instead of 204 when skipping tracks.
|
||||||
|
@ -84,7 +84,7 @@ export default definePlugin({
|
||||||
{
|
{
|
||||||
find: "artists.filter",
|
find: "artists.filter",
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /\(0,(\i)\.isNotNullish\)\((\i)\.id\)&&/,
|
match: /(?<=artists.filter\(\i=>).{0,10}\i\.id\)&&/,
|
||||||
replace: ""
|
replace: ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,9 +47,9 @@ export default definePlugin({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
find: ".trackEmojiSearchEmpty,200",
|
find: ".EMOJI_PICKER_CONSTANTS_EMOJI_CONTAINER_PADDING_HORIZONTAL)",
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /(\.trackEmojiSearchEmpty,200(?=.+?isBurstReaction:(\i).+?(\i===\i\.EmojiIntention.REACTION)).+?\[\2,\i\]=\i\.useState\().+?\)/,
|
match: /(openPopoutType:void 0(?=.+?isBurstReaction:(\i).+?(\i===\i\.\i.REACTION)).+?\[\2,\i\]=\i\.useState\().+?\)/,
|
||||||
replace: (_, rest, isBurstReactionVariable, isReactionIntention) => `${rest}$self.shouldSuperReactByDefault&&${isReactionIntention})`
|
replace: (_, rest, isBurstReactionVariable, isReactionIntention) => `${rest}$self.shouldSuperReactByDefault&&${isReactionIntention})`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,19 +58,13 @@ export default definePlugin({
|
||||||
patches: [
|
patches: [
|
||||||
{
|
{
|
||||||
find: ".NITRO_BANNER,",
|
find: ".NITRO_BANNER,",
|
||||||
replacement: [
|
replacement: {
|
||||||
{
|
match: /\?\(0,\i\.jsx\)\(\i,{type:\i,shown/,
|
||||||
match: /(\i)\.premiumType/,
|
replace: "&&$self.shouldShowBadge(arguments[0])$&"
|
||||||
replace: "$self.patchPremiumType($1)||$&"
|
}
|
||||||
},
|
|
||||||
{
|
|
||||||
match: /\?\(0,\i\.jsx\)\(\i,{type:\i,shown/,
|
|
||||||
replace: "&&$self.shouldShowBadge(arguments[0])$&"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
find: "BannerLoadingStatus:function",
|
find: ".banner)==null",
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /(?<=void 0:)\i.getPreviewBanner\(\i,\i,\i\)/,
|
match: /(?<=void 0:)\i.getPreviewBanner\(\i,\i,\i\)/,
|
||||||
replace: "$self.patchBannerUrl(arguments[0])||$&"
|
replace: "$self.patchBannerUrl(arguments[0])||$&"
|
||||||
|
@ -115,10 +109,6 @@ export default definePlugin({
|
||||||
if (this.userHasBackground(displayProfile?.userId)) return this.getImageUrl(displayProfile?.userId);
|
if (this.userHasBackground(displayProfile?.userId)) return this.getImageUrl(displayProfile?.userId);
|
||||||
},
|
},
|
||||||
|
|
||||||
patchPremiumType({ userId }: any) {
|
|
||||||
if (this.userHasBackground(userId)) return 2;
|
|
||||||
},
|
|
||||||
|
|
||||||
shouldShowBadge({ displayProfile, user }: any) {
|
shouldShowBadge({ displayProfile, user }: any) {
|
||||||
return displayProfile?.banner && (!this.userHasBackground(user.id) || settings.store.nitroFirst);
|
return displayProfile?.banner && (!this.userHasBackground(user.id) || settings.store.nitroFirst);
|
||||||
},
|
},
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
import definePlugin from "@utils/types";
|
import definePlugin from "@utils/types";
|
||||||
import { findByProps } from "@webpack";
|
import { findByCode } from "@webpack";
|
||||||
import { FluxDispatcher, RestAPI } from "@webpack/common";
|
import { FluxDispatcher, RestAPI } from "@webpack/common";
|
||||||
import { Message, User } from "discord-types/general";
|
import { Message, User } from "discord-types/general";
|
||||||
import { Channel } from "discord-types/general/index.js";
|
import { Channel } from "discord-types/general/index.js";
|
||||||
|
@ -29,7 +29,7 @@ interface Reply {
|
||||||
const fetching = new Map<string, string>();
|
const fetching = new Map<string, string>();
|
||||||
let ReplyStore: any;
|
let ReplyStore: any;
|
||||||
|
|
||||||
const { createMessageRecord } = findByProps("createMessageRecord");
|
const createMessageRecord = findByCode(".createFromServer(", ".isBlockedForMessage", "messageReference:");
|
||||||
|
|
||||||
export default definePlugin({
|
export default definePlugin({
|
||||||
name: "ValidReply",
|
name: "ValidReply",
|
||||||
|
|
|
@ -184,7 +184,7 @@ export default definePlugin({
|
||||||
|
|
||||||
patches: [
|
patches: [
|
||||||
// Profiles Modal pfp
|
// Profiles Modal pfp
|
||||||
...[".UserProfileTypes.MODAL,hasProfileEffect", ".UserProfileTypes.FULL_SIZE,hasProfileEffect:"].map(find => ({
|
...[".MODAL,hasProfileEffect", ".FULL_SIZE,hasProfileEffect:"].map(find => ({
|
||||||
find,
|
find,
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /\{src:(\i)(?=,avatarDecoration)/,
|
match: /\{src:(\i)(?=,avatarDecoration)/,
|
||||||
|
@ -222,7 +222,7 @@ export default definePlugin({
|
||||||
{
|
{
|
||||||
find: /\.recipients\.length>=2(?!<isMultiUserDM.{0,50})/,
|
find: /\.recipients\.length>=2(?!<isMultiUserDM.{0,50})/,
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /null==\i\.icon\?.+?src:(\(0,\i\.getChannelIconURL\).+?\))(?=[,}])/,
|
match: /null==\i\.icon\?.+?src:(\(0,\i\.\i\).+?\))(?=[,}])/,
|
||||||
replace: (m, iconUrl) => `${m},onClick:()=>$self.openImage(${iconUrl})`
|
replace: (m, iconUrl) => `${m},onClick:()=>$self.openImage(${iconUrl})`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -21,6 +21,7 @@ import { Button, showToast, Toasts, useState } from "@webpack/common";
|
||||||
|
|
||||||
import type { VoiceRecorder } from ".";
|
import type { VoiceRecorder } from ".";
|
||||||
import { settings } from "./settings";
|
import { settings } from "./settings";
|
||||||
|
import { MediaEngineStore } from "./utils";
|
||||||
|
|
||||||
const Native = VencordNative.pluginHelpers.VoiceMessages as PluginNative<typeof import("./native")>;
|
const Native = VencordNative.pluginHelpers.VoiceMessages as PluginNative<typeof import("./native")>;
|
||||||
|
|
||||||
|
@ -41,6 +42,7 @@ export const VoiceRecorderDesktop: VoiceRecorder = ({ setAudioBlob, onRecordingC
|
||||||
{
|
{
|
||||||
echoCancellation: settings.store.echoCancellation,
|
echoCancellation: settings.store.echoCancellation,
|
||||||
noiseCancellation: settings.store.noiseSuppression,
|
noiseCancellation: settings.store.noiseSuppression,
|
||||||
|
deviceId: MediaEngineStore.getInputDeviceId(),
|
||||||
},
|
},
|
||||||
(success: boolean) => {
|
(success: boolean) => {
|
||||||
if (success)
|
if (success)
|
||||||
|
|
|
@ -20,6 +20,7 @@ import { Button, useState } from "@webpack/common";
|
||||||
|
|
||||||
import type { VoiceRecorder } from ".";
|
import type { VoiceRecorder } from ".";
|
||||||
import { settings } from "./settings";
|
import { settings } from "./settings";
|
||||||
|
import { MediaEngineStore } from "./utils";
|
||||||
|
|
||||||
export const VoiceRecorderWeb: VoiceRecorder = ({ setAudioBlob, onRecordingChange }) => {
|
export const VoiceRecorderWeb: VoiceRecorder = ({ setAudioBlob, onRecordingChange }) => {
|
||||||
const [recording, setRecording] = useState(false);
|
const [recording, setRecording] = useState(false);
|
||||||
|
@ -40,6 +41,7 @@ export const VoiceRecorderWeb: VoiceRecorder = ({ setAudioBlob, onRecordingChang
|
||||||
audio: {
|
audio: {
|
||||||
echoCancellation: settings.store.echoCancellation,
|
echoCancellation: settings.store.echoCancellation,
|
||||||
noiseSuppression: settings.store.noiseSuppression,
|
noiseSuppression: settings.store.noiseSuppression,
|
||||||
|
deviceId: MediaEngineStore.getInputDeviceId()
|
||||||
}
|
}
|
||||||
}).then(stream => {
|
}).then(stream => {
|
||||||
const chunks = [] as Blob[];
|
const chunks = [] as Blob[];
|
||||||
|
|
|
@ -27,7 +27,7 @@ import { ModalContent, ModalFooter, ModalHeader, ModalProps, ModalRoot, openModa
|
||||||
import { useAwaiter } from "@utils/react";
|
import { useAwaiter } from "@utils/react";
|
||||||
import definePlugin from "@utils/types";
|
import definePlugin from "@utils/types";
|
||||||
import { chooseFile } from "@utils/web";
|
import { chooseFile } from "@utils/web";
|
||||||
import { findByProps, findStore } from "@webpack";
|
import { find, findByProps, findStore } from "@webpack";
|
||||||
import { Button, Card, Constants, FluxDispatcher, Forms, lodash, Menu, MessageActions, PermissionsBits, PermissionStore, RestAPI, SelectedChannelStore, showToast, SnowflakeUtils, Toasts, useEffect, useState } from "@webpack/common";
|
import { Button, Card, Constants, FluxDispatcher, Forms, lodash, Menu, MessageActions, PermissionsBits, PermissionStore, RestAPI, SelectedChannelStore, showToast, SnowflakeUtils, Toasts, useEffect, useState } from "@webpack/common";
|
||||||
import { ComponentType } from "react";
|
import { ComponentType } from "react";
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@ import { cl } from "./utils";
|
||||||
import { VoicePreview } from "./VoicePreview";
|
import { VoicePreview } from "./VoicePreview";
|
||||||
import { VoiceRecorderWeb } from "./WebRecorder";
|
import { VoiceRecorderWeb } from "./WebRecorder";
|
||||||
|
|
||||||
const CloudUtils = findByProps("CloudUpload");
|
const CloudUpload = find(m => m.prototype?.trackUploadFinished);
|
||||||
const PendingReplyStore = findStore("PendingReplyStore");
|
const PendingReplyStore = findStore("PendingReplyStore");
|
||||||
const OptionClasses = findByProps("optionName", "optionIcon", "optionLabel");
|
const OptionClasses = findByProps("optionName", "optionIcon", "optionLabel");
|
||||||
|
|
||||||
|
@ -89,9 +89,8 @@ function sendAudio(blob: Blob, meta: AudioMetadata) {
|
||||||
const reply = PendingReplyStore.getPendingReply(channelId);
|
const reply = PendingReplyStore.getPendingReply(channelId);
|
||||||
if (reply) FluxDispatcher.dispatch({ type: "DELETE_PENDING_REPLY", channelId });
|
if (reply) FluxDispatcher.dispatch({ type: "DELETE_PENDING_REPLY", channelId });
|
||||||
|
|
||||||
const upload = new CloudUtils.CloudUpload({
|
const upload = new CloudUpload({
|
||||||
file: new File([blob], "voice-message.ogg", { type: "audio/ogg; codecs=opus" }),
|
file: new File([blob], "voice-message.ogg", { type: "audio/ogg; codecs=opus" }),
|
||||||
isClip: false,
|
|
||||||
isThumbnail: false,
|
isThumbnail: false,
|
||||||
platform: 1,
|
platform: 1,
|
||||||
}, channelId, false, 0);
|
}, channelId, false, 0);
|
||||||
|
|
|
@ -17,5 +17,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { classNameFactory } from "@api/Styles";
|
import { classNameFactory } from "@api/Styles";
|
||||||
|
import { findStore } from "@webpack";
|
||||||
|
|
||||||
|
export const MediaEngineStore = findStore("MediaEngineStore");
|
||||||
export const cl = classNameFactory("vc-vmsg-");
|
export const cl = classNameFactory("vc-vmsg-");
|
||||||
|
|
|
@ -197,8 +197,8 @@ export default definePlugin({
|
||||||
{
|
{
|
||||||
find: '"MediaEngineWebRTC");',
|
find: '"MediaEngineWebRTC");',
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /supports\(\i\)\{switch\(\i\)\{case (\i).Features/,
|
match: /supports\(\i\)\{switch\(\i\)\{(case (\i).\i)/,
|
||||||
replace: "$&.DISABLE_VIDEO:return true;case $1.Features"
|
replace: "$&.DISABLE_VIDEO:return true;$1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
|
@ -9,11 +9,11 @@ import { makeRange } from "@components/PluginSettings/components";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
import { Logger } from "@utils/Logger";
|
import { Logger } from "@utils/Logger";
|
||||||
import definePlugin, { OptionType, PluginNative, ReporterTestable } from "@utils/types";
|
import definePlugin, { OptionType, PluginNative, ReporterTestable } from "@utils/types";
|
||||||
import { findByProps } from "@webpack";
|
import { find, findByCode } from "@webpack";
|
||||||
import { ChannelStore, GuildStore, UserStore } from "@webpack/common";
|
import { ChannelStore, GuildStore, UserStore } from "@webpack/common";
|
||||||
import type { Channel, Embed, GuildMember, MessageAttachment, User } from "discord-types/general";
|
import type { Channel, Embed, GuildMember, MessageAttachment, User } from "discord-types/general";
|
||||||
|
|
||||||
const { ChannelTypes } = findByProps("ChannelTypes");
|
const ChannelTypes = find(m => m.ANNOUNCEMENT_THREAD === 10);
|
||||||
|
|
||||||
interface Message {
|
interface Message {
|
||||||
guild_id: string,
|
guild_id: string,
|
||||||
|
@ -68,7 +68,7 @@ interface Call {
|
||||||
ringing: string[];
|
ringing: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
const Notifs = findByProps("makeTextChatNotification");
|
const notificationsShouldNotify = findByCode(".SUPPRESS_NOTIFICATIONS))return!1");
|
||||||
const XSLog = new Logger("XSOverlay");
|
const XSLog = new Logger("XSOverlay");
|
||||||
|
|
||||||
const settings = definePluginSettings({
|
const settings = definePluginSettings({
|
||||||
|
@ -136,7 +136,7 @@ const settings = definePluginSettings({
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const Native = VencordNative.pluginHelpers.XsOverlay as PluginNative<typeof import("./native")>;
|
const Native = VencordNative.pluginHelpers.XSOverlay as PluginNative<typeof import("./native")>;
|
||||||
|
|
||||||
export default definePlugin({
|
export default definePlugin({
|
||||||
name: "XSOverlay",
|
name: "XSOverlay",
|
||||||
|
@ -304,7 +304,7 @@ function shouldNotify(message: Message, channel: string) {
|
||||||
const currentUser = UserStore.getCurrentUser();
|
const currentUser = UserStore.getCurrentUser();
|
||||||
if (message.author.id === currentUser.id) return false;
|
if (message.author.id === currentUser.id) return false;
|
||||||
if (message.author.bot && !settings.store.botNotifications) return false;
|
if (message.author.bot && !settings.store.botNotifications) return false;
|
||||||
return Notifs.shouldNotify(message, channel);
|
return notificationsShouldNotify(message, channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
function calculateHeight(content: string) {
|
function calculateHeight(content: string) {
|
||||||
|
|
|
@ -120,6 +120,8 @@ export function openImageModal(url: string, props?: Partial<ImageModalProps>): s
|
||||||
placeholder={url}
|
placeholder={url}
|
||||||
src={url}
|
src={url}
|
||||||
renderLinkComponent={props => <MaskedLink {...props} />}
|
renderLinkComponent={props => <MaskedLink {...props} />}
|
||||||
|
// Don't render forward message button
|
||||||
|
renderForwardComponent={() => null}
|
||||||
shouldHideMediaOptions={false}
|
shouldHideMediaOptions={false}
|
||||||
shouldAnimate
|
shouldAnimate
|
||||||
{...props}
|
{...props}
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { filters, find, findByProps, findExportedComponent } from "@webpack";
|
import { filters, find, findByProps, findComponentByCode } from "@webpack";
|
||||||
import type { ComponentType, PropsWithChildren, ReactNode, Ref } from "react";
|
import type { ComponentType, PropsWithChildren, ReactNode, Ref } from "react";
|
||||||
|
|
||||||
import { NoopComponent } from "./react";
|
import { NoopComponent } from "./react";
|
||||||
|
@ -38,7 +38,7 @@ const enum ModalTransitionState {
|
||||||
|
|
||||||
export interface ModalProps {
|
export interface ModalProps {
|
||||||
transitionState: ModalTransitionState;
|
transitionState: ModalTransitionState;
|
||||||
onClose(): Promise<void>;
|
onClose(): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ModalOptions {
|
export interface ModalOptions {
|
||||||
|
@ -124,6 +124,7 @@ export type ImageModalProps = {
|
||||||
animated?: boolean;
|
animated?: boolean;
|
||||||
responsive?: boolean;
|
responsive?: boolean;
|
||||||
renderLinkComponent(props: any): ReactNode;
|
renderLinkComponent(props: any): ReactNode;
|
||||||
|
renderForwardComponent(props: any): ReactNode;
|
||||||
maxWidth?: number;
|
maxWidth?: number;
|
||||||
maxHeight?: number;
|
maxHeight?: number;
|
||||||
shouldAnimate?: boolean;
|
shouldAnimate?: boolean;
|
||||||
|
@ -131,7 +132,7 @@ export type ImageModalProps = {
|
||||||
shouldHideMediaOptions?: boolean;
|
shouldHideMediaOptions?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ImageModal = findExportedComponent<ImageModalProps>("ImageModal");
|
export const ImageModal = findComponentByCode<ImageModalProps>(".MEDIA_MODAL_CLOSE", "responsive");
|
||||||
|
|
||||||
const ModalAPI = findByProps("openModalLazy");
|
const ModalAPI = findByProps("openModalLazy");
|
||||||
|
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue