diff --git a/assets/locales/en-us.json b/assets/locales/en-us.json index 52f68164..e008f65c 100644 --- a/assets/locales/en-us.json +++ b/assets/locales/en-us.json @@ -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." } } \ No newline at end of file diff --git a/renderer/src/modules/settingsmanager.js b/renderer/src/modules/settingsmanager.js index 63717a68..e5684604 100644 --- a/renderer/src/modules/settingsmanager.js +++ b/renderer/src/modules/settingsmanager.js @@ -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); diff --git a/renderer/src/ui/icons/restore.jsx b/renderer/src/ui/icons/restore.jsx new file mode 100644 index 00000000..092cdd75 --- /dev/null +++ b/renderer/src/ui/icons/restore.jsx @@ -0,0 +1,9 @@ +import React from "@modules/react"; + +export default function Restore(props) { + const size = props.size || "24px"; + return + + + ; +} diff --git a/renderer/src/ui/settings.js b/renderer/src/ui/settings.js index c54d3c07..ca167511 100644 --- a/renderer/src/ui/settings.js +++ b/renderer/src/ui/settings.js @@ -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 + {(props) => + + } + ; +} + +/** + * @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 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(); } }; \ No newline at end of file diff --git a/renderer/src/ui/settings/panel.jsx b/renderer/src/ui/settings/panel.jsx new file mode 100644 index 00000000..bc7c7080 --- /dev/null +++ b/renderer/src/ui/settings/panel.jsx @@ -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 + {(props) => + + } + ; +} + +/** + * @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 <> + + {makeResetButton(id)} + , + {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 ; + })} + ; + +} \ No newline at end of file