From e8242f22c998ffdc50fa9e663c40c3da4d7fc4d8 Mon Sep 17 00:00:00 2001 From: Nuckyz <61953774+Nuckyz@users.noreply.github.com> Date: Fri, 20 Sep 2024 09:06:26 -0300 Subject: [PATCH] UserVoiceShow: Better support for DM channels --- src/plugins/userVoiceShow/components.tsx | 63 +++++++++++++++++------- src/plugins/userVoiceShow/index.tsx | 6 +-- src/plugins/userVoiceShow/style.css | 15 +++++- 3 files changed, 62 insertions(+), 22 deletions(-) diff --git a/src/plugins/userVoiceShow/components.tsx b/src/plugins/userVoiceShow/components.tsx index 095785dd0..fad860dfa 100644 --- a/src/plugins/userVoiceShow/components.tsx +++ b/src/plugins/userVoiceShow/components.tsx @@ -7,15 +7,22 @@ import { classNameFactory } from "@api/Styles"; import ErrorBoundary from "@components/ErrorBoundary"; import { classes } from "@utils/misc"; -import { findByPropsLazy, findComponentByCodeLazy, findStoreLazy } from "@webpack"; -import { ChannelStore, GuildStore, IconUtils, NavigationRouter, PermissionsBits, PermissionStore, React, showToast, Text, Toasts, Tooltip, useMemo, UserStore, useStateFromStores } from "@webpack/common"; +import { filters, findByCodeLazy, findByPropsLazy, findComponentByCodeLazy, findStoreLazy, mapMangledModuleLazy } from "@webpack"; +import { ChannelStore, GuildStore, IconUtils, match, NavigationRouter, P, PermissionsBits, PermissionStore, React, showToast, Text, Toasts, Tooltip, useMemo, UserStore, useStateFromStores } from "@webpack/common"; import { Channel } from "discord-types/general"; const cl = classNameFactory("vc-uvs-"); -const { selectVoiceChannel } = findByPropsLazy("selectChannel", "selectVoiceChannel"); +const { selectVoiceChannel } = findByPropsLazy("selectVoiceChannel", "selectChannel"); +const { useChannelName } = mapMangledModuleLazy(".Messages.GROUP_DM_ALONE", { + useChannelName: filters.byCode("()=>null==") +}); +const getDMChannelIcon = findByCodeLazy(".getChannelIconURL({"); const VoiceStateStore = findStoreLazy("VoiceStateStore"); + const UserSummaryItem = findComponentByCodeLazy("defaultRenderUser", "showDefaultAvatarsForNullUsers"); +const Avatar = findComponentByCodeLazy(".AVATAR_STATUS_TYPING_16;"); +const GroupDMAvatars = findComponentByCodeLazy(".AvatarSizeSpecs[", "getAvatarURL"); interface IconProps extends React.ComponentPropsWithoutRef<"div"> { size?: number; @@ -28,7 +35,7 @@ function SpeakerIcon(props: IconProps) {
{ + return channel.recipients.length >= 2 && channel.icon == null + ? + : ; + }) + .otherwise(() => null); + const channelName = useChannelName(channel); + return ( <> {guild != null && ( -
+
{guildIcon != null && } {guild.name}
)} - {channel.name} +
+ {channelIcon} + {channelName} +
; -export const VoiceChannelIndicator = ErrorBoundary.wrap(({ userId }: VoiceChannelIndicatorProps) => { +export const VoiceChannelIndicator = ErrorBoundary.wrap(({ userId, size, isActionButton }: VoiceChannelIndicatorProps) => { const channelId = useStateFromStores([VoiceStateStore], () => VoiceStateStore.getVoiceStateForUser(userId)?.channelId as string | undefined); const channel = channelId == null ? undefined : ChannelStore.getChannel(channelId); if (channel == null) return null; + const isDM = channel.isDM() || channel.isMultiUserDM(); + const isLocked = !isDM && (!PermissionStore.can(PermissionsBits.VIEW_CHANNEL, channel) || !PermissionStore.can(PermissionsBits.CONNECT, channel)); + function onClick(e: React.MouseEvent) { e.preventDefault(); e.stopPropagation(); if (channel == null || channelId == null) return; - if (!PermissionStore.can(PermissionsBits.VIEW_CHANNEL, channel)) { + if (!isDM && !PermissionStore.can(PermissionsBits.VIEW_CHANNEL, channel)) { showToast("You cannot view the user's Voice Channel", Toasts.Type.FAILURE); return; } @@ -133,7 +157,7 @@ export const VoiceChannelIndicator = ErrorBoundary.wrap(({ userId }: VoiceChanne delete clickTimers[channelId]; if (e.detail > 1) { - if (!PermissionStore.can(PermissionsBits.CONNECT, channel)) { + if (!isDM && !PermissionStore.can(PermissionsBits.CONNECT, channel)) { showToast("You cannot join the user's Voice Channel", Toasts.Type.FAILURE); return; } @@ -147,19 +171,24 @@ export const VoiceChannelIndicator = ErrorBoundary.wrap(({ userId }: VoiceChanne } } - const isLocked = !PermissionStore.can(PermissionsBits.VIEW_CHANNEL, channel) || !PermissionStore.can(PermissionsBits.CONNECT, channel); - return ( } tooltipClassName={cl("tooltip-container")} tooltipContentClassName={cl("tooltip-content")} > - {props => - isLocked ? - - : - } + {props => { + const iconProps = { + ...props, + onClick, + size, + className: isActionButton ? cl("indicator-action-button") : cl("speaker-padding") + }; + + return isLocked ? + + : ; + }} ); }, { noop: true }); diff --git a/src/plugins/userVoiceShow/index.tsx b/src/plugins/userVoiceShow/index.tsx index 5efd936ce..573fd0e38 100644 --- a/src/plugins/userVoiceShow/index.tsx +++ b/src/plugins/userVoiceShow/index.tsx @@ -77,10 +77,10 @@ export default definePlugin({ }, */ // Friends List { - find: ".avatar,animate:", + find: "null!=this.peopleListItemRef.current", replacement: { - match: /\.subtext,children:.+?}\)\]}\)(?=])/, - replace: "$&,$self.VoiceChannelIndicator({userId:arguments[0]?.user?.id})" + match: /\.actions,children:\[/, + replace: "$&$self.VoiceChannelIndicator({userId:this?.props?.user?.id,size:20,isActionButton:true})," }, predicate: () => settings.store.showInMemberList } diff --git a/src/plugins/userVoiceShow/style.css b/src/plugins/userVoiceShow/style.css index 3e36df217..67f4c4958 100644 --- a/src/plugins/userVoiceShow/style.css +++ b/src/plugins/userVoiceShow/style.css @@ -1,6 +1,5 @@ .vc-uvs-speaker { color: var(--interactive-normal); - padding: 0 4px; display: flex; align-items: center; justify-content: center; @@ -14,6 +13,18 @@ color: var(--interactive-hover); } +.vc-uvs-speaker-padding { + padding: 0 4px; +} + +.vc-uvs-indicator-action-button { + background-color: var(--background-secondary); + border-radius: 100%; + height: 36px; + width: 36px; + margin-left: 10px; +} + .vc-uvs-tooltip-container { max-width: 300px; } @@ -24,7 +35,7 @@ gap: 6px; } -.vc-uvs-guild-name { +.vc-uvs-name { display: flex; align-items: center; gap: 8px;