/* * Vencord, a modification for Discord's desktop app * Copyright (c) 2022 Vendicated and contributors * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ import { User } from "discord-types/general"; import { Constructor } from "type-fest"; import { generateId } from "../../api/Commands"; import { useSettings } from "../../api/settings"; import { LazyComponent, lazyWebpack, proxyLazy } from "../../utils"; import { ModalContent, ModalFooter, ModalHeader, ModalProps, ModalRoot, ModalSize } from "../../utils/modal"; import { OptionType, Plugin } from "../../utils/types"; import { filters, findByCode } from "../../webpack"; import { Button, FluxDispatcher, Forms, React, Text, Tooltip, UserStore, UserUtils } from "../../webpack/common"; import ErrorBoundary from "../ErrorBoundary"; import { Flex } from "../Flex"; import { ISettingElementProps, SettingBooleanComponent, SettingCustomComponent, SettingNumericComponent, SettingSelectComponent, SettingSliderComponent, SettingTextComponent } from "./components"; const UserSummaryItem = LazyComponent(() => findByCode("defaultRenderUser", "showDefaultAvatarsForNullUsers")); const AvatarStyles = lazyWebpack(filters.byProps("moreUsers", "emptyUser", "avatarContainer", "clickableAvatar")); const UserRecord: Constructor> = proxyLazy(() => UserStore.getCurrentUser().constructor) as any; interface PluginModalProps extends ModalProps { plugin: Plugin; onRestartNeeded(): void; } /** To stop discord making unwanted requests... */ function makeDummyUser(user: { name: string, id: BigInt; }) { const newUser = new UserRecord({ username: user.name, id: generateId(), bot: true, }); FluxDispatcher.dispatch({ type: "USER_UPDATE", user: newUser, }); return newUser; } const Components: Record>> = { [OptionType.STRING]: SettingTextComponent, [OptionType.NUMBER]: SettingNumericComponent, [OptionType.BIGINT]: SettingNumericComponent, [OptionType.BOOLEAN]: SettingBooleanComponent, [OptionType.SELECT]: SettingSelectComponent, [OptionType.SLIDER]: SettingSliderComponent, [OptionType.COMPONENT]: SettingCustomComponent }; export default function PluginModal({ plugin, onRestartNeeded, onClose, transitionState }: PluginModalProps) { const [authors, setAuthors] = React.useState[]>([]); const pluginSettings = useSettings().plugins[plugin.name]; const [tempSettings, setTempSettings] = React.useState>({}); const [errors, setErrors] = React.useState>({}); const [saveError, setSaveError] = React.useState(null); const canSubmit = () => Object.values(errors).every(e => !e); React.useEffect(() => { (async () => { for (const user of plugin.authors.slice(0, 6)) { const author = user.id ? await UserUtils.fetchUser(`${user.id}`).catch(() => makeDummyUser(user)) : makeDummyUser(user); setAuthors(a => [...a, author]); } })(); }, []); async function saveAndClose() { if (!plugin.options) { onClose(); return; } if (plugin.beforeSave) { const result = await Promise.resolve(plugin.beforeSave(tempSettings)); if (result !== true) { setSaveError(result); return; } } let restartNeeded = false; for (const [key, value] of Object.entries(tempSettings)) { const option = plugin.options[key]; pluginSettings[key] = value; option?.onChange?.(value); if (option?.restartNeeded) restartNeeded = true; } if (restartNeeded) onRestartNeeded(); onClose(); } function renderSettings() { if (!pluginSettings || !plugin.options) { return There are no settings for this plugin.; } const options = Object.entries(plugin.options).map(([key, setting]) => { function onChange(newValue: any) { setTempSettings(s => ({ ...s, [key]: newValue })); } function onError(hasError: boolean) { setErrors(e => ({ ...e, [key]: hasError })); } const Component = Components[setting.type]; return ( ); }); return {options}; } function renderMoreUsers(_label: string, count: number) { const sliceCount = plugin.authors.length - count; const sliceStart = plugin.authors.length - sliceCount; const sliceEnd = sliceStart + plugin.authors.length - count; return ( u.name).join(", ")}> {({ onMouseEnter, onMouseLeave }) => (
+{sliceCount}
)}
); } return ( {plugin.name} About {plugin.name} {plugin.description}
{!!plugin.settingsAboutComponent && (
)} Settings {renderSettings()}
{({ onMouseEnter, onMouseLeave }) => ( )} {saveError && Error while saving: {saveError}}
); }