Compare commits

...

22 commits

Author SHA1 Message Date
thororen
1489c0e2a4
remove separator
Some checks failed
Build Branches / Build Equicord (push) Has been skipped
Release / Build Equicord (push) Failing after 8s
Release Browser Extension / release (push) Failing after 5s
Test / Test (push) Failing after 4s
Sync to Codeberg / codeberg (push) Has been skipped
2026-10-03 16:37:38 -04:00
thororen
e8a11aa0a2
vee's tray updates 2026-10-03 16:35:13 -04:00
thororen
ebf7242051
lint 2026-10-03 13:01:51 -04:00
thororen
e68a69641c
Fixes 2026-10-03 11:16:17 -04:00
thororen
cfec48401b
Merge remote-tracking branch 'upstream/dev' into dev 2026-10-03 11:10:38 -04:00
uku
14723674a2
FakeNitro: fix transforming stickers with spaces in name (#4640)
Co-authored-by: Vendicated <vendicated@riseup.net>
2026-10-03 16:57:26 +02:00
sadan
445edc7586
fix RoleColorEverywhere, StickerPaste, BetterRoleContext (#4641)
Co-authored-by: V <vendicated@riseup.net>
2026-10-03 13:41:29 +00:00
Vendicated
b52ed365cf
Remove 'Run Snippet' functionality
This was really nice to have support, but having functionality like this is inherently unsafe.
For security reasons, it's better to remove it.
2026-10-03 00:56:19 +02:00
Vendicated
0c3c9625a7
fix Toasts 2026-10-03 00:50:35 +02:00
Vendicated
d9bc6f71fd
IgnoreActivities: fix breaking all activities 2026-10-03 00:05:16 +02:00
thororen
779a87b9b1
Decor: make wysiwyg better 2026-10-02 10:23:38 -04:00
thororen
cbab61da91
BetterAudioPlayer: Use CORS Proxy Again 2026-10-02 08:58:51 -04:00
thororen
bc68ff9b10
MessageLinkTooltip: Fix Random Crashing 2026-10-02 08:53:44 -04:00
Etorix
c82de288f7
Questify & SongSpotlight: Patch Fixes. (#1382)
* Questify: Patch Fix.

* SongSpotlight: Fix profile modal options.
2026-10-01 23:26:42 -04:00
thororen
5408a0224c
RoleColorEverywhere: Debatably Fix Conflict 2026-10-01 21:43:40 -04:00
thororen
c96a1cae9b
Fix Decor WYSIWG Patch 2026-10-01 21:37:29 -04:00
thororen
d0706ac443
Fix Patches 2026-10-01 21:36:45 -04:00
thororen
6c7fed05cd
Sadan's Patch Fixes
Co-Authored-By: sadan <117494111+sadan4@users.noreply.github.com>
2026-10-01 21:09:14 -04:00
thororen
96334432fa
ChannelTabs: Remove dead css 2026-09-30 22:58:26 -04:00
Vendicated
09210898a0
Fix native titlebar setting 2026-09-30 17:13:02 +02:00
Ambushfall
d3edab7ba8
ImplicitRelationship: fix bug in user fetching (#4217) 2026-09-30 16:54:44 +02:00
Connor
40ae4d2a39
CustomRPC: add toggle & Toolbox action for disabling presence (#4636)
Co-authored-by: Vendicated <vendicated@riseup.net>
2026-09-30 16:02:18 +02:00
138 changed files with 1055 additions and 1339 deletions

View file

@ -73,8 +73,8 @@ window.VencordNative = {
updater: { updater: {
getRepo: async () => ({ ok: true, value: "https://github.com/Equicord/Equicord" }), getRepo: async () => ({ ok: true, value: "https://github.com/Equicord/Equicord" }),
getUpdates: async () => ({ ok: true, value: [] }), getUpdates: async () => ({ ok: true, value: [] }),
update: async () => ({ ok: true, value: false }), fetchUpdate: async () => ({ ok: true, value: false }),
rebuild: async () => ({ ok: true, value: true }), applyUpdate: async () => ({ ok: true, value: true }),
}, },
quickCss: { quickCss: {
@ -136,9 +136,4 @@ window.VencordNative = {
pluginHelpers: {} as any, pluginHelpers: {} as any,
csp: {} as any, csp: {} as any,
tray: {
setUpdateState: NOOP,
onCheckUpdates: NOOP,
onRepair: NOOP,
},
}; };

View file

@ -97,7 +97,7 @@
"typescript-transform-paths": "^3.5.6", "typescript-transform-paths": "^3.5.6",
"zip-local": "^0.3.5" "zip-local": "^0.3.5"
}, },
"packageManager": "pnpm@12.6.0", "packageManager": "pnpm@12.8.1",
"engines": { "engines": {
"node": ">=22" "node": ">=22"
} }

View file

@ -53,3 +53,8 @@ export const enum PremiumType {
TIER_2 = 2, TIER_2 = 2,
TIER_0 = 3, TIER_0 = 3,
} }
export const enum ToastPosition {
TOP = 0,
BOTTOM = 1,
}

View file

@ -7,5 +7,6 @@ export * from "./fluxEvents";
export * from "./menu"; export * from "./menu";
export * from "./modules"; export * from "./modules";
export * from "./stores"; export * from "./stores";
export * from "./toasts";
export * from "./utils"; export * from "./utils";
export * as Webpack from "../webpack"; export * as Webpack from "../webpack";

35
packages/discord-types/src/toasts.d.ts vendored Normal file
View file

@ -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;
}

View file

@ -416,3 +416,46 @@ export interface EmojiUtils {
triggerFullscreenAnimation(emoji: any, node: HTMLElement): void; triggerFullscreenAnimation(emoji: any, node: HTMLElement): void;
applyPlatformToThemedEmojiColorPalette(colors: any): any; applyPlatformToThemedEmojiColorPalette(colors: any): any;
} }
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 {@link SettingsRouter.openUserSettings} source)
*/
path?: string;
/**
* modal stacking behavior, defaults to "replaceAll"
*/
stackingBehavior?: "replaceAll" | "stack" | "replace";
// ... misc analytics options
}
export interface SettingsRouter {
openUserSettings(navigationTarget?: string, opts?: OpenUserSettingsOptions, onOpen?: () => void): Promise<void>;
}
export interface OpenUserProfileModalOptions {
userId: string;
guildId?: string | null;
originGuildId?: string | null;
channelId?: string | null;
messageId?: string | null;
roleId?: string | null;
sessionId?: unknown | null;
joinRequestId?: unknown;
tabSection?: unknown;
scrollTarget?: unknown;
hideRestrictedProfile?: boolean;
sourceAnalyticsLocations?: string[];
appContext?: unknown;
/**
* defaults to null
*/
customStatusPrompt?: unknown;
onModalOpen?: unknown;
}
export type OpenUserProfileModal = (opts: OpenUserProfileModalOptions) => Promise<void>;

122
pnpm-lock.yaml generated
View file

@ -7,153 +7,153 @@ importers:
configDependencies: {} configDependencies: {}
packageManagerDependencies: packageManagerDependencies:
pnpm: pnpm:
specifier: 12.6.0 specifier: 12.8.1
version: 12.6.0 version: 12.8.1
packages: packages:
'@pnpm/exe.android-arm64@12.6.0': '@pnpm/exe.android-arm64@12.8.1':
resolution: {integrity: sha512-kviIHft9h02q+7N2In7tSL9T/HRUSGwYmU74YPtsWU5ee7vgqPyC0JT6RRX6miW+NxX1CvHgQxg69qq1qTLJYQ==} resolution: {integrity: sha512-siDxcidfz5eM6L2tJfik+i2bbUEw8UC7MZ3Yl2HYdRmqbdhHGAOQACtOOu6QVW4Jul4/w5wVKm+wM8ACtgh1Pg==}
cpu: [arm64] cpu: [arm64]
os: [android] os: [android]
'@pnpm/exe.android-x64@12.6.0': '@pnpm/exe.android-x64@12.8.1':
resolution: {integrity: sha512-CT8aJKLq2mtZFE71pr4E5Z2xHL8uGnRGr+NclDqsXlVF4SVcQ2QAs14mWi0C8gjT4hbmi+Q0lJRRIkMAWfjjng==} resolution: {integrity: sha512-0F/uqPRc3aN4vLHsa0f+6fTtmsigFQ9/yxEU43fionF//pNHEd5e97b3w/nKIgqYMCUQCJphmBRMA9Q8/wlo9Q==}
cpu: [x64] cpu: [x64]
os: [android] os: [android]
'@pnpm/exe.darwin-arm64@12.6.0': '@pnpm/exe.darwin-arm64@12.8.1':
resolution: {integrity: sha512-rafpVkjzugKBMxSvGQd5wK1x5eOTkD/+lcJIFHeQhvd+BJ8kDisOOvwhQDrpGd4vd2Fx+hhW0P2Ptt638OlhFg==} resolution: {integrity: sha512-/rwavvMQJsl2RIxOHBnDF+4Gk+fhQFAY4M3PQZoKskJOEnaJcygG9p1xby6wcQcbS4d9dIubv09CQhufTgfmpw==}
cpu: [arm64] cpu: [arm64]
os: [darwin] os: [darwin]
'@pnpm/exe.darwin-x64@12.6.0': '@pnpm/exe.darwin-x64@12.8.1':
resolution: {integrity: sha512-72Jpuv1m24gI8zUNcaylYpBWEhBzz1VPhnDIU2GYM2eRP+KsOqVLwV78i+JrihI39zY2NNXmaN4eAKX1inpaDQ==} resolution: {integrity: sha512-htYt2gN7zqJKLhC99Ft6EUiO7myjZAZXfmGCTJUL1v+o7vE9hZdE1+fAkk4Oj1ZHNRti6b2woOxEkRkAusi8OQ==}
cpu: [x64] cpu: [x64]
os: [darwin] os: [darwin]
'@pnpm/exe.freebsd-x64@12.6.0': '@pnpm/exe.freebsd-x64@12.8.1':
resolution: {integrity: sha512-LON4QgNy1w/XF4uySZIyC/5hEB0oGdelXsY9tSKqstER+2j2X2oHz67skD11RRd/HWFRtMr64shQZ4I9ZoZ0zg==} resolution: {integrity: sha512-PB5BULNgytxvExoOXUUeseS/DcpPENs+cg3iA6xHHeaLT4ctEGKSGXEbuj7USeqvo8JBpAx039hivnbzGqDwnA==}
cpu: [x64] cpu: [x64]
os: [freebsd] os: [freebsd]
'@pnpm/exe.linux-arm64-musl@12.6.0': '@pnpm/exe.linux-arm64-musl@12.8.1':
resolution: {integrity: sha512-BdDpX+DeaMUc5x6WNcE6FkmFy36NwrBbBvwsZU737Zt3u1fTY+iKFPchjEQNCM4rT6q6xvF2oN3ZwExGsJCkxQ==} resolution: {integrity: sha512-kKeyC/ArjrgdciQRBrOL0j9HtOI4gDRgoyP+eJ1CQKyadpKlf/DhDDyspXe07R3B9KagTVLUF2nlt6Dr5quFIg==}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
libc: [musl] libc: [musl]
'@pnpm/exe.linux-arm64@12.6.0': '@pnpm/exe.linux-arm64@12.8.1':
resolution: {integrity: sha512-8h2sNoIhHDpHDYqZZCh9PXr6krqW10btb0GHVGuw710muDHlFAHMtUG2ogmaHge6zJG1xgY4Y7mwX5g/LWvrYg==} resolution: {integrity: sha512-q4s9a9X2O3N9aeUFooW24orNrxvu20+jyVUFR5RanPCqOKKPBrgs2iywMkBBx1aXkkzdWT54/mfz8Be8sJlWEw==}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
libc: [glibc] libc: [glibc]
'@pnpm/exe.linux-ppc64@12.6.0': '@pnpm/exe.linux-ppc64@12.8.1':
resolution: {integrity: sha512-ld6xgcEhFCFrsVsJhbmdmR714PnsEspO/Ij8w0/D7OSiz2hYGu3fZd5tKRxOI5m6H6Gl0/RRFAPncTHbsgXVjQ==} resolution: {integrity: sha512-F7XSjKJthwCh/L6abZiMpAfo2Cm61SZIT3e4dfgiIjESndlWaXCnfLKngSgZ/SEMsdmHT6dud3+kWIB3tw0/xQ==}
cpu: [ppc64] cpu: [ppc64]
os: [linux] os: [linux]
libc: [glibc] libc: [glibc]
'@pnpm/exe.linux-riscv64@12.6.0': '@pnpm/exe.linux-riscv64@12.8.1':
resolution: {integrity: sha512-HIbImydoC3J8NFt+8MXfhTCf5rO6NjCMyinSAHac0VmV8uCHw+kbQkyAzxV84rzz9ZOzmBOnj0b1N461UIYGsw==} resolution: {integrity: sha512-z1ecpIK/ZY08Unk69KWWE9867oaKUytGUjrHnBoGFAAhsK+q+0cfvBH+f5fWobJ7FX97leMlLO+gkJolddM45Q==}
cpu: [riscv64] cpu: [riscv64]
os: [linux] os: [linux]
libc: [glibc] libc: [glibc]
'@pnpm/exe.linux-s390x@12.6.0': '@pnpm/exe.linux-s390x@12.8.1':
resolution: {integrity: sha512-DjSqT7+BZ/lWcDHwNMuzsRVfyxUimh+D54Xw4tSWbdVVQhtWtNMUyI93LVnwCmsoEpar2gC3SFeAgywx37svKQ==} resolution: {integrity: sha512-KU6tnrBfu4uKXTq6N5qJwSm8FSrs9Wc8b5AUEsHK9bRXwNdsZ1/lRxG1++X29SKRW9OSNuDSjxASv5mAvGo1gA==}
cpu: [s390x] cpu: [s390x]
os: [linux] os: [linux]
libc: [glibc] libc: [glibc]
'@pnpm/exe.linux-x64-musl@12.6.0': '@pnpm/exe.linux-x64-musl@12.8.1':
resolution: {integrity: sha512-31lKeGPmRE6xfV6I3VjaEGVFRei14pl/zgoFDK4w+UkbJqOuNl2Ht3O1GuqNIg3Gl14qTEb4kZRAYFHXifDx9A==} resolution: {integrity: sha512-eUE8BWJkDr2tJb/yrk0yVnszlmNqFarVxUlqiZ9BAkct28Nq/5g2H0tvMDmPA7fAQW3STNj+omJPPRVT+4s5sQ==}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
libc: [musl] libc: [musl]
'@pnpm/exe.linux-x64@12.6.0': '@pnpm/exe.linux-x64@12.8.1':
resolution: {integrity: sha512-qFWBneHJAJ73W4whtbaFOL1M/7DBC6ILHXuxc7ZPtEhfPuT1zeZiGrmKHoMAfJA+mcm6xhOFljqVTUS+00Jabw==} resolution: {integrity: sha512-8bDZ0lZlCdi2rvnFul7EYgcC7zKeWSe76y8JV2oXobaS8p9i9d6PSf6LgLtTM0fI7R9Oh4eLCbveXyNDMmvZ+g==}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
libc: [glibc] libc: [glibc]
'@pnpm/exe.win32-arm64@12.6.0': '@pnpm/exe.win32-arm64@12.8.1':
resolution: {integrity: sha512-OhfefXEEykZlslSUhR8PPRe6MVPV3Oink/dVfIecE5velpc7j80cZYsHlaDrtRDcm3TPwQHkaRW1SJ1efX9oFg==} resolution: {integrity: sha512-MsT0dlrRxnCRCHCaosNbhWpEiAFnFuMEu3KuDJDU41BXgTwiINxU8goloUSUDejWZUqKaUqNC/qUTihl9nFtqg==}
cpu: [arm64] cpu: [arm64]
os: [win32] os: [win32]
'@pnpm/exe.win32-x64@12.6.0': '@pnpm/exe.win32-x64@12.8.1':
resolution: {integrity: sha512-L2tuyrD2+Imgxs3VK/ST/2L3xD6vDP0ktJQxM0TaGw7TbAQEMq+RMc8iK6Ew7Id579uzjJe8jSfJID2ZGsOHCA==} resolution: {integrity: sha512-SWtPe0PsbTTk//gJND10tMdOfCYjrkq5+qV49hzVhY7xz2iJ339Rc+xwASlcvbwTfrvH39YNqpKYibD+CRGLwA==}
cpu: [x64] cpu: [x64]
os: [win32] os: [win32]
pnpm@12.6.0: pnpm@12.8.1:
resolution: {integrity: sha512-PvaPlRyxEawgS0paFvCy3fDaVqluBBPoHYVdnwtV75JnFHCQKOHNAMQFwsX7e56OxNxGd3yAXQNzwvL/AP0g7A==} resolution: {integrity: sha512-9kupB1B/XOr+BsjTjmBS0BeURFgOwSed3Vv8EctIqoomRLZlmOB+dh2oSHKp/FfV+QK4f6SdAkGY1VhhKqu+RQ==}
engines: {node: '>=18.*'} engines: {node: '>=18.*'}
hasBin: true hasBin: true
snapshots: snapshots:
'@pnpm/exe.android-arm64@12.6.0': '@pnpm/exe.android-arm64@12.8.1':
optional: true optional: true
'@pnpm/exe.android-x64@12.6.0': '@pnpm/exe.android-x64@12.8.1':
optional: true optional: true
'@pnpm/exe.darwin-arm64@12.6.0': '@pnpm/exe.darwin-arm64@12.8.1':
optional: true optional: true
'@pnpm/exe.darwin-x64@12.6.0': '@pnpm/exe.darwin-x64@12.8.1':
optional: true optional: true
'@pnpm/exe.freebsd-x64@12.6.0': '@pnpm/exe.freebsd-x64@12.8.1':
optional: true optional: true
'@pnpm/exe.linux-arm64-musl@12.6.0': '@pnpm/exe.linux-arm64-musl@12.8.1':
optional: true optional: true
'@pnpm/exe.linux-arm64@12.6.0': '@pnpm/exe.linux-arm64@12.8.1':
optional: true optional: true
'@pnpm/exe.linux-ppc64@12.6.0': '@pnpm/exe.linux-ppc64@12.8.1':
optional: true optional: true
'@pnpm/exe.linux-riscv64@12.6.0': '@pnpm/exe.linux-riscv64@12.8.1':
optional: true optional: true
'@pnpm/exe.linux-s390x@12.6.0': '@pnpm/exe.linux-s390x@12.8.1':
optional: true optional: true
'@pnpm/exe.linux-x64-musl@12.6.0': '@pnpm/exe.linux-x64-musl@12.8.1':
optional: true optional: true
'@pnpm/exe.linux-x64@12.6.0': '@pnpm/exe.linux-x64@12.8.1':
optional: true optional: true
'@pnpm/exe.win32-arm64@12.6.0': '@pnpm/exe.win32-arm64@12.8.1':
optional: true optional: true
'@pnpm/exe.win32-x64@12.6.0': '@pnpm/exe.win32-x64@12.8.1':
optional: true optional: true
pnpm@12.6.0: pnpm@12.8.1:
optionalDependencies: optionalDependencies:
'@pnpm/exe.android-arm64': 12.6.0 '@pnpm/exe.android-arm64': 12.8.1
'@pnpm/exe.android-x64': 12.6.0 '@pnpm/exe.android-x64': 12.8.1
'@pnpm/exe.darwin-arm64': 12.6.0 '@pnpm/exe.darwin-arm64': 12.8.1
'@pnpm/exe.darwin-x64': 12.6.0 '@pnpm/exe.darwin-x64': 12.8.1
'@pnpm/exe.freebsd-x64': 12.6.0 '@pnpm/exe.freebsd-x64': 12.8.1
'@pnpm/exe.linux-arm64': 12.6.0 '@pnpm/exe.linux-arm64': 12.8.1
'@pnpm/exe.linux-arm64-musl': 12.6.0 '@pnpm/exe.linux-arm64-musl': 12.8.1
'@pnpm/exe.linux-ppc64': 12.6.0 '@pnpm/exe.linux-ppc64': 12.8.1
'@pnpm/exe.linux-riscv64': 12.6.0 '@pnpm/exe.linux-riscv64': 12.8.1
'@pnpm/exe.linux-s390x': 12.6.0 '@pnpm/exe.linux-s390x': 12.8.1
'@pnpm/exe.linux-x64': 12.6.0 '@pnpm/exe.linux-x64': 12.8.1
'@pnpm/exe.linux-x64-musl': 12.6.0 '@pnpm/exe.linux-x64-musl': 12.8.1
'@pnpm/exe.win32-arm64': 12.6.0 '@pnpm/exe.win32-arm64': 12.8.1
'@pnpm/exe.win32-x64': 12.6.0 '@pnpm/exe.win32-x64': 12.8.1
--- ---
lockfileVersion: '9.0' lockfileVersion: '9.0'

View file

@ -20,6 +20,8 @@
import "~plugins"; import "~plugins";
import "./fixWeirdAppRegionBug.css"; import "./fixWeirdAppRegionBug.css";
import nativeTitleBarStyles from "./nativeTitleBar.css?managed";
export * as Api from "./api"; export * as Api from "./api";
export * as Plugins from "./api/PluginManager"; export * as Plugins from "./api/PluginManager";
export * as Components from "./components"; export * as Components from "./components";
@ -29,22 +31,20 @@ export * as Webpack from "./webpack";
export * as WebpackPatcher from "./webpack/patchWebpack"; export * as WebpackPatcher from "./webpack/patchWebpack";
export { PlainSettings, Settings }; export { PlainSettings, Settings };
import { coreStyleRootNode, initStyles } from "@api/Styles"; import { enableStyle, initStyles } from "@api/Styles";
import { openSettingsTabModal, UpdaterTab } from "@components/settings"; import { openSettingsTabModal, UpdaterTab } from "@components/settings";
import { debounce } from "@shared/debounce"; import { debounce } from "@shared/debounce";
import { IS_WINDOWS } from "@utils/constants";
import { createAndAppendStyle } from "@utils/css";
import { StartAt } from "@utils/types"; import { StartAt } from "@utils/types";
import { SettingsRouter } from "@webpack/common"; import { SettingsRouter } from "@webpack/common";
import { get as dsGet } from "./api/DataStore"; import { get as dsGet } from "./api/DataStore";
import { popNotice, showNotice } from "./api/Notices"; import { showNotice } from "./api/Notices";
import { NotificationData, showNotification } from "./api/Notifications"; import { NotificationData, showNotification } from "./api/Notifications";
import { initPluginManager, PMLogger, startAllPlugins } from "./api/PluginManager"; import { initPluginManager, PMLogger, startAllPlugins } from "./api/PluginManager";
import { PlainSettings, Settings, SettingsStore } from "./api/Settings"; import { PlainSettings, Settings, SettingsStore } from "./api/Settings";
import { areLocalSettingsDirty, getCloudSettings, getCloudSyncDirection, markLocalSettingsDirty, putCloudSettings, shouldCloudSync } from "./api/SettingsSync/cloudSync"; import { areLocalSettingsDirty, getCloudSettings, getCloudSyncDirection, markLocalSettingsDirty, putCloudSettings, shouldCloudSync } from "./api/SettingsSync/cloudSync";
import { relaunch } from "./utils/native"; import { relaunch } from "./utils/native";
import { checkForUpdates, isOutdated as getIsOutdated, update, UpdateLogger } from "./utils/updater"; import { checkForUpdates, update, UpdateLogger } from "./utils/updater";
import { onceReady } from "./webpack"; import { onceReady } from "./webpack";
import { patches } from "./webpack/patchWebpack"; import { patches } from "./webpack/patchWebpack";
@ -137,7 +137,6 @@ async function runUpdateCheck() {
try { try {
const isOutdated = await checkForUpdates(); const isOutdated = await checkForUpdates();
if (IS_DISCORD_DESKTOP) VencordNative.tray.setUpdateState(isOutdated);
if (!isOutdated) return; if (!isOutdated) return;
if (Settings.autoUpdate) { if (Settings.autoUpdate) {
@ -168,43 +167,11 @@ async function runUpdateCheck() {
} }
} }
function initTrayIpc() {
if (IS_WEB || IS_UPDATER_DISABLED) return;
VencordNative.tray.onCheckUpdates(async () => {
try {
const isOutdated = await checkForUpdates();
VencordNative.tray.setUpdateState(isOutdated);
if (isOutdated) {
showNotice("An Equicord update is available!", "View Update", () => openSettingsTabModal(UpdaterTab!));
} else {
showNotice("No updates available, you're on the latest version!", "OK", popNotice);
}
} catch (err) {
UpdateLogger.error("Failed to check for updates from tray", err);
showNotice("Failed to check for updates, check the console for more info", "OK", popNotice);
}
});
VencordNative.tray.onRepair(async () => {
try {
await update();
relaunch();
} catch (err) {
UpdateLogger.error("Failed to repair Equicord", err);
}
});
VencordNative.tray.setUpdateState(getIsOutdated);
}
async function init() { async function init() {
await onceReady; await onceReady;
startAllPlugins(StartAt.WebpackReady); startAllPlugins(StartAt.WebpackReady);
syncSettings(); syncSettings();
initTrayIpc();
if (!IS_DEV && !IS_WEB && !IS_UPDATER_DISABLED) { if (!IS_DEV && !IS_WEB && !IS_UPDATER_DISABLED) {
runUpdateCheck(); runUpdateCheck();
@ -237,8 +204,7 @@ init();
document.addEventListener("DOMContentLoaded", () => { document.addEventListener("DOMContentLoaded", () => {
startAllPlugins(StartAt.DOMContentLoaded); startAllPlugins(StartAt.DOMContentLoaded);
// FIXME if (IS_DISCORD_DESKTOP && Settings.nativeTitleBar) {
if (IS_DISCORD_DESKTOP && Settings.winNativeTitleBar && IS_WINDOWS) { enableStyle(nativeTitleBarStyles);
createAndAppendStyle("vencord-native-titlebar-style", coreStyleRootNode).textContent = "[class*=titleBar]{display: none!important}";
} }
}, { once: true }); }, { once: true });

View file

@ -8,6 +8,7 @@ import type { Settings } from "@api/Settings";
import type { CspRequestResult } from "@main/csp/manager"; import type { CspRequestResult } from "@main/csp/manager";
import type { PluginIpcMappings } from "@main/ipcPlugins"; import type { PluginIpcMappings } from "@main/ipcPlugins";
import { UserThemeHeader } from "@main/themes"; import { UserThemeHeader } from "@main/themes";
import { UpdateData } from "@main/updater";
import { IpcEvents } from "@shared/IpcEvents"; import { IpcEvents } from "@shared/IpcEvents";
import type { IpcRes } from "@utils/types"; import type { IpcRes } from "@utils/types";
import { ipcRenderer } from "electron/renderer"; import { ipcRenderer } from "electron/renderer";
@ -46,10 +47,10 @@ export default {
}, },
updater: { updater: {
getUpdates: () => invoke<IpcRes<Record<"hash" | "author" | "message", string>[]>>(IpcEvents.GET_UPDATES), getRepo: () => invoke<IpcRes<string>>(IpcEvents.UPDATER_GET_REPO),
update: () => invoke<IpcRes<boolean>>(IpcEvents.UPDATE), getUpdates: () => invoke<IpcRes<UpdateData[]>>(IpcEvents.UPDATER_LIST_UPDATES),
rebuild: () => invoke<IpcRes<boolean>>(IpcEvents.BUILD), fetchUpdate: () => invoke<IpcRes<boolean>>(IpcEvents.UPDATER_FETCH_UPDATE),
getRepo: () => invoke<IpcRes<string>>(IpcEvents.GET_REPO), applyUpdate: () => invoke<IpcRes<boolean>>(IpcEvents.UPDATER_APPLY_UPDATE),
}, },
settings: { settings: {
@ -101,11 +102,5 @@ export default {
invoke<CspRequestResult>(IpcEvents.CSP_REQUEST_ADD_OVERRIDE, url, directives, callerName), invoke<CspRequestResult>(IpcEvents.CSP_REQUEST_ADD_OVERRIDE, url, directives, callerName),
}, },
tray: {
setUpdateState: (available: boolean) => ipcRenderer.send(IpcEvents.SET_TRAY_UPDATE_STATE, available),
onCheckUpdates: (cb: () => void) => { ipcRenderer.on(IpcEvents.TRAY_CHECK_UPDATES, cb); },
onRepair: (cb: () => void) => { ipcRenderer.on(IpcEvents.TRAY_REPAIR, cb); },
},
pluginHelpers: PluginHelpers pluginHelpers: PluginHelpers
}; };

View file

@ -72,7 +72,7 @@ export interface Settings {
| undefined; | undefined;
windowsMaterial: "none" | "mica" | "tabbed" | "acrylic"; windowsMaterial: "none" | "mica" | "tabbed" | "acrylic";
disableMinSize: boolean; disableMinSize: boolean;
winNativeTitleBar: boolean; nativeTitleBar: boolean;
plugins: { plugins: {
[plugin: string]: { [plugin: string]: {
enabled: boolean; enabled: boolean;
@ -124,7 +124,7 @@ const DefaultSettings: Settings = {
macosVibrancyStyle: undefined, macosVibrancyStyle: undefined,
windowsMaterial: "none", windowsMaterial: "none",
disableMinSize: false, disableMinSize: false,
winNativeTitleBar: false, nativeTitleBar: false,
plugins: {}, plugins: {},
uiElements: { uiElements: {

View file

@ -7,24 +7,17 @@
import { PlainSettings } from "@api/Settings"; import { PlainSettings } from "@api/Settings";
import { Logger } from "@utils/Logger"; import { Logger } from "@utils/Logger";
import { chooseFile, saveFile } from "@utils/web"; import { chooseFile, saveFile } from "@utils/web";
import { moment, Toasts } from "@webpack/common"; import { moment, showToast } from "@webpack/common";
import { DataStore } from ".."; import { DataStore } from "..";
type BackupType = "all" | "plugins" | "css" | "datastore"; type BackupType = "all" | "plugins" | "css" | "datastore";
const toast = (type: string, message: string) =>
Toasts.show({
type,
message,
id: Toasts.genId()
});
const toastSuccess = () => 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) => 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"); const logger = new Logger("SettingsSync:Offline", "#39b7e0");
@ -118,7 +111,7 @@ export async function exportSettings({ syncDataStore = true, type = "all", minif
if (type === "all") { if (type === "all") {
logger.warn("Skipping DataStore in backup due to size. Export DataStore separately if needed."); 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; dataStore = undefined;
} else if (type === "datastore") { } else if (type === "datastore") {
throw new Error("DataStore is too large to export. Please clear some plugin data and try again."); 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) { } catch (err) {
logger.error("Failed to export settings:", 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; throw err;
} }
} }

View file

@ -19,7 +19,8 @@ import { HashLink } from "@components/settings/tabs/updater/Components";
import { Margins } from "@utils/margins"; import { Margins } from "@utils/margins";
import { useAwaiter } from "@utils/react"; import { useAwaiter } from "@utils/react";
import { getRepo, UpdateLogger } from "@utils/updater"; import { getRepo, UpdateLogger } from "@utils/updater";
import { Alerts, React, Toasts } from "@webpack/common"; import { ToastPosition } from "@vencord/discord-types/enums";
import { Alerts, React, showToast } from "@webpack/common";
import gitHash from "~git-hash"; import gitHash from "~git-hash";
@ -352,13 +353,8 @@ function ChangelogContent() {
const logged = await ensureLocalUpdateLogged(); const logged = await ensureLocalUpdateLogged();
if (!logged) { if (!logged) {
setChangelog([]); setChangelog([]);
Toasts.show({ showToast("Already up to date with repository", "message", {
message: "Already up to date with repository", position: ToastPosition.BOTTOM,
id: Toasts.genId(),
type: Toasts.Type.MESSAGE,
options: {
position: Toasts.Position.BOTTOM,
},
}); });
} }
return; return;
@ -384,26 +380,16 @@ function ChangelogContent() {
await loadChangelogHistory(); await loadChangelogHistory();
setRecentlyChecked(true); setRecentlyChecked(true);
Toasts.show({ showToast(`Found ${updates.value.length} commit${updates.value.length === 1 ? "" : "s"} from repository`, "success", {
message: `Found ${updates.value.length} commit${updates.value.length === 1 ? "" : "s"} from repository`, position: ToastPosition.BOTTOM,
id: Toasts.genId(),
type: Toasts.Type.SUCCESS,
options: {
position: Toasts.Position.BOTTOM,
},
}); });
} else { } else {
const logged = await ensureLocalUpdateLogged(); const logged = await ensureLocalUpdateLogged();
setRecentlyChecked(true); setRecentlyChecked(true);
Toasts.show({ showToast(logged
message: logged ? "Logged commits from your latest update"
? "Logged commits from your latest update" : "Repository is up to date with your local copy", logged ? "success" : "message", {
: "Repository is up to date with your local copy", position: ToastPosition.BOTTOM,
id: Toasts.genId(),
type: logged ? Toasts.Type.SUCCESS : Toasts.Type.MESSAGE,
options: {
position: Toasts.Position.BOTTOM,
},
}); });
if (!logged) { if (!logged) {
setChangelog([]); setChangelog([]);
@ -422,13 +408,8 @@ function ChangelogContent() {
setError(errorMessage); setError(errorMessage);
// funny little error toast hopefully doesn't happen! // funny little error toast hopefully doesn't happen!
Toasts.show({ showToast("Could not fetch commits from repository", "failure", {
message: "Could not fetch commits from repository", position: ToastPosition.BOTTOM,
id: Toasts.genId(),
type: Toasts.Type.FAILURE,
options: {
position: Toasts.Position.BOTTOM,
},
}); });
} finally { } finally {
setIsLoading(false); setIsLoading(false);
@ -520,13 +501,8 @@ function ChangelogContent() {
await clearChangelogHistory(); await clearChangelogHistory();
await loadChangelogHistory(); await loadChangelogHistory();
setShowHistory(false); setShowHistory(false);
Toasts.show({ showToast("All logs have been cleared", "success", {
message: "All logs have been cleared", position: ToastPosition.BOTTOM,
id: Toasts.genId(),
type: Toasts.Type.SUCCESS,
options: {
position: Toasts.Position.BOTTOM,
},
}); });
}, },
}); });
@ -659,13 +635,8 @@ function ChangelogContent() {
Array.from(expandedLogs).filter(id => id !== logId), Array.from(expandedLogs).filter(id => id !== logId),
), ),
); );
Toasts.show({ showToast("Log has been cleared", "success", {
message: "Log has been cleared", position: ToastPosition.BOTTOM,
id: Toasts.genId(),
type: Toasts.Type.SUCCESS,
options: {
position: Toasts.Position.BOTTOM,
},
}); });
}, },
}); });

View file

@ -12,7 +12,8 @@ import { AddonCard } from "@components/settings/AddonCard";
import { classNameFactory } from "@utils/css"; import { classNameFactory } from "@utils/css";
import { Logger } from "@utils/Logger"; import { Logger } from "@utils/Logger";
import { Plugin } from "@utils/types"; 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"; import { PluginMeta } from "~plugins";
@ -79,9 +80,7 @@ export function PluginCard({ plugin, disabled, onRestartNeeded, onMouseEnter, on
settings.enabled = false; settings.enabled = false;
const msg = `Error while ${wasEnabled ? "stopping" : "starting"} plugin ${plugin.name}`; const msg = `Error while ${wasEnabled ? "stopping" : "starting"} plugin ${plugin.name}`;
showToast(msg, Toasts.Type.FAILURE, { showToast(msg, "failure", { position: ToastPosition.BOTTOM });
position: Toasts.Position.BOTTOM,
});
return; return;
} }

View file

@ -34,8 +34,9 @@ import { Margins } from "@utils/margins";
import { classes, isObjectEmpty } from "@utils/misc"; import { classes, isObjectEmpty } from "@utils/misc";
import { OptionType, Plugin, PluginTag } from "@utils/types"; import { OptionType, Plugin, PluginTag } from "@utils/types";
import { RenderModalProps, User } from "@vencord/discord-types"; import { RenderModalProps, User } from "@vencord/discord-types";
import { ToastPosition } from "@vencord/discord-types/enums";
import { findComponentByCodeLazy, findCssClassesLazy } from "@webpack"; import { findComponentByCodeLazy, findCssClassesLazy } from "@webpack";
import { Clickable, FluxDispatcher, Modal, openModal, React, Text, Toasts, Tooltip, useEffect, useMemo, UserStore, UserSummaryItem, UserUtils, useState } from "@webpack/common"; import { Clickable, FluxDispatcher, Modal, openModal, React, showToast,Text, Tooltip, useEffect, useMemo, UserStore, UserSummaryItem, UserUtils, useState } from "@webpack/common";
import { Constructor } from "type-fest"; import { Constructor } from "type-fest";
import { PluginMeta } from "~plugins"; import { PluginMeta } from "~plugins";
@ -324,14 +325,9 @@ function resetSettings(plugin: Plugin, onRestartNeeded?: (pluginName: string) =>
onRestartNeeded?.(plugin.name); onRestartNeeded?.(plugin.name);
} }
Toasts.show({ showToast(`Settings for ${pluginName} have been reset.`, "success", {
message: `Settings for ${pluginName} have been reset.`, position: ToastPosition.TOP
id: Toasts.genId(), });
type: Toasts.Type.SUCCESS,
options: {
position: Toasts.Position.TOP
}
});
} }
export function openWarningModal(plugin?: Plugin | null, onRestartNeeded?: (pluginName: string) => void, isPlugin = true, enabledPlugins?: number | null, reset?: () => void) { export function openWarningModal(plugin?: Plugin | null, onRestartNeeded?: (pluginName: string) => void, isPlugin = true, enabledPlugins?: number | null, reset?: () => void) {

View file

@ -38,7 +38,8 @@ import { classes } from "@utils/misc";
import { PluginTarget } from "@utils/pluginTargets"; import { PluginTarget } from "@utils/pluginTargets";
import { useAwaiter, useCleanupEffect, useIntersection } from "@utils/react"; import { useAwaiter, useCleanupEffect, useIntersection } from "@utils/react";
import { PluginTag, PluginTags } from "@utils/types"; import { PluginTag, PluginTags } from "@utils/types";
import { Alerts, ConfirmModal, lodash, openModal, Parser, React, SearchableSelect, Select, TextInput, Toasts, Tooltip, useCallback, useMemo, useRef, useState } from "@webpack/common"; import { ToastPosition } from "@vencord/discord-types/enums";
import { Alerts, ConfirmModal, lodash, openModal, Parser, React, SearchableSelect, Select, showToast,TextInput, Tooltip, useCallback, useMemo, useRef, useState } from "@webpack/common";
import { JSX } from "react"; import { JSX } from "react";
import Plugins, { ExcludedPlugins, PluginMeta } from "~plugins"; import Plugins, { ExcludedPlugins, PluginMeta } from "~plugins";
@ -52,14 +53,9 @@ export const cl = classNameFactory("vc-plugins-");
export const logger = new Logger("PluginSettings", "#a6d189"); export const logger = new Logger("PluginSettings", "#a6d189");
function showErrorToast(message: string) { function showErrorToast(message: string) {
Toasts.show({ showToast(message, "failure", {
message, position: ToastPosition.BOTTOM
type: Toasts.Type.FAILURE, });
id: Toasts.genId(),
options: {
position: Toasts.Position.BOTTOM
}
});
} }
function ReloadRequiredCard({ required, enabledPlugins, openWarningModal, resetCheckAndDo }) { function ReloadRequiredCard({ required, enabledPlugins, openWarningModal, resetCheckAndDo }) {

View file

@ -18,7 +18,7 @@ import { copyWithToast } from "@utils/discord";
import { Margins } from "@utils/margins"; import { Margins } from "@utils/margins";
import { classes } from "@utils/misc"; import { classes } from "@utils/misc";
import { getStylusWebStoreUrl } from "@utils/web"; import { getStylusWebStoreUrl } from "@utils/web";
import { React, Select, showToast, TextInput, Toasts, useEffect, useMemo, useRef, useState } from "@webpack/common"; import { React, Select, showToast, TextInput, useEffect, useMemo, useRef, useState } from "@webpack/common";
import { SyntheticEvent } from "react"; import { SyntheticEvent } from "react";
import { OnlineThemesSection } from "./OnlineThemes"; import { OnlineThemesSection } from "./OnlineThemes";
@ -263,9 +263,9 @@ function ThemesTab() {
setOnlineThemes(prev => setOnlineThemes(prev =>
prev?.map(t => t.link === link ? updatedTheme : t) ?? null prev?.map(t => t.link === link ? updatedTheme : t) ?? null
); );
showToast("Theme refreshed!", Toasts.Type.SUCCESS); showToast("Theme refreshed!", "success");
} catch { } catch {
showToast("Failed to refresh theme", Toasts.Type.FAILURE); showToast("Failed to refresh theme", "failure");
} }
} }
@ -288,7 +288,7 @@ function ThemesTab() {
URL.revokeObjectURL(url); URL.revokeObjectURL(url);
} }
} catch { } catch {
showToast("Failed to download theme", Toasts.Type.FAILURE); showToast("Failed to download theme", "failure");
} }
} }

