From a0308e03affd9345fe8774e528113ca280725d0e Mon Sep 17 00:00:00 2001 From: Nuckyz <61953774+Nuckyz@users.noreply.github.com> Date: Tue, 19 Nov 2024 21:17:20 -0300 Subject: [PATCH 01/23] Fix OpenInApp & ShowHiddenThings --- .../decor/ui/modals/ChangeDecorationModal.tsx | 12 ++++++++---- .../decor/ui/modals/CreateDecorationModal.tsx | 2 +- src/plugins/openInApp/index.ts | 2 +- src/plugins/showHiddenThings/index.ts | 2 +- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/plugins/decor/ui/modals/ChangeDecorationModal.tsx b/src/plugins/decor/ui/modals/ChangeDecorationModal.tsx index 6501e0fe..a3edc097 100644 --- a/src/plugins/decor/ui/modals/ChangeDecorationModal.tsx +++ b/src/plugins/decor/ui/modals/ChangeDecorationModal.tsx @@ -10,6 +10,7 @@ import { openInviteModal } from "@utils/discord"; import { Margins } from "@utils/margins"; import { classes, copyWithToast } from "@utils/misc"; import { closeAllModals, ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalProps, ModalRoot, ModalSize, openModal } from "@utils/modal"; +import { Queue } from "@utils/Queue"; import { findComponentByCodeLazy } from "@webpack"; import { Alerts, Button, FluxDispatcher, Forms, GuildStore, NavigationRouter, Parser, Text, Tooltip, useEffect, UserStore, UserUtils, useState } from "@webpack/common"; import { User } from "discord-types/general"; @@ -49,6 +50,8 @@ interface SectionHeaderProps { section: Section; } +const fetchAuthorsQueue = new Queue(); + function SectionHeader({ section }: SectionHeaderProps) { const hasSubtitle = typeof section.subtitle !== "undefined"; const hasAuthorIds = typeof section.authorIds !== "undefined"; @@ -56,17 +59,18 @@ function SectionHeader({ section }: SectionHeaderProps) { const [authors, setAuthors] = useState([]); useEffect(() => { - (async () => { + fetchAuthorsQueue.push(async () => { if (!section.authorIds) return; for (const authorId of section.authorIds) { - const author = UserStore.getUser(authorId) ?? await UserUtils.getUser(authorId); + const author = UserStore.getUser(authorId) ?? await UserUtils.getUser(authorId).catch(() => null); + if (author == null) continue; + setAuthors(authors => [...authors, author]); } - })(); + }); }, [section.authorIds]); - return
{section.title} diff --git a/src/plugins/decor/ui/modals/CreateDecorationModal.tsx b/src/plugins/decor/ui/modals/CreateDecorationModal.tsx index 57a39540..eb39c16d 100644 --- a/src/plugins/decor/ui/modals/CreateDecorationModal.tsx +++ b/src/plugins/decor/ui/modals/CreateDecorationModal.tsx @@ -119,7 +119,7 @@ function CreateDecorationModal(props: ModalProps) { />
- + To receive updates on your decoration's review, join { diff --git a/src/plugins/openInApp/index.ts b/src/plugins/openInApp/index.ts index 1e4f3041..2d27c2b2 100644 --- a/src/plugins/openInApp/index.ts +++ b/src/plugins/openInApp/index.ts @@ -87,7 +87,7 @@ export default definePlugin({ { find: "trackAnnouncementMessageLinkClicked({", replacement: { - match: /function (\i\(\i,\i\)\{)(?=.{0,100}trusted:)/, + match: /function (\i\(\i,\i\)\{)(?=.{0,150}trusted:)/, replace: "async function $1 if(await $self.handleLink(...arguments)) return;" } }, diff --git a/src/plugins/showHiddenThings/index.ts b/src/plugins/showHiddenThings/index.ts index 8fd6ef82..9f6fd2a9 100644 --- a/src/plugins/showHiddenThings/index.ts +++ b/src/plugins/showHiddenThings/index.ts @@ -107,7 +107,7 @@ export default definePlugin({ predicate: () => settings.store.disableDisallowedDiscoveryFilters, all: true, replacement: { - match: /\i\.\i\.get\(\{url:\i\.\i\.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,rejectWithError:!1\}\)/g, replace: "Promise.resolve({ body: { valid: true } })" } } From 13993f3f69d587c247900589a88e4264cc57b0c8 Mon Sep 17 00:00:00 2001 From: sadan4 <117494111+sadan4@users.noreply.github.com> Date: Sat, 23 Nov 2024 21:01:58 -0500 Subject: [PATCH 02/23] Decor: Fix avatar decorations not showing (again) (#3025) --- src/plugins/consoleJanitor/index.ts | 21 --------------------- src/webpack/common/utils.ts | 4 ++-- 2 files changed, 2 insertions(+), 23 deletions(-) diff --git a/src/plugins/consoleJanitor/index.ts b/src/plugins/consoleJanitor/index.ts index a02fcad1..2c29bf67 100644 --- a/src/plugins/consoleJanitor/index.ts +++ b/src/plugins/consoleJanitor/index.ts @@ -130,27 +130,6 @@ export default definePlugin({ replace: "" } }, - // Zustand section - { - find: "[DEPRECATED] Passing a vanilla store will be unsupported in a future version. Instead use `import { useStore } from 'zustand'`.", - replacement: [ - { - match: /&&console\.warn\("\[DEPRECATED\] Passing a vanilla store will be unsupported in a future version\. Instead use `import { useStore } from 'zustand'`\."\)/, - replace: "" - }, - { - match: /console\.warn\("\[DEPRECATED\] Use `createWithEqualityFn` instead of `create` or use `useStoreWithEqualityFn` instead of `useStore`\. They can be imported from 'zustand\/traditional'\. https:\/\/github\.com\/pmndrs\/zustand\/discussions\/1937"\),/, - replace: "" - } - ] - }, - { - find: "[DEPRECATED] `getStorage`, `serialize` and `deserialize` options are deprecated. Use `storage` option instead.", - replacement: { - match: /console\.warn\("\[DEPRECATED\] `getStorage`, `serialize` and `deserialize` options are deprecated\. Use `storage` option instead\."\),/, - replace: "" - } - }, // Patches discords generic logger function { find: "Σ:", diff --git a/src/webpack/common/utils.ts b/src/webpack/common/utils.ts index 4b1959b5..dc337a2e 100644 --- a/src/webpack/common/utils.ts +++ b/src/webpack/common/utils.ts @@ -163,8 +163,8 @@ waitFor(["open", "saveAccountChanges"], m => SettingsRouter = m); export const PermissionsBits: t.PermissionsBits = findLazy(m => typeof m.ADMINISTRATOR === "bigint"); -export const { zustandCreate } = mapMangledModuleLazy(["useSyncExternalStoreWithSelector:", "Object.assign", /(\i)\?(\i)\(\1\):\2/], { - zustandCreate: filters.byCode(/(\i)\?(\i)\(\1\):\2/) +export const { zustandCreate } = mapMangledModuleLazy(["useSyncExternalStoreWithSelector:", "Object.assign"], { + zustandCreate: filters.byCode(/=>(\i)\?\i\(\1/) }); export const { zustandPersist } = mapMangledModuleLazy(".onRehydrateStorage)?", { From ac1b1d44f5d994cd8d3c44e58f28bd1d76842cef Mon Sep 17 00:00:00 2001 From: sadan4 <117494111+sadan4@users.noreply.github.com> Date: Sat, 23 Nov 2024 21:03:59 -0500 Subject: [PATCH 03/23] ShowHiddenChannels: Fix viewing voice channels (#3033) --- src/plugins/showHiddenChannels/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/showHiddenChannels/index.tsx b/src/plugins/showHiddenChannels/index.tsx index ba367542..6b67aee8 100644 --- a/src/plugins/showHiddenChannels/index.tsx +++ b/src/plugins/showHiddenChannels/index.tsx @@ -103,7 +103,7 @@ export default definePlugin({ replacement: [ { // Do not show confirmation to join a voice channel when already connected to another if clicking on a hidden voice channel - match: /(?<=getBlockedUsersForVoiceChannel\((\i)\.id\);return\()/, + match: /(?<=getIgnoredUsersForVoiceChannel\((\i)\.id\);return\()/, replace: (_, channel) => `!$self.isHiddenChannel(${channel})&&` }, { From f22d0e14a42fc600a4768afd3855cd5959829b81 Mon Sep 17 00:00:00 2001 From: sadan4 <117494111+sadan4@users.noreply.github.com> Date: Sat, 23 Nov 2024 21:07:46 -0500 Subject: [PATCH 04/23] EmoteCloner: Fix recognizing animated emojis (#3027) --- src/plugins/emoteCloner/index.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/emoteCloner/index.tsx b/src/plugins/emoteCloner/index.tsx index 6dd3eb30..1b26e2f0 100644 --- a/src/plugins/emoteCloner/index.tsx +++ b/src/plugins/emoteCloner/index.tsx @@ -310,7 +310,8 @@ function buildMenuItem(type: "Emoji" | "Sticker", fetchData: () => Promisable { From f8dfe217b11844c2a08c1d3890def4a82cb192b8 Mon Sep 17 00:00:00 2001 From: Cassie <37855219+CodeF53@users.noreply.github.com> Date: Sat, 23 Nov 2024 19:08:53 -0700 Subject: [PATCH 05/23] Remove no-longer desired collaborator (#3032) --- src/plugins/clientTheme/index.tsx | 2 +- src/utils/constants.ts | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/plugins/clientTheme/index.tsx b/src/plugins/clientTheme/index.tsx index 7e648427..4c1668aa 100644 --- a/src/plugins/clientTheme/index.tsx +++ b/src/plugins/clientTheme/index.tsx @@ -110,7 +110,7 @@ const settings = definePluginSettings({ export default definePlugin({ name: "ClientTheme", - authors: [Devs.F53, Devs.Nuckyz], + authors: [Devs.Nuckyz], description: "Recreation of the old client theme experiment. Add a color to your Discord client theme", settings, diff --git a/src/utils/constants.ts b/src/utils/constants.ts index 362a22de..e7582591 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -267,10 +267,6 @@ export const Devs = /* #__PURE__*/ Object.freeze({ name: "arHSM", id: 841509053422632990n }, - F53: { - name: "Cassie (Code)", - id: 280411966126948353n - }, AutumnVN: { name: "AutumnVN", id: 393694671383166998n From 7ca4ea3d136db420e29f82535b2c6f1d59e6aa28 Mon Sep 17 00:00:00 2001 From: Hen <68553709+henmalib@users.noreply.github.com> Date: Sun, 24 Nov 2024 03:16:41 +0100 Subject: [PATCH 06/23] RoleColorEverywhere: Fix message headers colors (#3036) --- src/plugins/roleColorEverywhere/index.tsx | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/plugins/roleColorEverywhere/index.tsx b/src/plugins/roleColorEverywhere/index.tsx index 090c35d3..7b811943 100644 --- a/src/plugins/roleColorEverywhere/index.tsx +++ b/src/plugins/roleColorEverywhere/index.tsx @@ -156,7 +156,7 @@ export default definePlugin({ find: "#{intl::MESSAGE_EDITED}", replacement: { match: /(?<=isUnsupported\]:(\i)\.isUnsupported\}\),)(?=children:\[)/, - replace: "style:$self.useMessageColorStyle($1)," + replace: "style:$self.useMessageColorsStyle($1)," }, predicate: () => settings.store.colorChatMessages } @@ -188,13 +188,19 @@ export default definePlugin({ }; }, - useMessageColor(message: any) { + useMessageColorsStyle(message: any) { try { const { messageSaturation } = settings.use(["messageSaturation"]); const author = useMessageAuthor(message); if (author.colorString != null && messageSaturation !== 0) { - return `color-mix(in oklab, ${author.colorString} ${messageSaturation}%, var(--text-normal))`; + const value = `color-mix(in oklab, ${author.colorString} ${messageSaturation}%, var({DEFAULT}))`; + + return { + color: value.replace("{DEFAULT}", "--text-normal"), + "--header-primary": value.replace("{DEFAULT}", "--header-primary"), + "--text-muted": value.replace("{DEFAULT}", "--text-muted") + }; } } catch (e) { new Logger("RoleColorEverywhere").error("Failed to get message color", e); @@ -203,14 +209,6 @@ export default definePlugin({ return null; }, - useMessageColorStyle(message: any) { - const color = this.useMessageColor(message); - - return color && { - color - }; - }, - RoleGroupColor: ErrorBoundary.wrap(({ id, count, title, guildId, label }: { id: string; count: number; title: string; guildId: string; label: string; }) => { const role = GuildStore.getRole(guildId, id); From 2bfeef88caa95d8af170807666c8595818fb2c48 Mon Sep 17 00:00:00 2001 From: samara Date: Sat, 23 Nov 2024 18:23:03 -0800 Subject: [PATCH 07/23] Update to newer Discord icons in Vencord Settings (#3029) --- src/components/Icons.tsx | 52 +++++++++++-------- .../PluginSettings/LinkIconButton.tsx | 7 ++- 2 files changed, 35 insertions(+), 24 deletions(-) diff --git a/src/components/Icons.tsx b/src/components/Icons.tsx index d0d2ecbe..e48cfe5f 100644 --- a/src/components/Icons.tsx +++ b/src/components/Icons.tsx @@ -18,7 +18,7 @@ import "./iconStyles.css"; -import { getIntlMessage, getTheme, Theme } from "@utils/discord"; +import { getIntlMessage } from "@utils/discord"; import { classes } from "@utils/misc"; import type { PropsWithChildren } from "react"; @@ -122,8 +122,8 @@ export function InfoIcon(props: IconProps) { > ); @@ -211,9 +211,10 @@ export function CogWheel(props: IconProps) { viewBox="0 0 24 24" > ); @@ -406,23 +407,30 @@ export function PencilIcon(props: IconProps) { ); } -const WebsiteIconDark = "/assets/e1e96d89e192de1997f73730db26e94f.svg"; -const WebsiteIconLight = "/assets/730f58bcfd5a57a5e22460c445a0c6cf.svg"; -const GithubIconLight = "/assets/3ff98ad75ac94fa883af5ed62d17c459.svg"; -const GithubIconDark = "/assets/6a853b4c87fce386cbfef4a2efbacb09.svg"; - -export function GithubIcon(props: ImageProps) { - const src = getTheme() === Theme.Light - ? GithubIconLight - : GithubIconDark; - - return ; +export function GithubIcon(props: IconProps) { + return ( + + + + ); } -export function WebsiteIcon(props: ImageProps) { - const src = getTheme() === Theme.Light - ? WebsiteIconLight - : WebsiteIconDark; - - return ; +export function WebsiteIcon(props: IconProps) { + return ( + + + + ); } diff --git a/src/components/PluginSettings/LinkIconButton.tsx b/src/components/PluginSettings/LinkIconButton.tsx index dd840f52..4dae0e1e 100644 --- a/src/components/PluginSettings/LinkIconButton.tsx +++ b/src/components/PluginSettings/LinkIconButton.tsx @@ -6,16 +6,19 @@ import "./LinkIconButton.css"; +import { getTheme, Theme } from "@utils/discord"; import { MaskedLink, Tooltip } from "@webpack/common"; import { GithubIcon, WebsiteIcon } from ".."; export function GithubLinkIcon() { - return ; + const theme = getTheme() === Theme.Light ? "#000000" : "#FFFFFF"; + return ; } export function WebsiteLinkIcon() { - return ; + const theme = getTheme() === Theme.Light ? "#000000" : "#FFFFFF"; + return ; } interface Props { From 5fb63246cacf4152010267e33c8cc32c01bbaa7e Mon Sep 17 00:00:00 2001 From: Etorix <92535668+EtorixDev@users.noreply.github.com> Date: Sun, 24 Nov 2024 16:25:30 -0800 Subject: [PATCH 08/23] Add support for onAuxClick on ChatBarButton (#3043) --- src/api/ChatButtons.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/api/ChatButtons.tsx b/src/api/ChatButtons.tsx index fcb76fff..5f9ae9e7 100644 --- a/src/api/ChatButtons.tsx +++ b/src/api/ChatButtons.tsx @@ -99,7 +99,8 @@ export interface ChatBarButtonProps { tooltip: string; onClick: MouseEventHandler; onContextMenu?: MouseEventHandler; - buttonProps?: Omit, "size" | "onClick" | "onContextMenu">; + onAuxClick?: MouseEventHandler; + buttonProps?: Omit, "size" | "onClick" | "onContextMenu" | "onAuxClick">; } export const ChatBarButton = ErrorBoundary.wrap((props: ChatBarButtonProps) => { return ( @@ -115,6 +116,7 @@ export const ChatBarButton = ErrorBoundary.wrap((props: ChatBarButtonProps) => { innerClassName={`${ButtonWrapperClasses.button} ${ChannelTextAreaClasses?.button}`} onClick={props.onClick} onContextMenu={props.onContextMenu} + onAuxClick={props.onAuxClick} {...props.buttonProps} >
From 23c9e2ce2212a03641cb524c931309c3ab113da4 Mon Sep 17 00:00:00 2001 From: sadan4 <117494111+sadan4@users.noreply.github.com> Date: Sun, 24 Nov 2024 19:30:27 -0500 Subject: [PATCH 09/23] ShowHiddenThings: Allow opening mod view on yourself (#3045) --- src/plugins/showHiddenThings/index.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/plugins/showHiddenThings/index.ts b/src/plugins/showHiddenThings/index.ts index 9f6fd2a9..30edb247 100644 --- a/src/plugins/showHiddenThings/index.ts +++ b/src/plugins/showHiddenThings/index.ts @@ -75,6 +75,15 @@ export default definePlugin({ replace: "$1$2arguments[0].member.highestRoleId]", } }, + // allows you to open mod view on yourself + { + find: ".MEMBER_SAFETY,{modViewPanel:", + predicate: () => settings.store.showModView, + replacement: { + match: /\i(?=\?null)/, + replace: "false" + } + }, { find: "prod_discoverable_guilds", predicate: () => settings.store.disableDiscoveryFilters, From e7a54b05872c24d63f64b258e73f807c1010d431 Mon Sep 17 00:00:00 2001 From: Mia Rodriguez <62818119+xNasuni@users.noreply.github.com> Date: Sun, 24 Nov 2024 19:35:12 -0500 Subject: [PATCH 10/23] SilentTyping: Improve button visual look (#3026) --- src/plugins/silentTyping/index.tsx | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/plugins/silentTyping/index.tsx b/src/plugins/silentTyping/index.tsx index ad28999a..d06ae837 100644 --- a/src/plugins/silentTyping/index.tsx +++ b/src/plugins/silentTyping/index.tsx @@ -54,9 +54,17 @@ const SilentTypingToggle: ChatBarButton = ({ isMainChat }) => { tooltip={isEnabled ? "Disable Silent Typing" : "Enable Silent Typing"} onClick={toggle} > - - - {isEnabled && } + + + {isEnabled && ( + <> + + + + + + + )} ); From a9d44e3341d909ee46e4e769c44e5d50e84a7227 Mon Sep 17 00:00:00 2001 From: Sqaaakoi Date: Mon, 25 Nov 2024 17:14:25 +1300 Subject: [PATCH 11/23] PermissionsViewer: Fix permission description tooltip & cleanup (#3040) --- src/components/ExpandableHeader.css | 11 -- src/components/ExpandableHeader.tsx | 121 ------------------ src/components/index.ts | 1 - .../components/RolesAndUsersPermissions.tsx | 21 ++- .../components/UserPermissions.tsx | 94 ++++++++------ src/plugins/permissionsViewer/index.tsx | 9 +- src/plugins/permissionsViewer/styles.css | 16 ++- src/plugins/permissionsViewer/utils.ts | 48 +------ 8 files changed, 87 insertions(+), 234 deletions(-) delete mode 100644 src/components/ExpandableHeader.css delete mode 100644 src/components/ExpandableHeader.tsx diff --git a/src/components/ExpandableHeader.css b/src/components/ExpandableHeader.css deleted file mode 100644 index a556e36b..00000000 --- a/src/components/ExpandableHeader.css +++ /dev/null @@ -1,11 +0,0 @@ -.vc-expandableheader-center-flex { - display: flex; - place-items: center; -} - -.vc-expandableheader-btn { - all: unset; - cursor: pointer; - width: 24px; - height: 24px; -} diff --git a/src/components/ExpandableHeader.tsx b/src/components/ExpandableHeader.tsx deleted file mode 100644 index 473dffaa..00000000 --- a/src/components/ExpandableHeader.tsx +++ /dev/null @@ -1,121 +0,0 @@ -/* - * 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 "./ExpandableHeader.css"; - -import { classNameFactory } from "@api/Styles"; -import { Text, Tooltip, useState } from "@webpack/common"; - -const cl = classNameFactory("vc-expandableheader-"); - -export interface ExpandableHeaderProps { - onMoreClick?: () => void; - moreTooltipText?: string; - onDropDownClick?: (state: boolean) => void; - defaultState?: boolean; - headerText: string; - children: React.ReactNode; - buttons?: React.ReactNode[]; - forceOpen?: boolean; -} - -export function ExpandableHeader({ - children, - onMoreClick, - buttons, - moreTooltipText, - onDropDownClick, - headerText, - defaultState = false, - forceOpen = false, -}: ExpandableHeaderProps) { - const [showContent, setShowContent] = useState(defaultState || forceOpen); - - return ( - <> -
- - {headerText} - - -
- { - buttons ?? null - } - - { - onMoreClick && // only show more button if callback is provided - - {tooltipProps => ( - - )} - - } - - - - {tooltipProps => ( - - )} - -
-
- {showContent && children} - - ); -} diff --git a/src/components/index.ts b/src/components/index.ts index 38e610fd..2782cb54 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -10,7 +10,6 @@ export * from "./CodeBlock"; export * from "./DonateButton"; export { default as ErrorBoundary } from "./ErrorBoundary"; export * from "./ErrorCard"; -export * from "./ExpandableHeader"; export * from "./Flex"; export * from "./Heart"; export * from "./Icons"; diff --git a/src/plugins/permissionsViewer/components/RolesAndUsersPermissions.tsx b/src/plugins/permissionsViewer/components/RolesAndUsersPermissions.tsx index 32dcaf8d..b1593779 100644 --- a/src/plugins/permissionsViewer/components/RolesAndUsersPermissions.tsx +++ b/src/plugins/permissionsViewer/components/RolesAndUsersPermissions.tsx @@ -22,12 +22,12 @@ import { InfoIcon, OwnerCrownIcon } from "@components/Icons"; import { getIntlMessage, getUniqueUsername } from "@utils/discord"; import { ModalCloseButton, ModalContent, ModalHeader, ModalProps, ModalRoot, ModalSize, openModal } from "@utils/modal"; import { findByCodeLazy } from "@webpack"; -import { Clipboard, ContextMenuApi, FluxDispatcher, GuildMemberStore, GuildStore, Menu, PermissionsBits, ScrollerThin, Text, Tooltip, useEffect, UserStore, useState, useStateFromStores } from "@webpack/common"; +import { Clipboard, ContextMenuApi, FluxDispatcher, GuildMemberStore, GuildStore, i18n, Menu, PermissionsBits, ScrollerThin, Text, Tooltip, useEffect, useMemo, UserStore, useState, useStateFromStores } from "@webpack/common"; import { UnicodeEmoji } from "@webpack/types"; import type { Guild, Role, User } from "discord-types/general"; import { settings } from ".."; -import { cl, getPermissionDescription, getPermissionString } from "../utils"; +import { cl, getGuildPermissionSpecMap } from "../utils"; import { PermissionAllowedIcon, PermissionDefaultIcon, PermissionDeniedIcon } from "./icons"; export const enum PermissionType { @@ -56,7 +56,7 @@ function getRoleIconSrc(role: Role) { } function RolesAndUsersPermissionsComponent({ permissions, guild, modalProps, header }: { permissions: Array; guild: Guild; modalProps: ModalProps; header: string; }) { - permissions.sort((a, b) => a.type - b.type); + const guildPermissionSpecMap = useMemo(() => getGuildPermissionSpecMap(guild), [guild.id]); useStateFromStores( [GuildMemberStore], @@ -65,6 +65,10 @@ function RolesAndUsersPermissionsComponent({ permissions, guild, modalProps, hea (old, current) => old.length === current.length ); + useEffect(() => { + permissions.sort((a, b) => a.type - b.type); + }, [permissions]); + useEffect(() => { const usersToRequest = permissions .filter(p => p.type === PermissionType.User && !GuildMemberStore.isMember(guild.id, p.id!)) @@ -173,7 +177,7 @@ function RolesAndUsersPermissionsComponent({ permissions, guild, modalProps, hea
- {Object.entries(PermissionsBits).map(([permissionName, bit]) => ( + {Object.values(PermissionsBits).map(bit => (
{(() => { @@ -192,9 +196,14 @@ function RolesAndUsersPermissionsComponent({ permissions, guild, modalProps, hea return PermissionDefaultIcon(); })()}
- {getPermissionString(permissionName)} + {guildPermissionSpecMap[String(bit)].title} - + { + const { description } = guildPermissionSpecMap[String(bit)]; + return typeof description === "function" ? i18n.intl.format(description, {}) : description; + })() + }> {props => }
diff --git a/src/plugins/permissionsViewer/components/UserPermissions.tsx b/src/plugins/permissionsViewer/components/UserPermissions.tsx index 720445da..6eaeef84 100644 --- a/src/plugins/permissionsViewer/components/UserPermissions.tsx +++ b/src/plugins/permissionsViewer/components/UserPermissions.tsx @@ -17,7 +17,6 @@ */ import ErrorBoundary from "@components/ErrorBoundary"; -import { ExpandableHeader } from "@components/ExpandableHeader"; import { getIntlMessage } from "@utils/discord"; import { classes } from "@utils/misc"; import { filters, findBulk, proxyLazyWebpack } from "@webpack"; @@ -25,7 +24,7 @@ import { PermissionsBits, Text, Tooltip, useMemo, UserStore } from "@webpack/com import type { Guild, GuildMember } from "discord-types/general"; import { PermissionsSortOrder, settings } from ".."; -import { cl, getPermissionString, getSortedRoles, sortUserRoles } from "../utils"; +import { cl, getGuildPermissionSpecMap, getSortedRoles, sortUserRoles } from "../utils"; import openRolesAndUsersPermissionsModal, { PermissionType, type RoleOrUserPermission } from "./RolesAndUsersPermissions"; interface UserPermission { @@ -87,9 +86,11 @@ function GrantedByTooltip({ roleName, roleColor }: GrantedByTooltipProps) { ); } -function UserPermissionsComponent({ guild, guildMember, forceOpen = false }: { guild: Guild; guildMember: GuildMember; forceOpen?: boolean; }) { +function UserPermissionsComponent({ guild, guildMember, closePopout }: { guild: Guild; guildMember: GuildMember; closePopout: () => void; }) { const { permissionsSortOrder } = settings.use(["permissionsSortOrder"]); + const guildPermissionSpecMap = useMemo(() => getGuildPermissionSpecMap(guild), [guild.id]); + const [rolePermissions, userPermissions] = useMemo(() => { const userPermissions: UserPermissions = []; @@ -106,7 +107,7 @@ function UserPermissionsComponent({ guild, guildMember, forceOpen = false }: { g permissions: Object.values(PermissionsBits).reduce((prev, curr) => prev | curr, 0n) }); - const OWNER = getIntlMessage("GUILD_OWNER") || "Server Owner"; + const OWNER = getIntlMessage("GUILD_OWNER") ?? "Server Owner"; userPermissions.push({ permission: OWNER, roleName: "Owner", @@ -117,11 +118,11 @@ function UserPermissionsComponent({ guild, guildMember, forceOpen = false }: { g sortUserRoles(userRoles); - for (const [permission, bit] of Object.entries(PermissionsBits)) { + for (const bit of Object.values(PermissionsBits)) { for (const { permissions, colorString, position, name } of userRoles) { if ((permissions & bit) === bit) { userPermissions.push({ - permission: getPermissionString(permission), + permission: guildPermissionSpecMap[String(bit)].title, roleName: name, roleColor: colorString || "var(--primary-300)", rolePosition: position @@ -137,26 +138,15 @@ function UserPermissionsComponent({ guild, guildMember, forceOpen = false }: { g return [rolePermissions, userPermissions]; }, [permissionsSortOrder]); - return ( - - openRolesAndUsersPermissionsModal( - rolePermissions, - guild, - guildMember.nick || UserStore.getUser(guildMember.userId).username - ) - } - onDropDownClick={state => settings.store.defaultPermissionsDropdownState = !state} - defaultState={settings.store.defaultPermissionsDropdownState} - buttons={[ + return
+
+ Permissions +
{tooltipProps => (
{ @@ -164,8 +154,8 @@ function UserPermissionsComponent({ guild, guildMember, forceOpen = false }: { g }} > @@ -174,24 +164,46 @@ function UserPermissionsComponent({ guild, guildMember, forceOpen = false }: { g
)}
- ]}> - {userPermissions.length > 0 && ( -
- {userPermissions.map(({ permission, roleColor, roleName }) => ( - } - tooltipClassName={cl("granted-by-container")} - tooltipContentClassName={cl("granted-by-content")} + + {tooltipProps => ( +
{ + closePopout(); + openRolesAndUsersPermissionsModal(rolePermissions, guild, guildMember.nick || UserStore.getUser(guildMember.userId).username); + }} > - {tooltipProps => ( - - )} - - ))} -
- )} - - ); + + + +
+ )} + +
+
+ {userPermissions.length > 0 && ( +
+ {userPermissions.map(({ permission, roleColor, roleName }) => ( + } + tooltipClassName={cl("granted-by-container")} + tooltipContentClassName={cl("granted-by-content")} + > + {tooltipProps => ( + + )} + + ))} +
+ )} +
; } export default ErrorBoundary.wrap(UserPermissionsComponent, { noop: true }); diff --git a/src/plugins/permissionsViewer/index.tsx b/src/plugins/permissionsViewer/index.tsx index 20b0b191..8d0cd4b1 100644 --- a/src/plugins/permissionsViewer/index.tsx +++ b/src/plugins/permissionsViewer/index.tsx @@ -56,11 +56,6 @@ export const settings = definePluginSettings({ { label: "Lowest Role", value: PermissionsSortOrder.LowestRole } ] }, - defaultPermissionsDropdownState: { - description: "Whether the permissions dropdown on user popouts should be open by default", - type: OptionType.BOOLEAN, - default: false - } }); function MenuItem(guildId: string, id?: string, type?: MenuItemParentType) { @@ -182,9 +177,9 @@ export default definePlugin({ ( + renderPopout={({ closePopout }) => ( - + )} > diff --git a/src/plugins/permissionsViewer/styles.css b/src/plugins/permissionsViewer/styles.css index 0123f86e..b7e42096 100644 --- a/src/plugins/permissionsViewer/styles.css +++ b/src/plugins/permissionsViewer/styles.css @@ -1,12 +1,22 @@ /* User Permissions Component */ -.vc-permviewer-user-sortorder-btn { +.vc-permviewer-user-header-container { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 8px; +} + +.vc-permviewer-user-header-btns { + display: flex; + gap: 8px; +} + +.vc-permviewer-user-header-btn { cursor: pointer; display: flex; align-items: center; justify-content: center; - width: 24px; - height: 24px; } /* RolesAndUsersPermissions Component */ diff --git a/src/plugins/permissionsViewer/utils.ts b/src/plugins/permissionsViewer/utils.ts index b2015840..dfa81e73 100644 --- a/src/plugins/permissionsViewer/utils.ts +++ b/src/plugins/permissionsViewer/utils.ts @@ -17,57 +17,17 @@ */ import { classNameFactory } from "@api/Styles"; -import { getIntlMessage } from "@utils/discord"; -import { wordsToTitle } from "@utils/text"; -import { GuildStore, Parser } from "@webpack/common"; +import { findByPropsLazy } from "@webpack"; +import { GuildStore } from "@webpack/common"; import { Guild, GuildMember, Role } from "discord-types/general"; -import type { ReactNode } from "react"; import { PermissionsSortOrder, settings } from "."; import { PermissionType } from "./components/RolesAndUsersPermissions"; +export const { getGuildPermissionSpecMap } = findByPropsLazy("getGuildPermissionSpecMap"); + export const cl = classNameFactory("vc-permviewer-"); -function formatPermissionWithoutMatchingString(permission: string) { - return wordsToTitle(permission.toLowerCase().split("_")); -} - -// because discord is unable to be consistent with their names -const PermissionKeyMap = { - MANAGE_GUILD: "MANAGE_SERVER", - MANAGE_GUILD_EXPRESSIONS: "MANAGE_EXPRESSIONS", - CREATE_GUILD_EXPRESSIONS: "CREATE_EXPRESSIONS", - MODERATE_MEMBERS: "MODERATE_MEMBER", // HELLOOOO ?????? - STREAM: "VIDEO", - SEND_VOICE_MESSAGES: "ROLE_PERMISSIONS_SEND_VOICE_MESSAGE", -} as const; - -export function getPermissionString(permission: string) { - permission = PermissionKeyMap[permission] || permission; - - return getIntlMessage(permission) || - // shouldn't get here but just in case - formatPermissionWithoutMatchingString(permission); -} - -export function getPermissionDescription(permission: string): ReactNode { - // DISCORD PLEEEEEEEEAAAAASE IM BEGGING YOU :( - if (permission === "USE_APPLICATION_COMMANDS") - permission = "USE_APPLICATION_COMMANDS_GUILD"; - else if (permission === "SEND_VOICE_MESSAGES") - permission = "SEND_VOICE_MESSAGE_GUILD"; - else if (permission !== "STREAM") - permission = PermissionKeyMap[permission] || permission; - - const msg = getIntlMessage(`ROLE_PERMISSIONS_${permission}_DESCRIPTION`) as any; - if (msg?.hasMarkdown) - return Parser.parse(msg.message); - - if (typeof msg === "string") return msg; - - return ""; -} - export function getSortedRoles({ id }: Guild, member: GuildMember) { const roles = GuildStore.getRoles(id); From d8df96d1e34cd1c67724a0dd2702c2465406d585 Mon Sep 17 00:00:00 2001 From: sadan4 <117494111+sadan4@users.noreply.github.com> Date: Mon, 25 Nov 2024 17:41:00 -0500 Subject: [PATCH 12/23] BetterFolders: Fix dedicated sidebar (#3037) --- src/plugins/betterFolders/index.tsx | 34 +++++++++++++++++------------ 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/src/plugins/betterFolders/index.tsx b/src/plugins/betterFolders/index.tsx index 5d4d52c4..68746d36 100644 --- a/src/plugins/betterFolders/index.tsx +++ b/src/plugins/betterFolders/index.tsx @@ -123,7 +123,7 @@ export default definePlugin({ }, // If we are rendering the Better Folders sidebar, we filter out everything but the servers and folders from the GuildsBar Guild List children { - match: /lastTargetNode:\i\[\i\.length-1\].+?Fragment.+?\]}\)\]/, + match: /lastTargetNode:\i\[\i\.length-1\].+?}\)\](?=}\))/, replace: "$&.filter($self.makeGuildsBarGuildListFilter(!!arguments[0]?.isBetterFolders))" }, // If we are rendering the Better Folders sidebar, we filter out everything but the scroller for the guild list from the GuildsBar Tree children @@ -275,24 +275,30 @@ export default definePlugin({ }, makeGuildsBarGuildListFilter(isBetterFolders: boolean) { - return child => { - if (isBetterFolders) { - try { - return child?.props?.["aria-label"] === getIntlMessage("SERVERS"); - } catch (e) { - console.error(e); - } - } - return true; - }; + return child => { + if (!isBetterFolders) return true; + + try { + return child?.props?.["aria-label"] === getIntlMessage("SERVERS"); + } catch (e) { + console.error(e); + } + + return true; + }; }, makeGuildsBarTreeFilter(isBetterFolders: boolean) { return child => { - if (isBetterFolders) { - return child?.props?.onScroll != null; + if (!isBetterFolders) return true; + + if (child?.props?.className?.includes("itemsContainer") && child.props.children != null) { + // Filter out everything but the scroller for the guild list + child.props.children = child.props.children.filter(child => child?.props?.onScroll != null); + return true; } - return true; + + return false; }; }, From 60b776669bb2775e561b9a3a670d6e33eef72a48 Mon Sep 17 00:00:00 2001 From: Nuckyz <61953774+Nuckyz@users.noreply.github.com> Date: Mon, 25 Nov 2024 20:03:34 -0300 Subject: [PATCH 13/23] WebContextMenus: Fix copy context menu --- src/plugins/webContextMenus.web/index.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/plugins/webContextMenus.web/index.ts b/src/plugins/webContextMenus.web/index.ts index d3934bc2..a11ef243 100644 --- a/src/plugins/webContextMenus.web/index.ts +++ b/src/plugins/webContextMenus.web/index.ts @@ -216,9 +216,12 @@ export default definePlugin({ replace: "true" }, { - match: /\i\.\i\.copy/, + match: /\i\.\i\.copy(?=\(\i)/, replace: "Vencord.Webpack.Common.Clipboard.copy" - }] + } + ], + all: true, + noWarn: true }, // Automod add filter words { From 11321eb693858a88665b5801ce173e7ebd6c68c4 Mon Sep 17 00:00:00 2001 From: v Date: Fri, 29 Nov 2024 16:11:55 +0100 Subject: [PATCH 14/23] Update CONTRIBUTING.md Plugins interacting with specific Discord bots are not allowed. --- CONTRIBUTING.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6c133225..0146065e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -31,6 +31,7 @@ Before starting your plugin: - No FakeDeafen or FakeMute - No StereoMic - No plugins that simply hide or redesign ui elements. This can be done with CSS +- No plugins that interact with specific Discord bots (official Discord apps like Youtube WatchTogether are okay) - No selfbots or API spam (animated status, message pruner, auto reply, nitro snipers, etc) - No untrusted third party APIs. Popular services like Google or GitHub are fine, but absolutely no self hosted ones - No plugins that require the user to enter their own API key From 1150a503554b1a366e602b4ae27cacf424369851 Mon Sep 17 00:00:00 2001 From: Vendicated Date: Fri, 29 Nov 2024 22:46:28 +0100 Subject: [PATCH 15/23] Badges: fix overflow in Discord's css --- src/plugins/_api/badges/fixDiscordBadgePadding.css | 5 +++++ src/plugins/_api/badges/index.tsx | 2 ++ 2 files changed, 7 insertions(+) create mode 100644 src/plugins/_api/badges/fixDiscordBadgePadding.css diff --git a/src/plugins/_api/badges/fixDiscordBadgePadding.css b/src/plugins/_api/badges/fixDiscordBadgePadding.css new file mode 100644 index 00000000..eb1d60d5 --- /dev/null +++ b/src/plugins/_api/badges/fixDiscordBadgePadding.css @@ -0,0 +1,5 @@ +/* the profile popout badge container(s) */ +[class*="biteSize_"] [class*="tags_"] [class*="container_"] { + /* Discord has padding set to 2px instead of 1px, which causes the 12th badge to wrap to a new line. */ + padding: 0 1px; +} diff --git a/src/plugins/_api/badges/index.tsx b/src/plugins/_api/badges/index.tsx index c44d98b9..d02b5e1d 100644 --- a/src/plugins/_api/badges/index.tsx +++ b/src/plugins/_api/badges/index.tsx @@ -16,6 +16,8 @@ * along with this program. If not, see . */ +import "./fixDiscordBadgePadding.css"; + import { _getBadges, BadgePosition, BadgeUserArgs, ProfileBadge } from "@api/Badges"; import DonateButton from "@components/DonateButton"; import ErrorBoundary from "@components/ErrorBoundary"; From 02f50b161b0fda1686bbba71e4ef53bfee9dd124 Mon Sep 17 00:00:00 2001 From: sadan4 <117494111+sadan4@users.noreply.github.com> Date: Fri, 29 Nov 2024 17:26:10 -0500 Subject: [PATCH 16/23] ImageZoom: Fix zoom level not saving (#3054) --- src/plugins/imageZoom/components/Magnifier.tsx | 18 +++++++++++------- src/webpack/common/react.ts | 3 ++- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/plugins/imageZoom/components/Magnifier.tsx b/src/plugins/imageZoom/components/Magnifier.tsx index 585026d6..31fa7a11 100644 --- a/src/plugins/imageZoom/components/Magnifier.tsx +++ b/src/plugins/imageZoom/components/Magnifier.tsx @@ -18,7 +18,7 @@ import { classNameFactory } from "@api/Styles"; import ErrorBoundary from "@components/ErrorBoundary"; -import { FluxDispatcher, React, useRef, useState } from "@webpack/common"; +import { FluxDispatcher, useLayoutEffect, useRef, useState } from "@webpack/common"; import { ELEMENT_ID } from "../constants"; import { settings } from "../index"; @@ -55,7 +55,7 @@ export const Magnifier = ErrorBoundary.wrap(({ instance, size: i const imageRef = useRef(null); // since we accessing document im gonna use useLayoutEffect - React.useLayoutEffect(() => { + useLayoutEffect(() => { const onKeyDown = (e: KeyboardEvent) => { if (e.key === "Shift") { isShiftDown.current = true; @@ -135,12 +135,14 @@ export const Magnifier = ErrorBoundary.wrap(({ instance, size: i setReady(true); }); + document.addEventListener("keydown", onKeyDown); document.addEventListener("keyup", onKeyUp); document.addEventListener("mousemove", updateMousePosition); document.addEventListener("mousedown", onMouseDown); document.addEventListener("mouseup", onMouseUp); document.addEventListener("wheel", onWheel); + return () => { document.removeEventListener("keydown", onKeyDown); document.removeEventListener("keyup", onKeyUp); @@ -148,14 +150,16 @@ export const Magnifier = ErrorBoundary.wrap(({ instance, size: i document.removeEventListener("mousedown", onMouseDown); document.removeEventListener("mouseup", onMouseUp); document.removeEventListener("wheel", onWheel); - - if (settings.store.saveZoomValues) { - settings.store.zoom = zoom.current; - settings.store.size = size.current; - } }; }, []); + useLayoutEffect(() => () => { + if (settings.store.saveZoomValues) { + settings.store.zoom = zoom.current; + settings.store.size = size.current; + } + }); + if (!ready) return null; const box = element.current?.getBoundingClientRect(); diff --git a/src/webpack/common/react.ts b/src/webpack/common/react.ts index 17196132..99f3f9dd 100644 --- a/src/webpack/common/react.ts +++ b/src/webpack/common/react.ts @@ -22,6 +22,7 @@ import { findByPropsLazy, waitFor } from "../webpack"; export let React: typeof import("react"); export let useState: typeof React.useState; export let useEffect: typeof React.useEffect; +export let useLayoutEffect: typeof React.useLayoutEffect; export let useMemo: typeof React.useMemo; export let useRef: typeof React.useRef; export let useReducer: typeof React.useReducer; @@ -31,5 +32,5 @@ export const ReactDOM: typeof import("react-dom") & typeof import("react-dom/cli waitFor("useState", m => { React = m; - ({ useEffect, useState, useMemo, useRef, useReducer, useCallback } = React); + ({ useEffect, useState, useLayoutEffect, useMemo, useRef, useReducer, useCallback } = React); }); From fcece6199511108f7f9eeec65a6d9120f720deb2 Mon Sep 17 00:00:00 2001 From: Nuckyz <61953774+Nuckyz@users.noreply.github.com> Date: Fri, 29 Nov 2024 19:26:55 -0300 Subject: [PATCH 17/23] Bump to 1.10.8 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d5b23e57..967c0ccc 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "vencord", "private": "true", - "version": "1.10.7", + "version": "1.10.8", "description": "The cutest Discord client mod", "homepage": "https://github.com/Vendicated/Vencord#readme", "bugs": { From 0ac80ce9d180bbdaf4d3863f4a249f3b165072df Mon Sep 17 00:00:00 2001 From: Nuckyz <61953774+Nuckyz@users.noreply.github.com> Date: Sun, 1 Dec 2024 00:10:08 -0300 Subject: [PATCH 18/23] MessagePopoverAPI: Add buttons after quick reactions --- src/plugins/_api/messagePopover.ts | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/plugins/_api/messagePopover.ts b/src/plugins/_api/messagePopover.ts index 21e5accd..0133d0c6 100644 --- a/src/plugins/_api/messagePopover.ts +++ b/src/plugins/_api/messagePopover.ts @@ -23,11 +23,14 @@ export default definePlugin({ name: "MessagePopoverAPI", description: "API to add buttons to message popovers.", authors: [Devs.KingFish, Devs.Ven, Devs.Nuckyz], - patches: [{ - find: "#{intl::MESSAGE_UTILITIES_A11Y_LABEL}", - replacement: { - match: /\.jsx\)\((\i\.\i),\{label:\i\.\i\.string\(\i\.\i#{intl::MESSAGE_ACTION_REPLY}.{0,200}?"reply-self".{0,50}?\}\):null(?=,.+?message:(\i))/, - replace: "$&,Vencord.Api.MessagePopover._buildPopoverElements($1,$2)" + patches: [ + { + find: "#{intl::MESSAGE_UTILITIES_A11Y_LABEL}", + replacement: { + match: /(?<=:null),(.{0,40}togglePopout:.+?}\))\]}\):null,(?<=\((\i\.\i),{label:.+?:null,(\i&&!\i)\?\(0,\i\.jsxs?\)\(\i\.Fragment.+?message:(\i).+?)/, + replace: (_, ReactButton, ButtonComponent, showReactButton, message) => "" + + `]}):null,Vencord.Api.MessagePopover._buildPopoverElements(${ButtonComponent},${message}),${showReactButton}?${ReactButton}:null,` + } } - }], + ] }); From d70e0f27dcdaca24443d57b319fee2c0a8997501 Mon Sep 17 00:00:00 2001 From: Nuckyz <61953774+Nuckyz@users.noreply.github.com> Date: Mon, 2 Dec 2024 20:39:54 -0300 Subject: [PATCH 19/23] ServerListIndicators: Account for pending clans count --- src/plugins/serverListIndicators/index.tsx | 63 +++++++++------------- 1 file changed, 26 insertions(+), 37 deletions(-) diff --git a/src/plugins/serverListIndicators/index.tsx b/src/plugins/serverListIndicators/index.tsx index 96833d8f..7648bc2d 100644 --- a/src/plugins/serverListIndicators/index.tsx +++ b/src/plugins/serverListIndicators/index.tsx @@ -20,9 +20,9 @@ import { addServerListElement, removeServerListElement, ServerListRenderPosition import { Settings } from "@api/Settings"; import ErrorBoundary from "@components/ErrorBoundary"; import { Devs } from "@utils/constants"; -import { useForceUpdater } from "@utils/react"; import definePlugin, { OptionType } from "@utils/types"; -import { GuildStore, PresenceStore, RelationshipStore } from "@webpack/common"; +import { findStoreLazy } from "@webpack"; +import { GuildStore, PresenceStore, RelationshipStore, useStateFromStores } from "@webpack/common"; const enum IndicatorType { SERVER = 1 << 0, @@ -30,13 +30,24 @@ const enum IndicatorType { BOTH = SERVER | FRIEND, } -let onlineFriends = 0; -let guildCount = 0; -let forceUpdateFriendCount: () => void; -let forceUpdateGuildCount: () => void; +const UserGuildJoinRequestStore = findStoreLazy("UserGuildJoinRequestStore"); function FriendsIndicator() { - forceUpdateFriendCount = useForceUpdater(); + const onlineFriendsCount = useStateFromStores([RelationshipStore, PresenceStore], () => { + let count = 0; + + const friendIds = RelationshipStore.getFriendIDs(); + for (const id of friendIds) { + const status = PresenceStore.getStatus(id) ?? "offline"; + if (status === "offline") { + continue; + } + + count++; + } + + return count; + }); return ( - {onlineFriends} online + {onlineFriendsCount} online ); } function ServersIndicator() { - forceUpdateGuildCount = useForceUpdater(); + const guildCount = useStateFromStores([GuildStore, UserGuildJoinRequestStore], () => { + const guildJoinRequests: string[] = UserGuildJoinRequestStore.computeGuildIds(); + const guilds = GuildStore.getGuilds(); + + // Filter only pending guild join requests + return GuildStore.getGuildCount() + guildJoinRequests.filter(id => guilds[id] == null).length; + }); return ( ; }, - flux: { - PRESENCE_UPDATES: handlePresenceUpdate, - GUILD_CREATE: handleGuildUpdate, - GUILD_DELETE: handleGuildUpdate, - }, - - start() { addServerListElement(ServerListRenderPosition.Above, this.renderIndicator); - - handlePresenceUpdate(); - handleGuildUpdate(); }, stop() { From 3f61fe722dfa92b467c907b14237767877ef6ed1 Mon Sep 17 00:00:00 2001 From: Nuckyz <61953774+Nuckyz@users.noreply.github.com> Date: Mon, 2 Dec 2024 21:51:29 -0300 Subject: [PATCH 20/23] AlwaysTrust: Fix disabling suspicious file popup --- src/plugins/alwaysTrust/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/alwaysTrust/index.ts b/src/plugins/alwaysTrust/index.ts index 7484a619..0c89ae11 100644 --- a/src/plugins/alwaysTrust/index.ts +++ b/src/plugins/alwaysTrust/index.ts @@ -51,7 +51,7 @@ export default definePlugin({ { find: "bitbucket.org", replacement: { - match: /function \i\(\i\){(?=.{0,60}\.parse\(\i\))/, + match: /function \i\(\i\){(?=.{0,30}pathname:\i)/, replace: "$&return null;" }, predicate: () => settings.store.file From dd87f360d74f61b4532b523dc47cd734b6ffeb05 Mon Sep 17 00:00:00 2001 From: Etorix <92535668+EtorixDev@users.noreply.github.com> Date: Mon, 2 Dec 2024 18:13:27 -0800 Subject: [PATCH 21/23] CommandsAPI: Fix spread overwriting omitted subcommand options (#3057) --- src/api/Commands/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/api/Commands/index.ts b/src/api/Commands/index.ts index e5803ba0..2b7a4de6 100644 --- a/src/api/Commands/index.ts +++ b/src/api/Commands/index.ts @@ -110,6 +110,7 @@ function registerSubCommands(cmd: Command, plugin: string) { const subCmd = { ...cmd, ...o, + options: o.options !== undefined ? o.options : undefined, type: ApplicationCommandType.CHAT_INPUT, name: `${cmd.name} ${o.name}`, id: `${o.name}-${cmd.id}`, From 66286240820c132a8aa98bcaa2e9c7c2535ca403 Mon Sep 17 00:00:00 2001 From: Etorix <92535668+EtorixDev@users.noreply.github.com> Date: Mon, 2 Dec 2024 18:16:13 -0800 Subject: [PATCH 22/23] CommandHelpers: Make findOption use nullish coalescing (#3047) --- src/api/Commands/commandHelpers.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/Commands/commandHelpers.ts b/src/api/Commands/commandHelpers.ts index 4ae022c5..ac1dafc9 100644 --- a/src/api/Commands/commandHelpers.ts +++ b/src/api/Commands/commandHelpers.ts @@ -54,5 +54,5 @@ export function sendBotMessage(channelId: string, message: PartialDeep) export function findOption(args: Argument[], name: string): T & {} | undefined; export function findOption(args: Argument[], name: string, fallbackValue: T): T & {}; export function findOption(args: Argument[], name: string, fallbackValue?: any) { - return (args.find(a => a.name === name)?.value || fallbackValue) as any; + return (args.find(a => a.name === name)?.value ?? fallbackValue) as any; } From df454ca95218dc32ef1521e5836f38c76bb24a61 Mon Sep 17 00:00:00 2001 From: Sqaaakoi Date: Tue, 3 Dec 2024 13:30:56 +1100 Subject: [PATCH 23/23] MutualGroupDMs: Fix in DM sidebar when no mutual friends/servers (#2976) --- src/plugins/mutualGroupDMs/index.tsx | 52 +++++++++++++++++++--------- 1 file changed, 36 insertions(+), 16 deletions(-) diff --git a/src/plugins/mutualGroupDMs/index.tsx b/src/plugins/mutualGroupDMs/index.tsx index a4f690af..080a7989 100644 --- a/src/plugins/mutualGroupDMs/index.tsx +++ b/src/plugins/mutualGroupDMs/index.tsx @@ -19,6 +19,7 @@ import ErrorBoundary from "@components/ErrorBoundary"; import { Devs } from "@utils/constants"; import { isNonNullish } from "@utils/guards"; +import { Logger } from "@utils/Logger"; import definePlugin from "@utils/types"; import { findByPropsLazy, findComponentByCodeLazy } from "@webpack"; import { Avatar, ChannelStore, Clickable, IconUtils, RelationshipStore, ScrollerThin, useMemo, UserStore } from "@webpack/common"; @@ -87,7 +88,7 @@ export default definePlugin({ replacement: [ { match: /\i\.useEffect.{0,100}(\i)\[0\]\.section/, - replace: "$self.pushSection($1, arguments[0].user);$&" + replace: "$self.pushSection($1,arguments[0].user);$&" }, { match: /\(0,\i\.jsx\)\(\i,\{items:\i,section:(\i)/, @@ -97,26 +98,46 @@ export default definePlugin({ }, { find: 'section:"MUTUAL_FRIENDS"', - replacement: { - match: /\.openUserProfileModal.+?\)}\)}\)(?<=(\(0,\i\.jsxs?\)\(\i\.\i,{className:(\i)\.divider}\)).+?)/, - replace: "$&,$self.renderDMPageList({user: arguments[0].user, Divider: $1, listStyle: $2.list})" - } + replacement: [ + { + match: /\i\|\|\i(?=\?\(0,\i\.jsxs?\)\(\i\.\i\.Overlay,)/, + replace: "$&||$self.getMutualGroupDms(arguments[0].user.id).length>0" + }, + { + match: /\.openUserProfileModal.+?\)}\)}\)(?<=,(\i)&&(\i)&&(\(0,\i\.jsxs?\)\(\i\.\i,{className:(\i)\.divider}\)).+?)/, + replace: (m, hasMutualGuilds, hasMutualFriends, Divider, classes) => "" + + `${m},$self.renderDMPageList({user:arguments[0].user,hasDivider:${hasMutualGuilds}||${hasMutualFriends},Divider:${Divider},listStyle:${classes}.list})` + } + ] } ], - pushSection(sections: any[], user: User) { - if (isBotOrSelf(user) || sections[IS_PATCHED]) return; + getMutualGroupDms(userId: string) { + try { + return getMutualGroupDms(userId); + } catch (e) { + new Logger("MutualGroupDMs").error("Failed to get mutual group dms:", e); + } - sections[IS_PATCHED] = true; - sections.push({ - section: "MUTUAL_GDMS", - text: getMutualGDMCountText(user) - }); + return []; + }, + + pushSection(sections: any[], user: User) { + try { + if (isBotOrSelf(user) || sections[IS_PATCHED]) return; + + sections[IS_PATCHED] = true; + sections.push({ + section: "MUTUAL_GDMS", + text: getMutualGDMCountText(user) + }); + } catch (e) { + new Logger("MutualGroupDMs").error("Failed to push mutual group dms section:", e); + } }, renderMutualGDMs: ErrorBoundary.wrap(({ user, onClose }: { user: User, onClose: () => void; }) => { const mutualGDms = useMemo(() => getMutualGroupDms(user.id), [user.id]); - const entries = renderClickableGDMs(mutualGDms, onClose); return ( @@ -138,14 +159,13 @@ export default definePlugin({ ); }), - renderDMPageList: ErrorBoundary.wrap(({ user, Divider, listStyle }: { user: User, Divider: JSX.Element, listStyle: string; }) => { + renderDMPageList: ErrorBoundary.wrap(({ user, hasDivider, Divider, listStyle }: { user: User, hasDivider: boolean, Divider: JSX.Element, listStyle: string; }) => { const mutualGDms = getMutualGroupDms(user.id); if (mutualGDms.length === 0) return null; - return ( <> - {Divider} + {hasDivider && Divider}