diff --git a/src/plugins/decor/index.tsx b/src/plugins/decor/index.tsx index 7a4ea0468..9bbde8217 100644 --- a/src/plugins/decor/index.tsx +++ b/src/plugins/decor/index.tsx @@ -9,6 +9,7 @@ import "./ui/styles.css"; import ErrorBoundary from "@components/ErrorBoundary"; import { Devs } from "@utils/constants"; import definePlugin from "@utils/types"; +import { User } from "@vencord/discord-types"; import { UserStore } from "@webpack/common"; import { CDN_URL, RAW_SKU_ID, setBaseUrl, SKU_ID } from "./lib/constants"; @@ -29,6 +30,7 @@ export default definePlugin({ description: "Create and use your own custom avatar decorations, or pick your favorite from the presets.", tags: ["Appearance", "Customisation"], authors: [Devs.FieryFlames], + isModified: true, patches: [ // Patch MediaResolver to return correct URL for Decor avatar decorations { @@ -122,10 +124,17 @@ export default definePlugin({ find: '("UserProfileModalV2EditingPanel")', replacement: [ { - match: /disabled:\i\|\|\i,errorMessage:\i\}\),/, - replace: "$&$self.ExperimentDecorSection()," + match: /disabled:(\i\|\|\i),avatarErrorMessage:\i,avatarDecorationErrorMessage:\i\}\),/, + replace: "$&$self.ExperimentDecorSection({disabled:$1})," } ] + }, + { + find: "isPreviewingMainProfileFallback:", + replacement: { + match: /(?<=avatarDecorationSrc:(\i),.{0,150}userId:(\i)\.id,.{0,100}avatarDecorationOverride:(\i\?\i:\i\?\i:void 0),animateOnHover:!\i\}\))/, + replace: ",vcDecorTileDecoration=($1=$self.useDiscordTileDecorationSrc($2,$1,$3))" + } } ], settings, @@ -158,6 +167,11 @@ export default definePlugin({ useUserDecorAvatarDecoration, + useDiscordTileDecorationSrc(user: User, src: string | null, override: unknown) { + const hasDecorDecoration = useUsersDecorationsStore(state => state.getAsset(user.id) != null); + return override === undefined && hasDecorDecoration ? null : src; + }, + async start() { await setBaseUrl(settings.store.baseUrl); useUsersDecorationsStore.getState().fetch(UserStore.getCurrentUser().id, true); diff --git a/src/plugins/decor/lib/stores/UsersDecorationsStore.ts b/src/plugins/decor/lib/stores/UsersDecorationsStore.ts index 3adb9847e..82656def9 100644 --- a/src/plugins/decor/lib/stores/UsersDecorationsStore.ts +++ b/src/plugins/decor/lib/stores/UsersDecorationsStore.ts @@ -104,8 +104,8 @@ export function useUserDecorAvatarDecoration(user?: User): AvatarDecoration | nu state => { if (!user) return; const newDecorAvatarDecoration = state.getAsset(user.id); - if (!newDecorAvatarDecoration) return; - if (decorAvatarDecoration !== newDecorAvatarDecoration) setDecorAvatarDecoration(newDecorAvatarDecoration); + if (newDecorAvatarDecoration === undefined) return; + setDecorAvatarDecoration(newDecorAvatarDecoration); } ); } catch { diff --git a/src/plugins/decor/ui/components/DecorSection.tsx b/src/plugins/decor/ui/components/DecorSection.tsx index e31a27d56..dd2323ef0 100644 --- a/src/plugins/decor/ui/components/DecorSection.tsx +++ b/src/plugins/decor/ui/components/DecorSection.tsx @@ -6,23 +6,76 @@ import { Button } from "@components/Button"; import { Flex } from "@components/Flex"; +import { SKU_ID } from "@plugins/decor/lib/constants"; import { useAuthorizationStore } from "@plugins/decor/lib/stores/AuthorizationStore"; import { useCurrentUserDecorationsStore } from "@plugins/decor/lib/stores/CurrentUserDecorationsStore"; +import { useUsersDecorationsStore } from "@plugins/decor/lib/stores/UsersDecorationsStore"; import { cl } from "@plugins/decor/ui"; import { openChangeDecorationModal } from "@plugins/decor/ui/modals/ChangeDecorationModal"; -import { findComponentByCodeLazy } from "@webpack"; -import { NewCustomizationSection, useEffect } from "@webpack/common"; +import { classes } from "@utils/misc"; +import { findByCodeLazy, findComponentByCodeLazy, findCssClassesLazy } from "@webpack"; +import { Avatar, NewCustomizationSection, useEffect, UserStore } from "@webpack/common"; +import type { ComponentType } from "react"; const CustomizationSection = findComponentByCodeLazy(".DESCRIPTION", "hasBackground:"); +const EditTile = findComponentByCodeLazy(".tileButton,", "affordance:"); +const useAvatarWithDecoration = findByCodeLazy("avatarOverride:", "avatarDecorationOverride:", "avatarPlaceholderSrc:"); +const TilePreviewClasses = findCssClassesLazy("emptyPreview", "fadeInAvatarImg"); + +const AvatarWithDecoration = Avatar as ComponentType; export interface DecorSectionProps { hideTitle?: boolean; hideDivider?: boolean; noMargin?: boolean; useNewSection?: boolean; + disabled?: boolean; } -export default function DecorSection({ hideTitle = false, hideDivider = false, noMargin = false, useNewSection = false }: DecorSectionProps) { +function DecorTilePreview({ asset, isInteracting }: { asset: string | null | undefined; isInteracting: boolean; }) { + const { avatarDecorationSrc, avatarSrc, avatarPlaceholderSrc } = useAvatarWithDecoration({ + userId: UserStore.getCurrentUser().id, + size: "SIZE_72", + showPending: true, + avatarDecorationOverride: asset ? { asset, skuId: SKU_ID } : null, + animateOnHover: !isInteracting + }); + + const showAvatar = avatarDecorationSrc != null && isInteracting; + + return ( + + ); +} + +function DecorTile({ disabled, onClick, onRemove }: { disabled?: boolean; onClick(): void; onRemove?(): void; }) { + const asset = useUsersDecorationsStore(state => state.getAsset(UserStore.getCurrentUser().id)); + + return ( + } + /> + ); +} + +export default function DecorSection({ hideTitle = false, hideDivider = false, noMargin = false, useNewSection = false, disabled = false }: DecorSectionProps) { const authorization = useAuthorizationStore(); const { selectedDecoration, select: selectDecoration, fetch: fetchDecorations } = useCurrentUserDecorationsStore(); @@ -30,49 +83,51 @@ export default function DecorSection({ hideTitle = false, hideDivider = false, n if (authorization.isAuthorized()) fetchDecorations(); }, [authorization.token]); - const NewSection = useNewSection ? NewCustomizationSection : undefined; + const openModal = () => { + if (!authorization.isAuthorized()) { + authorization.authorize().then(openChangeDecorationModal).catch(() => { }); + } else { + openChangeDecorationModal(); + } + }; - if (useNewSection && !NewSection) return null; + const canRemove = selectedDecoration != null && authorization.isAuthorized(); - const Section = (useNewSection ? NewCustomizationSection : CustomizationSection); - const sectionProps = useNewSection - ? { heading: hideTitle ? undefined : "Decor" } - : { - title: hideTitle ? undefined : "Decor", - hasBackground: true, - hideDivider, - className: noMargin ? cl("section-remove-margin") : undefined - }; + if (useNewSection) { + if (!NewCustomizationSection) return null; - const changeLabel = useNewSection ? "Change" : "Change Decoration"; - const removeLabel = useNewSection ? "Remove" : "Remove Decoration"; + return ( + + selectDecoration(null) : undefined} + /> + + ); + } return ( -
+ - - {selectedDecoration && authorization.isAuthorized() && ( + {canRemove && ( )} -
+ ); }