/* * 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 { Settings } from "@api/settings"; import { Badge } from "@components/Badge"; import { Flex } from "@components/Flex"; import { Devs } from "@utils/constants"; import { ModalContent, ModalFooter, ModalHeader, ModalRoot, ModalSize, openModal } from "@utils/modal"; import definePlugin, { OptionType } from "@utils/types"; import { findByPropsLazy } from "@webpack"; import { Button, ChannelStore, moment, Parser, PermissionStore, SnowflakeUtils, Text, Timestamp, Tooltip } from "@webpack/common"; const ChannelListClasses = findByPropsLazy("channelName", "subtitle", "modeMuted", "iconContainer"); const VIEW_CHANNEL = 1024n; enum ChannelTypes { GUILD_TEXT = 0, GUILD_ANNOUNCEMENT = 5, GUILD_FORUM = 15 } const ChannelTypesToChannelName = { [ChannelTypes.GUILD_TEXT]: "TEXT", [ChannelTypes.GUILD_ANNOUNCEMENT]: "ANNOUNCEMENT", [ChannelTypes.GUILD_FORUM]: "FORUM" }; enum ShowMode { LockIcon, HiddenIconWithMutedStyle } export default definePlugin({ name: "ShowHiddenChannels", description: "Show channels that you do not have access to view.", authors: [Devs.BigDuck, Devs.AverageReactEnjoyer, Devs.D3SOX, Devs.Ven, Devs.Nuckyz, Devs.Nickyux], options: { hideUnreads: { description: "Hide Unreads", type: OptionType.BOOLEAN, default: true, restartNeeded: true }, showMode: { description: "The mode used to display hidden channels.", type: OptionType.SELECT, options: [ { label: "Plain style with Lock Icon instead", value: ShowMode.LockIcon, default: true }, { label: "Muted style with hidden eye icon on the right", value: ShowMode.HiddenIconWithMutedStyle }, ], restartNeeded: true } }, patches: [ { // RenderLevel defines if a channel is hidden, collapsed in category, visible, etc find: ".CannotShow", // These replacements only change the necessary CannotShow's replacement: [ { match: /(?renderLevel:(?\i\(this,\i\)\?\i\.Show:\i\.WouldShowIfUncollapsed).+?renderLevel:).+?,/, replace: "$$," }, { match: /(?activeJoinedRelevantThreads.{1,100}renderLevel:(?\i)\.Show.+?renderLevel:).+?,/, replace: "$$.Show," }, { match: /(?isChannelGatedAndVisible\(this\.record\.guild_id,this\.record\.id\).+?renderLevel:)(?\i)\.CannotShow/, replace: "$this.category.isCollapsed?$.WouldShowIfUncollapsed:$.Show" }, { match: /(?getRenderLevel=function.+?return).+?\?(?.+?):\i\.CannotShow}/, replace: "$ $}" } ] }, { // inside the onMouseClick handler, we check if the channel is hidden and open the modal if it is find: ".handleThreadsPopoutClose();", replacement: { match: /(?\i)\.handleThreadsPopoutClose\(\);/, replace: "if(arguments[0].button===0&&$self.channelSelected($?.props?.channel))return;$&" } }, { find: ".UNREAD_HIGHLIGHT", predicate: () => Settings.plugins.ShowHiddenChannels.hideUnreads === true, replacement: [{ // Hide unreads match: /(?\i\.connected,)(?\i)=(?\i).unread/, replace: "$$=$self.isHiddenChannel($.channel)?false:$.unread" }] }, { find: ".Messages.CHANNEL_TOOLTIP_DIRECTORY", predicate: () => Settings.plugins.ShowHiddenChannels.showMode === ShowMode.LockIcon, replacement: { // Lock Icon match: /switch\((?\i)\.type\).{1,30}\.GUILD_ANNOUNCEMENT.{1,30}\(0,\i\.\i\)\(\i\)/, replace: "if($self.isHiddenChannel($))return $self.LockIcon;$&" } }, { find: ".UNREAD_HIGHLIGHT", predicate: () => Settings.plugins.ShowHiddenChannels.showMode === ShowMode.HiddenIconWithMutedStyle, replacement: [ // Make the channel appear as muted if it's hidden { match: /(?\i\.name,)(?\i)=(?\i).muted/, replace: "$$=$self.isHiddenChannel($.channel)?true:$.muted" }, // Add the hidden eye icon if the channel is hidden { match: /channel:(?\i),.+?\.channelName.+?\.children.+?:null/, replace: "$&,$self.isHiddenChannel($)?$self.HiddenChannelIcon():null" }, // Make voice channels also appear as muted if they are muted { match: /(?.wrapper:\i\(\).notInteractive,)(?.+?)(?(?\i)\?\i\.MUTED:)/, replace: "$$\"\",$$?\"\":" } ] }, { // Hide New unreads box for hidden channels find: '.displayName="ChannelListUnreadsStore"', replacement: { match: /(?return null!=(?\i))(?&&null!=\i\.getGuildId\(\).{1,120}hasRelevantUnread\(\i\)\))/, replace: "$&&!$self.isHiddenChannel($)$" } }, ], isHiddenChannel(channel) { if (!channel) return false; if (channel.channelId) channel = ChannelStore.getChannel(channel.channelId); if (!channel || channel.isDM() || channel.isGroupDM() || channel.isMultiUserDM()) return false; return !PermissionStore.can(VIEW_CHANNEL, channel); }, channelSelected(channel) { if (!channel) return false; const isHidden = this.isHiddenChannel(channel); // Check for type, otherwise it would attempt to show the modal for stage channels if ([ChannelTypes.GUILD_TEXT, ChannelTypes.GUILD_ANNOUNCEMENT, ChannelTypes.GUILD_FORUM].includes(channel.type) && isHidden) { openModal(modalProps => ( #{channel.name} {} {channel.isNSFW() && } You don't have permission to view {channel.type === ChannelTypes.GUILD_FORUM ? "posts" : "messages"} in this channel. {(channel.topic ?? "").length > 0 && ( <> {channel.type === ChannelTypes.GUILD_FORUM ? "Guidelines:" : "Topic:"}
{Parser.parseTopic(channel.topic, true, { channelId: channel.id })}
)} {channel.lastMessageId && ( <> {channel.type === ChannelTypes.GUILD_FORUM ? "Last Post Created" : "Last Message Sent:"}
)}
)); } return isHidden; }, LockIcon: () => ( ), HiddenChannelIcon: () => ( {({ onMouseLeave, onMouseEnter }) => ( )} ) });