spinner image, closes #77

This commit is contained in:
Aria Moradi 2021-05-28 19:37:26 +04:30
parent 1b122d1157
commit 1a99ec76e4
4 changed files with 93 additions and 55 deletions

View File

@ -0,0 +1,67 @@
/*
* Copyright (C) Contributors to the Suwayomi project
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
import React, { useEffect, useState } from 'react';
import CircularProgress from '@material-ui/core/CircularProgress';
interface IProps {
src: string
alt: string
imgRef?: React.RefObject<HTMLImageElement>
spinnerClassName?: string
imgClassName?: string
onImageLoad?: () => void
}
export default function SpinnerImage(props: IProps) {
const {
src, alt, onImageLoad, imgRef, spinnerClassName, imgClassName,
} = props;
const [imageSrc, setImagsrc] = useState<string>('');
useEffect(() => {
const img = new Image();
img.src = src;
img.onload = () => {
setImagsrc(src);
onImageLoad?.();
};
return () => {
img.onload = null;
};
}, [src]);
if (imageSrc.length === 0) {
return (
// <div className={`${classes.image} ${classes.loadingImage}`}>
<div className={spinnerClassName}>
<CircularProgress thickness={5} />
</div>
);
}
return (
<img
className={imgClassName}
ref={imgRef}
src={imageSrc}
alt={alt}
/>
);
}
SpinnerImage.defaultProps = {
spinnerClassName: '',
imgClassName: '',
onImageLoad: () => {},
imgRef: undefined,
};

View File

@ -9,11 +9,11 @@ import React from 'react';
import { makeStyles } from '@material-ui/core/styles'; import { makeStyles } from '@material-ui/core/styles';
import Card from '@material-ui/core/Card'; import Card from '@material-ui/core/Card';
import CardActionArea from '@material-ui/core/CardActionArea'; import CardActionArea from '@material-ui/core/CardActionArea';
import CardMedia from '@material-ui/core/CardMedia';
import Typography from '@material-ui/core/Typography'; import Typography from '@material-ui/core/Typography';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { Grid } from '@material-ui/core'; import { Grid } from '@material-ui/core';
import useLocalStorage from 'util/useLocalStorage'; import useLocalStorage from 'util/useLocalStorage';
import SpinnerImage from 'components/SpinnerImage';
const useStyles = makeStyles({ const useStyles = makeStyles({
root: { root: {
@ -43,6 +43,11 @@ const useStyles = makeStyles({
height: '100%', height: '100%',
width: '100%', width: '100%',
}, },
spinner: {
minHeight: '400px',
padding: '180px calc(50% - 20px)',
},
}); });
interface IProps { interface IProps {
@ -63,12 +68,11 @@ const MangaCard = React.forwardRef((props: IProps, ref) => {
<Card className={classes.root} ref={ref}> <Card className={classes.root} ref={ref}>
<CardActionArea> <CardActionArea>
<div className={classes.wrapper}> <div className={classes.wrapper}>
<CardMedia <SpinnerImage
className={classes.image}
component="img"
alt={title} alt={title}
image={serverAddress + thumbnailUrl} src={serverAddress + thumbnailUrl}
title={title} spinnerClassName={classes.spinner}
imgClassName={classes.image}
/> />
<div className={classes.gradient} /> <div className={classes.gradient} />
<Typography className={classes.title} variant="h5" component="h2">{title}</Typography> <Typography className={classes.title} variant="h5" component="h2">{title}</Typography>

View File

@ -5,10 +5,10 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
import CircularProgress from '@material-ui/core/CircularProgress';
import { makeStyles } from '@material-ui/core/styles'; import { makeStyles } from '@material-ui/core/styles';
import { CSSProperties } from '@material-ui/core/styles/withStyles'; import { CSSProperties } from '@material-ui/core/styles/withStyles';
import React, { useEffect, useRef, useState } from 'react'; import React, { useEffect, useRef } from 'react';
import SpinnerImage from 'components/SpinnerImage';
function imageStyle(settings: IReaderSettings): CSSProperties { function imageStyle(settings: IReaderSettings): CSSProperties {
if (settings.readerType === 'DoubleLTR' || settings.readerType === 'DoubleRTL') { if (settings.readerType === 'DoubleLTR' || settings.readerType === 'DoubleRTL') {
@ -56,18 +56,17 @@ interface IProps {
settings: IReaderSettings settings: IReaderSettings
} }
function LazyImage(props: IProps) { const Page = React.forwardRef((props: IProps, ref: any) => {
const { const {
src, index, onImageLoad, setCurPage, settings, src, index, onImageLoad, setCurPage, settings,
} = props; } = props;
const classes = useStyles(settings)(); const classes = useStyles(settings)();
const [imageSrc, setImagsrc] = useState<string>(''); const imgRef = useRef<HTMLImageElement>(null);
const ref = useRef<HTMLImageElement>(null);
const handleScroll = () => { const handleScroll = () => {
if (ref.current) { if (imgRef.current) {
const rect = ref.current.getBoundingClientRect(); const rect = imgRef.current.getBoundingClientRect();
if (rect.y < 0 && rect.y + rect.height > 0) { if (rect.y < 0 && rect.y + rect.height > 0) {
setCurPage(index); setCurPage(index);
} }
@ -84,51 +83,15 @@ function LazyImage(props: IProps) {
} return () => {}; } return () => {};
}, [handleScroll]); }, [handleScroll]);
useEffect(() => {
const img = new Image();
img.src = src;
img.onload = () => {
setImagsrc(src);
onImageLoad();
};
return () => {
img.onload = null;
};
}, [src]);
if (imageSrc.length === 0) {
return (
<div className={`${classes.image} ${classes.loadingImage}`}>
<CircularProgress thickness={5} />
</div>
);
}
return (
<img
className={classes.image}
ref={ref}
src={imageSrc}
alt={`Page #${index}`}
/>
);
}
const Page = React.forwardRef((props: IProps, ref: any) => {
const {
src, index, onImageLoad, setCurPage, settings,
} = props;
return ( return (
<div ref={ref} style={{ margin: '0 auto' }}> <div ref={ref} style={{ margin: '0 auto' }}>
<LazyImage <SpinnerImage
src={src} src={src}
index={index}
onImageLoad={onImageLoad} onImageLoad={onImageLoad}
setCurPage={setCurPage} alt={`Page #${index}`}
settings={settings} imgRef={imgRef}
spinnerClassName={`${classes.image} ${classes.loadingImage}`}
imgClassName={classes.image}
/> />
</div> </div>
); );

View File

@ -29,6 +29,10 @@ export default function VerticalReader(props: IReaderProps) {
const selfRef = useRef<HTMLDivElement>(null); const selfRef = useRef<HTMLDivElement>(null);
const pagesRef = useRef<HTMLDivElement[]>([]); const pagesRef = useRef<HTMLDivElement[]>([]);
useEffect(() => {
pagesRef.current = pagesRef.current.slice(0, pages.length);
}, [pages.length]);
function nextPage() { function nextPage() {
if (curPage < pages.length - 1) { if (curPage < pages.length - 1) {
pagesRef.current[curPage + 1]?.scrollIntoView(); pagesRef.current[curPage + 1]?.scrollIntoView();
@ -104,7 +108,7 @@ export default function VerticalReader(props: IReaderProps) {
if (initialPage > -1) { if (initialPage > -1) {
pagesRef.current[initialPage].scrollIntoView(); pagesRef.current[initialPage].scrollIntoView();
} }
}, []); }, [pagesRef.current.length]);
return ( return (
<div ref={selfRef} className={classes.reader}> <div ref={selfRef} className={classes.reader}>