View file

@ -14,7 +14,8 @@ import { Span } from "@components/Span";
import { Margins } from "@utils/margins"; import { Margins } from "@utils/margins";
import { relaunch } from "@utils/native"; import { relaunch } from "@utils/native";
import { changes, checkForUpdates, update, updateError } from "@utils/updater"; 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, useState } from "@webpack/common";
import { runWithDispatch } from "./runWithDispatch"; import { runWithDispatch } from "./runWithDispatch";
@ -90,13 +91,8 @@ export function Updatable(props: CommonProps) {
} else { } else {
setUpdates([]); setUpdates([]);
Toasts.show({ showToast("No updates found!", "message", {
message: "No updates found!", position: ToastPosition.BOTTOM
id: Toasts.genId(),
type: Toasts.Type.MESSAGE,
options: {
position: Toasts.Position.BOTTOM
}
}); });
} }
})} })}

View file

@ -49,7 +49,7 @@ type KeysOfType<Object, Type> = {
}[keyof Object]; }[keyof Object];
function Switches() { 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 = [ const Switches = [
{ {
@ -71,7 +71,7 @@ function Switches() {
restartRequired: true, restartRequired: true,
} }
: { : {
key: "winNativeTitleBar", key: "nativeTitleBar",
title: "Use Windows' native title bar instead of Discord's custom one", 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.", description: "Replace Discord's custom title bar with the standard Windows title bar. This may improve compatibility with some window management tools.",
restartRequired: true, restartRequired: true,

View file

@ -10,9 +10,11 @@ import { definePluginSettings } from "@api/Settings";
import { EquicordDevs } from "@utils/constants"; import { EquicordDevs } from "@utils/constants";
import { classNameFactory } from "@utils/css"; import { classNameFactory } from "@utils/css";
import definePlugin, { OptionType } from "@utils/types"; import definePlugin, { OptionType } from "@utils/types";
import { ColorUtils, React, showToast, Toasts } from "@webpack/common"; import { ColorUtils, React, showToast } from "@webpack/common";
const cl = classNameFactory("vc-better-audio-player-"); const cl = classNameFactory("vc-better-audio-player-");
const CORS_PROXY = "https://cors.keiran0.workers.dev?url=";
const MAX_FILE_SIZE = 12e6;
interface PlayerInstance { interface PlayerInstance {
mediaRef: React.RefObject<HTMLAudioElement | null>; mediaRef: React.RefObject<HTMLAudioElement | null>;
@ -20,6 +22,12 @@ interface PlayerInstance {
state: { playing: boolean; }; state: { playing: boolean; };
} }
interface AudioGraph {
ctx: AudioContext;
analyser: AnalyserNode;
blobUrl: string;
}
function validateColor(value: string, key: string, fallback: string) { function validateColor(value: string, key: string, fallback: string) {
if (/^\d{1,3}\s*,\s*\d{1,3}\s*,\s*\d{1,3}$/.test(value)) return; if (/^\d{1,3}\s*,\s*\d{1,3}\s*,\s*\d{1,3}$/.test(value)) return;
@ -31,7 +39,7 @@ function validateColor(value: string, key: string, fallback: string) {
} }
} catch { /* invalid hex */ } } catch { /* invalid hex */ }
showToast(`Invalid color format for ${key}, use "R, G, B" or "#RRGGBB"`, Toasts.Type.FAILURE); showToast(`Invalid color format for ${key}, use "R, G, B" or "#RRGGBB"`, "failure");
settings.store[key] = fallback; settings.store[key] = fallback;
} }
@ -98,62 +106,101 @@ function drawSpectrograph(ctx: CanvasRenderingContext2D, w: number, h: number, f
} }
} }
async function fetchAudioBlob(src: string): Promise<string | null> {
const url = new URL(src);
url.searchParams.set("t", Date.now().toString());
const response = await fetch(CORS_PROXY + encodeURIComponent(url.href));
const contentLength = response.headers.get("content-length");
if (contentLength && Number(contentLength) > MAX_FILE_SIZE) return null;
const blob = await response.blob();
return URL.createObjectURL(blob);
}
async function createAudioGraph(audio: HTMLAudioElement): Promise<AudioGraph | null> {
const blobUrl = await fetchAudioBlob(audio.currentSrc || audio.src).catch(() => null);
if (!blobUrl) return null;
const wasPlaying = !audio.paused;
const { currentTime } = audio;
audio.src = blobUrl;
audio.currentTime = currentTime;
if (wasPlaying) audio.play().catch(() => { });
const ctx = new AudioContext();
const analyser = ctx.createAnalyser();
analyser.fftSize = 2048;
ctx.createMediaElementSource(audio).connect(analyser);
analyser.connect(ctx.destination);
return { ctx, analyser, blobUrl };
}
function Visualizer({ mediaRef, playing }: { mediaRef: PlayerInstance["mediaRef"]; playing: boolean; }) { function Visualizer({ mediaRef, playing }: { mediaRef: PlayerInstance["mediaRef"]; playing: boolean; }) {
const canvasRef = React.useRef<HTMLCanvasElement>(null); const canvasRef = React.useRef<HTMLCanvasElement>(null);
const graphRef = React.useRef<{ ctx: AudioContext; analyser: AnalyserNode; } | null>(null); const graphRef = React.useRef<Promise<AudioGraph | null> | null>(null);
React.useEffect(() => { React.useEffect(() => {
const audio = mediaRef.current; const audio = mediaRef.current;
const canvasCtx = canvasRef.current?.getContext("2d"); const canvasCtx = canvasRef.current?.getContext("2d");
if (!playing || !audio || !canvasCtx) return; if (!playing || !audio || !canvasCtx) return;
if (!graphRef.current) { graphRef.current ??= createAudioGraph(audio);
const ctx = new AudioContext();
const analyser = ctx.createAnalyser();
analyser.fftSize = 2048;
ctx.createMediaElementSource(audio).connect(analyser);
analyser.connect(ctx.destination);
graphRef.current = { ctx, analyser };
}
const { ctx, analyser } = graphRef.current;
ctx.resume();
const dataArray = new Uint8Array(analyser.frequencyBinCount);
const frequencyData = new Uint8Array(analyser.frequencyBinCount);
let frame = 0; let frame = 0;
let stopped = false;
let graphCtx: AudioContext | null = null;
const draw = () => { graphRef.current.then(graph => {
frame = requestAnimationFrame(draw); if (stopped || !graph) return;
analyser.getByteTimeDomainData(dataArray); const { ctx, analyser } = graph;
analyser.getByteFrequencyData(frequencyData); graphCtx = ctx;
ctx.resume();
const { canvas } = canvasCtx; const dataArray = new Uint8Array(analyser.frequencyBinCount);
const width = canvas.clientWidth; const frequencyData = new Uint8Array(analyser.frequencyBinCount);
const height = canvas.clientHeight;
const dpr = window.devicePixelRatio;
const pixelWidth = Math.round(width * dpr);
const pixelHeight = Math.round(height * dpr);
if (canvas.width !== pixelWidth || canvas.height !== pixelHeight) {
canvas.width = pixelWidth;
canvas.height = pixelHeight;
canvasCtx.setTransform(dpr, 0, 0, dpr, 0, 0);
}
canvasCtx.clearRect(0, 0, width, height); const draw = () => {
if (settings.store.oscilloscope) drawOscilloscope(canvasCtx, width, height, dataArray, dataArray.length); frame = requestAnimationFrame(draw);
if (settings.store.spectrograph) drawSpectrograph(canvasCtx, width, height, frequencyData, frequencyData.length);
}; analyser.getByteTimeDomainData(dataArray);
draw(); analyser.getByteFrequencyData(frequencyData);
const { canvas } = canvasCtx;
const width = canvas.clientWidth;
const height = canvas.clientHeight;
const dpr = window.devicePixelRatio;
const pixelWidth = Math.round(width * dpr);
const pixelHeight = Math.round(height * dpr);
if (canvas.width !== pixelWidth || canvas.height !== pixelHeight) {
canvas.width = pixelWidth;
canvas.height = pixelHeight;
canvasCtx.setTransform(dpr, 0, 0, dpr, 0, 0);
}
canvasCtx.clearRect(0, 0, width, height);
if (settings.store.oscilloscope) drawOscilloscope(canvasCtx, width, height, dataArray, dataArray.length);
if (settings.store.spectrograph) drawSpectrograph(canvasCtx, width, height, frequencyData, frequencyData.length);
};
draw();
});
return () => { return () => {
stopped = true;
cancelAnimationFrame(frame); cancelAnimationFrame(frame);
ctx.suspend(); graphCtx?.suspend();
}; };
}, [playing]); }, [playing]);
React.useEffect(() => () => void graphRef.current?.ctx.close(), []); React.useEffect(() => () => {
graphRef.current?.then(graph => {
if (!graph) return;
graph.ctx.close();
URL.revokeObjectURL(graph.blobUrl);
});
}, []);
return ( return (
<canvas <canvas
@ -209,10 +256,6 @@ export default definePlugin({
{ {
find: "}renderPlayIcon(){", find: "}renderPlayIcon(){",
replacement: [ replacement: [
{
match: /"audio",\{(?=className:)/,
replace: '$&crossOrigin:"anonymous",',
},
{ {
match: /this\.renderAudio\(\):this\.renderVideo\(\)/, match: /this\.renderAudio\(\):this\.renderVideo\(\)/,
replace: "$&,$self.renderVisualizer(this)", replace: "$&,$self.renderVisualizer(this)",

View file

@ -13,7 +13,7 @@ import { Logger } from "@utils/Logger";
import { classes, pluralise } from "@utils/misc"; import { classes, pluralise } from "@utils/misc";
import definePlugin, { OptionType } from "@utils/types"; import definePlugin, { OptionType } from "@utils/types";
import { chooseFile, saveFile } from "@utils/web"; import { chooseFile, saveFile } from "@utils/web";
import { Alerts, Button, React, showToast, Toasts, useCallback, useEffect, useRef, useState } from "@webpack/common"; import { Alerts, Button, React, showToast, useCallback, useEffect, useRef, useState } from "@webpack/common";
import { cl, croppedLabel, Shelf } from "./components/Shelf"; import { cl, croppedLabel, Shelf } from "./components/Shelf";
import { add, clear, CropState, currentApplied, Entry, exportAll, forget, forgetCrops, getFile, getThumbs, Group, importAll, Kind, previousApplied, readIndex, recordApplied, saveCrop, toDataUrl, togglePin, touch } from "./library"; import { add, clear, CropState, currentApplied, Entry, exportAll, forget, forgetCrops, getFile, getThumbs, Group, importAll, Kind, previousApplied, readIndex, recordApplied, saveCrop, toDataUrl, togglePin, touch } from "./library";
@ -86,7 +86,7 @@ const settings = definePluginSettings({
onConfirm: () => forgetCrops() onConfirm: () => forgetCrops()
.then(count => showToast( .then(count => showToast(
count ? `Forgot the framing on ${pluralise(count, "picture")}` : "Nothing was framed", count ? `Forgot the framing on ${pluralise(count, "picture")}` : "Nothing was framed",
Toasts.Type.SUCCESS "success"
)) ))
.catch(err => logger.error("could not forget the remembered crops", err)) .catch(err => logger.error("could not forget the remembered crops", err))
})} })}
@ -165,7 +165,7 @@ async function exportLibrary() {
else saveFile(new File([data], FILENAME, { type: "application/json" })); else saveFile(new File([data], FILENAME, { type: "application/json" }));
} catch (err) { } catch (err) {
logger.error("could not export the library", err); logger.error("could not export the library", err);
showToast("Could not export your pictures", Toasts.Type.FAILURE); showToast("Could not export your pictures", "failure");
} }
} }
@ -186,11 +186,11 @@ async function importLibrary() {
const added = await importAll(json, settings.store.librarySize); const added = await importAll(json, settings.store.librarySize);
showToast( showToast(
added ? `Added ${pluralise(added, "picture")}` : "Nothing new in that file", added ? `Added ${pluralise(added, "picture")}` : "Nothing new in that file",
Toasts.Type.SUCCESS "success"
); );
} catch (err) { } catch (err) {
logger.error("could not import the library", err); logger.error("could not import the library", err);
showToast("Could not read that file", Toasts.Type.FAILURE); showToast("Could not read that file", "failure");
} }
} }
@ -324,7 +324,7 @@ function PickerShelf({ kind, open, complete, maxSize }: {
const onPick = useCallback(async (entry: Entry) => { const onPick = useCallback(async (entry: Entry) => {
const blob = await getFile(entry.id); const blob = await getFile(entry.id);
if (!blob) return showToast("That picture is missing", Toasts.Type.FAILURE); if (!blob) return showToast("That picture is missing", "failure");
const file = new File([blob], entry.name, { type: blob.type }); const file = new File([blob], entry.name, { type: blob.type });
await touch(entry.id); await touch(entry.id);
@ -344,7 +344,7 @@ function PickerShelf({ kind, open, complete, maxSize }: {
}, [bump]); }, [bump]);
const accept = useCallback(async (file: File) => { const accept = useCallback(async (file: File) => {
if (maxSize && file.size > maxSize) return showToast("That picture is too big for Discord", Toasts.Type.FAILURE); if (maxSize && file.size > maxSize) return showToast("That picture is too big for Discord", "failure");
try { try {
const entry = await add(file, kind, "original", settings.store.librarySize); const entry = await add(file, kind, "original", settings.store.librarySize);
@ -352,7 +352,7 @@ function PickerShelf({ kind, open, complete, maxSize }: {
await hand(entry.id, file, settings.store.rememberCrop ? entry.crop ?? null : null); await hand(entry.id, file, settings.store.rememberCrop ? entry.crop ?? null : null);
} catch (err) { } catch (err) {
logger.error("could not take that picture", err); logger.error("could not take that picture", err);
showToast("Could not use that picture", Toasts.Type.FAILURE); showToast("Could not use that picture", "failure");
} }
}, [kind, hand, bump, maxSize]); }, [kind, hand, bump, maxSize]);
@ -432,7 +432,7 @@ function EditorShelf({ Original, ownProps }: { Original: React.ComponentType<Edi
await show(entry.id, file, settings.store.rememberCrop ? entry.crop ?? null : null); await show(entry.id, file, settings.store.rememberCrop ? entry.crop ?? null : null);
} catch (err) { } catch (err) {
logger.error("could not take that picture", err); logger.error("could not take that picture", err);
showToast("Could not use that picture", Toasts.Type.FAILURE); showToast("Could not use that picture", "failure");
} }
}, [kind, show, bump, setGroup]); }, [kind, show, bump, setGroup]);
@ -440,7 +440,7 @@ function EditorShelf({ Original, ownProps }: { Original: React.ComponentType<Edi
const onPick = useCallback(async (entry: Entry) => { const onPick = useCallback(async (entry: Entry) => {
const blob = await getFile(entry.id); const blob = await getFile(entry.id);
if (!blob) return showToast("That picture is missing", Toasts.Type.FAILURE); if (!blob) return showToast("That picture is missing", "failure");
await touch(entry.id); await touch(entry.id);
bump(); bump();
@ -464,7 +464,7 @@ function EditorShelf({ Original, ownProps }: { Original: React.ComponentType<Edi
}; };
const run = () => save().catch(err => { const run = () => save().catch(err => {
logger.error("could not keep the cropped copy", err); logger.error("could not keep the cropped copy", err);
showToast("Could not keep the cropped copy", Toasts.Type.FAILURE); showToast("Could not keep the cropped copy", "failure");
}); });
if (!settings.store.askBeforeSavingCropped) return void run(); if (!settings.store.askBeforeSavingCropped) return void run();

View file

@ -8,7 +8,6 @@ import { Flex } from "@components/Flex";
import { Heading } from "@components/Heading"; import { Heading } from "@components/Heading";
import { Paragraph } from "@components/Paragraph"; import { Paragraph } from "@components/Paragraph";
import { BasicChannelTabsProps, ChannelTabsProps, clearStaleNavigationContext, closeTab, createTab, handleChannelSwitch, isNavigationFromSource, isTabSelected, moveToTab, openedTabs, openStartupTabs, saveTabs, settings, setUpdaterFunction, useGhostTabs } from "@equicordplugins/channelTabs/util"; import { BasicChannelTabsProps, ChannelTabsProps, clearStaleNavigationContext, closeTab, createTab, handleChannelSwitch, isNavigationFromSource, isTabSelected, moveToTab, openedTabs, openStartupTabs, saveTabs, settings, setUpdaterFunction, useGhostTabs } from "@equicordplugins/channelTabs/util";
import { IS_MAC } from "@utils/constants";
import { classNameFactory } from "@utils/css"; import { classNameFactory } from "@utils/css";
import { classes } from "@utils/misc"; import { classes } from "@utils/misc";
import { useForceUpdater } from "@utils/react"; import { useForceUpdater } from "@utils/react";
@ -289,7 +288,6 @@ export default function ChannelsTabsContainer(props: BasicChannelTabsProps) {
className={classes( className={classes(
cl("container"), cl("container"),
tabBarPosition === "top" && cl("container-top"), tabBarPosition === "top" && cl("container-top"),
IS_MAC && !IS_WEB && tabBarPosition === "top" && cl("container-top-macos"),
!animationHover && cl("no-hover-animation"), !animationHover && cl("no-hover-animation"),
!animationSelection && cl("no-selection-animation"), !animationSelection && cl("no-selection-animation"),
!animationDragDrop && cl("no-drag-animation"), !animationDragDrop && cl("no-drag-animation"),

View file

@ -76,10 +76,6 @@
z-index: 102; z-index: 102;
} }
.vc-channeltabs-container-top-macos {
padding-left: 80px;
}
/* as its in the same region as notices, it needs to hide itself when a notice is shown /* as its in the same region as notices, it needs to hide itself when a notice is shown
there's no permanent notices, right? */ there's no permanent notices, right? */
[class*="notice"] + .vc-channeltabs-container-top { [class*="notice"] + .vc-channeltabs-container-top {
@ -1349,4 +1345,4 @@
/* disable transitions when compact expand animation is disabled */ /* disable transitions when compact expand animation is disabled */
.vc-channeltabs-no-compact-animation .vc-channeltabs-tab-number-badge { .vc-channeltabs-no-compact-animation .vc-channeltabs-tab-number-badge {
transition: none !important; transition: none !important;
} }

View file

@ -7,7 +7,7 @@
import { DataStore } from "@api/index"; import { DataStore } from "@api/index";
import { isPluginEnabled } from "@api/PluginManager"; import { isPluginEnabled } from "@api/PluginManager";
import { classNameFactory } from "@utils/css"; import { classNameFactory } from "@utils/css";
import { NavigationRouter, SelectedChannelStore, SelectedGuildStore, showToast, Toasts, useEffect, useRef, useState } from "@webpack/common"; import { NavigationRouter, SelectedChannelStore, SelectedGuildStore, showToast, useEffect, useRef, useState } from "@webpack/common";
import { JSX } from "react"; import { JSX } from "react";
import { logger, settings } from "./constants"; import { logger, settings } from "./constants";
@ -418,7 +418,7 @@ export async function openStartupTabs(props: BasicChannelTabsProps & { userId: s
savedTabs = persistedTabs?.[userId]; savedTabs = persistedTabs?.[userId];
} catch (error) { } catch (error) {
logger.error("Failed to load persisted tabs from DataStore", error); logger.error("Failed to load persisted tabs from DataStore", error);
showToast("Failed to load saved tabs", Toasts.Type.FAILURE); showToast("Failed to load saved tabs", "failure");
} }
} }
@ -430,14 +430,14 @@ export async function openStartupTabs(props: BasicChannelTabsProps & { userId: s
if (keepCurrentChannel) { if (keepCurrentChannel) {
hydratedUserId = undefined; hydratedUserId = undefined;
showToast("Not restoring tabs as KeepCurrentChannel is enabled", Toasts.Type.FAILURE); showToast("Not restoring tabs as KeepCurrentChannel is enabled", "failure");
return; return;
} }
switch (settings.store.onStartup) { switch (settings.store.onStartup) {
case "remember": { case "remember": {
if (!savedTabs?.openTabs.length) { if (!savedTabs?.openTabs.length) {
showToast("Failed to restore tabs", Toasts.Type.FAILURE); showToast("Failed to restore tabs", "failure");
break; break;
} }

View file

@ -160,8 +160,8 @@ export default definePlugin({
{ {
find: 'tutorialId:"whos-online"', find: 'tutorialId:"whos-online"',
replacement: { replacement: {
match: /\((function\(\i\)\{let\{id:.*?#{intl::CHANNEL_MEMBERS_A11Y_LABEL}.*?\}\))\}\);/, match: /\((function\(\i\)\{let\{id:.*?#{intl::CHANNEL_MEMBERS_A11Y_LABEL}.*?\}\))\}\)/,
replace: "($self.wrapRoleGroup($1}));", replace: "($self.wrapRoleGroup($1}))",
}, },
}, },
], ],

View file

@ -9,7 +9,7 @@ import { Flex } from "@components/Flex";
import { Heading } from "@components/Heading"; import { Heading } from "@components/Heading";
import { Paragraph } from "@components/Paragraph"; import { Paragraph } from "@components/Paragraph";
import type { RenderModalProps } from "@vencord/discord-types"; import type { RenderModalProps } from "@vencord/discord-types";
import { Checkbox, FluxDispatcher, MessageActions, Modal, openModal, PendingReplyStore, showToast, Toasts, useEffect, useState } from "@webpack/common"; import { Checkbox, FluxDispatcher, MessageActions, Modal, openModal, PendingReplyStore, showToast, useEffect, useState } from "@webpack/common";
import { ApplicationField, BooleanField, DateTimeField, getDateTimeLocalValue, ParticipantField, TextField } from "./fields"; import { ApplicationField, BooleanField, DateTimeField, getDateTimeLocalValue, ParticipantField, TextField } from "./fields";
import { abortActiveClipUploads, type ClipMetadata, getClipCreatedAt, getClipTitleFromName, getDefaultClipTitle, getDefaultFileName, getErrorMessage, getParticipantIds, getString, isValidDate, pickClipFile, uploadClipFile } from "./upload"; import { abortActiveClipUploads, type ClipMetadata, getClipCreatedAt, getClipTitleFromName, getDefaultClipTitle, getDefaultFileName, getErrorMessage, getParticipantIds, getString, isValidDate, pickClipFile, uploadClipFile } from "./upload";
@ -52,7 +52,7 @@ function UploadClipFileModal({ modalProps, channelId, clip }: { modalProps: Rend
result = await pickClipFile(parseMetadata); result = await pickClipFile(parseMetadata);
if (!result) return; if (!result) return;
} catch (error) { } catch (error) {
showToast(getErrorMessage(error), Toasts.Type.FAILURE); showToast(getErrorMessage(error), "failure");
return; return;
} }

View file

@ -8,7 +8,7 @@ import { Logger } from "@utils/Logger";
import { isObject } from "@utils/misc"; import { isObject } from "@utils/misc";
import type { PluginNative } from "@utils/types"; import type { PluginNative } from "@utils/types";
import type { User } from "@vencord/discord-types"; import type { User } from "@vencord/discord-types";
import { Constants, MediaEngineStore, RestAPI, showToast, SnowflakeUtils, Toasts } from "@webpack/common"; import { Constants, MediaEngineStore, RestAPI, showToast, SnowflakeUtils } from "@webpack/common";
import { convertClipToMp4 } from "./ffmpeg"; import { convertClipToMp4 } from "./ffmpeg";
const logger = new Logger("ClipUpload"); const logger = new Logger("ClipUpload");
@ -329,7 +329,7 @@ function shouldRetryWithFFmpeg(error: unknown) {
export async function uploadClipFile(file: File, options: ClipUploadOptions) { export async function uploadClipFile(file: File, options: ClipUploadOptions) {
try { try {
showToast("Checking clip file.", Toasts.Type.MESSAGE); showToast("Checking clip file.", "message");
const uploadFile = await prepareClipFile(file, options.fileName); const uploadFile = await prepareClipFile(file, options.fileName);
@ -338,15 +338,15 @@ export async function uploadClipFile(file: File, options: ClipUploadOptions) {
} catch (error) { } catch (error) {
if (!shouldRetryWithFFmpeg(error)) throw error; if (!shouldRetryWithFFmpeg(error)) throw error;
showToast("Converting clip file.", Toasts.Type.MESSAGE); showToast("Converting clip file.", "message");
await sendClipUpload(await stampVideoFile(await convertClipToMp4(file, options.fileName), options.fileName), options); await sendClipUpload(await stampVideoFile(await convertClipToMp4(file, options.fileName), options.fileName), options);
} }
showToast("Clip uploaded.", Toasts.Type.SUCCESS); showToast("Clip uploaded.", "success");
return true; return true;
} catch (error) { } catch (error) {
logger.error(error); logger.error(error);
showToast(getErrorMessage(error), Toasts.Type.FAILURE); showToast(getErrorMessage(error), "failure");
return false; return false;
} }
} }

View file

@ -6,7 +6,7 @@
import { insertTextIntoChatInputBox } from "@utils/discord"; import { insertTextIntoChatInputBox } from "@utils/discord";
import { parseUrl } from "@utils/misc"; import { parseUrl } from "@utils/misc";
import { showToast, Toasts } from "@webpack/common"; import { showToast } from "@webpack/common";
import { registerCommands } from "../api/registry"; import { registerCommands } from "../api/registry";
import type { FormPageSpec, PageEntry, PaletteAction, PaletteCommand } from "../api/types"; import type { FormPageSpec, PageEntry, PaletteAction, PaletteCommand } from "../api/types";
@ -109,7 +109,7 @@ function commandForm(existing: CustomCommandData | null): PageEntry {
: [...store.get(), next]); : [...store.get(), next]);
registerCustomCommands(); registerCustomCommands();
showToast(existing ? "Command saved." : "Command created.", Toasts.Type.SUCCESS); showToast(existing ? "Command saved." : "Command created.", "success");
ctx.pop(); ctx.pop();
} }
}; };
@ -138,7 +138,7 @@ function toCommand(data: CustomCommandData): PaletteCommand {
run() { run() {
store.set(store.get().filter(entry => entry.id !== data.id)); store.set(store.get().filter(entry => entry.id !== data.id));
registerCustomCommands(); registerCustomCommands();
showToast("Command deleted.", Toasts.Type.SUCCESS); showToast("Command deleted.", "success");
} }
} }
]; ];

View file

@ -7,7 +7,7 @@
import { getUserSettingLazy } from "@api/UserSettings"; import { getUserSettingLazy } from "@api/UserSettings";
import type { Theme } from "@vencord/discord-types"; import type { Theme } from "@vencord/discord-types";
import { findByCodeLazy } from "@webpack"; import { findByCodeLazy } from "@webpack";
import { showToast, ThemeStore, Toasts, VoiceActions } from "@webpack/common"; import { showToast, ThemeStore, VoiceActions } from "@webpack/common";
import type { PaletteCommand } from "../api/types"; import type { PaletteCommand } from "../api/types";
import { CircleIcon, HeadphonesIcon, MicIcon, MoonIcon } from "../ui/icons"; import { CircleIcon, HeadphonesIcon, MicIcon, MoonIcon } from "../ui/icons";
@ -78,7 +78,7 @@ export const discordCommands: PaletteCommand[] = [
label: `Set ${status.label}`, label: `Set ${status.label}`,
run() { run() {
StatusSetting?.updateSetting(status.value); StatusSetting?.updateSetting(status.value);
showToast(`Status set to ${status.label}.`, Toasts.Type.SUCCESS); showToast(`Status set to ${status.label}.`, "success");
} }
}] }]
})) }))
@ -98,7 +98,7 @@ export const discordCommands: PaletteCommand[] = [
const currentIdx = THEMES.findIndex(theme => theme.value === ThemeStore.theme); const currentIdx = THEMES.findIndex(theme => theme.value === ThemeStore.theme);
const next = THEMES[(currentIdx + 1) % THEMES.length]; const next = THEMES[(currentIdx + 1) % THEMES.length];
updateDiscordTheme({ theme: next.value }); updateDiscordTheme({ theme: next.value });
showToast(`Theme set to ${next.label}.`, Toasts.Type.SUCCESS); showToast(`Theme set to ${next.label}.`, "success");
} }
}] }]
} }

View file

@ -5,7 +5,7 @@
*/ */
import { Logger } from "@utils/Logger"; import { Logger } from "@utils/Logger";
import { SettingsRouter, showToast, Toasts } from "@webpack/common"; import { SettingsRouter, showToast } from "@webpack/common";
export interface SettingsRoute { export interface SettingsRoute {
route: string; route: string;
@ -110,7 +110,7 @@ const logger = new Logger("CommandPalette");
export async function openSettingsPage(route: string, label?: string) { export async function openSettingsPage(route: string, label?: string) {
const candidates = resolveRouteCandidates(route); const candidates = resolveRouteCandidates(route);
if (candidates.length === 0) { if (candidates.length === 0) {
showToast("No settings page was provided.", Toasts.Type.FAILURE); showToast("No settings page was provided.", "failure");
return false; return false;
} }
@ -124,6 +124,6 @@ export async function openSettingsPage(route: string, label?: string) {
} }
} }
showToast(`Unable to open ${label ?? "that settings page"}.`, Toasts.Type.FAILURE); showToast(`Unable to open ${label ?? "that settings page"}.`, "failure");
return false; return false;
} }

