From ae80749dd80b69fd269df23956c66832951ebcd5 Mon Sep 17 00:00:00 2001 From: Nuckyz <61953774+Nuckyz@users.noreply.github.com> Date: Sun, 2 Apr 2023 21:13:44 -0300 Subject: [PATCH] Game Activity Toggle and SettingsStoreAPI (#587) --- README.md | 2 +- src/api/SettingsStore.ts | 71 +++++++++++++++++++++++ src/api/index.ts | 5 ++ src/plugins/apiSettingsStore.ts | 38 ++++++++++++ src/plugins/gameActivityToggle/index.tsx | 73 ++++++++++++++++++++++++ src/plugins/gameActivityToggle/style.css | 19 ++++++ 6 files changed, 207 insertions(+), 1 deletion(-) create mode 100644 src/api/SettingsStore.ts create mode 100644 src/plugins/apiSettingsStore.ts create mode 100644 src/plugins/gameActivityToggle/index.tsx create mode 100644 src/plugins/gameActivityToggle/style.css diff --git a/README.md b/README.md index 9b0b757b3..fa754d617 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ The cutest Discord client mod - Super easy to install (Download Installer, open, click install button, done) - 100+ plugins built in: [See a list](https://gist.github.com/Vendicated/8696cde7b92548064a3ae92ead84d033) - - Some highlights: SpotifyControls, Experiments, NoTrack, MessageLogger, QuickReply, Free Emotes/Stickers, CustomCommands, ShowHiddenChannels, PronounDB + - Some highlights: SpotifyControls, GameActivityToggle, Experiments, NoTrack, MessageLogger, QuickReply, Free Emotes/Stickers, CustomCommands, ShowHiddenChannels, PronounDB - Fairly lightweight despite the many inbuilt plugins - Excellent Browser Support: Run Vencord in your Browser via extension or UserScript - Works on any Discord branch: Stable, Canary or PTB all work (though for the best experience I recommend stable!) diff --git a/src/api/SettingsStore.ts b/src/api/SettingsStore.ts new file mode 100644 index 000000000..59c78ed6b --- /dev/null +++ b/src/api/SettingsStore.ts @@ -0,0 +1,71 @@ +/* + * Vencord, a modification for Discord's desktop app + * Copyright (c) 2023 Vendicated and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . +*/ + +import Logger from "@utils/Logger"; +import { proxyLazy } from "@utils/proxyLazy"; +import { findModuleId, wreq } from "@webpack"; + +import { Settings } from "./settings"; + +interface Setting { + /** + * Get the setting value + */ + getSetting(): T; + /** + * Update the setting value + * @param value The new value + */ + updateSetting(value: T | ((old: T) => T)): Promise; + /** + * React hook for automatically updating components when the setting is updated + */ + useSetting(): T; + settingsStoreApiGroup: string; + settingsStoreApiName: string; +} + +const SettingsStores: Array> | undefined = proxyLazy(() => { + const modId = findModuleId('"textAndImages","renderSpoilers"'); + if (modId == null) return new Logger("SettingsStoreAPI").error("Didn't find stores module."); + + const mod = wreq(modId); + if (mod == null) return; + + return Object.values(mod).filter((s: any) => s?.settingsStoreApiGroup) as any; +}); + +/** + * Get the store for a setting + * @param group The setting group + * @param name The name of the setting + */ +export function getSettingStore(group: string, name: string): Setting | undefined { + if (!Settings.plugins.SettingsStoreAPI.enabled) throw new Error("Cannot use SettingsStoreAPI without setting as dependency."); + + return SettingsStores?.find(s => s?.settingsStoreApiGroup === group && s?.settingsStoreApiName === name); +} + +/** + * getSettingStore but lazy + */ +export function getSettingStoreLazy(group: string, name: string) { + if (!Settings.plugins.SettingsStoreAPI.enabled) throw new Error("Cannot use SettingsStoreAPI without setting as dependency."); + + return proxyLazy(() => getSettingStore(group, name)); +} diff --git a/src/api/index.ts b/src/api/index.ts index e4b87bfce..ba2978ee6 100644 --- a/src/api/index.ts +++ b/src/api/index.ts @@ -28,6 +28,7 @@ import * as $MessagePopover from "./MessagePopover"; import * as $Notices from "./Notices"; import * as $Notifications from "./Notifications"; import * as $ServerList from "./ServerList"; +import * as $SettingsStore from "./SettingsStore"; import * as $Styles from "./Styles"; /** @@ -85,6 +86,10 @@ export const MessageDecorations = $MessageDecorations; * An API allowing you to add components to member list users, in both DM's and servers */ export const MemberListDecorators = $MemberListDecorators; +/** + * An API allowing you to read, manipulate and automatically update components based on Discord settings + */ +export const SettingsStore = $SettingsStore; /** * An API allowing you to dynamically load styles * a diff --git a/src/plugins/apiSettingsStore.ts b/src/plugins/apiSettingsStore.ts new file mode 100644 index 000000000..ca1dc65bf --- /dev/null +++ b/src/plugins/apiSettingsStore.ts @@ -0,0 +1,38 @@ +/* + * Vencord, a modification for Discord's desktop app + * Copyright (c) 2022 Vendicated and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . +*/ + +import { Devs } from "@utils/constants"; +import definePlugin from "@utils/types"; + +export default definePlugin({ + name: "SettingsStoreAPI", + description: "Patches Discord's SettingsStores to expose their group and name", + authors: [Devs.Nuckyz], + + patches: [ + { + find: '"textAndImages","renderSpoilers"', + replacement: [ + { + match: /(?<=INFREQUENT_USER_ACTION.{0,20}),useSetting:function/, + replace: ",settingsStoreApiGroup:arguments[0],settingsStoreApiName:arguments[1]$&" + } + ] + } + ] +}); diff --git a/src/plugins/gameActivityToggle/index.tsx b/src/plugins/gameActivityToggle/index.tsx new file mode 100644 index 000000000..1617e9cf1 --- /dev/null +++ b/src/plugins/gameActivityToggle/index.tsx @@ -0,0 +1,73 @@ +/* + * Vencord, a modification for Discord's desktop app + * Copyright (c) 2023 Vendicated and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . +*/ + +import "./style.css"; + +import { getSettingStoreLazy } from "@api/SettingsStore"; +import ErrorBoundary from "@components/ErrorBoundary"; +import { Devs } from "@utils/constants"; +import definePlugin from "@utils/types"; +import { Tooltip } from "@webpack/common"; + +const ShowCurrentGame = getSettingStoreLazy("status", "showCurrentGame"); + +function GameActivityToggleButton() { + const showCurrentGame = ShowCurrentGame?.useSetting(); + + return ( + + {tooltipProps => ( + + )} + + ); +} + +export default definePlugin({ + name: "GameActivityToggle", + description: "Adds a button next to the mic and deafen button to toggle game activity.", + authors: [Devs.Nuckyz], + dependencies: ["SettingsStoreAPI"], + + patches: [ + { + find: ".Messages.ACCOUNT_SPEAKING_WHILE_MUTED", + replacement: { + match: /this\.renderNameZone\(\).+?children:\[/, + replace: "$&$self.GameActivityToggleButton()," + } + } + ], + + GameActivityToggleButton: ErrorBoundary.wrap(GameActivityToggleButton, { noop: true }) +}); diff --git a/src/plugins/gameActivityToggle/style.css b/src/plugins/gameActivityToggle/style.css new file mode 100644 index 000000000..b6abf47fe --- /dev/null +++ b/src/plugins/gameActivityToggle/style.css @@ -0,0 +1,19 @@ +[class*="withTagAsButton"] { + min-width: 88px; +} + +.game-activity-toggle-btn { + all: unset; + color: var(--interactive-normal); + width: 32px; + height: 32px; + border-radius: 4px; + display: flex; + justify-content: center; + align-items: center; +} + +.game-activity-toggle-btn:hover { + color: var(--interactive-hover); + background-color: var(--background-modifier-selected); +}