pc-settings/index.js

181 lines
6.3 KiB
JavaScript

const { React, getModuleByDisplayName, getModule, i18n: { Messages } } = require('powercord/webpack');
const { AsyncComponent, Menu } = require('powercord/components');
const { inject, uninject } = require('powercord/injector');
const { Plugin } = require('powercord/entities');
const { sleep } = require('powercord/util');
const ErrorBoundary = require('./components/ErrorBoundary');
const GeneralSettings = require('./components/GeneralSettings');
// const Labs = require('./components/Labs');
const FormTitle = AsyncComponent.from(getModuleByDisplayName('FormTitle'));
const FormSection = AsyncComponent.from(getModuleByDisplayName('FormSection'));
module.exports = class Settings extends Plugin {
async startPlugin() {
powercord.api.settings.registerSettings('pc-general', {
category: 'pc-general',
label: () => Messages.POWERCORD_GENERAL_SETTINGS,
render: GeneralSettings
});
await this.loadStylesheet('scss/style.scss');
// Force load
await this._forceLoadSettings();
// this.patchSettingsContextMenu();
this.patchSettingsComponent();
this.patchExperiments();
}
async pluginWillUnload() {
powercord.api.settings.unregisterSettings('pc-general');
uninject('pc-settings-items');
uninject('pc-settings-actions');
uninject('pc-settings-errorHandler');
}
async patchExperiments() {
try {
const experimentsModule = await getModule(r => r.isDeveloper !== void 0);
Object.defineProperty(experimentsModule, 'isDeveloper', {
get: () => powercord.settings.get('experiments', false)
});
// Ensure components do get the update
experimentsModule._changeCallbacks.forEach(cb => cb());
} catch (_) {
// memes
}
}
async patchSettingsComponent() {
const SettingsView = await getModuleByDisplayName('SettingsView');
inject('pc-settings-items', SettingsView.prototype, 'getPredicateSections', (_, sections) => {
if (sections.length < 10) {
return sections;
}
const changelog = sections.find(c => c.section === 'changelog');
if (changelog) {
const settingsSections = Object.keys(powercord.api.settings.tabs).map(s => this._makeSection(s));
sections.splice(
sections.indexOf(changelog), 0,
{
section: 'HEADER',
label: 'Powercord'
},
...settingsSections,
{ section: 'DIVIDER' }
);
}
if (sections.find(c => c.section === 'CUSTOM')) {
sections.find(c => c.section === 'CUSTOM').element = ((_element) => function () {
const res = _element();
if (res.props.children && res.props.children.length === 3) {
res.props.children.unshift(
Object.assign({}, res.props.children[0], {
props: Object.assign({}, res.props.children[0].props, {
href: 'https://milky.quest',
title: 'Milky Quest',
className: `${res.props.children[0].props.className} powercord-pc-icon`
})
})
);
}
return res;
})(sections.find(c => c.section === 'CUSTOM').element);
}
const latestCommitHash = powercord.gitInfos.revision.substring(0, 7);
const debugInfo = sections[sections.findIndex(c => c.section === 'CUSTOM') + 1];
if (debugInfo) {
debugInfo.element = ((_element) => function () {
const res = _element();
if (res.props.children && res.props.children.length === 4) {
res.props.children.push(
Object.assign({}, res.props.children[0], {
props: Object.assign({}, res.props.children[0].props, {
children: ['Powercord', ' ', React.createElement('span', {
className: res.props.children[0].props.children[4].props.className,
children: [powercord.gitInfos.branch, ' (', latestCommitHash, ')']
})]
})
})
);
}
return res;
})(debugInfo.element);
}
return sections;
});
}
_makeSection(tabId) {
const props = powercord.api.settings.tabs[tabId];
const label = typeof props.label === 'function' ? props.label() : props.label;
return {
label,
section: tabId,
element: () => this._renderWrapper(label, props.render)
};
}
_renderWrapper(label, Component) {
return React.createElement(ErrorBoundary, null,
React.createElement(FormSection, {},
React.createElement(FormTitle, { tag: 'h2' }, label),
React.createElement(Component)
)
);
}
async patchSettingsContextMenu() {
const SettingsContextMenu = await getModule(m => m.default?.displayName === 'UserSettingsCogContextMenu');
inject('pc-settings-actions', SettingsContextMenu, 'default', (_, res) => {
const parent = React.createElement(Menu.MenuItem, {
id: 'powercord-actions',
label: 'Powercord'
}, Object.keys(powercord.api.settings.tabs).map(tabId => {
const props = powercord.api.settings.tabs[tabId];
const label = typeof props.label === 'function' ? props.label() : props.label;
return React.createElement(Menu.MenuItem, {
label,
id: tabId,
action: async () => {
const settingsModule = await getModule(['open', 'saveAccountChanges']);
settingsModule.open(tabId);
}
});
}));
parent.key = 'Powercord';
const items = res.props.children.find(child => Array.isArray(child));
const changelog = items.find(item => item?.props?.id === 'changelog');
if (changelog) {
items.splice(items.indexOf(changelog), 0, parent);
} else {
this.error('Unable to locate "Change Log" item; forcing element to context menu!');
res.props.children.push(parent);
}
return res;
});
}
async _forceLoadSettings() {
await sleep(5e3); // Everyone's favorite fix
document.body.classList.add('__powercord-no-settings-animation');
const layers = await getModule(['popLayer'], false);
const opener = await getModule(['open', 'updateAccount'], false);
opener.open();
layers.popLayer();
setTimeout(() => document.body.classList.remove('__powercord-no-settings-animation'), 1100);
}
};