diff --git a/src/renderer/features/albums/routes/album-detail-route.tsx b/src/renderer/features/albums/routes/album-detail-route.tsx index 66d57d49..cf069ce7 100644 --- a/src/renderer/features/albums/routes/album-detail-route.tsx +++ b/src/renderer/features/albums/routes/album-detail-route.tsx @@ -1,4 +1,4 @@ -import { NativeScrollArea } from '/@/renderer/components'; +import { NativeScrollArea, Spinner } from '/@/renderer/components'; import { AnimatedPage, LibraryHeaderBar } from '/@/renderer/features/shared'; import { useRef } from 'react'; import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/lib/agGridReact'; @@ -20,7 +20,11 @@ const AlbumDetailRoute = () => { const { albumId } = useParams() as { albumId: string }; const server = useCurrentServer(); const detailQuery = useAlbumDetail({ query: { id: albumId }, serverId: server?.id }); - const background = useFastAverageColor(detailQuery.data?.imageUrl, !detailQuery.isLoading); + const { color: background, colorId } = useFastAverageColor({ + id: albumId, + src: detailQuery.data?.imageUrl, + srcLoaded: !detailQuery.isLoading, + }); const handlePlayQueueAdd = usePlayQueueAdd(); const playButtonBehavior = usePlayButtonBehavior(); @@ -34,7 +38,9 @@ const AlbumDetailRoute = () => { }); }; - if (!background) return null; + if (!background || colorId !== albumId) { + return ; + } return ( diff --git a/src/renderer/features/artists/routes/album-artist-detail-route.tsx b/src/renderer/features/artists/routes/album-artist-detail-route.tsx index 5f8f9bb0..6d60499b 100644 --- a/src/renderer/features/artists/routes/album-artist-detail-route.tsx +++ b/src/renderer/features/artists/routes/album-artist-detail-route.tsx @@ -1,4 +1,4 @@ -import { NativeScrollArea } from '/@/renderer/components'; +import { NativeScrollArea, Spinner } from '/@/renderer/components'; import { AnimatedPage, LibraryHeaderBar } from '/@/renderer/features/shared'; import { useRef } from 'react'; import { useParams } from 'react-router'; @@ -23,7 +23,11 @@ const AlbumArtistDetailRoute = () => { query: { id: albumArtistId }, serverId: server?.id, }); - const background = useFastAverageColor(detailQuery.data?.imageUrl, !detailQuery.isLoading); + const { color, colorId } = useFastAverageColor({ + id: albumArtistId, + src: detailQuery.data?.imageUrl, + srcLoaded: !detailQuery.isLoading, + }); const handlePlay = () => { handlePlayQueueAdd?.({ @@ -35,14 +39,16 @@ const AlbumArtistDetailRoute = () => { }); }; - if (detailQuery.isLoading || !background) return null; + if (detailQuery.isLoading || !color || colorId !== albumArtistId) { + return ; + } return ( @@ -57,9 +63,9 @@ const AlbumArtistDetailRoute = () => { > - + ); diff --git a/src/renderer/features/player/components/full-screen-player-image.tsx b/src/renderer/features/player/components/full-screen-player-image.tsx index b8991c1f..61ab8b49 100644 --- a/src/renderer/features/player/components/full-screen-player-image.tsx +++ b/src/renderer/features/player/components/full-screen-player-image.tsx @@ -122,7 +122,11 @@ export const FullScreenPlayerImage = () => { const { queue } = usePlayerData(); const useImageAspectRatio = useFullScreenPlayerStore((state) => state.useImageAspectRatio); const currentSong = queue.current; - const background = useFastAverageColor(queue.current?.imageUrl, true, 'dominant'); + const { color: background } = useFastAverageColor({ + algorithm: 'dominant', + src: queue.current?.imageUrl, + srcLoaded: true, + }); const imageKey = `image-${background}`; const [imageState, setImageState] = useSetState({ diff --git a/src/renderer/features/player/components/full-screen-player.tsx b/src/renderer/features/player/components/full-screen-player.tsx index 8ecbae91..c40b96f9 100644 --- a/src/renderer/features/player/components/full-screen-player.tsx +++ b/src/renderer/features/player/components/full-screen-player.tsx @@ -193,7 +193,11 @@ export const FullScreenPlayer = () => { }, [location, setStore]); const currentSong = useCurrentSong(); - const background = useFastAverageColor(currentSong?.imageUrl, true, 'dominant'); + const { color: background } = useFastAverageColor({ + algorithm: 'dominant', + src: currentSong?.imageUrl, + srcLoaded: true, + }); return ( { @@ -166,7 +160,6 @@ export const PlaylistDetailContent = ({ tableRef }: PlaylistDetailContentProps) return ( @@ -217,12 +210,13 @@ export const PlaylistDetailContent = ({ tableRef }: PlaylistDetailContentProps) - + { const server = useCurrentServer(); const detailQuery = usePlaylistDetail({ query: { id: playlistId }, serverId: server?.id }); - const background = useFastAverageColor( - detailQuery?.data?.imageUrl, - !detailQuery?.isLoading, - 'sqrt', - ); + const { color: background, colorId } = useFastAverageColor({ + algorithm: 'sqrt', + id: playlistId, + src: detailQuery?.data?.imageUrl, + srcLoaded: !detailQuery?.isLoading, + }); const handlePlayQueueAdd = usePlayQueueAdd(); const playButtonBehavior = usePlayButtonBehavior(); @@ -39,7 +40,9 @@ const PlaylistDetailRoute = () => { }); }; - if (!background) return null; + if (!background || colorId !== playlistId) { + return ; + } return ( @@ -55,6 +58,7 @@ const PlaylistDetailRoute = () => { ), + offset: 200, target: headerRef, }} > diff --git a/src/renderer/hooks/use-fast-average-color.tsx b/src/renderer/hooks/use-fast-average-color.tsx index 6f37f75f..d1ae342f 100644 --- a/src/renderer/hooks/use-fast-average-color.tsx +++ b/src/renderer/hooks/use-fast-average-color.tsx @@ -1,11 +1,15 @@ -import { useEffect, useState } from 'react'; +import { useEffect, useRef, useState } from 'react'; import { FastAverageColor } from 'fast-average-color'; -export const useFastAverageColor = ( - src?: string | null, - srcLoaded?: boolean, - aglorithm?: 'dominant' | 'simple' | 'sqrt', -) => { +export const useFastAverageColor = (args: { + algorithm?: 'dominant' | 'simple' | 'sqrt'; + id?: string; + src?: string | null; + srcLoaded?: boolean; +}) => { + const { algorithm, src, srcLoaded, id } = args; + const idRef = useRef(id); + const [color, setColor] = useState(undefined); useEffect(() => { @@ -13,7 +17,7 @@ export const useFastAverageColor = ( if (src && srcLoaded) { fac.getColorAsync(src, { - algorithm: aglorithm || 'dominant', + algorithm: algorithm || 'dominant', ignoredColor: [ [255, 255, 255, 255, 90], // White [0, 0, 0, 255, 30], // Black @@ -22,10 +26,12 @@ export const useFastAverageColor = ( mode: 'precision', }) .then((color) => { + idRef.current = id; return setColor(color.rgb); }) .catch((e) => { console.log('Error fetching average color', e); + idRef.current = id; return setColor('rgba(0, 0, 0, 0)'); }); } else if (srcLoaded) { @@ -35,7 +41,7 @@ export const useFastAverageColor = ( return () => { fac.destroy(); }; - }, [aglorithm, srcLoaded, src]); + }, [algorithm, srcLoaded, src, id]); - return color; + return { color, colorId: idRef.current }; };