/*
* 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 "./PluginModal.css";
import { generateId } from "@api/Commands";
import { useSettings } from "@api/Settings";
import { classNameFactory } from "@api/Styles";
import ErrorBoundary from "@components/ErrorBoundary";
import { Flex } from "@components/Flex";
import { debounce } from "@shared/debounce";
import { gitRemote } from "@shared/vencordUserAgent";
import { proxyLazy } from "@utils/lazy";
import { Margins } from "@utils/margins";
import { isObjectEmpty } from "@utils/misc";
import { ModalCloseButton, ModalContent, ModalHeader, ModalProps, ModalRoot, ModalSize, openModal } from "@utils/modal";
import { OptionType, Plugin } from "@utils/types";
import { User } from "@vencord/discord-types";
import { findByPropsLazy } from "@webpack";
import { Clickable, FluxDispatcher, Forms, React, Text, Tooltip, useEffect, UserStore, UserSummaryItem, UserUtils, useState } from "@webpack/common";
import { Constructor } from "type-fest";
import { PluginMeta } from "~plugins";
import { OptionComponentMap } from "./components";
import { openContributorModal } from "./ContributorModal";
import { GithubButton, WebsiteButton } from "./LinkIconButton";
const cl = classNameFactory("vc-plugin-modal-");
const AvatarStyles = findByPropsLazy("moreUsers", "emptyUser", "avatarContainer", "clickableAvatar");
const UserRecord: Constructor> = proxyLazy(() => UserStore.getCurrentUser().constructor) as any;
interface PluginModalProps extends ModalProps {
plugin: Plugin;
onRestartNeeded(key: string): void;
}
function makeDummyUser(user: { username: string; id?: string; avatar?: string; }) {
const newUser = new UserRecord({
username: user.username,
id: user.id ?? generateId(),
avatar: user.avatar,
/** To stop discord making unwanted requests... */
bot: true,
});
FluxDispatcher.dispatch({
type: "USER_UPDATE",
user: newUser,
});
return newUser;
}
export default function PluginModal({ plugin, onRestartNeeded, onClose, transitionState }: PluginModalProps) {
const pluginSettings = useSettings().plugins[plugin.name];
const hasSettings = Boolean(pluginSettings && plugin.options && !isObjectEmpty(plugin.options));
const [authors, setAuthors] = useState[]>([]);
useEffect(() => {
(async () => {
for (const user of plugin.authors.slice(0, 6)) {
const author = user.id
? await UserUtils.getUser(`${user.id}`)
.catch(() => makeDummyUser({ username: user.name }))
: makeDummyUser({ username: user.name });
setAuthors(a => [...a, author]);
}
})();
}, [plugin.authors]);
function renderSettings() {
if (!hasSettings || !plugin.options)
return There are no settings for this plugin.;
const options = Object.entries(plugin.options).map(([key, setting]) => {
if (setting.type === OptionType.CUSTOM || setting.hidden) return null;
function onChange(newValue: any) {
const option = plugin.options?.[key];
if (!option || option.type === OptionType.CUSTOM) return;
pluginSettings[key] = newValue;
if (option.restartNeeded) onRestartNeeded(key);
}
const Component = OptionComponentMap[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}
)}
);
}
const pluginMeta = PluginMeta[plugin.name];
return (
{plugin.name}
{plugin.description}
{!pluginMeta.userPlugin && (
)}
Authors
(
openContributorModal(user)}
>
)}
/>
{!!plugin.settingsAboutComponent && (
)}
Settings
{renderSettings()}
);
}
export function openPluginModal(plugin: Plugin, onRestartNeeded?: (pluginName: string, key: string) => void) {
openModal(modalProps => (
onRestartNeeded?.(plugin.name, key)}
/>
));
}