View file

@ -8,7 +8,7 @@ import { isPluginEnabled, pluginRequiresRestart, plugins, startDependenciesRecur
import { Settings } from "@api/Settings"; import { Settings } from "@api/Settings";
import { openPluginModal } from "@components/settings/tabs/plugins/PluginModal"; import { openPluginModal } from "@components/settings/tabs/plugins/PluginModal";
import type { Plugin } from "@utils/types"; import type { Plugin } from "@utils/types";
import { showToast, Toasts } from "@webpack/common"; import { showToast } from "@webpack/common";
import type { PaletteCommand, PaletteListItem } from "../api/types"; import type { PaletteCommand, PaletteListItem } from "../api/types";
import { GearIcon, PlugIcon } from "../ui/icons"; import { GearIcon, PlugIcon } from "../ui/icons";
@ -20,37 +20,37 @@ function togglePlugin(plugin: Plugin) {
if (!wasEnabled) { if (!wasEnabled) {
const { restartNeeded, failures } = startDependenciesRecursive(plugin); const { restartNeeded, failures } = startDependenciesRecursive(plugin);
if (failures.length) { if (failures.length) {
showToast(`Failed to start dependencies: ${failures.join(", ")}`, Toasts.Type.FAILURE); showToast(`Failed to start dependencies: ${failures.join(", ")}`, "failure");
return; return;
} }
if (restartNeeded) { if (restartNeeded) {
pluginSettings.enabled = true; pluginSettings.enabled = true;
showToast(`${plugin.name} enabled. Restart to apply.`, Toasts.Type.MESSAGE); showToast(`${plugin.name} enabled. Restart to apply.`, "message");
return; return;
} }
} }
if (pluginRequiresRestart(plugin)) { if (pluginRequiresRestart(plugin)) {
pluginSettings.enabled = !wasEnabled; pluginSettings.enabled = !wasEnabled;
showToast(`${plugin.name} ${wasEnabled ? "disabled" : "enabled"}. Restart to apply.`, Toasts.Type.MESSAGE); showToast(`${plugin.name} ${wasEnabled ? "disabled" : "enabled"}. Restart to apply.`, "message");
return; return;
} }
if (wasEnabled && !plugin.started) { if (wasEnabled && !plugin.started) {
pluginSettings.enabled = false; pluginSettings.enabled = false;
showToast(`${plugin.name} disabled.`, Toasts.Type.SUCCESS); showToast(`${plugin.name} disabled.`, "success");
return; return;
} }
const result = wasEnabled ? stopPlugin(plugin) : startPlugin(plugin); const result = wasEnabled ? stopPlugin(plugin) : startPlugin(plugin);
if (!result) { if (!result) {
pluginSettings.enabled = false; pluginSettings.enabled = false;
showToast(`Error while ${wasEnabled ? "stopping" : "starting"} ${plugin.name}.`, Toasts.Type.FAILURE); showToast(`Error while ${wasEnabled ? "stopping" : "starting"} ${plugin.name}.`, "failure");
return; return;
} }
pluginSettings.enabled = !wasEnabled; pluginSettings.enabled = !wasEnabled;
showToast(`${plugin.name} ${wasEnabled ? "disabled" : "enabled"}.`, Toasts.Type.SUCCESS); showToast(`${plugin.name} ${wasEnabled ? "disabled" : "enabled"}.`, "success");
} }
function pluginItems(): PaletteListItem[] { function pluginItems(): PaletteListItem[] {

View file

@ -7,7 +7,7 @@
import { openPrivateChannel, sendMessage } from "@utils/discord"; import { openPrivateChannel, sendMessage } from "@utils/discord";
import { sleep } from "@utils/misc"; import { sleep } from "@utils/misc";
import { CloudUploadPlatform } from "@vencord/discord-types/enums"; import { CloudUploadPlatform } from "@vencord/discord-types/enums";
import { ChannelStore, CloudUploader, IconUtils, RelationshipStore, showToast, Toasts, UserStore } from "@webpack/common"; import { ChannelStore, CloudUploader, IconUtils, RelationshipStore, showToast, UserStore } from "@webpack/common";
import type { FormFieldOption, FormSubmitExtras, PaletteCommand } from "../api/types"; import type { FormFieldOption, FormSubmitExtras, PaletteCommand } from "../api/types";
import { fuzzyScore } from "../search/ranker"; import { fuzzyScore } from "../search/ranker";
@ -82,7 +82,7 @@ export const sendDmCommand: PaletteCommand = {
}); });
const user = UserStore.getUser(values.recipient); const user = UserStore.getUser(values.recipient);
showToast(`Message sent to ${user.globalName || user.username}.`, Toasts.Type.SUCCESS); showToast(`Message sent to ${user.globalName || user.username}.`, "success");
ctx.close(); ctx.close();
} }
} }

View file

@ -10,7 +10,7 @@ import { EquicordDevs } from "@utils/constants";
import { Logger } from "@utils/Logger"; import { Logger } from "@utils/Logger";
import definePlugin from "@utils/types"; import definePlugin from "@utils/types";
import { User } from "@vencord/discord-types"; import { User } from "@vencord/discord-types";
import { Menu, SelectedGuildStore, Toasts, UserProfileStore } from "@webpack/common"; import { Menu, SelectedGuildStore, showToast,UserProfileStore } from "@webpack/common";
const logger = new Logger("CopyProfileColors"); const logger = new Logger("CopyProfileColors");
@ -38,11 +38,7 @@ function copyProfileColors(userId: string, guildId?: string) {
const colors = getProfileColors(userId, guildId); const colors = getProfileColors(userId, guildId);
if (!colors) { if (!colors) {
Toasts.show({ showToast("No profile colors found!", "failure");
type: Toasts.Type.FAILURE,
message: "No profile colors found!",
id: Toasts.genId()
});
return; return;
} }
@ -53,18 +49,10 @@ function copyProfileColors(userId: string, guildId?: string) {
try { try {
copyToClipboard(formattedColors); copyToClipboard(formattedColors);
Toasts.show({ showToast("Profile colors copied to clipboard!", "success");
type: Toasts.Type.SUCCESS,
message: "Profile colors copied to clipboard!",
id: Toasts.genId()
});
} catch (e) { } catch (e) {
logger.error("Failed to copy to clipboard:", e); logger.error("Failed to copy to clipboard:", e);
Toasts.show({ showToast("Error copying profile colors!", "failure");
type: Toasts.Type.FAILURE,
message: "Error copying profile colors!",
id: Toasts.genId()
});
} }
} }

View file

@ -8,8 +8,9 @@ import { copyToClipboard } from "@utils/clipboard";
import { Devs } from "@utils/constants"; import { Devs } from "@utils/constants";
import definePlugin from "@utils/types"; import definePlugin from "@utils/types";
import { User } from "@vencord/discord-types"; import { User } from "@vencord/discord-types";
import { ToastPosition } from "@vencord/discord-types/enums";
import { findByCodeLazy } from "@webpack"; import { findByCodeLazy } from "@webpack";
import { Toasts } from "@webpack/common"; import { showToast } from "@webpack/common";
interface MakeContextMenuProps { interface MakeContextMenuProps {
user: User, user: User,
@ -44,24 +45,14 @@ export default definePlugin({
throw new Error("button_urls does not contain index"); throw new Error("button_urls does not contain index");
} }
copyToClipboard(button_urls[index]); copyToClipboard(button_urls[index]);
Toasts.show({ showToast("Copied URL", "success", {
id: Toasts.genId(), position: ToastPosition.TOP
message: "Copied URL", });
type: Toasts.Type.SUCCESS,
options: {
position: Toasts.Position.TOP
}
});
} catch (e) { } catch (e) {
console.error(e); console.error(e);
Toasts.show({ showToast("Error copying URL, check console for more info", "failure", {
id: Toasts.genId(), position: ToastPosition.TOP
message: "Error copying URL, check console for more info", });
type: Toasts.Type.FAILURE,
options: {
position: Toasts.Position.TOP
}
});
} }
}; };
} }

View file

