/* * 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 "./style.css"; import { definePluginSettings, Settings } from "@api/Settings"; import { getUserSettingLazy } from "@api/UserSettings"; import ErrorBoundary from "@components/ErrorBoundary"; import { EquicordDevs } from "@utils/constants"; import { proxyLazy } from "@utils/lazy"; import { classes } from "@utils/misc"; import { ModalProps, openModalLazy } from "@utils/modal"; import { useForceUpdater } from "@utils/react"; import definePlugin, { OptionType, StartAt } from "@utils/types"; import { extractAndLoadChunksLazy, findByPropsLazy, findComponentByCodeLazy, findModuleId, wreq } from "@webpack"; import { Button, Clickable, Menu, Toasts, UserStore, useState } from "@webpack/common"; import { FunctionComponent } from "react"; const settings = definePluginSettings({ StatusPresets: { type: OptionType.COMPONENT, description: "Status Presets", component: () => <>, default: {} } }); interface Emoji { animated: boolean; id: bigint | null; name: string; } function CircleXIcon() { return ; } interface DiscordStatus { emojiInfo: Emoji | null; text: string; clearAfter: "TODAY" | number | null; status: "online" | "dnd" | "idle" | "invisible"; } const StatusStyles = findByPropsLazy("statusItem"); // TODO: find clearCustomStatusHint original css/svg or replace const PMenu = findComponentByCodeLazy(".menuItemLabel", ".menuItemInner"); const EmojiComponent = findComponentByCodeLazy(/\.translateSurrogatesToInlineEmoji\(\i.\i\),/); const CustomStatusSettings = getUserSettingLazy("status", "customStatus")!; const StatsModule: { default: FunctionComponent; } = proxyLazy(() => { const id = findModuleId("this.renderCustomStatusInput()"); return wreq(Number(id)); }); const requireCustomStatusModal = extractAndLoadChunksLazy(["action:\"PRESS_ADD_CUSTOM_STATUS\"", ".openModalLazy"]); const openCustomStatusModalLazy = () => openModalLazy(async () => { await requireCustomStatusModal(); return props => ; }); function getExpirationMs(expiration: "TODAY" | number) { if (expiration !== "TODAY") return Date.now() + expiration; const now = new Date(); return new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1).getTime(); } function setStatus(status: DiscordStatus) { CustomStatusSettings.updateSetting({ text: status.text.trim(), expiresAtMs: status.clearAfter != null ? String(getExpirationMs(status.clearAfter)) : "0", emojiId: status.emojiInfo?.id ?? "0", emojiName: status.emojiInfo?.name ?? "", createdAtMs: String(Date.now()) }); } const ClearStatusButton = () => { e.stopPropagation(); CustomStatusSettings?.updateSetting(null); }}>; function StatusIcon({ isHovering, status }: { isHovering: boolean; status: DiscordStatus; }) { return
{isHovering ? : (status.emojiInfo != null ? :
)}
; } const RenderStatusMenuItem = ({ status, update, disabled }: { status: DiscordStatus; update: () => void; disabled: boolean; }) => { const [isHovering, setIsHovering] = useState(false); const handleMouseOver = () => { setIsHovering(true); }; const handleMouseOut = () => { setIsHovering(false); }; return
{ e.stopPropagation(); settings.store.StatusPresets[status.text] = undefined; // setting to undefined to remove it. update(); }}>
{status.text}
; }; const StatusSubMenuComponent = () => { let premiumType; if (Settings.plugins.NoNitroUpsell?.enabled) { // @ts-ignore premiumType = UserStore?.getCurrentUser()?._realPremiumType ?? UserStore?.getCurrentUser()?.premiumType ?? 0; } else { premiumType = UserStore?.getCurrentUser()?.premiumType ?? 0; } const update = useForceUpdater(); return { }}> {Object.entries((settings.store.StatusPresets as { [k: string]: DiscordStatus | undefined; })).map(([index, status]) => status != null ? (status.emojiInfo?.id != null && premiumType > 0 || status.emojiInfo?.id == null) && setStatus(status)} render={() => } /> : null)} ; }; export default definePlugin({ name: "StatusPresets", description: "Allows you to remember your statuses and set them later", authors: [EquicordDevs.iamme], settings: settings, dependencies: ["UserSettingsAPI"], patches: [ { find: "#{intl::CUSTOM_STATUS_SET_CUSTOM_STATUS}", replacement: { match: /\.\i\i,children:.{0,70}\i\.\i\.string\(\i\.\i#{intl::SAVE}\)\}\)/, replace: "$&,$self.renderRememberButton(this.state)" } }, { find: "#{intl::STATUS_MENU_LABEL}", replacement: { match: /"set-status-submenu-mobile-web".{150,165}void 0\}\)/, replace: "$&,$self.render()" }, all: true } ], render() { const status = CustomStatusSettings.getSetting(); return
{status == null ?
} label="Set Custom Status" renderSubmenu={StatusSubMenuComponent} /> : } icon={() => status.emoji != null ? : null} label="Edit Custom Status" renderSubmenu={StatusSubMenuComponent} />} ; }, renderRememberButton(statue: DiscordStatus) { return ; }, startAt: StartAt.WebpackReady });