import clsx from 'clsx'; import { AnimatePresence, HTMLMotionProps, motion, Variants } from 'motion/react'; import { Fragment, useEffect, useRef } from 'react'; import { generatePath, Link } from 'react-router'; import styles from './full-screen-player-image.module.css'; import { useItemImageUrl } from '/@/renderer/components/item-image/item-image'; import { AppRoute } from '/@/renderer/router/routes'; import { useNativeAspectRatio, usePlayerData, usePlayerSong } from '/@/renderer/store'; import { Badge } from '/@/shared/components/badge/badge'; import { Center } from '/@/shared/components/center/center'; import { Flex } from '/@/shared/components/flex/flex'; import { Group } from '/@/shared/components/group/group'; import { Icon } from '/@/shared/components/icon/icon'; import { Stack } from '/@/shared/components/stack/stack'; import { Text } from '/@/shared/components/text/text'; import { useSetState } from '/@/shared/hooks/use-set-state'; import { LibraryItem } from '/@/shared/types/domain-types'; const imageVariants: Variants = { closed: { opacity: 0, transition: { duration: 0.8, ease: 'linear', }, }, initial: { opacity: 0, }, open: (custom) => { const { isOpen } = custom; return { opacity: isOpen ? 1 : 0, transition: { duration: 0.4, ease: 'linear', }, }; }, }; const MotionImage = motion.img; const ImageWithPlaceholder = ({ className, ...props }: HTMLMotionProps<'img'> & { placeholder?: string }) => { const nativeAspectRatio = useNativeAspectRatio(); if (!props.src) { return (
); } return ( ); }; export const FullScreenPlayerImage = () => { const mainImageRef = useRef(null); const currentSong = usePlayerSong(); const { nextSong } = usePlayerData(); const currentImageUrl = useItemImageUrl({ id: currentSong?.imageId || undefined, itemType: LibraryItem.SONG, serverId: currentSong?._serverId, type: 'fullScreenPlayer', }); const nextImageUrl = useItemImageUrl({ id: nextSong?.imageId || undefined, itemType: LibraryItem.SONG, serverId: nextSong?._serverId, type: 'fullScreenPlayer', }); const [imageState, setImageState] = useSetState({ bottomImage: nextImageUrl, current: 0, topImage: currentImageUrl, }); // Track previous song to detect changes const previousSongRef = useRef(currentSong?._uniqueId); const imageStateRef = useRef(imageState); // Keep ref in sync useEffect(() => { imageStateRef.current = imageState; }, [imageState]); // Update images when song or size changes useEffect(() => { if (currentSong?._uniqueId === previousSongRef.current) { return; } const isTop = imageStateRef.current.current === 0; setImageState({ bottomImage: isTop ? currentImageUrl : nextImageUrl, current: isTop ? 1 : 0, topImage: isTop ? nextImageUrl : currentImageUrl, }); previousSongRef.current = currentSong?._uniqueId; }, [currentSong?._uniqueId, currentImageUrl, nextSong?._uniqueId, nextImageUrl, setImageState]); return (
{imageState.current === 0 && ( )} {imageState.current === 1 && ( )}
{currentSong?.name} {currentSong?.album} {currentSong?.artists?.map((artist, index) => ( {index > 0 && ( )} {artist.name} ))} {currentSong?.container && ( {currentSong?.container} )} {currentSong?.releaseYear && ( {currentSong?.releaseYear} )}
); };