@ -11,7 +11,7 @@ import { Logger } from "@utils/Logger";
import { pluralize } from "@utils/misc"; import { pluralize } from "@utils/misc";
import definePlugin, { OptionType } from "@utils/types"; import definePlugin, { OptionType } from "@utils/types";
import { Message, MessageAttachment } from "@vencord/discord-types"; import { Message, MessageAttachment } from "@vencord/discord-types";
import { ChannelStore, showToast, Toasts } from "@webpack/common"; import { ChannelStore, showToast } from "@webpack/common";
const logger = new Logger("DownloadAllAttachments"); const logger = new Logger("DownloadAllAttachments");
@ -71,9 +71,9 @@ async function downloadAll(attachments: MessageAttachment[]) {
const succeeded = attachments.length - failed; const succeeded = attachments.length - failed;
if (failed === 0) if (failed === 0)
showToast(`Downloaded ${pluralize(succeeded, "attachment")}.`, Toasts.Type.SUCCESS); showToast(`Downloaded ${pluralize(succeeded, "attachment")}.`, "success");
else else
showToast(`Downloaded ${succeeded} of ${attachments.length} attachments. ${failed} failed.`, Toasts.Type.FAILURE); showToast(`Downloaded ${succeeded} of ${attachments.length} attachments. ${failed} failed.`, "failure");
} }
export default definePlugin({ export default definePlugin({

View file

@ -13,7 +13,7 @@ import { Logger } from "@utils/Logger";
import definePlugin, { OptionType } from "@utils/types"; import definePlugin, { OptionType } from "@utils/types";
import type { Channel } from "@vencord/discord-types"; import type { Channel } from "@vencord/discord-types";
import { ChannelType } from "@vencord/discord-types/enums"; import { ChannelType } from "@vencord/discord-types/enums";
import { ChannelStore, GuildStore, IconUtils, RelationshipStore, SelectedChannelStore, showToast, Toasts, UserStore } from "@webpack/common"; import { ChannelStore, GuildStore, IconUtils, RelationshipStore, SelectedChannelStore, showToast, UserStore } from "@webpack/common";
import { beginDrag as beginSessionDrag, clearDragState, getLastDropAt, hasActiveDrag, isGuildDragActive, isInputDragSource, isUserDragActive, markDrop, markInputDragSource, scheduleGuildCleanup, shouldIgnoreDrop, startDragWatchdog, stopDragState, touchDrag } from "./dragState"; import { beginDrag as beginSessionDrag, clearDragState, getLastDropAt, hasActiveDrag, isGuildDragActive, isInputDragSource, isUserDragActive, markDrop, markInputDragSource, scheduleGuildCleanup, shouldIgnoreDrop, startDragWatchdog, stopDragState, touchDrag } from "./dragState";
import { type GhostState, hideGhost as hideDragGhost, isGhostVisible, mountGhost as mountDragGhost, scheduleGhostPosition as scheduleDragGhostPosition, showGhost as showDragGhost, unmountGhost as unmountDragGhost } from "./ghost"; import { type GhostState, hideGhost as hideDragGhost, isGhostVisible, mountGhost as mountDragGhost, scheduleGhostPosition as scheduleDragGhostPosition, showGhost as showDragGhost, unmountGhost as unmountDragGhost } from "./ghost";
@ -293,7 +293,7 @@ export default definePlugin({
} catch (error) { } catch (error) {
clearDragState(); clearDragState();
logger.error("Failed handling drop", error); logger.error("Failed handling drop", error);
showToast("Dragify failed to handle drop.", Toasts.Type.FAILURE); showToast("Dragify failed to handle drop.", "failure");
} }
}, },

View file

@ -7,7 +7,7 @@
import { Logger } from "@utils/Logger"; import { Logger } from "@utils/Logger";
import type { Channel } from "@vencord/discord-types"; import type { Channel } from "@vencord/discord-types";
import { ChannelType } from "@vencord/discord-types/enums"; import { ChannelType } from "@vencord/discord-types/enums";
import { ChannelStore, GuildChannelStore, GuildStore, PermissionsBits, PermissionStore, RestAPI, showToast, Toasts } from "@webpack/common"; import { ChannelStore, GuildChannelStore, GuildStore, PermissionsBits, PermissionStore, RestAPI, showToast } from "@webpack/common";
const logger = new Logger("Dragify"); const logger = new Logger("Dragify");
@ -135,7 +135,7 @@ function getInviteUrl(code: string) {
export async function createInvite(guildId: string, currentChannel: Channel, settings: InviteSettings): Promise<string | null> { export async function createInvite(guildId: string, currentChannel: Channel, settings: InviteSettings): Promise<string | null> {
const inviteChannel = resolveInviteChannel(guildId, currentChannel); const inviteChannel = resolveInviteChannel(guildId, currentChannel);
if (!inviteChannel) { if (!inviteChannel) {
showToast("No channel available for invites.", Toasts.Type.FAILURE); showToast("No channel available for invites.", "failure");
return null; return null;
} }
@ -147,7 +147,7 @@ export async function createInvite(guildId: string, currentChannel: Channel, set
reused.reason === "missing" reused.reason === "missing"
? "No reusable invite available." ? "No reusable invite available."
: "Unable to reuse invite.", : "Unable to reuse invite.",
Toasts.Type.FAILURE, "failure",
); );
return null; return null;
} }
@ -174,11 +174,11 @@ export async function createInvite(guildId: string, currentChannel: Channel, set
maxUses: maxUses === 0 ? null : maxUses, maxUses: maxUses === 0 ? null : maxUses,
uses: 0, uses: 0,
}); });
showToast("Invite created.", Toasts.Type.SUCCESS); showToast("Invite created.", "success");
return getInviteUrl(code); return getInviteUrl(code);
} catch (error) { } catch (error) {
logger.error("Failed to create invite", error); logger.error("Failed to create invite", error);
showToast("Unable to create invite.", Toasts.Type.FAILURE); showToast("Unable to create invite.", "failure");
return null; return null;
} }
} }

View file

@ -314,7 +314,7 @@ export default definePlugin({
match: /case \i\.\i\.WINDOWS:/, match: /case \i\.\i\.WINDOWS:/,
replace: 'case "WEB":' replace: 'case "WEB":'
}, },
predicate: () => Settings.winNativeTitleBar, predicate: () => Settings.nativeTitleBar,
}, },
{ {
find: '"refresh-title-bar-small"', find: '"refresh-title-bar-small"',
@ -328,7 +328,7 @@ export default definePlugin({
replace: "true" replace: "true"
} }
], ],
predicate: () => Settings.winNativeTitleBar, predicate: () => Settings.nativeTitleBar,
}, },
{ {
find: "DirectMessage: getSpringConfigs()", find: "DirectMessage: getSpringConfigs()",
@ -350,7 +350,7 @@ export default definePlugin({
replace: "$&&&!$self.isChannelMuted($1?.guildId,$1?.channelId)" replace: "$&&&!$self.isChannelMuted($1?.guildId,$1?.channelId)"
}, },
{ {
match: /\.getEmbeddedActivitiesForGuild\((\i)\)(?=.flatMap\(\i=>)/, match: /\.getEmbeddedActivitiesForGuild\((\i)\)(?=.{0,100}\.flatMap\(\i=>)/,
replace: "$&.filter(e=>!$self.isChannelMuted($1?.guildId,e?.channelId))" replace: "$&.filter(e=>!$self.isChannelMuted($1?.guildId,e?.channelId))"
} }
], ],

View file

@ -9,7 +9,7 @@ import ErrorBoundary from "@components/ErrorBoundary";
import { Logger } from "@utils/Logger"; import { Logger } from "@utils/Logger";
import { isEquicordGuild, isEquicordSupport } from "@utils/misc"; import { isEquicordGuild, isEquicordSupport } from "@utils/misc";
import { Message } from "@vencord/discord-types"; import { Message } from "@vencord/discord-types";
import { Button, showToast, Toasts } from "@webpack/common"; import { Button, showToast } from "@webpack/common";
import { JSX } from "react"; import { JSX } from "react";
import { toggleEnabled } from "./utils"; import { toggleEnabled } from "./utils";
@ -50,10 +50,10 @@ export const PluginButtons = ErrorBoundary.wrap(function PluginCards({ message }
onClick={async () => { onClick={async () => {
try { try {
const success = await toggleEnabled(matchedPlugin); const success = await toggleEnabled(matchedPlugin);
if (success) showToast(`${label}`, Toasts.Type.SUCCESS); if (success) showToast(`${label}`, "success");
} catch (e) { } catch (e) {
new Logger("EquicordHelper").error("Error while toggling:", e); new Logger("EquicordHelper").error("Error while toggling:", e);
showToast(`Failed to ${label.toLowerCase()}`, Toasts.Type.FAILURE); showToast(`Failed to ${label.toLowerCase()}`, "failure");
} }
}} }}
> >

View file

@ -7,17 +7,13 @@
import { showNotice } from "@api/Notices"; import { showNotice } from "@api/Notices";
import { plugins, startDependenciesRecursive, startPlugin, stopPlugin } from "@api/PluginManager"; import { plugins, startDependenciesRecursive, startPlugin, stopPlugin } from "@api/PluginManager";
import { Settings } from "@api/Settings"; import { Settings } from "@api/Settings";
import { Alerts, Toasts } from "@webpack/common"; import { ToastPosition } from "@vencord/discord-types/enums";
import { Alerts, showToast } from "@webpack/common";
function showErrorToast(message: string) { function showErrorToast(message: string) {
Toasts.show({ showToast(message, "failure", {
message, position: ToastPosition.BOTTOM
type: Toasts.Type.FAILURE, });
id: Toasts.genId(),
options: {
position: Toasts.Position.BOTTOM
}
});
} }
function restartPrompt(): Promise<boolean> { function restartPrompt(): Promise<boolean> {

View file

@ -14,7 +14,7 @@ import { Devs } from "@utils/constants";
import { classNameFactory } from "@utils/css"; import { classNameFactory } from "@utils/css";
import definePlugin, { OptionType } from "@utils/types"; import definePlugin, { OptionType } from "@utils/types";
import { findComponentByCodeLazy } from "@webpack"; import { findComponentByCodeLazy } from "@webpack";
import { Constants, GuildStore, IconUtils, MediaEngineStore, Menu, RestAPI, SearchableSelect, SelectedChannelStore, TextInput, Toasts } from "@webpack/common"; import { Constants, GuildStore, IconUtils, MediaEngineStore, Menu, RestAPI, SearchableSelect, SelectedChannelStore, showToast,TextInput } from "@webpack/common";
const cl = classNameFactory("vc-exitsounds-"); const cl = classNameFactory("vc-exitsounds-");
@ -134,11 +134,7 @@ export default definePlugin({
} }
}); });
} catch { } catch {
Toasts.show({ showToast("Oops! Something went wrong.", "failure");
message: "Oops! Something went wrong.",
id: Toasts.genId(),
type: Toasts.Type.FAILURE
});
} }
} }
}); });

View file

@ -15,7 +15,8 @@ import { showItemInFolder } from "@utils/native";
import definePlugin, { OptionType } from "@utils/types"; import definePlugin, { OptionType } from "@utils/types";
import { saveFile } from "@utils/web"; import { saveFile } from "@utils/web";
import { Message } from "@vencord/discord-types"; import { Message } from "@vencord/discord-types";
import { Menu, Toasts } from "@webpack/common"; import { ToastPosition } from "@vencord/discord-types/enums";
import { Menu, showToast } from "@webpack/common";
import { ContactsList } from "./types"; import { ContactsList } from "./types";
@ -175,28 +176,18 @@ export default definePlugin({
copyContactToClipboard() { copyContactToClipboard() {
if (this.contactList) { if (this.contactList) {
copyToClipboard(JSON.stringify(this.contactList)); copyToClipboard(JSON.stringify(this.contactList));
Toasts.show({ showToast("Contacts copied to clipboard successfully.", "success", {
message: "Contacts copied to clipboard successfully.",
type: Toasts.Type.SUCCESS,
id: Toasts.genId(),
options: {
duration: 3000, duration: 3000,
position: Toasts.Position.BOTTOM position: ToastPosition.BOTTOM
} });
});
return; return;
} }
// reason why you need to click the all tab is because the data is extracted during // reason why you need to click the all tab is because the data is extracted during
// the request itself when you fetch all your friends. this is done to avoid sending a // the request itself when you fetch all your friends. this is done to avoid sending a
// manual request to discord, which may raise suspicion and might even get you terminated. // manual request to discord, which may raise suspicion and might even get you terminated.
Toasts.show({ showToast("Contact list is undefined. Click on the \"All\" tab before exporting.", "failure", {
message: "Contact list is undefined. Click on the \"All\" tab before exporting.",
type: Toasts.Type.FAILURE,
id: Toasts.genId(),
options: {
duration: 3000, duration: 3000,
position: Toasts.Position.BOTTOM position: ToastPosition.BOTTOM
} });
});
} }
}); });

View file

