WhosWatching: Add Guild Profile Picture Support

This commit is contained in:
thororen1234 2026-05-25 13:08:58 -04:00
parent 5d1b3e8a12
commit 432377383a
No known key found for this signature in database
3 changed files with 28 additions and 10 deletions

View file

@ -1,7 +1,7 @@
{ {
"name": "equicord", "name": "equicord",
"private": "true", "private": "true",
"version": "1.14.13.0", "version": "1.14.13.1",
"description": "The other cutest Discord client mod", "description": "The other cutest Discord client mod",
"homepage": "https://github.com/Equicord/Equicord#readme", "homepage": "https://github.com/Equicord/Equicord#readme",
"bugs": { "bugs": {

View file

@ -15,11 +15,11 @@ import { Devs, EquicordDevs } from "@utils/constants";
import { classNameFactory } from "@utils/css"; import { classNameFactory } from "@utils/css";
import { getIntlMessage, openUserProfile } from "@utils/discord"; import { getIntlMessage, openUserProfile } from "@utils/discord";
import { Margins } from "@utils/margins"; import { Margins } from "@utils/margins";
import { classes } from "@utils/misc"; import { classes, getUserAvatarUrl } from "@utils/misc";
import definePlugin, { OptionType } from "@utils/types"; import definePlugin, { OptionType } from "@utils/types";
import { User } from "@vencord/discord-types"; import { User } from "@vencord/discord-types";
import { findComponentByCodeLazy, findCssClassesLazy, findStoreLazy } from "@webpack"; import { findComponentByCodeLazy, findCssClassesLazy } from "@webpack";
import { Clickable, RelationshipStore, Tooltip, UserStore, useStateFromStores } from "@webpack/common"; import { ApplicationStreamingStore, Clickable, RelationshipStore, Tooltip, UserStore, useStateFromStores } from "@webpack/common";
import { JSX } from "react"; import { JSX } from "react";
interface WatchingProps { interface WatchingProps {
@ -27,7 +27,6 @@ interface WatchingProps {
guildId?: string; guildId?: string;
} }
const ApplicationStreamingStore = findStoreLazy("ApplicationStreamingStore");
const UserSummaryItem = findComponentByCodeLazy("defaultRenderUser", "showDefaultAvatarsForNullUsers"); const UserSummaryItem = findComponentByCodeLazy("defaultRenderUser", "showDefaultAvatarsForNullUsers");
const AvatarStyles = findCssClassesLazy("moreUsers", "clickableAvatar", "avatar"); const AvatarStyles = findCssClassesLazy("moreUsers", "clickableAvatar", "avatar");
const cl = classNameFactory("vc-whos-watching-"); const cl = classNameFactory("vc-whos-watching-");
@ -39,6 +38,7 @@ function getUsername(user: User): string {
function Watching({ userIds, guildId }: WatchingProps): JSX.Element { function Watching({ userIds, guildId }: WatchingProps): JSX.Element {
let missingUsers = 0; let missingUsers = 0;
const users = userIds.map(id => UserStore.getUser(id)).filter(user => Boolean(user) ? true : (missingUsers += 1, false)); const users = userIds.map(id => UserStore.getUser(id)).filter(user => Boolean(user) ? true : (missingUsers += 1, false));
return ( return (
<div className={cl("content")}> <div className={cl("content")}>
{userIds.length ? {userIds.length ?
@ -48,7 +48,7 @@ function Watching({ userIds, guildId }: WatchingProps): JSX.Element {
<Flex flexDirection="column" gap="6" > <Flex flexDirection="column" gap="6" >
{users.map(user => ( {users.map(user => (
<Flex key={user.id} flexDirection="row" gap="6" alignContent="center"> <Flex key={user.id} flexDirection="row" gap="6" alignContent="center">
<img className={cl("user-avatar")} src={user.getAvatarURL(guildId)} alt="" /> <img className={cl("user-avatar")} src={getUserAvatarUrl(user, guildId, true, 80)} alt="" />
{getUsername(user)} {getUsername(user)}
</Flex> </Flex>
))} ))}
@ -108,11 +108,12 @@ export default definePlugin({
let missingUsers = 0; let missingUsers = 0;
const userIds: string[] = ApplicationStreamingStore.getViewerIds(stream); const userIds: string[] = ApplicationStreamingStore.getViewerIds(stream);
const users = userIds.map(id => UserStore.getUser(id)).filter(user => Boolean(user) ? true : (missingUsers += 1, false)); const users = userIds.map(id => UserStore.getUser(id)).filter(user => Boolean(user) ? true : (missingUsers += 1, false));
const guildId = stream?.guildId ?? "";
function renderMoreUsers(_label: string, count: number) { function renderMoreUsers(_label: string, count: number) {
const sliced = users.slice(count - 1); const sliced = users.slice(count - 1);
return ( return (
<Tooltip text={<Watching userIds={userIds} guildId={stream.guildId} />}> <Tooltip text={<Watching userIds={userIds} guildId={guildId} />}>
{({ onMouseEnter, onMouseLeave }) => ( {({ onMouseEnter, onMouseLeave }) => (
<div <div
className={AvatarStyles.moreUsers} className={AvatarStyles.moreUsers}
@ -150,7 +151,7 @@ export default definePlugin({
> >
<img <img
className={AvatarStyles.avatar} className={AvatarStyles.avatar}
src={user.getAvatarURL(void 0, 80, true)} src={getUserAvatarUrl(user, guildId, true, 80)}
alt={user.username} alt={user.username}
title={user.username} title={user.username}
/> />
@ -172,7 +173,9 @@ export default definePlugin({
if (!stream) return null; if (!stream) return null;
const viewers = ApplicationStreamingStore.getViewerIds(stream); const viewers = ApplicationStreamingStore.getViewerIds(stream);
return <Tooltip text={<Watching userIds={viewers} guildId={stream.guildId} />}> const guildId = stream?.guildId ?? "";
return <Tooltip text={<Watching userIds={viewers} guildId={guildId} />}>
{({ onMouseEnter, onMouseLeave }) => ( {({ onMouseEnter, onMouseLeave }) => (
<div onMouseEnter={onMouseEnter} onMouseLeave={onMouseLeave}> <div onMouseEnter={onMouseEnter} onMouseLeave={onMouseLeave}>
<OriginalComponent {...props} /> <OriginalComponent {...props} />

View file

@ -16,7 +16,8 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
import { ChannelStore, GuildMemberStore } from "@webpack/common"; import { User } from "@vencord/discord-types";
import { ChannelStore, GuildMemberStore, IconUtils } from "@webpack/common";
import { EQUICORD_HELPERS, EquicordDevsById, GUILD_ID, SUPPORT_CHANNEL_ID, VencordDevsById } from "./constants"; import { EQUICORD_HELPERS, EquicordDevsById, GUILD_ID, SUPPORT_CHANNEL_ID, VencordDevsById } from "./constants";
@ -130,3 +131,17 @@ export function removeFromArray<T>(arr: T[], predicate: (e: T) => boolean) {
const idx = arr.findIndex(predicate); const idx = arr.findIndex(predicate);
if (idx !== -1) arr.splice(idx, 1); if (idx !== -1) arr.splice(idx, 1);
} }
export function getUserAvatarUrl(user: User, guildId?: string, canAnimate?: boolean, size?: number): string {
const memberAvatar = guildId ? GuildMemberStore.getMember(guildId, user.id)?.avatar || null : null;
return memberAvatar
? IconUtils.getGuildMemberAvatarURLSimple({
guildId: guildId!,
userId: user.id,
avatar: memberAvatar,
canAnimate,
size
})
: IconUtils.getUserAvatarURL(user, canAnimate, size);
}