From 051bce89f8b16034b37a42ad2755928abd1b7c61 Mon Sep 17 00:00:00 2001 From: Nuckyz <61953774+Nuckyz@users.noreply.github.com> Date: Sun, 18 Aug 2024 00:26:40 -0300 Subject: [PATCH 01/20] feat(Webpack): Add $$vencordPatchedSource to patched factories --- src/webpack/patchWebpack.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/webpack/patchWebpack.ts b/src/webpack/patchWebpack.ts index f32aeb789..4629434ae 100644 --- a/src/webpack/patchWebpack.ts +++ b/src/webpack/patchWebpack.ts @@ -233,7 +233,7 @@ function patchFactories(factories: Record string, original: any, (...args: any[]): void; }; + } as any as { toString: () => string, original: any, (...args: any[]): void; $$vencordPatchedSource?: string; }; factory.toString = originalMod.toString.bind(originalMod); factory.original = originalMod; @@ -354,5 +354,9 @@ function patchFactories(factories: Record Date: Sun, 18 Aug 2024 00:47:16 -0300 Subject: [PATCH 02/20] fix(Webpack): Not canonicalizing regex in some places --- src/webpack/webpack.ts | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/webpack/webpack.ts b/src/webpack/webpack.ts index fcd4adb8a..19519d647 100644 --- a/src/webpack/webpack.ts +++ b/src/webpack/webpack.ts @@ -38,15 +38,15 @@ export let cache: WebpackInstance["c"]; export type FilterFn = (mod: any) => boolean; -type PropsFilter = Array; -type CodeFilter = Array; -type StoreNameFilter = string; +export type PropsFilter = Array; +export type CodeFilter = Array; +export type StoreNameFilter = string; -const stringMatches = (s: string, filter: CodeFilter) => +export const stringMatches = (s: string, filter: CodeFilter) => filter.every(f => typeof f === "string" ? s.includes(f) - : f.test(s) + : (f.global && (f.lastIndex = 0), f.test(s)) ); export const filters = { @@ -258,6 +258,8 @@ export const findBulk = traceFunction("findBulk", function findBulk(...filterFns * @returns string or null */ export const findModuleId = traceFunction("findModuleId", function findModuleId(...code: CodeFilter) { + code = code.map(canonicalizeMatch); + for (const id in wreq.m) { if (stringMatches(wreq.m[id].toString(), code)) return id; } @@ -452,12 +454,9 @@ export function findExportedComponentLazy(...props: Prop * }) */ export const mapMangledModule = traceFunction("mapMangledModule", function mapMangledModule(code: string | RegExp | CodeFilter, mappers: Record): Record { - if (!Array.isArray(code)) code = [code]; - code = code.map(canonicalizeMatch); - const exports = {} as Record; - const id = findModuleId(...code); + const id = findModuleId(...Array.isArray(code) ? code : [code]); if (id === null) return exports; @@ -606,6 +605,8 @@ export function waitFor(filter: string | PropsFilter | FilterFn, callback: Callb * @returns Mapping of found modules */ export function search(...code: CodeFilter) { + code = code.map(canonicalizeMatch); + const results = {} as Record; const factories = wreq.m; From 904022a2f76b74d3360cc7d3124f30e720eb9196 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?rini=20=E2=98=94?= Date: Sun, 18 Aug 2024 15:20:03 -0300 Subject: [PATCH 03/20] [Webkeybinds] Don't override browser keybinds (#2792) --- src/plugins/webKeybinds.web/index.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/plugins/webKeybinds.web/index.ts b/src/plugins/webKeybinds.web/index.ts index 12d485aac..1c43dc0cf 100644 --- a/src/plugins/webKeybinds.web/index.ts +++ b/src/plugins/webKeybinds.web/index.ts @@ -35,6 +35,7 @@ export default definePlugin({ if (hasCtrl) switch (e.key) { case "t": case "T": + if (!IS_VESKTOP) return; e.preventDefault(); if (e.shiftKey) { if (SelectedGuildStore.getGuildId()) NavigationRouter.transitionToGuild("@me"); @@ -47,14 +48,15 @@ export default definePlugin({ }); } break; + case "Tab": + if (!IS_VESKTOP) return; + const handler = e.shiftKey ? KeyBinds.SERVER_PREV : KeyBinds.SERVER_NEXT; + handler.action(e); + break; case ",": e.preventDefault(); SettingsRouter.open("My Account"); break; - case "Tab": - const handler = e.shiftKey ? KeyBinds.SERVER_PREV : KeyBinds.SERVER_NEXT; - handler.action(e); - break; default: if (e.key >= "1" && e.key <= "9") { e.preventDefault(); From 3d80cb2d551b43c54d2e2accf5d7b45fb575c60a Mon Sep 17 00:00:00 2001 From: Nuckyz <61953774+Nuckyz@users.noreply.github.com> Date: Mon, 19 Aug 2024 17:50:21 -0300 Subject: [PATCH 04/20] Delete AutomodContext ~ Now a stock feature --- src/plugins/automodContext/README.md | 5 -- src/plugins/automodContext/index.tsx | 73 ---------------------------- 2 files changed, 78 deletions(-) delete mode 100644 src/plugins/automodContext/README.md delete mode 100644 src/plugins/automodContext/index.tsx diff --git a/src/plugins/automodContext/README.md b/src/plugins/automodContext/README.md deleted file mode 100644 index f70d71d90..000000000 --- a/src/plugins/automodContext/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# AutomodContext - -Allows you to jump to the messages surrounding an automod hit - -![Visualization](https://github.com/Vendicated/Vencord/assets/61953774/d13740c8-2062-4553-b975-82fd3d6cc08b) diff --git a/src/plugins/automodContext/index.tsx b/src/plugins/automodContext/index.tsx deleted file mode 100644 index 5425c5526..000000000 --- a/src/plugins/automodContext/index.tsx +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Vencord, a Discord client mod - * Copyright (c) 2024 Vendicated and contributors - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -import ErrorBoundary from "@components/ErrorBoundary"; -import { Devs } from "@utils/constants"; -import definePlugin from "@utils/types"; -import { findByPropsLazy } from "@webpack"; -import { Button, ChannelStore, Text } from "@webpack/common"; - -const { selectChannel } = findByPropsLazy("selectChannel", "selectVoiceChannel"); - -function jumpToMessage(channelId: string, messageId: string) { - const guildId = ChannelStore.getChannel(channelId)?.guild_id; - - selectChannel({ - guildId, - channelId, - messageId, - jumpType: "INSTANT" - }); -} - -function findChannelId(message: any): string | null { - const { embeds: [embed] } = message; - const channelField = embed.fields.find(({ rawName }) => rawName === "channel_id"); - - if (!channelField) { - return null; - } - - return channelField.rawValue; -} - -export default definePlugin({ - name: "AutomodContext", - description: "Allows you to jump to the messages surrounding an automod hit.", - authors: [Devs.JohnyTheCarrot], - - patches: [ - { - find: ".Messages.GUILD_AUTOMOD_REPORT_ISSUES", - replacement: { - match: /\.Messages\.ACTIONS.+?}\)(?=,(\(0.{0,40}\.dot.*?}\)),)/, - replace: (m, dot) => `${m},${dot},$self.renderJumpButton({message:arguments[0].message})` - } - } - ], - - renderJumpButton: ErrorBoundary.wrap(({ message }: { message: any; }) => { - const channelId = findChannelId(message); - - if (!channelId) { - return null; - } - - return ( - - ); - }, { noop: true }) -}); From 66b247b2d3e6f1fda1621f5c0e154d6120b13bb2 Mon Sep 17 00:00:00 2001 From: Nuckyz <61953774+Nuckyz@users.noreply.github.com> Date: Tue, 20 Aug 2024 04:13:21 -0300 Subject: [PATCH 05/20] Fix persisting $$vencordPatchedSource when a module is loaded again --- src/webpack/patchWebpack.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/webpack/patchWebpack.ts b/src/webpack/patchWebpack.ts index 4629434ae..fb640cea8 100644 --- a/src/webpack/patchWebpack.ts +++ b/src/webpack/patchWebpack.ts @@ -355,8 +355,16 @@ function patchFactories(factories: Record Date: Thu, 22 Aug 2024 17:08:46 +0200 Subject: [PATCH 06/20] delete ShowAllRoles ~ now a stock feature --- src/plugins/showAllRoles/README.md | 6 ------ src/plugins/showAllRoles/index.ts | 23 ----------------------- 2 files changed, 29 deletions(-) delete mode 100644 src/plugins/showAllRoles/README.md delete mode 100644 src/plugins/showAllRoles/index.ts diff --git a/src/plugins/showAllRoles/README.md b/src/plugins/showAllRoles/README.md deleted file mode 100644 index d5d99c794..000000000 --- a/src/plugins/showAllRoles/README.md +++ /dev/null @@ -1,6 +0,0 @@ -# ShowAllRoles - -Display all roles on the new profiles instead of limiting them to the default two rows. - -![image](https://github.com/Vendicated/Vencord/assets/71079641/3f021f03-c6f9-4fe5-83ac-a1891b5e4b37) - diff --git a/src/plugins/showAllRoles/index.ts b/src/plugins/showAllRoles/index.ts deleted file mode 100644 index 97f0181fa..000000000 --- a/src/plugins/showAllRoles/index.ts +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Vencord, a Discord client mod - * Copyright (c) 2024 Vendicated and contributors - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -import { Devs } from "@utils/constants"; -import definePlugin from "@utils/types"; - -export default definePlugin({ - name: "ShowAllRoles", - description: "Show all roles in new profiles.", - authors: [Devs.Luna], - patches: [ - { - find: ".Messages.VIEW_ALL_ROLES", - replacement: { - match: /(\i)\.slice\(0,\i\)/, - replace: "$1" - } - } - ] -}); From 44c84634960bb6c1695c4681f49fff878c48bbab Mon Sep 17 00:00:00 2001 From: v Date: Thu, 22 Aug 2024 17:13:57 +0200 Subject: [PATCH 07/20] Remove obsolete patches for old profiles (#2800) Co-authored-by: Nuckyz <61953774+Nuckyz@users.noreply.github.com> --- src/plugins/_api/badges/index.tsx | 28 --------- src/plugins/betterNotes/index.tsx | 18 ------ src/plugins/friendsSince/index.tsx | 62 +------------------ src/plugins/moreUserTags/index.tsx | 4 +- src/plugins/mutualGroupDMs/index.tsx | 17 ----- src/plugins/noProfileThemes/index.ts | 9 --- src/plugins/permissionsViewer/index.tsx | 10 --- src/plugins/pronoundb/index.ts | 24 +------ src/plugins/reviewDB/index.tsx | 36 +---------- src/plugins/showConnections/index.tsx | 62 +++---------------- .../components/VoiceChannelSection.tsx | 8 +-- src/plugins/userVoiceShow/index.tsx | 20 +----- src/plugins/viewIcons/index.tsx | 16 ----- 13 files changed, 23 insertions(+), 291 deletions(-) diff --git a/src/plugins/_api/badges/index.tsx b/src/plugins/_api/badges/index.tsx index 89a992ac3..cf00a0e29 100644 --- a/src/plugins/_api/badges/index.tsx +++ b/src/plugins/_api/badges/index.tsx @@ -62,34 +62,6 @@ export default definePlugin({ authors: [Devs.Megu, Devs.Ven, Devs.TheSun], required: true, patches: [ - /* Patch the badge list component on user profiles */ - { - find: 'id:"premium",', - replacement: [ - { - match: /&&(\i)\.push\(\{id:"premium".+?\}\);/, - replace: "$&$1.unshift(...$self.getBadges(arguments[0]));", - }, - { - // alt: "", aria-hidden: false, src: originalSrc - match: /alt:" ","aria-hidden":!0,src:(?=(\i)\.src)/, - // ...badge.props, ..., src: badge.image ?? ... - replace: "...$1.props,$& $1.image??" - }, - // replace their component with ours if applicable - { - match: /(?<=text:(\i)\.description,spacing:12,.{0,50})children:/, - replace: "children:$1.component ? () => $self.renderBadgeComponent($1) :" - }, - // conditionally override their onClick with badge.onClick if it exists - { - match: /href:(\i)\.link/, - replace: "...($1.onClick && { onClick: vcE => $1.onClick(vcE, $1) }),$&" - } - ] - }, - - /* new profiles */ { find: ".FULL_SIZE]:26", replacement: { diff --git a/src/plugins/betterNotes/index.tsx b/src/plugins/betterNotes/index.tsx index b97076bf4..63fcf6477 100644 --- a/src/plugins/betterNotes/index.tsx +++ b/src/plugins/betterNotes/index.tsx @@ -17,13 +17,9 @@ */ import { definePluginSettings, Settings } from "@api/Settings"; -import ErrorBoundary from "@components/ErrorBoundary"; import { Devs } from "@utils/constants"; import { canonicalizeMatch } from "@utils/patches"; import definePlugin, { OptionType } from "@utils/types"; -import { findByPropsLazy } from "@webpack"; - -const UserPopoutSectionCssClasses = findByPropsLazy("section", "lastSection"); const settings = definePluginSettings({ hide: { @@ -72,23 +68,9 @@ export default definePlugin({ match: /\.NOTE_PLACEHOLDER,/, replace: "$&spellCheck:!$self.noSpellCheck," } - }, - { - find: ".popularApplicationCommandIds,", - replacement: { - match: /lastSection:(!?\i)}\),/, - replace: "$&$self.patchPadding({lastSection:$1})," - } } ], - patchPadding: ErrorBoundary.wrap(({ lastSection }) => { - if (!lastSection) return null; - return ( -
- ); - }), - get noSpellCheck() { return settings.store.noSpellCheck; } diff --git a/src/plugins/friendsSince/index.tsx b/src/plugins/friendsSince/index.tsx index 717bd754c..0399a2f72 100644 --- a/src/plugins/friendsSince/index.tsx +++ b/src/plugins/friendsSince/index.tsx @@ -16,7 +16,6 @@ const containerWrapper = findByPropsLazy("memberSinceWrapper"); const container = findByPropsLazy("memberSince"); const getCreatedAtDate = findByCodeLazy('month:"short",day:"numeric"'); const locale = findByPropsLazy("getLocale"); -const lastSection = findByPropsLazy("lastSection"); const section = findLazy((m: any) => m.section !== void 0 && m.heading !== void 0 && Object.values(m).length === 2); export default definePlugin({ @@ -24,31 +23,7 @@ export default definePlugin({ description: "Shows when you became friends with someone in the user popout", authors: [Devs.Elvyra, Devs.Antti], patches: [ - // User popup - old layout - { - find: ".USER_PROFILE}};return", - replacement: { - match: /,{userId:(\i.id).{0,30}}\)/, - replace: "$&,$self.friendsSinceOld({ userId: $1 })" - } - }, - // DM User Sidebar - old layout - { - find: ".PROFILE_PANEL,", - replacement: { - match: /,{userId:([^,]+?)}\)/, - replace: "$&,$self.friendsSinceOld({ userId: $1 })" - } - }, - // User Profile Modal - old layout - { - find: ".userInfoSectionHeader,", - replacement: { - match: /(\.Messages\.USER_PROFILE_MEMBER_SINCE.+?userId:(.+?),textClassName:)(\i\.userInfoText)}\)/, - replace: (_, rest, userId, textClassName) => `${rest}!$self.getFriendSince(${userId}) ? ${textClassName} : void 0 }), $self.friendsSinceOld({ userId: ${userId}, textClassName: ${textClassName} })` - } - }, - // DM User Sidebar - new layout + // DM User Sidebar { find: ".PANEL}),nicknameIcons", replacement: { @@ -56,7 +31,7 @@ export default definePlugin({ replace: "$&,$self.friendsSinceNew({userId:$1,isSidebar:true})" } }, - // User Profile Modal - new layout + // User Profile Modal { find: "action:\"PRESS_APP_CONNECTION\"", replacement: { @@ -77,39 +52,6 @@ export default definePlugin({ } }, - friendsSinceOld: ErrorBoundary.wrap(({ userId, textClassName }: { userId: string; textClassName?: string; }) => { - if (!RelationshipStore.isFriend(userId)) return null; - - const friendsSince = RelationshipStore.getSince(userId); - if (!friendsSince) return null; - - return ( -
- - Friends Since - - -
- {!!getCurrentChannel()?.guild_id && ( - - )} - - {getCreatedAtDate(friendsSince, locale.getLocale())} - -
-
- ); - }, { noop: true }), - friendsSinceNew: ErrorBoundary.wrap(({ userId, isSidebar }: { userId: string; isSidebar: boolean; }) => { if (!RelationshipStore.isFriend(userId)) return null; diff --git a/src/plugins/moreUserTags/index.tsx b/src/plugins/moreUserTags/index.tsx index 45538fb66..4802f04a1 100644 --- a/src/plugins/moreUserTags/index.tsx +++ b/src/plugins/moreUserTags/index.tsx @@ -247,9 +247,9 @@ export default definePlugin({ } }, { - find: 'copyMetaData:"User Tag"', + find: ".Messages.USER_PROFILE_PRONOUNS", replacement: { - match: /(?=,botClass:)/, + match: /(?=,hideBotTag:!0)/, replace: ",moreTags_channelId:arguments[0].moreTags_channelId" } }, diff --git a/src/plugins/mutualGroupDMs/index.tsx b/src/plugins/mutualGroupDMs/index.tsx index 7c71e1edb..a1e73cabf 100644 --- a/src/plugins/mutualGroupDMs/index.tsx +++ b/src/plugins/mutualGroupDMs/index.tsx @@ -58,20 +58,6 @@ export default definePlugin({ authors: [Devs.amia], patches: [ - { - find: ".Messages.MUTUAL_GUILDS_WITH_END_COUNT", // Note: the module is lazy-loaded - replacement: { - match: /(?<=\.tabBarItem.{0,50}MUTUAL_GUILDS.+?}\),)(?=.+?(\(0,\i\.jsxs?\)\(.{0,100}id:))/, - replace: '$self.isBotOrSelf(arguments[0].user)?null:$1"MUTUAL_GDMS",children:$self.getMutualGDMCountText(arguments[0].user)}),' - } - }, - { - find: ".USER_INFO_CONNECTIONS:case", - replacement: { - match: /(?<={user:(\i),onClose:(\i)}\);)(?=case \i\.\i\.MUTUAL_FRIENDS)/, - replace: "case \"MUTUAL_GDMS\":return $self.renderMutualGDMs({user: $1, onClose: $2});" - } - }, { find: ".MUTUAL_FRIENDS?(", replacement: [ @@ -87,9 +73,6 @@ export default definePlugin({ } ], - isBotOrSelf, - getMutualGDMCountText, - pushSection(sections: any[], user: User) { if (isBotOrSelf(user) || sections[IS_PATCHED]) return; diff --git a/src/plugins/noProfileThemes/index.ts b/src/plugins/noProfileThemes/index.ts index e2b9327e8..2cb83cc72 100644 --- a/src/plugins/noProfileThemes/index.ts +++ b/src/plugins/noProfileThemes/index.ts @@ -33,15 +33,6 @@ export default definePlugin({ replace: "=(arguments[0]?.bannerSrc||$1?.banner)&&" } }, - { - find: ".avatarPositionPremiumNoBanner,default:", - replacement: { - // premiumUserWithoutBanner: foo().avatarPositionPremiumNoBanner, default: foo().avatarPositionNormal - match: /\.avatarPositionPremiumNoBanner(?=,default:\i\.(\i))/, - // premiumUserWithoutBanner: foo().avatarPositionNormal... - replace: ".$1" - } - }, { find: "hasThemeColors(){", replacement: { diff --git a/src/plugins/permissionsViewer/index.tsx b/src/plugins/permissionsViewer/index.tsx index 6a503f2da..1bb8ea194 100644 --- a/src/plugins/permissionsViewer/index.tsx +++ b/src/plugins/permissionsViewer/index.tsx @@ -169,13 +169,6 @@ export default definePlugin({ settings, patches: [ - { - find: ".popularApplicationCommandIds,", - replacement: { - match: /showBorder:(.{0,60})}\),(?<=guild:(\i),guildMember:(\i),.+?)/, - replace: (m, showBoder, guild, guildMember) => `${m}$self.UserPermissions(${guild},${guildMember},${showBoder}),` - } - }, { find: ".VIEW_ALL_ROLES,", replacement: { @@ -185,9 +178,6 @@ export default definePlugin({ } ], - UserPermissions: (guild: Guild, guildMember: GuildMember | undefined, showBorder: boolean) => - !!guildMember && , - ViewPermissionsButton: ErrorBoundary.wrap(({ guild, guildMember }: { guild: Guild; guildMember: GuildMember; }) => ( { - const [reviewCount, setReviewCount] = useState(); - - return ( - openReviewsModal(user.id, user.username)} - moreTooltipText={ - reviewCount && reviewCount > 50 - ? `View all ${reviewCount} reviews` - : "Open Review Modal" - } - onDropDownClick={state => settings.store.reviewsDropdownState = !state} - defaultState={settings.store.reviewsDropdownState} - > - setReviewCount(r.reviewCount)} - showInput - /> - - ); - }, { message: "Failed to render Reviews" }), - BiteSizeReviewsButton: ErrorBoundary.wrap(({ user }: { user: User; }) => { return ( diff --git a/src/plugins/showConnections/index.tsx b/src/plugins/showConnections/index.tsx index f9f3d9eb7..d712027e3 100644 --- a/src/plugins/showConnections/index.tsx +++ b/src/plugins/showConnections/index.tsx @@ -25,15 +25,12 @@ import { CopyIcon, LinkIcon } from "@components/Icons"; import { Devs } from "@utils/constants"; import { copyWithToast } from "@utils/misc"; import definePlugin, { OptionType } from "@utils/types"; -import { findByCodeLazy, findByPropsLazy, findComponentByCodeLazy, findStoreLazy } from "@webpack"; -import { Text, Tooltip, UserProfileStore } from "@webpack/common"; +import { findByCodeLazy, findByPropsLazy } from "@webpack"; +import { Tooltip, UserProfileStore } from "@webpack/common"; import { User } from "discord-types/general"; import { VerifiedIcon } from "./VerifiedIcon"; -const Section = findComponentByCodeLazy(".lastSection", "children:"); -const ThemeStore = findStoreLazy("ThemeStore"); - const useLegacyPlatformType: (platform: string) => string = findByCodeLazy(".TWITTER_LEGACY:"); const platforms: { get(type: string): ConnectionPlatform; } = findByPropsLazy("isSupported", "getByUrl"); const getProfileThemeProps = findByCodeLazy(".getPreviewThemeColors", "primaryColor:"); @@ -76,7 +73,7 @@ interface ConnectionPlatform { } const profilePopoutComponent = ErrorBoundary.wrap( - (props: { user: User; displayProfile?: any; simplified?: boolean; }) => ( + (props: { user: User; displayProfile?: any; }) => ( ( - - ), - { noop: true } -); - -function ConnectionsComponent({ id, theme, simplified }: { id: string, theme: string, simplified?: boolean; }) { +function ConnectionsComponent({ id, theme }: { id: string, theme: string; }) { const profile = UserProfileStore.getUserProfile(id); if (!profile) return null; @@ -105,31 +92,14 @@ function ConnectionsComponent({ id, theme, simplified }: { id: string, theme: st if (!connections?.length) return null; - const connectionsContainer = ( + return ( {connections.map(connection => )} ); - - if (simplified) - return connectionsContainer; - - return ( -
- - Connections - - {connectionsContainer} -
- ); } function CompactConnectionComponent({ connection, theme }: { connection: Connection, theme: string; }) { @@ -194,31 +164,17 @@ export default definePlugin({ name: "ShowConnections", description: "Show connected accounts in user popouts", authors: [Devs.TheKodeToad], + settings, + patches: [ - { - find: "{isUsingGuildBio:null!==(", - replacement: { - match: /,theme:\i\}\)(?=,.{0,150}setNote:)/, - replace: "$&,$self.profilePopoutComponent({ user: arguments[0].user, displayProfile: arguments[0].displayProfile })" - } - }, - { - find: ".PROFILE_PANEL,", - replacement: { - // createElement(Divider, {}), createElement(NoteComponent) - match: /\(0,\i\.jsx\)\(\i\.\i,\{\}\).{0,100}setNote:(?=.+?channelId:(\i).id)/, - replace: "$self.profilePanelComponent({ id: $1.recipients[0] }),$&" - } - }, { find: '"BiteSizeProfileBody"', replacement: { match: /currentUser:\i,guild:\i}\)(?<=user:(\i),bio:null==(\i)\?.+?)/, - replace: "$&,$self.profilePopoutComponent({ user: $1, displayProfile: $2, simplified: true })" + replace: "$&,$self.profilePopoutComponent({ user: $1, displayProfile: $2 })" } } ], - settings, + profilePopoutComponent, - profilePanelComponent }); diff --git a/src/plugins/userVoiceShow/components/VoiceChannelSection.tsx b/src/plugins/userVoiceShow/components/VoiceChannelSection.tsx index c1bcbd657..8ca335bb6 100644 --- a/src/plugins/userVoiceShow/components/VoiceChannelSection.tsx +++ b/src/plugins/userVoiceShow/components/VoiceChannelSection.tsx @@ -18,12 +18,11 @@ import "./VoiceChannelSection.css"; -import { findByCodeLazy, findByPropsLazy } from "@webpack"; +import { findByPropsLazy } from "@webpack"; import { Button, Forms, PermissionStore, Toasts } from "@webpack/common"; import { Channel } from "discord-types/general"; const ChannelActions = findByPropsLazy("selectChannel", "selectVoiceChannel"); -const UserPopoutSection = findByCodeLazy(".lastSection", "children:"); const CONNECT = 1n << 20n; @@ -34,7 +33,8 @@ interface VoiceChannelFieldProps { } export const VoiceChannelSection = ({ channel, label, showHeader }: VoiceChannelFieldProps) => ( - + // @TODO The div is supposed to be a UserPopoutSection +
{showHeader && In a voice channel} - +
); diff --git a/src/plugins/userVoiceShow/index.tsx b/src/plugins/userVoiceShow/index.tsx index 53044a558..cad539b46 100644 --- a/src/plugins/userVoiceShow/index.tsx +++ b/src/plugins/userVoiceShow/index.tsx @@ -84,7 +84,7 @@ export default definePlugin({ ); }, - patchPopout: ({ user }: UserProps) => { + patchProfilePopout: ({ user }: UserProps) => { const isSelfUser = user.id === UserStore.getCurrentUser().id; return (
@@ -94,21 +94,7 @@ export default definePlugin({ }, patches: [ - // above message box - { - find: ".popularApplicationCommandIds,", - replacement: { - match: /(?<=,)(?=!\i&&!\i&&.{0,50}setNote:)/, - replace: "$self.patchPopout(arguments[0]),", - } - }, - // below username - { - find: ".Messages.MUTUAL_GUILDS_WITH_END_COUNT", // Lazy-loaded - replacement: { - match: /\.body.+?displayProfile:\i}\),/, - replace: "$&$self.patchModal(arguments[0]),", - } - } + // @TODO Maybe patch UserVoiceShow in simplified profile popout + // @TODO Patch new profile modal ], }); diff --git a/src/plugins/viewIcons/index.tsx b/src/plugins/viewIcons/index.tsx index 927a974f0..38d775540 100644 --- a/src/plugins/viewIcons/index.tsx +++ b/src/plugins/viewIcons/index.tsx @@ -192,14 +192,6 @@ export default definePlugin({ }, all: true }, - // Old Profiles Modal pfp - { - find: ".MODAL,hasProfileEffect", - replacement: { - match: /\{src:(\i)(?=,avatarDecoration)/, - replace: "{src:$1,onClick:()=>$self.openImage($1)" - } - }, // Banners ...[".NITRO_BANNER,", "=!1,canUsePremiumCustomization:"].map(find => ({ find, @@ -211,14 +203,6 @@ export default definePlugin({ 'onClick:ev=>$1&&ev.target.style.backgroundImage&&$self.openImage($2),style:{cursor:$1?"pointer":void 0,' } })), - // Old User DMs "User Profile" popup in the right - { - find: ".avatarPositionPanel", - replacement: { - match: /(avatarWrapperNonUserBot.{0,50})onClick:(\i\|\|\i)\?void 0(?<=,avatarSrc:(\i).+?)/, - replace: "$1style:($2)?{cursor:\"pointer\"}:{},onClick:$2?()=>{$self.openImage($3)}" - } - }, // Group DMs top small & large icon { find: /\.recipients\.length>=2(?! Date: Thu, 22 Aug 2024 20:29:39 -0300 Subject: [PATCH 08/20] PermissionsViewer: Fix user popout --- .../components/UserPermissions.tsx | 32 +++++++++---------- src/plugins/permissionsViewer/index.tsx | 2 +- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/plugins/permissionsViewer/components/UserPermissions.tsx b/src/plugins/permissionsViewer/components/UserPermissions.tsx index 49770bbe1..f53f93b6d 100644 --- a/src/plugins/permissionsViewer/components/UserPermissions.tsx +++ b/src/plugins/permissionsViewer/components/UserPermissions.tsx @@ -35,15 +35,17 @@ interface UserPermission { type UserPermissions = Array; -const Classes = proxyLazyWebpack(() => - Object.assign({}, ...findBulk( - filters.byProps("roles", "rolePill", "rolePillBorder"), - filters.byProps("roleCircle", "dotBorderBase", "dotBorderColor"), - filters.byProps("roleNameOverflow", "root", "roleName", "roleRemoveButton") - )) -) as Record<"roles" | "rolePill" | "rolePillBorder" | "desaturateUserColors" | "flex" | "alignCenter" | "justifyCenter" | "svg" | "background" | "dot" | "dotBorderColor" | "roleCircle" | "dotBorderBase" | "flex" | "alignCenter" | "justifyCenter" | "wrap" | "root" | "role" | "roleRemoveButton" | "roleDot" | "roleFlowerStar" | "roleRemoveIcon" | "roleRemoveIconFocused" | "roleVerifiedIcon" | "roleName" | "roleNameOverflow" | "actionButton" | "overflowButton" | "addButton" | "addButtonIcon" | "overflowRolesPopout" | "overflowRolesPopoutArrowWrapper" | "overflowRolesPopoutArrow" | "popoutBottom" | "popoutTop" | "overflowRolesPopoutHeader" | "overflowRolesPopoutHeaderIcon" | "overflowRolesPopoutHeaderText" | "roleIcon", string>; +const { RoleRootClasses, RoleClasses, RoleBorderClasses } = proxyLazyWebpack(() => { + const [RoleRootClasses, RoleClasses, RoleBorderClasses] = findBulk( + filters.byProps("root", "showMoreButton", "collapseButton"), + filters.byProps("role", "roleCircle", "roleName"), + filters.byProps("roleCircle", "dot", "dotBorderColor") + ) as Record[]; -function UserPermissionsComponent({ guild, guildMember, showBorder, forceOpen = false }: { guild: Guild; guildMember: GuildMember; showBorder: boolean; forceOpen?: boolean; }) { + return { RoleRootClasses, RoleClasses, RoleBorderClasses }; +}); + +function UserPermissionsComponent({ guild, guildMember, forceOpen = false }: { guild: Guild; guildMember: GuildMember; forceOpen?: boolean; }) { const stns = settings.use(["permissionsSortOrder"]); const [rolePermissions, userPermissions] = useMemo(() => { @@ -91,8 +93,6 @@ function UserPermissionsComponent({ guild, guildMember, showBorder, forceOpen = return [rolePermissions, userPermissions]; }, [stns.permissionsSortOrder]); - const { root, role, roleRemoveButton, roleNameOverflow, roles, rolePill, rolePillBorder, roleCircle, roleName } = Classes; - return ( ) ]}> {userPermissions.length > 0 && ( -
+
{userPermissions.map(({ permission, roleColor }) => ( -
-
+
+
-
+
{permission} diff --git a/src/plugins/permissionsViewer/index.tsx b/src/plugins/permissionsViewer/index.tsx index 1bb8ea194..5039d04f8 100644 --- a/src/plugins/permissionsViewer/index.tsx +++ b/src/plugins/permissionsViewer/index.tsx @@ -184,7 +184,7 @@ export default definePlugin({ align="center" renderPopout={() => ( - + )} > From ed9b28febf5da93e97ca80fbd89680c5f7a8abe6 Mon Sep 17 00:00:00 2001 From: Nuckyz <61953774+Nuckyz@users.noreply.github.com> Date: Fri, 23 Aug 2024 03:02:04 -0300 Subject: [PATCH 09/20] Fix ViewIcons and NoProfileThemes --- src/debug/loadLazyChunks.ts | 2 +- src/plugins/fakeProfileThemes/index.tsx | 2 +- src/plugins/noProfileThemes/index.ts | 33 ++++++++++++++++--------- src/plugins/usrbg/index.tsx | 13 +--------- src/plugins/viewIcons/index.tsx | 13 ++++------ 5 files changed, 29 insertions(+), 34 deletions(-) diff --git a/src/debug/loadLazyChunks.ts b/src/debug/loadLazyChunks.ts index d3484bd9a..73a89504f 100644 --- a/src/debug/loadLazyChunks.ts +++ b/src/debug/loadLazyChunks.ts @@ -134,7 +134,7 @@ export async function loadLazyChunks() { const allChunks = [] as number[]; // Matches "id" or id: - for (const currentMatch of wreq!.u.toString().matchAll(/(?:"([\deE]+?)")|(?:([\deE]+?):)/g)) { + for (const currentMatch of wreq!.u.toString().matchAll(/(?:"([\deE]+?)"(?![,}]))|(?:([\deE]+?):)/g)) { const id = currentMatch[1] ?? currentMatch[2]; if (id == null) continue; diff --git a/src/plugins/fakeProfileThemes/index.tsx b/src/plugins/fakeProfileThemes/index.tsx index ab240837b..708c961aa 100644 --- a/src/plugins/fakeProfileThemes/index.tsx +++ b/src/plugins/fakeProfileThemes/index.tsx @@ -121,7 +121,7 @@ export default definePlugin({ { find: "UserProfileStore", replacement: { - match: /(?<=getUserProfile\(\i\){return )(\i\[\i\])/, + match: /(?<=getUserProfile\(\i\){return )(.+?)(?=})/, replace: "$self.colorDecodeHook($1)" } }, diff --git a/src/plugins/noProfileThemes/index.ts b/src/plugins/noProfileThemes/index.ts index 2cb83cc72..d4737d43e 100644 --- a/src/plugins/noProfileThemes/index.ts +++ b/src/plugins/noProfileThemes/index.ts @@ -18,27 +18,36 @@ import { Devs } from "@utils/constants"; import definePlugin from "@utils/types"; +import { UserStore } from "@webpack/common"; +import virtualMerge from "virtual-merge"; export default definePlugin({ name: "NoProfileThemes", - description: "Completely removes Nitro profile themes", + description: "Completely removes Nitro profile themes from everyone but yourself", authors: [Devs.TheKodeToad], patches: [ - { - find: ".NITRO_BANNER,", - replacement: { - // = isPremiumAtLeast(user.premiumType, TIER_2) - match: /=(?=\i\.\i\.isPremiumAtLeast\(null==(\i))/, - // = user.banner && isPremiumAtLeast(user.premiumType, TIER_2) - replace: "=(arguments[0]?.bannerSrc||$1?.banner)&&" - } - }, { find: "hasThemeColors(){", replacement: { match: /get canUsePremiumProfileCustomization\(\){return /, - replace: "$&false &&" + replace: "$&$self.isCurrentUser(this.userId)&&" + } + }, + { + find: "UserProfileStore", + replacement: { + match: /(?<=getUserProfile\(\i\){return )(.+?)(?=})/, + replace: "$self.removeProfileThemes($1)" } } - ] + ], + + isCurrentUser: (userId: string) => userId === UserStore.getCurrentUser()?.id, + removeProfileThemes: (displayProfile: any) => { + if (displayProfile == null) return displayProfile; + + return displayProfile.userId === UserStore.getCurrentUser()?.id + ? displayProfile + : virtualMerge(displayProfile, { banner: undefined, profileEffectId: undefined }); + } }); diff --git a/src/plugins/usrbg/index.tsx b/src/plugins/usrbg/index.tsx index fbc75f52c..788a79ae7 100644 --- a/src/plugins/usrbg/index.tsx +++ b/src/plugins/usrbg/index.tsx @@ -57,14 +57,7 @@ export default definePlugin({ settings, patches: [ { - find: ".NITRO_BANNER,", - replacement: { - match: /\?\(0,\i\.jsx\)\(\i,{type:\i,shown/, - replace: "&&$self.shouldShowBadge(arguments[0])$&" - } - }, - { - find: ".banner)==null", + find: '.banner)==null?"COMPLETE"', replacement: { match: /(?<=void 0:)\i.getPreviewBanner\(\i,\i,\i\)/, replace: "$self.patchBannerUrl(arguments[0])||$&" @@ -109,10 +102,6 @@ export default definePlugin({ if (this.userHasBackground(displayProfile?.userId)) return this.getImageUrl(displayProfile?.userId); }, - shouldShowBadge({ displayProfile, user }: any) { - return displayProfile?.banner && (!this.userHasBackground(user.id) || settings.store.nitroFirst); - }, - userHasBackground(userId: string) { return !!this.data?.users[userId]; }, diff --git a/src/plugins/viewIcons/index.tsx b/src/plugins/viewIcons/index.tsx index 38d775540..c154de636 100644 --- a/src/plugins/viewIcons/index.tsx +++ b/src/plugins/viewIcons/index.tsx @@ -193,16 +193,13 @@ export default definePlugin({ all: true }, // Banners - ...[".NITRO_BANNER,", "=!1,canUsePremiumCustomization:"].map(find => ({ - find, + { + find: 'backgroundColor:"COMPLETE"', replacement: { - // style: { backgroundImage: shouldShowBanner ? "url(".concat(bannerUrl, - match: /style:\{(?=backgroundImage:(null!=\i)\?"url\("\.concat\((\i),)/, - replace: - // onClick: () => shouldShowBanner && ev.target.style.backgroundImage && openImage(bannerUrl), style: { cursor: shouldShowBanner ? "pointer" : void 0, - 'onClick:ev=>$1&&ev.target.style.backgroundImage&&$self.openImage($2),style:{cursor:$1?"pointer":void 0,' + match: /(\.banner,.+?),style:{(?=.+?backgroundImage:null!=(\i)\?"url\("\.concat\(\2,)/, + replace: (_, rest, bannerSrc) => `${rest},onClick:()=>${bannerSrc}!=null&&$self.openImage(${bannerSrc}),style:{cursor:${bannerSrc}!=null?"pointer":void 0,` } - })), + }, // Group DMs top small & large icon { find: /\.recipients\.length>=2(?! Date: Fri, 23 Aug 2024 18:54:12 +0300 Subject: [PATCH 10/20] MemberCount: add thread support (#2785) Co-authored-by: v --- src/plugins/memberCount/MemberCount.tsx | 12 +++++++++++- src/plugins/memberCount/index.tsx | 4 ++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/plugins/memberCount/MemberCount.tsx b/src/plugins/memberCount/MemberCount.tsx index 3231d01ce..084e7ecc4 100644 --- a/src/plugins/memberCount/MemberCount.tsx +++ b/src/plugins/memberCount/MemberCount.tsx @@ -5,9 +5,10 @@ */ import { getCurrentChannel } from "@utils/discord"; +import { isObjectEmpty } from "@utils/misc"; import { SelectedChannelStore, Tooltip, useEffect, useStateFromStores } from "@webpack/common"; -import { ChannelMemberStore, cl, GuildMemberCountStore, numberFormat } from "."; +import { ChannelMemberStore, cl, GuildMemberCountStore, numberFormat, ThreadMemberListStore } from "."; import { OnlineMemberCountStore } from "./OnlineMemberCountStore"; export function MemberCount({ isTooltip, tooltipGuildId }: { isTooltip?: true; tooltipGuildId?: string; }) { @@ -30,10 +31,19 @@ export function MemberCount({ isTooltip, tooltipGuildId }: { isTooltip?: true; t () => ChannelMemberStore.getProps(guildId, currentChannel?.id) ); + const threadGroups = useStateFromStores( + [ThreadMemberListStore], + () => ThreadMemberListStore.getMemberListSections(currentChannel.id) + ); + if (!isTooltip && (groups.length >= 1 || groups[0].id !== "unknown")) { onlineCount = groups.reduce((total, curr) => total + (curr.id === "offline" ? 0 : curr.count), 0); } + if (!isTooltip && threadGroups && !isObjectEmpty(threadGroups)) { + onlineCount = Object.values(threadGroups).reduce((total, curr) => total + (curr.sectionId === "offline" ? 0 : curr.userIds.length), 0); + } + useEffect(() => { OnlineMemberCountStore.ensureCount(guildId); }, [guildId]); diff --git a/src/plugins/memberCount/index.tsx b/src/plugins/memberCount/index.tsx index 28ecb9db7..7e591357d 100644 --- a/src/plugins/memberCount/index.tsx +++ b/src/plugins/memberCount/index.tsx @@ -32,6 +32,10 @@ export const GuildMemberCountStore = findStoreLazy("GuildMemberCountStore") as F export const ChannelMemberStore = findStoreLazy("ChannelMemberStore") as FluxStore & { getProps(guildId: string, channelId: string): { groups: { count: number; id: string; }[]; }; }; +export const ThreadMemberListStore = findStoreLazy("ThreadMemberListStore") as FluxStore & { + getMemberListSections(channelId: string): { [sectionId: string]: { sectionId: string; userIds: string[]; }; }; +}; + const settings = definePluginSettings({ toolTip: { From 8afcb8e4dd58efdb886fd7efb9890f64e6dc2bbe Mon Sep 17 00:00:00 2001 From: Supertiger Date: Fri, 23 Aug 2024 14:36:47 -0700 Subject: [PATCH 11/20] new plugin NoMaskedLinkPaste (#2782) Co-authored-by: v --- src/plugins/noMaskedUrlPaste/README.md | 3 +++ src/plugins/noMaskedUrlPaste/index.ts | 23 +++++++++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 src/plugins/noMaskedUrlPaste/README.md create mode 100644 src/plugins/noMaskedUrlPaste/index.ts diff --git a/src/plugins/noMaskedUrlPaste/README.md b/src/plugins/noMaskedUrlPaste/README.md new file mode 100644 index 000000000..36707ac93 --- /dev/null +++ b/src/plugins/noMaskedUrlPaste/README.md @@ -0,0 +1,3 @@ +# NoMaskedUrlPaste + +Pasting a link while you have text selected will NOT paste your link as a masked link. diff --git a/src/plugins/noMaskedUrlPaste/index.ts b/src/plugins/noMaskedUrlPaste/index.ts new file mode 100644 index 000000000..64f522cae --- /dev/null +++ b/src/plugins/noMaskedUrlPaste/index.ts @@ -0,0 +1,23 @@ +/* + * Vencord, a Discord client mod + * Copyright (c) 2023 Vendicated and contributors + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +import { Devs } from "@utils/constants.js"; +import definePlugin from "@utils/types"; + +export default definePlugin({ + name: "NoMaskedUrlPaste", + authors: [Devs.CatNoir], + description: "Pasting a link while having text selected will not paste as masked URL", + patches: [ + { + find: ".selection,preventEmojiSurrogates:", + replacement: { + match: /if\(null!=\i.selection&&\i.\i.isExpanded\(\i.selection\)\)/, + replace: "if(false)" + } + } + ], +}); From f0e6986835050dca5f6a73a693ee77c299e7763c Mon Sep 17 00:00:00 2001 From: Nuckyz <61953774+Nuckyz@users.noreply.github.com> Date: Fri, 23 Aug 2024 18:41:34 -0300 Subject: [PATCH 12/20] PronounDB: Fix on user profiles --- src/plugins/noProfileThemes/index.ts | 15 --------------- src/plugins/pronoundb/index.ts | 24 ++++++++++++++++++------ src/plugins/pronoundb/pronoundbUtils.ts | 17 +++++++++++------ 3 files changed, 29 insertions(+), 27 deletions(-) diff --git a/src/plugins/noProfileThemes/index.ts b/src/plugins/noProfileThemes/index.ts index d4737d43e..7c440df80 100644 --- a/src/plugins/noProfileThemes/index.ts +++ b/src/plugins/noProfileThemes/index.ts @@ -19,7 +19,6 @@ import { Devs } from "@utils/constants"; import definePlugin from "@utils/types"; import { UserStore } from "@webpack/common"; -import virtualMerge from "virtual-merge"; export default definePlugin({ name: "NoProfileThemes", @@ -33,21 +32,7 @@ export default definePlugin({ replace: "$&$self.isCurrentUser(this.userId)&&" } }, - { - find: "UserProfileStore", - replacement: { - match: /(?<=getUserProfile\(\i\){return )(.+?)(?=})/, - replace: "$self.removeProfileThemes($1)" - } - } ], isCurrentUser: (userId: string) => userId === UserStore.getCurrentUser()?.id, - removeProfileThemes: (displayProfile: any) => { - if (displayProfile == null) return displayProfile; - - return displayProfile.userId === UserStore.getCurrentUser()?.id - ? displayProfile - : virtualMerge(displayProfile, { banner: undefined, profileEffectId: undefined }); - } }); diff --git a/src/plugins/pronoundb/index.ts b/src/plugins/pronoundb/index.ts index 51486e6ec..b0c5bfe6f 100644 --- a/src/plugins/pronoundb/index.ts +++ b/src/plugins/pronoundb/index.ts @@ -26,11 +26,6 @@ import { CompactPronounsChatComponentWrapper, PronounsChatComponentWrapper } fro import { useProfilePronouns } from "./pronoundbUtils"; import { settings } from "./settings"; -const PRONOUN_TOOLTIP_PATCH = { - match: /text:(.{0,10}.Messages\.USER_PROFILE_PRONOUNS)(?=,)/, - replace: '$& + (typeof vcPronounSource !== "undefined" ? ` (${vcPronounSource})` : "")' -}; - export default definePlugin({ name: "PronounDB", authors: [Devs.Tyman, Devs.TheKodeToad, Devs.Ven, Devs.Elvyra], @@ -52,7 +47,24 @@ export default definePlugin({ ] }, - // @TODO Patch discord pronoun hook in user profiles (useProfilePronouns) + { + find: ".Messages.USER_PROFILE_PRONOUNS", + group: true, + replacement: [ + { + match: /\.PANEL},/, + replace: "$&[vcPronoun,vcPronounSource,vcHasPendingPronouns]=$self.useProfilePronouns(arguments[0].user?.id)," + }, + { + match: /text:\i\.\i.Messages.USER_PROFILE_PRONOUNS/, + replace: '$&+vcHasPendingPronouns?"":` (${vcPronounSource})`' + }, + { + match: /(\.pronounsText.+?children:)(\i)/, + replace: "$1vcHasPendingPronouns?$2:vcPronoun" + } + ] + } ], settings, diff --git a/src/plugins/pronoundb/pronoundbUtils.ts b/src/plugins/pronoundb/pronoundbUtils.ts index d4fdb09d3..991e9031a 100644 --- a/src/plugins/pronoundb/pronoundbUtils.ts +++ b/src/plugins/pronoundb/pronoundbUtils.ts @@ -21,13 +21,16 @@ import { debounce } from "@shared/debounce"; import { VENCORD_USER_AGENT } from "@shared/vencordUserAgent"; import { getCurrentChannel } from "@utils/discord"; import { useAwaiter } from "@utils/react"; +import { findStoreLazy } from "@webpack"; import { UserProfileStore, UserStore } from "@webpack/common"; import { settings } from "./settings"; import { CachePronouns, PronounCode, PronounMapping, PronounsResponse } from "./types"; -type PronounsWithSource = [string | null, string]; -const EmptyPronouns: PronounsWithSource = [null, ""]; +const UserSettingsAccountStore = findStoreLazy("UserSettingsAccountStore"); + +type PronounsWithSource = [pronouns: string | null, source: string, hasPendingPronouns: boolean]; +const EmptyPronouns: PronounsWithSource = [null, "", false]; export const enum PronounsFormat { Lowercase = "LOWERCASE", @@ -75,13 +78,15 @@ export function useFormattedPronouns(id: string, useGlobalProfile: boolean = fal onError: e => console.error("Fetching pronouns failed: ", e) }); + const hasPendingPronouns = UserSettingsAccountStore.getPendingPronouns() != null; + if (settings.store.pronounSource === PronounSource.PreferDiscord && discordPronouns) - return [discordPronouns, "Discord"]; + return [discordPronouns, "Discord", hasPendingPronouns]; if (result && result !== PronounMapping.unspecified) - return [result, "PronounDB"]; + return [result, "PronounDB", hasPendingPronouns]; - return [discordPronouns, "Discord"]; + return [discordPronouns, "Discord", hasPendingPronouns]; } export function useProfilePronouns(id: string, useGlobalProfile: boolean = false): PronounsWithSource { @@ -147,7 +152,7 @@ async function bulkFetchPronouns(ids: string[]): Promise { } } -export function extractPronouns(pronounSet?: { [locale: string]: PronounCode[] }): string { +export function extractPronouns(pronounSet?: { [locale: string]: PronounCode[]; }): string { if (!pronounSet || !pronounSet.en) return PronounMapping.unspecified; // PronounDB returns an empty set instead of {sets: {en: ["unspecified"]}}. const pronouns = pronounSet.en; From 1e8f59f13d73b361a5a726bdbe733a102747da22 Mon Sep 17 00:00:00 2001 From: Nuckyz <61953774+Nuckyz@users.noreply.github.com> Date: Fri, 23 Aug 2024 18:50:05 -0300 Subject: [PATCH 13/20] ReviewDB: Add view review button to other profiles types --- src/plugins/reviewDB/index.tsx | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/plugins/reviewDB/index.tsx b/src/plugins/reviewDB/index.tsx index 8f24131c0..caf9bacba 100644 --- a/src/plugins/reviewDB/index.tsx +++ b/src/plugins/reviewDB/index.tsx @@ -79,8 +79,22 @@ export default definePlugin({ { find: ".BITE_SIZE,user:", replacement: { - match: /(?<=\.BITE_SIZE,children:\[)\(0,\i\.jsx\)\(\i\.\i,\{user:(\i),/, - replace: "$self.BiteSizeReviewsButton({user:$1}),$&" + match: /{profileType:\i\.\i\.BITE_SIZE,children:\[/, + replace: "$&$self.BiteSizeReviewsButton({user:arguments[0].user})," + } + }, + { + find: ".FULL_SIZE,user:", + replacement: { + match: /{profileType:\i\.\i\.FULL_SIZE,children:\[/, + replace: "$&$self.BiteSizeReviewsButton({user:arguments[0].user})," + } + }, + { + find: ".PANEL,isInteractionSource:", + replacement: { + match: /{profileType:\i\.\i\.PANEL,children:\[/, + replace: "$&$self.BiteSizeReviewsButton({user:arguments[0].user})," } } ], From 1fb5e8df99442b959cfd55be6586d7ea5f92fa80 Mon Sep 17 00:00:00 2001 From: Nuckyz <61953774+Nuckyz@users.noreply.github.com> Date: Fri, 23 Aug 2024 19:00:26 -0300 Subject: [PATCH 14/20] Add missing methods to ExpressionPickerStore --- src/plugins/showConnections/index.tsx | 2 +- src/webpack/common/types/utils.d.ts | 19 ++++++++++++++++++- src/webpack/common/utils.ts | 10 ++++++---- 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/plugins/showConnections/index.tsx b/src/plugins/showConnections/index.tsx index d712027e3..a946e0433 100644 --- a/src/plugins/showConnections/index.tsx +++ b/src/plugins/showConnections/index.tsx @@ -168,7 +168,7 @@ export default definePlugin({ patches: [ { - find: '"BiteSizeProfileBody"', + find: ".hasAvatarForGuild(null==", replacement: { match: /currentUser:\i,guild:\i}\)(?<=user:(\i),bio:null==(\i)\?.+?)/, replace: "$&,$self.profilePopoutComponent({ user: $1, displayProfile: $2 })" diff --git a/src/webpack/common/types/utils.d.ts b/src/webpack/common/types/utils.d.ts index ce1e3e268..dd76d1ade 100644 --- a/src/webpack/common/types/utils.d.ts +++ b/src/webpack/common/types/utils.d.ts @@ -223,9 +223,26 @@ export interface Constants { FriendsSections: Record; } +export type ActiveView = LiteralUnion<"emoji" | "gif" | "sticker" | "soundboard", string>; + +export interface ExpressionPickerStoreState extends Record { + activeView: ActiveView | null; + lastActiveView: ActiveView | null; + activeViewType: any | null; + searchQuery: string; + isSearchSuggestion: boolean, + pickerId: string; +} + export interface ExpressionPickerStore { + openExpressionPicker(activeView: ActiveView, activeViewType?: any): void; closeExpressionPicker(activeViewType?: any): void; - openExpressionPicker(activeView: LiteralUnion<"emoji" | "gif" | "sticker", string>, activeViewType?: any): void; + toggleMultiExpressionPicker(activeViewType?: any): void; + toggleExpressionPicker(activeView: ActiveView, activeViewType?: any): void; + setExpressionPickerView(activeView: ActiveView): void; + setSearchQuery(searchQuery: string, isSearchSuggestion?: boolean): void; + useExpressionPickerStore(): ExpressionPickerStoreState; + useExpressionPickerStore(selector: (state: ExpressionPickerStoreState) => T): T; } export interface BrowserWindowFeatures { diff --git a/src/webpack/common/utils.ts b/src/webpack/common/utils.ts index 280b2ba90..f9cce556b 100644 --- a/src/webpack/common/utils.ts +++ b/src/webpack/common/utils.ts @@ -16,7 +16,6 @@ * along with this program. If not, see . */ -import { canonicalizeMatch } from "@utils/patches"; import type { Channel } from "discord-types/general"; // eslint-disable-next-line path-alias/no-relative @@ -162,11 +161,14 @@ export const InviteActions = findByPropsLazy("resolveInvite"); export const IconUtils: t.IconUtils = findByPropsLazy("getGuildBannerURL", "getUserAvatarURL"); -const openExpressionPickerMatcher = canonicalizeMatch(/setState\({activeView:\i,activeViewType:/); -// TODO: type export const ExpressionPickerStore: t.ExpressionPickerStore = mapMangledModuleLazy("expression-picker-last-active-view", { + openExpressionPicker: filters.byCode(/setState\({activeView:(?:(?!null)\i),activeViewType:/), closeExpressionPicker: filters.byCode("setState({activeView:null"), - openExpressionPicker: m => typeof m === "function" && openExpressionPickerMatcher.test(m.toString()), + toggleMultiExpressionPicker: filters.byCode(".EMOJI,"), + toggleExpressionPicker: filters.byCode(/getState\(\)\.activeView===\i\?\i\(\):\i\(/), + setExpressionPickerView: filters.byCode(/setState\({activeView:\i,lastActiveView:/), + setSearchQuery: filters.byCode("searchQuery:"), + useExpressionPickerStore: filters.byCode("Object.is") }); export const PopoutActions: t.PopoutActions = mapMangledModuleLazy('type:"POPOUT_WINDOW_OPEN"', { From 6659f2c4134ad9f284a8eac1b38ea16252c86c27 Mon Sep 17 00:00:00 2001 From: Vendicated Date: Sat, 24 Aug 2024 00:19:10 +0200 Subject: [PATCH 15/20] bump to v1.9.8 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 22b99f8bc..65d97f2e0 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "vencord", "private": "true", - "version": "1.9.7", + "version": "1.9.8", "description": "The cutest Discord client mod", "homepage": "https://github.com/Vendicated/Vencord#readme", "bugs": { From 7ec842d4b0c94ee10d598e7daa320549554a8978 Mon Sep 17 00:00:00 2001 From: Nuckyz <61953774+Nuckyz@users.noreply.github.com> Date: Fri, 23 Aug 2024 20:09:58 -0300 Subject: [PATCH 16/20] MoreUserTags: fix settings ui logic Co-authored-by: Vendicated --- src/api/Settings.ts | 4 ++++ src/plugins/moreUserTags/index.tsx | 29 +++++++---------------------- src/utils/types.ts | 2 ++ 3 files changed, 13 insertions(+), 22 deletions(-) diff --git a/src/api/Settings.ts b/src/api/Settings.ts index 88337a917..ac116f547 100644 --- a/src/api/Settings.ts +++ b/src/api/Settings.ts @@ -230,6 +230,10 @@ export function definePluginSettings< if (!definedSettings.pluginName) throw new Error("Cannot access settings before plugin is initialized"); return Settings.plugins[definedSettings.pluginName] as any; }, + get plain() { + if (!definedSettings.pluginName) throw new Error("Cannot access settings before plugin is initialized"); + return PlainSettings.plugins[definedSettings.pluginName] as any; + }, use: settings => useSettings( settings?.map(name => `plugins.${definedSettings.pluginName}.${name}`) as UseSettings[] ).plugins[definedSettings.pluginName] as any, diff --git a/src/plugins/moreUserTags/index.tsx b/src/plugins/moreUserTags/index.tsx index 4802f04a1..0a87c57a9 100644 --- a/src/plugins/moreUserTags/index.tsx +++ b/src/plugins/moreUserTags/index.tsx @@ -22,7 +22,7 @@ import { Devs } from "@utils/constants"; import { Margins } from "@utils/margins"; import definePlugin, { OptionType } from "@utils/types"; import { findByCodeLazy, findLazy } from "@webpack"; -import { Card, ChannelStore, Forms, GuildStore, PermissionsBits, Switch, TextInput, Tooltip, useState } from "@webpack/common"; +import { Card, ChannelStore, Forms, GuildStore, PermissionsBits, Switch, TextInput, Tooltip } from "@webpack/common"; import type { Permissions, RC } from "@webpack/types"; import type { Channel, Guild, Message, User } from "discord-types/general"; @@ -107,14 +107,8 @@ const defaultSettings = Object.fromEntries( tags.map(({ name, displayName }) => [name, { text: displayName, showInChat: true, showInNotChat: true }]) ) as TagSettings; -function SettingsComponent(props: { setValue(v: any): void; }) { - settings.store.tagSettings ??= defaultSettings; - - const [tagSettings, setTagSettings] = useState(settings.store.tagSettings as TagSettings); - const setValue = (v: TagSettings) => { - setTagSettings(v); - props.setValue(v); - }; +function SettingsComponent() { + const tagSettings = settings.store.tagSettings ??= defaultSettings; return ( @@ -137,19 +131,13 @@ function SettingsComponent(props: { setValue(v: any): void; }) { type="text" value={tagSettings[t.name]?.text ?? t.displayName} placeholder={`Text on tag (default: ${t.displayName})`} - onChange={v => { - tagSettings[t.name].text = v; - setValue(tagSettings); - }} + onChange={v => tagSettings[t.name].text = v} className={Margins.bottom16} /> { - tagSettings[t.name].showInChat = v; - setValue(tagSettings); - }} + onChange={v => tagSettings[t.name].showInChat = v} hideBorder > Show in messages @@ -157,10 +145,7 @@ function SettingsComponent(props: { setValue(v: any): void; }) { { - tagSettings[t.name].showInNotChat = v; - setValue(tagSettings); - }} + onChange={v => tagSettings[t.name].showInNotChat = v} hideBorder > Show in member list and profiles @@ -183,7 +168,7 @@ const settings = definePluginSettings({ tagSettings: { type: OptionType.COMPONENT, component: SettingsComponent, - description: "fill me", + description: "fill me" } }); diff --git a/src/utils/types.ts b/src/utils/types.ts index 8c24843f8..e5486e9a5 100644 --- a/src/utils/types.ts +++ b/src/utils/types.ts @@ -309,6 +309,8 @@ export interface DefinedSettings< > { /** Shorthand for `Vencord.Settings.plugins.PluginName`, but with typings */ store: SettingsStore & PrivateSettings; + /** Shorthand for `Vencord.PlainSettings.plugins.PluginName`, but with typings */ + plain: SettingsStore & PrivateSettings; /** * React hook for getting the settings for this plugin * @param filter optional filter to avoid rerenders for irrelevent settings From 4b16fbcaa9b8b0b2401dfd48d7690e7830d82af8 Mon Sep 17 00:00:00 2001 From: SerStars <90714930+SerStars@users.noreply.github.com> Date: Mon, 26 Aug 2024 12:27:00 +0200 Subject: [PATCH 17/20] MentionAvatars: Also display role icons in role mentions (#2801) Co-authored-by: Vendicated --- src/plugins/mentionAvatars/README.md | 3 +- src/plugins/mentionAvatars/index.tsx | 59 ++++++++++++++++++++++++--- src/plugins/mentionAvatars/styles.css | 7 +++- src/utils/constants.ts | 4 ++ 4 files changed, 64 insertions(+), 9 deletions(-) diff --git a/src/plugins/mentionAvatars/README.md b/src/plugins/mentionAvatars/README.md index 912b51916..5e553419e 100644 --- a/src/plugins/mentionAvatars/README.md +++ b/src/plugins/mentionAvatars/README.md @@ -1,5 +1,6 @@ # MentionAvatars -Shows user avatars inside mentions +Shows user avatars and role icons inside mentions ![](https://github.com/user-attachments/assets/fc76ea47-5e19-4063-a592-c57785a75cc7) +![](https://github.com/user-attachments/assets/76c4c3d9-7cde-42db-ba84-903cbb40c163) diff --git a/src/plugins/mentionAvatars/index.tsx b/src/plugins/mentionAvatars/index.tsx index 311303ab9..53ab93e38 100644 --- a/src/plugins/mentionAvatars/index.tsx +++ b/src/plugins/mentionAvatars/index.tsx @@ -10,21 +10,42 @@ import { definePluginSettings } from "@api/Settings"; import ErrorBoundary from "@components/ErrorBoundary"; import { Devs } from "@utils/constants"; import definePlugin, { OptionType } from "@utils/types"; -import { SelectedGuildStore, useState } from "@webpack/common"; +import { GuildStore, SelectedGuildStore, useState } from "@webpack/common"; import { User } from "discord-types/general"; const settings = definePluginSettings({ showAtSymbol: { type: OptionType.BOOLEAN, - description: "Whether the the @ symbol should be displayed", + description: "Whether the the @ symbol should be displayed on user mentions", default: true } }); +function DefaultRoleIcon() { + return ( + + + + + + ); +} + export default definePlugin({ name: "MentionAvatars", - description: "Shows user avatars inside mentions", - authors: [Devs.Ven], + description: "Shows user avatars and role icons inside mentions", + authors: [Devs.Ven, Devs.SerStars], patches: [{ find: ".USER_MENTION)", @@ -32,6 +53,13 @@ export default definePlugin({ match: /children:"@"\.concat\((null!=\i\?\i:\i)\)(?<=\.useName\((\i)\).+?)/, replace: "children:$self.renderUsername({username:$1,user:$2})" } + }, + { + find: ".ROLE_MENTION)", + replacement: { + match: /children:\[\i&&.{0,50}\.RoleDot.{0,300},\i(?=\])/, + replace: "$&,$self.renderRoleIcon(arguments[0])" + } }], settings, @@ -47,12 +75,31 @@ export default definePlugin({ onMouseEnter={() => setIsHovering(true)} onMouseLeave={() => setIsHovering(false)} > - + {getUsernameString(username)} ); - }, { noop: true }) + }, { noop: true }), + renderRoleIcon: ErrorBoundary.wrap(({ roleId, guildId }: { roleId: string, guildId: string; }) => { + // Discord uses Role Mentions for uncached users because .... idk + if (!roleId) return null; + + const role = GuildStore.getRole(guildId, roleId); + + if (!role?.icon) return ; + + return ( + + ); + }), }); function getUsernameString(username: string) { diff --git a/src/plugins/mentionAvatars/styles.css b/src/plugins/mentionAvatars/styles.css index 022f968c0..64eb41416 100644 --- a/src/plugins/mentionAvatars/styles.css +++ b/src/plugins/mentionAvatars/styles.css @@ -1,8 +1,11 @@ -.vc-mentionAvatars-avatar { +.vc-mentionAvatars-icon { vertical-align: middle; width: 1em !important; /* insane discord sets width: 100% in channel topic */ height: 1em; margin: 0 4px 0.2rem 2px; - border-radius: 50%; box-sizing: border-box; } + +.vc-mentionAvatars-role-icon { + margin: 0 2px 0.2rem 4px; +} diff --git a/src/utils/constants.ts b/src/utils/constants.ts index febb8f9af..d27759e95 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -546,6 +546,10 @@ export const Devs = /* #__PURE__*/ Object.freeze({ name: "Lumap", id: 585278686291427338n, }, + SerStars: { + name: "SerStars", + id: 861631850681729045n, + }, } satisfies Record); // iife so #__PURE__ works correctly From 7d8214fc37b4f4baeca1c7deb06ef37147c70fde Mon Sep 17 00:00:00 2001 From: Nuckyz <61953774+Nuckyz@users.noreply.github.com> Date: Wed, 28 Aug 2024 02:10:20 -0300 Subject: [PATCH 18/20] Fix PermissionsViewer on user popouts --- src/plugins/permissionsViewer/components/UserPermissions.tsx | 2 +- src/plugins/permissionsViewer/index.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/permissionsViewer/components/UserPermissions.tsx b/src/plugins/permissionsViewer/components/UserPermissions.tsx index f53f93b6d..dc2aa6fa4 100644 --- a/src/plugins/permissionsViewer/components/UserPermissions.tsx +++ b/src/plugins/permissionsViewer/components/UserPermissions.tsx @@ -37,7 +37,7 @@ type UserPermissions = Array; const { RoleRootClasses, RoleClasses, RoleBorderClasses } = proxyLazyWebpack(() => { const [RoleRootClasses, RoleClasses, RoleBorderClasses] = findBulk( - filters.byProps("root", "showMoreButton", "collapseButton"), + filters.byProps("root", "expandButton", "collapseButton"), filters.byProps("role", "roleCircle", "roleName"), filters.byProps("roleCircle", "dot", "dotBorderColor") ) as Record[]; diff --git a/src/plugins/permissionsViewer/index.tsx b/src/plugins/permissionsViewer/index.tsx index 5039d04f8..7c3967a37 100644 --- a/src/plugins/permissionsViewer/index.tsx +++ b/src/plugins/permissionsViewer/index.tsx @@ -172,7 +172,7 @@ export default definePlugin({ { find: ".VIEW_ALL_ROLES,", replacement: { - match: /children:"\+"\.concat\(\i\.length-\i\.length\).{0,20}\}\),/, + match: /\.collapseButton,.+?}\)}\),/, replace: "$&$self.ViewPermissionsButton(arguments[0])," } } From 5bfc608f7dc9e6c82f03adf3313a1c83e390291b Mon Sep 17 00:00:00 2001 From: Surge <112782958+surgedevs@users.noreply.github.com> Date: Thu, 29 Aug 2024 08:43:52 +0200 Subject: [PATCH 19/20] new plugin AlwaysExpandRoles ~ Alternative to ShowAllRoles (#2809) --- src/plugins/alwaysExpandRoles/README.md | 3 ++ src/plugins/alwaysExpandRoles/index.ts | 37 +++++++++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 src/plugins/alwaysExpandRoles/README.md create mode 100644 src/plugins/alwaysExpandRoles/index.ts diff --git a/src/plugins/alwaysExpandRoles/README.md b/src/plugins/alwaysExpandRoles/README.md new file mode 100644 index 000000000..344268cbf --- /dev/null +++ b/src/plugins/alwaysExpandRoles/README.md @@ -0,0 +1,3 @@ +# Always Expand Roles + +Always expands the role list in profile popouts diff --git a/src/plugins/alwaysExpandRoles/index.ts b/src/plugins/alwaysExpandRoles/index.ts new file mode 100644 index 000000000..1c20b9777 --- /dev/null +++ b/src/plugins/alwaysExpandRoles/index.ts @@ -0,0 +1,37 @@ +/* + * 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 . +*/ + +import { migratePluginSettings } from "@api/Settings"; +import { Devs } from "@utils/constants"; +import definePlugin from "@utils/types"; + +migratePluginSettings("AlwaysExpandRoles", "ShowAllRoles"); +export default definePlugin({ + name: "AlwaysExpandRoles", + description: "Always expands the role list in profile popouts", + authors: [Devs.surgedevs], + patches: [ + { + find: 'action:"EXPAND_ROLES"', + replacement: { + match: /(roles:\i(?=.+?(\i)\(!0\)[,;]\i\({action:"EXPAND_ROLES"}\)).+?\[\i,\2\]=\i\.useState\()!1\)/, + replace: (_, rest, setExpandedRoles) => `${rest}!0)` + } + } + ] +}); From db2f5c9292ad40c5939e1023b21aed622a793a6f Mon Sep 17 00:00:00 2001 From: Nuckyz <61953774+Nuckyz@users.noreply.github.com> Date: Thu, 29 Aug 2024 03:56:21 -0300 Subject: [PATCH 20/20] ConsoleJanitor: Remove non needed patch notosans no longer errors --- src/plugins/consoleJanitor/index.ts | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/plugins/consoleJanitor/index.ts b/src/plugins/consoleJanitor/index.ts index dfb59957d..e847c4124 100644 --- a/src/plugins/consoleJanitor/index.ts +++ b/src/plugins/consoleJanitor/index.ts @@ -60,13 +60,6 @@ export default definePlugin({ replace: "" } }, - { - find: "notosans-400-normalitalic", - replacement: { - match: /,"notosans-.+?"/g, - replace: "" - } - }, { find: 'console.warn("[DEPRECATED] Please use `subscribeWithSelector` middleware");', all: true,