profileSets avatar / types fix (#794)

* profileSets avatar / types fix

- Fix avatar pending payload flow to use USER_PROFILE_SETTINGS_SET_PENDING_AVATAR with NEW_ASSET imageUri payload.

- Resolve TypeScript typing issues around IconUtils avatar/banner URL resolution without any casts.

- Remove debug logging and legacy pending dispatch paths; keep recents and profile pending behavior aligned with current Discord profile settings.

- Clean up profileSets rulebook compliance issues (nullish coalescing/defaults, typed preset field updates, no logger/console usage).

* profilesets: remove display name sanitizer subscription

* fixed checks

* fix pending profile event flow

* skip collectible dispatch when already equipped

* fixed checks

* Remove empty stop method from profile set plugin

Removed the empty stop method from the profile set plugin.

* bleh

* Update src/equicordplugins/profileSets/utils/profile.ts

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>

* Update src/equicordplugins/profileSets/utils/profile.ts

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>

* t

* fix fallback guard

* restore avatar size fallback

* fix fallback guard

* fix fallback guard

* fix to slider

* address gemini review issues

* fix avatarSize

* update avatarSize

* address review: destructure avatarSize

* restore direct avatarSize access

* destructure avatarSize

* Apply suggestion from @gemini-code-assist[bot]

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>

* Apply suggestion from @gemini-code-assist[bot]

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>

* Apply suggestion from @gemini-code-assist[bot]

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>

---------

Co-authored-by: thororen <78185467+thororen1234@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
This commit is contained in:
Eazvy 2026-02-20 16:06:46 -05:00 • committed by GitHub
parent cd125be7e8
commit 189ab429bb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 191 additions and 122 deletions

View file

@ -14,15 +14,15 @@ export interface PermissionOverwrite {
export interface AvatarDecorationData {
asset: string;
expires_at: string | null;
sku_id: string;
skuId: string;
}
/** Clan identity information. */
export interface ClanData {
badge: string;
identity_enabled: boolean;
identity_guild_id: string;
tag: string;
identityEnabled: boolean;
identityGuildId: string;
}
/** Display name style configuration. */
@ -38,7 +38,8 @@ export interface CollectibleItem {
expires_at: string | null;
label: string;
palette: string;
sku_id: string;
type: number;
skuId: string;
}
/** User collectibles configuration. */

View file

@ -39,7 +39,7 @@ export class User extends DiscordRecord {
get avatarDecoration(): AvatarDecorationData | null;
get createdAt(): Date;
get isProvisional(): boolean;
get nameplate(): { asset: string; sku_id: string; } | null;
get nameplate(): { asset: string; skuId: string; } | null;
get premiumGroupRole(): { id: string; name: string; color: number; } | null;
get tag(): string;

View file

@ -4,7 +4,9 @@
* SPDX-License-Identifier: GPL-3.0-or-later
*/
import { isNonNullish } from "@utils/guards";
import { classes } from "@utils/misc";
import { ProfilePreset } from "@vencord/discord-types";
import { ContextMenuApi, Menu, React, TextInput } from "@webpack/common";
import { cl } from "..";
@ -37,6 +39,7 @@ export function PresetList({
currentPage,
onPageChange
}: PresetListProps) {
type EditableProfile = Omit<ProfilePreset, "name" | "timestamp">;
const [renaming, setRenaming] = React.useState<number>(-1);
const [renameText, setRenameText] = React.useState("");
const isGuildProfile = section === "server";
@ -149,11 +152,11 @@ export function PresetList({
label="Update"
action={async () => {
const profile = await getCurrentProfile(guildId, { isGuildProfile });
Object.entries(profile).forEach(([key, value]) => {
if (value !== null && value !== undefined) {
updatePresetField(actualIndex, key as any, value, section, guildId);
}
});
await Promise.all(
(Object.entries(profile) as [keyof EditableProfile, EditableProfile[keyof EditableProfile]][])
.filter(([, value]) => isNonNullish(value))
.map(([key, value]) => updatePresetField(actualIndex, key, value, section, guildId))
);
onUpdate();
}}
/>

View file

@ -137,7 +137,7 @@ export function PresetManager({ section, guildId }: PresetManagerProps) {
});
};
const avatarSize = settings.store.avatarSize || 40;
const { avatarSize } = settings.store;
const hasPresets = presets.length > 0;
const shouldShowPagination = filteredPresets.length > PRESETS_PER_PAGE;

View file

@ -18,9 +18,11 @@ import { loadPresets, PresetSection } from "./utils/storage";
export const cl = classNameFactory("vc-profile-presets-");
export const settings = definePluginSettings({
avatarSize: {
type: OptionType.NUMBER,
type: OptionType.SLIDER,
description: "Avatar size in preset list.",
default: 40,
markers: [56, 64, 72, 80, 88, 96],
default: 56,
stickToMarkers: true
},
});
@ -40,8 +42,8 @@ export default definePlugin({
{
find: "USER_SETTINGS_GUILD_PROFILE)",
replacement: {
match: /onChange:\i\}\)(?=.{0,25}profilePreviewTitle:)/,
replace: '$&,$self.renderPresetSection("server")'
match: /guildId:(\i\.id),onChange:(\i)\}\)(?=.{0,25}profilePreviewTitle:)/,
replace: 'guildId:$1,onChange:$2}),$self.renderPresetSection("server",$1)'
}
}
],

View file

@ -4,24 +4,64 @@
* SPDX-License-Identifier: GPL-3.0-or-later
*/
import { isNonNullish } from "@utils/guards";
import { ProfilePreset } from "@vencord/discord-types";
import { findStoreLazy } from "@webpack";
import { showToast, Toasts } from "@webpack/common";
import { getCurrentProfile } from "./profile";
import { addPreset, movePresetInArray, PresetSection, presets, removePreset, replaceAllPresets, savePresetsData, updatePreset, type ProfilePresetEx } from "./storage";
import { addPreset, movePresetInArray, presets, PresetSection, type ProfilePresetEx, removePreset, replaceAllPresets, savePresetsData, updatePreset } from "./storage";
const UserProfileSettingsStore = findStoreLazy("UserProfileSettingsStore");
function isImageInput(value: unknown): value is string | { imageUri: string; } {
if (typeof value === "string") return value.length > 0;
return typeof value === "object" && isNonNullish(value) && "imageUri" in value && typeof (value as { imageUri: unknown }).imageUri === "string";
}
function getFreshPendingAvatar(section: PresetSection, guildId?: string): string | null {
const pending = (section === "server" && guildId
? UserProfileSettingsStore.getPendingChanges?.(guildId)
: UserProfileSettingsStore.getPendingChanges?.()) ?? {};
const pendingObj = pending as Record<string, unknown>;
const candidates = [
pendingObj.selectedAvatarRaw,
pendingObj.presetAvatarRaw,
pendingObj.pendingAvatar,
pendingObj.avatar,
pendingObj.selectedAvatarProcessed,
pendingObj.presetAvatarProcessed
];
const selected = candidates.find(isImageInput);
if (!selected) return null;
return typeof selected === "string" ? selected : selected.imageUri;
}
export async function savePreset(name: string, section: PresetSection, guildId?: string) {
const profile = await getCurrentProfile(guildId, { isGuildProfile: section === "server" });
const freshPendingAvatar = getFreshPendingAvatar(section, guildId);
const effectiveAvatar = freshPendingAvatar ?? profile.avatarDataUrl ?? null;
const newPreset: ProfilePresetEx = {
name,
timestamp: Date.now(),
...profile,
avatarDataUrl: effectiveAvatar,
};
addPreset(newPreset);
await savePresetsData(section);
}
export async function updatePresetField(index: number, field: keyof Omit<ProfilePreset, "name" | "timestamp">, value: any, section: PresetSection, guildId?: string) {
export async function updatePresetField<K extends keyof Omit<ProfilePreset, "name" | "timestamp">>(
index: number,
field: K,
value: Omit<ProfilePreset, "name" | "timestamp">[K],
section: PresetSection,
guildId?: string
) {
if (index < 0 || index >= presets.length) return;
void guildId;
const updatedPreset = {
...presets[index],
@ -55,17 +95,14 @@ export async function renamePreset(index: number, newName: string, section: Pres
}
export function exportPresets(section: PresetSection) {
try {
const dataStr = JSON.stringify(presets, null, 2);
const dataBlob = new Blob([dataStr], { type: "application/json" });
const url = URL.createObjectURL(dataBlob);
const link = document.createElement("a");
link.href = url;
link.download = `profile-presets-${section}-${Date.now()}.json`;
link.click();
URL.revokeObjectURL(url);
} catch {
}
const dataStr = JSON.stringify(presets, null, 2);
const dataBlob = new Blob([dataStr], { type: "application/json" });
const url = URL.createObjectURL(dataBlob);
const link = document.createElement("a");
link.href = url;
link.download = `profile-presets-${section}-${Date.now()}.json`;
link.click();
URL.revokeObjectURL(url);
}
export type ImportDecision = "override" | "merge" | "cancel";
@ -108,6 +145,7 @@ export async function importPresets(
await savePresetsData(section);
forceUpdate();
} catch {
showToast("Failed to import presets. The file might be invalid.", Toasts.Type.FAILURE);
}
};
input.click();

View file

@ -7,12 +7,16 @@
import { getUserSettingLazy } from "@api/UserSettings";
import { CustomStatus, DisplayNameStyles, Nameplate, ProfileEffect, ProfilePreset } from "@vencord/discord-types";
import { findStoreLazy } from "@webpack";
import { FluxDispatcher, GuildMemberStore,IconUtils, UserProfileStore, UserStore } from "@webpack/common";
import { FluxDispatcher, GuildMemberStore, IconUtils, UserProfileStore, UserStore } from "@webpack/common";
const UserProfileSettingsStore = findStoreLazy("UserProfileSettingsStore");
const CustomStatusSettings = getUserSettingLazy("status", "customStatus")!;
type PendingChanges = Record<string, unknown> & {
selectedAvatarRaw?: ImageInput;
presetAvatarRaw?: ImageInput;
selectedAvatarProcessed?: ImageInput;
presetAvatarProcessed?: ImageInput;
pendingAvatar?: ImageInput;
avatar?: ImageInput;
pendingBanner?: ImageInput;
@ -30,39 +34,23 @@ type PendingChanges = Record<string, unknown> & {
pendingPrimaryGuildId?: string | null;
};
type UserExtras = {
collectibles?: {
nameplate?: Nameplate;
};
displayNameStyles?: DisplayNameStyles;
avatarDecorationData?: {
asset: string;
skuId: string;
} | null;
primaryGuild?: {
identityGuildId?: string | null;
} | null;
};
type ProfileCollectible = {
skuId: string;
title?: string;
description?: string;
accessibilityLabel?: string;
reducedMotionSrc?: string;
thumbnailPreviewSrc?: string;
effects?: ProfileEffect["effects"];
animationType?: number;
staticFrameSrc?: string;
type?: number;
};
type ImageInput = string | { imageUri: string; } | null | undefined;
type DisplayNameStylesLike = DisplayNameStyles & {
fontId?: number;
effectId?: number;
};
type CurrentProfileOptions = {
isGuildProfile?: boolean;
};
type LoadPresetOptions = {
skipGlobalName?: boolean;
skipBio?: boolean;
skipPronouns?: boolean;
isGuildProfile?: boolean;
};
function dispatch(type: string, payload: Record<string, unknown>) {
FluxDispatcher.dispatch({ type, ...payload });
}
@ -74,7 +62,7 @@ function isNonEmptyString(value: unknown): value is string {
function hasImageInput(value: ImageInput): boolean {
if (!value) return false;
if (typeof value === "string") return value.length > 0;
return typeof value === "object" && "imageUri" in value && isNonEmptyString(value.imageUri);
return typeof value === "object" && isNonEmptyString(value?.imageUri);
}
function normalizeDisplayNameStyles(value: DisplayNameStylesLike | null | undefined): DisplayNameStylesLike | null {
@ -111,7 +99,7 @@ export async function imageUrlToBase64(url: string): Promise<string | null> {
async function processImage(imageData: ImageInput, userId: string, type: "avatar" | "banner", guildId?: string, useGuildPath?: boolean): Promise<string | null> {
if (!imageData) return null;
if (typeof imageData === "object" && "imageUri" in imageData && isNonEmptyString(imageData.imageUri)) {
if (typeof imageData === "object" && isNonEmptyString(imageData?.imageUri)) {
return imageData.imageUri;
}
@ -137,17 +125,6 @@ async function processImage(imageData: ImageInput, userId: string, type: "avatar
return null;
}
type CurrentProfileOptions = {
isGuildProfile?: boolean;
};
type LoadPresetOptions = {
skipGlobalName?: boolean;
skipBio?: boolean;
skipPronouns?: boolean;
isGuildProfile?: boolean;
};
export async function getCurrentProfile(guildId?: string, options: CurrentProfileOptions = {}): Promise<Omit<ProfilePreset, "name" | "timestamp">> {
const currentUser = UserStore.getCurrentUser();
const baseProfile = UserProfileStore.getUserProfile(currentUser.id);
@ -155,19 +132,17 @@ export async function getCurrentProfile(guildId?: string, options: CurrentProfil
const effectiveGuildId = isGuildProfile ? guildId : undefined;
const guildProfile = effectiveGuildId ? UserProfileStore.getGuildMemberProfile(currentUser.id, effectiveGuildId) : null;
const userProfile = guildProfile ?? baseProfile;
const userAny = currentUser as UserExtras;
const userAny = currentUser;
const guildMember = effectiveGuildId ? GuildMemberStore.getMember(effectiveGuildId, currentUser.id) : null;
const pendingChangesDefault = (UserProfileSettingsStore.getPendingChanges() ?? {}) as PendingChanges;
const pendingChangesForGuild = (effectiveGuildId
? (UserProfileSettingsStore.getPendingChanges(effectiveGuildId) ?? {})
: {}) as PendingChanges;
const pendingChangesDefault: PendingChanges = UserProfileSettingsStore.getPendingChanges() ?? {};
const pendingChangesForGuild: PendingChanges = UserProfileSettingsStore.getPendingChanges(effectiveGuildId) ?? {};
const pendingChanges: PendingChanges = isGuildProfile && Object.keys(pendingChangesForGuild).length > 0
? pendingChangesForGuild
: pendingChangesDefault;
const customStatusSetting = CustomStatusSettings.getSetting();
const customStatus: CustomStatus | null = isGuildProfile
const customStatus = isGuildProfile
? null
: {
text: customStatusSetting?.text ?? "",
@ -200,7 +175,7 @@ export async function getCurrentProfile(guildId?: string, options: CurrentProfil
type: effectToUse.type || 1
};
} else if (effectToUse.skuId) {
const collectibles = (userProfile as { collectibles?: ProfileCollectible[]; } | null)?.collectibles;
const collectibles = userProfile?.collectibles;
const collectible = collectibles?.find(c => c?.skuId === effectToUse.skuId);
if (collectible) {
profileEffect = {
@ -232,7 +207,7 @@ export async function getCurrentProfile(guildId?: string, options: CurrentProfil
? (guildMember?.displayNameStyles ?? userAny.displayNameStyles)
: userAny.displayNameStyles;
const displayNameStylesToUse = pendingChanges.pendingDisplayNameStyles ?? savedDisplayNameStyles;
const displayNameStyles = normalizeDisplayNameStyles(displayNameStylesToUse as DisplayNameStylesLike | null | undefined);
const displayNameStyles = normalizeDisplayNameStyles(displayNameStylesToUse);
const pendingAvatar = pendingChanges.pendingAvatar ?? pendingChanges.avatar;
const avatarToUse: ImageInput = hasImageInput(pendingAvatar)
@ -282,106 +257,156 @@ function jsonEq(a: unknown, b: unknown): boolean {
}
function customStatusEq(a: CustomStatus | null | undefined, b: CustomStatus | null | undefined): boolean {
if (a == null && b == null) return true;
if (a == null || b == null) return false;
if (a == null || b == null) return a == null && b == null;
return a.text === b.text
&& String(a.emojiId ?? "") === String(b.emojiId ?? "")
&& a.emojiName === b.emojiName
&& String(a.expiresAtMs ?? "0") === String(b.expiresAtMs ?? "0");
}
function resolvePendingAvatar(pendingChanges: PendingChanges | null): ImageInput {
if (!pendingChanges) return null;
const candidates: ImageInput[] = [
pendingChanges.selectedAvatarRaw,
pendingChanges.presetAvatarRaw,
pendingChanges.pendingAvatar,
pendingChanges.avatar,
pendingChanges.selectedAvatarProcessed,
pendingChanges.presetAvatarProcessed
];
return candidates.find(hasImageInput) ?? null;
}
function normalizeImageValue(value: unknown): string | null {
if (typeof value === "string") return value;
if (value && typeof value === "object" && "imageUri" in value) {
const { imageUri } = value as { imageUri: unknown };
return typeof imageUri === "string" ? imageUri : null;
}
return null;
}
function collectibleEqBySku(a: { skuId?: string | number | null; } | null | undefined, b: { skuId?: string | number | null; } | null | undefined): boolean {
if (a == null || b == null) return a == null && b == null;
return String(a.skuId ?? "") === String(b.skuId ?? "");
}
function avatarDecorationEq(a: { skuId?: string | number | null; asset?: string | null; } | null | undefined, b: { skuId?: string | number | null; asset?: string | null; } | null | undefined): boolean {
if (a == null || b == null) return a == null && b == null;
return String(a.skuId ?? "") === String(b.skuId ?? "") && String(a.asset ?? "") === String(b.asset ?? "");
}
function nameplateEq(a: { skuId?: string | number | null; asset?: string | null; } | null | undefined, b: { skuId?: string | number | null; asset?: string | null; } | null | undefined): boolean {
if (a == null || b == null) return a == null && b == null;
return String(a.skuId ?? "") === String(b.skuId ?? "") && String(a.asset ?? "") === String(b.asset ?? "");
}
export async function loadPresetAsPending(preset: ProfilePreset, guildId?: string, options: LoadPresetOptions = {}) {
try {
const isGuild = options.isGuildProfile ?? Boolean(guildId);
if (isGuild && !guildId) return;
const currentUser = UserStore.getCurrentUser();
const baseProfile = UserProfileStore.getUserProfile(currentUser.id);
const guildProfile = isGuild && guildId ? UserProfileStore.getGuildMemberProfile(currentUser.id, guildId) : null;
const equippedProfile = guildProfile ?? baseProfile;
const current = await getCurrentProfile(guildId, {
isGuildProfile: isGuild
});
const profilePrefix = isGuild ? "GUILD_IDENTITY_SETTINGS" : "USER_SETTINGS_ACCOUNT";
const dispatchProfile = (type: string, payload: Record<string, unknown>) => {
dispatch(type, isGuild ? { ...payload, guildId } : payload);
};
const setPending = (type: string, payload: Record<string, unknown>) => {
dispatchProfile(type, payload);
if (isGuild && type.startsWith("GUILD_IDENTITY_SETTINGS_")) {
dispatchProfile(type.replace("GUILD_IDENTITY_SETTINGS_", "USER_SETTINGS_ACCOUNT_"), payload);
}
const pendingChanges = (isGuild && guildId
? UserProfileSettingsStore.getPendingChanges(guildId)
: UserProfileSettingsStore.getPendingChanges());
const equippedAvatarDecoration = currentUser.avatarDecorationData ?? null;
const equippedProfileEffect = equippedProfile?.profileEffect ?? null;
const equippedNameplate = currentUser.collectibles?.nameplate ?? null;
const pendingAvatarDecoration = pendingChanges?.pendingAvatarDecoration ?? null;
const pendingProfileEffect = pendingChanges?.pendingProfileEffect ?? null;
const pendingNameplate = pendingChanges?.pendingNameplate ?? null;
const setPending = (field: string, payload: Record<string, unknown>) => {
const cleanPayload = Object.fromEntries(Object.entries(payload).filter(([, v]) => v !== undefined));
if (!Object.keys(cleanPayload).length) return;
dispatch(`USER_PROFILE_SETTINGS_SET_PENDING_${field}`, isGuild ? { ...cleanPayload, guildId } : cleanPayload);
};
if ("avatarDataUrl" in preset) {
const avatarValue = preset.avatarDataUrl;
if (isGuild || avatarValue !== current.avatarDataUrl) {
setPending(`${profilePrefix}_SET_PENDING_AVATAR`, { avatar: avatarValue });
const presetAvatar = normalizeImageValue(avatarValue);
const currentAvatar = normalizeImageValue(current.avatarDataUrl);
const pendingAvatar = normalizeImageValue(resolvePendingAvatar(pendingChanges));
if (isGuild || (presetAvatar !== currentAvatar && presetAvatar !== pendingAvatar)) {
const avatarPayload =
typeof avatarValue === "string" && avatarValue.startsWith("data:")
? {
assetOrigin: "NEW_ASSET",
imageUri: avatarValue,
description: `profilesets-${preset.name ?? "preset"}`
}
: avatarValue;
setPending("AVATAR", { avatar: avatarPayload });
}
}
if ("bannerDataUrl" in preset && preset.bannerDataUrl !== current.bannerDataUrl) {
setPending(`${profilePrefix}_SET_PENDING_BANNER`, { banner: preset.bannerDataUrl });
setPending("BANNER", { banner: preset.bannerDataUrl });
}
if (!options.skipBio && "bio" in preset && preset.bio !== current.bio) {
if (!options.skipBio && preset?.bio !== current?.bio) {
const bioValue = preset.bio === null ? "" : preset.bio;
setPending(`${profilePrefix}_SET_PENDING_BIO`, { bio: bioValue });
setPending("BIO", { bio: bioValue });
}
if (!isGuild && !options.skipPronouns && "pronouns" in preset && preset.pronouns !== current.pronouns) {
if (!isGuild && !options.skipPronouns && preset?.pronouns !== current?.pronouns) {
const pronounsValue = preset.pronouns === null ? "" : preset.pronouns;
setPending(`${profilePrefix}_SET_PENDING_PRONOUNS`, { pronouns: pronounsValue });
setPending("PRONOUNS", { pronouns: pronounsValue });
}
if (!options.skipGlobalName && preset.globalName !== undefined && preset.globalName !== current.globalName) {
if (!options.skipGlobalName && preset?.globalName !== current?.globalName) {
if (isGuild) {
setPending("GUILD_IDENTITY_SETTINGS_SET_PENDING_NICKNAME", { nickname: preset.globalName });
setPending("NICKNAME", { nickname: preset.globalName });
} else {
setPending("USER_SETTINGS_ACCOUNT_SET_PENDING_GLOBAL_NAME", { globalName: preset.globalName });
setPending("GLOBAL_NAME", { globalName: preset.globalName });
}
}
if (preset.avatarDecoration !== undefined && !jsonEq(preset.avatarDecoration, current.avatarDecoration)) {
dispatchProfile(`${profilePrefix}_SET_PENDING_COLLECTIBLES_ITEM`, {
if (preset.avatarDecoration && ![pendingAvatarDecoration, equippedAvatarDecoration, current.avatarDecoration].some(d => avatarDecorationEq(preset.avatarDecoration, d))) {
setPending("COLLECTIBLES_ITEM", {
item: { type: 0, value: preset.avatarDecoration }
});
}
if (preset.profileEffect !== undefined && !jsonEq(preset.profileEffect, current.profileEffect)) {
dispatchProfile(`${profilePrefix}_SET_PENDING_COLLECTIBLES_ITEM`, {
if (preset.profileEffect && ![pendingProfileEffect, equippedProfileEffect, current.profileEffect].some(d => collectibleEqBySku(preset.profileEffect, d))) {
setPending("COLLECTIBLES_ITEM", {
item: { type: 1, value: preset.profileEffect }
});
}
if (preset.nameplate !== undefined && !jsonEq(preset.nameplate, current.nameplate)) {
dispatchProfile(`${profilePrefix}_SET_PENDING_COLLECTIBLES_ITEM`, {
if (preset.nameplate && ![pendingNameplate, equippedNameplate, current.nameplate].some(d => nameplateEq(preset.nameplate, d))) {
setPending("COLLECTIBLES_ITEM", {
item: { type: 2, value: preset.nameplate }
});
}
if (preset.displayNameStyles !== undefined) {
const presetDisplayNameStyles = normalizeDisplayNameStyles(preset.displayNameStyles as DisplayNameStylesLike | null | undefined);
if (preset.displayNameStyles) {
const presetDisplayNameStyles = normalizeDisplayNameStyles(preset.displayNameStyles);
if (!jsonEq(presetDisplayNameStyles, current.displayNameStyles)) {
setPending(`${profilePrefix}_SET_PENDING_DISPLAY_NAME_STYLES`, { displayNameStyles: presetDisplayNameStyles });
setPending("DISPLAY_NAME_STYLES", { displayNameStyles: presetDisplayNameStyles });
}
}
if (preset.themeColors !== undefined && !jsonEq(preset.themeColors, current.themeColors)) {
setPending(`${profilePrefix}_SET_PENDING_THEME_COLORS`, { themeColors: preset.themeColors });
if (preset.themeColors && !jsonEq(preset.themeColors, current.themeColors)) {
setPending("THEME_COLORS", { themeColors: preset.themeColors });
}
if (preset.primaryGuildId !== undefined && !isGuild && preset.primaryGuildId !== current.primaryGuildId) {
if (preset.primaryGuildId && !isGuild && preset.primaryGuildId !== current.primaryGuildId) {
dispatch("USER_SETTINGS_SET_PENDING_PRIMARY_GUILD_ID", { primaryGuildId: preset.primaryGuildId });
}
if (preset.customStatus !== undefined && !isGuild && !customStatusEq(preset.customStatus, current.customStatus)) {
const customStatusValue = preset.customStatus ?? {
text: "",
expiresAtMs: "0",
emojiId: "0",
emojiName: ""
};
if (preset.customStatus && !isGuild && !customStatusEq(preset.customStatus, current.customStatus)) {
CustomStatusSettings.updateSetting({
text: customStatusValue.text || "",
expiresAtMs: customStatusValue.expiresAtMs || "0",
emojiId: customStatusValue.emojiId || "0",
emojiName: customStatusValue.emojiName || ""
text: preset.customStatus?.text ?? "",
expiresAtMs: preset.customStatus?.expiresAtMs ?? "0",
emojiId: preset.customStatus?.emojiId ?? "0",
emojiName: preset.customStatus?.emojiName ?? ""
});
}
} catch (err) {