diff --git a/renderer/src/api/I18n.js b/renderer/src/api/I18n.js index 11b0d7dd..3f9319da 100644 --- a/renderer/src/api/I18n.js +++ b/renderer/src/api/I18n.js @@ -52,7 +52,7 @@ export default class I18n extends API { async start () { locale = getModule('locale', 'theme')?.locale; - FluxDispatcher.subscribe($discord.constants.ActionTypes.I18N_LOAD_SUCCESS, this._handleLocaleChange); + FluxDispatcher.subscribe('I18N_LOAD_SUCCESS', this._handleLocaleChange); this.injectAllStrings(__coreMessages); } diff --git a/renderer/src/api/settings/store/Actions.js b/renderer/src/api/settings/store/Actions.js index c6a3df46..86a112ac 100644 --- a/renderer/src/api/settings/store/Actions.js +++ b/renderer/src/api/settings/store/Actions.js @@ -3,7 +3,7 @@ import { ActionTypes } from '@vizality/constants'; export default { toggleSetting (category, setting, defaultValue) { - FluxDispatcher.dirtyDispatch({ + FluxDispatcher.dispatch({ type: ActionTypes.VIZALITY_TOGGLE_SETTING, category, setting, @@ -12,7 +12,7 @@ export default { }, updateSettings (category, settings) { - FluxDispatcher.dirtyDispatch({ + FluxDispatcher.dispatch({ type: ActionTypes.VIZALITY_UPDATE_SETTINGS, category, settings @@ -20,7 +20,7 @@ export default { }, updateSetting (category, setting, value) { - FluxDispatcher.dirtyDispatch({ + FluxDispatcher.dispatch({ type: ActionTypes.VIZALITY_UPDATE_SETTING, category, setting, @@ -29,7 +29,7 @@ export default { }, deleteSetting (category, setting) { - FluxDispatcher.dirtyDispatch({ + FluxDispatcher.dispatch({ type: ActionTypes.VIZALITY_DELETE_SETTING, category, setting diff --git a/renderer/src/builtins/attributes/modules/components/Anchor.js b/renderer/src/builtins/attributes/modules/components/Anchor.js index ecf5631c..a2836a08 100644 --- a/renderer/src/builtins/attributes/modules/components/Anchor.js +++ b/renderer/src/builtins/attributes/modules/components/Anchor.js @@ -109,8 +109,8 @@ export default builtin => { icon: 'PersonRemove' }); } - return FluxDispatcher.dirtyDispatch({ - type: $discord.constants.ActionTypes.USER_PROFILE_MODAL_OPEN, + return FluxDispatcher.dispatch({ + type: 'USER_PROFILE_MODAL_OPEN', userId }); } catch (err) { diff --git a/renderer/src/builtins/attributes/modules/members/Member.js b/renderer/src/builtins/attributes/modules/members/Member.js index 749cd342..c32d8057 100644 --- a/renderer/src/builtins/attributes/modules/members/Member.js +++ b/renderer/src/builtins/attributes/modules/members/Member.js @@ -4,24 +4,31 @@ * @memberof Builtin.Attributes.Misc */ -import { getModuleByDisplayName } from '@vizality/webpack'; +import { getModule } from '@vizality/webpack'; import { patch, unpatch } from '@vizality/patcher'; export const labels = [ 'Members', 'Member' ]; export default builtin => { - const MemberListItem = getModuleByDisplayName('MemberListItem'); - patch('vz-attributes-members-member', MemberListItem?.prototype, 'render', function (_, res) { + const MemberListItem = getModule([ 'AVATAR_DECORATION_PADDING' ]) + patch('vz-attributes-members-member', MemberListItem?.default, 'type', (_, res) => { try { - if (!res || !this?.props?.user) return; - const { activities } = res.props?.subText?.props; - const { user, isOwner } = this.props; + if (!res || !res?.props?.user) return; + const { user, isOwner, activities } = res.props; if (!user) return; - res.props['vz-user-id'] = user.id; - res.props['vz-activity'] = Boolean(activities?.some(activity => activity.type !== 4)) && ''; - res.props['vz-self'] = Boolean(user.email) && ''; - res.props['vz-bot'] = Boolean(user.bot) && ''; - res.props['vz-owner'] = Boolean(isOwner) && ''; + + const old = res.type.prototype.render + res.type.prototype.render = function() { + const res = old.apply(this, arguments) + + res.props['vz-user-id'] = user.id; + res.props['vz-activity'] = Boolean(activities?.some(activity => activity.type !== 4)) && ''; + res.props['vz-self'] = Boolean(user.email) && ''; + res.props['vz-bot'] = Boolean(user.bot) && ''; + res.props['vz-owner'] = Boolean(isOwner) && ''; + + return res + } } catch (err) { return builtin.error(builtin._labels.concat(labels), err); } diff --git a/renderer/src/builtins/attributes/modules/misc/Settings.js b/renderer/src/builtins/attributes/modules/misc/Settings.js index 7c8c4a13..332bd2c6 100644 --- a/renderer/src/builtins/attributes/modules/misc/Settings.js +++ b/renderer/src/builtins/attributes/modules/misc/Settings.js @@ -40,7 +40,7 @@ export default () => { /** * Subscribe to Discord's user settings uppdate flux store. */ - FluxDispatcher?.subscribe($discord.constants.ActionTypes.USER_SETTINGS_UPDATE, handleSettingsChange); + FluxDispatcher?.subscribe('USER_SETTINGS_UPDATE', handleSettingsChange); /** * Remove attributes and unsubscribe from Flux on unload. @@ -48,6 +48,6 @@ export default () => { return () => { root?.removeAttribute('vz-theme'); root?.removeAttribute('vz-mode'); - FluxDispatcher?.unsubscribe($discord.constants.ActionTypes.USER_SETTINGS_UPDATE, handleSettingsChange); + FluxDispatcher?.unsubscribe('USER_SETTINGS_UPDATE', handleSettingsChange); }; }; diff --git a/renderer/src/builtins/settings/index.js b/renderer/src/builtins/settings/index.js index c84b1206..3d454999 100644 --- a/renderer/src/builtins/settings/index.js +++ b/renderer/src/builtins/settings/index.js @@ -1,92 +1,18 @@ import { openModal, closeModal } from '@vizality/modal'; -import { getModuleByDisplayName, getModule, instance } from '@vizality/webpack'; +import { getModule, contextMenu } from '@vizality/webpack'; import { SettingsContextMenu } from '@vizality/components/vizality'; import { Content, Layout } from '@vizality/components/dashboard'; -import { toPlural, toTitleCase } from '@vizality/util/string'; +import { toPlural } from '@vizality/util/string'; import { Confirm, ContextMenu, Modal } from '@vizality/components'; -import { joinClassNames } from '@vizality/util/dom'; +import { joinClassNames, waitForElement } from '@vizality/util/dom'; import { patch, unpatch } from '@vizality/patcher'; import { Builtin } from '@vizality/entities'; import { Messages } from '@vizality/i18n'; import React from 'react'; +import { webFrame } from 'electron' import SettingsPage from './components/Settings'; -/** - * Contributed by DoggyBootsy, originally written by Strencher. - */ -{ - const modules = Object.values(instance.m).filter(e => e.toString().search(/openContextMenuLazy[)(]/) > -1); - const regex = [ - { - regex: /return Promise\.all\(\[(.*?)\]\)\.then\(\D+(.+?)\)\)/, - parse (match) { - return { - imports: matchAll(/\(([\de]+)\)/g, match[0]).map(e => Number(e)), - main: match[1] - }; - } - }, - { - regex: /return Promise\.resolve\(\)\.then\(\D+(.+?)\)/, - parse (match) { - return { - imports: [], - main: match[0] - }; - } - }, - { - regex: /return [rn]\.e\((\d+)\)\.then\(\D+(\d+)\)\)/, - parse (match) { - return { - imports: [ match[0] ], - main: match[0] - }; - } - } - ]; - - function matchAll (regex, input, parent = false) { - const output = []; - let matches, - lastIndex = 0; - while (matches = regex.exec(input.slice(lastIndex))) { - if (!regex.global) lastIndex += matches.index + matches[0].length; - if (parent) output.push(matches); - else { - const [ , ...match ] = matches; - output.push(match); - } - } - return output; - } - - const found = []; - - for (let i = 0; i < modules.length; i++) { - const str = modules[i].toString(); - - for (let i2 = 0; i2 < regex.length; i2++) { - const { regex: reg, parse } = regex[i2]; - if (!reg.test(str)) continue; - const result = matchAll(reg, str).map(res => ({ ...parse(res), module: modules[i], reg })); - found.push(...result); - - break; - } - } - - Promise.all(found.map(item => { - try { - const imports = item.imports.map(i => instance.e(i)); - return Promise.all(imports).then(instance.bind(instance, item.main)).catch(() => void 0); - } catch (error) { - return Promise.resolve(); - } - })); -} - /** * The settings page categories. */ @@ -183,22 +109,59 @@ export default class Settings extends Builtin { )); } + async waitFor(filter) { + const exists = await getModule(filter, true, true) + if (exists) return exists + return await this.waitFor(filter) + } + async patchSettingsContextMenu () { - const DiscordSettingsContextMenu = await getModule(m => m.default?.displayName === 'UserSettingsCogContextMenu', true); + const { panels } = await getModule('panels', 'downloadProgressCircle', 'hasNotice', true) + const { container } = await getModule('container', 'usernameContainer', 'godlike', true) + const { button } = await getModule('button', 'disabled', 'enabled', true) + + await waitForElement(`.${panels} > .${container} .${button}:last-child`); + const settingsNode = webFrame.top.context.document.querySelector(`.${panels} > .${container} .${button}:last-child`); + + settingsNode.__reactProps$.onContextMenu({ + stopPropagation() {}, + currentTarget: { contains: () => true }, + preventDefault() {} + }); + contextMenu.closeContextMenu(); + + + const DiscordSettingsContextMenu = await this.waitFor(m => { + if (!m.default) return; + const string = String(m.default); + return string.includes('.AnalyticsLocationProvider,') && string.includes('.createElement(') && !string.includes('return function') && !m. + default.displayName; + }); + patch('vz-settings-context-menu', DiscordSettingsContextMenu, 'default', (_, res) => { - const items = res.props.children.find(child => Array.isArray(child)); - items.push( - <> - - vizality.api.routes.navigateTo('dashboard')} - > - {SettingsContextMenu.type().props.children} - - - ); + const { children } = res.props; + const old = children.type; + + children.type = () => { + const result = old(children.props); + + const items = result.props.children.props.children.find(child => Array.isArray(child)); + + items.push( + <> + + vizality.api.routes.navigateTo('dashboard')} + > + {SettingsContextMenu.type().props.children} + + + ); + + return result; + }; }); } diff --git a/renderer/src/index.js b/renderer/src/index.js index 119c31e2..0312ac7c 100644 --- a/renderer/src/index.js +++ b/renderer/src/index.js @@ -6,7 +6,7 @@ import { log as _log, warn as _warn, error as _error, deprecate as _deprecate } from '@vizality/util/logger'; import { initialize as initializeWebpackModules, getModule, FluxDispatcher, getAllModules } from '@vizality/webpack'; -import { Directories, Events, Protocols, Developers } from '@vizality/constants'; +import { Directories, Events, Protocols } from '@vizality/constants'; import { resolveCompiler } from '@vizality/compilers'; import { createElement } from '@vizality/util/dom'; import { toPlural } from '@vizality/util/string'; @@ -60,7 +60,6 @@ export default class Vizality extends Updatable { async handleConnectionOpen () { return new Promise(resolve => { - console.log(getAllModules()?.length); if (getAllModules()?.length > 7000) { return resolve(); } @@ -93,6 +92,7 @@ export default class Vizality extends Updatable { * @note This has to be after webpack modules have been initialized. */ const Flux = await getModule('Store', 'PersistedStore', true); + Flux.connectStoresAsync = (stores, fn) => Component => import('./components').AsyncComponent.from((async () => { const awaitedStores = await Promise.all(stores); diff --git a/renderer/src/modules/components/Anchor.jsx b/renderer/src/modules/components/Anchor.jsx index ccb5dc43..ea4b4429 100644 --- a/renderer/src/modules/components/Anchor.jsx +++ b/renderer/src/modules/components/Anchor.jsx @@ -76,8 +76,8 @@ export default memo(({ onClick, href, className, userId, children, type, addonId icon: 'PersonRemove' }); } - return FluxDispatcher.dirtyDispatch({ - type: $discord.constants.ActionTypes.USER_PROFILE_MODAL_OPEN, + return FluxDispatcher.dispatch({ + type: 'USER_PROFILE_MODAL_OPEN', userId }); } diff --git a/renderer/src/modules/components/index.js b/renderer/src/modules/components/index.js index 3bb5717f..ca1a1254 100644 --- a/renderer/src/modules/components/index.js +++ b/renderer/src/modules/components/index.js @@ -25,7 +25,7 @@ export const ShinyButton = AsyncComponent.fromDisplayName('ShinyButton'); export const WebhookCard = AsyncComponent.fromDisplayName('WebhookCard'); export const Tooltip = AsyncComponent.fetchFromProps('TooltipContainer'); export const HelpMessage = AsyncComponent.fromDisplayName('HelpMessage'); -export const Button = AsyncComponent.fromProps(m => m.Link && m.Hovers); +export const Button = AsyncComponent.from(getModule('Link', 'Hovers', 'Sizes', true)); export const FormNotice = AsyncComponent.fromDisplayName('FormNotice'); // "count", "color", "shape", "disableColor", "className" export const NumberBadge = AsyncComponent.fetchFromProps('NumberBadge'); @@ -65,7 +65,7 @@ export const Table = AsyncComponent.fromDisplayName('Table'); export const Image = AsyncComponent.fromDisplayName('Image'); export const Video = AsyncComponent.fromDisplayName('Video'); export const Card = AsyncComponent.fromDisplayName('Card'); -export const Text = AsyncComponent.fromDisplayName('Text'); +export const Text = AsyncComponent.fromDisplayName('LegacyText'); export const Flex = AsyncComponent.fromDisplayName('Flex'); export { default as ProgressBar } from './ProgressBar'; @@ -197,7 +197,7 @@ getModuleByDisplayName('TextInput', true, true).then(TextInput => { this.TextInput.Sizes = TextInput.Sizes; }); -getModuleByDisplayName('Text', true, true).then(Text => { +getModuleByDisplayName('LegacyText', true, true).then(Text => { this.Text.Colors = Text.Colors; this.Text.Sizes = Text.Sizes; }); diff --git a/renderer/src/modules/discord/constants.js b/renderer/src/modules/discord/constants.js index 96f58dc6..00517cb3 100644 --- a/renderer/src/modules/discord/constants.js +++ b/renderer/src/modules/discord/constants.js @@ -24,4 +24,4 @@ export default { } }; -export const { ActionTypes, Permissions, Routes } = this.default; +export const { Permissions, Routes } = this.default; diff --git a/renderer/src/modules/discord/modal/userProfile/action/open.js b/renderer/src/modules/discord/modal/userProfile/action/open.js index 8e36c91c..7cbc328f 100644 --- a/renderer/src/modules/discord/modal/userProfile/action/open.js +++ b/renderer/src/modules/discord/modal/userProfile/action/open.js @@ -1,8 +1,8 @@ // if (!userId) return; // // @todo Use Discord module for this after it's set up. // getModule('getUser').getUser(userId) -// .then(() => getModule('dirtyDispatch').wait( -// () => getModule('dirtyDispatch').dispatch({ type: constants.ActionTypes.USER_PROFILE_MODAL_OPEN, userId }))) +// .then(() => getModule('dispatch').wait( +// () => getModule('dispatch').dispatch({ type: 'USER_PROFILE_MODAL_OPEN', userId }))) // .catch(() => vizality.api.notifications.sendToast({ // header: 'User Not Found', // type: 'User Not Found', diff --git a/renderer/src/modules/webpack/index.js b/renderer/src/modules/webpack/index.js index e8b9f88d..2fc257b1 100644 --- a/renderer/src/modules/webpack/index.js +++ b/renderer/src/modules/webpack/index.js @@ -80,19 +80,16 @@ const _getModule = (filter, retry = false, forever = false) => { */ export const initialize = async () => { /** - * Wait until webpack is ready. + * If 'window.webpackChunkdiscord_app' doesn't exist create it + * (Discord loads modules that existed window object exists) */ - while (!window.webpackChunkdiscord_app) { - await sleep(100); - } + if (!window.webpackChunkdiscord_app) window.webpackChunkdiscord_app = [] - let instance; window.webpackChunkdiscord_app.push([ - [ '_vizality' ], - {}, exports => instance = exports - ]); - - this.instance = instance; + [ Symbol('vizality') ], + {}, + (exports) => this.instance = exports + ]) for (const mdl in moduleFilters) { this[mdl] = await _getModule(moduleFilters[mdl], true);