@ -12,7 +12,7 @@ import { useForceUpdater } from "@utils/react";
import { PluginNative } from "@utils/types"; import { PluginNative } from "@utils/types";
import { Channel, MessageAttachment } from "@vencord/discord-types"; import { Channel, MessageAttachment } from "@vencord/discord-types";
import { findByCodeLazy, findByPropsLazy } from "@webpack"; import { findByCodeLazy, findByPropsLazy } from "@webpack";
import { Constants, createRoot, DraftType, FluxDispatcher, Humanize, MessageActions, PendingReplyStore, PermissionStore, ReactDOM, RestAPI, Toasts, UploadAttachmentStore, UploadHandler, UploadManager, useCallback, useEffect, useRef, UserSettingsActionCreators, UserSettingsProtoStore, useStateFromStores } from "@webpack/common"; import { Constants, createRoot, DraftType, FluxDispatcher, Humanize, MessageActions, PendingReplyStore, PermissionStore, ReactDOM, RestAPI, showToast,UploadAttachmentStore, UploadHandler, UploadManager, useCallback, useEffect, useRef, UserSettingsActionCreators, UserSettingsProtoStore, useStateFromStores } from "@webpack/common";
import { deflateSync, inflateSync } from "fflate"; import { deflateSync, inflateSync } from "fflate";
import { Key, ReactNode } from "react"; import { Key, ReactNode } from "react";
import { JsonValue } from "type-fest"; import { JsonValue } from "type-fest";
@ -189,13 +189,13 @@ async function fetchAttachment(attachment: MessageAttachment): Promise<File> {
export async function sendAttachment(attachment: MessageAttachment, channel: Channel) { export async function sendAttachment(attachment: MessageAttachment, channel: Channel) {
const { filename, title, description } = attachment; const { filename, title, description } = attachment;
const file = await fetchAttachment(attachment).catch(() => const file = await fetchAttachment(attachment).catch(() =>
Toasts.show({ message: `Couldn't fetch ${filename}`, id: Toasts.genId(), type: Toasts.Type.FAILURE }) showToast(`Couldn't fetch ${filename}`, "failure")
); );
if (!file) return; if (!file) return;
// Using promptToUpload instead of addFiles directly since it has file size checks with error popups // Using promptToUpload instead of addFiles directly since it has file size checks with error popups
await UploadHandler.promptToUpload([file], channel, DraftType.ChannelMessage).catch(() => await UploadHandler.promptToUpload([file], channel, DraftType.ChannelMessage).catch(() =>
Toasts.show({ message: `Couldn't upload ${filename}`, id: Toasts.genId(), type: Toasts.Type.FAILURE }) showToast(`Couldn't upload ${filename}`, "failure")
); );
const uploads = [...UploadAttachmentStore.getUploads(channel.id, DraftType.ChannelMessage)]; const uploads = [...UploadAttachmentStore.getUploads(channel.id, DraftType.ChannelMessage)];

View file

@ -14,7 +14,7 @@ import { classNameFactory } from "@utils/css";
import definePlugin from "@utils/types"; import definePlugin from "@utils/types";
import { CloudUpload } from "@vencord/discord-types"; import { CloudUpload } from "@vencord/discord-types";
import { findByPropsLazy } from "@webpack"; import { findByPropsLazy } from "@webpack";
import { DraftType, FluxDispatcher, Menu, PermissionsBits, PermissionStore, React, showToast, Toasts, UploadAttachmentStore, useEffect, UserStore, useState } from "@webpack/common"; import { DraftType, FluxDispatcher, Menu, PermissionsBits, PermissionStore, React, showToast, UploadAttachmentStore, useEffect, UserStore, useState } from "@webpack/common";
import { settings } from "./settings"; import { settings } from "./settings";
import { serviceLabels, ServiceType } from "./types"; import { serviceLabels, ServiceType } from "./types";
@ -233,12 +233,12 @@ async function handleUploadFileFromDraft(upload: CloudUpload) {
if (!file) return; if (!file) return;
if (!isFileTypeAllowed(file)) { if (!isFileTypeAllowed(file)) {
showToast("File type not allowed by current filter", Toasts.Type.FAILURE); showToast("File type not allowed by current filter", "failure");
return; return;
} }
if (!isConfigured()) { if (!isConfigured()) {
showToast("Please configure FileUpload settings first", Toasts.Type.FAILURE); showToast("Please configure FileUpload settings first", "failure");
return; return;
} }

View file

@ -11,7 +11,7 @@ import { Switch } from "@components/Switch";
import { classNameFactory } from "@utils/css"; import { classNameFactory } from "@utils/css";
import { useForceUpdater } from "@utils/react"; import { useForceUpdater } from "@utils/react";
import { OptionType } from "@utils/types"; import { OptionType } from "@utils/types";
import { React, Select, showToast, TextArea, TextInput, Toasts } from "@webpack/common"; import { React, Select, showToast, TextArea, TextInput } from "@webpack/common";
import { CORS_PROXY } from "./constants"; import { CORS_PROXY } from "./constants";
import { fallbackServiceOrder, serviceLabels, ServiceType } from "./types"; import { fallbackServiceOrder, serviceLabels, ServiceType } from "./types";
@ -520,10 +520,10 @@ export function SettingsComponent() {
const validateShareXConfig = () => { const validateShareXConfig = () => {
try { try {
parseShareXConfig(settings.store.sharexConfig || ""); parseShareXConfig(settings.store.sharexConfig || "");
showToast("ShareX config is valid", Toasts.Type.SUCCESS); showToast("ShareX config is valid", "success");
} catch (error) { } catch (error) {
const message = error instanceof Error ? error.message : "Invalid ShareX config"; const message = error instanceof Error ? error.message : "Invalid ShareX config";
showToast(message, Toasts.Type.FAILURE); showToast(message, "failure");
} }
}; };
@ -542,10 +542,10 @@ export function SettingsComponent() {
const parsed = parseShareXConfig(content); const parsed = parseShareXConfig(content);
settings.store.sharexConfig = JSON.stringify(parsed, null, 2); settings.store.sharexConfig = JSON.stringify(parsed, null, 2);
update(); update();
showToast("Imported ShareX config", Toasts.Type.SUCCESS); showToast("Imported ShareX config", "success");
} catch (error) { } catch (error) {
const message = error instanceof Error ? error.message : "Failed to import ShareX config"; const message = error instanceof Error ? error.message : "Failed to import ShareX config";
showToast(message, Toasts.Type.FAILURE); showToast(message, "failure");
} }
}; };
reader.readAsText(file); reader.readAsText(file);

View file

@ -12,7 +12,7 @@ import { insertTextIntoChatInputBox } from "@utils/discord";
import { Logger } from "@utils/Logger"; import { Logger } from "@utils/Logger";
import { PluginNative } from "@utils/types"; import { PluginNative } from "@utils/types";
import { chooseFile } from "@utils/web"; import { chooseFile } from "@utils/web";
import { showToast, Toasts } from "@webpack/common"; import { showToast } from "@webpack/common";
import { convertApngToGif } from "./apngToGif"; import { convertApngToGif } from "./apngToGif";
import { getExtensionFromBytes, getExtensionFromMime, getMimeFromExtension, getUrlExtension } from "./getMediaUrl"; import { getExtensionFromBytes, getExtensionFromMime, getMimeFromExtension, getUrlExtension } from "./getMediaUrl";
@ -1304,19 +1304,19 @@ function getFilenameExtension(filename: string): string | undefined {
async function notifyUploadSuccess(finalUrl: string, forceSend?: boolean): Promise<void> { async function notifyUploadSuccess(finalUrl: string, forceSend?: boolean): Promise<void> {
if (settings.store.autoCopy) { if (settings.store.autoCopy) {
if (!finalUrl || !finalUrl.trim()) { if (!finalUrl || !finalUrl.trim()) {
showToast("Upload successful, but no URL was available to copy", Toasts.Type.MESSAGE); showToast("Upload successful, but no URL was available to copy", "message");
return; return;
} }
try { try {
await copyToClipboard(finalUrl); await copyToClipboard(finalUrl);
showToast("Upload successful, URL copied to clipboard", Toasts.Type.SUCCESS); showToast("Upload successful, URL copied to clipboard", "success");
} catch (error) { } catch (error) {
logger.warn("Upload succeeded but clipboard copy failed", error); logger.warn("Upload succeeded but clipboard copy failed", error);
showToast("Upload successful, but failed to copy URL", Toasts.Type.MESSAGE); showToast("Upload successful, but failed to copy URL", "message");
} }
} else { } else {
showToast("Upload successful", Toasts.Type.SUCCESS); showToast("Upload successful", "success");
} }
const autoSend = forceSend || Boolean((settings.store as { autoSend?: boolean; }).autoSend); const autoSend = forceSend || Boolean((settings.store as { autoSend?: boolean; }).autoSend);
@ -1366,7 +1366,7 @@ async function uploadWithFallbacks(fileBlob: Blob, filename: string, primary: Se
try { try {
const uploadedUrl = await uploadToService(service, fileBlob, filename); const uploadedUrl = await uploadToService(service, fileBlob, filename);
if (attempted.length) { if (attempted.length) {
showToast(`Upload succeeded with ${serviceLabels[service]} after fallback`, Toasts.Type.SUCCESS); showToast(`Upload succeeded with ${serviceLabels[service]} after fallback`, "success");
} }
setUploadState({ setUploadState({
@ -1433,7 +1433,7 @@ async function normalizeUploadBlob(blob: Blob, sourceUrl?: string): Promise<{ bl
blob = gifBlob; blob = gifBlob;
ext = "gif"; ext = "gif";
} else { } else {
showToast("APNG to GIF conversion failed, uploading as APNG", Toasts.Type.FAILURE); showToast("APNG to GIF conversion failed, uploading as APNG", "failure");
} }
} }
@ -1463,12 +1463,12 @@ async function uploadPreparedBlob(blob: Blob, sourceUrl?: string, forceSend?: bo
export async function uploadFile(url: string): Promise<void> { export async function uploadFile(url: string): Promise<void> {
if (isUploading) { if (isUploading) {
showToast("Upload already in progress", Toasts.Type.MESSAGE); showToast("Upload already in progress", "message");
return; return;
} }
if (!isConfigured()) { if (!isConfigured()) {
showToast("Please configure FileUpload settings first", Toasts.Type.FAILURE); showToast("Please configure FileUpload settings first", "failure");
return; return;
} }
@ -1527,10 +1527,10 @@ export async function uploadFile(url: string): Promise<void> {
} catch (error) { } catch (error) {
const message = error instanceof Error ? error.message : "Unknown error"; const message = error instanceof Error ? error.message : "Unknown error";
if (isUploadCancelledError(error)) { if (isUploadCancelledError(error)) {
showToast("Upload cancelled", Toasts.Type.MESSAGE); showToast("Upload cancelled", "message");
setUploadState({ phase: "cancelled", status: "Upload cancelled.", canCancel: false, percent: 0 }); setUploadState({ phase: "cancelled", status: "Upload cancelled.", canCancel: false, percent: 0 });
} else { } else {
showToast(`Upload failed: ${message}`, Toasts.Type.FAILURE); showToast(`Upload failed: ${message}`, "failure");
logger.error("Upload error", error); logger.error("Upload error", error);
setUploadState({ phase: "failed", status: `Upload failed: ${message}`, canCancel: false, percent: 0 }); setUploadState({ phase: "failed", status: `Upload failed: ${message}`, canCancel: false, percent: 0 });
} }
@ -1547,7 +1547,7 @@ export async function uploadPickedFile(): Promise<void> {
if (!file) return; if (!file) return;
if (!isFileTypeAllowed(file)) { if (!isFileTypeAllowed(file)) {
showToast("File type not allowed by current filter", Toasts.Type.FAILURE); showToast("File type not allowed by current filter", "failure");
return; return;
} }
@ -1556,12 +1556,12 @@ export async function uploadPickedFile(): Promise<void> {
export async function uploadProvidedFiles(files: readonly File[], forceSend?: boolean): Promise<void> { export async function uploadProvidedFiles(files: readonly File[], forceSend?: boolean): Promise<void> {
if (isUploading) { if (isUploading) {
showToast("Upload already in progress", Toasts.Type.MESSAGE); showToast("Upload already in progress", "message");
return; return;
} }
if (!isConfigured()) { if (!isConfigured()) {
showToast("Please configure FileUpload settings first", Toasts.Type.FAILURE); showToast("Please configure FileUpload settings first", "failure");
return; return;
} }
@ -1596,10 +1596,10 @@ export async function uploadProvidedFiles(files: readonly File[], forceSend?: bo
} catch (error) { } catch (error) {
const message = error instanceof Error ? error.message : "Unknown error"; const message = error instanceof Error ? error.message : "Unknown error";
if (isUploadCancelledError(error)) { if (isUploadCancelledError(error)) {
showToast("Upload cancelled", Toasts.Type.MESSAGE); showToast("Upload cancelled", "message");
setUploadState({ phase: "cancelled", status: "Upload cancelled.", canCancel: false, percent: 0 }); setUploadState({ phase: "cancelled", status: "Upload cancelled.", canCancel: false, percent: 0 });
} else { } else {
showToast(`Upload failed: ${message}`, Toasts.Type.FAILURE); showToast(`Upload failed: ${message}`, "failure");
logger.error("Manual upload error", error); logger.error("Manual upload error", error);
setUploadState({ phase: "failed", status: `Upload failed: ${message}`, canCancel: false, percent: 0 }); setUploadState({ phase: "failed", status: `Upload failed: ${message}`, canCancel: false, percent: 0 });
} }

View file

@ -22,7 +22,7 @@ import { Devs } from "@utils/constants";
import definePlugin, { OptionType } from "@utils/types"; import definePlugin, { OptionType } from "@utils/types";
import { Message } from "@vencord/discord-types"; import { Message } from "@vencord/discord-types";
import { findByPropsLazy } from "@webpack"; import { findByPropsLazy } from "@webpack";
import { ChannelStore, createRoot, MessageStore, Toasts } from "@webpack/common"; import { ChannelStore, createRoot, MessageStore, showToast } from "@webpack/common";
import { Root } from "react-dom/client"; import { Root } from "react-dom/client";
import ReplyNavigator from "./ReplyNavigator"; import ReplyNavigator from "./ReplyNavigator";
@ -115,18 +115,10 @@ export default definePlugin({
jumpType: "INSTANT" jumpType: "INSTANT"
}); });
if (replies.length > 1) { if (replies.length > 1) {
Toasts.show({ showToast("Use the bottom panel to navigate between replies.", "message");
id: Toasts.genId(),
message: "Use the bottom panel to navigate between replies.",
type: Toasts.Type.MESSAGE
});
const container = document.querySelector("[class*=channelBottomBarArea_]"); const container = document.querySelector("[class*=channelBottomBarArea_]");
if (!container) { if (!container) {
Toasts.show({ showToast("Couldn't find the container element.", "failure");
id: Toasts.genId(),
message: "Couldn't find the container element.",
type: Toasts.Type.FAILURE
});
return; return;
} }
@ -139,11 +131,7 @@ export default definePlugin({
root!.render(<ReplyNavigator replies={replies} />); root!.render(<ReplyNavigator replies={replies} />);
} }
} else { } else {
Toasts.show({ showToast("Couldn't find a reply.", "failure");
id: Toasts.genId(),
message: "Couldn't find a reply.",
type: Toasts.Type.FAILURE
});
} }
} }
}; };

View file

@ -7,7 +7,7 @@
import { findGroupChildrenByChildId, NavContextMenuPatchCallback } from "@api/ContextMenu"; import { findGroupChildrenByChildId, NavContextMenuPatchCallback } from "@api/ContextMenu";
import { FolderIcon, InfoIcon, LinkIcon, PencilIcon, PlusIcon, RemixIcon, TrashIcon } from "@components/Icons"; import { FolderIcon, InfoIcon, LinkIcon, PencilIcon, PlusIcon, RemixIcon, TrashIcon } from "@components/Icons";
import { copyToClipboard } from "@utils/clipboard"; import { copyToClipboard } from "@utils/clipboard";
import { Alerts, Button, FluxDispatcher, Menu, showToast, Toasts } from "@webpack/common"; import { Alerts, Button, FluxDispatcher, Menu, showToast } from "@webpack/common";
import { settings } from "../settings"; import { settings } from "../settings";
import { Gif } from "../types"; import { Gif } from "../types";
@ -71,7 +71,7 @@ export const addCollectionContextMenuPatch: NavContextMenuPatchCallback = (child
leadingAccessory={{ type: "icon", icon: LinkIcon }} leadingAccessory={{ type: "icon", icon: LinkIcon }}
action={() => { action={() => {
copyToClipboard(gif.url); copyToClipboard(gif.url);
showToast("Image link copied to clipboard", Toasts.Type.SUCCESS); showToast("Image link copied to clipboard", "success");
}} }}
/> />
); );
@ -131,7 +131,7 @@ export function RemoveItemContextMenuItems({ type, nameOrId }: { type: "collecti
const gif = getGifById(nameOrId); const gif = getGifById(nameOrId);
if (!gif) return; if (!gif) return;
copyToClipboard(gif.url); copyToClipboard(gif.url);
showToast("URL copied to clipboard", Toasts.Type.SUCCESS); showToast("URL copied to clipboard", "success");
}} }}
/> />
<Menu.MenuItem <Menu.MenuItem
@ -198,7 +198,7 @@ export function GifPickerContextMenu({ gif }: { gif: Gif; }) {
leadingAccessory={{ type: "icon", icon: LinkIcon }} leadingAccessory={{ type: "icon", icon: LinkIcon }}
action={() => { action={() => {
copyToClipboard(gif.url); copyToClipboard(gif.url);
showToast("Image link copied to clipboard", Toasts.Type.SUCCESS); showToast("Image link copied to clipboard", "success");
}} }}
/> />
)} )}
@ -220,7 +220,7 @@ export function getGifPickerContextMenuItems(src: string, url: string, height: n
leadingAccessory={{ type: "icon", icon: LinkIcon }} leadingAccessory={{ type: "icon", icon: LinkIcon }}
action={() => { action={() => {
copyToClipboard(url); copyToClipboard(url);
showToast("Image link copied to clipboard", Toasts.Type.SUCCESS); showToast("Image link copied to clipboard", "success");
}} }}
/> />
)} )}

View file

@ -5,7 +5,8 @@
*/ */
import { DataStore } from "@api/index"; import { DataStore } from "@api/index";
import { Toasts } from "@webpack/common"; import { ToastPosition } from "@vencord/discord-types/enums";
import { showToast } from "@webpack/common";
import { settings } from "../settings"; import { settings } from "../settings";
import { Collection, Gif } from "../types"; import { Collection, Gif } from "../types";
@ -32,7 +33,7 @@ export async function createCollection(name: string, gifs: Gif[]): Promise<void>
const fullName = `${settings.store.collectionPrefix}${name}`; const fullName = `${settings.store.collectionPrefix}${name}`;
if (collections.some(c => c.name === fullName)) { if (collections.some(c => c.name === fullName)) {
Toasts.show({ message: "That collection already exists", type: Toasts.Type.FAILURE, id: Toasts.genId(), options: { duration: 3000, position: Toasts.Position.BOTTOM } }); showToast("That collection already exists", "failure", { duration: 3000, position: ToastPosition.BOTTOM });
return; return;
} }
@ -56,7 +57,7 @@ export async function addToCollection(name: string, gif: Gif): Promise<void> {
if (!collection) return void logger.warn("Collection not found"); if (!collection) return void logger.warn("Collection not found");
if (settings.store.preventDuplicates && collection.gifs.some(g => g.url === gif.url)) { if (settings.store.preventDuplicates && collection.gifs.some(g => g.url === gif.url)) {
Toasts.show({ message: "This GIF is already in the collection", type: Toasts.Type.FAILURE, id: Toasts.genId(), options: { duration: 3000, position: Toasts.Position.BOTTOM } }); showToast("This GIF is already in the collection", "failure", { duration: 3000, position: ToastPosition.BOTTOM });
return; return;
} }

View file

@ -6,7 +6,7 @@
import { DataStore } from "@api/index"; import { DataStore } from "@api/index";
import { chooseFile, saveFile } from "@utils/web"; import { chooseFile, saveFile } from "@utils/web";
import { Toasts } from "@webpack/common"; import { showToast } from "@webpack/common";
import { DATA_COLLECTION_NAME, getCollections, refreshCacheCollection } from "./collectionManager"; import { DATA_COLLECTION_NAME, getCollections, refreshCacheCollection } from "./collectionManager";
import { logger } from "./misc"; import { logger } from "./misc";
@ -70,14 +70,6 @@ export async function uploadGifCollections(showToast = true): Promise<void> {
} }
} }
const toastSuccess = () => Toasts.show({ const toastSuccess = () => showToast("Collections imported successfully.", "success");
type: Toasts.Type.SUCCESS,
message: "Collections imported successfully.",
id: Toasts.genId(),
});
const toastFailure = (err: unknown) => Toasts.show({ const toastFailure = (err: unknown) => showToast(`Failed to import collections: ${String(err)}`, "failure");
type: Toasts.Type.FAILURE,
message: `Failed to import collections: ${String(err)}`,
id: Toasts.genId(),
});

View file

@ -12,7 +12,7 @@ import { BadgeContextMenu } from "@plugins/_api/badges";
import { Devs, EquicordDevs } from "@utils/constants"; import { Devs, EquicordDevs } from "@utils/constants";
import { openInviteModal } from "@utils/discord"; import { openInviteModal } from "@utils/discord";
import definePlugin from "@utils/types"; import definePlugin from "@utils/types";
import { ContextMenuApi, React, Toasts } from "@webpack/common"; import { ContextMenuApi, React, showToast } from "@webpack/common";
import { settings } from "./settings"; import { settings } from "./settings";
import { cl, GlobalBadges, INVITE_LINK, loadBadges } from "./utils"; import { cl, GlobalBadges, INVITE_LINK, loadBadges } from "./utils";
@ -47,11 +47,7 @@ export default definePlugin({
toolboxActions: { toolboxActions: {
async "Refetch Global Badges"() { async "Refetch Global Badges"() {
await loadBadges(); await loadBadges();
Toasts.show({ showToast("Successfully refetched global badges!", "success");
id: Toasts.genId(),
message: "Successfully refetched global badges!",
type: Toasts.Type.SUCCESS
});
} }
}, },
get GlobalBadges() { get GlobalBadges() {

View file

@ -11,7 +11,7 @@ import { Devs, EquicordDevs } from "@utils/constants";
import definePlugin from "@utils/types"; import definePlugin from "@utils/types";
import { VoiceState } from "@vencord/discord-types"; import { VoiceState } from "@vencord/discord-types";
import { findByCodeLazy } from "@webpack"; import { findByCodeLazy } from "@webpack";
import { ApplicationStreamingSettingsStore, ChannelStore, MediaEngineStore, PermissionsBits, PermissionStore, SelectedChannelStore, showToast, Toasts, UserStore, VoiceActions, WindowStore } from "@webpack/common"; import { ApplicationStreamingSettingsStore, ChannelStore, MediaEngineStore, PermissionsBits, PermissionStore, SelectedChannelStore, showToast, UserStore, VoiceActions, WindowStore } from "@webpack/common";
import { getCurrentMedia, settings } from "./utils"; import { getCurrentMedia, settings } from "./utils";
@ -141,7 +141,7 @@ export default definePlugin({
toolboxActions: { toolboxActions: {
"Instant Screenshare"() { "Instant Screenshare"() {
settings.store.toolboxManagement = !settings.store.toolboxManagement; settings.store.toolboxManagement = !settings.store.toolboxManagement;
showToast(`Instant Screenshare ${settings.store.toolboxManagement ? "Enabled" : "Disabled"}`, Toasts.Type.SUCCESS); showToast(`Instant Screenshare ${settings.store.toolboxManagement ? "Enabled" : "Disabled"}`, "success");
} }
} }
}); });

View file

@ -8,7 +8,7 @@ import { NavContextMenuPatchCallback } from "@api/ContextMenu";
import { Devs } from "@utils/constants"; import { Devs } from "@utils/constants";
import definePlugin from "@utils/types"; import definePlugin from "@utils/types";
import { Channel, Message, User } from "@vencord/discord-types"; import { Channel, Message, User } from "@vencord/discord-types";
import { ChannelStore, Constants, Menu, NavigationRouter, RestAPI, SelectedChannelStore, SelectedGuildStore, Toasts } from "@webpack/common"; import { ChannelStore, Constants, Menu, NavigationRouter, RestAPI, SelectedChannelStore, SelectedGuildStore, showToast } from "@webpack/common";
function jumpToFirstMessage(channelId: string, guildId?: string | null) { function jumpToFirstMessage(channelId: string, guildId?: string | null) {
NavigationRouter.transitionTo(`/channels/${guildId ?? "@me"}/${channelId}/0`); NavigationRouter.transitionTo(`/channels/${guildId ?? "@me"}/${channelId}/0`);
@ -38,21 +38,13 @@ async function jumpToUserMessage(channelId: string, guildId: string, userId: str
const messageId = res.body?.messages?.[0]?.[0]?.id; const messageId = res.body?.messages?.[0]?.[0]?.id;
if (!messageId) { if (!messageId) {
Toasts.show({ showToast("No messages found from this user in this channel.", "failure");
type: Toasts.Type.FAILURE,
message: "No messages found from this user in this channel.",
id: Toasts.genId()
});
return; return;
} }
NavigationRouter.transitionTo(`/channels/${guildId}/${channelId}/${messageId}`); NavigationRouter.transitionTo(`/channels/${guildId}/${channelId}/${messageId}`);
} catch (e) { } catch (e) {
Toasts.show({ showToast("Failed to search for messages.", "failure");
type: Toasts.Type.FAILURE,
message: "Failed to search for messages.",
id: Toasts.genId()
});
} }
} }

View file

@ -10,7 +10,8 @@ import { gitHashShort } from "@shared/vencordUserAgent";
import { copyToClipboard } from "@utils/clipboard"; import { copyToClipboard } from "@utils/clipboard";
import { relaunch, showItemInFolder } from "@utils/native"; import { relaunch, showItemInFolder } from "@utils/native";
import { checkForUpdates, getRepo } from "@utils/updater"; import { checkForUpdates, getRepo } from "@utils/updater";
import { GuildStore, NavigationRouter, SettingsRouter, Toasts } from "@webpack/common"; import { ToastPosition } from "@vencord/discord-types/enums";
import { GuildStore, NavigationRouter, SettingsRouter, showToast } from "@webpack/common";
import gitRemote from "~git-remote"; import gitRemote from "~git-remote";
import Plugins from "~plugins"; import Plugins from "~plugins";
@ -46,14 +47,9 @@ export const actions: ButtonAction[] = [
new URL(newUrl); // Throws if invalid new URL(newUrl); // Throws if invalid
VencordNative.native.openExternal(newUrl); VencordNative.native.openExternal(newUrl);
} catch { } catch {
Toasts.show({ showToast("Invalid URL", "failure", {
message: "Invalid URL", position: ToastPosition.BOTTOM
type: Toasts.Type.FAILURE, });
id: Toasts.genId(),
options: {
position: Toasts.Position.BOTTOM
}
});
} }
}, registrar: "Equicord" }, registrar: "Equicord"
}, },
@ -92,24 +88,14 @@ export const actions: ButtonAction[] = [
const text = await res.text(); const text = await res.text();
copyToClipboard(text); copyToClipboard(text);
Toasts.show({ showToast("Copied response to clipboard!", "success", {
message: "Copied response to clipboard!", position: ToastPosition.BOTTOM
type: Toasts.Type.SUCCESS, });
id: Toasts.genId(),
options: {
position: Toasts.Position.BOTTOM
}
});
} catch (e) { } catch (e) {
Toasts.show({ showToast("Issue fetching URL", "failure", {
message: "Issue fetching URL", position: ToastPosition.BOTTOM
type: Toasts.Type.FAILURE, });
id: Toasts.genId(),
options: {
position: Toasts.Position.BOTTOM
}
});
} }
}, registrar: "Equicord" }, registrar: "Equicord"
}, },
@ -118,14 +104,9 @@ export const actions: ButtonAction[] = [
id: "copyGitInfo", label: "Copy Git Info", callback: async () => { id: "copyGitInfo", label: "Copy Git Info", callback: async () => {
copyToClipboard(`gitHash: ${gitHashShort}\ngitRemote: ${gitRemote}`); copyToClipboard(`gitHash: ${gitHashShort}\ngitRemote: ${gitRemote}`);
Toasts.show({ showToast("Copied git info to clipboard!", "success", {
message: "Copied git info to clipboard!", position: ToastPosition.BOTTOM
type: Toasts.Type.SUCCESS, });
id: Toasts.genId(),
options: {
position: Toasts.Position.BOTTOM
}
});
}, registrar: "Equicord" }, registrar: "Equicord"
}, },
@ -144,14 +125,9 @@ export const actions: ButtonAction[] = [
} }
}), 10_000); }), 10_000);
} else { } else {
Toasts.show({ showToast("No updates available", "message", {
message: "No updates available", position: ToastPosition.BOTTOM
type: Toasts.Type.MESSAGE, });
id: Toasts.genId(),
options: {
position: Toasts.Position.BOTTOM
}
});
} }
}, registrar: "Equicord" }, registrar: "Equicord"
}, },
@ -181,14 +157,9 @@ function togglePlugin(plugin: ButtonAction, enabled: boolean) {
Settings.plugins[plugin.id].enabled = enabled; Settings.plugins[plugin.id].enabled = enabled;
Toasts.show({ showToast(`Successfully ${enabled ? "enabled" : "disabled"} ${plugin.id}`, "success", {
message: `Successfully ${enabled ? "enabled" : "disabled"} ${plugin.id}`, position: ToastPosition.BOTTOM
type: Toasts.Type.SUCCESS, });
id: Toasts.genId(),
options: {
position: Toasts.Position.BOTTOM
}
});
} }
export function registerAction(action: ButtonAction) { export function registerAction(action: ButtonAction) {

View file

@ -8,7 +8,7 @@ import { NavContextMenuPatchCallback } from "@api/ContextMenu";
import { EquicordDevs } from "@utils/constants"; import { EquicordDevs } from "@utils/constants";
import definePlugin from "@utils/types"; import definePlugin from "@utils/types";
import { Channel } from "@vencord/discord-types"; import { Channel } from "@vencord/discord-types";
import { Menu, NavigationRouter, RestAPI, Toasts, UserStore } from "@webpack/common"; import { Menu, NavigationRouter, RestAPI, showToast,UserStore } from "@webpack/common";
async function findLastMessageFromUser(guildId: string, channelId: string, userId: string) { async function findLastMessageFromUser(guildId: string, channelId: string, userId: string) {
try { try {
@ -33,29 +33,17 @@ async function findLastMessageFromUser(guildId: string, channelId: string, userI
if (messageId) return messageId; if (messageId) return messageId;
} catch (error) { } catch (error) {
console.error("Error finding last message:", error); console.error("Error finding last message:", error);
Toasts.show({ showToast("Failed to find messages. Check console for details.", "failure");
type: Toasts.Type.FAILURE,
message: "Failed to find messages. Check console for details.",
id: Toasts.genId()
});
return null; return null;
} }
Toasts.show({ showToast("Couldn't find any recent messages from this user.", "failure");
type: Toasts.Type.FAILURE,
message: "Couldn't find any recent messages from this user.",
id: Toasts.genId()
});
return null; return null;
} }
async function jumpToLastActive(channel: Channel, targetUserId?: string) { async function jumpToLastActive(channel: Channel, targetUserId?: string) {
if (!channel) { if (!channel) {
Toasts.show({ showToast("Channel information not available.", "failure");
type: Toasts.Type.FAILURE,
message: "Channel information not available.",
id: Toasts.genId()
});
return; return;
} }
@ -69,11 +57,7 @@ async function jumpToLastActive(channel: Channel, targetUserId?: string) {
} }
} catch (error) { } catch (error) {
console.error("Error in jumpToLastActive:", error); console.error("Error in jumpToLastActive:", error);
Toasts.show({ showToast("Failed to jump to message. Check console for details.", "failure");
type: Toasts.Type.FAILURE,
message: "Failed to jump to message. Check console for details.",
id: Toasts.genId()
});
} }
} }

View file

@ -97,17 +97,19 @@ export default definePlugin({
], ],
MentionTooltip({ Component, vcProps, ...props }) { MentionTooltip({ Component, vcProps, ...props }) {
return withTooltip(Component, props, vcProps.messageId, vcProps.channelId); return withTooltip(Component, props, vcProps?.messageId, vcProps?.channelId);
}, },
ReplyTooltip({ Component, vcProps, ...props }) { ReplyTooltip({ Component, vcProps, ...props }) {
const mess = vcProps.baseMessage.messageReference; const messageReference = vcProps?.baseMessage?.messageReference;
return withTooltip(Component, props, mess?.message_id, mess?.channel_id); if (!messageReference) return <Component {...props} />;
return withTooltip(Component, props, messageReference?.message_id, messageReference?.channel_id);
}, },
ForwardTooltip({ Component, vcProps, ...props }) { ForwardTooltip({ Component, vcProps, ...props }) {
const mess = vcProps.message.messageReference; const messageReference = vcProps?.message?.messageReference;
return withTooltip(Component, props, mess?.message_id, mess?.channel_id); if (!messageReference) return <Component {...props} />;
return withTooltip(Component, props, messageReference?.message_id, messageReference?.channel_id);
}, },
}); });

View file

@ -5,7 +5,7 @@
*/ */
import { Button } from "@components/Button"; import { Button } from "@components/Button";
import { Alerts, Toasts, useState } from "@webpack/common"; import { Alerts, showToast,useState } from "@webpack/common";
import { clearMessagesIDB } from "../db"; import { clearMessagesIDB } from "../db";
import { Flogger } from "../index"; import { Flogger } from "../index";
@ -33,18 +33,10 @@ export function ClearLogsButton({ label = "Clear Logs", onCleared }: ClearLogsBu
try { try {
await clearMessagesIDB(); await clearMessagesIDB();
onCleared?.(); onCleared?.();
Toasts.show({ showToast("Cleared Logs", "success");
id: Toasts.genId(),
message: "Cleared Logs",
type: Toasts.Type.SUCCESS
});
} catch (err) { } catch (err) {
Flogger.error("Failed to clear logs", err); Flogger.error("Failed to clear logs", err);
Toasts.show({ showToast("Failed to clear logs", "failure");
id: Toasts.genId(),
message: "Failed to clear logs",
type: Toasts.Type.FAILURE
});
} finally { } finally {
setLoading(false); setLoading(false);
} }

View file

@ -23,7 +23,7 @@ import { DEFAULT_IMAGE_CACHE_DIR } from "@equicordplugins/messageLoggerEnhanced/
import { copyWithToast } from "@utils/discord"; import { copyWithToast } from "@utils/discord";
import { classes } from "@utils/misc"; import { classes } from "@utils/misc";
import { findCssClassesLazy } from "@webpack"; import { findCssClassesLazy } from "@webpack";
import { Toasts } from "@webpack/common"; import { showToast } from "@webpack/common";
const inputClasses = findCssClassesLazy("input", "inputWrapper", "editable") as Record<string, string>; const inputClasses = findCssClassesLazy("input", "inputWrapper", "editable") as Record<string, string>;
@ -65,17 +65,9 @@ export function SelectFolderInput({ settingsKey, successMessage }: Props) {
const res = await Native.chooseDir(settingsKey); const res = await Native.chooseDir(settingsKey);
settings.store[settingsKey] = res; settings.store[settingsKey] = res;
return Toasts.show({ return showToast(successMessage, "success");
id: Toasts.genId(),
type: Toasts.Type.SUCCESS,
message: successMessage
});
} catch (err) { } catch (err) {
Toasts.show({ showToast("Failed to update directory", "failure");
id: Toasts.genId(),
type: Toasts.Type.FAILURE,
message: "Failed to update directory"
});
} }
} }

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: GPL-3.0-or-later * SPDX-License-Identifier: GPL-3.0-or-later
*/ */
import { ChannelStore, Toasts } from "@webpack/common"; import { ChannelStore, showToast } from "@webpack/common";
import { DBSchema, IDBPDatabase, openDB } from "idb"; import { DBSchema, IDBPDatabase, openDB } from "idb";
import { LoggedMessageJSON } from "./types"; import { LoggedMessageJSON } from "./types";
@ -256,7 +256,7 @@ export async function deleteMessagesBulkIDB(message_ids: string[]) {
message_ids.forEach(id => cachedMessages.delete(id)); message_ids.forEach(id => cachedMessages.delete(id));
} }
export async function clearMessagesIDB(showToast = true) { export async function clearMessagesIDB(toast = true) {
cachedMessages.clear(); cachedMessages.clear();
const deleted = await new Promise<boolean>(resolve => { const deleted = await new Promise<boolean>(resolve => {
@ -271,13 +271,9 @@ export async function clearMessagesIDB(showToast = true) {
cachedMessages.clear(); cachedMessages.clear();
if (!showToast) return; if (!toast) return;
Toasts.show({ showToast("Cleared message log database and cache.", "message");
type: Toasts.Type.MESSAGE,
message: "Cleared message log database and cache.",
id: Toasts.genId()
});
} }
// faster than db.clear on large dbs // faster than db.clear on large dbs

View file

@ -41,8 +41,8 @@ let didClearLogsOnStartup = false;
const cacheThing = findByPropsLazy("commit", "getOrCreate"); const cacheThing = findByPropsLazy("commit", "getOrCreate");
export async function clearLogs(showToast = true) { export async function clearLogs(toast = true) {
await idb.clearMessagesIDB(showToast); await idb.clearMessagesIDB(toast);
cacheSentMessages.clear(); cacheSentMessages.clear();
} }

View file

@ -6,7 +6,7 @@
import { addContextMenuPatch, NavContextMenuPatchCallback, removeContextMenuPatch } from "@api/ContextMenu"; import { addContextMenuPatch, NavContextMenuPatchCallback, removeContextMenuPatch } from "@api/ContextMenu";
import { updateMessage } from "@api/MessageUpdater"; import { updateMessage } from "@api/MessageUpdater";
import { FluxDispatcher, Menu, MessageActions, React, SortedGuildStore, Toasts, UserStore } from "@webpack/common"; import { FluxDispatcher, Menu, MessageActions, React, showToast,SortedGuildStore, UserStore } from "@webpack/common";
import { openLogModal } from "../components/LogsModal"; import { openLogModal } from "../components/LogsModal";
import { deleteMessageIDB } from "../db"; import { deleteMessageIDB } from "../db";
@ -80,11 +80,7 @@ const removeMessageAction = async (props: any) => {
} }
} catch (e) { } catch (e) {
console.error("Failed to remove message", e); console.error("Failed to remove message", e);
Toasts.show({ showToast("Failed to remove message. Check console for details.", "failure");
type: Toasts.Type.FAILURE,
message: "Failed to remove message. Check console for details.",
id: Toasts.genId()
});
} }
}; };

View file

@ -18,7 +18,7 @@
import JSONParser from "@streamparser/json/jsonparser.js"; import JSONParser from "@streamparser/json/jsonparser.js";
import { chooseFile as chooseFileWeb } from "@utils/web"; import { chooseFile as chooseFileWeb } from "@utils/web";
import { Toasts } from "@webpack/common"; import { showToast } from "@webpack/common";
import { showSaveFilePicker } from "native-file-system-adapter"; import { showSaveFilePicker } from "native-file-system-adapter";
import { clearLogs,Native } from ".."; import { clearLogs,Native } from "..";
@ -60,27 +60,15 @@ export async function importLogs() {
} }
if (count === 0) { if (count === 0) {
Toasts.show({ showToast("No messages found in log file", "failure");
id: Toasts.genId(),
message: "No messages found in log file",
type: Toasts.Type.FAILURE
});
return; return;
} }
Toasts.show({ showToast(`Successfully imported ${count} logs`, "success");
id: Toasts.genId(),
message: `Successfully imported ${count} logs`,
type: Toasts.Type.SUCCESS
});
} catch (e) { } catch (e) {
console.error(e); console.error(e);
Toasts.show({ showToast("Error importing logs. Check the console for more information", "failure");
id: Toasts.genId(),
message: "Error importing logs. Check the console for more information",
type: Toasts.Type.FAILURE
});
} }
} }
@ -106,11 +94,7 @@ export async function exportLogs() {
await Native.writeNativeLogChunk(streamId, "\n ]\n}"); await Native.writeNativeLogChunk(streamId, "\n ]\n}");
await Native.finishNativeLogExport(streamId); await Native.finishNativeLogExport(streamId);
Toasts.show({ showToast("Successfully exported logs", "success");
id: Toasts.genId(),
message: "Successfully exported logs",
type: Toasts.Type.SUCCESS
});
return; return;
} }
@ -143,20 +127,12 @@ export async function exportLogs() {
await writer.write(encoder.encode("\n ]\n}")); await writer.write(encoder.encode("\n ]\n}"));
await writer.close(); await writer.close();
Toasts.show({ showToast(`Successfully exported ${count} logs`, "success");
id: Toasts.genId(),
message: `Successfully exported ${count} logs`,
type: Toasts.Type.SUCCESS
});
} }
} catch (e) { } catch (e) {
console.error(e); console.error(e);
Toasts.show({ showToast("Error exporting logs. Check the console for more information", "failure");
id: Toasts.genId(),
message: "Error exporting logs. Check the console for more information",
type: Toasts.Type.FAILURE
});
} }
} }

View file

