From 0e167188a2ed5ee65fe3a76a8c39b2deabead250 Mon Sep 17 00:00:00 2001 From: programminglaboratorys <107296738+programminglaboratorys@users.noreply.github.com> Date: Tue, 15 Oct 2024 21:18:31 +0300 Subject: [PATCH] feat(plugin): StatusPresets (#56) * lint fix * the actual lint fix & readme removing unwanted text * Delete src/equicordplugins/statusPresets/README.md --------- Co-authored-by: thororen <78185467+thororen1234@users.noreply.github.com> --- README.md | 3 +- src/equicordplugins/statusPresets/index.tsx | 187 ++++++++++++++++++++ src/equicordplugins/statusPresets/style.css | 8 + src/webpack/common/types/components.d.ts | 2 +- 4 files changed, 198 insertions(+), 2 deletions(-) create mode 100644 src/equicordplugins/statusPresets/index.tsx create mode 100644 src/equicordplugins/statusPresets/style.css diff --git a/README.md b/README.md index 7b2c8ad5..4950e342 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ You can join our [discord server](https://discord.gg/5Xh2W87egW) for commits, ch ### Extra included plugins
-130 additional plugins +131 additional plugins - AllCallTimers by MaxHerbold & D3SOX - AltKrispSwitch by newwares @@ -113,6 +113,7 @@ You can join our [discord server](https://discord.gg/5Xh2W87egW) for commits, ch - ShowBadgesInChat by Inbestigator & KrystalSkull - Slap by Korbo - SoundBoardLogger by Moxxie, fres, echo (Maintained by thororen) +- StatusPresets by iamme - StatusWhilePlaying by thororen (Desktop app only) - SteamStatusSync by niko - StickerBlocker by Samwich diff --git a/src/equicordplugins/statusPresets/index.tsx b/src/equicordplugins/statusPresets/index.tsx new file mode 100644 index 00000000..61847609 --- /dev/null +++ b/src/equicordplugins/statusPresets/index.tsx @@ -0,0 +1,187 @@ +/* + * 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 } from "@api/Settings"; +import { getUserSettingLazy } from "@api/UserSettings"; +import ErrorBoundary from "@components/ErrorBoundary"; +import { EquicordDevs } from "@utils/constants"; +import { classes } from "@utils/misc"; +import { useForceUpdater } from "@utils/react"; +import definePlugin, { OptionType, StartAt } from "@utils/types"; +import { findByPropsLazy, findComponentByCodeLazy } from "@webpack"; +import { Button, Clickable, Icons, Menu, Toasts, UserStore, useState } from "@webpack/common"; + +const settings = definePluginSettings({ + StatusPresets: { + type: OptionType.COMPONENT, + description: "Status Presets", + component: () => <>, + default: {} + } +}); + +interface Emoji { + animated: boolean; + id: bigint | null; + name: string; +} + +interface DiscordStatus { + emojiInfo: Emoji | null; + text: string; + clearAfter: "TODAY" | number | null; + status: "online" | "dnd" | "idle" | "invisible"; +} + +const StatusStyles = findByPropsLazy("statusItem"); + +const PMenu = findComponentByCodeLazy(".menuItemLabel", ".menuItemInner"); +const EmojiComponent = findComponentByCodeLazy(".translateSurrogatesToInlineEmoji("); + +const CustomStatusSettings = getUserSettingLazy("status", "customStatus")!; + +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 = () => { + const update = useForceUpdater(); + return { }}> + {Object.entries((settings.store.StatusPresets as { [k: string]: DiscordStatus | undefined; })).map(([index, status]) => status != null ? (status.emojiInfo?.id != null && UserStore.getCurrentUser().hasPremiumPerks || 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: ".Messages.CUSTOM_STATUS_CLEAR_AFTER", + replacement: { + match: /\.ModalFooter,.{0,70}\.Messages\.SAVE\}\)/, + replace: "$&,$self.renderRememberButton(this.state)" + } + }, + { + find: ".Messages.STATUS_MENU_LABEL", + replacement: { + match: /!\i&&(.{0,15}\i\.Fragment.{0,55}null==(\i).{0,200}customEmojiPlaceholder\}\),onClick:([^}]+}))/, + replace: "$self.render($2, $3),false&&$1" + } + } + ], + render(status: null | { emoji: Emoji | null; }, openCustomStatusModal: () => void) { + 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 +}); diff --git a/src/equicordplugins/statusPresets/style.css b/src/equicordplugins/statusPresets/style.css new file mode 100644 index 00000000..41bfb38d --- /dev/null +++ b/src/equicordplugins/statusPresets/style.css @@ -0,0 +1,8 @@ +.vc-sp-disabled { + opacity: 0.5; +} + +.vc-sp-item:hover { + background-color: var(--menu-item-default-hover-bg) !important; + color: var(--white) !important; +} diff --git a/src/webpack/common/types/components.d.ts b/src/webpack/common/types/components.d.ts index 69bf635e..7d2a7580 100644 --- a/src/webpack/common/types/components.d.ts +++ b/src/webpack/common/types/components.d.ts @@ -478,7 +478,7 @@ export type Clickable = ComponentType): void; onKeyPress?(): void; }>>;