diff --git a/package.json b/package.json index 2e9ec032..f052be31 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "equicord", "private": "true", - "version": "1.12.0", + "version": "1.12.1", "description": "The other cutest Discord client mod", "homepage": "https://github.com/Equicord/Equicord#readme", "bugs": { diff --git a/scripts/build/common.mjs b/scripts/build/common.mjs index fd2ff6a7..ca3eab14 100644 --- a/scripts/build/common.mjs +++ b/scripts/build/common.mjs @@ -186,7 +186,7 @@ export const globPlugins = kind => ({ const mod = `p${i}`; code += `import ${mod} from "./${dir}/${fileName.replace(/\.tsx?$/, "")}";\n`; pluginsCode += `[${mod}.name]:${mod},\n`; - metaCode += `[${mod}.name]:${JSON.stringify({ folderName, userPlugin })},\n`; // TODO: add excluded plugins to display in the UI? + metaCode += `[${mod}.name]:${JSON.stringify({ folderName, userPlugin })},\n`; i++; } } diff --git a/src/Vencord.ts b/src/Vencord.ts index 586d732c..927db413 100644 --- a/src/Vencord.ts +++ b/src/Vencord.ts @@ -33,7 +33,7 @@ import { openUpdaterModal } from "@components/VencordSettings/UpdaterTab"; import { StartAt } from "@utils/types"; import { get as dsGet } from "./api/DataStore"; -import { showNotification } from "./api/Notifications"; +import { NotificationData, showNotification } from "./api/Notifications"; import { PlainSettings, Settings } from "./api/Settings"; import { patches, PMLogger, startAllPlugins } from "./plugins"; import { localStorage } from "./utils/localStorage"; @@ -105,6 +105,46 @@ async function syncSettings() { } } +let notifiedForUpdatesThisSession = false; + +async function runUpdateCheck() { + const notify = (data: NotificationData) => { + if (notifiedForUpdatesThisSession) return; + notifiedForUpdatesThisSession = true; + + setTimeout(() => showNotification({ + permanent: true, + noPersist: true, + ...data + }), 10_000); + }; + + try { + const isOutdated = await checkForUpdates(); + if (!isOutdated) return; + + if (Settings.autoUpdate) { + await update(); + if (Settings.autoUpdateNotification) { + notify({ + title: "Equicord has been updated!", + body: "Click here to restart", + onClick: relaunch + }); + } + return; + } + + notify({ + title: "A Equicord update is available!", + body: "Click here to view the update", + onClick: openUpdaterModal! + }); + } catch (err) { + UpdateLogger.error("Failed to check for updates", err); + } +} + async function init() { await onceReady; startAllPlugins(StartAt.WebpackReady); @@ -112,34 +152,8 @@ async function init() { syncSettings(); if (!IS_WEB && !IS_UPDATER_DISABLED) { - try { - const isOutdated = await checkForUpdates(); - if (!isOutdated) return; - - if (Settings.autoUpdate) { - await update(); - if (Settings.updateRelaunch) return relaunch; - if (Settings.autoUpdateNotification) - setTimeout(() => showNotification({ - title: "Equicord has been updated!", - body: "Click here to restart", - permanent: true, - noPersist: true, - onClick: relaunch - }), 10_000); - return; - } - - setTimeout(() => showNotification({ - title: "A Equicord update is available!", - body: "Click here to view the update", - permanent: true, - noPersist: true, - onClick: openUpdaterModal! - }), 10_000); - } catch (err) { - UpdateLogger.error("Failed to check for updates", err); - } + runUpdateCheck(); + setInterval(runUpdateCheck, 1000 * 60 * 30); // 30 minutes } if (IS_DEV) { diff --git a/src/api/Settings.ts b/src/api/Settings.ts index 25c4b3d9..e4dc21c5 100644 --- a/src/api/Settings.ts +++ b/src/api/Settings.ts @@ -39,7 +39,6 @@ export interface Settings { themeLinks: string[]; frameless: boolean; transparent: boolean; - updateRelaunch: boolean; winCtrlQ: boolean; macosVibrancyStyle: | "content" @@ -101,7 +100,6 @@ const DefaultSettings: Settings = { winCtrlQ: false, macosVibrancyStyle: undefined, disableMinSize: false, - updateRelaunch: false, winNativeTitleBar: false, plugins: {}, diff --git a/src/components/DonateButton.tsx b/src/components/DonateButton.tsx index 0d96276c..814eba8e 100644 --- a/src/components/DonateButton.tsx +++ b/src/components/DonateButton.tsx @@ -41,7 +41,7 @@ export function VCDonateButton({ ); } -export default function DonateButton({ +export function DonateButton({ look = Button.Looks.LINK, color = Button.Colors.TRANSPARENT, ...props diff --git a/src/components/VencordSettings/UpdaterTab.tsx b/src/components/VencordSettings/UpdaterTab.tsx index c03f5b93..f500b720 100644 --- a/src/components/VencordSettings/UpdaterTab.tsx +++ b/src/components/VencordSettings/UpdaterTab.tsx @@ -106,8 +106,6 @@ function Updatable(props: CommonProps) { const [updates, setUpdates] = React.useState(changes); const [isChecking, setIsChecking] = React.useState(false); const [isUpdating, setIsUpdating] = React.useState(false); - - const settings = useSettings(["updateRelaunch"]); const isOutdated = (updates?.length ?? 0) > 0; return ( @@ -119,7 +117,6 @@ function Updatable(props: CommonProps) { onClick={withDispatcher(setIsUpdating, async () => { if (await update()) { setUpdates([]); - if (settings.updateRelaunch) return relaunch(); return await new Promise(r => { Alerts.show({ title: "Update Success!", @@ -191,7 +188,7 @@ function Newer(props: CommonProps) { } function Updater() { - const settings = useSettings(["autoUpdate", "updateRelaunch", "autoUpdateNotification"]); + const settings = useSettings(["autoUpdate", "autoUpdateNotification"]); const [repo, err, repoPending] = useAwaiter(getRepo, { fallbackValue: "Loading..." }); @@ -217,30 +214,12 @@ function Updater() { { - settings.autoUpdateNotification = v; - if (settings.updateRelaunch) { - settings.updateRelaunch = !v; - } - }} + onChange={(v: boolean) => settings.autoUpdateNotification = v} note="Shows a notification when Equicord automatically updates" disabled={!settings.autoUpdate} > Get notified when an automatic update completes - { - settings.updateRelaunch = v; - if (settings.autoUpdateNotification) { - settings.autoUpdateNotification = !v; - } - }} - note="Relaunches the app after updating with no prompt" - disabled={!settings.autoUpdate} - > - Automatically relaunch after updating - Repo diff --git a/src/components/VencordSettings/VencordTab.tsx b/src/components/VencordSettings/VencordTab.tsx index b1908270..606986b7 100644 --- a/src/components/VencordSettings/VencordTab.tsx +++ b/src/components/VencordSettings/VencordTab.tsx @@ -9,7 +9,7 @@ import "./VencordTab.css"; import { openNotificationLogModal } from "@api/Notifications/notificationLog"; import { useSettings } from "@api/Settings"; import { classNameFactory } from "@api/Styles"; -import DonateButton, { InviteButton } from "@components/DonateButton"; +import { DonateButton, InviteButton } from "@components/DonateButton"; import { openContributorModal } from "@components/PluginSettings/ContributorModal"; import { openPluginModal } from "@components/PluginSettings/PluginModal"; import { gitRemote } from "@shared/vencordUserAgent"; diff --git a/src/plugins/_api/badges/index.tsx b/src/plugins/_api/badges/index.tsx index 7e6d9a3e..c3ef0598 100644 --- a/src/plugins/_api/badges/index.tsx +++ b/src/plugins/_api/badges/index.tsx @@ -19,21 +19,18 @@ import "./fixDiscordBadgePadding.css"; import { _getBadges, BadgePosition, BadgeUserArgs, ProfileBadge } from "@api/Badges"; -import DonateButton, { VCDonateButton } from "@components/DonateButton"; import ErrorBoundary from "@components/ErrorBoundary"; -import { Flex } from "@components/Flex"; -import { Heart } from "@components/Heart"; import { openContributorModal } from "@components/PluginSettings/ContributorModal"; import { isEquicordDonor } from "@components/VencordSettings/VencordTab"; import { Devs } from "@utils/constants"; import { Logger } from "@utils/Logger"; -import { Margins } from "@utils/margins"; import { isEquicordPluginDev, isPluginDev } from "@utils/misc"; -import { closeModal, ModalContent, ModalFooter, ModalHeader, ModalRoot, openModal } from "@utils/modal"; import definePlugin from "@utils/types"; -import { Forms, Toasts, UserStore } from "@webpack/common"; +import { Toasts, UserStore } from "@webpack/common"; import { User } from "discord-types/general"; +import { EquicordDonorModal, VencordDonorModal } from "./modals"; + const CONTRIBUTOR_BADGE = "https://vencord.dev/assets/favicon.png"; const EQUICORD_CONTRIBUTOR_BADGE = "https://i.imgur.com/57ATLZu.png"; const EQUICORD_DONOR_BADGE = "https://cdn.nest.rip/uploads/78cb1e77-b7a6-4242-9089-e91f866159bf.png"; @@ -62,6 +59,9 @@ const EquicordDonorBadge: ProfileBadge = { const donorBadges = EquicordDonorBadges[userId]?.map(badge => badge.badge); const hasDonorBadge = donorBadges?.includes("https://cdn.nest.rip/uploads/78cb1e77-b7a6-4242-9089-e91f866159bf.png"); return isEquicordDonor(userId) && !hasDonorBadge; + }, + onClick: () => { + return EquicordDonorModal(); } }; @@ -83,6 +83,7 @@ async function loadAllBadges(noCache = false) { EquicordDonorBadges = equicordBadges; } +let intervalId: any; export default definePlugin({ name: "BadgeAPI", @@ -117,6 +118,15 @@ export default definePlugin({ } ], + // for access from the console or other plugins + get DonorBadges() { + return DonorBadges; + }, + + get EquicordDonorBadges() { + return EquicordDonorBadges; + }, + toolboxActions: { async "Refetch Badges"() { await loadAllBadges(true); @@ -128,11 +138,16 @@ export default definePlugin({ } }, + userProfileBadges: [ContributorBadge, EquicordContributorBadge, EquicordDonorBadge], + async start() { - Vencord.Api.Badges.addProfileBadge(ContributorBadge); - Vencord.Api.Badges.addProfileBadge(EquicordContributorBadge); - Vencord.Api.Badges.addProfileBadge(EquicordDonorBadge); await loadAllBadges(); + clearInterval(intervalId); + intervalId = setInterval(loadAllBadges, 1000 * 60 * 30); // 30 minutes + }, + + async stop() { + clearInterval(intervalId); }, getBadges(props: { userId: string; user?: User; guildId: string; }) { @@ -166,59 +181,7 @@ export default definePlugin({ } }, onClick() { - const modalKey = openModal(props => ( - { - closeModal(modalKey); - VencordNative.native.openExternal("https://github.com/sponsors/Vendicated"); - }}> - - - - - - Vencord Donor - - - - - - - - -
- - This Badge is a special perk for Vencord Donors - - - Please consider supporting the development of Vencord by becoming a donor. It would mean a lot! - -
-
- - - - - -
-
- )); + return VencordDonorModal(); }, })); }, @@ -235,60 +198,7 @@ export default definePlugin({ } }, onClick() { - const modalKey = openModal(props => ( - { - closeModal(modalKey); - // Will get my own in the future - VencordNative.native.openExternal("https://github.com/sponsors/Vendicated"); - }}> - - - - - - Equicord Donor - - - - - - - - -
- - This Badge is a special perk for Equicord (Not Vencord) Donors - - - Please consider supporting the development of Equicord by becoming a donor. It would mean a lot! :3 - -
-
- - - - - -
-
- )); + return EquicordDonorModal(); }, })); } diff --git a/src/plugins/_api/badges/modals.tsx b/src/plugins/_api/badges/modals.tsx new file mode 100644 index 00000000..5955387d --- /dev/null +++ b/src/plugins/_api/badges/modals.tsx @@ -0,0 +1,126 @@ +/* + * Vencord, a Discord client mod + * Copyright (c) 2025 Vendicated and contributors + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +import { DonateButton, VCDonateButton } from "@components/DonateButton"; +import { Flex } from "@components/Flex"; +import { Heart } from "@components/Heart"; +import { ErrorBoundary } from "@components/index"; +import { Margins } from "@utils/margins"; +import { closeModal, ModalContent, ModalFooter, ModalHeader, ModalRoot, openModal } from "@utils/modal"; +import { Forms } from "@webpack/common"; + +export function VencordDonorModal() { + const modalKey = openModal(props => ( + { + closeModal(modalKey); + VencordNative.native.openExternal("https://github.com/sponsors/Vendicated"); + }}> + + + + + + Vencord Donor + + + + + + + + +
+ + This Badge is a special perk for Vencord Donors + + + Please consider supporting the development of Vencord by becoming a donor. It would mean a lot! + +
+
+ + + + + +
+
+ )); +} + +export function EquicordDonorModal() { + const modalKey = openModal(props => ( + { + closeModal(modalKey); + // Will get my own in the future + VencordNative.native.openExternal("https://github.com/sponsors/thororen1234"); + }}> + + + + + + Equicord Donor + + + + + + + + +
+ + This Badge is a special perk for Equicord (Not Vencord) Donors + + + Please consider supporting the development of Equicord by becoming a donor. It would mean a lot! :3 + +
+
+ + + + + +
+
+ )); +} diff --git a/src/plugins/index.ts b/src/plugins/index.ts index c1ca6023..5a16c434 100644 --- a/src/plugins/index.ts +++ b/src/plugins/index.ts @@ -133,7 +133,7 @@ for (const p of pluginsValues) if (isPluginEnabled(p.name)) { if (p.renderMessageAccessory) neededApiPlugins.add("MessageAccessoriesAPI"); if (p.renderMessageDecoration) neededApiPlugins.add("MessageDecorationsAPI"); if (p.renderMessagePopoverButton) neededApiPlugins.add("MessagePopoverAPI"); - if (p.userProfileBadge) neededApiPlugins.add("BadgeAPI"); + if (p.userProfileBadges) neededApiPlugins.add("BadgeAPI"); for (const key of pluginKeysToBind) { p[key] &&= p[key].bind(p) as any; @@ -261,7 +261,7 @@ export function subscribeAllPluginsFluxEvents(fluxDispatcher: typeof FluxDispatc export const startPlugin = traceFunction("startPlugin", function startPlugin(p: Plugin) { const { - name, commands, contextMenus, managedStyle, userProfileBadge, + name, commands, contextMenus, managedStyle, userProfileBadges, onBeforeMessageEdit, onBeforeMessageSend, onMessageClick, renderChatBarButton, renderMemberListDecorator, renderNicknameIcon, renderMessageAccessory, renderMessageDecoration, renderMessagePopoverButton } = p; @@ -307,7 +307,7 @@ export const startPlugin = traceFunction("startPlugin", function startPlugin(p: if (managedStyle) enableStyle(managedStyle); - if (userProfileBadge) addProfileBadge(userProfileBadge); + if (userProfileBadges) userProfileBadges.forEach(e => addProfileBadge(e)); if (onBeforeMessageEdit) addMessagePreEditListener(onBeforeMessageEdit); if (onBeforeMessageSend) addMessagePreSendListener(onBeforeMessageSend); @@ -325,7 +325,7 @@ export const startPlugin = traceFunction("startPlugin", function startPlugin(p: export const stopPlugin = traceFunction("stopPlugin", function stopPlugin(p: Plugin) { const { - name, commands, contextMenus, managedStyle, userProfileBadge, + name, commands, contextMenus, managedStyle, userProfileBadges, onBeforeMessageEdit, onBeforeMessageSend, onMessageClick, renderChatBarButton, renderMemberListDecorator, renderNicknameIcon, renderMessageAccessory, renderMessageDecoration, renderMessagePopoverButton } = p; @@ -369,7 +369,7 @@ export const stopPlugin = traceFunction("stopPlugin", function stopPlugin(p: Plu if (managedStyle) disableStyle(managedStyle); - if (userProfileBadge) removeProfileBadge(userProfileBadge); + if (userProfileBadges) userProfileBadges.forEach(e => removeProfileBadge(e)); if (onBeforeMessageEdit) removeMessagePreEditListener(onBeforeMessageEdit); if (onBeforeMessageSend) removeMessagePreSendListener(onBeforeMessageSend); diff --git a/src/plugins/invisibleChat.desktop/index.tsx b/src/plugins/invisibleChat.desktop/index.tsx index f5e8cbb5..ab124192 100644 --- a/src/plugins/invisibleChat.desktop/index.tsx +++ b/src/plugins/invisibleChat.desktop/index.tsx @@ -110,7 +110,7 @@ export default definePlugin({ patches: [ { // Indicator - find: "#{intl::MESSAGE_EDITED}", + find: ".SEND_FAILED,", replacement: { match: /let\{className:\i,message:\i[^}]*\}=(\i)/, replace: "try {$1 && $self.INV_REGEX.test($1.message.content) ? $1.content.push($self.indicator()) : null } catch {};$&" diff --git a/src/plugins/messageLogger/index.tsx b/src/plugins/messageLogger/index.tsx index d58bf636..b2f368ff 100644 --- a/src/plugins/messageLogger/index.tsx +++ b/src/plugins/messageLogger/index.tsx @@ -487,22 +487,23 @@ export default definePlugin({ ], }, + // Message content renderer + { + find: ".SEND_FAILED,", + replacement: { + // Render editHistory in the deepest div for message content + match: /(\)\("div",\{id:.+?children:\[)/, + replace: "$1 (!!arguments[0].message.editHistory?.length && $self.renderEdits(arguments[0]))," + } + }, + { - // Message content renderer find: "#{intl::MESSAGE_EDITED}", - replacement: [ - { - // Render editHistory in the deepest div for message content - match: /(\)\("div",\{id:.+?children:\[)/, - replace: - "$1 (!!arguments[0].message.editHistory?.length && $self.renderEdits(arguments[0])),", - }, - { - // Make edit marker clickable - match: /"span",\{(?=className:\i\.edited,)/, - replace: "$self.EditMarker,{message:arguments[0].message,", - }, - ], + replacement: { + // Make edit marker clickable + match: /"span",\{(?=className:\i\.edited,)/, + replace: "$self.EditMarker,{message:arguments[0].message," + } }, { diff --git a/src/plugins/noServerEmojis/index.ts b/src/plugins/noServerEmojis/index.ts index 6a39f55c..cd950b42 100644 --- a/src/plugins/noServerEmojis/index.ts +++ b/src/plugins/noServerEmojis/index.ts @@ -30,7 +30,7 @@ export default definePlugin({ { find: "}searchWithoutFetchingLatest(", replacement: { - match: /searchWithoutFetchingLatest.{20,300}get\((\i).{10,40}?reduce\(\((\i),(\i)\)=>\{/, + match: /\.get\((\i)\)\.nameMatchesChain\(\i\)\.reduce\(\((\i),(\i)\)=>\{/, replace: "$& if ($self.shouldSkip($1, $3)) return $2;" } } diff --git a/src/plugins/roleColorEverywhere/index.tsx b/src/plugins/roleColorEverywhere/index.tsx index dfa8dd5c..7b2d5714 100644 --- a/src/plugins/roleColorEverywhere/index.tsx +++ b/src/plugins/roleColorEverywhere/index.tsx @@ -154,7 +154,7 @@ export default definePlugin({ }, // Messages { - find: "#{intl::MESSAGE_EDITED}", + find: ".SEND_FAILED,", replacement: { match: /(?<=isUnsupported\]:(\i)\.isUnsupported\}\),)(?=children:\[)/, replace: "style:$self.useMessageColorsStyle($1)," diff --git a/src/utils/types.ts b/src/utils/types.ts index b2435c6f..fcbde877 100644 --- a/src/utils/types.ts +++ b/src/utils/types.ts @@ -177,7 +177,7 @@ export interface PluginDef { */ managedStyle?: string; - userProfileBadge?: ProfileBadge; + userProfileBadges?: ProfileBadge[]; onMessageClick?: MessageClickListener; onBeforeMessageSend?: MessageSendListener; diff --git a/src/utils/updater.ts b/src/utils/updater.ts index f99c6ca1..25fe6ee8 100644 --- a/src/utils/updater.ts +++ b/src/utils/updater.ts @@ -39,10 +39,15 @@ async function Unwrap(p: Promise>) { export async function checkForUpdates() { changes = await Unwrap(VencordNative.updater.getUpdates()); - if (changes.some(c => c.hash === gitHash)) { - isNewer = true; - return (isOutdated = false); + + // we only want to check this for the git updater, not the http updater + if (!IS_STANDALONE) { + if (changes.some(c => c.hash === gitHash)) { + isNewer = true; + return (isOutdated = false); + } } + return (isOutdated = changes.length > 0); }