diff --git a/packages/discord-types/enums/misc.ts b/packages/discord-types/enums/misc.ts index 81a6e41ca..aaecd1a70 100644 --- a/packages/discord-types/enums/misc.ts +++ b/packages/discord-types/enums/misc.ts @@ -53,3 +53,8 @@ export const enum PremiumType { TIER_2 = 2, TIER_0 = 3, } + +export const enum ToastPosition { + TOP = 0, + BOTTOM = 1, +} diff --git a/packages/discord-types/src/index.d.ts b/packages/discord-types/src/index.d.ts index 83bbba26e..024f3418c 100644 --- a/packages/discord-types/src/index.d.ts +++ b/packages/discord-types/src/index.d.ts @@ -7,5 +7,6 @@ export * from "./fluxEvents"; export * from "./menu"; export * from "./modules"; export * from "./stores"; +export * from "./toasts"; export * from "./utils"; export * as Webpack from "../webpack"; diff --git a/packages/discord-types/src/toasts.d.ts b/packages/discord-types/src/toasts.d.ts new file mode 100644 index 000000000..c058a920b --- /dev/null +++ b/packages/discord-types/src/toasts.d.ts @@ -0,0 +1,35 @@ +import type { ComponentType } from "react"; +import { ToastPosition } from "../enums"; + +export type ToastType = "message" | "success" | "failure" | "custom" | "clip" | "link" | "forward" | "bookmark" | "clock"; + +export type NewToastVariant = "default" | "success" | "critical"; +export type NewToastPosition = "top" | "bottom"; + +export interface ToastData { + message: string; + type?: ToastType; + options?: { + position?: ToastPosition; + duration?: number; + }; +} + +export interface NewToastData { + text: string; + variant: NewToastVariant; + position?: NewToastPosition; + duration?: number; + + icon?: ComponentType; + iconColor?: any; +} + +export type showToast = (data: NewToastData) => void; +export type popToast = (context?: string) => void; +export type createToast = (data: ToastData) => NewToastData; + +export interface Toasts { + show: showToast; + pop: popToast; +} diff --git a/packages/discord-types/src/utils.d.ts b/packages/discord-types/src/utils.d.ts index a45f04eb5..1ad506bab 100644 --- a/packages/discord-types/src/utils.d.ts +++ b/packages/discord-types/src/utils.d.ts @@ -417,13 +417,13 @@ export interface EmojiUtils { applyPlatformToThemedEmojiColorPalette(colors: any): any; } -export interface OpenUserSettingsOpts { +export interface OpenUserSettingsOptions { /** * a *sub*section of settings to navigate to * * to navigate to a top-level section, use the navigationTarget parameter of {@link SettingsRouter.openUserSettings} instead * - * discord has an enum with all the possible values (go dig in the openUserSettings source) + * discord has an enum with all the possible values (go dig in the {@link SettingsRouter.openUserSettings} source) */ path?: string; /** @@ -434,10 +434,10 @@ export interface OpenUserSettingsOpts { } export interface SettingsRouter { - openUserSettings(navigationTarget?: string, opts?: OpenUserSettingsOpts, onOpen?: () => void): Promise; + openUserSettings(navigationTarget?: string, opts?: OpenUserSettingsOptions, onOpen?: () => void): Promise; } -export interface OpenUserProfileModalOpts { +export interface OpenUserProfileModalOptions { userId: string; guildId?: string | null; originGuildId?: string | null; @@ -458,6 +458,4 @@ export interface OpenUserProfileModalOpts { onModalOpen?: unknown; } -export interface UserProfileModalActionCreators { - openUserProfileModal(opts: OpenUserProfileModalOpts): Promise; -} +export type OpenUserProfileModal = (opts: OpenUserProfileModalOptions) => Promise; diff --git a/src/Vencord.ts b/src/Vencord.ts index 21f288a66..adc06b7df 100644 --- a/src/Vencord.ts +++ b/src/Vencord.ts @@ -20,6 +20,8 @@ import "~plugins"; import "./fixWeirdAppRegionBug.css"; +import nativeTitleBarStyles from "./nativeTitleBar.css?managed"; + export * as Api from "./api"; export * as Plugins from "./api/PluginManager"; export * as Components from "./components"; @@ -29,11 +31,9 @@ export * as Webpack from "./webpack"; export * as WebpackPatcher from "./webpack/patchWebpack"; export { PlainSettings, Settings }; -import { coreStyleRootNode, initStyles } from "@api/Styles"; +import { enableStyle, initStyles } from "@api/Styles"; import { openSettingsTabModal, UpdaterTab } from "@components/settings"; import { debounce } from "@shared/debounce"; -import { IS_WINDOWS } from "@utils/constants"; -import { createAndAppendStyle } from "@utils/css"; import { StartAt } from "@utils/types"; import { SettingsRouter } from "@webpack/common"; @@ -237,8 +237,7 @@ init(); document.addEventListener("DOMContentLoaded", () => { startAllPlugins(StartAt.DOMContentLoaded); - // FIXME - if (IS_DISCORD_DESKTOP && Settings.winNativeTitleBar && IS_WINDOWS) { - createAndAppendStyle("vencord-native-titlebar-style", coreStyleRootNode).textContent = "[class*=titleBar]{display: none!important}"; + if (IS_DISCORD_DESKTOP && Settings.nativeTitleBar) { + enableStyle(nativeTitleBarStyles); } }, { once: true }); diff --git a/src/api/Settings.ts b/src/api/Settings.ts index 32c2ea42b..1ce00383c 100644 --- a/src/api/Settings.ts +++ b/src/api/Settings.ts @@ -72,7 +72,7 @@ export interface Settings { | undefined; windowsMaterial: "none" | "mica" | "tabbed" | "acrylic"; disableMinSize: boolean; - winNativeTitleBar: boolean; + nativeTitleBar: boolean; plugins: { [plugin: string]: { enabled: boolean; @@ -124,7 +124,7 @@ const DefaultSettings: Settings = { macosVibrancyStyle: undefined, windowsMaterial: "none", disableMinSize: false, - winNativeTitleBar: false, + nativeTitleBar: false, plugins: {}, uiElements: { diff --git a/src/api/SettingsSync/offline.ts b/src/api/SettingsSync/offline.ts index 0daa0af9d..34d691f4a 100644 --- a/src/api/SettingsSync/offline.ts +++ b/src/api/SettingsSync/offline.ts @@ -7,24 +7,17 @@ import { PlainSettings } from "@api/Settings"; import { Logger } from "@utils/Logger"; import { chooseFile, saveFile } from "@utils/web"; -import { moment, Toasts } from "@webpack/common"; +import { moment, showToast } from "@webpack/common"; import { DataStore } from ".."; type BackupType = "all" | "plugins" | "css" | "datastore"; -const toast = (type: string, message: string) => - Toasts.show({ - type, - message, - id: Toasts.genId() - }); - const toastSuccess = () => - toast(Toasts.Type.SUCCESS, "Settings successfully imported. Restart to apply changes!"); + showToast("Settings successfully imported. Restart to apply changes!", "success"); const toastFailure = (err: any) => - toast(Toasts.Type.FAILURE, `Failed to import settings: ${String(err)}`); + showToast(`Failed to import settings: ${String(err)}`, "failure"); const logger = new Logger("SettingsSync:Offline", "#39b7e0"); @@ -118,7 +111,7 @@ export async function exportSettings({ syncDataStore = true, type = "all", minif if (type === "all") { logger.warn("Skipping DataStore in backup due to size. Export DataStore separately if needed."); - toast(Toasts.Type.MESSAGE, "DataStore too large - exported without it. Use 'Export DataStore' separately if needed."); + showToast("DataStore too large - exported without it. Use 'Export DataStore' separately if needed.", "message"); dataStore = undefined; } else if (type === "datastore") { throw new Error("DataStore is too large to export. Please clear some plugin data and try again."); @@ -156,7 +149,7 @@ export async function downloadSettingsBackup(type: BackupType = "all", { minify } } catch (err) { logger.error("Failed to export settings:", err); - toast(Toasts.Type.FAILURE, "Failed to export settings, check console"); + showToast("Failed to export settings, check console", "failure"); throw err; } } diff --git a/src/components/settings/tabs/plugins/PluginCard.tsx b/src/components/settings/tabs/plugins/PluginCard.tsx index 72507ab1e..04993efb6 100644 --- a/src/components/settings/tabs/plugins/PluginCard.tsx +++ b/src/components/settings/tabs/plugins/PluginCard.tsx @@ -12,7 +12,8 @@ import { AddonCard } from "@components/settings/AddonCard"; import { classNameFactory } from "@utils/css"; import { Logger } from "@utils/Logger"; import { Plugin } from "@utils/types"; -import { React, showToast, Toasts } from "@webpack/common"; +import { ToastPosition } from "@vencord/discord-types/enums"; +import { React, showToast } from "@webpack/common"; import { PluginMeta } from "~plugins"; @@ -79,9 +80,7 @@ export function PluginCard({ plugin, disabled, onRestartNeeded, onMouseEnter, on settings.enabled = false; const msg = `Error while ${wasEnabled ? "stopping" : "starting"} plugin ${plugin.name}`; - showToast(msg, Toasts.Type.FAILURE, { - position: Toasts.Position.BOTTOM, - }); + showToast(msg, "failure", { position: ToastPosition.BOTTOM }); return; } diff --git a/src/components/settings/tabs/updater/Components.tsx b/src/components/settings/tabs/updater/Components.tsx index 88893d43f..783c7fd1d 100644 --- a/src/components/settings/tabs/updater/Components.tsx +++ b/src/components/settings/tabs/updater/Components.tsx @@ -14,7 +14,8 @@ import { Span } from "@components/Span"; import { Margins } from "@utils/margins"; import { relaunch } from "@utils/native"; import { changes, checkForUpdates, update, updateError } from "@utils/updater"; -import { ConfirmModal, openModal, React, Toasts, useState } from "@webpack/common"; +import { ToastPosition } from "@vencord/discord-types/enums"; +import { ConfirmModal, openModal, React, showToast, Toasts, useState } from "@webpack/common"; import { runWithDispatch } from "./runWithDispatch"; @@ -135,6 +136,24 @@ export function Updatable(props: CommonProps) { Update Now )} + {!updates && updateError ? ( <> diff --git a/src/components/settings/tabs/vencord/index.tsx b/src/components/settings/tabs/vencord/index.tsx index fc7f9d080..f834856c3 100644 --- a/src/components/settings/tabs/vencord/index.tsx +++ b/src/components/settings/tabs/vencord/index.tsx @@ -49,7 +49,7 @@ type KeysOfType = { }[keyof Object]; function Switches() { - const settings = useSettings(["useQuickCss", "enableReactDevtools", "mainWindowFrameless", "frameless", "winNativeTitleBar", "transparent", "winCtrlQ", "disableMinSize"]); + const settings = useSettings(["useQuickCss", "enableReactDevtools", "mainWindowFrameless", "frameless", "nativeTitleBar", "transparent", "winCtrlQ", "disableMinSize"]); const Switches = [ { @@ -71,7 +71,7 @@ function Switches() { restartRequired: true, } : { - key: "winNativeTitleBar", + key: "nativeTitleBar", title: "Use Windows' native title bar instead of Discord's custom one", description: "Replace Discord's custom title bar with the standard Windows title bar. This may improve compatibility with some window management tools.", restartRequired: true, diff --git a/src/main/patcher.ts b/src/main/patcher.ts index c2283dc55..a93f78848 100644 --- a/src/main/patcher.ts +++ b/src/main/patcher.ts @@ -87,7 +87,7 @@ if (!IS_VANILLA) { return; } - const { frameless, mainWindowFrameless, winNativeTitleBar, disableMinSize, transparent, macosVibrancyStyle, windowsMaterial } = settings; + const { frameless, mainWindowFrameless, nativeTitleBar, disableMinSize, transparent, macosVibrancyStyle, windowsMaterial } = settings; const original = options.webPreferences.preload; const isMainWindow = options.title === "Discord"; @@ -98,7 +98,7 @@ if (!IS_VANILLA) { options.frame = false; } else if (frameless) { options.frame = false; - } else if (process.platform === "win32" && winNativeTitleBar) { + } else if (process.platform === "win32" && nativeTitleBar) { delete options.frame; } diff --git a/src/nativeTitleBar.css b/src/nativeTitleBar.css new file mode 100644 index 000000000..f9e5ba465 --- /dev/null +++ b/src/nativeTitleBar.css @@ -0,0 +1,7 @@ +[class*="bar_"] { + margin-inline-end: 12px !important; +} + +[class*="winButtons_"] { + display: none !important; +} \ No newline at end of file diff --git a/src/plugins/_api/badges/index.tsx b/src/plugins/_api/badges/index.tsx index 69b6d0eca..aa8111a4d 100644 --- a/src/plugins/_api/badges/index.tsx +++ b/src/plugins/_api/badges/index.tsx @@ -27,7 +27,7 @@ import { copyWithToast } from "@utils/discord"; import { Logger } from "@utils/Logger"; import { shouldShowContributorBadge, shouldShowEquicordContributorBadge } from "@utils/misc"; import definePlugin from "@utils/types"; -import { ContextMenuApi, Menu, Toasts, UserStore } from "@webpack/common"; +import { ContextMenuApi, Menu, showToast, UserStore } from "@webpack/common"; import Plugins, { PluginMeta } from "~plugins"; @@ -181,11 +181,7 @@ export default definePlugin({ toolboxActions: { async "Refetch Badges"() { await loadAllBadges(true); - Toasts.show({ - id: Toasts.genId(), - message: "Successfully refetched badges!", - type: Toasts.Type.SUCCESS - }); + showToast("Successfully refetched badges!", "success"); } }, diff --git a/src/plugins/_core/supportHelper.tsx b/src/plugins/_core/supportHelper.tsx index 4dc10c289..ed543db73 100644 --- a/src/plugins/_core/supportHelper.tsx +++ b/src/plugins/_core/supportHelper.tsx @@ -16,7 +16,6 @@ * along with this program. If not, see . */ -import { sendBotMessage } from "@api/Commands"; import { isPluginEnabled } from "@api/PluginManager"; import { definePluginSettings } from "@api/Settings"; import { getUserSettingLazy } from "@api/UserSettings"; @@ -34,7 +33,7 @@ import { CONTRIB_ROLE_ID, Devs, DONOR_ROLE_ID, EQUICORD_TEAM, GUILD_ID, SUPPORT_ import { sendMessage } from "@utils/discord"; import { Logger } from "@utils/Logger"; import { Margins } from "@utils/margins"; -import { isAnyPluginDev, isEquicordGuild, isEquicordSupport, isKnownIssuesCategory, isSupportChannel, tryOrElse } from "@utils/misc"; +import { isAnyPluginDev, isEquicordGuild, isEquicordSupport, isSupportChannel, tryOrElse } from "@utils/misc"; import { relaunch } from "@utils/native"; import { onlyOnce } from "@utils/onlyOnce"; import { makeCodeblock } from "@utils/text"; @@ -49,8 +48,6 @@ import plugins, { PluginMeta } from "~plugins"; import SettingsPlugin from "./settings"; -const CodeBlockRe = /```snippet\n(.+?)```/s; - const TrustedRolesIds = [ VC_CONTRIB_ROLE_ID, // Vencord Contributor VC_REGULAR_ROLE_ID, // Vencord Regular @@ -61,8 +58,6 @@ const TrustedRolesIds = [ VENCORD_CONTRIB_ROLE_ID, // Vencord Contributor ]; -const AsyncFunction = async function () { }.constructor; - const ShowCurrentGame = getUserSettingLazy("status", "showCurrentGame")!; const ShowEmbeds = getUserSettingLazy("textAndImages", "renderEmbeds")!; @@ -451,12 +446,12 @@ export default definePlugin({ onClick={async () => { try { if (await forceUpdate()) - showToast("Success! Restarting...", Toasts.Type.SUCCESS); + showToast("Success! Restarting...", "success"); else - showToast("Already up to date!", Toasts.Type.MESSAGE); + showToast("Already up to date!"); } catch (e) { new Logger(this.name).error("Error while updating:", e); - showToast("Failed to update :(", Toasts.Type.FAILURE); + showToast("Failed to update :(", "failure"); } }} > @@ -498,34 +493,6 @@ export default definePlugin({ ); } } - if (equicordSupport || isSupportChannel(props?.channel?.id, true) || isKnownIssuesCategory(props?.channel?.parent_id, true)) { - const match = CodeBlockRe.exec(props.message.content || props.message.embeds[0]?.rawDescription || ""); - if (match) { - buttons.push( - - ); - } - } return buttons.length ? {buttons} diff --git a/src/plugins/addAttachments/index.tsx b/src/plugins/addAttachments/index.tsx index 8982b138c..18119f1f9 100644 --- a/src/plugins/addAttachments/index.tsx +++ b/src/plugins/addAttachments/index.tsx @@ -7,12 +7,12 @@ import { ChatBarButton } from "@api/ChatButtons"; import { UploadIcon } from "@components/Icons"; import { Devs } from "@utils/constants"; -import { pluralize } from "@utils/misc"; +import { pluralise } from "@utils/misc"; import definePlugin from "@utils/types"; import { Message } from "@vencord/discord-types"; import { MessageFlags, MessageType } from "@vencord/discord-types/enums"; import { findByPropsLazy } from "@webpack"; -import { AuthenticationStore, ChannelStore, EditMessageStore, MessageStore, PermissionsBits, PermissionStore, RestAPI, SelectedChannelStore, showToast, Toasts } from "@webpack/common"; +import { AuthenticationStore, ChannelStore, EditMessageStore, MessageStore, PermissionsBits, PermissionStore, RestAPI, SelectedChannelStore, showToast } from "@webpack/common"; const { uniqueId } = findByPropsLazy("uniqueId"); @@ -39,15 +39,15 @@ async function addAttachments(channelId: string, messageId: string, existingAtta if (files.length + existingAttachmentCount > 10) { const remaining = 10 - existingAttachmentCount; if (remaining <= 0) { - showToast("You cannot add more attachments to this message.", Toasts.Type.FAILURE); + showToast("You cannot add more attachments to this message.", "failure"); return; } - showToast(`You can only add ${pluralize(remaining, "more attachment")} to this message.`, Toasts.Type.FAILURE); + showToast(`You can only add ${pluralise(remaining, "more attachment")} to this message.`, "failure"); return; } - showToast("Uploading, this can take a while...", Toasts.Type.CLOCK); + showToast("Uploading, this can take a while...", "clock"); const { body: { attachments } } = await RestAPI.post({ url: `/channels/${channelId}/attachments`, @@ -86,7 +86,7 @@ async function addAttachments(channelId: string, messageId: string, existingAtta } }); - showToast(`${files.length === 1 ? "Attachment" : "Attachments"} added successfully!`, Toasts.Type.SUCCESS); + showToast(`${files.length === 1 ? "Attachment" : "Attachments"} added successfully!`, "success"); } function canAddAttachments(msg: Message) { diff --git a/src/plugins/arRPC.web/index.tsx b/src/plugins/arRPC.web/index.tsx index 31a813211..b39f07083 100644 --- a/src/plugins/arRPC.web/index.tsx +++ b/src/plugins/arRPC.web/index.tsx @@ -23,7 +23,7 @@ import { Link } from "@components/Link"; import { Paragraph } from "@components/Paragraph"; import { Devs } from "@utils/constants"; import definePlugin, { ReporterTestable } from "@utils/types"; -import { ApplicationAssetUtils, fetchApplicationsRPC, FluxDispatcher, Toasts } from "@webpack/common"; +import { ApplicationAssetUtils, fetchApplicationsRPC, FluxDispatcher, showToast } from "@webpack/common"; async function lookupAsset(applicationId: string, key: string): Promise { return (await ApplicationAssetUtils.fetchAssetIds(applicationId, [key]))[0]; @@ -92,16 +92,7 @@ export default definePlugin({ return; } - Toasts.show({ - // show toast on success - message: "Connected to arRPC", - type: Toasts.Type.SUCCESS, - id: Toasts.genId(), - options: { - duration: 1000, - position: Toasts.Position.BOTTOM - } - }); + showToast("Connected to arRPC", "success"); }, stop() { diff --git a/src/plugins/betterRoleContext/index.tsx b/src/plugins/betterRoleContext/index.tsx index 2bb93a103..5931d53fd 100644 --- a/src/plugins/betterRoleContext/index.tsx +++ b/src/plugins/betterRoleContext/index.tsx @@ -218,12 +218,10 @@ export default definePlugin({ settings, openRoleContextMenu, patches: [ - // This patch is completely overwritten by RoleColorEverywhere, but RoleColorEverywhere handles it itself - // member list role headers (in threads) { find: 'tutorialId:"whos-online', replacement: { - match: /(?<=#{intl::CHANNEL_MEMBERS_A11Y_LABEL}.{0,200}?"aria-hidden":!0,)children:.{0,200}?(?:—|\\u2014) ",\i\]\}\)\]/, + match: /(?<=#{intl::CHANNEL_MEMBERS_A11Y_LABEL}.{0,400}?)children:(?=.{0,20}?(?:—|\\u2014) ",\i\])/, replace: "onContextMenu:e=>$self.openRoleContextMenu(e,arguments[0]),$&" } }, diff --git a/src/plugins/customRPC/index.tsx b/src/plugins/customRPC/index.tsx index 17b123332..82b9988fb 100644 --- a/src/plugins/customRPC/index.tsx +++ b/src/plugins/customRPC/index.tsx @@ -18,22 +18,21 @@ import { definePluginSettings } from "@api/Settings"; import { getUserSettingLazy } from "@api/UserSettings"; +import { BaseText } from "@components/BaseText"; +import { Button } from "@components/Button"; +import { Card } from "@components/Card"; import { Divider } from "@components/Divider"; -import { ErrorCard } from "@components/ErrorCard"; import { Flex } from "@components/Flex"; -import { Heading } from "@components/Heading"; import { Link } from "@components/Link"; import { Paragraph } from "@components/Paragraph"; import { Devs } from "@utils/constants"; import { isTruthy } from "@utils/guards"; -import { Margins } from "@utils/margins"; -import { classes } from "@utils/misc"; import { useAwaiter } from "@utils/react"; import definePlugin, { OptionType } from "@utils/types"; import { Activity } from "@vencord/discord-types"; import { ActivityType } from "@vencord/discord-types/enums"; import { findByCodeLazy, findComponentByCodeLazy } from "@webpack"; -import { ApplicationAssetUtils, Button, FluxDispatcher, React, UserStore } from "@webpack/common"; +import { ApplicationAssetUtils, FluxDispatcher, Menu, React, UserStore } from "@webpack/common"; import { RPCSettings } from "./RpcSettings"; @@ -80,6 +79,12 @@ export interface RpcConfig { } export const settings = definePluginSettings({ + enablePresence: { + type: OptionType.BOOLEAN, + description: "Whether to show the presence", + default: true, + onChange: v => setRpc(!v) + }, config: { type: OptionType.COMPONENT, component: RPCSettings @@ -211,11 +216,12 @@ async function createActivity(): Promise { } export async function setRpc(disable?: boolean) { + const shouldDisable = disable ?? !settings.store.enablePresence; const activity: Activity | undefined = await createActivity(); FluxDispatcher.dispatch({ type: "LOCAL_ACTIVITY_UPDATE", - activity: !disable ? activity : null, + activity: !shouldDisable ? activity : null, socketId: "CustomRPC", }); } @@ -257,12 +263,28 @@ export default definePlugin({ name: "CustomRPC", description: "Add a fully customisable Rich Presence (Game status) to your Discord profile", tags: ["Activity", "Customisation"], - authors: [Devs.captain, Devs.AutumnVN, Devs.nin0dev], + authors: [Devs.captain, Devs.AutumnVN, Devs.nin0dev, Devs.c0nnorgg], dependencies: ["UserSettingsAPI"], // This plugin's patch is not important for functionality, so don't require a restart requiresRestart: false, settings, + toolboxActions() { + const { enablePresence } = settings.use(["enablePresence"]); + + return ( + { + settings.store.enablePresence = !enablePresence; + setRpc(); + }} + /> + ); + }, + start() { startTimestampLoop(); setRpc(); @@ -284,31 +306,38 @@ export default definePlugin({ ], settingsAboutComponent: () => { + const { enablePresence } = settings.use(["enablePresence"]); const [activity] = useAwaiter(createActivity, { fallbackValue: undefined, deps: Object.values(settings.store) }); const gameActivityEnabled = ShowCurrentGame.useSetting(); const { profileThemeStyle } = useProfileThemeStyle({}); return ( - <> + + {!enablePresence && ( + + + Custom RPC disabled + The "Enable Presence" setting is disabled, so your presence won't show. If this was unintentional, enable it below. + + + )} {!gameActivityEnabled && ( - - Notice - Activity Sharing isn't enabled, people won't be able to see your custom rich presence! + + + Activity Sharing disabled + Activity Sharing isn't enabled, so people won't be able to see your custom rich presence! - - + + + )} - + Go to the Discord Developer Portal to create an application and get the application ID. @@ -327,16 +356,16 @@ export default definePlugin({ - + -
+
{activity && }
- + ); } }); diff --git a/src/plugins/decor/lib/stores/AuthorizationStore.tsx b/src/plugins/decor/lib/stores/AuthorizationStore.tsx index 06fc47400..7aa223d43 100644 --- a/src/plugins/decor/lib/stores/AuthorizationStore.tsx +++ b/src/plugins/decor/lib/stores/AuthorizationStore.tsx @@ -8,7 +8,7 @@ import * as DataStore from "@api/DataStore"; import { AUTHORIZE_URL, CLIENT_ID } from "@plugins/decor/lib/constants"; import { proxyLazy } from "@utils/lazy"; import { Logger } from "@utils/Logger"; -import { OAuth2AuthorizeModal, openModal, showToast, Toasts, UserStore, zustandCreate, zustandPersist } from "@webpack/common"; +import { OAuth2AuthorizeModal, openModal, showToast, UserStore, zustandCreate, zustandPersist } from "@webpack/common"; interface AuthorizationState { token: string | null; @@ -74,7 +74,7 @@ export const useAuthorizationStore = proxyLazy(() => zustandCreate( resolve(void 0); } catch (e) { if (e instanceof Error) { - showToast(`Failed to authorize: ${e.message}`, Toasts.Type.FAILURE); + showToast(`Failed to authorize: ${e.message}`, "failure"); new Logger("Decor").error("Failed to authorize", e); reject(e); } diff --git a/src/plugins/expressionCloner/index.tsx b/src/plugins/expressionCloner/index.tsx index 3794cb902..e7f791e21 100644 --- a/src/plugins/expressionCloner/index.tsx +++ b/src/plugins/expressionCloner/index.tsx @@ -31,7 +31,7 @@ import definePlugin from "@utils/types"; import { Guild, GuildSticker, Message } from "@vencord/discord-types"; import { StickerFormatType } from "@vencord/discord-types/enums"; import { findByCodeLazy } from "@webpack"; -import { Constants, EmojiStore, FluxDispatcher, GuildStore, IconUtils, Menu, Modal, openModalLazy, PermissionsBits, PermissionStore, React, RestAPI, StickersStore, Toasts, Tooltip, UserStore } from "@webpack/common"; +import { Constants, EmojiStore, FluxDispatcher, GuildStore, IconUtils, Menu, Modal, openModalLazy, PermissionsBits, PermissionStore, React, RestAPI, showToast, StickersStore, Tooltip, UserStore } from "@webpack/common"; import { Promisable } from "type-fest"; const uploadEmoji = findByCodeLazy(".GUILD_EMOJIS(", "EMOJI_UPLOAD_START"); @@ -198,11 +198,7 @@ async function doClone(guildId: string, data: Sticker | Emoji) { else await cloneEmoji(guildId, data); - Toasts.show({ - message: `Successfully cloned ${data.name} to ${GuildStore.getGuild(guildId)?.name ?? "your server"}!`, - type: Toasts.Type.SUCCESS, - id: Toasts.genId() - }); + showToast(`Successfully cloned ${data.name} to ${GuildStore.getGuild(guildId)?.name ?? "your server"}!`, "success"); } catch (e: any) { let message = "Something went wrong (check console!)"; try { @@ -210,11 +206,7 @@ async function doClone(guildId: string, data: Sticker | Emoji) { } catch { } new Logger("ExpressionCloner").error("Failed to clone", data.name, "to", guildId, e); - Toasts.show({ - message: "Failed to clone: " + message, - type: Toasts.Type.FAILURE, - id: Toasts.genId() - }); + showToast("Failed to clone: " + message, "failure"); } } diff --git a/src/plugins/fakeNitro/index.tsx b/src/plugins/fakeNitro/index.tsx index 699df29ad..cc6e42d0f 100644 --- a/src/plugins/fakeNitro/index.tsx +++ b/src/plugins/fakeNitro/index.tsx @@ -75,6 +75,7 @@ const fakeNitroEmojiRegex = /\/emojis\/(\d+?)\.(png|webp|gif)/; const fakeNitroStickerRegex = /\/stickers\/(\d+?)\./; const fakeNitroGifStickerRegex = /\/attachments\/\d+?\/\d+?\/(\d+?)\.gif/; const hyperLinkRegex = /\[.+?\]\((https?:\/\/.+?)\)/; +const hyperLinkOnlyRegex = new RegExp(`^${hyperLinkRegex.source}$`); const mediaSizes = [16, 32, 48, 56, 64, 96, 128, 160, 256, 512, 1024]; const DEFAULT_EMOJI_SIZE = 48; @@ -578,6 +579,7 @@ export default definePlugin({ const contentItems = message.content.split(/\s/); if (settings.store.transformCompoundSentence) itemsToMaybePush.push(...contentItems); else if (contentItems.length === 1) itemsToMaybePush.push(contentItems[0]); + else if (hyperLinkOnlyRegex.test(message.content)) itemsToMaybePush.push(message.content); itemsToMaybePush.push(...message.attachments.filter(attachment => attachment.content_type === "image/gif").map(attachment => attachment.url)); @@ -622,7 +624,7 @@ export default definePlugin({ shouldIgnoreEmbed(embed: Message["embeds"][number], message: Message) { try { const contentItems = message.content.split(/\s/); - if (contentItems.length > 1 && !settings.store.transformCompoundSentence) return false; + if (contentItems.length > 1 && !settings.store.transformCompoundSentence && !hyperLinkOnlyRegex.test(message.content)) return false; switch (embed.type) { case "image": { @@ -631,6 +633,7 @@ export default definePlugin({ if ( !settings.store.transformCompoundSentence && !contentItems.some(item => item === url || item.match(hyperLinkRegex)?.[1] === url) + && !hyperLinkOnlyRegex.test(message.content) ) return false; if (settings.store.transformEmojis) { diff --git a/src/plugins/ignoreActivities/index.tsx b/src/plugins/ignoreActivities/index.tsx index f60eb404f..7b590c15d 100644 --- a/src/plugins/ignoreActivities/index.tsx +++ b/src/plugins/ignoreActivities/index.tsx @@ -16,7 +16,7 @@ import CustomRpcPlugin from "@plugins/customRPC"; import { Devs } from "@utils/constants"; import { Margins } from "@utils/margins"; import definePlugin, { OptionType } from "@utils/types"; -import { FluxDispatcher, Menu, RunningGameStore, showToast, TextArea, Toasts, Tooltip, useEffect, useState } from "@webpack/common"; +import { FluxDispatcher, Menu, RunningGameStore, showToast, TextArea, Tooltip, useEffect, useState } from "@webpack/common"; const enum ActivitiesTypes { Game, @@ -91,12 +91,12 @@ function ImportCustomRPCComponent() { onClick={() => { const id = CustomRpcPlugin.settings.store.appID; if (!id) { - return showToast("CustomRPC application ID is not set.", Toasts.Type.FAILURE); + return showToast("CustomRPC application ID is not set.", "failure"); } const isAlreadyAdded = idsListPushID?.(id); if (isAlreadyAdded) { - showToast("CustomRPC application ID is already added.", Toasts.Type.FAILURE); + showToast("CustomRPC application ID is already added.", "failure"); } }} > @@ -296,8 +296,8 @@ export default definePlugin({ find: '"LocalActivityStore"', replacement: [ { - match: /\.LISTENING.+?(?=!?\i\(\)\(\i,\i\))(?<=(\i)\.push.+?)/, - replace: (m, activities) => `${m}${activities}=${activities}.filter($self.isActivityNotIgnored);` + match: /\.LISTENING.+?([,:])(?=!?\i\(\)\(\i,\i\))(?<=(\i)\.push.+?)/, + replace: (m, commaOrSemiColon, activities) => `${m}${activities}=${activities}.filter($self.isActivityNotIgnored)${commaOrSemiColon}` } ] }, diff --git a/src/plugins/implicitRelationships/index.ts b/src/plugins/implicitRelationships/index.ts index 2ec66fc0b..031e67220 100644 --- a/src/plugins/implicitRelationships/index.ts +++ b/src/plugins/implicitRelationships/index.ts @@ -163,7 +163,7 @@ export default definePlugin({ FluxDispatcher.dispatch({ type: "GUILD_MEMBERS_REQUEST", guildIds: allGuildIds, - userIds: toRequest.slice(i, i + 100), + userIds: toRequest.slice(i, i + 100).map(e => e.otherUserId), presences: true, nonce: sentNonce, }); diff --git a/src/plugins/openInApp/index.ts b/src/plugins/openInApp/index.ts index 08dbfe9c8..c68c24e6c 100644 --- a/src/plugins/openInApp/index.ts +++ b/src/plugins/openInApp/index.ts @@ -19,7 +19,7 @@ import { definePluginSettings } from "@api/Settings"; import { Devs } from "@utils/constants"; import definePlugin, { OptionType, PluginNative, SettingsDefinition } from "@utils/types"; -import { showToast, Toasts } from "@webpack/common"; +import { showToast } from "@webpack/common"; import type { MouseEvent } from "react"; interface URLReplacementRule { @@ -145,7 +145,7 @@ export default definePlugin({ } if (rule.match.test(url)) { - showToast("Opened link in native app", Toasts.Type.SUCCESS); + showToast("Opened link in native app", "success"); const newUrl = url.replace(rule.match, rule.replace); VencordNative.native.openExternal(newUrl); diff --git a/src/plugins/pinDms/components/CreateCategoryModal.tsx b/src/plugins/pinDms/components/CreateCategoryModal.tsx index 3f418ed7d..7e2568027 100644 --- a/src/plugins/pinDms/components/CreateCategoryModal.tsx +++ b/src/plugins/pinDms/components/CreateCategoryModal.tsx @@ -10,7 +10,7 @@ import { categoryLen, createCategory, getCategory } from "@plugins/pinDms/data"; import { classNameFactory } from "@utils/css"; import { RenderModalProps } from "@vencord/discord-types"; import { extractAndLoadChunksLazy, findComponentByCodeLazy } from "@webpack"; -import { ColorPicker, Modal, openModalLazy, TextInput, Toasts, useMemo, useState } from "@webpack/common"; +import { ColorPicker, Modal, openModalLazy, TextInput, useMemo, useState } from "@webpack/common"; interface ColorPickerWithSwatchesProps { className?: string; @@ -41,7 +41,7 @@ function useCategory(categoryId: string | null, initalChannelId: string | null) return getCategory(categoryId); } else if (initalChannelId) { return { - id: Toasts.genId(), + id: crypto.randomUUID(), name: `Pin Category ${categoryLen() + 1}`, color: DEFAULT_COLOR, collapsed: false, diff --git a/src/plugins/reviewDB/auth.tsx b/src/plugins/reviewDB/auth.tsx index 7cf7794af..8215bff62 100644 --- a/src/plugins/reviewDB/auth.tsx +++ b/src/plugins/reviewDB/auth.tsx @@ -6,7 +6,7 @@ import * as DataStore from "@api/DataStore"; import { Logger } from "@utils/Logger"; -import { OAuth2AuthorizeModal, openModal, showToast, Toasts, UserStore } from "@webpack/common"; +import { OAuth2AuthorizeModal, openModal, showToast, UserStore } from "@webpack/common"; import { ReviewDBAuth } from "./entities"; @@ -60,13 +60,13 @@ export function authorize(callback?: () => void) { if (!res.ok) { const { message } = await res.json(); - showToast(message ?? "An error occured while authorizing", Toasts.Type.FAILURE); + showToast(message ?? "An error occured while authorizing", "failure"); return; } const { token } = await res.json(); updateAuth({ token }); - showToast("Successfully logged in!", Toasts.Type.SUCCESS); + showToast("Successfully logged in!", "success"); callback?.(); } catch (e) { new Logger("ReviewDB").error("Failed to authorize", e); diff --git a/src/plugins/reviewDB/reviewDbApi.ts b/src/plugins/reviewDB/reviewDbApi.ts index 0a040b866..0f57853ae 100644 --- a/src/plugins/reviewDB/reviewDbApi.ts +++ b/src/plugins/reviewDB/reviewDbApi.ts @@ -4,8 +4,6 @@ * SPDX-License-Identifier: GPL-3.0-or-later */ -import { Toasts } from "@webpack/common"; - import { Auth, authorize, getToken, updateAuth } from "./auth"; import { Review, ReviewDBCurrentUser, ReviewDBUser, ReviewType } from "./entities"; import { settings } from "./settings"; @@ -51,7 +49,7 @@ async function rdbRequest(path: string, options: RequestInit = {}): ...options, headers, }).catch(err => { - showToast("Network error: Failed to connect to ReviewDB.", Toasts.Type.FAILURE); + showToast("Network error: Failed to connect to ReviewDB.", "failure"); return null; }); @@ -61,7 +59,7 @@ async function rdbRequest(path: string, options: RequestInit = {}): if (!res.ok) { const message = data?.message ?? `ReviewDB: Request failed with status ${res.status}`; - showToast(message, Toasts.Type.FAILURE); + showToast(message, "failure"); return null; } @@ -92,7 +90,7 @@ export async function getReviews(id: string, { limit, offset = 0, fetchVotes = f }; if (!req.ok) { - showToast(res.message, Toasts.Type.FAILURE); + showToast(res.message, "failure"); return { ...res, reviews: [ @@ -140,7 +138,7 @@ export async function getReviewVotes(id: string): Promise { return res?.votes ?? []; } -export async function addReview(review): Promise { +export async function addReview(review: { userid: string; comment: string; }): Promise { const token = await getToken(); if (!token) { @@ -224,7 +222,7 @@ async function patchBlock(action: "block" | "unblock", userId: string) { if (!data) return; - showToast(`Successfully ${action}ed user`, Toasts.Type.SUCCESS); + showToast(`Successfully ${action}ed user`, "success"); if (Auth?.user?.blockedUsers) { const newBlockedUsers = action === "block" diff --git a/src/plugins/reviewDB/utils.tsx b/src/plugins/reviewDB/utils.tsx index ec7609c50..e9ea0a68e 100644 --- a/src/plugins/reviewDB/utils.tsx +++ b/src/plugins/reviewDB/utils.tsx @@ -17,7 +17,9 @@ */ import { classNameFactory } from "@utils/css"; -import { Toasts, UserStore } from "@webpack/common"; +import { ToastType } from "@vencord/discord-types"; +import { ToastPosition } from "@vencord/discord-types/enums"; +import { showToast as originalShowToast, UserStore } from "@webpack/common"; import { Auth } from "./auth"; import { Review, UserType } from "./entities"; @@ -42,13 +44,8 @@ export function canReportReview(review: Review) { return review.sender.discordID !== UserStore.getCurrentUser().id; } -export function showToast(message: string, type = Toasts.Type.MESSAGE) { - Toasts.show({ - id: Toasts.genId(), - message, - type, - options: { - position: Toasts.Position.BOTTOM, // NOBODY LIKES TOASTS AT THE TOP - }, +export function showToast(message: string, type: ToastType = "message") { + originalShowToast(message, type, { + position: ToastPosition.BOTTOM }); } diff --git a/src/plugins/roleColorEverywhere/index.tsx b/src/plugins/roleColorEverywhere/index.tsx index 29111da5b..3f42848ef 100644 --- a/src/plugins/roleColorEverywhere/index.tsx +++ b/src/plugins/roleColorEverywhere/index.tsx @@ -17,10 +17,8 @@ */ import { isPluginEnabled } from "@api/PluginManager"; -import { definePluginSettings, Settings } from "@api/Settings"; -import ErrorBoundary from "@components/ErrorBoundary"; -import { getCustomColorString } from "@equicordplugins/customUserColors"; -import BetterRoleContext from "@plugins/betterRoleContext"; +import { definePluginSettings } from "@api/Settings"; +import customUserColors, { getCustomColorString } from "@equicordplugins/customUserColors"; import { Devs } from "@utils/constants"; import { Logger } from "@utils/Logger"; import definePlugin, { makeRange, OptionType } from "@utils/types"; @@ -110,8 +108,8 @@ export default definePlugin({ find: 'tutorialId:"whos-online', replacement: [ { - match: /(#{intl::CHANNEL_MEMBERS_A11Y_LABEL}.{0,200}?}\):null,).{0,200}?(?:—|\\u2014) ",\i\]\}\)\]/, - replace: "$1$self.RoleGroupColor(arguments[0])]" + match: /(?<=#{intl::CHANNEL_MEMBERS_A11Y_LABEL}.{0,400}?)children:(?=.{0,20}?(?:—|\\u2014) ",\i\])/, + replace: "style:{color:$self.getRoleColor(arguments[0])},$&" }, ], predicate: () => settings.store.memberList @@ -121,8 +119,8 @@ export default definePlugin({ find: "?null:new Intl.NumberFormat", replacement: [ { - match: /\(0,\i\.jsx\)\("span",\{[^}]+\}\),null==\i\?null:\(0,\i\.jsxs\)\("span",\{children:\["\\xa0\\u2014 ",\i\]\}\)\]/, - replace: "$self.RoleGroupColor(arguments[0])]" + match: /(?<=#{intl::CHANNEL_MEMBERS_A11Y_LABEL},\{title:\i,count:\i\}\)\}\),\(0,\i\.jsxs\)\("div",\{)/, + replace: "style:{color:$self.getRoleColor(arguments[0])}," }, ], predicate: () => settings.store.memberList @@ -169,7 +167,7 @@ export default definePlugin({ getColorString(userId: string, channelOrGuildId: string) { try { - if (Settings.plugins.CustomUserColors.enabled) { + if (isPluginEnabled(customUserColors.name)) { const customColor = getCustomColorString(userId, true); if (customColor) return customColor; } @@ -222,22 +220,9 @@ export default definePlugin({ return null; }, - RoleGroupColor: ErrorBoundary.wrap(({ id, count, title, guildId, label }: { id: string; count: number; title: string; guildId: string; label: string; }) => { - const role = GuildRoleStore.getRole(guildId, id); - // we overwrite the context menu event added by BetterRoleContext in our patch - const wantsRoleContext = isPluginEnabled(BetterRoleContext.name); - - return ( - BetterRoleContext.openRoleContextMenu(e, { guildId, id }) : undefined} - > - {title ?? label} — {count} - - ); - }, { noop: true }) + getRoleColor(props: any) { + try { + return GuildRoleStore.getRole(props?.guildId, props?.id)?.colorString; + } catch (e) { } + } }); diff --git a/src/plugins/stickerPaste/index.ts b/src/plugins/stickerPaste/index.ts index afdd53f57..4d216d6ba 100644 --- a/src/plugins/stickerPaste/index.ts +++ b/src/plugins/stickerPaste/index.ts @@ -17,7 +17,7 @@ export default definePlugin({ { // This function is a util func from another module // but it only has once use here so it's inlined - find: ".CREATE_FORUM_POST||function(", + find: '.STICKER_PICKER:return""', replacement: { match: /(?<=\){)if\(\i\.\i\.getUploadCount/, replace: "return true;$&", diff --git a/src/plugins/translate/utils.ts b/src/plugins/translate/utils.ts index 2c77db511..934def25d 100644 --- a/src/plugins/translate/utils.ts +++ b/src/plugins/translate/utils.ts @@ -19,7 +19,7 @@ import { classNameFactory } from "@utils/css"; import { onlyOnce } from "@utils/onlyOnce"; import { PluginNative } from "@utils/types"; -import { showToast, Toasts } from "@webpack/common"; +import { showToast } from "@webpack/common"; import { DeeplLanguages, deeplLanguageToGoogleLanguage, GoogleLanguages, KagiLanguages } from "./languages"; import { resetLanguageDefaults, settings } from "./settings"; @@ -89,7 +89,7 @@ export async function translate(kind: "received" | "sent", text: string): Promis ? e : "Something went wrong. If this issue persists, please check the console or ask for help in the support server."; - showToast(userMessage, Toasts.Type.FAILURE); + showToast(userMessage, "failure"); throw e instanceof Error ? e @@ -131,12 +131,12 @@ function fallbackToGoogle(text: string, sourceLang: string, targetLang: string): } const showDeeplApiQuotaToast = onlyOnce( - () => showToast("Deepl API quota exceeded. Falling back to Google Translate", Toasts.Type.FAILURE) + () => showToast("Deepl API quota exceeded. Falling back to Google Translate", "failure") ); async function deeplTranslate(text: string, sourceLang: string, targetLang: string): Promise { if (!settings.store.deeplApiKey) { - showToast("DeepL API key is not set. Resetting to Google", Toasts.Type.FAILURE); + showToast("DeepL API key is not set. Resetting to Google", "failure"); settings.store.service = "google"; resetLanguageDefaults(); diff --git a/src/plugins/userVoiceShow/components.tsx b/src/plugins/userVoiceShow/components.tsx index 9d96e2b9a..48d5ee264 100644 --- a/src/plugins/userVoiceShow/components.tsx +++ b/src/plugins/userVoiceShow/components.tsx @@ -12,7 +12,7 @@ import { classNameFactory } from "@utils/css"; import { classes } from "@utils/misc"; import { Channel } from "@vencord/discord-types"; import { findByPropsLazy, findCssClassesLazy } from "@webpack"; -import { ChannelRouter, ChannelStore, Parser, PermissionsBits, PermissionStore, React, showToast, Toasts, Tooltip, useMemo, UserStore, UserSummaryItem, useStateFromStores, VoiceStateStore } from "@webpack/common"; +import { ChannelRouter, ChannelStore, Parser, PermissionsBits, PermissionStore, React, showToast, Tooltip, useMemo, UserStore, UserSummaryItem, useStateFromStores, VoiceStateStore } from "@webpack/common"; import { PropsWithChildren } from "react"; const cl = classNameFactory("vc-uvs-"); @@ -155,7 +155,7 @@ export const VoiceChannelIndicator = ErrorBoundary.wrap(({ userId, isProfile, is if (e.detail > 1) { if (!isDM && !PermissionStore.can(PermissionsBits.CONNECT, channel)) { - showToast("You cannot join the user's Voice Channel", Toasts.Type.FAILURE); + showToast("You cannot join the user's Voice Channel", "failure"); return; } diff --git a/src/plugins/voiceMessages/components/DesktopRecorder.tsx b/src/plugins/voiceMessages/components/DesktopRecorder.tsx index b29cb2f03..f8d241823 100644 --- a/src/plugins/voiceMessages/components/DesktopRecorder.tsx +++ b/src/plugins/voiceMessages/components/DesktopRecorder.tsx @@ -17,7 +17,7 @@ */ import { PluginNative } from "@utils/types"; -import { Button, MediaEngineStore, showToast, Toasts, useState } from "@webpack/common"; +import { Button, MediaEngineStore, showToast, useState } from "@webpack/common"; import { settings, type VoiceRecorder } from ".."; @@ -46,7 +46,7 @@ export const VoiceRecorderDesktop: VoiceRecorder = ({ setAudioBlob, onRecordingC if (success) changeRecording(true); else - showToast("Failed to start recording", Toasts.Type.FAILURE); + showToast("Failed to start recording", "failure"); } ); } else { @@ -56,7 +56,7 @@ export const VoiceRecorderDesktop: VoiceRecorder = ({ setAudioBlob, onRecordingC if (buf) setAudioBlob(new Blob([new Uint8Array(buf)], { type: "audio/ogg; codecs=opus" })); else - showToast("Failed to finish recording", Toasts.Type.FAILURE); + showToast("Failed to finish recording", "failure"); } changeRecording(false); }); diff --git a/src/plugins/voiceMessages/index.tsx b/src/plugins/voiceMessages/index.tsx index cee15c23a..89a2c13f4 100644 --- a/src/plugins/voiceMessages/index.tsx +++ b/src/plugins/voiceMessages/index.tsx @@ -33,7 +33,7 @@ import definePlugin, { OptionType } from "@utils/types"; import { chooseFile } from "@utils/web"; import { RenderModalProps } from "@vencord/discord-types"; import { CloudUploadPlatform } from "@vencord/discord-types/enums"; -import { Button, CloudUploader, Constants, FluxDispatcher, Forms, lodash, Menu, MessageActions, Modal, openModal, PendingReplyStore, PermissionsBits, PermissionStore, RestAPI, SelectedChannelStore, showToast, SnowflakeUtils, Toasts, useEffect, useState } from "@webpack/common"; +import { Button, CloudUploader, Constants, FluxDispatcher, Forms, lodash, Menu, MessageActions, Modal, openModal, PendingReplyStore, PermissionsBits, PermissionStore, RestAPI, SelectedChannelStore, showToast, SnowflakeUtils, useEffect, useState } from "@webpack/common"; import { ComponentType } from "react"; import { VoiceRecorderDesktop } from "./components/DesktopRecorder"; @@ -190,7 +190,7 @@ function sendAudio(blob: Blob, meta: AudioMetadata) { } }); }); - upload.on("error", () => showToast("Failed to upload voice message", Toasts.Type.FAILURE)); + upload.on("error", () => showToast("Failed to upload voice message", "failure")); upload.upload(); } @@ -244,7 +244,7 @@ function VoiceMessageModal({ modalProps }: { modalProps: RenderModalProps; }) { onClick: () => { sendAudio(blob!, meta ?? EMPTY_META); modalProps.onClose(); - showToast("Now sending voice message... Please be patient", Toasts.Type.MESSAGE); + showToast("Now sending voice message... Please be patient", "clock"); }, disabled: !blob }]} diff --git a/src/utils/constants.ts b/src/utils/constants.ts index 201970624..e6b8bd0a1 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -698,6 +698,10 @@ export const Devs = /* #__PURE__*/ Object.freeze({ Kaede: { name: "Kaede", id: 1492642701320126504n + }, + c0nnorgg: { + name: "c0nnorgg", + id: 1088882977985003620n, } } satisfies Record); diff --git a/src/utils/discord.tsx b/src/utils/discord.tsx index aeeacc723..256cd53f5 100644 --- a/src/utils/discord.tsx +++ b/src/utils/discord.tsx @@ -18,7 +18,7 @@ import type { MessageObject } from "@api/MessageEvents"; import type { BasicGuild, Channel, CloudUpload, Guild, GuildFeatures, GuildProfile, MediaModalItem, MediaModalProps, Message, User } from "@vencord/discord-types"; -import { ChannelActionCreators, ChannelStore, ComponentDispatch, Constants, FluxDispatcher, GuildStore, i18n, InviteActions, MessageActions, openMediaModal, RestAPI, SelectedChannelStore, SelectedGuildStore, Toasts, UserProfileActions, UserProfileStore, UserSettingsActionCreators, UserUtils } from "@webpack/common"; +import { ChannelActionCreators, ChannelStore, ComponentDispatch, Constants, FluxDispatcher, GuildStore, i18n, InviteActions, MessageActions, openMediaModal, openUserProfileModal, RestAPI, SelectedChannelStore, SelectedGuildStore, showToast, UserProfileStore, UserSettingsActionCreators, UserUtils } from "@webpack/common"; import { Except } from "type-fest"; import { copyToClipboard } from "./clipboard"; @@ -116,11 +116,7 @@ export function insertTextIntoChatInputBox(text: string) { export async function copyWithToast(text: string, toastMessage = "Copied to clipboard!") { await copyToClipboard(text); - Toasts.show({ - message: toastMessage, - id: Toasts.genId(), - type: Toasts.Type.SUCCESS - }); + showToast(toastMessage, "success"); } export interface MessageOptions { @@ -182,10 +178,14 @@ export async function openUserProfile(id: string) { if (!user) throw new Error("No such user: " + id); const guildId = SelectedGuildStore.getGuildId(); - UserProfileActions.openUserProfileModal({ + openUserProfileModal({ userId: id, guildId, channelId: SelectedChannelStore.getChannelId(), + sourceAnalyticsLocations: [ + "username", + "user profile popout", + ] }); } diff --git a/src/webpack/common/utils.ts b/src/webpack/common/utils.ts index 129fe6de8..47903155b 100644 --- a/src/webpack/common/utils.ts +++ b/src/webpack/common/utils.ts @@ -16,7 +16,7 @@ * along with this program. If not, see . */ -import type * as t from "@vencord/discord-types"; +import * as t from "@vencord/discord-types"; import { _resolveReady, filters, findByCodeLazy, findByPropsLazy, findLazy, mapMangledModuleLazy, waitFor } from "@webpack"; import type * as TSPattern from "ts-pattern"; @@ -70,23 +70,6 @@ waitFor("parseTopic", m => Parser = m); export let Alerts: t.Alerts; waitFor(["show", "close"], m => Alerts = m); -const ToastType = { - MESSAGE: "message", - SUCCESS: "success", - FAILURE: "failure", - CUSTOM: "custom", - CLIP: "clip", - LINK: "link", - FORWARD: "forward", - BOOKMARK: "bookmark", - CLOCK: "clock" -}; - -const ToastPosition = { - TOP: 0, - BOTTOM: 1 -}; - export interface ToastData { message: string, id: string, @@ -106,40 +89,18 @@ export interface ToastOptions { duration?: number; } -interface ToastsExports { - showToast: (data: ToastData) => void; - popToast(): void; -} - -const ToastsExports = mapMangledModuleLazy(".currentToastMap.has(", { - showToast: filters.byCode(".currentToastMap.has("), - popToast: filters.byCode(".delete(") +export const Toasts: t.Toasts = mapMangledModuleLazy(".currentToastMap.has(", { + show: filters.byCode(".currentToastMap.has("), + pop: filters.byCode(".delete(") }); -export function createToast(message: string, type: string, options?: ToastOptions): ToastData { - return { - message, - id: Toasts.genId(), - type, - options - }; -} - -export const Toasts = { - Type: ToastType, - Position: ToastPosition, - genId: () => (Math.random() || Math.random()).toString(36).slice(2), - - show: ToastsExports.showToast, - pop: ToastsExports.popToast, - create: createToast, -}; +export const createToast: t.createToast = findByCodeLazy('variant:"default",icon:', ".duration"); /** * Show a simple toast. If you need more options, use Toasts.show manually */ -export function showToast(message: string, type = ToastType.MESSAGE, options?: ToastOptions) { - Toasts.show(Toasts.create(message, type, options)); +export function showToast(message: string, type: t.ToastType = "message", options?: ToastOptions) { + Toasts.show(createToast({ message, type, options })); } export const UserUtils = { @@ -185,9 +146,7 @@ export const { zustandPersist } = mapMangledModuleLazy(".onRehydrateStorage)?", export const MessageActions = findByPropsLazy("editMessage", "sendMessage"); export const MessageCache = findByPropsLazy("clearCache", "_channelMessages"); -export const UserProfileActions: t.UserProfileModalActionCreators = mapMangledModuleLazy(".log(`Failed to fetch profile for $", { - openUserProfileModal: filters.byCode('type:"USER_PROFILE_MODAL_OPEN"') -}); +export const openUserProfileModal: t.OpenUserProfileModal = findByCodeLazy('type:"USER_PROFILE_MODAL_OPEN"'); export const InviteActions = findByPropsLazy("resolveInvite"); export const ChannelActionCreators = findByPropsLazy("openPrivateChannel");