BetterDiscordApp-rauenzi/src/modules/settingsmanager.js

208 lines
9.4 KiB
JavaScript
Raw Normal View History

2019-06-10 01:04:39 +02:00
import {SettingsConfig} from "data";
2019-06-19 21:24:05 +02:00
import Logger from "./logger";
2019-05-31 07:53:11 +02:00
import DataStore from "./datastore";
2019-05-30 17:44:05 +02:00
import Events from "./emitter";
2019-06-19 21:24:05 +02:00
import WebpackModules from "./webpackmodules";
import DiscordModules from "./discordmodules";
2019-06-22 06:37:19 +02:00
import Patcher from "./patcher";
import ReactComponents from "./reactcomponents";
2019-05-29 05:48:41 +02:00
import {SettingsPanel as SettingsRenderer} from "ui";
2019-05-31 07:53:11 +02:00
import Utilities from "./utilities";
2019-06-04 21:17:23 +02:00
export default new class SettingsManager {
2019-05-29 05:48:41 +02:00
constructor() {
2019-06-10 01:04:39 +02:00
this.state = {};
2019-06-09 22:30:33 +02:00
this.collections = [];
2019-06-08 08:35:43 +02:00
this.panels = [];
2019-06-09 22:30:33 +02:00
this.registerCollection("settings", "Settings", SettingsConfig);
2019-05-29 05:48:41 +02:00
}
2019-05-31 07:53:11 +02:00
initialize() {
DataStore.initialize();
2019-06-06 21:57:25 +02:00
this.loadSettings();
2019-05-31 07:53:11 +02:00
this.patchSections();
2019-06-09 22:30:33 +02:00
}
registerCollection(id, name, settings, button = null) {
2019-06-19 21:24:05 +02:00
if (this.collections.find(c => c.id == id)) return Logger.error("Settings", "Already have a collection with id " + id);
2019-06-09 22:30:33 +02:00
this.collections.push({
type: "collection",
id: id,
name: name,
settings: settings,
button: button
});
this.setup();
}
removeCollection(id) {
const location = this.collections.findIndex(c => c.id == id);
2019-06-19 21:24:05 +02:00
if (!location < 0) return Logger.error("Settings", "No collection with id " + id);
2019-06-09 22:30:33 +02:00
this.collections.splice(location, 1);
2019-06-08 08:35:43 +02:00
}
2019-06-05 06:30:24 +02:00
2019-06-10 05:40:35 +02:00
registerPanel(id, name, options) {
2019-06-19 21:24:05 +02:00
if (this.panels.find(p => p.id == id)) return Logger.error("Settings", "Already have a panel with id " + id);
2019-06-10 05:40:35 +02:00
const {element, onClick, order = 1} = options;
const section = {id, order, label: name, section: name};
2019-06-10 22:37:50 +02:00
if (onClick) section.clickListener = onClick;
if (element) section.element = element instanceof DiscordModules.React.Component ? () => DiscordModules.React.createElement(element, {}) : typeof(element) == "function" ? element : () => element;
2019-06-08 08:35:43 +02:00
this.panels.push(section);
2019-06-05 06:30:24 +02:00
}
2019-06-10 05:40:35 +02:00
removePanel(id) {
const location = this.panels.findIndex(c => c.id == id);
2019-06-19 21:24:05 +02:00
if (!location < 0) return Logger.error("Settings", "No collection with id " + id);
2019-06-10 05:40:35 +02:00
this.panels.splice(location, 1);
}
2019-06-06 21:57:25 +02:00
getPath(path, collectionId = "", categoryId = "") {
const collection = path.length == 3 ? path[0] : collectionId;
const category = path.length == 3 ? path[1] : path.length == 2 ? path[0] : categoryId;
const setting = path[path.length - 1];
return {collection, category, setting};
}
2019-06-09 22:30:33 +02:00
setup() {
for (let c = 0; c < this.collections.length; c++) {
const collection = this.collections[c];
const categories = this.collections[c].settings;
if (!this.state[collection.id]) this.state[collection.id] = {};
2019-06-19 05:09:49 +02:00
for (let cc = 0; cc < categories.length; cc++) {
const category = categories[cc];
2019-06-09 22:30:33 +02:00
if (category.type != "category") {if (!this.state[collection.id].hasOwnProperty(category.id)) this.state[collection.id][category.id] = category.value;}
2019-06-06 21:57:25 +02:00
else {
2019-06-09 22:30:33 +02:00
if (!this.state[collection.id].hasOwnProperty(category.id)) this.state[collection.id][category.id] = {};
2019-06-06 21:57:25 +02:00
for (let s = 0; s < category.settings.length; s++) {
const setting = category.settings[s];
2019-06-09 22:30:33 +02:00
if (!this.state[collection.id][category.id].hasOwnProperty(setting.id)) this.state[collection.id][category.id][setting.id] = setting.value;
2019-06-06 21:57:25 +02:00
if (setting.enableWith) {
const path = this.getPath(setting.enableWith.split("."), collection.id, category.id);
2019-06-09 22:30:33 +02:00
if (setting.hasOwnProperty("disabled")) continue;
2019-06-06 21:57:25 +02:00
Object.defineProperty(setting, "disabled", {
get: () => {
2019-06-09 22:30:33 +02:00
return !this.state[path.collection][path.category][path.setting];
2019-06-06 21:57:25 +02:00
}
});
}
2019-06-10 22:37:50 +02:00
if (setting.disableWith) {
const path = this.getPath(setting.disableWith.split("."), collection.id, category.id);
if (setting.hasOwnProperty("disabled")) continue;
Object.defineProperty(setting, "disabled", {
get: () => {
return this.state[path.collection][path.category][path.setting];
}
});
}
2019-06-05 06:30:24 +02:00
}
}
}
}
}
2019-05-31 07:53:11 +02:00
async patchSections() {
2019-06-22 06:37:19 +02:00
Patcher.after("SettingsManager", WebpackModules.getByDisplayName("FluxContainer(GuildSettings)").prototype, "render", (thisObject) => {
thisObject._reactInternalFiber.return.return.return.return.return.return.memoizedProps.id = "guild-settings";
});
const UserSettings = await ReactComponents.get("UserSettings", m => m.prototype && m.prototype.generateSections);
Patcher.after("SettingsManager", UserSettings.prototype, "render", (thisObject) => {
thisObject._reactInternalFiber.return.return.return.return.return.return.return.memoizedProps.id = "user-settings";
});
Patcher.after("SettingsManager", UserSettings.prototype, "generateSections", (thisObject, args, returnValue) => {
let location = returnValue.findIndex(s => s.section.toLowerCase() == "linux") + 1;
2019-06-06 06:28:43 +02:00
const insert = (section) => {
2019-06-22 06:37:19 +02:00
returnValue.splice(location, 0, section);
2019-06-06 06:28:43 +02:00
location++;
};
insert({section: "DIVIDER"});
insert({section: "HEADER", label: "BandagedBD"});
2019-06-09 22:30:33 +02:00
for (const collection of this.collections) {
2019-06-06 21:57:25 +02:00
if (collection.disabled) continue;
insert({
section: collection.name,
label: collection.name,
2019-06-10 01:04:39 +02:00
element: () => SettingsRenderer.buildSettingsPanel(collection.name, collection.settings, this.state[collection.id], this.onSettingChange.bind(this, collection.id), collection.button ? collection.button : null)
2019-06-06 21:57:25 +02:00
});
}
2019-06-10 22:37:50 +02:00
for (const panel of this.panels.sort((a,b) => a.order > b.order)) {
2019-06-22 06:37:19 +02:00
if (panel.clickListener) panel.onClick = (event) => panel.clickListener(thisObject, event, returnValue);
2019-06-10 22:37:50 +02:00
insert(panel);
}
2019-06-08 08:35:43 +02:00
insert({section: "CUSTOM", element: () => SettingsRenderer.attribution});
2019-06-22 06:37:19 +02:00
});
2019-06-06 06:28:43 +02:00
this.forceUpdate();
}
forceUpdate() {
2019-05-31 07:53:11 +02:00
const viewClass = WebpackModules.getByProps("standardSidebarView").standardSidebarView.split(" ")[0];
const node = document.querySelector(`.${viewClass}`);
2019-06-20 04:19:34 +02:00
Utilities.getReactInstance(node).return.return.return.return.return.return.stateNode.forceUpdate();
2019-05-31 07:53:11 +02:00
}
saveSettings() {
2019-06-06 21:57:25 +02:00
DataStore.setData("settings", this.state);
2019-05-31 07:53:11 +02:00
}
loadSettings() {
2019-06-06 21:57:25 +02:00
const previousState = DataStore.getData("settings");
if (!previousState) return this.saveSettings();
for (const collection in this.state) {
if (!previousState[collection]) Object.assign(previousState, {[collection]: this.state[collection]});
for (const category in this.state[collection]) {
2019-06-10 05:40:35 +02:00
if (!previousState[collection][category]) Object.assign(previousState[collection], {[category]: this.state[collection][category]});
for (const setting in this.state[collection][category]) {
2019-06-06 21:57:25 +02:00
if (previousState[collection][category][setting] == undefined) continue;
this.state[collection][category][setting] = previousState[collection][category][setting];
}
}
}
this.saveSettings(); // in case new things were added
2019-05-31 07:53:11 +02:00
}
2019-06-06 21:57:25 +02:00
onSettingChange(collection, category, id, value) {
2019-06-10 05:40:35 +02:00
const before = this.collections.length + this.panels.length;
2019-06-06 21:57:25 +02:00
this.state[collection][category][id] = value;
Events.dispatch("setting-updated", collection, category, id, value);
2019-06-10 05:40:35 +02:00
const after = this.collections.length + this.panels.length;
2019-06-06 21:57:25 +02:00
this.saveSettings();
2019-06-10 22:37:50 +02:00
if (before != after) setTimeout(this.forceUpdate.bind(this), 50);
2019-06-06 06:28:43 +02:00
}
2019-06-06 21:57:25 +02:00
getSetting(collection, category, id) {
2019-06-09 22:30:33 +02:00
if (arguments.length == 2) return this.collections[0].find(c => c.id == arguments[0]).settings.find(s => s.id == arguments[1]);
return this.collections.find(c => c.id == collection).find(c => c.id == category).settings.find(s => s.id == id);
2019-06-06 06:28:43 +02:00
}
2019-06-06 21:57:25 +02:00
get(collection, category, id) {
2019-06-09 22:30:33 +02:00
if (arguments.length == 2) {
id = category;
category = collection;
collection = "settings";
}
if (!this.state[collection] || !this.state[collection][category]) return false;
2019-06-06 21:57:25 +02:00
return this.state[collection][category][id];
}
2019-06-10 05:40:35 +02:00
set(collection, category, id, value) {
if (arguments.length == 3) {
value = id;
id = category;
category = collection;
collection = "settings";
}
return this.onSettingChange(collection, category, id, value);
}
2019-06-06 21:57:25 +02:00
on(collection, category, identifier, callback) {
const handler = (col, cat, id, value) => {
if (col !== collection || cat !== category || id !== identifier) return;
callback(value);
};
Events.on("setting-updated", handler);
return () => {Events.off("setting-updated", handler);};
2019-06-06 06:28:43 +02:00
}
2019-05-29 05:48:41 +02:00
};