diff --git a/.gitignore b/.gitignore index 0a886e03..0e80c4a5 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ dist etc release +tests/tmp tests/log.txt # User data diff --git a/client/src/builtin/BlockedMessages.js b/client/src/builtin/BlockedMessages.js index c12ebd6f..a267dda3 100644 --- a/client/src/builtin/BlockedMessages.js +++ b/client/src/builtin/BlockedMessages.js @@ -21,7 +21,7 @@ export default new class BlockedMessages extends BuiltinModule { async enabled(e) { const MessageListComponents = Reflection.module.byProps('BlockedMessageGroup'); MessageListComponents.OriginalBlockedMessageGroup = MessageListComponents.BlockedMessageGroup; - MessageListComponents.BlockedMessageGroup = () => { return null; }; + MessageListComponents.BlockedMessageGroup = () => null; this.cancelBlockedMessages = () => { MessageListComponents.BlockedMessageGroup = MessageListComponents.OriginalBlockedMessageGroup; delete MessageListComponents.OriginalBlockedMessageGroup; diff --git a/client/src/builtin/BuiltinModule.js b/client/src/builtin/BuiltinModule.js index 28d26794..115c9be0 100644 --- a/client/src/builtin/BuiltinModule.js +++ b/client/src/builtin/BuiltinModule.js @@ -22,10 +22,10 @@ export default class BuiltinModule { this.patch = this.patch.bind(this); } - init() { + async init() { this.setting.on('setting-updated', this._settingUpdated); if (this.setting.value) { - if (this.enabled) this.enabled(); + if (this.enabled) await this.enabled(); if (this.applyPatches) this.applyPatches(); } } @@ -38,16 +38,15 @@ export default class BuiltinModule { return Patcher.getPatchesByCaller(`BD:${this.moduleName}`); } - _settingUpdated(e) { - const { value } = e; - if (value === true) { - if (this.enabled) this.enabled(e); - if (this.applyPatches) this.applyPatches(); - return; - } - if (value === false) { - if (this.disabled) this.disabled(e); + async _settingUpdated(e) { + if (e.value) { + if (this.enabled) await this.enabled(e); + if (this.applyPatches) await this.applyPatches(); + if (this.rerenderPatchedComponents) this.rerenderPatchedComponents(); + } else { + if (this.disabled) await this.disabled(e); this.unpatch(); + if (this.rerenderPatchedComponents) this.rerenderPatchedComponents(); } } @@ -75,12 +74,14 @@ export default class BuiltinModule { */ patch(module, fnName, cb, when = 'after') { if (!['before', 'after', 'instead'].includes(when)) when = 'after'; - Patch(`BD:${this.moduleName}`, module)[when](fnName, cb.bind(this)); + return Patch(`BD:${this.moduleName}`, module)[when](fnName, cb.bind(this)); } childPatch(module, fnName, child, cb, when = 'after') { + const last = child.pop(); + this.patch(module, fnName, (component, args, retVal) => { - this.patch(retVal[child[0]], child[1], cb, when); + const unpatch = this.patch(child.reduce((obj, key) => obj[key], retVal), last, function(...args) {unpatch(); return cb.call(this, component, ...args);}, when); }); } diff --git a/client/src/builtin/ColoredText.js b/client/src/builtin/ColoredText.js index 290eaf6a..f1002a2b 100644 --- a/client/src/builtin/ColoredText.js +++ b/client/src/builtin/ColoredText.js @@ -42,6 +42,10 @@ export default new class ColoredText extends BuiltinModule { this.intensitySetting.off('setting-updated', this._intensityUpdated); } + rerenderPatchedComponents() { + if (this.MessageContent) this.MessageContent.forceUpdateAll(); + } + /* Methods */ _intensityUpdated() { this.MessageContent.forceUpdateAll(); @@ -50,16 +54,16 @@ export default new class ColoredText extends BuiltinModule { /* Patches */ async applyPatches() { if (this.patches.length) return; - this.MessageContent = await ReactComponents.getComponent('MessageContent', { selector: Reflection.resolve('container', 'containerCozy', 'containerCompact', 'edited').selector }, m => m.defaultProps && m.defaultProps.hasOwnProperty('disableButtons')); + this.MessageContent = await ReactComponents.getComponent('MessageContent'); this.patch(this.MessageContent.component.prototype, 'render', this.injectColoredText); - this.MessageContent.forceUpdateAll(); } /** * Set markup text colour to match role colour */ injectColoredText(thisObject, args, originalReturn) { - this.patch(originalReturn.props, 'children', function(obj, args, returnValue) { + const unpatch = this.patch(originalReturn.props, 'children', (obj, args, returnValue) => { + unpatch(); const { TinyColor } = Reflection.modules; const markup = Utils.findInReactTree(returnValue, m => m && m.props && m.props.className && m.props.className.includes('da-markup')); const roleColor = thisObject.props.message.colorString; diff --git a/client/src/builtin/E2EE.js b/client/src/builtin/E2EE/E2EE.js similarity index 95% rename from client/src/builtin/E2EE.js rename to client/src/builtin/E2EE/E2EE.js index e85b5bad..ea6a4aae 100644 --- a/client/src/builtin/E2EE.js +++ b/client/src/builtin/E2EE/E2EE.js @@ -9,8 +9,8 @@ */ import { Settings, Cache, Events } from 'modules'; -import BuiltinModule from './BuiltinModule'; -import { Reflection, ReactComponents, MonkeyPatch, Patcher, DiscordApi, Security } from 'modules'; +import BuiltinModule from '../BuiltinModule'; +import { Reflection, ReactComponents, DiscordApi, Security } from 'modules'; import { VueInjector, Modals, Toasts } from 'ui'; import { ClientLogger as Logger, ClientIPC } from 'common'; import { request } from 'vendor'; @@ -172,7 +172,7 @@ export default new class E2EE extends BuiltinModule { this.patch(Dispatcher, 'dispatch', this.dispatcherPatch, 'before'); this.patchMessageContent(); - const ChannelTextArea = await ReactComponents.getComponent('ChannelTextArea', { selector: Reflection.resolve('channelTextArea', 'emojiButton').selector }); + const ChannelTextArea = await ReactComponents.getComponent('ChannelTextArea'); this.patchChannelTextArea(ChannelTextArea); this.patchChannelTextAreaSubmit(ChannelTextArea); ChannelTextArea.forceUpdateAll(); @@ -236,12 +236,14 @@ export default new class E2EE extends BuiltinModule { } async patchMessageContent() { - const MessageContent = await ReactComponents.getComponent('MessageContent', { selector: Reflection.resolve('container', 'containerCozy', 'containerCompact', 'edited').selector }, m => m.defaultProps && m.defaultProps.hasOwnProperty('disableButtons')); + const MessageContent = await ReactComponents.getComponent('MessageContent'); this.patch(MessageContent.component.prototype, 'render', this.beforeRenderMessageContent, 'before'); - this.patch(MessageContent.component.prototype, 'render', this.afterRenderMessageContent); + this.childPatch(MessageContent.component.prototype, 'render', ['props', 'children'], this.afterRenderMessageContent); + MessageContent.forceUpdateAll(); - const ImageWrapper = await ReactComponents.getComponent('ImageWrapper', { selector: Reflection.resolve('imageWrapper').selector }); + const ImageWrapper = await ReactComponents.getComponent('ImageWrapper'); this.patch(ImageWrapper.component.prototype, 'render', this.beforeRenderImageWrapper, 'before'); + ImageWrapper.forceUpdateAll(); } beforeRenderMessageContent(component) { @@ -285,10 +287,16 @@ export default new class E2EE extends BuiltinModule { component.props.message.contentParsed = create.contentParsed; } - afterRenderMessageContent(component, args, retVal) { + afterRenderMessageContent(component, _childrenObject, args, retVal) { if (!component.props.message.bd_encrypted) return; - const buttons = Utils.findInReactTree(retVal, m => Array.isArray(m) && m[1].props && m[1].props.currentUserId); + + const { className } = Reflection.resolve('buttonContainer', 'avatar', 'username'); + const buttonContainer = Utils.findInReactTree(retVal, m => m && m.className && m.className.indexOf(className) !== -1); + if (!buttonContainer) return; + + const buttons = buttonContainer.children.props.children; if (!buttons) return; + try { buttons.unshift(VueInjector.createReactElement(E2EEMessageButton)); } catch (err) { diff --git a/client/src/builtin/E2EEComponent.vue b/client/src/builtin/E2EE/E2EEComponent.vue similarity index 98% rename from client/src/builtin/E2EEComponent.vue rename to client/src/builtin/E2EE/E2EEComponent.vue index 81bfda70..1d943ff1 100644 --- a/client/src/builtin/E2EEComponent.vue +++ b/client/src/builtin/E2EE/E2EEComponent.vue @@ -45,7 +45,7 @@ import { E2EE } from 'builtin'; import { Settings, DiscordApi, Reflection } from 'modules'; import { Toasts } from 'ui'; - import { MiLock, MiImagePlus, MiIcVpnKey } from '../ui/components/common/MaterialIcon'; + import { MiLock, MiImagePlus, MiIcVpnKey } from 'commoncomponents'; export default { components: { diff --git a/client/src/builtin/E2EEMessageButton.vue b/client/src/builtin/E2EE/E2EEMessageButton.vue similarity index 90% rename from client/src/builtin/E2EEMessageButton.vue rename to client/src/builtin/E2EE/E2EEMessageButton.vue index 9edf4968..ded7b5bc 100644 --- a/client/src/builtin/E2EEMessageButton.vue +++ b/client/src/builtin/E2EE/E2EEMessageButton.vue @@ -17,7 +17,7 @@