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 {
useIsRadioActive,
useRadioPlayer,
} from '/@/renderer/features/radio/hooks/use-radio-player';
import { AppRoute } from '/@/renderer/router/routes';
import {
useGeneralSettings,
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 { ExplicitStatus, 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,
explicit,
placeholderIcon = 'itemAlbum',
...props
}: HTMLMotionProps<'img'> & {
explicit?: boolean;
placeholder?: string;
placeholderIcon?: 'itemAlbum' | 'radio';
}) => {
const nativeAspectRatio = useNativeAspectRatio();
if (!props.src) {
return (
);
}
return (
);
};
export const FullScreenPlayerImage = () => {
const mainImageRef = useRef(null);
const isRadioActive = useIsRadioActive();
const { isPlaying: isRadioPlaying, metadata: radioMetadata, stationName } = useRadioPlayer();
const currentSong = usePlayerSong();
const { nextSong } = usePlayerData();
const { blurExplicitImages } = useGeneralSettings();
const isPlayingRadio = isRadioActive && isRadioPlaying;
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({
bottomExplicit: nextSong?.explicitStatus === ExplicitStatus.EXPLICIT,
bottomImage: nextImageUrl,
current: 0,
topExplicit: currentSong?.explicitStatus === ExplicitStatus.EXPLICIT,
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 (skip when playing radio - no album art)
useEffect(() => {
if (isPlayingRadio) {
return;
}
if (currentSong?._uniqueId === previousSongRef.current) {
return;
}
const isTop = imageStateRef.current.current === 0;
setImageState({
bottomExplicit:
(isTop ? currentSong?.explicitStatus : nextSong?.explicitStatus) ===
ExplicitStatus.EXPLICIT,
bottomImage: isTop ? currentImageUrl : nextImageUrl,
current: isTop ? 1 : 0,
topExplicit:
(isTop ? nextSong?.explicitStatus : currentSong?.explicitStatus) ===
ExplicitStatus.EXPLICIT,
topImage: isTop ? nextImageUrl : currentImageUrl,
});
previousSongRef.current = currentSong?._uniqueId;
}, [
isPlayingRadio,
currentSong?._uniqueId,
currentImageUrl,
nextSong?._uniqueId,
nextImageUrl,
setImageState,
currentSong?.explicitStatus,
nextSong?.explicitStatus,
]);
return (
{!isPlayingRadio && imageState.current === 0 && (
)}
{!isPlayingRadio && imageState.current === 1 && (
)}
{isPlayingRadio && (
)}
{isPlayingRadio
? radioMetadata?.title || stationName || 'Radio'
: currentSong?.name}
{isPlayingRadio ? (
{stationName || 'Radio'}
) : (
{currentSong?.album}
)}
{isPlayingRadio
? radioMetadata?.artist || stationName || 'Radio'
: currentSong?.artists?.map((artist, index) => (
{index > 0 && (
•
)}
{artist.name}
))}
{!isPlayingRadio && (
{currentSong?.container && (
{currentSong?.container}
)}
{currentSong?.releaseYear && (
{currentSong?.releaseYear}
)}
)}
);
};