Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ShowConnections: Cap max number of connections displayed #3156

Open
wants to merge 19 commits into
base: dev
Choose a base branch
from
Open
2 changes: 1 addition & 1 deletion src/plugins/fakeProfileThemes/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ export default definePlugin({
],
settingsAboutComponent: () => {
const existingColors = decode(
UserProfileStore.getUserProfile(UserStore.getCurrentUser().id).bio
UserProfileStore.getUserProfile(UserStore.getCurrentUser().id)!.bio
) ?? [0, 0];
const [color1, setColor1] = useState(existingColors[0]);
const [color2, setColor2] = useState(existingColors[1]);
Expand Down
57 changes: 45 additions & 12 deletions src/plugins/showConnections/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,14 @@ import { definePluginSettings } from "@api/Settings";
import ErrorBoundary from "@components/ErrorBoundary";
import { Flex } from "@components/Flex";
import { CopyIcon, LinkIcon } from "@components/Icons";
import { makeRange } from "@components/PluginSettings/components";
import { Devs } from "@utils/constants";
import { openUserProfile } from "@utils/discord";
import { copyWithToast } from "@utils/misc";
import definePlugin, { OptionType } from "@utils/types";
import { findByCodeLazy, findByPropsLazy } from "@webpack";
import { Tooltip, UserProfileStore } from "@webpack/common";
import { Icons, Tooltip, UserProfileStore } from "@webpack/common";
import { Connection } from "@webpack/types";
import { User } from "discord-types/general";

import { VerifiedIcon } from "./VerifiedIcon";
Expand Down Expand Up @@ -57,16 +60,15 @@ const settings = definePluginSettings({
{ label: "Cozy", value: Spacing.COZY }, // US Spelling :/
{ label: "Roomy", value: Spacing.ROOMY }
]
},
maxNumberOfConnections: {
type: OptionType.SLIDER,
description: "Max number of connections to show",
default: 13,
markers: makeRange(6, 48, 7),
}
});

interface Connection {
type: string;
id: string;
name: string;
verified: boolean;
}

