Equicord/src/equicordplugins/bypassStatus/index.tsx
thororen1234 f8879cc801 Merge remote-tracking branch 'upstream/dev' into dev
# Conflicts:
#	eslint.config.mjs
#	package.json
#	pnpm-lock.yaml
#	src/components/PluginSettings/index.tsx
#	src/plugins/imageZoom/index.tsx
#	src/plugins/messageLogger/index.tsx
#	src/plugins/pictureInPicture/index.tsx
#	src/plugins/serverInfo/GuildInfoModal.tsx
#	src/plugins/whoReacted/index.tsx
2025-01-04 17:57:05 -05:00

183 lines
7.4 KiB
TypeScript

/*
* Vencord, a Discord client mod
* Copyright (c) 2024 Vendicated and contributors
* SPDX-License-Identifier: GPL-3.0-or-later
*/
import { type NavContextMenuPatchCallback } from "@api/ContextMenu";
import { Notifications } from "@api/index";
import { definePluginSettings, migratePluginSettings } from "@api/Settings";
import { Devs } from "@utils/constants";
import { getCurrentChannel } from "@utils/discord";
import { Logger } from "@utils/Logger";
import definePlugin, { OptionType } from "@utils/types";
import { ChannelStore, Menu, MessageStore, NavigationRouter, PresenceStore, PrivateChannelsStore, UserStore, WindowStore } from "@webpack/common";
import type { Message } from "discord-types/general";
import { JSX } from "react";
interface IMessageCreate {
channelId: string;
guildId: string;
message: Message;
}
function Icon(enabled?: boolean): JSX.Element {
return <svg
width="18"
height="18"
>
<circle cx="9" cy="9" r="8" fill={!enabled ? "var(--status-danger)" : "currentColor"} />
<circle cx="9" cy="9" r="3.75" fill={!enabled ? "white" : "black"} />
</svg>;
}
function processIds(value: string): string {
return value.replace(/\s/g, "").split(",").filter(id => id.trim() !== "").join(", ");
}
async function showNotification(message: Message, guildId: string | undefined): Promise<void> {
try {
const channel = ChannelStore.getChannel(message.channel_id);
const channelRegex = /<#(\d{19})>/g;
const userRegex = /<@(\d{18})>/g;
message.content = message.content.replace(channelRegex, (match: any, channelId: string) => {
return `#${ChannelStore.getChannel(channelId)?.name}`;
});
message.content = message.content.replace(userRegex, (match: any, userId: string) => {
return `@${(UserStore.getUser(userId) as any).globalName}`;
});
await Notifications.showNotification({
title: `${(message.author as any).globalName} ${guildId ? `(#${channel?.name}, ${ChannelStore.getChannel(channel?.parent_id)?.name})` : ""}`,
body: message.content,
icon: UserStore.getUser(message.author.id).getAvatarURL(undefined, undefined, false),
onClick: function (): void {
NavigationRouter.transitionTo(`/channels/${guildId ?? "@me"}/${message.channel_id}/${message.id}`);
}
});
if (settings.store.notificationSound) {
new Audio("https://discord.com/assets/9422aef94aa931248105.mp3").play();
}
} catch (error) {
new Logger("BypassStatus").error("Failed to notify user: ", error);
}
}
function ContextCallback(name: "guild" | "user" | "channel"): NavContextMenuPatchCallback {
return (children, props) => {
const type = props[name];
if (!type) return;
const enabled = settings.store[`${name}s`].split(", ").includes(type.id);
if (name === "user" && type.id === UserStore.getCurrentUser().id) return;
children.splice(-1, 0, (
<Menu.MenuGroup>
<Menu.MenuItem
id={`status-${name}-bypass`}
label={`${enabled ? "Remove" : "Add"} Status Bypass`}
icon={() => Icon(enabled)}
action={() => {
let bypasses: string[] = settings.store[`${name}s`].split(", ");
if (enabled) bypasses = bypasses.filter(id => id !== type.id);
else bypasses.push(type.id);
settings.store[`${name}s`] = bypasses.filter(id => id.trim() !== "").join(", ");
}}
/>
</Menu.MenuGroup>
));
};
}
const settings = definePluginSettings({
guilds: {
type: OptionType.STRING,
description: "Guilds to let bypass (notified when pinged anywhere in guild)",
default: "",
placeholder: "Separate with commas",
onChange: value => settings.store.guilds = processIds(value)
},
channels: {
type: OptionType.STRING,
description: "Channels to let bypass (notified when pinged in that channel)",
default: "",
placeholder: "Separate with commas",
onChange: value => settings.store.channels = processIds(value)
},
users: {
type: OptionType.STRING,
description: "Users to let bypass (notified for all messages sent in DMs)",
default: "",
placeholder: "Separate with commas",
onChange: value => settings.store.users = processIds(value)
},
allowOutsideOfDms: {
type: OptionType.BOOLEAN,
description: "Allow selected users to bypass status outside of DMs too (acts like a channel/guild bypass, but it's for all messages sent by the selected users)"
},
notificationSound: {
type: OptionType.BOOLEAN,
description: "Whether the notification sound should be played",
default: true,
},
statusToUse: {
type: OptionType.SELECT,
description: "Status to use for whitelist",
options: [
{
label: "Online",
value: "online",
},
{
label: "Idle",
value: "idle",
},
{
label: "Do Not Disturb",
value: "dnd",
default: true
},
{
label: "Invisible",
value: "invisible",
}
]
}
});
migratePluginSettings("BypassStatus", "BypassDND");
export default definePlugin({
name: "BypassStatus",
description: "Still get notifications from specific sources when in do not disturb mode. Right-click on users/channels/guilds to set them to bypass do not disturb mode.",
authors: [Devs.Inbestigator],
flux: {
async MESSAGE_CREATE({ message, guildId, channelId }: IMessageCreate): Promise<void> {
try {
const currentUser = UserStore.getCurrentUser();
const userStatus = await PresenceStore.getStatus(currentUser.id);
const currentChannelId = getCurrentChannel()?.id ?? "0";
if (message.state === "SENDING" || message.content === "" || message.author.id === currentUser.id || (channelId === currentChannelId && WindowStore.isFocused()) || userStatus !== settings.store.statusToUse) {
return;
}
const mentioned = MessageStore.getMessage(channelId, message.id)?.mentioned;
if ((settings.store.guilds.split(", ").includes(guildId) || settings.store.channels.split(", ").includes(channelId)) && mentioned) {
await showNotification(message, guildId);
} else if (settings.store.users.split(", ").includes(message.author.id)) {
const userChannelId = await PrivateChannelsStore.getOrEnsurePrivateChannel(message.author.id);
if (channelId === userChannelId || (mentioned && settings.store.allowOutsideOfDms === true)) {
await showNotification(message, guildId);
}
}
} catch (error) {
new Logger("BypassStatus").error("Failed to handle message: ", error);
}
}
},
settings,
contextMenus: {
"guild-context": ContextCallback("guild"),
"channel-context": ContextCallback("channel"),
"user-context": ContextCallback("user"),
}
});