Add ability to restore default settings

This commit is contained in:
Zerebos 2024-02-24 21:18:41 -05:00
parent 853c554d4d
commit 97b486657f
5 changed files with 170 additions and 15 deletions

View File

@ -257,6 +257,8 @@
"updateButton": "Update!"
},
"Settings": {
"customColor": "Custom Color"
"customColor": "Custom Color",
"resetSettings": "Reset Settings",
"resetSettingsWarning": "Resetting your settings returns them all to the original state, this cannot be undone."
}
}

View File

@ -73,12 +73,16 @@ export default new class SettingsManager {
if (!this.state[collection.id]) this.state[collection.id] = {};
for (let cc = 0; cc < categories.length; cc++) {
const category = categories[cc];
if (category.type != "category") {if (!this.state[collection.id].hasOwnProperty(category.id)) this.state[collection.id][category.id] = category.value;}
if (category.type != "category") {
if (!this.state[collection.id].hasOwnProperty(category.id)) this.state[collection.id][category.id] = category.value;
category.defaultValue = category.value;
}
else {
if (!this.state[collection.id].hasOwnProperty(category.id)) this.state[collection.id][category.id] = {};
for (let s = 0; s < category.settings.length; s++) {
const setting = category.settings[s];
if (!this.state[collection.id][category.id].hasOwnProperty(setting.id)) this.state[collection.id][category.id][setting.id] = setting.value;
setting.defaultValue = setting.value;
if (setting.hasOwnProperty("disabled")) continue;
if (!setting.enableWith && !setting.disableWith) continue;
const pathString = setting.enableWith || setting.disableWith;
@ -131,6 +135,28 @@ export default new class SettingsManager {
this.saveCollection(id); // in case new things were added
}
resetCollection(id) {
const collection = this.collections.find(c => c.id == id);
if (!collection) return;
const categories = collection.settings;
for (let cc = 0; cc < categories.length; cc++) {
const category = categories[cc];
if (category.type != "category") {
// console.log("cat", collection.id, category.id, this.get(collection.id, category.id), category.value);
if (this.get(collection.id, category.id) == category.defaultValue) continue;
this.set(collection.id, category.id, category.defaultValue);
}
else {
for (let s = 0; s < category.settings.length; s++) {
const setting = category.settings[s];
// console.log("setting", collection.id, category.id, setting.id, this.get(collection.id, category.id, setting.id), setting.defaultValue);
if (this.get(collection.id, category.id, setting.id) == setting.defaultValue) continue;
this.set(collection.id, category.id, setting.id, setting.defaultValue);
}
}
}
}
onSettingChange(collection, category, id, value) {
this.state[collection][category][id] = value;
Events.dispatch("setting-updated", collection, category, id, value);

View File

@ -0,0 +1,9 @@
import React from "@modules/react";
export default function Restore(props) {
const size = props.size || "24px";
return <svg className={props.className || ""} fill="#FFFFFF" viewBox="0 0 24 24" style={{width: size, height: size}} onClick={props.onClick}>
<path d="M0 0h24v24H0z" fill="none"/>
<path d="M14 12c0-1.1-.9-2-2-2s-2 .9-2 2 .9 2 2 2 2-.9 2-2zm-2-9c-4.97 0-9 4.03-9 9H0l4 4 4-4H5c0-3.87 3.13-7 7-7s7 3.13 7 7-3.13 7-7 7c-1.51 0-2.91-.49-4.06-1.3l-1.42 1.44C8.04 20.3 9.94 21 12 21c4.97 0 9-4.03 9-9s-4.03-9-9-9z"/>
</svg>;
}

View File

@ -1,15 +1,55 @@
import React from "@modules/react";
import Strings from "@modules/strings";
import Utilities from "@modules/utilities";
import Events from "@modules/emitter";
import Settings from "@modules/settingsmanager";
import DataStore from "@modules/datastore";
import WebpackModules, {Filters} from "@modules/webpackmodules";
import Patcher from "@modules/patcher";
import DiscordModules from "@modules/discordmodules";
import AddonList from "./settings/addonlist";
import SettingsGroup from "./settings/group";
import SettingsTitle from "./settings/title";
import Header from "./settings/sidebarheader";
import ReactUtils from "@modules/api/reactutils";
import Button from "@ui/base/button";
import Modals from "@ui/modals";
import AddonList from "@ui/settings/addonlist";
import SettingsGroup from "@ui/settings/group";
import SettingsTitle from "@ui/settings/title";
import Header from "@ui/settings/sidebarheader";
import Restore from "./icons/restore";
// import SettingsPanel from "./settings/panel";
function makeResetButton(collectionId, refresh) {
const action = confirmReset(() => {
Settings.resetCollection(collectionId);
refresh?.();
});
return <DiscordModules.Tooltip color="primary" position="top" text={Strings.Settings.resetSettings}>
{(props) =>
<Button {...props} size={Button.Sizes.ICON} look={Button.Looks.BLANK} color={Button.Colors.TRANSPARENT} onClick={action}>
<Restore />
</Button>
}
</DiscordModules.Tooltip>;
}
/**
* @param {function} action
* @returns
*/
function confirmReset(action) {
return () => {
Modals.showConfirmationModal(Strings.Modals.confirmAction, Strings.Settings.resetSettingsWarning, {
confirmText: Strings.Modals.okay,
cancelText: Strings.Modals.cancel,
danger: true,
onConfirm: action,
});
};
}
export default new class SettingsRenderer {
@ -34,22 +74,32 @@ export default new class SettingsRenderer {
onChange(onChange) {
return (collection, category, id) => {
const before = Settings.collections.length + Settings.panels.length;
onChange(collection, category, id);
const after = Settings.collections.length + Settings.panels.length;
if (before != after) setTimeout(this.forceUpdate.bind(this), 50);
// Delay until after switch animation
// TODO: lift settings state to SettingsPanel
// to prevent the need for this.
setTimeout(this.forceUpdate.bind(this), 250);
};
}
buildSettingsPanel(id, title, config, state, onChange, button = null) {
buildSettingsPanel(id, title, config, state, onChange) {
config.forEach(section => {
section.settings.forEach(item => item.value = state[section.id][item.id]);
});
return this.getSettingsPanel(id, title, config, this.onChange(onChange), button);
return this.getSettingsPanel(id, title, config, this.onChange(onChange));
}
getSettingsPanel(id, title, groups, onChange, button = null) {
return [React.createElement(SettingsTitle, {text: title, button: button}), groups.map(section => {
getSettingsPanel(id, title, groups, onChange) {
// return <SettingsPanel
// id={id}
// title={title}
// groups={groups}
// onChange={onChange}
// onDrawerToggle={(...args) => this.onDrawerToggle(...args)}
// getDrawerState={(...args) => this.getDrawerState(...args)}
// />;
return [React.createElement(SettingsTitle, {text: title}, makeResetButton(id, this.forceUpdate.bind(this))), groups.map(section => {
return React.createElement(SettingsGroup, Object.assign({}, section, {
onChange: onChange,
onDrawerToggle: state => this.onDrawerToggle(id, section.id, state),
@ -85,7 +135,7 @@ export default new class SettingsRenderer {
section: collection.name,
label: collection.name.toString(),
className: `bd-${collection.id}-tab`,
element: () => this.buildSettingsPanel(collection.id, collection.name, collection.settings, Settings.state[collection.id], Settings.onSettingChange.bind(Settings, collection.id), collection.button ? collection.button : null)
element: () => this.buildSettingsPanel(collection.id, collection.name, collection.settings, Settings.state[collection.id], Settings.onSettingChange.bind(Settings, collection.id))
});
}
for (const panel of Settings.panels.sort((a,b) => a.order > b.order ? 1 : -1)) {
@ -101,7 +151,7 @@ export default new class SettingsRenderer {
const viewClass = WebpackModules.getByProps("standardSidebarView")?.standardSidebarView.split(" ")[0];
const node = document.querySelector(`.${viewClass}`);
if (!node) return;
const stateNode = Utilities.findInTree(node?.__reactFiber$, m => m && m.getPredicateSections, {walkable: ["return", "stateNode"]});
const stateNode = Utilities.findInTree(ReactUtils.getInternalInstance(node), m => m && m.getPredicateSections, {walkable: ["return", "stateNode"]});
if (stateNode) stateNode.forceUpdate();
}
};

View File

@ -0,0 +1,68 @@
import React from "@modules/react";
import Strings from "@modules/strings";
import Utilities from "@modules/utilities";
import Events from "@modules/emitter";
import Settings from "@modules/settingsmanager";
import DataStore from "@modules/datastore";
import WebpackModules, {Filters} from "@modules/webpackmodules";
import Patcher from "@modules/patcher";
import DiscordModules from "@modules/discordmodules";
import Button from "@ui/base/button";
import Modals from "@ui/modals";
import AddonList from "@ui/settings/addonlist";
import SettingsGroup from "@ui/settings/group";
import SettingsTitle from "@ui/settings/title";
import Header from "@ui/settings/sidebarheader";
import Restore from "@ui/icons/restore";
const {useCallback, useEffect, useReducer} = React;
function makeResetButton(collectionId) {
const action = confirmReset(() => Settings.resetCollection(collectionId));
return <DiscordModules.Tooltip color="primary" position="top" text={Strings.Settings.resetSettings}>
{(props) =>
<Button {...props} size={Button.Sizes.ICON} look={Button.Looks.BLANK} color={Button.Colors.TRANSPARENT} onClick={action}>
<Restore />
</Button>
}
</DiscordModules.Tooltip>;
}
/**
* @param {function} action
* @returns
*/
function confirmReset(action) {
return () => {
Modals.showConfirmationModal(Strings.Modals.confirmAction, Strings.Settings.resetSettingsWarning, {
confirmText: Strings.Modals.okay,
cancelText: Strings.Modals.cancel,
danger: true,
onConfirm: action,
});
};
}
export default function SettingsPanel({id, title, groups, onChange, onDrawerToggle, getDrawerState}) {
// TODO: add onChange here to lift and manage state here
return <>
<SettingsTitle text={title}>
{makeResetButton(id)}
</SettingsTitle>,
{groups.map(section => {
const props = Object.assign({}, section, {
onChange,
onDrawerToggle: state => onDrawerToggle(id, section.id, state),
shown: getDrawerState(id, section.id, section.hasOwnProperty("shown") ? section.shown : true)
});
return <SettingsGroup {...props} />;
})}
</>;
}