interface ConnectionPlatform {
getPlatformUserUrl(connection: Connection): string;
icon: { lightSVG: string, darkSVG: string; };
Expand All @@ -88,20 +90,51 @@ function ConnectionsComponent({ id, theme }: { id: string, theme: string; }) {
if (!profile)
return null;

const connections: Connection[] = profile.connectedAccounts;
if (!connections?.length)
const { connectedAccounts } = profile;
if (!connectedAccounts?.length)
return null;

const connections = connectedAccounts.map(connection => <CompactConnectionComponent connection={connection} theme={theme} key={connection.id} />);

if (connectedAccounts.length > settings.store.maxNumberOfConnections) {
connections.length = settings.store.maxNumberOfConnections;
connections.push(<ConnectionsMoreIcon key="more-connections" onClick={() => openUserProfile(id, {
section: "USER_INFO",
subsection: "CONNECTIONS"
})} />);
}
return (
<Flex style={{
gap: getSpacingPx(settings.store.iconSpacing),
flexWrap: "wrap"
}}>
{connections.map(connection => <CompactConnectionComponent connection={connection} theme={theme} key={connection.id} />)}
{connections}
</Flex>
);
}

function ConnectionsMoreIcon({ onClick }: { onClick: () => void; }) {
return (
<Tooltip
text={
<span className="vc-sc-tooltip">
<span className="vc-sc-connection-name">
View All Connections
</span>
</span>
}
>
sadan4 marked this conversation as resolved.
Show resolved Hide resolved
{props => (
<Icons.MoreHorizontalIcon
{...props}
onClick={onClick}
sadan4 marked this conversation as resolved.
Show resolved Hide resolved
className="vc-user-connection"
/>
)}
</Tooltip>
);
}

function CompactConnectionComponent({ connection, theme }: { connection: Connection, theme: string; }) {
const platform = platforms.get(useLegacyPlatformType(connection.type));
const url = platform.getPlatformUserUrl?.(connection);
Expand Down Expand Up @@ -164,7 +197,7 @@ function CompactConnectionComponent({ connection, theme }: { connection: Connect
export default definePlugin({
name: "ShowConnections",
description: "Show connected accounts in user popouts",
authors: [Devs.TheKodeToad],
authors: [Devs.TheKodeToad, Devs.sadan],
settings,

patches: [
Expand Down
4 changes: 2 additions & 2 deletions src/plugins/userMessagesPronouns/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ import { UserProfileStore, useStateFromStores } from "@webpack/common";
import { PronounsFormat, settings } from "./settings";

function useDiscordPronouns(id: string, useGlobalProfile: boolean = false): string | undefined {
const globalPronouns: string | undefined = useStateFromStores([UserProfileStore], () => UserProfileStore.getUserProfile(id)?.pronouns);
const guildPronouns: string | undefined = useStateFromStores([UserProfileStore], () => UserProfileStore.getGuildMemberProfile(id, getCurrentChannel()?.getGuildId())?.pronouns);
const globalPronouns = useStateFromStores([UserProfileStore], () => UserProfileStore.getUserProfile(id)?.pronouns);
const guildPronouns = useStateFromStores([UserProfileStore], () => UserProfileStore.getGuildMemberProfile(id, getCurrentChannel()?.getGuildId())?.pronouns);

if (useGlobalProfile) return globalPronouns;
return guildPronouns || globalPronouns;
Expand Down
10 changes: 2 additions & 8 deletions src/plugins/validUser/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { sleep } from "@utils/misc";
import { Queue } from "@utils/Queue";
import definePlugin from "@utils/types";
import { Constants, FluxDispatcher, RestAPI, UserProfileStore, UserStore, useState } from "@webpack/common";
import { ProfileBadge, UserProfile } from "@webpack/types";
import { type ComponentType, type ReactNode } from "react";

// LYING to the type checker here
Expand All @@ -47,13 +48,6 @@ const badges: Record<string, ProfileBadge> = {
const fetching = new Set<string>();
const queue = new Queue(5);

interface ProfileBadge {
id: string;
description: string;
icon: string;
link?: string;
}

interface MentionProps {
data: {
userId?: string;
Expand Down Expand Up @@ -101,7 +95,7 @@ async function getUser(id: string) {
fakeBadges.push(badges.premium);

// Fill in what we can deduce
const profile = UserProfileStore.getUserProfile(id);
const profile: Partial<UserProfile> = UserProfileStore.getUserProfile(id) ?? {};
Comment on lines -104 to +98
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure what the point of this is in the first place, so not sure if this is the best/correct fix

profile.accentColor = user.accent_color;
profile.badges = fakeBadges;
profile.banner = user.banner;
Expand Down
6 changes: 4 additions & 2 deletions src/utils/discord.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import "./discord.css";

import { MessageObject } from "@api/MessageEvents";
import { ChannelStore, ComponentDispatch, Constants, FluxDispatcher, GuildStore, i18n, IconUtils, InviteActions, MessageActions, PrivateChannelsStore, RestAPI, SelectedChannelStore, SelectedGuildStore, UserProfileActions, UserProfileStore, UserSettingsActionCreators, UserUtils } from "@webpack/common";
import { OpenUserProfileModalProps } from "@webpack/types";
import { Channel, Guild, Message, User } from "discord-types/general";
import { Except } from "type-fest";

Expand Down Expand Up @@ -155,7 +156,7 @@ export function openImageModal(item: Except<MediaModalItem, "type">, mediaModalP
});
}

export async function openUserProfile(id: string) {
export async function openUserProfile(id: string, extraParams: Partial<OpenUserProfileModalProps> = {}) {
const user = await UserUtils.getUser(id);
if (!user) throw new Error("No such user: " + id);

Expand All @@ -167,7 +168,8 @@ export async function openUserProfile(id: string) {
analyticsLocation: {
page: guildId ? "Guild Channel" : "DM Channel",
section: "Profile Popout"
}
},
...extraParams
});
}

Expand Down
2 changes: 1 addition & 1 deletion src/webpack/common/stores.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export let PresenceStore: GenericStore;

export let GuildStore: t.GuildStore;
export let UserStore: Stores.UserStore & t.FluxStore;
export let UserProfileStore: GenericStore;
export let UserProfileStore: t.UserProfileStore;
export let SelectedChannelStore: Stores.SelectedChannelStore & t.FluxStore;
export let SelectedGuildStore: t.FluxStore & Record<string, any>;
export let ChannelStore: Stores.ChannelStore & t.FluxStore;
Expand Down
86 changes: 86 additions & 0 deletions src/webpack/common/types/stores.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,92 @@ export class ThemeStore extends FluxStore {
systemTheme: null;
}

export interface ProfileBadge {
description: string;
icon: string;
id: string;
link?: string;
}

export interface Connection {
id: string;
name: string;
type: string;
verified: boolean;
}

export interface Application {
customInstallUrl: never | undefined;
flags: number;
id: string;
installParams: never | undefined;
integrationTypesConfig: Record<number, object>;
name: string;
popularApplicationCommands: never | undefined;
primarySkuId: undefined | never;
storefront_available: boolean;
}

export const enum PremiumType {
NONE,
NITRO_CLASSIC,
NITRO,
NITRO_BASIC
}

export interface BaseProfile {
accentColor: number;
badges: ProfileBadge[];
banner: string | null;
bio: string;
popoutAnimationParticleType: never;
profileEffectExpiresAt: never;
profileEffectId: string;
pronouns: string;
themeColors: number[] | null;
userId: string;
}

export interface UserProfile extends BaseProfile {
application: Application;
applicationRoleConnections: never[];
connectedAccounts: Connection[];
fetchError: never;
lastFetched: number;
legacyUsername: string;
premiumGuildSince: Data | null;
premiumSince: Date | null;
premiumType: PremiumType;
}

export interface GuildProfile extends BaseProfile {
guildId: string;
}

export interface MutualFriend {
key: string;
status: "offline" | "online" | "idle" | "dnd";
}

export interface MutualGuild {
nick: string | null;
guild: Guild;
}

export class UserProfileStore extends FluxStore {
isFetchingProfile(userId: string, guildId?: string);
/**
* Fetching mutual friends
*/
isFetchingFriends(userId: string);
get isSubmitting(): boolean;
getUserProfile(userId: string): UserProfile | undefined;
getGuildMemberProfile(userId: string, guildId?: string): GuildProfile | null | undefined;
getMutualFriends(userId: string): MutualFriend[];
getMutualFriendsCount(userId: string): number | undefined;
getMutualGuilds(userId: string): MutualGuild[] | undefined;
}

export type useStateFromStores = <T>(
stores: t.FluxStore[],
mapper: () => T,
Expand Down
17 changes: 17 additions & 0 deletions src/webpack/common/types/utils.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -324,3 +324,20 @@ export interface DisplayProfileUtils {
getDisplayProfile(userId: string, guildId?: string, customStores?: any): DisplayProfile | null;
useDisplayProfile(userId: string, guildId?: string, customStores?: any): DisplayProfile | null;
}

export type OpenUserProfileModalProps = {
userId: string;
guildId: string;
showGuildProfile?: boolean;
channelId: string;
analyticsLocation: {
page: string;
section: string;
};
section?: "USER_INFO" | "BOT_INFO" | "ACTIVITY" | "MUTUAL_GUILDS" | "MUTUAL_FRIENDS" | "BOT_DATA_ACCESS";
subsection?: "ROLES" | "CONNECTIONS" | "NOTE" | "RECENT_ACTIVITY";
};

export interface UserProfileActions {
openUserProfileModal(props: OpenUserProfileModalProps): Promise<void>;
}
2 changes: 1 addition & 1 deletion src/webpack/common/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ export const { zustandPersist } = mapMangledModuleLazy(".onRehydrateStorage)?",

export const MessageActions = findByPropsLazy("editMessage", "sendMessage");
export const MessageCache = findByPropsLazy("clearCache", "_channelMessages");
export const UserProfileActions = findByPropsLazy("openUserProfileModal", "closeUserProfileModal");
export const UserProfileActions: t.UserProfileActions = findByPropsLazy("openUserProfileModal", "closeUserProfileModal");
export const InviteActions = findByPropsLazy("resolveInvite");

export const IconUtils: t.IconUtils = findByPropsLazy("getGuildBannerURL", "getUserAvatarURL");
Expand Down
Loading