aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNuckyz <61953774+Nuckyz@users.noreply.github.com>2023-01-23 18:04:50 -0300
committerGitHub <noreply@github.com>2023-01-23 22:04:50 +0100
commit75050e74ca01856f9b48867d7945e2b7263b42ae (patch)
treef2e72a2fc9b006f8e33ef75261651d22cfa4f6b7
parent8a43e9b25f97cda19a5dc85020152020873c6a8e (diff)
downloadVencord-75050e74ca01856f9b48867d7945e2b7263b42ae.tar.gz
Vencord-75050e74ca01856f9b48867d7945e2b7263b42ae.tar.bz2
Vencord-75050e74ca01856f9b48867d7945e2b7263b42ae.zip
ShowHiddenChannels: better ui, alternative display mode (#446)
Co-authored-by: Ven <vendicated@riseup.net>
-rw-r--r--src/plugins/messageLogger/index.tsx23
-rw-r--r--src/plugins/showHiddenChannels.tsx197
-rw-r--r--src/webpack/common.tsx4
3 files changed, 141 insertions, 83 deletions
diff --git a/src/plugins/messageLogger/index.tsx b/src/plugins/messageLogger/index.tsx
index 50a6f52..8c7fa11 100644
--- a/src/plugins/messageLogger/index.tsx
+++ b/src/plugins/messageLogger/index.tsx
@@ -23,8 +23,7 @@ import ErrorBoundary from "@components/ErrorBoundary";
import { Devs } from "@utils/constants";
import Logger from "@utils/Logger";
import definePlugin, { OptionType } from "@utils/types";
-import { findByPropsLazy } from "@webpack";
-import { Parser, UserStore } from "@webpack/common";
+import { moment, Parser, Timestamp, UserStore } from "@webpack/common";
function addDeleteStyleClass() {
if (Settings.plugins.MessageLogger.deleteStyle === "text") {
@@ -41,13 +40,7 @@ export default definePlugin({
description: "Temporarily logs deleted and edited messages.",
authors: [Devs.rushii, Devs.Ven],
- timestampModule: null as any,
- moment: null as Function | null,
-
start() {
- this.moment = findByPropsLazy("relativeTimeRounding", "relativeTimeThreshold");
- this.timestampModule = findByPropsLazy("messageLogger_TimestampComponent");
-
addDeleteStyleClass();
},
@@ -59,7 +52,6 @@ export default definePlugin({
},
renderEdit(edit: { timestamp: any, content: string; }) {
- const Timestamp = this.timestampModule.messageLogger_TimestampComponent;
return (
<ErrorBoundary noop>
<div className="messageLogger-edited">
@@ -78,7 +70,7 @@ export default definePlugin({
makeEdit(newMessage: any, oldMessage: any): any {
return {
- timestamp: this.moment?.call(newMessage.edited_timestamp),
+ timestamp: moment?.call(newMessage.edited_timestamp),
content: oldMessage.content
};
},
@@ -313,17 +305,6 @@ export default definePlugin({
},
{
- // Message "(edited)" timestamp component
- // Module 23552
- find: "Messages.MESSAGE_EDITED_TIMESTAMP_A11Y_LABEL.format",
- replacement: {
- // Re-export the timestamp component under a findable name
- match: /{(\w{1,2}:\(\)=>(\w{1,2}))}/,
- replace: "{$1,messageLogger_TimestampComponent:()=>$2}"
- }
- },
-
- {
// Message context base menu
// Module 600300
find: "id:\"remove-reactions\"",
diff --git a/src/plugins/showHiddenChannels.tsx b/src/plugins/showHiddenChannels.tsx
index a97259a..1225cf1 100644
--- a/src/plugins/showHiddenChannels.tsx
+++ b/src/plugins/showHiddenChannels.tsx
@@ -23,125 +23,177 @@ 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 { Button, ChannelStore, PermissionStore, SnowflakeUtils, Text } from "@webpack/common";
+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 CONNECT = 1048576n;
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 hidden channels",
- authors: [Devs.BigDuck, Devs.AverageReactEnjoyer, Devs.D3SOX, Devs.Ven],
+ 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",
+ description: "Hide Unreads",
type: OptionType.BOOLEAN,
default: true,
- restartNeeded: true // Restart is needed to refresh channel list
+ 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",
- replacement: {
- match: /renderLevel:(\w+)\.CannotShow/g,
- replace: "renderLevel:Vencord.Plugins.plugins.ShowHiddenChannels.shouldShow(this.record, this.category, this.isMuted)?$1.Show:$1.CannotShow"
- }
+ // These replacements only change the necessary CannotShow's
+ replacement: [
+ {
+ match: /(?<restOfFunction>renderLevel:(?<renderLevelExpression>\i\(this,\i\)\?\i\.Show:\i\.WouldShowIfUncollapsed).+?renderLevel:).+?,/,
+ replace: "$<restOfFunction>$<renderLevelExpression>,"
+ },
+ {
+ match: /(?<restOfFunction>activeJoinedRelevantThreads.{1,100}renderLevel:(?<RenderLevels>\i)\.Show.+?renderLevel:).+?,/,
+ replace: "$<restOfFunction>$<RenderLevels>.Show,"
+ },
+ {
+ match: /(?<restOfFunction>isChannelGatedAndVisible\(this\.record\.guild_id,this\.record\.id\).+?renderLevel:)(?<RenderLevels>\i)\.CannotShow/,
+ replace: "$<restOfFunction>this.category.isCollapsed?$<RenderLevels>.WouldShowIfUncollapsed:$<RenderLevels>.Show"
+ },
+ {
+ match: /(?<restOfFunction>getRenderLevel=function.+?return).+?\?(?<renderLevelExpression>.+?):\i\.CannotShow}/,
+ replace: "$<restOfFunction> $<renderLevelExpression>}"
+ }
+ ]
},
{
// inside the onMouseClick handler, we check if the channel is hidden and open the modal if it is
find: ".handleThreadsPopoutClose();",
replacement: {
- match: /((\w)\.handleThreadsPopoutClose\(\);)/g,
- replace: "if(arguments[0].button===0&&Vencord.Plugins.plugins.ShowHiddenChannels.channelSelected($2?.props?.channel))return;$1"
+ match: /(?<this>\i)\.handleThreadsPopoutClose\(\);/,
+ replace: "if(arguments[0].button===0&&$self.channelSelected($<this>?.props?.channel))return;$&"
}
},
{
- // Prevent categories from disappearing when they're collapsed
- find: ".prototype.shouldShowEmptyCategory=function(){",
- replacement: {
- match: /(\.prototype\.shouldShowEmptyCategory=function\(\){)/g,
- replace: "$1return true;"
- }
+ find: ".UNREAD_HIGHLIGHT",
+ predicate: () => Settings.plugins.ShowHiddenChannels.hideUnreads === true,
+ replacement: [{
+ // Hide unreads
+ match: /(?<restOfFunction>\i\.connected,)(?<hasUnread>\i)=(?<props>\i).unread/,
+ replace: "$<restOfFunction>$<hasUnread>=$self.isHiddenChannel($<props>.channel)?false:$<props>.unread"
+ }]
},
{
- // Hide unreads
- find: "?\"button\":\"link\"",
- predicate: () => Settings.plugins.ShowHiddenChannels.hideUnreads === true,
+ find: ".Messages.CHANNEL_TOOLTIP_DIRECTORY",
+ predicate: () => Settings.plugins.ShowHiddenChannels.showMode === ShowMode.LockIcon,
replacement: {
- match: /(\w)\.connected,(\w)=(\w\.unread),(\w=\w\.canHaveDot)/g,
- replace: "$1.connected,$2=Vencord.Plugins.plugins.ShowHiddenChannels.isHiddenChannel($1.channel)?false:$3,$4"
+ // Lock Icon
+ match: /switch\((?<channel>\i)\.type\).{1,30}\.GUILD_ANNOUNCEMENT.{1,30}\(0,\i\.\i\)\(\i\)/,
+ replace: "if($self.isHiddenChannel($<channel>))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: /(?<restOfFunction>\i\.name,)(?<isMuted>\i)=(?<props>\i).muted/,
+ replace: "$<restOfFunction>$<isMuted>=$self.isHiddenChannel($<props>.channel)?true:$<props>.muted"
+ },
+ // Add the hidden eye icon if the channel is hidden
+ {
+ match: /channel:(?<channel>\i),.+?\.channelName.+?\.children.+?:null/,
+ replace: "$&,$self.isHiddenChannel($<channel>)?$self.HiddenChannelIcon():null"
+ },
+ // Make voice channels also appear as muted if they are muted
+ {
+ match: /(?<restOfFunction>.wrapper:\i\(\).notInteractive,)(?<secondRestOfFunction>.+?)(?<isMutedClassExpression>(?<isMuted>\i)\?\i\.MUTED:)/,
+ replace: "$<restOfFunction>$<isMutedClassExpression>\"\",$<secondRestOfFunction>$<isMuted>?\"\":"
+ }
+ ]
+ },
+ {
// Hide New unreads box for hidden channels
find: '.displayName="ChannelListUnreadsStore"',
replacement: {
- match: /((.)\.getGuildId\(\))(&&\(!\(.\.isThread.{1,100}\.hasRelevantUnread\()/,
- replace: "$1&&!$2._isHiddenChannel$3"
+ match: /(?<restOfFunction>return null!=(?<channel>\i))(?<secondRestOfFunction>&&null!=\i\.getGuildId\(\).{1,120}hasRelevantUnread\(\i\)\))/,
+ replace: "$<restOfFunction>&&!$self.isHiddenChannel($<channel>)$<secondRestOfFunction>"
}
},
- // Lock Icon
- {
- find: ".rulesChannelId))",
- replacement: {
- match: /(\.locked.{0,400})(switch\((\i)\.type\))/,
- replace: "$1 if($3._isHiddenChannel)return $self.LockIcon;$2"
- }
- }
],
- shouldShow(channel, category, isMuted) {
- if (!this.isHiddenChannel(channel)) return false;
- if (!category) return false;
- if (channel.type === 0 && category.guild?.hideMutedChannels && isMuted) return false;
-
- return !category.isCollapsed;
- },
-
isHiddenChannel(channel) {
if (!channel) return false;
- if (channel.channelId)
- channel = ChannelStore.getChannel(channel.channelId);
- if (!channel || channel.isDM() || channel.isGroupDM() || channel.isMultiUserDM())
- return false;
-
- // check for disallowed voice channels too so that they get hidden when collapsing the category
- channel._isHiddenChannel = !PermissionStore.can(VIEW_CHANNEL, channel) || (channel.type === 2 && !PermissionStore.can(CONNECT, channel));
- return channel._isHiddenChannel;
+
+ 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 again, otherwise it would show it for hidden stage channels
- if (channel.type === 0 && isHidden) {
- const lastMessageDate = channel.lastMessageId ? new Date(SnowflakeUtils.extractTimestamp(channel.lastMessageId)).toLocaleString() : null;
+
+ // 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 => (
<ModalRoot size={ModalSize.SMALL} {...modalProps}>
<ModalHeader>
<Flex>
- <Text variant="heading-md/bold">{channel.name}</Text>
+ <Text variant="heading-md/bold">#{channel.name}</Text>
+ {<Badge text={ChannelTypesToChannelName[channel.type]} color="var(--brand-experiment)" />}
{channel.isNSFW() && <Badge text="NSFW" color="var(--status-danger)" />}
</Flex>
</ModalHeader>
<ModalContent style={{ marginBottom: 10, marginTop: 10, marginRight: 8, marginLeft: 8 }}>
- <Text variant="text-md/normal">You don't have the permission to view the messages in this channel.</Text>
- {(channel.topic || "").length > 0 && (
+ <Text variant="text-md/normal">You don't have permission to view {channel.type === ChannelTypes.GUILD_FORUM ? "posts" : "messages"} in this channel.</Text>
+ {(channel.topic ?? "").length > 0 && (
<>
<Text variant="text-md/bold" style={{ marginTop: 10 }}>
- Topic:
+ {channel.type === ChannelTypes.GUILD_FORUM ? "Guidelines:" : "Topic:"}
</Text>
- <Text variant="code">{channel.topic}</Text>
+ <div style={{ color: "var(--text-normal)", marginTop: 10 }}>
+ {Parser.parseTopic(channel.topic, true, { channelId: channel.id })}
+ </div>
</>
)}
- {lastMessageDate && (
+ {channel.lastMessageId && (
<>
<Text variant="text-md/bold" style={{ marginTop: 10 }}>
- Last message sent:
+ {channel.type === ChannelTypes.GUILD_FORUM ? "Last Post Created" : "Last Message Sent:"}
</Text>
- <Text variant="code">{lastMessageDate}</Text>
+ <div style={{ color: "var(--text-normal)", marginTop: 10 }}>
+ <Timestamp timestamp={moment(SnowflakeUtils.extractTimestamp(channel.lastMessageId))} />
+ </div>
</>
)}
</ModalContent>
@@ -164,11 +216,34 @@ export default definePlugin({
LockIcon: () => (
<svg
+ className={ChannelListClasses.icon}
height="18"
width="20"
viewBox="0 0 24 24"
+ aria-hidden={true}
+ role="img"
>
- <path fill="var(--channel-icon)" d="M17 11V7C17 4.243 14.756 2 12 2C9.242 2 7 4.243 7 7V11C5.897 11 5 11.896 5 13V20C5 21.103 5.897 22 7 22H17C18.103 22 19 21.103 19 20V13C19 11.896 18.103 11 17 11ZM12 18C11.172 18 10.5 17.328 10.5 16.5C10.5 15.672 11.172 15 12 15C12.828 15 13.5 15.672 13.5 16.5C13.5 17.328 12.828 18 12 18ZM15 11H9V7C9 5.346 10.346 4 12 4C13.654 4 15 5.346 15 7V11Z" />
+ <path fillRule="evenodd" fill="currentColor" d="M17 11V7C17 4.243 14.756 2 12 2C9.242 2 7 4.243 7 7V11C5.897 11 5 11.896 5 13V20C5 21.103 5.897 22 7 22H17C18.103 22 19 21.103 19 20V13C19 11.896 18.103 11 17 11ZM12 18C11.172 18 10.5 17.328 10.5 16.5C10.5 15.672 11.172 15 12 15C12.828 15 13.5 15.672 13.5 16.5C13.5 17.328 12.828 18 12 18ZM15 11H9V7C9 5.346 10.346 4 12 4C13.654 4 15 5.346 15 7V11Z" />
</svg>
+ ),
+
+ HiddenChannelIcon: () => (
+ <Tooltip text="Hidden Channel">
+ {({ onMouseLeave, onMouseEnter }) => (
+ <svg
+ onMouseLeave={onMouseLeave}
+ onMouseEnter={onMouseEnter}
+ className={ChannelListClasses.icon}
+ width="24"
+ height="24"
+ viewBox="0 0 24 24"
+ aria-hidden={true}
+ role="img"
+ style={{ marginLeft: 6, zIndex: 0, cursor: "not-allowed" }}
+ >
+ <path fillRule="evenodd" fill="currentColor" d="m19.8 22.6-4.2-4.15q-.875.275-1.762.413Q12.95 19 12 19q-3.775 0-6.725-2.087Q2.325 14.825 1 11.5q.525-1.325 1.325-2.463Q3.125 7.9 4.15 7L1.4 4.2l1.4-1.4 18.4 18.4ZM12 16q.275 0 .512-.025.238-.025.513-.1l-5.4-5.4q-.075.275-.1.513-.025.237-.025.512 0 1.875 1.312 3.188Q10.125 16 12 16Zm7.3.45-3.175-3.15q.175-.425.275-.862.1-.438.1-.938 0-1.875-1.312-3.188Q13.875 7 12 7q-.5 0-.938.1-.437.1-.862.3L7.65 4.85q1.025-.425 2.1-.638Q10.825 4 12 4q3.775 0 6.725 2.087Q21.675 8.175 23 11.5q-.575 1.475-1.512 2.738Q20.55 15.5 19.3 16.45Zm-4.625-4.6-3-3q.7-.125 1.288.112.587.238 1.012.688.425.45.613 1.038.187.587.087 1.162Z" />
+ </svg>
+ )}
+ </Tooltip>
)
});
diff --git a/src/webpack/common.tsx b/src/webpack/common.tsx
index 0be47ff..562332a 100644
--- a/src/webpack/common.tsx
+++ b/src/webpack/common.tsx
@@ -75,6 +75,7 @@ export let Button: any;
export const ButtonLooks = findByPropsLazy("BLANK", "FILLED", "INVERTED") as Record<"FILLED" | "INVERTED" | "OUTLINED" | "LINK" | "BLANK", string>;
export let Switch: any;
export let Tooltip: Components.Tooltip;
+export let Timestamp: any;
export let Router: any;
export let TextInput: any;
export let Text: (props: TextProps) => JSX.Element;
@@ -185,6 +186,8 @@ waitFor(["Hovers", "Looks", "Sizes"], m => Button = m);
waitFor(filters.byCode("tooltipNote", "ringTarget"), m => Switch = m);
+waitFor(filters.byCode(".Messages.MESSAGE_EDITED_TIMESTAMP_A11Y_LABEL.format"), m => Timestamp = m);
+
waitFor(["Positions", "Colors"], m => Tooltip = m);
waitFor(m => m.Types?.PRIMARY === "cardPrimary", m => Card = m);
@@ -307,4 +310,3 @@ export const ContextMenu = mapMangledModuleLazy('type:"CONTEXT_MENU_OPEN"', {
export const MaskedLinkStore = mapMangledModuleLazy('"MaskedLinkStore"', {
openUntrustedLink: filters.byCode(".apply(this,arguments)")
});
-