From 11e688dd9cedaa12b242445c8f6249372894360a Mon Sep 17 00:00:00 2001 From: Tharki-God Date: Sun, 21 Apr 2024 14:44:13 +0530 Subject: [PATCH] nyaa --- package.json | 2 +- pnpm-lock.yaml | 52 ++------ src/Components/AccountDetailsButton.tsx | 16 +-- src/Components/ContextMenu.tsx | 67 ++++------ src/Components/Icons.tsx | 1 - src/Components/Settings.tsx | 7 +- src/index.ts | 18 ++- .../AccountContextMenu.tsx | 81 ++++-------- src/{patches => injections}/AudioResolver.ts | 4 +- src/injections/index.ts | 10 ++ src/lib/UserSettingStore.ts | 39 +++--- src/lib/consts.ts | 6 +- src/lib/requiredModules.ts | 62 ++++----- src/lib/utils.ts | 122 ++++++++++++++---- src/listeners/CleanCallback.ts | 4 +- src/listeners/KeybindListener.ts | 7 +- src/listeners/index.ts | 21 +-- src/patches/index.ts | 8 -- src/types.ts | 101 +++++++++++++-- 19 files changed, 352 insertions(+), 276 deletions(-) rename src/{patches => injections}/AccountContextMenu.tsx (57%) rename src/{patches => injections}/AudioResolver.ts (87%) create mode 100644 src/injections/index.ts delete mode 100644 src/patches/index.ts diff --git a/package.json b/package.json index d80c650..669a5c0 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ "eslint-plugin-node": "^11.1.0", "eslint-plugin-react": "^7.33.2", "prettier": "^2.8.8", - "replugged": "^4.7.9", + "replugged": "4.7.9", "typescript": "^5.0.0" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 99430d9..15d5a5d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -33,7 +33,7 @@ devDependencies: specifier: ^2.8.8 version: 2.8.8 replugged: - specifier: ^4.7.9 + specifier: 4.7.9 version: 4.7.9(@codemirror/view@6.26.0)(@lezer/common@1.2.1) typescript: specifier: ^5.0.0 @@ -46,21 +46,7 @@ packages: engines: {node: '>=0.10.0'} dev: true - /@codemirror/autocomplete@6.9.1(@codemirror/language@6.10.1)(@codemirror/state@6.4.1)(@codemirror/view@6.19.0)(@lezer/common@1.2.1): - resolution: {integrity: sha512-yma56tqD7khIZK4gy4X5lX3/k5ArMiCGat7HEWRF/8L2kqOjVdp2qKZqpcJjwTIjSj6fqKAHqi7IjtH3QFE+Bw==} - peerDependencies: - '@codemirror/language': ^6.0.0 - '@codemirror/state': ^6.0.0 - '@codemirror/view': ^6.0.0 - '@lezer/common': ^1.0.0 - dependencies: - '@codemirror/language': 6.10.1 - '@codemirror/state': 6.4.1 - '@codemirror/view': 6.19.0 - '@lezer/common': 1.2.1 - dev: true - - /@codemirror/autocomplete@6.9.1(@codemirror/language@6.10.1)(@codemirror/state@6.4.1)(@codemirror/view@6.26.0)(@lezer/common@1.0.4): + /@codemirror/autocomplete@6.9.1(@codemirror/language@6.10.1)(@codemirror/state@6.4.1)(@codemirror/view@6.26.0)(@lezer/common@1.2.1): resolution: {integrity: sha512-yma56tqD7khIZK4gy4X5lX3/k5ArMiCGat7HEWRF/8L2kqOjVdp2qKZqpcJjwTIjSj6fqKAHqi7IjtH3QFE+Bw==} peerDependencies: '@codemirror/language': ^6.0.0 @@ -71,7 +57,7 @@ packages: '@codemirror/language': 6.10.1 '@codemirror/state': 6.4.1 '@codemirror/view': 6.26.0 - '@lezer/common': 1.0.4 + '@lezer/common': 1.2.1 dev: true /@codemirror/commands@6.2.5: @@ -79,17 +65,17 @@ packages: dependencies: '@codemirror/language': 6.10.1 '@codemirror/state': 6.4.1 - '@codemirror/view': 6.19.0 - '@lezer/common': 1.0.4 + '@codemirror/view': 6.26.0 + '@lezer/common': 1.2.1 dev: true /@codemirror/lang-css@6.2.1(@codemirror/view@6.26.0): resolution: {integrity: sha512-/UNWDNV5Viwi/1lpr/dIXJNWiwDxpw13I4pTUAsNxZdg6E0mI2kTQb0P2iHczg1Tu+H4EBgJR+hYhKiHKko7qg==} dependencies: - '@codemirror/autocomplete': 6.9.1(@codemirror/language@6.10.1)(@codemirror/state@6.4.1)(@codemirror/view@6.26.0)(@lezer/common@1.0.4) + '@codemirror/autocomplete': 6.9.1(@codemirror/language@6.10.1)(@codemirror/state@6.4.1)(@codemirror/view@6.26.0)(@lezer/common@1.2.1) '@codemirror/language': 6.10.1 '@codemirror/state': 6.4.1 - '@lezer/common': 1.0.4 + '@lezer/common': 1.2.1 '@lezer/css': 1.1.3 transitivePeerDependencies: - '@codemirror/view' @@ -110,7 +96,7 @@ packages: resolution: {integrity: sha512-wzRkluWb1ptPKdzlsrbwwjYCPLgzU6N88YBAmlZi8WFyuiEduSd05MnJYNogzyc8rPK7pj6m95ptUApc8sHKVA==} dependencies: '@codemirror/state': 6.4.1 - '@codemirror/view': 6.19.0 + '@codemirror/view': 6.26.0 crelt: 1.0.6 dev: true @@ -118,7 +104,7 @@ packages: resolution: {integrity: sha512-M1nGnpUTlOqp0Ywn6V30T8eFcuNFIDfx4+0ja5Wag+qQpL/HZgsIZ7FpE6qZatPziakgj+UXyZTrTUditrkwIQ==} dependencies: '@codemirror/state': 6.4.1 - '@codemirror/view': 6.19.0 + '@codemirror/view': 6.26.0 crelt: 1.0.6 dev: true @@ -126,14 +112,6 @@ packages: resolution: {integrity: sha512-QkEyUiLhsJoZkbumGZlswmAhA7CBU02Wrz7zvH4SrcifbsqwlXShVXg65f3v/ts57W3dqyamEriMhij1Z3Zz4A==} dev: true - /@codemirror/view@6.19.0: - resolution: {integrity: sha512-XqNIfW/3GaaF+T7Q1jBcRLCPm1NbrR2DBxrXacSt1FG+rNsdsNn3/azAfgpUoJ7yy4xgd8xTPa3AlL+y0lMizQ==} - dependencies: - '@codemirror/state': 6.4.1 - style-mod: 4.1.0 - w3c-keyname: 2.2.8 - dev: true - /@codemirror/view@6.26.0: resolution: {integrity: sha512-nSSmzONpqsNzshPOxiKhK203R6BvABepugAe34QfQDbNDslyjkqBuKgrK5ZBvqNXpfxz5iLrlGTmEfhbQyH46A==} dependencies: @@ -147,7 +125,7 @@ packages: dependencies: '@codemirror/language': 6.10.1 '@codemirror/state': 6.4.1 - '@codemirror/view': 6.19.0 + '@codemirror/view': 6.26.0 '@lezer/highlight': 1.1.6 dev: true @@ -425,10 +403,6 @@ packages: resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} dev: true - /@lezer/common@1.0.4: - resolution: {integrity: sha512-lZHlk8p67x4aIDtJl6UQrXSOP6oi7dQR3W/geFVrENdA1JDaAJWldnVqVjPMJupbTKbzDfFcePfKttqVidS/dg==} - dev: true - /@lezer/common@1.2.1: resolution: {integrity: sha512-yemX0ZD2xS/73llMZIK6KplkjIjf2EvAHcinDi/TfJ9hS25G0388+ClHt6/3but0oOxinTcQHJLDXh6w1crzFQ==} dev: true @@ -443,7 +417,7 @@ packages: /@lezer/highlight@1.1.6: resolution: {integrity: sha512-cmSJYa2us+r3SePpRCjN5ymCqCPv+zyXmDl0ciWtVaNiORT/MxM7ZgOMQZADD0o51qOaOg24qc/zBViOIwAjJg==} dependencies: - '@lezer/common': 1.0.4 + '@lezer/common': 1.2.1 dev: true /@lezer/lr@1.3.10: @@ -1043,13 +1017,13 @@ packages: /codemirror@6.0.1(@lezer/common@1.2.1): resolution: {integrity: sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==} dependencies: - '@codemirror/autocomplete': 6.9.1(@codemirror/language@6.10.1)(@codemirror/state@6.4.1)(@codemirror/view@6.19.0)(@lezer/common@1.2.1) + '@codemirror/autocomplete': 6.9.1(@codemirror/language@6.10.1)(@codemirror/state@6.4.1)(@codemirror/view@6.26.0)(@lezer/common@1.2.1) '@codemirror/commands': 6.2.5 '@codemirror/language': 6.10.1 '@codemirror/lint': 6.4.2 '@codemirror/search': 6.5.3 '@codemirror/state': 6.4.1 - '@codemirror/view': 6.19.0 + '@codemirror/view': 6.26.0 transitivePeerDependencies: - '@lezer/common' dev: true diff --git a/src/Components/AccountDetailsButton.tsx b/src/Components/AccountDetailsButton.tsx index 5bfbedc..2a8b9df 100644 --- a/src/Components/AccountDetailsButton.tsx +++ b/src/Components/AccountDetailsButton.tsx @@ -1,20 +1,14 @@ import { plugins } from "replugged"; import { contextMenu as ContextMenuApi, React } from "replugged/common"; import { SettingValues } from "../index"; -import { PanelButton } from "../lib/requiredModules"; +import Modules from "../lib/requiredModules"; import { defaultSettings } from "../lib/consts"; import UserSettingStore from "../lib/UserSettingStore"; import Icons from "../Components/Icons"; import SpotifyAccountsContextMenu from "./ContextMenu"; import Utils from "../lib/utils"; export const GameActivityPanelButton = (): React.ReactElement | null => { - const [enabled, setEnabled] = React.useState( - UserSettingStore.getSetting("status", "showCurrentGame"), - ); - React.useEffect(() => { - setEnabled(UserSettingStore.getSetting("status", "showCurrentGame")); - }, [UserSettingStore.getSetting("status", "showCurrentGame")]); - + const enabled = UserSettingStore.useSetting("status", "showCurrentGame"); if ( !SettingValues.get("userPanel", defaultSettings.userPanel) || plugins.getDisabled().includes("dev.tharki.ReGameActivityToggle") @@ -34,7 +28,7 @@ export const GameActivityPanelButton = (): React.ReactElement | null => { ); return ( - ContextMenuApi.open(event, (props) => ( @@ -48,6 +42,4 @@ export const GameActivityPanelButton = (): React.ReactElement | null => { /> ); }; -export const _addPanelButton = (): React.ReactElement | null => { - return ; -}; +export default () => (Modules.PanelButton ? : <>); diff --git a/src/Components/ContextMenu.tsx b/src/Components/ContextMenu.tsx index 27f1b24..eae06b2 100644 --- a/src/Components/ContextMenu.tsx +++ b/src/Components/ContextMenu.tsx @@ -1,42 +1,18 @@ -import { React } from "replugged/common"; +import { flux as Flux, React } from "replugged/common"; import { ContextMenu } from "replugged/components"; -import { SettingValues } from ".."; -import { Sounds, defaultSettings } from "../lib/consts"; -import { ConnectedAccountsStore, ConnectedAccountsUtils, SoundUtils } from "../lib/requiredModules"; +import Modules from "../lib/requiredModules"; import Icons from "./Icons"; +import Utils from "../lib/utils"; const { MenuCheckboxItem, ContextMenu: Menu, MenuSeparator, MenuItem } = ContextMenu; export default (props) => { - const ConnectedAccounts = ConnectedAccountsStore.getAccounts() as Array<{ - type: string; - id: string; - name: string; - showActivity: boolean; - }>; - const SpotifyAccounts = ConnectedAccounts.filter((a) => a.type === "spotify").map((a) => { - const [value, onChange] = React.useState(a.showActivity); - return ( - { - onChange((prev) => !prev); - a.showActivity = !a.showActivity; - ConnectedAccountsUtils.setShowActivity("spotify", a.id, a.showActivity); - if ( - e && - ((!a.showActivity && - (SettingValues.get("playAudio", defaultSettings.playAudio).spotifyDisable ?? true)) || - (a.showActivity && - (SettingValues.get("playAudio", defaultSettings.playAudio).spotifyEnable ?? true))) - ) { - SoundUtils.playSound(value ? Sounds.SpotifyEnable : Sounds.SpotifyDisable, 0.5); - } - }} - /> - ); + const { SpotifyAccounts } = Flux.useStateFromStores([Modules.ConnectedAccountsStore], () => { + const ConnectedAccounts = Modules.ConnectedAccountsStore.getAccounts(); + return { + SpotifyAccounts: ConnectedAccounts.filter((a) => a.type === "spotify"), + }; }); + return ( { id="spotify-accounts" showIconFirst={true} icon={() => } - action={() => { - for (const { - props: { action }, - } of SpotifyAccounts) - action(false); - if (SettingValues.get("playAudio", defaultSettings.playAudio).spotifyToogle ?? true) { - SoundUtils.playSound(Sounds.SpotifyToogle, 0.5); - } - }} + action={() => Utils.toggleSpotifyActivity()} /> {SpotifyAccounts.length ? ( - SpotifyAccounts + SpotifyAccounts.map((a) => { + const [value, onChange] = React.useState(a.showActivity); + return ( + { + onChange((prev) => !prev); + Utils.toggleSpotifyActivity(a); + }} + /> + ); + }) ) : ( { ); }); + +export default { registerSettings, Settings }; diff --git a/src/index.ts b/src/index.ts index 9933a6e..e767b48 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,18 +1,22 @@ import { Injector, Logger, settings } from "replugged"; +import { defaultSettings } from "./lib/consts"; import "./style.css"; -import { registerSettings } from "./Components/Settings"; export const PluginInjector = new Injector(); export const { utils: PluginInjectorUtils } = PluginInjector; export const PluginLogger = Logger.plugin("ReGameActivityToggle"); -export const SettingValues = await settings.init("dev.tharki.ReGameActivityToggle"); +export const SettingValues = await settings.init( + "dev.tharki.ReGameActivityToggle", + defaultSettings, +); export const CurrentlyPressed = new Map(); -import Injections from "./patches/index"; +import Settings from "./Components/Settings"; +import Injections from "./injections/index"; import Listeners from "./listeners/index"; export const start = (): void => { - registerSettings(); - Injections.applyInjections(); - Listeners.addListeners(); + Settings.registerSettings(); + void Injections.applyInjections(); + void Listeners.addListeners(); }; export const stop = (): void => { @@ -20,6 +24,6 @@ export const stop = (): void => { Listeners.removeListeners(); }; -export { _addPanelButton } from "./Components/AccountDetailsButton"; +export { default as _addPanelButton } from "./Components/AccountDetailsButton"; export { Settings } from "./Components/Settings.jsx"; diff --git a/src/patches/AccountContextMenu.tsx b/src/injections/AccountContextMenu.tsx similarity index 57% rename from src/patches/AccountContextMenu.tsx rename to src/injections/AccountContextMenu.tsx index 1915f37..a9ed0b4 100644 --- a/src/patches/AccountContextMenu.tsx +++ b/src/injections/AccountContextMenu.tsx @@ -1,51 +1,25 @@ -import { React } from "replugged/common"; +import { flux as Flux, React } from "replugged/common"; import { ContextMenu } from "replugged/components"; import { PluginInjectorUtils, SettingValues } from "../index"; -import { defaultSettings, Sounds } from "../lib/consts"; +import { defaultSettings } from "../lib/consts"; import UserSettingStore from "../lib/UserSettingStore"; import Icons from "../Components/Icons"; import Utils from "../lib/utils"; import Types from "../types"; -import { ConnectedAccountsStore, ConnectedAccountsUtils, SoundUtils } from "../lib/requiredModules"; +import Modules from "../lib/requiredModules"; export default (): void => { PluginInjectorUtils.addMenuItem( Types.DefaultTypes.ContextMenuTypes.Account, (_data, { children }: Types.MenuProps) => { if (!SettingValues.get("statusPicker", defaultSettings.statusPicker)) return; - const ConnectedAccounts = ConnectedAccountsStore.getAccounts() as Array<{ - type: string; - id: string; - name: string; - showActivity: boolean; - }>; - const SpotifyAccounts = ConnectedAccounts.filter((a) => a.type === "spotify").map((a) => { - const [value, onChange] = React.useState(a.showActivity); - return ( - { - onChange((prev) => !prev); - a.showActivity = !a.showActivity; - ConnectedAccountsUtils.setShowActivity("spotify", a.id, a.showActivity); - if ( - e && - ((!a.showActivity && - (SettingValues.get("playAudio", defaultSettings.playAudio).spotifyDisable ?? - true)) || - (a.showActivity && - (SettingValues.get("playAudio", defaultSettings.playAudio).spotifyEnable ?? - true))) - ) { - SoundUtils.playSound(value ? Sounds.SpotifyEnable : Sounds.SpotifyDisable, 0.5); - } - }} - /> - ); + const { SpotifyAccounts } = Flux.useStateFromStores([Modules.ConnectedAccountsStore], () => { + const ConnectedAccounts = Modules.ConnectedAccountsStore.getAccounts(); + return { + SpotifyAccounts: ConnectedAccounts.filter((a) => a.type === "spotify"), + }; }); - const enabled = UserSettingStore.getSetting("status", "showCurrentGame"); + const enabled = UserSettingStore.useSetting("status", "showCurrentGame"); const Icon = ( { ); const switchAccount = children.find((c) => c?.props?.children?.key === "switch-account"); - if (!children.find((c) => c?.props?.className === "yofukashuno")) + if (!children.find((c) => c?.props?.className === "yofukashino")) children.splice( children.indexOf(switchAccount), 0, - , + , ); - const section = children.find((c) => c?.props?.className === "yofukashuno"); + const section = children.find((c) => c?.props?.className === "yofukashino"); section.props.children = section.props.children.filter( (m) => m?.props?.id !== "game-activity", ); @@ -86,9 +60,6 @@ export default (): void => { { return Utils.toggleGameActivity(enabled); @@ -101,22 +72,24 @@ export default (): void => { id="spotify-accounts" showIconFirst={true} icon={() => } - action={() => { - for (const { - props: { action }, - } of SpotifyAccounts) - action(false); - if ( - SettingValues.get("playAudio", defaultSettings.playAudio).spotifyToogle ?? - true - ) { - SoundUtils.playSound(Sounds.SpotifyToogle, 0.5); - } - }} + action={() => Utils.toggleSpotifyActivity()} /> {SpotifyAccounts.length ? ( - SpotifyAccounts + SpotifyAccounts.map((a) => { + const [value, onChange] = React.useState(a.showActivity); + return ( + { + onChange((prev) => !prev); + Utils.toggleSpotifyActivity(a); + }} + /> + ); + }) ) : ( => { - const AudioResolver = await AudioResolverPromise; + const AudioResolver = await Modules.AudioResolverPromise; PluginInjector.instead(AudioResolver, "exports", ([sound]: [string], res) => { switch (sound) { case `./${Sounds.GameEnable}.mp3`: { diff --git a/src/injections/index.ts b/src/injections/index.ts new file mode 100644 index 0000000..88d1fed --- /dev/null +++ b/src/injections/index.ts @@ -0,0 +1,10 @@ +import Modules from "../lib/requiredModules"; +import injectAccountContextMenu from "./AccountContextMenu"; +import injectAudioResolver from "./AudioResolver"; +export const applyInjections = async (): Promise => { + await Modules.loadModules(); + injectAccountContextMenu(); + void injectAudioResolver(); +}; + +export default { applyInjections }; diff --git a/src/lib/UserSettingStore.ts b/src/lib/UserSettingStore.ts index 50ce75e..4fb497d 100644 --- a/src/lib/UserSettingStore.ts +++ b/src/lib/UserSettingStore.ts @@ -1,36 +1,31 @@ -import { - UserSettingsActionTypes, - UserSettingsProtoStore, - UserSettingsProtoUtils, -} from "./requiredModules"; -import Types from "../types"; +import { flux as Flux } from "replugged/common"; +import Modules from "./requiredModules"; export const getSetting = (category: string, key: string): boolean => { if (!category || !key) return; - return Boolean(UserSettingsProtoStore?.settings?.[category]?.[key]?.value); + return Boolean(Modules.UserSettingsProtoStore?.settings?.[category]?.[key]?.value); }; -export const getSettingsStore = (): { - updateAsync: ( - category: string, - setter: Types.DefaultTypes.AnyFunction, - type: string | number, - ) => void; -} => { - return Object.values(UserSettingsProtoUtils)?.find?.( - (n) => n?.updateAsync && n?.ProtoClass?.typeName?.endsWith(".PreloadedUserSettings"), - ); +export const useSetting = (category: string, key: string): boolean => { + if (!category || !key) return false; + const { setting } = Flux.useStateFromStores([Modules.UserSettingsProtoStore], () => { + return { + setting: Boolean(Modules.UserSettingsProtoStore?.settings?.[category]?.[key]?.value), + }; + }); + return setting; }; export const setSetting = (category: string, key: string, value: boolean): boolean => { if (!category || !key) return; - let store = getSettingsStore(); - if (store) - store.updateAsync( + const { PreloadedUserSettingsActionCreators, UserSettingsDelay } = + Modules.UserSettingsActionUtils; + if (PreloadedUserSettingsActionCreators) + PreloadedUserSettingsActionCreators.updateAsync( category, (settings) => { if (!settings) return; settings[key].value = value; }, - UserSettingsActionTypes.INFREQUENT_USER_ACTION, + UserSettingsDelay.INFREQUENT_USER_ACTION, ); }; -export default { getSetting, getSettingsStore, setSetting }; +export default { getSetting, useSetting, setSetting }; diff --git a/src/lib/consts.ts b/src/lib/consts.ts index c47666e..d9f5718 100644 --- a/src/lib/consts.ts +++ b/src/lib/consts.ts @@ -1,4 +1,4 @@ -import { KeybindUtils } from "./requiredModules"; +import Modules from "./requiredModules"; import GameEnable from "../assets/ga_enable.mp3"; import GameDisable from "../assets/ga_disable.mp3"; import SpotifyEnable from "../assets/sp_enable.mp3"; @@ -9,7 +9,9 @@ export const defaultSettings = { statusPicker: true, userPanel: true, showToast: true, - keybind: KeybindUtils.toCombo("ctrl+shift+g") as number[][], + get keybind() { + return Modules.KeybindUtils.toCombo("ctrl+shift+g") as number[][]; + }, playAudio: { gameDisable: true, gameEnable: true, diff --git a/src/lib/requiredModules.ts b/src/lib/requiredModules.ts index 9e69f08..04d3459 100644 --- a/src/lib/requiredModules.ts +++ b/src/lib/requiredModules.ts @@ -1,34 +1,34 @@ import { webpack } from "replugged"; import Types from "../types"; -export const WindowStore = webpack.getByStoreName("WindowStore"); - -export const SoundUtils = webpack.getByProps( - "playSound", - "createSound", - "createSoundForPack", -); -export const KeybindUtils = webpack.getByProps("toCombo"); - -export const UserSettingsProtoStore = - webpack.getByStoreName("UserSettingsProtoStore"); - -export const UserSettingsProtoUtils = webpack.getBySource("UserSettingsProtoLastWriteTimes"); -export const UserSettingsActionTypes = webpack.getExportsForProps( - UserSettingsProtoUtils, - ["SLOW_USER_ACTION", "DAILY", "INFREQUENT_USER_ACTION"], -); - -export const PanelButton = webpack.getBySource("Masks.PANEL_BUTTON"); - -export const ConnectedAccountsStore = - webpack.getByStoreName("ConnectedAccountsStore"); - -export const ConnectedAccountsUtils = webpack.getByProps( - "setShowActivity", - "refreshAccessToken", -); - -export const AudioResolverPromise = webpack.waitForModule<{ - exports: Types.DefaultTypes.AnyFunction & { keys: () => string[] }; -}>(webpack.filters.bySource("./mute.mp3"), { raw: true }); +export const Modules: Types.Modules = {}; + +Modules.loadModules = async (): Promise => { + Modules.SoundUtils ??= await webpack.waitForProps( + "playSound", + "createSound", + "createSoundForPack", + ); + Modules.KeybindUtils ??= await webpack.waitForProps("toCombo"); + Modules.UserSettingsActionUtils ??= await webpack.waitForProps( + "PreloadedUserSettingsActionCreators", + ); + Modules.PanelButton = await webpack.waitForModule( + webpack.filters.bySource("Masks.PANEL_BUTTON"), + ); + Modules.ConnectedAccountsUtils ??= await webpack.waitForProps( + "setShowActivity", + "refreshAccessToken", + ); + Modules.AudioResolverPromise = webpack.waitForModule( + webpack.filters.bySource("./mute.mp3"), + { raw: true }, + ); + Modules.UserSettingsProtoStore ??= + webpack.getByStoreName("UserSettingsProtoStore"); + Modules.WindowStore ??= webpack.getByStoreName("WindowStore"); + Modules.ConnectedAccountsStore ??= + webpack.getByStoreName("ConnectedAccountsStore"); +}; + +export default Modules; diff --git a/src/lib/utils.ts b/src/lib/utils.ts index d38d899..edd62e5 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -1,7 +1,7 @@ import { settings, util } from "replugged"; import { React, lodash } from "replugged/common"; -import { PluginInjector, SettingValues } from "../index"; -import { SoundUtils } from "./requiredModules"; +import { PluginInjector, PluginLogger, SettingValues } from "../index"; +import Modules from "./requiredModules"; import { Sounds, defaultSettings } from "./consts"; import UserSettingStore from "./UserSettingStore"; import Types from "../types"; @@ -21,39 +21,79 @@ export const toggleGameActivity = (enabled: boolean): void => { (enabled && (SettingValues.get("playAudio", defaultSettings.playAudio).gameDisable ?? true)) || (!enabled && (SettingValues.get("playAudio", defaultSettings.playAudio).gameEnable ?? true)) ) { - SoundUtils.playSound(enabled ? Sounds.GameDisable : Sounds.GameEnable, 0.5); + Modules.SoundUtils.playSound(enabled ? Sounds.GameDisable : Sounds.GameEnable, 0.5); } + PluginLogger.log(`${enabled ? "Disabled" : "Enabled"} Game Activity`); UserSettingStore.setSetting("status", "showCurrentGame", !enabled); }; +export const toggleSpotifyActivity = (account?: { + type: string; + id: string; + name: string; + showActivity: boolean; +}): void => { + const { ConnectedAccountsStore, ConnectedAccountsUtils, SoundUtils } = Modules; + const accounts = account + ? [account] + : ConnectedAccountsStore.getAccounts().filter((a) => a.type === "spotify"); + for (const a of accounts) { + a.showActivity = !a.showActivity; + ConnectedAccountsUtils.setShowActivity("spotify", a.id, a.showActivity); + } + if ( + account + ? (!account.showActivity && + (SettingValues.get("playAudio", defaultSettings.playAudio).spotifyDisable ?? true)) || + (account.showActivity && + (SettingValues.get("playAudio", defaultSettings.playAudio).spotifyEnable ?? true)) + : SettingValues.get("playAudio", defaultSettings.playAudio).spotifyToogle ?? true + ) { + SoundUtils.playSound( + account + ? account.showActivity + ? Sounds.SpotifyEnable + : Sounds.SpotifyDisable + : Sounds.SpotifyToogle, + 0.5, + ); + } + PluginLogger.log( + account + ? account.showActivity + ? `Enabled Spotify Song Activity for ${account.name}` + : `Disabled Spotify Song Activity for ${account.name}` + : `Toogled Spotify Song Activity for ${accounts.map((a) => a.name).join(", ")}`, + ); +}; + export const useSetting = < T extends Record, D extends keyof T, K extends Extract, F extends Types.NestedType | T[K] | undefined, - P extends `${K}.${string}` | K, + P extends `${K}.${string}` | `${K}/${string}` | `${K}-${string}` | K, + V extends P extends `${K}.${string}` | `${K}/${string}` | `${K}-${string}` + ? NonNullable> + : P extends D + ? NonNullable + : F extends null | undefined + ? T[P] | undefined + : NonNullable | F, >( settings: settings.SettingsManager, key: P, fallback?: F, ): { - value: Types.NestedType | F; - onChange: (newValue: Types.ValType | F>) => void; + value: V; + onChange: (newValue: Types.ValType> | Types.ValType) => void; } => { - const [initialKey, ...pathArray] = Object.keys(settings.all()).includes(key) - ? ([key] as [K]) - : (key.split(".") as [K, ...string[]]); - const path = pathArray.join("."); - const initial = settings.get(initialKey, path.length ? ({} as T[K]) : (fallback as T[K])); - const [value, setValue] = React.useState>( - path.length - ? (lodash.get(initial, path, fallback) as Types.NestedType) - : (initial as Types.NestedType), - ); + const initial = settings.get(key as K) ?? lodash.get(settings.all(), key) ?? fallback; + const [value, setValue] = React.useState(initial as V); return { value, - onChange: (newValue: Types.ValType | F>) => { + onChange: (newValue: Types.ValType> | Types.ValType) => { const isObj = newValue && typeof newValue === "object"; const value = isObj && "value" in newValue ? newValue.value : newValue; const checked = isObj && "checked" in newValue ? newValue.checked : void 0; @@ -63,15 +103,49 @@ export const useSetting = < : void 0; const targetValue = target && "value" in target ? target.value : void 0; const targetChecked = target && "checked" in target ? target.checked : void 0; - const finalValue = checked ?? targetChecked ?? targetValue ?? value ?? newValue; + const finalValue = (checked ?? targetChecked ?? targetValue ?? value ?? newValue) as T[K]; + + setValue(finalValue as V); - setValue(finalValue as Types.NestedType); - settings.set( - initialKey, - path.length ? (lodash.set(initial, path, finalValue) as T[K]) : (finalValue as T[K]), - ); + if (settings.get(key as K)) { + settings.set(key as K, finalValue); + } else { + const [rootKey] = key.split(/[-/.]/); + const setting = lodash.set(settings.all(), key, finalValue)[rootKey as K]; + settings.set(rootKey as K, setting); + } }, }; }; -export default { ...util, forceRerenderElement, toggleGameActivity, useSetting }; +export const useSettingArray = < + T extends Record, + D extends keyof T, + K extends Extract, + F extends Types.NestedType | T[K] | undefined, + P extends `${K}.${string}` | `${K}/${string}` | `${K}-${string}` | K, + V extends P extends `${K}.${string}` | `${K}/${string}` | `${K}-${string}` + ? NonNullable> + : P extends D + ? NonNullable + : F extends null | undefined + ? T[P] | undefined + : NonNullable | F, +>( + settings: settings.SettingsManager, + key: P, + fallback?: F, +): [V, (newValue: Types.ValType> | Types.ValType) => void] => { + const { value, onChange } = useSetting(settings, key, fallback); + + return [value as V, onChange]; +}; + +export default { + ...util, + forceRerenderElement, + toggleGameActivity, + toggleSpotifyActivity, + useSetting, + useSettingArray, +}; diff --git a/src/listeners/CleanCallback.ts b/src/listeners/CleanCallback.ts index 907f580..8134e52 100644 --- a/src/listeners/CleanCallback.ts +++ b/src/listeners/CleanCallback.ts @@ -1,5 +1,5 @@ import { CurrentlyPressed } from "../index"; -import { WindowStore } from "../lib/requiredModules"; +import Modules from "../lib/requiredModules"; export default (): void => { - if (WindowStore.isFocused()) CurrentlyPressed.clear(); + if (Modules.WindowStore?.isFocused()) CurrentlyPressed.clear(); }; diff --git a/src/listeners/KeybindListener.ts b/src/listeners/KeybindListener.ts index bf718b2..b6cb865 100644 --- a/src/listeners/KeybindListener.ts +++ b/src/listeners/KeybindListener.ts @@ -1,13 +1,12 @@ -import { common } from "replugged"; +import { toast as Toasts } from "replugged/common"; import { CurrentlyPressed, SettingValues } from "../index"; import { defaultSettings } from "../lib/consts"; -import { KeybindUtils } from "../lib/requiredModules"; +import Modules from "../lib/requiredModules"; import UserSettingStore from "../lib/UserSettingStore"; import Utils from "../lib/utils"; import Types from "../types"; -const { toast: Toasts } = common; export default (e: Types.KeybindEvent): void => { - const keybindEvents = KeybindUtils.toBrowserEvents( + const keybindEvents = Modules.KeybindUtils.toBrowserEvents( SettingValues.get("keybind", defaultSettings.keybind), ) as Types.KeybindEvents; if ( diff --git a/src/listeners/index.ts b/src/listeners/index.ts index 7107981..0fa0099 100644 --- a/src/listeners/index.ts +++ b/src/listeners/index.ts @@ -1,16 +1,17 @@ -import { WindowStore } from "../lib/requiredModules"; -import cleanKeybindsCallback from "./CleanCallback"; -import keybindListener from "./KeybindListener"; +import Modules from "../lib/requiredModules"; +import CleanKeybindsCallback from "./CleanCallback"; +import KeybindListener from "./KeybindListener"; -export const addListeners = (): void => { - WindowStore.addChangeListener(cleanKeybindsCallback); - window.addEventListener("keydown", keybindListener); - window.addEventListener("keyup", keybindListener); +export const addListeners = async (): Promise => { + await Modules.loadModules(); + Modules.WindowStore?.addChangeListener(CleanKeybindsCallback); + window.addEventListener("keydown", KeybindListener); + window.addEventListener("keyup", KeybindListener); }; export const removeListeners = (): void => { - WindowStore.removeChangeListener(cleanKeybindsCallback); - window.removeEventListener("keydown", keybindListener); - window.removeEventListener("keyup", keybindListener); + Modules.WindowStore?.removeChangeListener(CleanKeybindsCallback); + window.removeEventListener("keydown", KeybindListener); + window.removeEventListener("keyup", KeybindListener); }; export default { addListeners, removeListeners }; diff --git a/src/patches/index.ts b/src/patches/index.ts deleted file mode 100644 index 7b80704..0000000 --- a/src/patches/index.ts +++ /dev/null @@ -1,8 +0,0 @@ -import patchAccountContextMenu from "./AccountContextMenu"; -import patchAudioResolver from "./AudioResolver"; -export const applyInjections = (): void => { - patchAccountContextMenu(); - void patchAudioResolver(); -}; - -export default { applyInjections }; diff --git a/src/types.ts b/src/types.ts index f5b96e6..fb2a4e9 100644 --- a/src/types.ts +++ b/src/types.ts @@ -9,13 +9,73 @@ export namespace Types { export type UtilTree = util.Tree; export type ReactTree = util.Tree & React.ReactElement; export type GenericModule = Record; - - export interface UserSettingsActionTypes { - AUTOMATED: number; - DAILY: number; - FREQUENT_USER_ACTION: number; - INFREQUENT_USER_ACTION: number; - SLOW_USER_ACTION: number; + export interface AudioResolver { + exports: Types.DefaultTypes.AnyFunction & { keys: () => string[] }; + } + export enum UserSettingsDelay { + AUTOMATED = 30, + DAILY = 86400, + FREQUENT_USER_ACTION = 10, + INFREQUENT_USER_ACTION = 0, + SLOW_USER_ACTION = 20, + } + export interface SettingsActionCreators { + ProtoClass: { + defaultCheckDepth: number; + fields: unknown[]; + optionsobject; + typeName: string; + binaryReadMap1: DefaultTypes.AnyFunction; + create: DefaultTypes.AnyFunction; + internalBinaryRead: DefaultTypes.AnyFunction; + internalBinaryWrite: DefaultTypes.AnyFunction; + }; + beforeSendCallbacks: Array<{ + hasChanges: () => boolean; + processProto: () => void; + }>; + lastSendTime: number; + logger: { + error: DefaultTypes.AnyFunction; + fileOnly: DefaultTypes.AnyFunction; + info: DefaultTypes.AnyFunction; + log: DefaultTypes.AnyFunction; + logDangerously: DefaultTypes.AnyFunction; + name: string; + time: DefaultTypes.AnyFunction; + trace: DefaultTypes.AnyFunction; + verbose: DefaultTypes.AnyFunction; + verboseDangerously: DefaultTypes.AnyFunction; + warn: DefaultTypes.AnyFunction; + }; + persistChanges: DefaultTypes.AnyFunction; + type: number; + dispatchChanges: DefaultTypes.AnyFunction; + getCurrentValue: DefaultTypes.AnyFunction; + getEditInfo: DefaultTypes.AnyFunction; + loadIfNecessary: DefaultTypes.AnyFunction; + markDirty: DefaultTypes.AnyFunction; + markDirtyFromMigration: DefaultTypes.AnyFunction; + markDirtyIfHasPendingChange: DefaultTypes.AnyFunction; + saveLastSendTime: DefaultTypes.AnyFunction; + scheduleSaveFromOfflineEdit: DefaultTypes.AnyFunction; + updateAsync: ( + category: string, + setter: Types.DefaultTypes.AnyFunction, + type: string | number, + ) => void; + } + export interface UserSettingsActionUtils { + FrecencyUserSettingsActionCreators: SettingsActionCreators; + PreloadedUserSettingsActionCreators: SettingsActionCreators; + UserSettingsActionCreatorsByType: Record; + UserSettingsDelay: typeof UserSettingsDelay; + addDismissedContent: DefaultTypes.AnyFunction; + checkAllDismissedContents: DefaultTypes.AnyFunction; + clearDismissedContents: DefaultTypes.AnyFunction; + removeDismissedContent: DefaultTypes.AnyFunction; + updateUserChannelSettings: DefaultTypes.AnyFunction; + updateUserGuildSettings: DefaultTypes.AnyFunction; } export interface WindowStore extends Store { isFocused: () => boolean; @@ -44,7 +104,12 @@ export namespace Types { } export interface ConnectedAccountsStore extends Store { getAccount: DefaultTypes.AnyFunction; - getAccounts: DefaultTypes.AnyFunction; + getAccounts: () => Array<{ + type: string; + id: string; + name: string; + showActivity: boolean; + }>; getLocalAccount: DefaultTypes.AnyFunction; getLocalAccounts: DefaultTypes.AnyFunction; isFetching: DefaultTypes.AnyFunction; @@ -109,7 +174,18 @@ export namespace Types { disabled?: boolean; clearable?: boolean; } - + export interface Modules { + loadModules?: () => Promise; + WindowStore?: WindowStore; + SoundUtils?: SoundUtils; + KeybindUtils?: KeybindUtils; + UserSettingsProtoStore?: UserSettingsProtoStore; + UserSettingsActionUtils?: UserSettingsActionUtils; + PanelButton?: PanelButton; + ConnectedAccountsStore?: ConnectedAccountsStore; + ConnectedAccountsUtils?: ConnectedAccountsUtils; + AudioResolverPromise?: Promise; + } export type Jsonifiable = | null | undefined @@ -123,7 +199,10 @@ export namespace Types { | React.ChangeEvent | (Record & { value?: T; checked?: T }); - export type NestedType = P extends `${infer Left}.${infer Right}` + export type NestedType = P extends + | `${infer Left}.${infer Right}` + | `${infer Left}/${infer Right}` + | `${infer Left}-${infer Right}` ? Left extends keyof T ? NestedType : Left extends `${infer FieldKey}[${infer IndexKey}]` @@ -133,7 +212,7 @@ export namespace Types { : undefined : P extends keyof T ? T[P] - : P extends `${infer FieldKey}` + : P extends `${infer FieldKey}[${infer _IndexKey}]` ? FieldKey extends keyof T ? Exclude extends infer U ? U