/* * Vencord, a Discord client mod * Copyright (c) 2024 Vendicated and contributors * SPDX-License-Identifier: GPL-3.0-or-later */ import { NavContextMenuPatchCallback } from "@api/ContextMenu"; import { definePluginSettings } from "@api/Settings"; import ErrorBoundary from "@components/ErrorBoundary"; import { Devs } from "@utils/constants"; import { classes } from "@utils/misc"; import definePlugin, { OptionType } from "@utils/types"; import { findByPropsLazy } from "@webpack"; import { Button, Menu, React, RelationshipStore, TooltipContainer, UserStore, } from "@webpack/common"; import { User } from "discord-types/general"; const { toggleLocalMute } = findByPropsLazy("toggleLocalMute"); const { isLocalMute } = findByPropsLazy("isLocalMute"); const RoleButtonClasses = findByPropsLazy("button", "buttonInner", "icon", "banner"); const enum MenuItemParentType { User, } const settings = definePluginSettings({ autoMuteBlocked: { type: OptionType.BOOLEAN, default: true, description: "Automatically mute blocked users.", restartNeeded: false } }); /** * Adds a "Mute and Block" or "Unmute and Unblock" item to user context menus. * * If the user is blocked, the action will unmute and unblock the user. Otherwise, * the action will mute and block the user. * * @param children The menu items to add the new item to. * @param props The props passed to the user context menu. * @returns The modified children with the new item added. */ const userContextPatch: NavContextMenuPatchCallback = (children, { user }: { user?: User, onClose(): void; }) => { if (!user) return; // Determine the label and action based on the user's blocked status const isBlocked = RelationshipStore.isBlocked(user.id); const lbl = isBlocked ? "Unmute and Unblock" : "Mute and Block"; /** * Handles the logic for toggling mute and block/unblock when the user * clicks the "Mute and Block" or "Unmute and Unblock" context menu item. * * If the user is currently blocked, the action will unmute and unblock. * Otherwise, the action will mute and block. * * @private */ const action = () => { // Toggle mute and handle block/unblock logic if (isBlocked) { // Logic to unblock the user if (isLocalMute(user.id)) { toggleLocalMute(user.id); // Unmute the user } } else { // Logic to block the user if (!isLocalMute(user.id)) { toggleLocalMute(user.id); // Mute the user } } }; children.push( ); }; export default definePlugin({ name: "MuteBlockedUsers", description: `(Voice)-Mute blocked users for easy recognition / transform a block to a "real" block.`, authors: [Devs.notvexi], settings, patches: [], contextMenus: { "user-context": userContextPatch, "user-profile-actions": userContextPatch, "user-profile-overflow-menu": userContextPatch }, /** * Attaches a listener to the RelationshipStore and runs the automatic muted user check once. * * The listener is needed to detect when a user is blocked and should be muted. * The initial function call is needed to mute users that are already blocked when the plugin is started. */ start() { RelationshipStore.addChangeListener(() => { this.automaticMuteBlockedUsers(); }); this.automaticMuteBlockedUsers(); }, /** * Mutes all blocked users and unmutes all unblocked users. * * This function is called whenever the RelationshipStore changes. * It is also called once when the plugin is started. * * @private */ automaticMuteBlockedUsers() { const { autoMuteBlocked } = settings.store; if (!autoMuteBlocked) return; // Get all relationships and filter for blocked users const blockedIds = Object.entries(RelationshipStore.getRelationships()) .filter(([_, v]) => v === 2) // 2 represents blocked .map(([k]) => UserStore.getUser(k).id); // Get user IDs of blocked users // Mute blocked users for (const ID of blockedIds) { if (!isLocalMute(ID)) { toggleLocalMute(ID); } } // Check for unblocked users const allUsers = UserStore.getUsers(); // Get all users as a Record const allUserIds = Object.keys(allUsers); for (const ID of allUserIds) { if (!RelationshipStore.isBlocked(ID)) { // Unmute the user if they are unblocked if (isLocalMute(ID)) { toggleLocalMute(ID); } } } }, BlockUnblockButton: ErrorBoundary.wrap(({ user }: { user: User; }) => { if (!user) return null; // Return null if no user is provided // Determine the button label based on the user's blocked status const isBlocked = RelationshipStore.isBlocked(user.id); const lbl = isBlocked ? "Unmute and Unblock" : "Mute and Block"; return ( ); }, { noop: true }) });