feat: DisplayProfile

This commit is contained in:
ryan-0324 2024-07-14 18:05:08 -04:00
parent 79da1d2d59
commit 057cd87114
9 changed files with 102 additions and 39 deletions

View file

@ -67,6 +67,7 @@
"no-mixed-spaces-and-tabs": "error",
"indent": ["error", 4, { "SwitchCase": 1 }],
"arrow-parens": ["error", "as-needed"],
"linebreak-style": ["error", "unix"],
"eol-last": ["error", "always"],
"@typescript-eslint/func-call-spacing": ["error", "never"],
"no-multi-spaces": "error",

View file

@ -9,6 +9,8 @@
"[typescriptreact]": {
"editor.defaultFormatter": "vscode.typescript-language-features"
},
"files.eol": "\n",
"files.insertFinalNewline": true,
"javascript.format.semicolons": "insert",
"typescript.format.semicolons": "insert",
"typescript.preferences.quoteStyle": "double",

View file

@ -448,6 +448,11 @@ export default {
type: "class",
},
},
"./general/DisplayProfile.ts": {
DisplayProfile: {
type: "class",
},
},
"./general/Draft.ts": {
DraftType: {
type: "enum",

View file

@ -0,0 +1,67 @@
/*
* discord-types
* Copyright (C) 2024 Vencord project contributors
* SPDX-License-Identifier: GPL-3.0-or-later
*/
import type { Nullish, OptionalTuple } from "../internal";
import type { GuildMemberProfile } from "./GuildMemberProfile";
import type { ProfileBadge, ProfileThemeColors, UserProfile } from "./UserProfile";
export declare class DisplayProfile<
FetchFailed extends boolean = boolean,
Guild extends boolean = boolean
> {
constructor(
userProfile: UserProfile<FetchFailed>,
...guildMemberProfile: Guild extends true
? [guildMemberProfile: GuildMemberProfile]
: [guildMemberProfile?: Nullish]
);
get application(): UserProfile["application"];
get canEditThemes(): boolean;
get canUsePremiumProfileCustomization(): boolean;
getBadges(): ProfileBadge[];
getBannerURL(options: {
canAnimate?: boolean | undefined /* = false */;
size: number;
}): string | undefined;
getLegacyUsername(): UserProfile<FetchFailed>["legacyUsername"];
getPreviewBanner(
previewBanner?: string | Nullish,
canAnimate?: boolean | undefined,
size?: number | undefined /* = 480 */
): string | Nullish;
getPreviewBio(previewBio?: string | Nullish): (true extends Guild ? boolean : false) extends infer GuildValue
? GuildValue extends true
? { isUsingGuildValue: true; value: string; }
: { isUsingGuildValue: false; value: string | undefined; }
: never;
getPreviewThemeColors(
previewThemeColors?: OptionalTuple<ProfileThemeColors, Nullish> | Nullish
): UserProfile["themeColors"];
hasFullProfile(): boolean;
hasPremiumCustomization(): boolean;
hasThemeColors(): boolean;
isUsingGuildMemberBanner(): true extends Guild ? boolean : false;
isUsingGuildMemberBio(): true extends Guild ? boolean : false;
isUsingGuildMemberPronouns(): true extends Guild ? boolean : false;
get premiumGuildSince(): UserProfile<FetchFailed>["premiumGuildSince"];
get premiumSince(): UserProfile<FetchFailed>["premiumSince"];
get premiumType(): UserProfile<FetchFailed>["premiumType"];
get primaryColor(): UserProfile["accentColor"];
_guildMemberProfile: Guild extends true ? GuildMemberProfile : Nullish;
_userProfile: UserProfile<FetchFailed>;
accentColor: UserProfile<FetchFailed>["accentColor"];
banner: UserProfile["banner"];
bio: UserProfile["bio"];
guildId: Guild extends true ? string : undefined;
/** @todo Does not seem to be implemented. */
popoutAnimationParticleType: UserProfile["popoutAnimationParticleType"];
profileEffectId: UserProfile<FetchFailed>["profileEffectId"];
pronouns: UserProfile<FetchFailed>["pronouns"];
themeColors: UserProfile["themeColors"];
userId: UserProfile<FetchFailed>["userId"];
}

View file

@ -38,15 +38,25 @@ export interface UserProfileFetchFailed {
accentColor: null;
application: null;
applicationRoleConnections: [];
/** Never present if fetch failed. */
badges?: undefined;
banner: null;
bio: "";
connectedAccounts: [];
lastFetched: number;
legacyUsername: null;
/** Never present if fetch failed. */
popoutAnimationParticleType?: undefined;
premiumGuildSince: null;
premiumSince: null;
/** Never present if fetch failed. */
premiumType?: undefined;
/** Never present if fetch failed. */
profileEffectId?: undefined;
profileFetchFailed: true;
pronouns: "";
/** Never present if fetch failed. */
themeColors?: undefined;
userId: string;
}

View file

@ -10,6 +10,7 @@ export * from "./ApplicationRecord";
export * from "./channels";
export * from "./Clan";
export * from "./CompanyRecord";
export * from "./DisplayProfile";
export * from "./Draft";
export * from "./emojis";
export * from "./Frecency";

View file

@ -37,6 +37,10 @@ export type Optional<T, Value = undefined, Keys extends keyof T = keyof T, Exclu
? Pick<T, Keys> & { [Key in Exclude<keyof T, Keys>]?: T[Key] | Value; }
: Omit<T, Keys> & { [Key in Keys]?: T[Key] | Value; };
/** @internal */
export type OptionalTuple<T extends unknown[], Value = undefined>
= { [Key in keyof T]?: T[Key] | Value; };
/** @internal */
export type PartialOnUndefined<T>
= { [Key in keyof T as undefined extends T[Key] ? never : Key]: T[Key]; }

View file

@ -16,7 +16,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import type { GuildMember, GuildRecord, UserRecord } from "@vencord/discord-types";
import type { DisplayProfile, GuildMember, GuildRecord, UserProfileStore, UserRecord, UserStore } from "@vencord/discord-types";
import type { ReactNode } from "react";
import type { LiteralUnion } from "type-fest";
@ -139,6 +139,7 @@ export interface Constants {
FriendsSections: Record<string, string>;
}
// zustand store
export interface ExpressionPickerStore {
closeExpressionPicker(activeViewType?: any): void;
openExpressionPicker(activeView: LiteralUnion<"emoji" | "gif" | "sticker", string>, activeViewType?: any): void;
@ -197,41 +198,14 @@ export interface UserUtils {
humanizeStatus: any;
}
export class DisplayProfile {
userId: string;
banner?: string;
bio?: string;
pronouns?: string;
accentColor?: number;
themeColors?: number[];
popoutAnimationParticleType?: any;
profileEffectId?: string;
_userProfile?: any;
_guildMemberProfile?: any;
canUsePremiumProfileCustomization: boolean;
canEditThemes: boolean;
premiumGuildSince: Date | null;
premiumSince: Date | null;
premiumType?: number;
primaryColor?: number;
getBadges(): {
id: string;
description: string;
icon: string;
link?: string;
}[];
getBannerURL(options: { canAnimate: boolean; size: number; }): string;
getLegacyUsername(): string | null;
hasFullProfile(): boolean;
hasPremiumCustomization(): boolean;
hasThemeColors(): boolean;
isUsingGuildMemberBanner(): boolean;
isUsingGuildMemberBio(): boolean;
isUsingGuildMemberPronouns(): boolean;
}
export interface DisplayProfileUtils {
getDisplayProfile(userId: string, guildId?: string, customStores?: any): DisplayProfile | null;
useDisplayProfile(userId: string, guildId?: string, customStores?: any): DisplayProfile | null;
getDisplayProfile(
userId: string,
guildId?: string | null | undefined,
stores?: [
Pick<UserStore, "getUser">,
Pick<UserProfileStore, "getUserProfile" | "getGuildMemberProfile">
] | undefined /* = [UserStore, UserProfileStore] */
): DisplayProfile | null;
useDisplayProfile(userId: string, guildId?: string | null | undefined): DisplayProfile | null;
}

View file

@ -130,9 +130,8 @@ export const DisplayProfileUtils: t.DisplayProfileUtils = mapMangledModuleLazy(/
const openExpressionPickerMatcher = canonicalizeMatch(/setState\({activeView:\i,activeViewType:/);
// TODO: type
// zustand store
export const ExpressionPickerStore = mapMangledModuleLazy("expression-picker-last-active-view", {
export const ExpressionPickerStore: t.ExpressionPickerStore = mapMangledModuleLazy("expression-picker-last-active-view", {
closeExpressionPicker: filters.byCode("setState({activeView:null"),
openExpressionPicker: m => typeof m === "function" && openExpressionPickerMatcher.test(m.toString()),
});