diff --git a/src/features/manga/components/details/Thumbnail.tsx b/src/features/manga/components/details/Thumbnail.tsx index 42aad417..ba7af5c0 100644 --- a/src/features/manga/components/details/Thumbnail.tsx +++ b/src/features/manga/components/details/Thumbnail.tsx @@ -20,6 +20,8 @@ import { MANGA_COVER_ASPECT_RATIO } from '@/features/manga/Manga.constants.ts'; import { MangaThumbnailInfo } from '@/features/manga/Manga.types.ts'; import { useAppThemeContext } from '@/features/theme/AppThemeContext.tsx'; import { TAppThemeContext } from '@/features/theme/AppTheme.types.ts'; +import { ImageRequest, requestManager } from '@/lib/requests/RequestManager.ts'; +import { noOp } from '@/lib/HelperFunctions.ts'; export const Thumbnail = ({ manga, @@ -35,51 +37,67 @@ export const Thumbnail = ({ const [isImageReady, setIsImageReady] = useState(false); + const url = Mangas.getThumbnailUrl(manga); + useLayoutEffect(() => { if (!mangaDynamicColorSchemes) { return () => {}; } - const img = new Image(); - img.crossOrigin = 'anonymous'; - img.src = Mangas.getThumbnailUrl(manga); - - img.onload = () => { - const isLargeImage = img.width > 600 && img.height > 900; - - Promise.all([ - Vibrant.from(img).getPalette(), - new FastAverageColor().getColor(img, { - algorithm: 'dominant', - mode: isLargeImage ? 'speed' : 'precision', - ignoredColor: [ - [255, 255, 255, 255, 75], - [0, 0, 0, 255, 75], - ], - }), - ]).then(([palette, averageColor]) => { - if ( - !palette.Vibrant || - !palette.DarkVibrant || - !palette.LightVibrant || - !palette.LightMuted || - !palette.Muted || - !palette.DarkMuted - ) { - return; - } - - setDynamicColor({ - ...palette, - average: averageColor, - } as TAppThemeContext['dynamicColor']); - }); + let imageRequest: ImageRequest = { + response: Promise.resolve(''), + cleanup: noOp, + abortRequest: noOp, + fromCache: false, }; + const fetchImage = async () => { + imageRequest = await requestManager.requestImage(url); + const image = await imageRequest.response; + + const img = new Image(); + img.crossOrigin = 'anonymous'; + img.src = image; + + img.onload = () => { + const isLargeImage = img.width > 600 && img.height > 900; + + Promise.all([ + Vibrant.from(img).getPalette(), + new FastAverageColor().getColor(img, { + algorithm: 'dominant', + mode: isLargeImage ? 'speed' : 'precision', + ignoredColor: [ + [255, 255, 255, 255, 75], + [0, 0, 0, 255, 75], + ], + }), + ]).then(([palette, averageColor]) => { + if ( + !palette.Vibrant || + !palette.DarkVibrant || + !palette.LightVibrant || + !palette.LightMuted || + !palette.Muted || + !palette.DarkMuted + ) { + return; + } + + setDynamicColor({ + ...palette, + average: averageColor, + } as TAppThemeContext['dynamicColor']); + }); + }; + }; + + fetchImage().catch(() => {}); return () => { + imageRequest.cleanup(); setDynamicColor(null); }; - }, []); + }, [url, mangaDynamicColorSchemes]); return ( <> @@ -105,7 +123,7 @@ export const Thumbnail = ({ }} > setIsImageReady(true)} imgStyle={{ width: '100%', height: '100%', objectFit: 'cover' }} @@ -138,7 +156,7 @@ export const Thumbnail = ({ sx={{ height: '100vh', p: 2, outline: 0, justifyContent: 'center', alignItems: 'center' }} >