/*
* Vencord, a Discord client mod
* Copyright (c) 2024 Vendicated and contributors
* SPDX-License-Identifier: GPL-3.0-or-later
*/
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 { Channel } from "discord-types/general";
const cl = classNameFactory("vc-uvs-");
const { selectVoiceChannel } = findByPropsLazy("selectChannel", "selectVoiceChannel");
const VoiceStateStore = findStoreLazy("VoiceStateStore");
const UserSummaryItem = findComponentByCodeLazy("defaultRenderUser", "showDefaultAvatarsForNullUsers");
interface IconProps extends React.ComponentPropsWithoutRef<"div"> {
size?: number;
}
function SpeakerIcon(props: IconProps) {
props.size ??= 16;
return (
);
}
function LockedSpeakerIcon(props: IconProps) {
props.size ??= 16;
return (
);
}
interface VoiceChannelTooltipProps {
channel: Channel;
}
function VoiceChannelTooltip({ channel }: VoiceChannelTooltipProps) {
const voiceStates = useStateFromStores([VoiceStateStore], () => VoiceStateStore.getVoiceStatesForChannel(channel.id));
const users = useMemo(
() => Object.values(voiceStates).map(voiceState => UserStore.getUser(voiceState.userId)).filter(user => user != null),
[voiceStates]
);
const guild = channel.getGuildId() == null ? undefined : GuildStore.getGuild(channel.getGuildId());
const guildIcon = guild?.icon == null ? undefined : IconUtils.getGuildIconURL({
id: guild.id,
icon: guild.icon,
size: 30
});
return (
<>
{guild != null && (
{guildIcon != null &&
}
{guild.name}
)}
{channel.name}
>
);
}
interface VoiceChannelIndicatorProps {
userId: string;
}
const clickTimers = {} as Record;
export const VoiceChannelIndicator = ErrorBoundary.wrap(({ userId }: 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;
function onClick(e: React.MouseEvent) {
e.preventDefault();
e.stopPropagation();
if (channel == null || channelId == null) return;
if (!PermissionStore.can(PermissionsBits.VIEW_CHANNEL, channel)) {
showToast("You cannot view the user's Voice Channel", Toasts.Type.FAILURE);
return;
}
clearTimeout(clickTimers[channelId]);
delete clickTimers[channelId];
if (e.detail > 1) {
if (!PermissionStore.can(PermissionsBits.CONNECT, channel)) {
showToast("You cannot join the user's Voice Channel", Toasts.Type.FAILURE);
return;
}
selectVoiceChannel(channelId);
} else {
clickTimers[channelId] = setTimeout(() => {
NavigationRouter.transitionTo(`/channels/${channel.getGuildId() ?? "@me"}/${channelId}`);
delete clickTimers[channelId];
}, 250);
}
}
const isLocked = !PermissionStore.can(PermissionsBits.VIEW_CHANNEL, channel) || !PermissionStore.can(PermissionsBits.CONNECT, channel);
return (
}
tooltipClassName={cl("tooltip-container")}
tooltipContentClassName={cl("tooltip-content")}
>
{props =>
isLocked ?
:
}
);
}, { noop: true });