diff --git a/packages/discord-types/src/stores/RunningGameStore.d.ts b/packages/discord-types/src/stores/RunningGameStore.d.ts index 99b2987b0..569d2052d 100644 --- a/packages/discord-types/src/stores/RunningGameStore.d.ts +++ b/packages/discord-types/src/stores/RunningGameStore.d.ts @@ -53,7 +53,7 @@ export class RunningGameStore extends FluxStore { getSystemServiceStatus(service: string): SystemServiceStatus; getVisibleGame(): RunningGame | null; getVisibleRunningGames(): RunningGame[]; - isDetectionEnabled(type?: string): boolean; + isDetectionEnabled(game: RunningGame): boolean; isGamesSeenLoaded(): boolean; isObservedAppRunning(app: string): boolean; isSystemServiceInitialized(service: string): boolean; diff --git a/src/components/Icons.tsx b/src/components/Icons.tsx index 79c82675c..24c8e29b5 100644 --- a/src/components/Icons.tsx +++ b/src/components/Icons.tsx @@ -1453,3 +1453,17 @@ export function RemixIcon(props: IconProps) { ); } + +export function UploadIcon(props: IconProps) { + return ( + + + + ); +} diff --git a/src/fixWeirdAppRegionBug.css b/src/fixWeirdAppRegionBug.css index dadb596ac..ce2446aca 100644 --- a/src/fixWeirdAppRegionBug.css +++ b/src/fixWeirdAppRegionBug.css @@ -1,4 +1,4 @@ /* Works around a very strange issue where *something* (electron?) will inject body { app-region: drag } when using online themes */ body { - app-region: no-drag; + app-region: unset; } diff --git a/src/main/patcher.ts b/src/main/patcher.ts index 17c46b95f..6a3e1fcef 100644 --- a/src/main/patcher.ts +++ b/src/main/patcher.ts @@ -93,8 +93,6 @@ if (!IS_VANILLA) { const isMainWindow = options.title === "Discord"; options.webPreferences.preload = join(__dirname, "preload.js"); options.webPreferences.sandbox = false; - // work around discord unloading when in background - options.webPreferences.backgroundThrottling = false; if (mainWindowFrameless && isMainWindow) { options.frame = false; @@ -152,27 +150,6 @@ if (!IS_VANILLA) { }); process.env.DATA_DIR = join(app.getPath("userData"), "..", "Equicord"); - - // Monkey patch commandLine to: - // - disable UseEcoQoSForBackgroundProcess: Work around Discord unloading when in background - const originalAppend = app.commandLine.appendSwitch; - app.commandLine.appendSwitch = function (...args) { - if (args[0] === "disable-features") { - const disabledFeatures = new Set((args[1] ?? "").split(",")); - disabledFeatures.add("UseEcoQoSForBackgroundProcess"); - args[1] += [...disabledFeatures].join(","); - } - return originalAppend.apply(this, args); - }; - - // disable renderer backgrounding to prevent the app from unloading when in the background - // https://github.com/electron/electron/issues/2822 - // https://github.com/GoogleChrome/chrome-launcher/blob/5a27dd574d47a75fec0fb50f7b774ebf8a9791ba/docs/chrome-flags-for-tools.md#task-throttling - // Work around discord unloading when in background - // Discord also recently started adding these flags but only on windows for some reason dunno why, it happens on Linux too - app.commandLine.appendSwitch("disable-renderer-backgrounding"); - app.commandLine.appendSwitch("disable-background-timer-throttling"); - app.commandLine.appendSwitch("disable-backgrounding-occluded-windows"); } else { console.log("[Equicord] Running in vanilla mode. Not loading Equicord"); } diff --git a/src/plugins/addAttachments/README.md b/src/plugins/addAttachments/README.md new file mode 100644 index 000000000..8ecf140e7 --- /dev/null +++ b/src/plugins/addAttachments/README.md @@ -0,0 +1,7 @@ +# AddAttachments + +Allows you to add new attachments while editing messages. + +Start editing a message and then you can either press the "Add Attachment" button or paste files from your clipboard! + +![](https://github.com/user-attachments/assets/3a3a5cda-ab36-4dee-bd28-2d2a08f8f996) diff --git a/src/plugins/addAttachments/index.tsx b/src/plugins/addAttachments/index.tsx new file mode 100644 index 000000000..8f09666fd --- /dev/null +++ b/src/plugins/addAttachments/index.tsx @@ -0,0 +1,162 @@ +/* + * Vencord, a Discord client mod + * Copyright (c) 2025 Vendicated and contributors + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +import { ChatBarButton } from "@api/ChatButtons"; +import { UploadIcon } from "@components/Icons"; +import { Devs } from "@utils/constants"; +import { pluralise } from "@utils/misc"; +import definePlugin from "@utils/types"; +import { Message } from "@vencord/discord-types"; +import { MessageFlags, MessageType } from "@vencord/discord-types/enums"; +import { findByPropsLazy } from "@webpack"; +import { AuthenticationStore, ChannelStore, EditMessageStore, MessageStore, PermissionsBits, PermissionStore, RestAPI, SelectedChannelStore, showToast, Toasts } from "@webpack/common"; + +const { uniqueId } = findByPropsLazy("uniqueId"); + +function chooseAttachments(channelId: string, messageId: string, existingAttachmentCount: number) { + const input = document.createElement("input"); + input.type = "file"; + input.accept = "*/*"; + input.multiple = true; + input.click(); + + input.addEventListener("change", async () => { + try { + if (!input.files) return; + await addAttachments(channelId, messageId, existingAttachmentCount, input.files); + } finally { + input.remove(); + } + }); +} + +async function addAttachments(channelId: string, messageId: string, existingAttachmentCount: number, files: FileList) { + if (!files) return; + + if (files.length + existingAttachmentCount > 10) { + const remaining = 10 - existingAttachmentCount; + if (remaining <= 0) { + showToast("You cannot add more attachments to this message.", Toasts.Type.FAILURE); + return; + } + + showToast(`You can only add ${pluralise(remaining, "more attachment")} to this message.`, Toasts.Type.FAILURE); + return; + } + + showToast("Uploading, this can take a while...", Toasts.Type.CLOCK); + + const { body: { attachments } } = await RestAPI.post({ + url: `/channels/${channelId}/attachments`, + body: { + files: Array.from(files, file => ({ + filename: file.name, + file_size: file.size, + id: uniqueId(), + is_clip: false + })) + } + }) as { body: { attachments: { id: string, upload_url: string, upload_filename: string; }[]; }; }; + + const newAttachments = await Promise.all( + attachments.map((file, i) => + fetch(file.upload_url, { + method: "PUT", + body: files[i] + }).then(() => ({ + id: file.id, + uploaded_filename: file.upload_filename, + filename: files[i].name + })) + ) + ); + + + const msg = MessageStore.getMessage(channelId, messageId); + + await RestAPI.patch({ + url: `/channels/${channelId}/messages/${messageId}`, + body: { + attachments: [ + ...msg.attachments, + ...newAttachments + ] + } + }); + + showToast(`${files.length === 1 ? "Attachment" : "Attachments"} added successfully!`, Toasts.Type.SUCCESS); +} + +function canAddAttachments(msg: Message) { + return ( + [MessageType.DEFAULT, MessageType.REPLY].includes(msg.type) && + !msg.hasFlag(MessageFlags.IS_VOICE_MESSAGE) && + AuthenticationStore.getId() === msg.author.id && + msg.attachments.length < 10 + ); +} + +function handlePaste(e: ClipboardEvent) { + if (!e.clipboardData?.files.length) return; + + const msg = EditMessageStore.getEditingMessage(SelectedChannelStore.getChannelId()); + if (!msg) return; + + e.preventDefault(); + e.stopImmediatePropagation(); + + addAttachments(msg.channel_id, msg.id, msg.attachments.length, e.clipboardData.files); +} + +export default definePlugin({ + name: "AddAttachments", + description: "Allows you to add new attachments while editing messages", + authors: [Devs.Lumap], + + start() { + document.addEventListener("paste", handlePaste, { capture: true }); + }, + stop() { + document.removeEventListener("paste", handlePaste, { capture: true }); + }, + + messagePopoverButton: { + icon: UploadIcon, + render(msg) { + if (!canAddAttachments(msg)) return null; + + const channel = ChannelStore.getChannel(msg.channel_id); + if (!channel.isPrivate() && !PermissionStore.can(PermissionsBits.SEND_MESSAGES, channel)) return null; + + return { + label: "Add Attachments", + icon: UploadIcon, + message: msg, + channel: ChannelStore.getChannel(msg.channel_id), + onClick: () => chooseAttachments(msg.channel_id, msg.id, msg.attachments.length) + }; + }, + }, + + chatBarButton: { + icon: UploadIcon, + render({ channel, type }) { + if (type.analyticsName !== "edit") return null; + + const msg = EditMessageStore.getEditingMessage(channel.id); + if (!msg || !canAddAttachments(msg)) return null; + + return ( + chooseAttachments(msg.channel_id, msg.id, msg.attachments.length)} + > + + + ); + } + } +}); diff --git a/src/plugins/experiments/hideBugReport.css b/src/plugins/experiments/hideBugReport.css deleted file mode 100644 index ff78555d7..000000000 --- a/src/plugins/experiments/hideBugReport.css +++ /dev/null @@ -1,3 +0,0 @@ -#staff-help-popout-staff-help-bug-reporter { - display: none; -} diff --git a/src/plugins/ignoreActivities/README.md b/src/plugins/ignoreActivities/README.md index abc75720f..7496ada69 100644 --- a/src/plugins/ignoreActivities/README.md +++ b/src/plugins/ignoreActivities/README.md @@ -2,12 +2,14 @@ Ignore activities from showing up on your status ONLY. You can configure which ones are specifically ignored from the Registered Games and Activities tabs, or use the general settings. -![](https://github.com/user-attachments/assets/f0c19060-0ecf-4f1c-8165-a5aa40143c82) +![](https://github.com/user-attachments/assets/5da33269-af2d-4fd5-a3fb-7176c039f812) -![](https://github.com/user-attachments/assets/73c3fa7a-5b90-41ee-a4d6-91fa76458b74) +![](https://github.com/user-attachments/assets/7376d230-7ca0-4468-8598-a0e5818a7e28) -![](https://github.com/user-attachments/assets/1ab3fe73-3911-48d1-8a08-e976af614b41) +![](https://github.com/user-attachments/assets/96abf73c-bc3e-4eb1-8b15-01b914964677) -The activity stays showing as a detected game even if ignored, differently from the stock Toggle Detection button from Discord: +The activity stays showing as a detected game even if ignored, but is excluded from the status, differently from the stock Toggle Detection button from Discord: + +![](https://github.com/user-attachments/assets/f7b82992-279e-4449-bcad-d6ab536b9f13) +![](https://github.com/user-attachments/assets/d498bf1d-36ef-4cbe-8043-2893325176d3) -![](https://github.com/user-attachments/assets/08ea60c3-3a31-42de-ae4c-7535fbf1b45a) diff --git a/src/plugins/ignoreActivities/index.tsx b/src/plugins/ignoreActivities/index.tsx index 808776575..f60eb404f 100644 --- a/src/plugins/ignoreActivities/index.tsx +++ b/src/plugins/ignoreActivities/index.tsx @@ -4,17 +4,19 @@ * SPDX-License-Identifier: GPL-3.0-or-later */ +import { NavContextMenuPatchCallback } from "@api/ContextMenu"; import { definePluginSettings } from "@api/Settings"; import { getUserSettingLazy } from "@api/UserSettings"; +import { Button } from "@components/Button"; import ErrorBoundary from "@components/ErrorBoundary"; import { Flex } from "@components/Flex"; -import { HeadingSecondary } from "@components/Heading"; +import { Heading } from "@components/Heading"; import { Paragraph } from "@components/Paragraph"; import CustomRpcPlugin from "@plugins/customRPC"; import { Devs } from "@utils/constants"; import { Margins } from "@utils/margins"; import definePlugin, { OptionType } from "@utils/types"; -import { Button, RunningGameStore, showToast, TextArea, Toasts, Tooltip, useEffect, useState } from "@webpack/common"; +import { FluxDispatcher, Menu, RunningGameStore, showToast, TextArea, Toasts, Tooltip, useEffect, useState } from "@webpack/common"; const enum ActivitiesTypes { Game, @@ -32,16 +34,17 @@ const enum FilterMode { Blacklist } -const ShowCurrentGame = getUserSettingLazy("status", "showCurrentGame")!; +const ShowCurrentGame = getUserSettingLazy("status", "showCurrentGame")!; function ToggleIcon(activity: IgnoredActivity, tooltipText: string, path: string, fill: string) { return ( {tooltipProps => ( - + )} ); } -const ToggleIconOn = (activity: IgnoredActivity, fill: string) => ToggleIcon(activity, "Disable activity", "M480-320q75 0 127.5-52.5T660-500q0-75-52.5-127.5T480-680q-75 0-127.5 52.5T300-500q0 75 52.5 127.5T480-320Zm0-72q-45 0-76.5-31.5T372-500q0-45 31.5-76.5T480-608q45 0 76.5 31.5T588-500q0 45-31.5 76.5T480-392Zm0 192q-146 0-266-81.5T40-500q54-137 174-218.5T480-800q146 0 266 81.5T920-500q-54 137-174 218.5T480-200Zm0-300Zm0 220q113 0 207.5-59.5T832-500q-50-101-144.5-160.5T480-720q-113 0-207.5 59.5T128-500q50 101 144.5 160.5T480-280Z", fill); -const ToggleIconOff = (activity: IgnoredActivity, fill: string) => ToggleIcon(activity, "Enable activity", "m644-428-58-58q9-47-27-88t-93-32l-58-58q17-8 34.5-12t37.5-4q75 0 127.5 52.5T660-500q0 20-4 37.5T644-428Zm128 126-58-56q38-29 67.5-63.5T832-500q-50-101-143.5-160.5T480-720q-29 0-57 4t-55 12l-62-62q41-17 84-25.5t90-8.5q151 0 269 83.5T920-500q-23 59-60.5 109.5T772-302Zm20 246L624-222q-35 11-70.5 16.5T480-200q-151 0-269-83.5T40-500q21-53 53-98.5t73-81.5L56-792l56-56 736 736-56 56ZM222-624q-29 26-53 57t-41 67q50 101 143.5 160.5T480-280q20 0 39-2.5t39-5.5l-36-38q-11 3-21 4.5t-21 1.5q-75 0-127.5-52.5T300-500q0-11 1.5-21t4.5-21l-84-82Zm319 93Zm-151 75Z", fill); +const ToggleIconOn = (activity: IgnoredActivity, fill: string) => ToggleIcon(activity, "Disable Activity", "M480-320q75 0 127.5-52.5T660-500q0-75-52.5-127.5T480-680q-75 0-127.5 52.5T300-500q0 75 52.5 127.5T480-320Zm0-72q-45 0-76.5-31.5T372-500q0-45 31.5-76.5T480-608q45 0 76.5 31.5T588-500q0 45-31.5 76.5T480-392Zm0 192q-146 0-266-81.5T40-500q54-137 174-218.5T480-800q146 0 266 81.5T920-500q-54 137-174 218.5T480-200Zm0-300Zm0 220q113 0 207.5-59.5T832-500q-50-101-144.5-160.5T480-720q-113 0-207.5 59.5T128-500q50 101 144.5 160.5T480-280Z", fill); +const ToggleIconOff = (activity: IgnoredActivity, fill: string) => ToggleIcon(activity, "Enable Activity", "m644-428-58-58q9-47-27-88t-93-32l-58-58q17-8 34.5-12t37.5-4q75 0 127.5 52.5T660-500q0 20-4 37.5T644-428Zm128 126-58-56q38-29 67.5-63.5T832-500q-50-101-143.5-160.5T480-720q-29 0-57 4t-55 12l-62-62q41-17 84-25.5t90-8.5q151 0 269 83.5T920-500q-23 59-60.5 109.5T772-302Zm20 246L624-222q-35 11-70.5 16.5T480-200q-151 0-269-83.5T40-500q21-53 53-98.5t73-81.5L56-792l56-56 736 736-56 56ZM222-624q-29 26-53 57t-41 67q50 101 143.5 160.5T480-280q20 0 39-2.5t39-5.5l-36-38q-11 3-21 4.5t-21 1.5q-75 0-127.5-52.5T300-500q0-11 1.5-21t4.5-21l-84-82Zm319 93Zm-151 75Z", fill); -function ToggleActivityComponent(activity: IgnoredActivity, isPlaying = false) { +function ToggleActivityComponent(activity: IgnoredActivity) { const s = settings.use(["ignoredActivities"]); const { ignoredActivities } = s; if (ignoredActivities.some(act => act.id === activity.id)) return ToggleIconOff(activity, "var(--status-danger)"); - return ToggleIconOn(activity, isPlaying ? "var(--green-300)" : "var(--interactive-icon-default)"); + return ToggleIconOn(activity, "var(--interactive-icon-default)"); } -function handleActivityToggle(e: React.MouseEvent, activity: IgnoredActivity) { +function handleActivityToggle(e: React.MouseEvent, activity: IgnoredActivity) { e.stopPropagation(); const ignoredActivityIndex = settings.store.ignoredActivities.findIndex(act => act.id === activity.id); @@ -76,7 +79,7 @@ function handleActivityToggle(e: React.MouseEvent } function recalculateActivities() { - ShowCurrentGame.updateSetting(old => old); + ShowCurrentGame.updateSetting(current => current); } function ImportCustomRPCComponent() { @@ -132,7 +135,7 @@ function IdsListComponent(props: { setValue: (value: string) => void; }) { return (
- Filter List + Filter List Comma separated list of activity IDs to filter (Useful for filtering specific RPC activities and CustomRPC