/* * 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 ErrorBoundary from "@components/ErrorBoundary"; import { LazyComponent } from "@utils/react"; import { formatDuration } from "@utils/text"; import { find, findByPropsLazy } from "@webpack"; import { EmojiStore, FluxDispatcher, GuildMemberStore, GuildStore, moment, Parser, PermissionStore, SnowflakeUtils, Text, Timestamp, Tooltip, useEffect, useState } from "@webpack/common"; import type { Channel } from "discord-types/general"; import type { ComponentType } from "react"; import openRolesAndUsersPermissionsModal, { PermissionType, RoleOrUserPermission } from "../../permissionsViewer/components/RolesAndUsersPermissions"; import { sortPermissionOverwrites } from "../../permissionsViewer/utils"; import { settings, VIEW_CHANNEL } from ".."; const enum SortOrderTypes { LATEST_ACTIVITY = 0, CREATION_DATE = 1 } const enum ForumLayoutTypes { DEFAULT = 0, LIST = 1, GRID = 2 } interface DefaultReaction { emojiId: string | null; emojiName: string | null; } interface Tag { id: string; name: string; emojiId: string | null; emojiName: string | null; moderated: boolean; } interface ExtendedChannel extends Channel { defaultThreadRateLimitPerUser?: number; defaultSortOrder?: SortOrderTypes | null; defaultForumLayout?: ForumLayoutTypes; defaultReactionEmoji?: DefaultReaction | null; availableTags?: Array; } const enum ChannelTypes { GUILD_TEXT = 0, GUILD_VOICE = 2, GUILD_ANNOUNCEMENT = 5, GUILD_STAGE_VOICE = 13, GUILD_FORUM = 15 } const enum VideoQualityModes { AUTO = 1, FULL = 2 } const enum ChannelFlags { PINNED = 1 << 1, REQUIRE_TAG = 1 << 4 } let ChannelBeginHeader: ComponentType; export function setChannelBeginHeaderComponent(component: ComponentType) { ChannelBeginHeader = component; } const ChatScrollClasses = findByPropsLazy("auto", "content", "scrollerBase"); const ChatClasses = findByPropsLazy("chat", "content", "noChat", "chatContent"); const TagComponent = LazyComponent(() => find(m => { if (typeof m !== "function") return false; const code = Function.prototype.toString.call(m); // Get the component which doesn't include increasedActivity logic return code.includes(".Messages.FORUM_TAG_A11Y_FILTER_BY_TAG") && !code.includes("increasedActivityPill"); })); const EmojiParser = findByPropsLazy("convertSurrogateToName"); const EmojiUtils = findByPropsLazy("getURL", "buildEmojiReactionColorsPlatformed"); const ChannelTypesToChannelNames = { [ChannelTypes.GUILD_TEXT]: "text", [ChannelTypes.GUILD_ANNOUNCEMENT]: "announcement", [ChannelTypes.GUILD_FORUM]: "forum", [ChannelTypes.GUILD_VOICE]: "voice", [ChannelTypes.GUILD_STAGE_VOICE]: "stage" }; const SortOrderTypesToNames = { [SortOrderTypes.LATEST_ACTIVITY]: "Latest activity", [SortOrderTypes.CREATION_DATE]: "Creation date" }; const ForumLayoutTypesToNames = { [ForumLayoutTypes.DEFAULT]: "Not set", [ForumLayoutTypes.LIST]: "List view", [ForumLayoutTypes.GRID]: "Gallery view" }; const VideoQualityModesToNames = { [VideoQualityModes.AUTO]: "Automatic", [VideoQualityModes.FULL]: "720p" }; // Icon from the modal when clicking a message link you don't have access to view const HiddenChannelLogo = "/assets/433e3ec4319a9d11b0cbe39342614982.svg"; function HiddenChannelLockScreen({ channel }: { channel: ExtendedChannel; }) { const [viewAllowedUsersAndRoles, setViewAllowedUsersAndRoles] = useState(settings.store.defaultAllowedUsersAndRolesDropdownState); const [permissions, setPermissions] = useState([]); const { type, topic, lastMessageId, defaultForumLayout, lastPinTimestamp, defaultAutoArchiveDuration, availableTags, id: channelId, rateLimitPerUser, defaultThreadRateLimitPerUser, defaultSortOrder, defaultReactionEmoji, bitrate, rtcRegion, videoQualityMode, permissionOverwrites, guild_id } = channel; useEffect(() => { const membersToFetch: Array = []; const guildOwnerId = GuildStore.getGuild(guild_id).ownerId; if (!GuildMemberStore.getMember(guild_id, guildOwnerId)) membersToFetch.push(guildOwnerId); Object.values(permissionOverwrites).forEach(({ type, id: userId }) => { if (type === 1 && !GuildMemberStore.getMember(guild_id, userId)) { membersToFetch.push(userId); } }); if (membersToFetch.length > 0) { FluxDispatcher.dispatch({ type: "GUILD_MEMBERS_REQUEST", guildIds: [guild_id], userIds: membersToFetch }); } if (Settings.plugins.PermissionsViewer.enabled) { setPermissions(sortPermissionOverwrites(Object.values(permissionOverwrites).map(overwrite => ({ type: overwrite.type as PermissionType, id: overwrite.id, overwriteAllow: overwrite.allow, overwriteDeny: overwrite.deny })), guild_id)); } }, [channelId]); return (
This is a {!PermissionStore.can(VIEW_CHANNEL, channel) ? "hidden" : "locked"} {ChannelTypesToChannelNames[type]} channel. {channel.isNSFW() && {({ onMouseLeave, onMouseEnter }) => ( )} }
{(!channel.isGuildVoice() && !channel.isGuildStageVoice()) && ( You can not see the {channel.isForumChannel() ? "posts" : "messages"} of this channel. {channel.isForumChannel() && topic && topic.length > 0 && " However you may see its guidelines:"} )} {channel.isForumChannel() && topic && topic.length > 0 && (
{Parser.parseTopic(topic, false, { channelId })}
)} {lastMessageId && Last {channel.isForumChannel() ? "post" : "message"} created: } {lastPinTimestamp && Last message pin: } {(rateLimitPerUser ?? 0) > 0 && Slowmode: {formatDuration(rateLimitPerUser!, "seconds")} } {(defaultThreadRateLimitPerUser ?? 0) > 0 && Default thread slowmode: {formatDuration(defaultThreadRateLimitPerUser!, "seconds")} } {((channel.isGuildVoice() || channel.isGuildStageVoice()) && bitrate != null) && Bitrate: {bitrate} bits } {rtcRegion !== undefined && Region: {rtcRegion ?? "Automatic"} } {(channel.isGuildVoice() || channel.isGuildStageVoice()) && Video quality mode: {VideoQualityModesToNames[videoQualityMode ?? VideoQualityModes.AUTO]} } {(defaultAutoArchiveDuration ?? 0) > 0 && Default inactivity duration before archiving {channel.isForumChannel() ? "posts" : "threads"}: {" " + formatDuration(defaultAutoArchiveDuration!, "minutes")} } {defaultForumLayout != null && Default layout: {ForumLayoutTypesToNames[defaultForumLayout]} } {defaultSortOrder != null && Default sort order: {SortOrderTypesToNames[defaultSortOrder]} } {defaultReactionEmoji != null &&
Default reaction emoji: {Parser.defaultRules[defaultReactionEmoji.emojiName ? "emoji" : "customEmoji"].react({ name: defaultReactionEmoji.emojiName ? EmojiParser.convertSurrogateToName(defaultReactionEmoji.emojiName) : EmojiStore.getCustomEmojiById(defaultReactionEmoji.emojiId)?.name ?? "", emojiId: defaultReactionEmoji.emojiId ?? void 0, surrogate: defaultReactionEmoji.emojiName ?? void 0, src: defaultReactionEmoji.emojiName ? EmojiUtils.getURL(defaultReactionEmoji.emojiName) : void 0 }, void 0, { key: "0" })}
} {channel.hasFlag(ChannelFlags.REQUIRE_TAG) && Posts on this forum require a tag to be set. } {availableTags && availableTags.length > 0 &&
Available tags:
{availableTags.map(tag => )}
}
{Settings.plugins.PermissionsViewer.enabled && ( {({ onMouseLeave, onMouseEnter }) => ( )} )} Allowed users and roles: {({ onMouseLeave, onMouseEnter }) => ( )}
{viewAllowedUsersAndRoles && }
); } export default ErrorBoundary.wrap(HiddenChannelLockScreen);