diff --git a/src/components/Settings.tsx b/src/components/Settings.tsx index c2743664..dfea1167 100644 --- a/src/components/Settings.tsx +++ b/src/components/Settings.tsx @@ -1,9 +1,9 @@ -import { useAwaiter } from "../utils/misc"; +import { humanFriendlyJoin, useAwaiter } from "../utils/misc"; import Plugins from 'plugins'; import { useSettings } from "../api/settings"; import IpcEvents from "../utils/IpcEvents"; -import { Button, ButtonProps, Flex, Switch, Forms } from "../webpack/common"; +import { Button, ButtonProps, Flex, Switch, Forms, React } from "../webpack/common"; import ErrorBoundary from "./ErrorBoundary"; import { startPlugin } from "../plugins"; import { stopPlugin } from '../plugins/index'; @@ -12,6 +12,22 @@ export default ErrorBoundary.wrap(function Settings(props) { const [settingsDir, , settingsDirPending] = useAwaiter(() => VencordNative.ipc.invoke(IpcEvents.GET_SETTINGS_DIR), "Loading..."); const settings = useSettings(); + const depMap = React.useMemo(() => { + const o = {} as Record; + for (const plugin in Plugins) { + const deps = Plugins[plugin].dependencies; + if (deps) { + for (const dep of deps) { + o[dep] ??= []; + o[dep].push(plugin); + } + } + } + return o; + }, []); + + console.log(depMap); + return ( SettingsDir: {settingsDir} @@ -45,39 +61,50 @@ export default ErrorBoundary.wrap(function Settings(props) { Plugins - {Object.values(Plugins).map(p => ( - { - settings.plugins[p.name].enabled = v; - if (v) { - p.dependencies?.forEach(d => { - settings.plugins[d].enabled = true; - if (!Plugins[d].started && !stopPlugin) { + {Object.values(Plugins).map(p => { + const enabledDependants = depMap[p.name]?.filter(d => settings.plugins[d].enabled); + const dependency = enabledDependants?.length; + + return ( + { + settings.plugins[p.name].enabled = v; + if (v) { + p.dependencies?.forEach(d => { + settings.plugins[d].enabled = true; + if (!Plugins[d].started && !stopPlugin) { + // TODO show notification + settings.plugins[p.name].enabled = false; + } + }); + if (!p.started && !startPlugin(p)) { // TODO show notification - settings.plugins[p.name].enabled = false; } - }); - if (!p.started && !startPlugin(p)) { - // TODO show notification - } - } else { - if (p.started && !stopPlugin(p)) { + } else { + if (p.started && !stopPlugin(p)) { + // TODO show notification + } + } + if (p.patches) { // TODO show notification } + }} + note={p.description} + tooltipNote={ + p.required ? + "This plugin is required. Thus you cannot disable it." + : dependency ? + `${humanFriendlyJoin(enabledDependants)} ${enabledDependants.length === 1 ? "depends" : "depend"} on this plugin. Thus you cannot disable it.` + : "" } - if (p.patches) { - // TODO show notification - } - }} - note={p.description} - tooltipNote={p.required ? "This plugin is required. Thus you cannot disable it." : undefined} - > - {p.name} - - )) + > + {p.name} + + ); + }) } ); diff --git a/src/utils/misc.tsx b/src/utils/misc.tsx index aca7661b..9d4c001f 100644 --- a/src/utils/misc.tsx +++ b/src/utils/misc.tsx @@ -69,4 +69,32 @@ export function mergeDefaults(obj: T, defaults: T): T { } } return obj; -} \ No newline at end of file +} + + +/** + * Join an array of strings in a human readable way (1, 2 and 3) + * @param elements Elements + */ +export function humanFriendlyJoin(elements: string[]): string; +/** + * Join an array of strings in a human readable way (1, 2 and 3) + * @param elements Elements + * @param mapper Function that converts elements to a string + */ +export function humanFriendlyJoin(elements: T[], mapper: (e: T) => string): string; +export function humanFriendlyJoin(elements: any[], mapper: (e: any) => string = s => s): string { + const { length } = elements; + if (length === 0) return ""; + if (length === 1) return mapper(elements[0]); + + let s = ""; + + for (let i = 0; i < length; i++) { + s += mapper(elements[i]); + if (length - i > 2) s += ", "; + else if (length - i > 1) s += " and "; + } + + return s; +}