@ -17,7 +17,7 @@ import { isV1, migrate } from "@equicordplugins/moreStickers/migrate-v1";
import { deleteStickerPack, getStickerPack, getStickerPackMetas, saveStickerPack } from "@equicordplugins/moreStickers/stickers"; import { deleteStickerPack, getStickerPack, getStickerPackMetas, saveStickerPack } from "@equicordplugins/moreStickers/stickers";
import { SettingsTabsKey, Sticker, StickerPack, StickerPackMeta } from "@equicordplugins/moreStickers/types"; import { SettingsTabsKey, Sticker, StickerPack, StickerPackMeta } from "@equicordplugins/moreStickers/types";
import { cl, clPicker, Mutex } from "@equicordplugins/moreStickers/utils"; import { cl, clPicker, Mutex } from "@equicordplugins/moreStickers/utils";
import { Button, React, TabBar, TextArea, Toasts } from "@webpack/common"; import { Button, React, showToast,TabBar, TextArea } from "@webpack/common";
import { JSX } from "react"; import { JSX } from "react";
const mutex = new Mutex(); const mutex = new Mutex();
@ -58,24 +58,14 @@ const StickerPackMetadata = ({ meta, hoveredStickerPackId, setHoveredStickerPack
onClick={async () => { onClick={async () => {
try { try {
await deleteStickerPack(meta.id); await deleteStickerPack(meta.id);
Toasts.show({ showToast("Sticker Pack deleted", "success", {
message: "Sticker Pack deleted",
type: Toasts.Type.SUCCESS,
id: Toasts.genId(),
options: {
duration: 1000 duration: 1000
} });
});
await refreshStickerPackMetas(); await refreshStickerPackMetas();
} catch (e: any) { } catch (e: any) {
Toasts.show({ showToast(e.message, "failure", {
message: e.message,
type: Toasts.Type.FAILURE,
id: Toasts.genId(),
options: {
duration: 1000 duration: 1000
} });
});
} }
}} }}
> >
@ -210,23 +200,13 @@ export const Packs = () => {
refreshStickerPackMetas(); refreshStickerPackMetas();
if (errorMessage) { if (errorMessage) {
Toasts.show({ showToast(errorMessage, "failure", {
message: errorMessage,
type: Toasts.Type.FAILURE,
id: Toasts.genId(),
options: {
duration: 1000 duration: 1000
} });
});
} else { } else {
Toasts.show({ showToast("Sticker Pack added", "success", {
message: "Sticker Pack added",
type: Toasts.Type.SUCCESS,
id: Toasts.genId(),
options: {
duration: 1000 duration: 1000
} });
});
} }
}} }}
@ -288,23 +268,13 @@ export const Packs = () => {
refreshStickerPackMetas(); refreshStickerPackMetas();
if (errorMessage) { if (errorMessage) {
Toasts.show({ showToast(errorMessage, "failure", {
message: errorMessage,
type: Toasts.Type.FAILURE,
id: Toasts.genId(),
options: {
duration: 1000 duration: 1000
} });
});
} else { } else {
Toasts.show({ showToast("Sticker Pack added", "success", {
message: "Sticker Pack added",
type: Toasts.Type.SUCCESS,
id: Toasts.genId(),
options: {
duration: 1000 duration: 1000
} });
});
} }
}} }}
>Insert from HTML</Button> >Insert from HTML</Button>
@ -340,24 +310,14 @@ export const Packs = () => {
await saveStickerPack(stickerPack); await saveStickerPack(stickerPack);
} }
Toasts.show({ showToast("Sticker Packs added", "success", {
message: "Sticker Packs added",
type: Toasts.Type.SUCCESS,
id: Toasts.genId(),
options: {
duration: 1000 duration: 1000
} });
});
} catch (e: any) { } catch (e: any) {
console.error(e); console.error(e);
Toasts.show({ showToast(e.message, "failure", {
message: e.message,
type: Toasts.Type.FAILURE,
id: Toasts.genId(),
options: {
duration: 1000 duration: 1000
} });
});
} }
}; };
input.click(); input.click();
@ -395,14 +355,9 @@ export const Packs = () => {
a.click(); a.click();
setTimeout(() => URL.revokeObjectURL(objectUrl), 1000); setTimeout(() => URL.revokeObjectURL(objectUrl), 1000);
Toasts.show({ showToast("Sticker Packs exported", "success", {
message: "Sticker Packs exported",
type: Toasts.Type.SUCCESS,
id: Toasts.genId(),
options: {
duration: 1000 duration: 1000
} });
});
}} }}
>Export Sticker Packs</Button> >Export Sticker Packs</Button>
<Button <Button

View file

@ -5,7 +5,7 @@
*/ */
import { DataStore } from "@api/index"; import { DataStore } from "@api/index";
import { Toasts } from "@webpack/common"; import { showToast } from "@webpack/common";
import { getRecentStickers, setRecentStickers } from "./components/misc"; import { getRecentStickers, setRecentStickers } from "./components/misc";
import { deleteStickerPack, getStickerPack, getStickerPackMetas, saveStickerPack } from "./stickers"; import { deleteStickerPack, getStickerPack, getStickerPackMetas, saveStickerPack } from "./stickers";
@ -74,27 +74,17 @@ export async function isV1() {
export async function migrate() { export async function migrate() {
const newPackMetas = await getStickerPackMetas(PACKS_KEY); const newPackMetas = await getStickerPackMetas(PACKS_KEY);
if (newPackMetas.length > 0) { if (newPackMetas.length > 0) {
Toasts.show({ showToast("New sticker packs already exist, migration not needed", "failure", {
message: "New sticker packs already exist, migration not needed",
type: Toasts.Type.FAILURE,
id: Toasts.genId(),
options: {
duration: 1000 duration: 1000
} });
});
return; return;
} }
let oldPackMetas = await getStickerPackMetas(PACKS_KEY_OLD); let oldPackMetas = await getStickerPackMetas(PACKS_KEY_OLD);
if (oldPackMetas.length === 0) { if (oldPackMetas.length === 0) {
Toasts.show({ showToast("Old sticker packs not found, nothing to migrate", "failure", {
message: "Old sticker packs not found, nothing to migrate",
type: Toasts.Type.FAILURE,
id: Toasts.genId(),
options: {
duration: 1000 duration: 1000
} });
});
return; return;
} }
@ -112,14 +102,9 @@ export async function migrate() {
} }
} catch (e) { } catch (e) {
console.error(e); console.error(e);
Toasts.show({ showToast(`Migration failed: ${oldStickerPackMeta.title} (${oldStickerPackMeta.id})`, "failure", {
message: `Migration failed: ${oldStickerPackMeta.title} (${oldStickerPackMeta.id})`,
type: Toasts.Type.FAILURE,
id: Toasts.genId(),
options: {
duration: 1000 duration: 1000
} });
});
} }
} }
@ -136,12 +121,7 @@ export async function migrate() {
} }
console.log("Migration complete"); console.log("Migration complete");
Toasts.show({ showToast("Sticker Pack Migration Complete", "success", {
message: "Sticker Pack Migration Complete",
type: Toasts.Type.SUCCESS,
id: Toasts.genId(),
options: {
duration: 1000 duration: 1000
} });
});
} }

View file

@ -8,7 +8,7 @@ import { getMimeFromExtension } from "@equicordplugins/fileUpload/utils/getMedia
import { FFmpeg } from "@ffmpeg/ffmpeg"; import { FFmpeg } from "@ffmpeg/ffmpeg";
import { insertTextIntoChatInputBox, MessageOptions } from "@utils/discord"; import { insertTextIntoChatInputBox, MessageOptions } from "@utils/discord";
import { CloudUploadPlatform } from "@vencord/discord-types/enums"; import { CloudUploadPlatform } from "@vencord/discord-types/enums";
import { ChannelStore, CloudUploader, Constants, DraftStore, FluxDispatcher, MessageActions, PendingReplyStore, RestAPI, showToast, SnowflakeUtils, Toasts, UploadHandler } from "@webpack/common"; import { ChannelStore, CloudUploader, Constants, DraftStore, FluxDispatcher, MessageActions, PendingReplyStore, RestAPI, showToast, SnowflakeUtils, UploadHandler } from "@webpack/common";
import { settings } from "."; import { settings } from ".";
import { FFmpegState, Sticker } from "./types"; import { FFmpegState, Sticker } from "./types";
@ -169,7 +169,7 @@ export async function sendSticker({ channelId, sticker, ctrlKey, shiftKey, ffmpe
}); });
}); });
upload.on("error", () => showToast("Failed to upload sticker", Toasts.Type.FAILURE)); upload.on("error", () => showToast("Failed to upload sticker", "failure"));
upload.upload(); upload.upload();
} }

View file

