improve library header loading

This commit is contained in:
Kendall Garner 2025-06-20 17:57:15 -07:00
parent b8ceb174b3
commit b7fb7c7f94
No known key found for this signature in database
GPG key ID: 9355F387FE765C94
9 changed files with 59 additions and 61 deletions

View file

@ -18,8 +18,9 @@ import { AlbumDetailResponse, LibraryItem, ServerType } from '/@/shared/types/do
interface AlbumDetailHeaderProps {
background: {
background: string;
background?: string;
blur: number;
loading: boolean;
};
}

View file

@ -3,7 +3,7 @@ import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/li
import { useRef } from 'react';
import { useParams } from 'react-router';
import { NativeScrollArea, Spinner } from '/@/renderer/components';
import { NativeScrollArea } from '/@/renderer/components';
import { AlbumDetailContent } from '/@/renderer/features/albums/components/album-detail-content';
import { AlbumDetailHeader } from '/@/renderer/features/albums/components/album-detail-header';
import { useAlbumDetail } from '/@/renderer/features/albums/queries/album-detail-query';
@ -23,7 +23,7 @@ const AlbumDetailRoute = () => {
const { albumId } = useParams() as { albumId: string };
const server = useCurrentServer();
const detailQuery = useAlbumDetail({ query: { id: albumId }, serverId: server?.id });
const { color: backgroundColor, colorId } = useFastAverageColor({
const { background: backgroundColor, colorId } = useFastAverageColor({
id: albumId,
src: detailQuery.data?.imageUrl,
srcLoaded: !detailQuery.isLoading,
@ -41,10 +41,6 @@ const AlbumDetailRoute = () => {
});
};
if (!backgroundColor || colorId !== albumId) {
return <Spinner container />;
}
const backgroundUrl = detailQuery.data?.imageUrl || '';
const background = (albumBackground && `url(${backgroundUrl})`) || backgroundColor;
@ -70,6 +66,7 @@ const AlbumDetailRoute = () => {
background={{
background,
blur: (albumBackground && albumBackgroundBlur) || 0,
loading: !backgroundColor || colorId !== albumId,
}}
ref={headerRef}
/>

View file

@ -9,7 +9,7 @@ import { styled } from 'styled-components';
import { api } from '/@/renderer/api';
import { queryKeys } from '/@/renderer/api/query-keys';
import { Button, Spinner, Spoiler, Text } from '/@/renderer/components';
import { Button, Spoiler, Text } from '/@/renderer/components';
import { useHandleGeneralContextMenu } from '/@/renderer/features/context-menu';
import { SONG_ALBUM_PAGE } from '/@/renderer/features/context-menu/context-menu-items';
import { usePlayQueueAdd } from '/@/renderer/features/player';
@ -55,7 +55,7 @@ const DummyAlbumDetailRoute = () => {
queryKey,
});
const { color: background, colorId } = useFastAverageColor({
const { background, colorId } = useFastAverageColor({
id: albumId,
src: detailQuery.data?.imageUrl,
srcLoaded: !detailQuery.isLoading,
@ -114,10 +114,6 @@ const DummyAlbumDetailRoute = () => {
});
};
if (!background || colorId !== albumId) {
return <Spinner container />;
}
const metadataItems = [
{
id: 'releaseYear',
@ -138,6 +134,7 @@ const DummyAlbumDetailRoute = () => {
background={background}
imageUrl={detailQuery?.data?.imageUrl}
item={{ route: AppRoute.LIBRARY_SONGS, type: LibraryItem.SONG }}
loading={!background || colorId !== albumId}
title={detailQuery?.data?.name || ''}
>
<Stack spacing="sm">

View file

@ -12,11 +12,12 @@ import { formatDurationString } from '/@/renderer/utils';
import { LibraryItem, ServerType } from '/@/shared/types/domain-types';
interface AlbumArtistDetailHeaderProps {
background: string;
background?: string;
loading: boolean;
}
export const AlbumArtistDetailHeader = forwardRef(
({ background }: AlbumArtistDetailHeaderProps, ref: Ref<HTMLDivElement>) => {
({ background, loading }: AlbumArtistDetailHeaderProps, ref: Ref<HTMLDivElement>) => {
const { albumArtistId, artistId } = useParams() as {
albumArtistId?: string;
artistId?: string;
@ -76,6 +77,7 @@ export const AlbumArtistDetailHeader = forwardRef(
background={background}
imageUrl={detailQuery?.data?.imageUrl}
item={{ route: AppRoute.LIBRARY_ALBUM_ARTISTS, type: LibraryItem.ALBUM_ARTIST }}
loading={loading}
ref={ref}
title={detailQuery?.data?.name || ''}
>

View file

@ -1,7 +1,7 @@
import { useRef } from 'react';
import { useParams } from 'react-router';
import { NativeScrollArea, Spinner } from '/@/renderer/components';
import { NativeScrollArea } from '/@/renderer/components';
import { AlbumArtistDetailContent } from '/@/renderer/features/artists/components/album-artist-detail-content';
import { AlbumArtistDetailHeader } from '/@/renderer/features/artists/components/album-artist-detail-header';
import { useAlbumArtistDetail } from '/@/renderer/features/artists/queries/album-artist-detail-query';
@ -30,7 +30,7 @@ const AlbumArtistDetailRoute = () => {
query: { id: routeId },
serverId: server?.id,
});
const { color: background, colorId } = useFastAverageColor({
const { background, colorId } = useFastAverageColor({
id: routeId,
src: detailQuery.data?.imageUrl,
srcLoaded: !detailQuery.isLoading,
@ -46,10 +46,6 @@ const AlbumArtistDetailRoute = () => {
});
};
if (!background || colorId !== routeId) {
return <Spinner container />;
}
return (
<AnimatedPage key={`album-artist-detail-${routeId}`}>
<NativeScrollArea
@ -70,6 +66,7 @@ const AlbumArtistDetailRoute = () => {
>
<AlbumArtistDetailHeader
background={background}
loading={!background || colorId !== routeId}
ref={headerRef}
/>
<AlbumArtistDetailContent background={background} />

View file

@ -132,7 +132,7 @@ export const FullScreenPlayerImage = () => {
const { queue } = usePlayerData();
const { useImageAspectRatio } = useFullScreenPlayerStore();
const currentSong = queue.current;
const { color: background } = useFastAverageColor({
const { background } = useFastAverageColor({
algorithm: 'dominant',
src: queue.current?.imageUrl,
srcLoaded: true,

View file

@ -472,7 +472,7 @@ export const FullScreenPlayer = () => {
}, [location, setStore]);
const currentSong = useCurrentSong();
const { color: background } = useFastAverageColor({
const { background } = useFastAverageColor({
algorithm: 'dominant',
src: currentSong?.imageUrl,
srcLoaded: true,

View file

@ -14,18 +14,19 @@ import { useGeneralSettings } from '/@/renderer/store';
import { LibraryItem } from '/@/shared/types/domain-types';
interface LibraryHeaderProps {
background: string;
background?: string;
blur?: number;
children?: ReactNode;
imagePlaceholderUrl?: null | string;
imageUrl?: null | string;
item: { route: string; type: LibraryItem };
loading?: boolean;
title: string;
}
export const LibraryHeader = forwardRef(
(
{ background, blur, children, imageUrl, item, title }: LibraryHeaderProps,
{ background, blur, children, imageUrl, item, loading, title }: LibraryHeaderProps,
ref: Ref<HTMLDivElement>,
) => {
const { t } = useTranslation();
@ -106,7 +107,8 @@ export const LibraryHeader = forwardRef(
style={{ cursor: 'pointer' }}
tabIndex={0}
>
{imageUrl && !isImageError ? (
{!loading &&
(imageUrl && !isImageError ? (
<img
alt="cover"
className={styles.image}
@ -117,8 +119,9 @@ export const LibraryHeader = forwardRef(
/>
) : (
<ItemImagePlaceholder itemType={item.type} />
)}
))}
</div>
{title && (
<div className={styles.metadataSection}>
<Group>
<h2>
@ -138,6 +141,7 @@ export const LibraryHeader = forwardRef(
</h1>
{children}
</div>
)}
</div>
);
},

View file

@ -10,7 +10,7 @@ export const useFastAverageColor = (args: {
const { algorithm, id, src, srcLoaded } = args;
const idRef = useRef<string | undefined>(id);
const [color, setColor] = useState<string | undefined>(undefined);
const [background, setBackground] = useState<string | undefined>(undefined);
useEffect(() => {
const fac = new FastAverageColor();
@ -27,16 +27,16 @@ export const useFastAverageColor = (args: {
})
.then((color) => {
idRef.current = id;
return setColor(color.rgb);
return setBackground(color.rgb);
})
.catch((e) => {
console.log('Error fetching average color', e);
idRef.current = id;
return setColor('rgba(0, 0, 0, 0)');
return setBackground('rgba(0, 0, 0, 0)');
});
} else if (srcLoaded) {
idRef.current = id;
return setColor('var(--placeholder-bg)');
return setBackground('var(--placeholder-bg)');
}
return () => {
@ -44,5 +44,5 @@ export const useFastAverageColor = (args: {
};
}, [algorithm, srcLoaded, src, id]);
return { color, colorId: idRef.current };
return { background, colorId: idRef.current };
};