@ -11,7 +11,7 @@ import { HeadingSecondary } from "@components/Heading";
import { Paragraph } from "@components/Paragraph"; import { Paragraph } from "@components/Paragraph";
import { SettingsSection } from "@components/settings/tabs/plugins/components/Common"; import { SettingsSection } from "@components/settings/tabs/plugins/components/Common";
import { makeRange, OptionType } from "@utils/types"; import { makeRange, OptionType } from "@utils/types";
import { MaskedLink, Select, showToast, TextInput, Toasts } from "@webpack/common"; import { MaskedLink, Select, showToast, TextInput } from "@webpack/common";
import hoverOnlyStyle from "./hoverOnly.css?managed"; import hoverOnlyStyle from "./hoverOnly.css?managed";
import { clearLyricsCache, removeTranslations } from "./spotify/lyrics/api"; import { clearLyricsCache, removeTranslations } from "./spotify/lyrics/api";
@ -66,7 +66,7 @@ function LyricsProviderSettings() {
onChange={v => { onChange={v => {
settings.store.spotifyLyricsApiUrl = v; settings.store.spotifyLyricsApiUrl = v;
void clearLyricsCache(); void clearLyricsCache();
showToast("Lyrics cache purged", Toasts.Type.SUCCESS); showToast("Lyrics cache purged", "success");
}} }}
placeholder="https://spotify-lyrics-api-pi.vercel.app" placeholder="https://spotify-lyrics-api-pi.vercel.app"
maxLength={null} maxLength={null}
@ -113,7 +113,7 @@ export const settings = definePluginSettings({
default: "https://spotify-lyrics-api-pi.vercel.app", default: "https://spotify-lyrics-api-pi.vercel.app",
onChange: async () => { onChange: async () => {
await clearLyricsCache(); await clearLyricsCache();
showToast("Lyrics cache purged", Toasts.Type.SUCCESS); showToast("Lyrics cache purged", "success");
} }
}, },
lyricsProviderSettings: { lyricsProviderSettings: {
@ -126,7 +126,7 @@ export const settings = definePluginSettings({
options: languages, options: languages,
onChange: async () => { onChange: async () => {
await removeTranslations(); await removeTranslations();
showToast("Translations cleared", Toasts.Type.SUCCESS); showToast("Translations cleared", "success");
} }
}, },
lyricsConversion: { lyricsConversion: {
@ -162,7 +162,7 @@ export const settings = definePluginSettings({
color={ButtonCompat.Colors.RED} color={ButtonCompat.Colors.RED}
onClick={() => { onClick={() => {
clearLyricsCache(); clearLyricsCache();
showToast("Lyrics cache purged", Toasts.Type.SUCCESS); showToast("Lyrics cache purged", "success");
}} }}
> >
Purge Cache Purge Cache

View file

@ -7,7 +7,7 @@
import { definePluginSettings } from "@api/Settings"; import { definePluginSettings } from "@api/Settings";
import { EquicordDevs } from "@utils/constants"; import { EquicordDevs } from "@utils/constants";
import definePlugin, { OptionType } from "@utils/types"; import definePlugin, { OptionType } from "@utils/types";
import { ChannelStore, FluxDispatcher, GuildMemberStore, StreamerModeStore, Toasts, UserStore, VoiceStateStore } from "@webpack/common"; import { ChannelStore, FluxDispatcher, GuildMemberStore, showToast,StreamerModeStore, UserStore, VoiceStateStore } from "@webpack/common";
interface ChannelState { interface ChannelState {
userId: string; userId: string;
@ -211,11 +211,7 @@ const createWebsocket = () => {
setTimeout(() => { setTimeout(() => {
if (ws?.readyState !== WebSocket.OPEN) { if (ws?.readyState !== WebSocket.OPEN) {
Toasts.show({ showToast("Orbolay websocket could not connect. Is it running?", "failure");
message: "Orbolay websocket could not connect. Is it running?",
type: Toasts.Type.FAILURE,
id: Toasts.genId(),
});
ws = null; ws = null;
return; return;
} }
@ -235,11 +231,7 @@ const createWebsocket = () => {
ws = null; ws = null;
}; };
ws.onopen = async () => { ws.onopen = async () => {
Toasts.show({ showToast("Connected to Orbolay server", "success");
message: "Connected to Orbolay server",
type: Toasts.Type.SUCCESS,
id: Toasts.genId(),
});
const userId = await waitForPopulate(() => UserStore.getCurrentUser().id); const userId = await waitForPopulate(() => UserStore.getCurrentUser().id);
if (!userId) return; if (!userId) return;

View file

@ -6,7 +6,7 @@
import { isNonNullish } from "@utils/guards"; import { isNonNullish } from "@utils/guards";
import { ProfilePreset } from "@vencord/discord-types"; import { ProfilePreset } from "@vencord/discord-types";
import { showToast, Toasts, UserProfileSettingsStore } from "@webpack/common"; import { showToast, UserProfileSettingsStore } from "@webpack/common";
import { getCurrentProfile } from "./profile"; import { getCurrentProfile } from "./profile";
import { addPreset, movePresetInArray, presets, PresetSection, type ProfilePresetEx, removePreset, replaceAllPresets, savePresetsData, updatePreset } from "./storage"; import { addPreset, movePresetInArray, presets, PresetSection, type ProfilePresetEx, removePreset, replaceAllPresets, savePresetsData, updatePreset } from "./storage";
@ -133,7 +133,7 @@ export async function importPresets(
await savePresetsData(section); await savePresetsData(section);
forceUpdate(); forceUpdate();
} catch { } catch {
showToast("Failed to import presets. The file might be invalid.", Toasts.Type.FAILURE); showToast("Failed to import presets. The file might be invalid.", "failure");
} }
}; };
input.click(); input.click();

View file

@ -239,8 +239,8 @@ export default definePlugin({
find: "collapsed-with-rewards\":\"collapsed-without-rewards", find: "collapsed-with-rewards\":\"collapsed-without-rewards",
predicate: () => getQuestifySettings().disableAccountPanelPromo || !getQuestifySettings().disableAccountPanelQuestProgress, predicate: () => getQuestifySettings().disableAccountPanelPromo || !getQuestifySettings().disableAccountPanelQuestProgress,
replacement: { replacement: {
match: /(?<=function\(\)\{)(let (\i)=\(0,\i\.\i\)\(\)(?:,\i=\(0,\i\.\i\)\(.{0,55}?\))?;)(?=return null==\2(?:&&null!=\i)?\?)/, match: /(?<=function\(\)\{)(let (\i)=\(0,\i\.\i\)\(\),\i=\(0,\i\.\i\)\(.{0,55}?\);)(?=switch\(\2\.type\)\{case (\i\.\i\.QUEST):)/,
replace: "void $self.useQuestRerender();$1$2=$self.getQuestPanelOverride($2);" replace: "void $self.useQuestRerender();$1$2=$self.getQuestPanelOverride($2,$3);if(null==$2)return null;"
} }
}, },
{ {
@ -484,7 +484,7 @@ export default definePlugin({
}, },
{ {
// Adds the Questify sort option to Discord's Quest sort enum. // Adds the Questify sort option to Discord's Quest sort enum.
find: "SUGGESTED=\"suggested\",", find: "EXPIRING_SOON=\"expiring_soon\"",
predicate: () => !getQuestifySettings().disableQuestsEverything, predicate: () => !getQuestifySettings().disableQuestsEverything,
replacement: { replacement: {
match: /(?<=\(\((\i)=\{\}\))(?=\.SUGGESTED="suggested",)/, match: /(?<=\(\((\i)=\{\}\))(?=\.SUGGESTED="suggested",)/,

View file

@ -8,7 +8,7 @@ import type { PluginNative } from "@utils/types";
import type { Quest, User } from "@vencord/discord-types"; import type { Quest, User } from "@vencord/discord-types";
import { QuestTargetedContent, QuestTaskType } from "@vencord/discord-types/enums"; import { QuestTargetedContent, QuestTaskType } from "@vencord/discord-types/enums";
import { findByCodeLazy, findLazy } from "@webpack"; import { findByCodeLazy, findLazy } from "@webpack";
import { AuthorizedAppsStore, FluxDispatcher, QuestStore, RestAPI, showToast, Toasts, UserStore } from "@webpack/common"; import { AuthorizedAppsStore, FluxDispatcher, QuestStore, RestAPI, showToast, UserStore } from "@webpack/common";
import { getCurrentUserId, getQuestifySettings } from "../settings/access"; import { getCurrentUserId, getQuestifySettings } from "../settings/access";
import { autoCompleteQuestTaskTypes, isDesktopCompatible } from "../settings/def"; import { autoCompleteQuestTaskTypes, isDesktopCompatible } from "../settings/def";
@ -251,7 +251,7 @@ function showBrokenAutoCompleteToast(): void {
} }
didShowBrokenAutoCompleteToast = true; didShowBrokenAutoCompleteToast = true;
showToast("AutoComplete is broken. A fix will be implemented shortly.", Toasts.Type.FAILURE); showToast("AutoComplete is broken. A fix will be implemented shortly.", "failure");
} }
export function hasEnabledAutoCompleteQuestTypes(): boolean { export function hasEnabledAutoCompleteQuestTypes(): boolean {
@ -613,7 +613,7 @@ function blockQuestEnrollmentForRetryAfter(retryAfter: number | null): void {
function showQuestEnrollmentFailureToast(quest: Quest, result: Exclude<QuestEnrollmentResult, { type: "success"; }>): void { function showQuestEnrollmentFailureToast(quest: Quest, result: Exclude<QuestEnrollmentResult, { type: "success"; }>): void {
const rateLimitSuffix = result.type === "rate_limited" ? " due to rate limits" : ""; const rateLimitSuffix = result.type === "rate_limited" ? " due to rate limits" : "";
showToast(`Enrollment in ${normalizeQuestName(quest)} Quest failed${rateLimitSuffix}.`, Toasts.Type.FAILURE); showToast(`Enrollment in ${normalizeQuestName(quest)} Quest failed${rateLimitSuffix}.`, "failure");
} }
export async function enrollInQuestManually(quest: Quest): Promise<QuestManualEnrollResult> { export async function enrollInQuestManually(quest: Quest): Promise<QuestManualEnrollResult> {

View file

@ -43,6 +43,11 @@ const questProgressTaskPriority = [
QuestTaskType.PLAY_ON_XBOX, QuestTaskType.PLAY_ON_XBOX,
] as const satisfies readonly QuestTaskType[]; ] as const satisfies readonly QuestTaskType[];
interface QuestPanelCreative {
type: number;
quest?: Quest;
}
interface QuestPanelPercentCompleteOptions { interface QuestPanelPercentCompleteOptions {
quest?: Quest | null; quest?: Quest | null;
percentCompleteText?: string; percentCompleteText?: string;
@ -215,7 +220,7 @@ function getMostRecentlyCompletedUnclaimedQuest(): Quest | null {
})[0] ?? null; })[0] ?? null;
} }
export function getQuestPanelOverride(quest: Quest | null): Quest | null { export function getQuestPanelOverride(creative: QuestPanelCreative, questType: number): QuestPanelCreative | null {
const panelState = useQuestifySettings(["disableQuestsEverything", "disableAccountPanelPromo", "disableAccountPanelQuestProgress"]); const panelState = useQuestifySettings(["disableQuestsEverything", "disableAccountPanelPromo", "disableAccountPanelQuestProgress"]);
if (panelState.disableQuestsEverything) { if (panelState.disableQuestsEverything) {
@ -227,12 +232,16 @@ export function getQuestPanelOverride(quest: Quest | null): Quest | null {
} }
if (panelState.disableAccountPanelQuestProgress) { if (panelState.disableAccountPanelQuestProgress) {
return quest; return creative;
} }
const nextQuest = getAutoCompleteShowcaseQuest() ?? getMostRecentlyCompletedUnclaimedQuest(); const nextQuest = getAutoCompleteShowcaseQuest() ?? getMostRecentlyCompletedUnclaimedQuest();
return nextQuest ?? (panelState.disableAccountPanelPromo ? null : quest); if (nextQuest) {
return { ...creative, type: questType, quest: nextQuest };
}
return panelState.disableAccountPanelPromo ? null : creative;
} }
export function shouldForceQuestPanelVisible(quest: Quest | null): boolean { export function shouldForceQuestPanelVisible(quest: Quest | null): boolean {

View file

@ -10,7 +10,7 @@ import { Paragraph } from "@components/Paragraph";
import { debounce } from "@shared/debounce"; import { debounce } from "@shared/debounce";
import { Devs, IS_MAC } from "@utils/constants"; import { Devs, IS_MAC } from "@utils/constants";
import definePlugin, { OptionType, StartAt } from "@utils/types"; import definePlugin, { OptionType, StartAt } from "@utils/types";
import { showToast, Toasts } from "@webpack/common"; import { showToast } from "@webpack/common";
const { VencordNative } = window; const { VencordNative } = window;
@ -51,7 +51,7 @@ const refreshThemeList = async (silent = false) => {
const diff = themeList.length - oldCount; const diff = themeList.length - oldCount;
const action = diff > 0 ? "Added" : "Removed"; const action = diff > 0 ? "Added" : "Removed";
const count = Math.abs(diff); const count = Math.abs(diff);
showToast(`${action} ${count} theme${count > 1 ? "s" : ""}`, Toasts.Type.SUCCESS); showToast(`${action} ${count} theme${count > 1 ? "s" : ""}`, "success");
} }
}; };
@ -186,7 +186,7 @@ function toggleCurrentTheme(enable: boolean) {
async function reloadThemes() { async function reloadThemes() {
await refreshThemeList(true); await refreshThemeList(true);
showToast(`Reloaded ${themeList.length} themes`, Toasts.Type.SUCCESS); showToast(`Reloaded ${themeList.length} themes`, "success");
} }
async function watchForLocalThemeChanges() { async function watchForLocalThemeChanges() {
@ -204,7 +204,7 @@ async function watchForLocalThemeChanges() {
if (settings.store.showNotifications) { if (settings.store.showNotifications) {
const action = diff > 0 ? "Added" : "Removed"; const action = diff > 0 ? "Added" : "Removed";
const count = Math.abs(diff); const count = Math.abs(diff);
showToast(`${action} ${count} local theme${count > 1 ? "s" : ""}`, Toasts.Type.SUCCESS); showToast(`${action} ${count} local theme${count > 1 ? "s" : ""}`, "success");
} }
} }

View file

@ -15,9 +15,10 @@ import { debounce } from "@shared/debounce";
import { Devs, EquicordDevs, IS_MAC } from "@utils/constants"; import { Devs, EquicordDevs, IS_MAC } from "@utils/constants";
import { classNameFactory } from "@utils/css"; import { classNameFactory } from "@utils/css";
import definePlugin, { makeRange, OptionType } from "@utils/types"; import definePlugin, { makeRange, OptionType } from "@utils/types";
import type { Channel, VoiceState } from "@vencord/discord-types"; import type { Channel, ToastType, VoiceState } from "@vencord/discord-types";
import { ToastPosition } from "@vencord/discord-types/enums";
import { findByCodeLazy } from "@webpack"; import { findByCodeLazy } from "@webpack";
import { ChannelActions, ChannelRouter, ChannelStore, ContextMenuApi, FluxDispatcher, GuildStore, MediaEngineStore, Menu, PermissionsBits, PermissionStore, React, RelationshipStore, SelectedChannelStore, Toasts, useEffect, UserStore, useState, VoiceActions, VoiceStateStore } from "@webpack/common"; import { ChannelActions, ChannelRouter, ChannelStore, ContextMenuApi, FluxDispatcher, GuildStore, MediaEngineStore, Menu, PermissionsBits, PermissionStore, React, RelationshipStore, SelectedChannelStore, showToast as originalShowToast, useEffect, UserStore, useState, VoiceActions, VoiceStateStore } from "@webpack/common";
const startStream = findByCodeLazy('type:"STREAM_START"'); const startStream = findByCodeLazy('type:"STREAM_START"');
const getDesktopSources = findByCodeLazy("desktop sources"); const getDesktopSources = findByCodeLazy("desktop sources");
@ -372,13 +373,8 @@ const settings = definePluginSettings({
}, },
}); });
function showToast(message: string, type: (typeof Toasts.Type)[keyof typeof Toasts.Type]) { function showToast(message: string, type: ToastType) {
Toasts.show({ originalShowToast(message, type, { position: ToastPosition.BOTTOM });
message,
type,
id: Toasts.genId(),
options: { position: Toasts.Position.BOTTOM },
});
} }
function RandomVoiceIcon({ className }: { className?: string; }) { function RandomVoiceIcon({ className }: { className?: string; }) {
@ -594,13 +590,13 @@ function runAfterVoiceJoin(channelId: string, callbacks: PostJoinAction[]) {
async function joinRandomVoice() { async function joinRandomVoice() {
const channelId = pickRandomChannel(); const channelId = pickRandomChannel();
if (!channelId) { if (!channelId) {
showToast("Failed to find a voice channel.", Toasts.Type.MESSAGE); showToast("Failed to find a voice channel.", "message");
return; return;
} }
const channel = ChannelStore.getChannel(channelId); const channel = ChannelStore.getChannel(channelId);
if (!channel) { if (!channel) {
showToast("Voice channel is unavailable.", Toasts.Type.FAILURE); showToast("Voice channel is unavailable.", "failure");
return; return;
} }

View file

@ -11,7 +11,8 @@ import { definePluginSettings } from "@api/Settings";
import { EquicordDevs, IS_MAC } from "@utils/constants"; import { EquicordDevs, IS_MAC } from "@utils/constants";
import { classNameFactory } from "@utils/css"; import { classNameFactory } from "@utils/css";
import definePlugin, { makeRange, OptionType } from "@utils/types"; import definePlugin, { makeRange, OptionType } from "@utils/types";
import { Button, ChannelRouter, ChannelStore, closeModal, IconUtils, openModal,React, RelationshipStore, SelectedChannelStore, Toasts, UserStore } from "@webpack/common"; import { ToastPosition } from "@vencord/discord-types/enums";
import { Button, ChannelRouter, ChannelStore, closeModal, IconUtils, openModal, React, RelationshipStore, SelectedChannelStore, showToast,UserStore } from "@webpack/common";
const STORAGE_KEY = "RDMSwitch_history"; const STORAGE_KEY = "RDMSwitch_history";
@ -76,7 +77,7 @@ const settings = definePluginSettings({
cycleSnapshot = []; cycleSnapshot = [];
cycleIndex = -1; cycleIndex = -1;
await DataStore.set(STORAGE_KEY, []); await DataStore.set(STORAGE_KEY, []);
Toasts.show({ id: Toasts.genId(), type: Toasts.Type.SUCCESS, message: "Cleared RDMS history" }); showToast("Cleared RDMS history", "success");
}}> }}>
"Clear RDMS History "Clear RDMS History
</Button> </Button>
@ -84,7 +85,6 @@ const settings = definePluginSettings({
} }
}); });
let activeToastId: string | null = null;
let overlayModalKey: string | null = null; let overlayModalKey: string | null = null;
let overlayRerender: (() => void) | null = null; let overlayRerender: (() => void) | null = null;
@ -164,7 +164,6 @@ function endCycleSession() {
cycleSnapshot = []; cycleSnapshot = [];
cycleIndex = -1; cycleIndex = -1;
activeToastId = null;
const visEnd = (settings as any).store?.visualStyle; const visEnd = (settings as any).store?.visualStyle;
if (visEnd === "overlay") unmountOverlay(); if (visEnd === "overlay") unmountOverlay();
@ -319,13 +318,7 @@ function showCycleToast() {
const id = cycleSnapshot[cycleIndex]; const id = cycleSnapshot[cycleIndex];
if (!id) return; if (!id) return;
const { name } = getDisplayForChannel(id); const { name } = getDisplayForChannel(id);
if (!activeToastId) activeToastId = Toasts.genId(); showToast(`Switching to: ${name}`, "message", { position: ToastPosition.BOTTOM, duration: settings.store.toastDurationMs });
Toasts.show({
id: activeToastId,
message: `Switching to: ${name}`,
type: Toasts.Type.MESSAGE,
options: { position: Toasts.Position.BOTTOM, duration: settings.store.toastDurationMs }
});
} }
export default definePlugin({ export default definePlugin({
@ -369,7 +362,6 @@ export default definePlugin({
suppressRdmsWhileCycling = false; suppressRdmsWhileCycling = false;
cycleSnapshot = []; cycleSnapshot = [];
cycleIndex = -1; cycleIndex = -1;
activeToastId = null;
const visEnd = (settings as any).store?.visualStyle; const visEnd = (settings as any).store?.visualStyle;
if (visEnd === "overlay") unmountOverlay(); if (visEnd === "overlay") unmountOverlay();

View file

@ -79,8 +79,8 @@ export default definePlugin({
{ {
find: '"LocalActivityStore"', find: '"LocalActivityStore"',
replacement: { replacement: {
match: /function\(\i\)\{.{0,40}activity:(\i).*?\i\[\i\];/, match: /(function\(\i\)\{.{0,40}activity:(\i).{0,25}=\i),(\i)/,
replace: "$&$self.patchActivity($1);", replace: "$1;$self.patchActivity($2);let $3",
} }
} }
], ],

View file

@ -10,7 +10,7 @@ import { Heading } from "@components/Heading";
import { classNameFactory } from "@utils/css"; import { classNameFactory } from "@utils/css";
import { RenderModalProps } from "@vencord/discord-types"; import { RenderModalProps } from "@vencord/discord-types";
import { findByPropsLazy } from "@webpack"; import { findByPropsLazy } from "@webpack";
import { ChannelStore, closeModal, DraftType, Modal, openModal, showToast, TextInput, Toasts, UploadManager, useState } from "@webpack/common"; import { ChannelStore, closeModal, DraftType, Modal, openModal, showToast, TextInput, UploadManager, useState } from "@webpack/common";
import { ScheduledAttachment } from "../types"; import { ScheduledAttachment } from "../types";
import { addScheduledMessage, getChannelDisplayInfo } from "../utils"; import { addScheduledMessage, getChannelDisplayInfo } from "../utils";
@ -61,7 +61,7 @@ function ScheduleTimeModalInner({ channelId, content, attachments, rootProps, cl
if (result.success) { if (result.success) {
ComponentDispatch.dispatchToLastSubscribed("CLEAR_TEXT"); ComponentDispatch.dispatchToLastSubscribed("CLEAR_TEXT");
UploadManager.clearAll(channelId, DraftType.ChannelMessage); UploadManager.clearAll(channelId, DraftType.ChannelMessage);
showToast("Message scheduled!", Toasts.Type.SUCCESS); showToast("Message scheduled!", "success");
close(); close();
} else { } else {
setError(result.error ?? "Failed to schedule message"); setError(result.error ?? "Failed to schedule message");

View file

@ -8,7 +8,7 @@ import { Button } from "@components/Button";
import ErrorBoundary from "@components/ErrorBoundary"; import ErrorBoundary from "@components/ErrorBoundary";
import { classNameFactory } from "@utils/css"; import { classNameFactory } from "@utils/css";
import { RenderModalProps } from "@vencord/discord-types"; import { RenderModalProps } from "@vencord/discord-types";
import { ChannelStore, closeModal, Modal, openModal, showToast, Toasts, useState } from "@webpack/common"; import { ChannelStore, closeModal, Modal, openModal, showToast, useState } from "@webpack/common";
import { clearAllScheduledMessages, getChannelDisplayInfo, getScheduledMessages, removeScheduledMessage } from "../utils"; import { clearAllScheduledMessages, getChannelDisplayInfo, getScheduledMessages, removeScheduledMessage } from "../utils";
import { CalendarIcon, TimerIcon } from "./Icons"; import { CalendarIcon, TimerIcon } from "./Icons";
@ -26,13 +26,13 @@ function ViewScheduledModalInner({ rootProps, close }: ViewScheduledModalProps)
const handleDelete = async (id: string) => { const handleDelete = async (id: string) => {
await removeScheduledMessage(id); await removeScheduledMessage(id);
setMessages(getScheduledMessages()); setMessages(getScheduledMessages());
showToast("Scheduled message removed", Toasts.Type.SUCCESS); showToast("Scheduled message removed", "success");
}; };
const handleClearAll = async () => { const handleClearAll = async () => {
await clearAllScheduledMessages(); await clearAllScheduledMessages();
setMessages([]); setMessages([]);
showToast("All scheduled messages cleared", Toasts.Type.SUCCESS); showToast("All scheduled messages cleared", "success");
}; };
const actions = [ const actions = [

View file

@ -8,7 +8,7 @@ import * as DataStore from "@api/DataStore";
import { Logger } from "@utils/Logger"; import { Logger } from "@utils/Logger";
import { Message } from "@vencord/discord-types"; import { Message } from "@vencord/discord-types";
import { CloudUploadPlatform } from "@vencord/discord-types/enums"; import { CloudUploadPlatform } from "@vencord/discord-types/enums";
import { ChannelStore, CloudUploader, Constants, FluxDispatcher, GuildStore, IconUtils, MessageActions, MessageStore, RestAPI, showToast, SnowflakeUtils, Toasts, UserStore } from "@webpack/common"; import { ChannelStore, CloudUploader, Constants, FluxDispatcher, GuildStore, IconUtils, MessageActions, MessageStore, RestAPI, showToast, SnowflakeUtils, UserStore } from "@webpack/common";
import { settings } from "."; import { settings } from ".";
import { PhantomMessageData, ScheduledAttachment, ScheduledMessage, ScheduledReaction } from "./types"; import { PhantomMessageData, ScheduledAttachment, ScheduledMessage, ScheduledReaction } from "./types";
@ -374,11 +374,11 @@ async function sendScheduledMessage(msg: ScheduledMessage): Promise<boolean> {
} }
if (settings.store.showNotifications) { if (settings.store.showNotifications) {
showToast(`Scheduled message sent to ${getChannelDisplayInfo(msg.channelId).name}`, Toasts.Type.SUCCESS); showToast(`Scheduled message sent to ${getChannelDisplayInfo(msg.channelId).name}`, "success");
} }
return true; return true;
} catch { } catch {
if (settings.store.showNotifications) showToast("Failed to send scheduled message", Toasts.Type.FAILURE); if (settings.store.showNotifications) showToast("Failed to send scheduled message", "failure");
return false; return false;
} }
} }

View file

@ -12,8 +12,9 @@ import { Logger } from "@utils/Logger";
import { parseUrl } from "@utils/misc"; import { parseUrl } from "@utils/misc";
import definePlugin from "@utils/types"; import definePlugin from "@utils/types";
import { Message } from "@vencord/discord-types"; import { Message } from "@vencord/discord-types";
import { ToastPosition } from "@vencord/discord-types/enums";
import { findByCodeLazy } from "@webpack"; import { findByCodeLazy } from "@webpack";
import { ChannelStore, Constants, Menu, MessageStore, React, RestAPI, showToast, Toasts } from "@webpack/common"; import { ChannelStore, Constants, Menu, MessageStore, React, RestAPI, showToast } from "@webpack/common";
const logger = new Logger("ShowMessageEmbeds"); const logger = new Logger("ShowMessageEmbeds");
@ -189,7 +190,7 @@ function removeEmbed(url: string, message: Message) {
} }
function showFailureToast(message: string) { function showFailureToast(message: string) {
showToast(message, Toasts.Type.FAILURE, { position: Toasts.Position.BOTTOM }); showToast(message, "failure", { position: ToastPosition.BOTTOM });
} }
export default definePlugin({ export default definePlugin({

View file

@ -5,7 +5,7 @@
*/ */
import type { UserData } from "@song-spotlight/api/structs"; import type { UserData } from "@song-spotlight/api/structs";
import { showToast, Toasts, UserStore } from "@webpack/common"; import { showToast, UserStore } from "@webpack/common";
import { useAuthorizationStore } from "./stores/AuthorizationStore"; import { useAuthorizationStore } from "./stores/AuthorizationStore";
import { useSongStore } from "./stores/SongStore"; import { useSongStore } from "./stores/SongStore";
@ -65,20 +65,20 @@ export async function authFetch(url: string | URL, options?: RequestInit, retrie
if (retry) return await authFetch(url, options, true); if (retry) return await authFetch(url, options, true);
else { else {
useAuthorizationStore.getState().deleteTokens(); useAuthorizationStore.getState().deleteTokens();
showToast("You have been signed out from Song Spotlight. Please sign in again.", Toasts.Type.FAILURE); showToast("You have been signed out from Song Spotlight. Please sign in again.", "failure");
} }
} else { } else {
showToast( showToast(
!text.includes("<body>") && res.status >= 400 && res.status <= 599 !text.includes("<body>") && res.status >= 400 && res.status <= 599
? `Song Spotlight: ${text}` ? `Song Spotlight: ${text}`
: `Song Spotlight fetch error at ${url.pathname}`, : `Song Spotlight fetch error at ${url.pathname}`,
Toasts.Type.FAILURE, "failure",
); );
} }
throw new Error(text); throw new Error(text);
} catch (error) { } catch (error) {
showToast(`Song Spotlight: ${error}`, Toasts.Type.FAILURE); showToast(`Song Spotlight: ${error}`, "failure");
throw error; throw error;
} }

View file

@ -5,7 +5,7 @@
*/ */
import { ApplicationIntegrationType } from "@vencord/discord-types/enums"; import { ApplicationIntegrationType } from "@vencord/discord-types/enums";
import { OAuth2AuthorizeModal, openModal,showToast, Toasts } from "@webpack/common"; import { OAuth2AuthorizeModal, openModal, showToast } from "@webpack/common";
import { apiConstants, authFetch, getData } from "./api"; import { apiConstants, authFetch, getData } from "./api";
import { useAuthorizationStore } from "./stores/AuthorizationStore"; import { useAuthorizationStore } from "./stores/AuthorizationStore";
@ -41,10 +41,10 @@ export function presentOAuth2Modal() {
useAuthorizationStore.getState().setToken(access, refresh); useAuthorizationStore.getState().setToken(access, refresh);
getData(); getData();
showToast("Successfully authorized!", Toasts.Type.SUCCESS); showToast("Successfully authorized!", "success");
} catch (error) { } catch (error) {
logger.error("Got an error during OAuth2", error); logger.error("Got an error during OAuth2", error);
if (typeof error === "string") showToast(error, Toasts.Type.FAILURE); if (typeof error === "string") showToast(error, "failure");
} }
}} }}
/> />

View file

@ -7,7 +7,7 @@
import { logger } from "@equicordplugins/songSpotlight.desktop/lib/utils"; import { logger } from "@equicordplugins/songSpotlight.desktop/lib/utils";
import settings from "@equicordplugins/songSpotlight.desktop/settings"; import settings from "@equicordplugins/songSpotlight.desktop/settings";
import { RenderInfoEntry, RenderInfoEntryAudio } from "@song-spotlight/api/handlers"; import { RenderInfoEntry, RenderInfoEntryAudio } from "@song-spotlight/api/handlers";
import { showToast, Toasts, useCallback, useEffect, useMemo, useRef } from "@webpack/common"; import { showToast, useCallback, useEffect, useMemo, useRef } from "@webpack/common";
import { RefObject } from "react"; import { RefObject } from "react";
interface AudioItemProps { interface AudioItemProps {
@ -103,7 +103,7 @@ export default function AudioPlayer({ audioRef, list, playing, setPlaying, setLo
node.currentTime = audio.previewStart ? audio.previewStart / 1000 : 0; node.currentTime = audio.previewStart ? audio.previewStart / 1000 : 0;
node.volume = BASE_VOLUME * (settings.store.previewVolume / 100); node.volume = BASE_VOLUME * (settings.store.previewVolume / 100);
node.play().catch(error => { node.play().catch(error => {
showToast("Failed to play song preview!", Toasts.Type.FAILURE); showToast("Failed to play song preview!", "failure");
logger.error("Failed to play audio", error); logger.error("Failed to play audio", error);
setPlaying(undefined); setPlaying(undefined);
}); });

View file

@ -21,7 +21,7 @@ import { sid } from "@song-spotlight/api/util";
import { readClipboard } from "@utils/clipboard"; import { readClipboard } from "@utils/clipboard";
import { copyWithToast } from "@utils/discord"; import { copyWithToast } from "@utils/discord";
import { RenderModalProps } from "@vencord/discord-types"; import { RenderModalProps } from "@vencord/discord-types";
import { Alerts, Modal,openModal, Parser, showToast, Toasts, useCallback, useEffect, useMemo, useRef, useState } from "@webpack/common"; import { Alerts, Modal, openModal, Parser, showToast, useCallback, useEffect, useMemo, useRef, useState } from "@webpack/common";
interface ImportButtonProps { interface ImportButtonProps {
overwrite: boolean; overwrite: boolean;
@ -39,24 +39,24 @@ function ImportButton({ overwrite, pending, setPending, onImport }: ImportButton
json = JSON.parse(await readClipboard()); json = JSON.parse(await readClipboard());
} catch { } catch {
setPending(false); setPending(false);
return showToast("No JSON in clipboard!", Toasts.Type.FAILURE); return showToast("No JSON in clipboard!", "failure");
} }
const { error, data } = UserDataSchema.max(apiConstants.songLimit).safeParse(json); const { error, data } = UserDataSchema.max(apiConstants.songLimit).safeParse(json);
if (error) { if (error) {
setPending(false); setPending(false);
return showToast("Invalid Song Spotlight data in clipboard!", Toasts.Type.FAILURE); return showToast("Invalid Song Spotlight data in clipboard!", "failure");
} }
const validated = await Promise.allSettled(data.map(song => Native.validateSong(song))); const validated = await Promise.allSettled(data.map(song => Native.validateSong(song)));
if (!validated.every(x => x.status === "fulfilled" && x.value)) { if (!validated.every(x => x.status === "fulfilled" && x.value)) {
setPending(false); setPending(false);
return showToast("One or more imported songs were invalid.", Toasts.Type.FAILURE); return showToast("One or more imported songs were invalid.", "failure");
} }
onImport(data); onImport(data);
setPending(false); setPending(false);
showToast("Imported songs from clipboard!", Toasts.Type.SUCCESS); showToast("Imported songs from clipboard!", "success");
}, [pending]); }, [pending]);
return ( return (
@ -153,7 +153,7 @@ export default function Settings({ templateData }: SettingsProps) {
setPending(true); setPending(true);
try { try {
await saveData(localData); await saveData(localData);
showToast("Successfully saved songs!", Toasts.Type.SUCCESS); showToast("Successfully saved songs!", "success");
} finally { } finally {
setPending(false); setPending(false);
} }
@ -173,7 +173,7 @@ export default function Settings({ templateData }: SettingsProps) {
variant="dangerPrimary" variant="dangerPrimary"
onClick={() => { onClick={() => {
deleteTokens(); deleteTokens();
showToast("Successfully signed out!", Toasts.Type.SUCCESS); showToast("Successfully signed out!", "success");
}} }}
disabled={pending} disabled={pending}
> >
@ -191,7 +191,7 @@ export default function Settings({ templateData }: SettingsProps) {
await deleteData(); await deleteData();
deleteTokens(); deleteTokens();
showToast("Successfully deleted songs!", Toasts.Type.SUCCESS); showToast("Successfully deleted songs!", "success");
} finally { } finally {
setPending(false); setPending(false);
} }

View file

@ -19,11 +19,11 @@ import { sid } from "@song-spotlight/api/util";
import { classes } from "@utils/misc"; import { classes } from "@utils/misc";
import { User } from "@vencord/discord-types"; import { User } from "@vencord/discord-types";
import { import {
openUserProfileModal,
SelectedChannelStore, SelectedChannelStore,
SelectedGuildStore, SelectedGuildStore,
useEffect, useEffect,
useMemo, useMemo,
UserProfileActions,
UserStore, UserStore,
useState, useState,
} from "@webpack/common"; } from "@webpack/common";
@ -70,14 +70,14 @@ export default function CollapsedProfileSongs({ data, user, isSideBar, isRedesig
if (!user) return; if (!user) return;
const guildId = SelectedGuildStore.getGuildId(); const guildId = SelectedGuildStore.getGuildId();
UserProfileActions.openUserProfileModal({ openUserProfileModal({
userId, userId,
guildId, guildId,
channelId: SelectedChannelStore.getChannelId(), channelId: SelectedChannelStore.getChannelId(),
analyticsLocation: { sourceAnalyticsLocations: [
page: guildId ? "Guild Channel" : "DM Channel", "username",
section: "Profile Popout", "user profile popout",
}, ],
tabSection: "SONG_SPOTLIGHT", tabSection: "SONG_SPOTLIGHT",
}); });
}} }}

View file

@ -30,21 +30,7 @@ import { Song as SongType } from "@song-spotlight/api/structs";
import { isListLayout, sid } from "@song-spotlight/api/util"; import { isListLayout, sid } from "@song-spotlight/api/util";
import { copyWithToast } from "@utils/discord"; import { copyWithToast } from "@utils/discord";
import { classes } from "@utils/misc"; import { classes } from "@utils/misc";
import { import { Clickable, ContextMenuApi, FluxDispatcher, Menu, React, ScrollerThin, showToast, Tooltip, useCallback, useMemo, useRef, useState } from "@webpack/common";
Clickable,
ContextMenuApi,
FluxDispatcher,
Menu,
React,
ScrollerThin,
showToast,
Toasts,
Tooltip,
useCallback,
useMemo,
useRef,
useState
} from "@webpack/common";
interface SongEntryProps { interface SongEntryProps {
entry: RenderInfoEntryBased; entry: RenderInfoEntryBased;
@ -88,7 +74,7 @@ function SongEntry({ entry, number, isLoaded, isPlaying, big, onClick }: SongEnt
const song = await Native.parseLink(entry.link); const song = await Native.parseLink(entry.link);
if (!song) { if (!song) {
return showToast("Uh oh, this song doesn't exist!", Toasts.Type.FAILURE); return showToast("Uh oh, this song doesn't exist!", "failure");
} }
if (self.find(x => sid(x) === sid(song))) { if (self.find(x => sid(x) === sid(song))) {

View file

@ -12,7 +12,7 @@ import { Logger } from "@utils/Logger";
import { sleep } from "@utils/misc"; import { sleep } from "@utils/misc";
import definePlugin, { makeRange, OptionType } from "@utils/types"; import definePlugin, { makeRange, OptionType } from "@utils/types";
import type { Channel } from "@vencord/discord-types"; import type { Channel } from "@vencord/discord-types";
import { ChannelStore, ComponentDispatch, PermissionsBits, PermissionStore, Toasts, UserStore } from "@webpack/common"; import { ChannelStore, ComponentDispatch, PermissionsBits, PermissionStore, showToast,UserStore } from "@webpack/common";
import { splitMessage, type SplitMode } from "./splitMessage"; import { splitMessage, type SplitMode } from "./splitMessage";
@ -120,11 +120,7 @@ const listener: MessageSendListener = async (channelId, message) => {
const channel = ChannelStore.getChannel(channelId); const channel = ChannelStore.getChannel(channelId);
if (!canSplitInChannel(channel)) { if (!canSplitInChannel(channel)) {
Toasts.show({ showToast("Cannot split this message because of the channel's slowmode.", "failure");
message: "Cannot split this message because of the channel's slowmode.",
id: "vc-splitLargeMessages-blocked",
type: Toasts.Type.FAILURE,
});
return { cancel: true }; return { cancel: true };
} }
@ -134,11 +130,7 @@ const listener: MessageSendListener = async (channelId, message) => {
const sent = await sendChunks(channelId, chunks, getSendDelay(channel)); const sent = await sendChunks(channelId, chunks, getSendDelay(channel));
if (sent !== chunks.length) { if (sent !== chunks.length) {
restoreUnsentContent(channelId, chunks, sent); restoreUnsentContent(channelId, chunks, sent);
Toasts.show({ showToast(`Only ${sent}/${chunks.length} message parts were sent.`, "failure");
message: `Only ${sent}/${chunks.length} message parts were sent.`,
id: "vc-splitLargeMessages-failure",
type: Toasts.Type.FAILURE,
});
} }
return { cancel: true }; return { cancel: true };

View file

@ -26,7 +26,7 @@ import { proxyLazy } from "@utils/lazy";
import { useForceUpdater } from "@utils/react"; import { useForceUpdater } from "@utils/react";
import definePlugin, { OptionType, StartAt } from "@utils/types"; import definePlugin, { OptionType, StartAt } from "@utils/types";
import { extractAndLoadChunksLazy, findComponentByCodeLazy, findModuleId, wreq } from "@webpack"; import { extractAndLoadChunksLazy, findComponentByCodeLazy, findModuleId, wreq } from "@webpack";
import { Menu, openModalLazy, OverridePremiumTypeStore, Toasts } from "@webpack/common"; import { Menu, openModalLazy, OverridePremiumTypeStore, showToast } from "@webpack/common";
interface Emoji { interface Emoji {
animated: boolean; animated: boolean;
@ -141,7 +141,7 @@ export default definePlugin({
{ {
find: "#{intl::STATUS_MENU_LABEL}", find: "#{intl::STATUS_MENU_LABEL}",
replacement: { replacement: {
match: /(popoutContainerRef:\i,forceOpen:\i.{0,25}\}\))(?=\])/, match: /(popoutContainerRef:\i,scrollerRef:\i.{0,50}\}\))(?=\])/,
replace: "$1,$self.render()" replace: "$1,$self.render()"
} }
}, },
@ -189,11 +189,7 @@ export default definePlugin({
style: { marginLeft: "20px" }, style: { marginLeft: "20px" },
onClick: () => { onClick: () => {
settings.store.StatusPresets[status.text] = status; settings.store.StatusPresets[status.text] = status;
Toasts.show({ showToast("Successfully Saved Status", "success");
message: "Successfully Saved Status",
type: Toasts.Type.SUCCESS,
id: Toasts.genId()
});
} }
}; };
}, },

View file

@ -7,7 +7,7 @@
import * as DataStore from "@api/DataStore"; import * as DataStore from "@api/DataStore";
import { proxyLazy } from "@utils/lazy"; import { proxyLazy } from "@utils/lazy";
import { Logger } from "@utils/Logger"; 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";
import { AUTHORIZE_URL, CLIENT_ID } from "../constants"; import { AUTHORIZE_URL, CLIENT_ID } from "../constants";
import { useStreaksStore } from "./StreaksStore"; import { useStreaksStore } from "./StreaksStore";
@ -78,7 +78,7 @@ export const useAuthorizationStore = proxyLazy(() => zustandCreate(
resolve(void 0); resolve(void 0);
} catch (e) { } catch (e) {
if (e instanceof Error) { if (e instanceof Error) {
showToast(`Failed to authorize: ${e.message}`, Toasts.Type.FAILURE); showToast(`Failed to authorize: ${e.message}`, "failure");
new Logger("Streaks").error("Failed to authorize", e); new Logger("Streaks").error("Failed to authorize", e);
reject(e); reject(e);
} }

View file

@ -15,7 +15,7 @@ import { openInviteModal } from "@utils/discord";
import { Margins } from "@utils/margins"; import { Margins } from "@utils/margins";
import type { PluginNative } from "@utils/types"; import type { PluginNative } from "@utils/types";
import { findComponentByCodeLazy } from "@webpack"; import { findComponentByCodeLazy } from "@webpack";
import { Button, Modal, openModal, Parser, React, showToast, Toasts } from "@webpack/common"; import { Button, Modal, openModal, Parser, React, showToast } from "@webpack/common";
import { logger } from "./ThemeTab"; import { logger } from "./ThemeTab";
@ -25,10 +25,10 @@ const UserSummaryItem = findComponentByCodeLazy("defaultRenderUser", "showDefaul
async function downloadTheme(theme: Theme) { async function downloadTheme(theme: Theme) {
try { try {
await Native.downloadTheme(theme); await Native.downloadTheme(theme);
showToast(`Downloaded ${theme.name}!`, Toasts.Type.SUCCESS); showToast(`Downloaded ${theme.name}!`, "success");
} catch (err: unknown) { } catch (err: unknown) {
logger.error(err); logger.error(err);
showToast(`Failed to download ${theme.name}! (check console)`, Toasts.Type.FAILURE); showToast(`Failed to download ${theme.name}! (check console)`, "failure");
} }
} }
@ -166,7 +166,7 @@ export const ThemeInfoModal: React.FC<ThemeInfoModalProps> = ({ author, theme, .
onClick={async e => { onClick={async e => {
e.preventDefault(); e.preventDefault();
const useInvite = guild ? guild.invite_link?.split("discord.gg/")[1] : invite; const useInvite = guild ? guild.invite_link?.split("discord.gg/")[1] : invite;
useInvite != null && openInviteModal(useInvite).catch(() => showToast("Invalid or expired invite!", Toasts.Type.FAILURE)); useInvite != null && openInviteModal(useInvite).catch(() => showToast("Invalid or expired invite!", "failure"));
}} }}
> >
Join Discord Server Join Discord Server
@ -194,7 +194,7 @@ export const ThemeInfoModal: React.FC<ThemeInfoModalProps> = ({ author, theme, .
variant: "primary", variant: "primary",
onClick: () => { onClick: () => {
copyToClipboard(themeContent); copyToClipboard(themeContent);
showToast("Copied to Clipboard", Toasts.Type.SUCCESS); showToast("Copied to Clipboard", "success");
} }
} }
]} ]}

View file

@ -7,7 +7,8 @@
import * as DataStore from "@api/DataStore"; import * as DataStore from "@api/DataStore";
import { showNotification } from "@api/Notifications"; import { showNotification } from "@api/Notifications";
import { logger, themeRequest } from "@equicordplugins/themeLibrary/components/ThemeTab"; import { logger, themeRequest } from "@equicordplugins/themeLibrary/components/ThemeTab";
import { OAuth2AuthorizeModal, openModal,Toasts, UserStore } from "@webpack/common"; import { ToastPosition } from "@vencord/discord-types/enums";
import { OAuth2AuthorizeModal, openModal, showToast,UserStore } from "@webpack/common";
export async function authorizeUser(triggerModal: boolean = true) { export async function authorizeUser(triggerModal: boolean = true) {
const isAuthorized = await getAuthorization(); const isAuthorized = await getAuthorization();
@ -64,15 +65,10 @@ export async function authorizeUser(triggerModal: boolean = true) {
export async function deauthorizeUser() { export async function deauthorizeUser() {
const uniqueToken = await DataStore.get<Record<string, string>>("ThemeLibrary_uniqueToken"); const uniqueToken = await DataStore.get<Record<string, string>>("ThemeLibrary_uniqueToken");
if (!uniqueToken) return Toasts.show({ if (!uniqueToken) return showToast("No uniqueToken present, try authorizing first!", "failure", {
message: "No uniqueToken present, try authorizing first!",
id: Toasts.genId(),
type: Toasts.Type.FAILURE,
options: {
duration: 2e3, duration: 2e3,
position: Toasts.Position.BOTTOM position: ToastPosition.BOTTOM
} });
});
const res = await themeRequest("/user/revoke", { const res = await themeRequest("/user/revoke", {
method: "DELETE", method: "DELETE",

View file

@ -12,7 +12,8 @@ import { Paragraph } from "@components/Paragraph";
import { copyToClipboard } from "@utils/clipboard"; import { copyToClipboard } from "@utils/clipboard";
import { classNameFactory } from "@utils/css"; import { classNameFactory } from "@utils/css";
import { OptionType } from "@utils/types"; import { OptionType } from "@utils/types";
import { Button, Toasts } from "@webpack/common"; import { ToastPosition } from "@vencord/discord-types/enums";
import { Button, showToast } from "@webpack/common";
import { authorizeUser, deauthorizeUser } from "./auth"; import { authorizeUser, deauthorizeUser } from "./auth";
@ -32,27 +33,17 @@ export const settings = definePluginSettings({
const handleClick = async () => { const handleClick = async () => {
const token = await DataStore.get("ThemeLibrary_uniqueToken"); const token = await DataStore.get("ThemeLibrary_uniqueToken");
if (!token) return Toasts.show({ if (!token) return showToast("No token to copy, try authorizing first!", "failure", {
message: "No token to copy, try authorizing first!",
id: Toasts.genId(),
type: Toasts.Type.FAILURE,
options: {
duration: 2.5e3, duration: 2.5e3,
position: Toasts.Position.BOTTOM position: ToastPosition.BOTTOM
} });
});
copyToClipboard(token); copyToClipboard(token);
Toasts.show({ showToast("Copied to Clipboard!", "success", {
message: "Copied to Clipboard!",
id: Toasts.genId(),
type: Toasts.Type.SUCCESS,
options: {
duration: 2.5e3, duration: 2.5e3,
position: Toasts.Position.BOTTOM position: ToastPosition.BOTTOM
} });
});
}; };
return ( return (

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: GPL-3.0-or-later * SPDX-License-Identifier: GPL-3.0-or-later
*/ */
import { OAuth2AuthorizeModal, openModal, showToast, Toasts } from "@webpack/common"; import { OAuth2AuthorizeModal, openModal, showToast } from "@webpack/common";
import { settings } from "."; import { settings } from ".";
@ -22,7 +22,7 @@ function getRedirectUri(): string {
function handleApiError(error: any, defaultMessage: string): void { function handleApiError(error: any, defaultMessage: string): void {
console.error(defaultMessage, error); console.error(defaultMessage, error);
const message = error?.message || defaultMessage; const message = error?.message || defaultMessage;
showToast(message, Toasts.Type.FAILURE); showToast(message, "failure");
} }
async function safeJsonParse(response: Response): Promise<any> { async function safeJsonParse(response: Response): Promise<any> {
@ -111,7 +111,7 @@ async function setTimezoneInternal(timezone: string): Promise<boolean> {
return false; return false;
} }
showToast("Timezone updated successfully!", Toasts.Type.SUCCESS); showToast("Timezone updated successfully!", "success");
return true; return true;
} catch (e) { } catch (e) {
handleApiError(e, "Failed to set timezone"); handleApiError(e, "Failed to set timezone");
@ -149,7 +149,7 @@ async function deleteTimezoneInternal(): Promise<boolean> {
return false; return false;
} }
showToast("Timezone deleted successfully!", Toasts.Type.SUCCESS); showToast("Timezone deleted successfully!", "success");
return true; return true;
} catch (e) { } catch (e) {
handleApiError(e, "Failed to delete timezone"); handleApiError(e, "Failed to delete timezone");
@ -180,7 +180,7 @@ export function authModal(callback?: () => void) {
handleApiError(json, "Authorization failed"); handleApiError(json, "Authorization failed");
return; return;
} }
showToast("Authorization successful!", Toasts.Type.SUCCESS); showToast("Authorization successful!", "success");
callback?.(); callback?.();
} catch (e) { } catch (e) {
handleApiError(e, "Unexpected error during authorization"); handleApiError(e, "Unexpected error during authorization");

View file

@ -13,8 +13,9 @@ import ErrorBoundary from "@components/ErrorBoundary";
import { Devs, EquicordDevs } from "@utils/constants"; import { Devs, EquicordDevs } from "@utils/constants";
import definePlugin, { OptionType } from "@utils/types"; import definePlugin, { OptionType } from "@utils/types";
import { Message, User } from "@vencord/discord-types"; import { Message, User } from "@vencord/discord-types";
import { ToastPosition } from "@vencord/discord-types/enums";
import { findByPropsLazy, findCssClassesLazy } from "@webpack"; import { findByPropsLazy, findCssClassesLazy } from "@webpack";
import { Button, ChannelStore, Menu, openModal, showToast, Toasts, Tooltip, useEffect, UserStore, useState } from "@webpack/common"; import { Button, ChannelStore, Menu, openModal, showToast, Tooltip, useEffect, UserStore, useState } from "@webpack/common";
import { deleteTimezone, getTimezone, loadDatabaseTimezones, setUserDatabaseTimezone } from "./database"; import { deleteTimezone, getTimezone, loadDatabaseTimezones, setUserDatabaseTimezone } from "./database";
import { SetTimezoneModal } from "./TimezoneModal"; import { SetTimezoneModal } from "./TimezoneModal";
@ -127,7 +128,7 @@ export const settings = definePluginSettings({
await deleteTimezone(); await deleteTimezone();
} catch (error) { } catch (error) {
console.error("Error resetting database timezone:", error); console.error("Error resetting database timezone:", error);
showToast("Failed to reset database timezone", Toasts.Type.FAILURE); showToast("Failed to reset database timezone", "failure");
} }
}} }}
> >
@ -312,14 +313,14 @@ export default definePlugin({
const good = await loadDatabaseTimezones(); const good = await loadDatabaseTimezones();
if (good) { if (good) {
showToast("Timezones refreshed successfully!", Toasts.Type.SUCCESS); showToast("Timezones refreshed successfully!", "success");
} else { } else {
showToast("Timezones Failed to refresh!", Toasts.Type.FAILURE); showToast("Timezones Failed to refresh!", "failure");
} }
} }
catch (error) { catch (error) {
console.error("Failed to refresh timezone:", error); console.error("Failed to refresh timezone:", error);
showToast("Failed to refresh timezones.", Toasts.Type.FAILURE); showToast("Failed to refresh timezones.", "failure");
} }
} }
}, },
@ -333,7 +334,7 @@ export default definePlugin({
if (!settings.store.askedTimezone) { if (!settings.store.askedTimezone) {
showToast( showToast(
"", "",
Toasts.Type.MESSAGE, "message",
{ {
duration: 10000, duration: 10000,
component: ( component: (
@ -346,7 +347,7 @@ export default definePlugin({
Want to save your timezone to the database? Click here to set it. Want to save your timezone to the database? Click here to set it.
</Button> </Button>
), ),
position: Toasts.Position.BOTTOM position: ToastPosition.BOTTOM
} }
); );
settings.store.askedTimezone = true; settings.store.askedTimezone = true;

View file

@ -8,7 +8,7 @@ import { sendBotMessage } from "@api/Commands";
import { insertTextIntoChatInputBox, sendMessage } from "@utils/discord"; import { insertTextIntoChatInputBox, sendMessage } from "@utils/discord";
import { Logger } from "@utils/Logger"; import { Logger } from "@utils/Logger";
import { Message } from "@vencord/discord-types"; import { Message } from "@vencord/discord-types";
import { MessageStore, showToast, Toasts, UserStore } from "@webpack/common"; import { MessageStore, showToast, UserStore } from "@webpack/common";
import { settings } from "./settings"; import { settings } from "./settings";
@ -225,7 +225,7 @@ function getSystemPrompt() {
export async function getResponse(payload: ApiMessage[]): Promise<string> { export async function getResponse(payload: ApiMessage[]): Promise<string> {
if (!settings.store.apiKey || !settings.store.endpoint || !settings.store.model) { if (!settings.store.apiKey || !settings.store.endpoint || !settings.store.model) {
showToast("TriviaAI: API settings are incomplete.", Toasts.Type.FAILURE); showToast("TriviaAI: API settings are incomplete.", "failure");
return ""; return "";
} }
@ -258,7 +258,7 @@ export async function getResponse(payload: ApiMessage[]): Promise<string> {
if (!req.ok || data.error) { if (!req.ok || data.error) {
const errorMsg = data.error?.message ?? rawBody ?? `Status ${req.status}`; const errorMsg = data.error?.message ?? rawBody ?? `Status ${req.status}`;
logger.error(`API Error: ${errorMsg}`); logger.error(`API Error: ${errorMsg}`);
showToast(errorMsg, Toasts.Type.FAILURE); showToast(errorMsg, "failure");
return ""; return "";
} }
@ -271,7 +271,7 @@ export async function getResponse(payload: ApiMessage[]): Promise<string> {
return response; return response;
} catch (e) { } catch (e) {
logger.error("Error getting response from AI model", e); logger.error("Error getting response from AI model", e);
showToast("Error getting response from AI model", Toasts.Type.FAILURE); showToast("Error getting response from AI model", "failure");
return ""; return "";
} }
} }

View file

@ -9,7 +9,7 @@ import { Heading } from "@components/Heading";
import { Margins } from "@components/margins"; import { Margins } from "@components/margins";
import { classNameFactory } from "@utils/css"; import { classNameFactory } from "@utils/css";
import { RenderModalProps } from "@vencord/discord-types"; import { RenderModalProps } from "@vencord/discord-types";
import { IconUtils, Modal, React, TextInput, Toasts, UserStore, useState } from "@webpack/common"; import { IconUtils, Modal, React, showToast,TextInput, UserStore, useState } from "@webpack/common";
import { data, KEY_DATASTORE } from "."; import { data, KEY_DATASTORE } from ".";
@ -47,11 +47,7 @@ export function SetAvatarModal({ userId, modalProps }: { userId: string; modalPr
if (!file.type.startsWith("image/")) return; if (!file.type.startsWith("image/")) return;
if (file.type === "image/gif" || file.type === "image/webp") { if (file.type === "image/gif" || file.type === "image/webp") {
Toasts.show({ showToast("GIFs/WebP must be added via URL. Upload your GIF/WebP to a image hosting service and paste the link.", "failure");
message: "GIFs/WebP must be added via URL. Upload your GIF/WebP to a image hosting service and paste the link.",
type: Toasts.Type.FAILURE,
id: Toasts.genId(),
});
return; return;
} }

View file

@ -20,7 +20,7 @@ import {
} from "@components/settings/tabs/BaseTab"; } from "@components/settings/tabs/BaseTab";
import { classes, isObjectEmpty } from "@utils/misc"; import { classes, isObjectEmpty } from "@utils/misc";
import { relaunch } from "@utils/native"; import { relaunch } from "@utils/native";
import { Alerts, closeAllModals,NavigationRouter, Toasts, useEffect, useState } from "@webpack/common"; import { Alerts, closeAllModals, NavigationRouter, showToast,useEffect, useState } from "@webpack/common";
import userpluginInstaller, { Native } from ".."; import userpluginInstaller, { Native } from "..";
import { import {
@ -236,11 +236,7 @@ function UserPluginsTab() {
setEnabled={t => { setEnabled={t => {
Vencord.Settings.plugins[pl.name].enabled = t; Vencord.Settings.plugins[pl.name].enabled = t;
if (pluginRequiresRestart(pl)) { if (pluginRequiresRestart(pl)) {
Toasts.show({ showToast("Restart to apply changes!", "message");
id: Toasts.genId(),
message: "Restart to apply changes!",
type: Toasts.Type.MESSAGE
});
} else { } else {
(t ? startPlugin : stopPlugin)(pl); (t ? startPlugin : stopPlugin)(pl);
} }

View file

@ -12,8 +12,9 @@ import { definePluginSettings } from "@api/Settings";
import { EquicordDevs } from "@utils/constants"; import { EquicordDevs } from "@utils/constants";
import definePlugin, { OptionType } from "@utils/types"; import definePlugin, { OptionType } from "@utils/types";
import { chooseFile, saveFile } from "@utils/web"; import { chooseFile, saveFile } from "@utils/web";
import { CustomEmoji, UnicodeEmoji } from "@vencord/discord-types"; import { CustomEmoji, ToastType, UnicodeEmoji } from "@vencord/discord-types";
import { Alerts, Button, EmojiStore, GuildStore, IconUtils, Menu, Toasts, useEffect, useState } from "@webpack/common"; import { ToastPosition } from "@vencord/discord-types/enums";
import { Alerts, Button, EmojiStore, GuildStore, IconUtils, Menu, showToast as originalShowToast, useEffect, useState } from "@webpack/common";
import { JSX } from "react"; import { JSX } from "react";
import { ContextMenuEmoji, SavedEmoji, Target } from "./types"; import { ContextMenuEmoji, SavedEmoji, Target } from "./types";
@ -73,14 +74,9 @@ function buildSaveData(item: ContextMenuEmoji): SavedEmoji {
return saveData; return saveData;
} }
function showToast(message: string, type = Toasts.Type.SUCCESS) { function showToast(message: string, type: ToastType = "success") {
if (settings.store.disableToasts) return; if (settings.store.disableToasts) return;
Toasts.show({ originalShowToast(message, type, { duration: 3000, position: ToastPosition.BOTTOM });
message,
type,
id: Toasts.genId(),
options: { duration: 3000, position: Toasts.Position.BOTTOM }
});
} }
function addBulkToAllowedList(items: ContextMenuEmoji[]) { function addBulkToAllowedList(items: ContextMenuEmoji[]) {
@ -104,7 +100,7 @@ function removeBulkFromAllowedList(items: ContextMenuEmoji[]) {
function addToAllowedList(item: ContextMenuEmoji) { function addToAllowedList(item: ContextMenuEmoji) {
return withWriteLock(async () => { return withWriteLock(async () => {
if (itemAlreadyInList(item)) { if (itemAlreadyInList(item)) {
showToast(`"${item.name}" is already in the list`, Toasts.Type.FAILURE); showToast(`"${item.name}" is already in the list`, "failure");
return; return;
} }
@ -116,7 +112,7 @@ function addToAllowedList(item: ContextMenuEmoji) {
function removeFromAllowedList(item: ContextMenuEmoji) { function removeFromAllowedList(item: ContextMenuEmoji) {
return withWriteLock(async () => { return withWriteLock(async () => {
if (!itemAlreadyInList(item)) { if (!itemAlreadyInList(item)) {
showToast(`"${item.name}" is not in the list`, Toasts.Type.FAILURE); showToast(`"${item.name}" is not in the list`, "failure");
return; return;
} }
@ -323,10 +319,10 @@ const importEmojis = (data: string) => withWriteLock(async () => {
await setAllowedList(parsed.emojis); await setAllowedList(parsed.emojis);
showToast("Successfully imported emojis"); showToast("Successfully imported emojis");
} else { } else {
showToast("Invalid JSON data", Toasts.Type.FAILURE); showToast("Invalid JSON data", "failure");
} }
} catch (err) { } catch (err) {
showToast(`Failed to import emojis: ${err}`, Toasts.Type.FAILURE); showToast(`Failed to import emojis: ${err}`, "failure");
} }
}); });

View file

@ -87,7 +87,7 @@ if (!IS_VANILLA) {
return; 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 original = options.webPreferences.preload;
const isMainWindow = options.title === "Discord"; const isMainWindow = options.title === "Discord";
@ -98,7 +98,7 @@ if (!IS_VANILLA) {
options.frame = false; options.frame = false;
} else if (frameless) { } else if (frameless) {
options.frame = false; options.frame = false;
} else if (process.platform === "win32" && winNativeTitleBar) { } else if (process.platform === "win32" && nativeTitleBar) {
delete options.frame; delete options.frame;
} }

View file

@ -4,27 +4,13 @@
* SPDX-License-Identifier: GPL-3.0-or-later * SPDX-License-Identifier: GPL-3.0-or-later
*/ */
import { IpcEvents } from "@shared/IpcEvents"; import { gitHash } from "@shared/vencordUserAgent";
import { gitHashShort } from "@shared/vencordUserAgent"; import { app, BaseWindow, BrowserWindow, dialog, Menu, MenuItemConstructorOptions, shell } from "electron";
import { BrowserWindow, ipcMain, Menu, MenuItemConstructorOptions, shell } from "electron";
import aboutHtml from "file://about.html?minify"; import aboutHtml from "file://about.html?minify";
import updater from "./updater";
import { SETTINGS_DIR, THEMES_DIR } from "./utils/constants"; import { SETTINGS_DIR, THEMES_DIR } from "./utils/constants";
let cachedUpdateAvailable = false;
ipcMain.on(IpcEvents.SET_TRAY_UPDATE_STATE, (_, available: boolean) => {
cachedUpdateAvailable = available;
});
function getMainWindow(): BrowserWindow | undefined {
return BrowserWindow.getFocusedWindow() ?? BrowserWindow.getAllWindows()[0];
}
function sendToRenderer(event: IpcEvents): void {
getMainWindow()?.webContents.send(event);
}
function findInsertIndex(template: MenuItemConstructorOptions[]): number { function findInsertIndex(template: MenuItemConstructorOptions[]): number {
const openIndex = template.findIndex(item => { const openIndex = template.findIndex(item => {
const label = item.label?.toLowerCase() ?? ""; const label = item.label?.toLowerCase() ?? "";
@ -61,14 +47,11 @@ function openAboutWindow() {
return; return;
} }
const height = 750;
const width = height * (4 / 3);
aboutWindow = new BrowserWindow({ aboutWindow = new BrowserWindow({
center: true, center: true,
autoHideMenuBar: true, autoHideMenuBar: true,
height, height: 525,
width width: 900
}); });
aboutWindow.webContents.setWindowOpenHandler(({ url }) => { aboutWindow.webContents.setWindowOpenHandler(({ url }) => {
@ -83,7 +66,7 @@ function openAboutWindow() {
const aboutParams = aboutHtml const aboutParams = aboutHtml
.replaceAll("{{VERSION}}", VERSION) .replaceAll("{{VERSION}}", VERSION)
.replaceAll("{{GIT_HASH}}", gitHashShort); .replaceAll("{{GIT_HASH}}", gitHash); // change to gitHashShort if/when its added
const base64Html = Buffer.from(aboutParams).toString("base64"); const base64Html = Buffer.from(aboutParams).toString("base64");
aboutWindow.loadURL(`data:text/html;base64,${base64Html}`); aboutWindow.loadURL(`data:text/html;base64,${base64Html}`);
aboutWindow.on("closed", () => { aboutWindow.on("closed", () => {
@ -91,7 +74,9 @@ function openAboutWindow() {
}); });
} }
function createEquicordMenuItems(): MenuItemConstructorOptions[] { const notify = (window: BaseWindow, title: string, message: string) => dialog.showMessageBox(window, { title, message });
function createVencordMenuItems(): MenuItemConstructorOptions[] {
return [ return [
{ {
label: "Equicord", label: "Equicord",
@ -101,12 +86,28 @@ function createEquicordMenuItems(): MenuItemConstructorOptions[] {
click: () => openAboutWindow() click: () => openAboutWindow()
}, },
{ {
label: cachedUpdateAvailable ? "Update Equicord" : "Check for Updates", label: "Update Equicord",
click: () => sendToRenderer(IpcEvents.TRAY_CHECK_UPDATES) async click(_item, window) {
}, if (!window) return;
{
label: "Repair Equicord", try {
click: () => sendToRenderer(IpcEvents.TRAY_REPAIR) const updateAvailable = await updater.fetchUpdate();
if (!updateAvailable) {
return notify(window, "No Update Available", "You are already using the latest version of Equicord.");
}
const result = await updater.applyUpdate();
if (!result) {
return notify(window, "Update Failed", "Failed to apply the update for Equicord.");
}
await notify(window, "Update Successful", "Now relaunching Equicord to apply the update.");
app.relaunch();
app.exit();
} catch (e) {
notify(window, "Update Error", `An error occurred while updating Equicord.\n\n${String(e)}`);
}
}
}, },
{ type: "separator" }, { type: "separator" },
{ {
@ -119,7 +120,6 @@ function createEquicordMenuItems(): MenuItemConstructorOptions[] {
} }
] ]
}, },
{ type: "separator" }
]; ];
} }
@ -130,8 +130,8 @@ export function patchTrayMenu(): void {
const alreadyPatched = template.some(item => item.label === "Equicord"); const alreadyPatched = template.some(item => item.label === "Equicord");
if (isTrayMenu(template) && !alreadyPatched) { if (isTrayMenu(template) && !alreadyPatched) {
const insertIndex = findInsertIndex(template); const insertIndex = findInsertIndex(template);
const equicordItems = createEquicordMenuItems(); const vencordItems = createVencordMenuItems();
template.splice(insertIndex, 0, ...equicordItems); template.splice(insertIndex, 0, ...vencordItems);
} }
return originalBuildFromTemplate.call(this, template); return originalBuildFromTemplate.call(this, template);

View file

@ -16,13 +16,11 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
import { IpcEvents } from "@shared/IpcEvents";
import { execFile as cpExecFile } from "child_process"; import { execFile as cpExecFile } from "child_process";
import { ipcMain } from "electron";
import { join } from "path"; import { join } from "path";
import { promisify } from "util"; import { promisify } from "util";
import { serializeErrors } from "./common"; import { Updater } from ".";
const VENCORD_SRC_DIR = join(__dirname, ".."); const VENCORD_SRC_DIR = join(__dirname, "..");
const EQUICORD_DIR = join(__dirname, "../../"); const EQUICORD_DIR = join(__dirname, "../../");
@ -85,7 +83,11 @@ async function build() {
return !res.stderr.includes("Build failed"); return !res.stderr.includes("Build failed");
} }
ipcMain.handle(IpcEvents.GET_REPO, serializeErrors(getRepo)); const GitUpdater: Updater = {
ipcMain.handle(IpcEvents.GET_UPDATES, serializeErrors(calculateGitChanges)); getRepo,
ipcMain.handle(IpcEvents.UPDATE, serializeErrors(pull)); listUpdates: calculateGitChanges,
ipcMain.handle(IpcEvents.BUILD, serializeErrors(build)); fetchUpdate: pull,
applyUpdate: build
};
export default GitUpdater;

View file

@ -17,15 +17,14 @@
*/ */
import { fetchBuffer, fetchJson } from "@main/utils/http"; import { fetchBuffer, fetchJson } from "@main/utils/http";
import { IpcEvents } from "@shared/IpcEvents";
import { VENCORD_USER_AGENT } from "@shared/vencordUserAgent"; import { VENCORD_USER_AGENT } from "@shared/vencordUserAgent";
import { ipcMain } from "electron";
import { writeFileSync } from "original-fs"; import { writeFileSync } from "original-fs";
import gitHash from "~git-hash"; import gitHash from "~git-hash";
import gitRemote from "~git-remote"; import gitRemote from "~git-remote";
import { ASAR_FILE, serializeErrors } from "./common"; import { Updater } from ".";
import { ASAR_FILE } from "./common";
const API_BASE = `https://api.github.com/repos/${gitRemote}`; const API_BASE = `https://api.github.com/repos/${gitRemote}`;
let PendingUpdate: string | null = null; let PendingUpdate: string | null = null;
@ -41,8 +40,8 @@ async function githubGet<T = any>(endpoint: string) {
}); });
} }
async function calculateGitChanges() { async function listUpdates() {
const isOutdated = await fetchUpdates(); const isOutdated = await fetchUpdate();
if (!isOutdated) return []; if (!isOutdated) return [];
const data = await githubGet(`/compare/${gitHash}...HEAD`); const data = await githubGet(`/compare/${gitHash}...HEAD`);
@ -54,7 +53,7 @@ async function calculateGitChanges() {
})); }));
} }
async function fetchUpdates() { async function fetchUpdate() {
const data = await githubGet("/releases/latest"); const data = await githubGet("/releases/latest");
const hash = data.name.slice(data.name.lastIndexOf(" ") + 1); const hash = data.name.slice(data.name.lastIndexOf(" ") + 1);
@ -67,7 +66,7 @@ async function fetchUpdates() {
return true; return true;
} }
async function applyUpdates() { async function applyUpdate() {
if (!PendingUpdate) return true; if (!PendingUpdate) return true;
const data = await fetchBuffer(PendingUpdate); const data = await fetchBuffer(PendingUpdate);
@ -78,7 +77,11 @@ async function applyUpdates() {
return true; return true;
} }
ipcMain.handle(IpcEvents.GET_REPO, serializeErrors(() => `https://github.com/${gitRemote}`)); const HttpUpdater: Updater = {
ipcMain.handle(IpcEvents.GET_UPDATES, serializeErrors(calculateGitChanges)); getRepo: async () => `https://github.com/${gitRemote}`,
ipcMain.handle(IpcEvents.UPDATE, serializeErrors(fetchUpdates)); listUpdates,
ipcMain.handle(IpcEvents.BUILD, serializeErrors(applyUpdates)); fetchUpdate,
applyUpdate
};
export default HttpUpdater;

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