mirror of
https://github.com/Suwayomi/Suwayomi-Server.git
synced 2026-07-04 11:24:35 -05:00
Merge pull request #79 from Suwayomi/read-category
Support more chapter parameters
This commit is contained in:
@@ -17,6 +17,7 @@ import ir.armor.tachidesk.model.database.table.MangaTable
|
|||||||
import ir.armor.tachidesk.model.database.table.PageTable
|
import ir.armor.tachidesk.model.database.table.PageTable
|
||||||
import ir.armor.tachidesk.model.dataclass.ChapterDataClass
|
import ir.armor.tachidesk.model.dataclass.ChapterDataClass
|
||||||
import org.jetbrains.exposed.sql.and
|
import org.jetbrains.exposed.sql.and
|
||||||
|
import org.jetbrains.exposed.sql.deleteWhere
|
||||||
import org.jetbrains.exposed.sql.insert
|
import org.jetbrains.exposed.sql.insert
|
||||||
import org.jetbrains.exposed.sql.select
|
import org.jetbrains.exposed.sql.select
|
||||||
import org.jetbrains.exposed.sql.selectAll
|
import org.jetbrains.exposed.sql.selectAll
|
||||||
@@ -66,12 +67,29 @@ object Chapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// clear any orphaned chapters that are in the db but not in `chapterList`
|
// clear any orphaned chapters that are in the db but not in `chapterList`
|
||||||
val dbChapterCount = transaction { ChapterTable.selectAll().count() }
|
val dbChapterCount = transaction { ChapterTable.select { ChapterTable.manga eq mangaId }.count() }
|
||||||
if (dbChapterCount > chapterCount) { // we got some clean up due
|
if (dbChapterCount > chapterCount) { // we got some clean up due
|
||||||
// TODO: delete orphan chapters
|
val dbChapterList = transaction { ChapterTable.select { ChapterTable.manga eq mangaId } }
|
||||||
|
|
||||||
|
dbChapterList.forEach {
|
||||||
|
if (it[ChapterTable.chapterIndex] >= chapterList.size ||
|
||||||
|
chapterList[it[ChapterTable.chapterIndex] - 1].url != it[ChapterTable.url]
|
||||||
|
) {
|
||||||
|
transaction {
|
||||||
|
PageTable.deleteWhere { PageTable.chapter eq it[ChapterTable.id] }
|
||||||
|
ChapterTable.deleteWhere { ChapterTable.id eq it[ChapterTable.id] }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val dbChapterMap = transaction { ChapterTable.selectAll() }
|
||||||
|
.associateBy({ it[ChapterTable.url] }, { it })
|
||||||
|
|
||||||
chapterList.mapIndexed { index, it ->
|
chapterList.mapIndexed { index, it ->
|
||||||
|
|
||||||
|
val dbChapter = dbChapterMap.getValue(it.url)
|
||||||
|
|
||||||
ChapterDataClass(
|
ChapterDataClass(
|
||||||
it.url,
|
it.url,
|
||||||
it.name,
|
it.name,
|
||||||
@@ -79,6 +97,11 @@ object Chapter {
|
|||||||
it.chapter_number,
|
it.chapter_number,
|
||||||
it.scanlator,
|
it.scanlator,
|
||||||
mangaId,
|
mangaId,
|
||||||
|
|
||||||
|
dbChapter[ChapterTable.isRead],
|
||||||
|
dbChapter[ChapterTable.isBookmarked],
|
||||||
|
dbChapter[ChapterTable.lastPageRead],
|
||||||
|
|
||||||
chapterCount - index,
|
chapterCount - index,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -132,6 +155,10 @@ object Chapter {
|
|||||||
chapterEntry[ChapterTable.chapter_number],
|
chapterEntry[ChapterTable.chapter_number],
|
||||||
chapterEntry[ChapterTable.scanlator],
|
chapterEntry[ChapterTable.scanlator],
|
||||||
mangaId,
|
mangaId,
|
||||||
|
chapterEntry[ChapterTable.isRead],
|
||||||
|
chapterEntry[ChapterTable.isBookmarked],
|
||||||
|
chapterEntry[ChapterTable.lastPageRead],
|
||||||
|
|
||||||
chapterEntry[ChapterTable.chapterIndex],
|
chapterEntry[ChapterTable.chapterIndex],
|
||||||
chapterCount.toInt(),
|
chapterCount.toInt(),
|
||||||
pageList.count()
|
pageList.count()
|
||||||
|
|||||||
@@ -80,11 +80,11 @@ object LegacyBackupImport : LegacyBackupBase() {
|
|||||||
return validationResult
|
return validationResult
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun restoreCategories(jsonCategories: JsonElement) { // TODO
|
private fun restoreCategories(jsonCategories: JsonElement) {
|
||||||
val backupCategories = parser.fromJson<List<CategoryImpl>>(jsonCategories)
|
val backupCategories = parser.fromJson<List<CategoryImpl>>(jsonCategories)
|
||||||
val dbCategories = getCategoryList()
|
val dbCategories = getCategoryList()
|
||||||
|
|
||||||
// Iterate over them
|
// Iterate over them and create missing categories
|
||||||
backupCategories.forEach { category ->
|
backupCategories.forEach { category ->
|
||||||
if (dbCategories.none { it.name == category.name }) {
|
if (dbCategories.none { it.name == category.name }) {
|
||||||
createCategory(category.name)
|
createCategory(category.name)
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ object CachedImageResponse {
|
|||||||
|
|
||||||
private fun findFileNameStartingWith(directoryPath: String, fileName: String): String? {
|
private fun findFileNameStartingWith(directoryPath: String, fileName: String): String? {
|
||||||
File(directoryPath).listFiles().forEach { file ->
|
File(directoryPath).listFiles().forEach { file ->
|
||||||
if (file.name.startsWith(fileName))
|
if (file.name.startsWith("$fileName."))
|
||||||
return "$directoryPath/${file.name}"
|
return "$directoryPath/${file.name}"
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
|
|||||||
@@ -10,12 +10,21 @@ package ir.armor.tachidesk.model.dataclass
|
|||||||
data class ChapterDataClass(
|
data class ChapterDataClass(
|
||||||
val url: String,
|
val url: String,
|
||||||
val name: String,
|
val name: String,
|
||||||
val date_upload: Long,
|
val uploadDate: Long,
|
||||||
val chapter_number: Float,
|
val chapterNumber: Float,
|
||||||
val scanlator: String?,
|
val scanlator: String?,
|
||||||
val mangaId: Int,
|
val mangaId: Int,
|
||||||
|
|
||||||
/** this chapter's index */
|
/** chapter is read */
|
||||||
|
val read: Boolean,
|
||||||
|
|
||||||
|
/** chapter is bookmarked */
|
||||||
|
val bookmarked: Boolean,
|
||||||
|
|
||||||
|
/** last read page, zero means not read/no data */
|
||||||
|
val lastPageRead: Int,
|
||||||
|
|
||||||
|
/** this chapter's index, starts with 1 */
|
||||||
val chapterIndex: Int? = null,
|
val chapterIndex: Int? = null,
|
||||||
|
|
||||||
/** total chapter count, used to calculate if there's a next and prev chapter */
|
/** total chapter count, used to calculate if there's a next and prev chapter */
|
||||||
|
|||||||
@@ -109,7 +109,6 @@ fun applicationSetup() {
|
|||||||
|
|
||||||
// socks proxy settings
|
// socks proxy settings
|
||||||
if (serverConfig.socksProxyEnabled) {
|
if (serverConfig.socksProxyEnabled) {
|
||||||
// System.getProperties()["proxySet"] = "true"
|
|
||||||
System.getProperties()["socksProxyHost"] = serverConfig.socksProxyHost
|
System.getProperties()["socksProxyHost"] = serverConfig.socksProxyHost
|
||||||
System.getProperties()["socksProxyPort"] = serverConfig.socksProxyPort
|
System.getProperties()["socksProxyPort"] = serverConfig.socksProxyPort
|
||||||
logger.info("Socks Proxy is enabled to ${serverConfig.socksProxyHost}:${serverConfig.socksProxyPort}")
|
logger.info("Socks Proxy is enabled to ${serverConfig.socksProxyHost}:${serverConfig.socksProxyPort}")
|
||||||
|
|||||||
@@ -3,21 +3,18 @@
|
|||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@material-ui/core": "^4.11.2",
|
"@fontsource/roboto": "^4.3.0",
|
||||||
|
"@material-ui/core": "^4.11.4",
|
||||||
"@material-ui/icons": "^4.11.2",
|
"@material-ui/icons": "^4.11.2",
|
||||||
"@testing-library/jest-dom": "^5.11.4",
|
|
||||||
"@testing-library/react": "^11.1.0",
|
|
||||||
"@testing-library/user-event": "^12.1.10",
|
|
||||||
"@types/react-lazyload": "^3.1.0",
|
|
||||||
"axios": "^0.21.1",
|
"axios": "^0.21.1",
|
||||||
"file-selector": "^0.2.4",
|
"file-selector": "^0.2.4",
|
||||||
"fontsource-roboto": "^4.0.0",
|
"react": "^17.0.2",
|
||||||
"react": "^17.0.1",
|
|
||||||
"react-beautiful-dnd": "^13.0.0",
|
"react-beautiful-dnd": "^13.0.0",
|
||||||
"react-dom": "^17.0.1",
|
"react-dom": "^17.0.2",
|
||||||
"react-lazyload": "^3.2.0",
|
"react-lazyload": "^3.2.0",
|
||||||
"react-router-dom": "^5.2.0",
|
"react-router-dom": "^5.2.0",
|
||||||
"react-scripts": "4.0.1",
|
"react-scripts": "4.0.3",
|
||||||
|
"react-virtuoso": "^1.8.6",
|
||||||
"web-vitals": "^0.2.4"
|
"web-vitals": "^0.2.4"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -39,17 +36,18 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/react": "^17.0.0",
|
"@types/react": "^17.0.2",
|
||||||
"@types/react-dom": "^17.0.0",
|
"@types/react-dom": "^17.0.2",
|
||||||
"@types/react-router-dom": "^5.1.6",
|
"@types/react-lazyload": "^3.1.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^4.11.0",
|
"@types/react-router-dom": "^5.1.7",
|
||||||
"@typescript-eslint/parser": "4.11.0",
|
"@typescript-eslint/eslint-plugin": "4.23.0",
|
||||||
"eslint": "^7.16.0",
|
"@typescript-eslint/parser": "4.23.0",
|
||||||
"eslint-config-airbnb-typescript": "^12.0.0",
|
"eslint": "^7.26.0",
|
||||||
|
"eslint-config-airbnb-typescript": "^12.3.1",
|
||||||
"eslint-plugin-import": "^2.22.1",
|
"eslint-plugin-import": "^2.22.1",
|
||||||
"eslint-plugin-jsx-a11y": "^6.4.1",
|
"eslint-plugin-jsx-a11y": "^6.4.1",
|
||||||
"eslint-plugin-react": "^7.21.5",
|
"eslint-plugin-react": "^7.23.2",
|
||||||
"eslint-plugin-react-hooks": "^4.2.0",
|
"eslint-plugin-react-hooks": "^4.2.0",
|
||||||
"typescript": "^4.1.0"
|
"typescript": "^4.2.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,12 +7,15 @@
|
|||||||
* 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 React from 'react';
|
import React from 'react';
|
||||||
import { makeStyles } from '@material-ui/core/styles';
|
import { makeStyles, useTheme } from '@material-ui/core/styles';
|
||||||
import Card from '@material-ui/core/Card';
|
import Card from '@material-ui/core/Card';
|
||||||
import CardContent from '@material-ui/core/CardContent';
|
import CardContent from '@material-ui/core/CardContent';
|
||||||
import Button from '@material-ui/core/Button';
|
import IconButton from '@material-ui/core/IconButton';
|
||||||
|
import MoreVertIcon from '@material-ui/icons/MoreVert';
|
||||||
import Typography from '@material-ui/core/Typography';
|
import Typography from '@material-ui/core/Typography';
|
||||||
import { Link, useHistory } from 'react-router-dom';
|
import { Link, useHistory } from 'react-router-dom';
|
||||||
|
import Menu from '@material-ui/core/Menu';
|
||||||
|
import MenuItem from '@material-ui/core/MenuItem';
|
||||||
|
|
||||||
const useStyles = makeStyles((theme) => ({
|
const useStyles = makeStyles((theme) => ({
|
||||||
root: {
|
root: {
|
||||||
@@ -47,41 +50,63 @@ interface IProps{
|
|||||||
export default function ChapterCard(props: IProps) {
|
export default function ChapterCard(props: IProps) {
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
|
const theme = useTheme();
|
||||||
const { chapter } = props;
|
const { chapter } = props;
|
||||||
|
|
||||||
const dateStr = chapter.date_upload && new Date(chapter.date_upload).toISOString().slice(0, 10);
|
const dateStr = chapter.uploadDate && new Date(chapter.uploadDate).toISOString().slice(0, 10);
|
||||||
|
|
||||||
|
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
|
||||||
|
|
||||||
|
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
|
||||||
|
setAnchorEl(event.currentTarget);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleClose = () => {
|
||||||
|
setAnchorEl(null);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<li>
|
<li>
|
||||||
<Card>
|
<Card>
|
||||||
<CardContent className={classes.root}>
|
<CardContent className={classes.root}>
|
||||||
<div style={{ display: 'flex' }}>
|
|
||||||
<div style={{ display: 'flex', flexDirection: 'column' }}>
|
|
||||||
<Typography variant="h5" component="h2">
|
|
||||||
{chapter.name}
|
|
||||||
{chapter.chapter_number > 0 && ` : ${chapter.chapter_number}`}
|
|
||||||
</Typography>
|
|
||||||
<Typography variant="caption" display="block" gutterBottom>
|
|
||||||
{chapter.scanlator}
|
|
||||||
{chapter.scanlator && ' '}
|
|
||||||
{dateStr}
|
|
||||||
</Typography>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<Link
|
<Link
|
||||||
to={`/manga/${chapter.mangaId}/chapter/${chapter.chapterIndex}`}
|
to={`/manga/${chapter.mangaId}/chapter/${chapter.chapterIndex}`}
|
||||||
style={{ textDecoration: 'none' }}
|
style={{
|
||||||
|
textDecoration: 'none',
|
||||||
|
color: theme.palette.text.primary,
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<Button
|
<div style={{ display: 'flex' }}>
|
||||||
variant="outlined"
|
<div style={{ display: 'flex', flexDirection: 'column' }}>
|
||||||
style={{ marginLeft: 20 }}
|
|
||||||
>
|
|
||||||
open
|
|
||||||
|
|
||||||
</Button>
|
<Typography variant="h5" component="h2">
|
||||||
|
{chapter.name}
|
||||||
|
{chapter.chapterNumber > 0 && ` : ${chapter.chapterNumber}`}
|
||||||
|
</Typography>
|
||||||
|
<Typography variant="caption" display="block" gutterBottom>
|
||||||
|
{chapter.scanlator}
|
||||||
|
{chapter.scanlator && ' '}
|
||||||
|
{dateStr}
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
|
<IconButton aria-label="more" onClick={handleClick}>
|
||||||
|
<MoreVertIcon />
|
||||||
|
</IconButton>
|
||||||
|
<Menu
|
||||||
|
anchorEl={anchorEl}
|
||||||
|
keepMounted
|
||||||
|
open={Boolean(anchorEl)}
|
||||||
|
onClose={handleClose}
|
||||||
|
>
|
||||||
|
{/* <MenuItem onClick={handleClose}>Download</MenuItem> */}
|
||||||
|
<MenuItem onClick={handleClose}>Bookmark</MenuItem>
|
||||||
|
<MenuItem onClick={handleClose}>Mark as Read</MenuItem>
|
||||||
|
<MenuItem onClick={handleClose}>Mark previous as Read</MenuItem>
|
||||||
|
</Menu>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import ReactDOM from 'react-dom';
|
|||||||
import App from './App';
|
import App from './App';
|
||||||
import './index.css';
|
import './index.css';
|
||||||
// roboto font
|
// roboto font
|
||||||
import 'fontsource-roboto';
|
import '@fontsource/roboto';
|
||||||
|
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<React.StrictMode>
|
<React.StrictMode>
|
||||||
|
|||||||
@@ -7,9 +7,9 @@
|
|||||||
* 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 React, { useEffect, useState, useContext } from 'react';
|
import React, { useEffect, useState, useContext } from 'react';
|
||||||
import { makeStyles, Theme } from '@material-ui/core/styles';
|
import { makeStyles, Theme, useTheme } from '@material-ui/core/styles';
|
||||||
import { useParams } from 'react-router-dom';
|
import { useParams } from 'react-router-dom';
|
||||||
import CircularProgress from '@material-ui/core/CircularProgress';
|
import { Virtuoso } from 'react-virtuoso';
|
||||||
import ChapterCard from '../components/ChapterCard';
|
import ChapterCard from '../components/ChapterCard';
|
||||||
import MangaDetails from '../components/MangaDetails';
|
import MangaDetails from '../components/MangaDetails';
|
||||||
import NavbarContext from '../context/NavbarContext';
|
import NavbarContext from '../context/NavbarContext';
|
||||||
@@ -41,13 +41,18 @@ const useStyles = makeStyles((theme: Theme) => ({
|
|||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
const InnerItem = React.memo(({ chapters, index }: any) => (
|
||||||
|
<ChapterCard chapter={chapters[index]} />
|
||||||
|
));
|
||||||
|
|
||||||
export default function Manga() {
|
export default function Manga() {
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
|
const theme = useTheme();
|
||||||
|
|
||||||
const { setTitle } = useContext(NavbarContext);
|
const { setTitle } = useContext(NavbarContext);
|
||||||
useEffect(() => { setTitle('Manga'); }, []); // delegate setting topbar action to MangaDetails
|
useEffect(() => { setTitle('Manga'); }, []); // delegate setting topbar action to MangaDetails
|
||||||
|
|
||||||
const { id } = useParams<{id: string}>();
|
const { id } = useParams<{ id: string }>();
|
||||||
|
|
||||||
const [manga, setManga] = useState<IManga>();
|
const [manga, setManga] = useState<IManga>();
|
||||||
const [chapters, setChapters] = useState<IChapter[]>([]);
|
const [chapters, setChapters] = useState<IChapter[]>([]);
|
||||||
@@ -67,16 +72,7 @@ export default function Manga() {
|
|||||||
.then((data) => setChapters(data));
|
.then((data) => setChapters(data));
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const chapterCards = (
|
const itemContent = (index:any) => <InnerItem chapters={chapters} index={index} />;
|
||||||
<LoadingPlaceholder
|
|
||||||
shouldRender={chapters.length > 0}
|
|
||||||
>
|
|
||||||
<ol className={classes.chapters}>
|
|
||||||
{chapters.map((chapter) => (<ChapterCard chapter={chapter} />))}
|
|
||||||
</ol>
|
|
||||||
</LoadingPlaceholder>
|
|
||||||
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classes.root}>
|
<div className={classes.root}>
|
||||||
@@ -85,7 +81,25 @@ export default function Manga() {
|
|||||||
component={MangaDetails}
|
component={MangaDetails}
|
||||||
componentProps={{ manga }}
|
componentProps={{ manga }}
|
||||||
/>
|
/>
|
||||||
{chapterCards}
|
|
||||||
|
<LoadingPlaceholder
|
||||||
|
shouldRender={chapters.length > 0}
|
||||||
|
>
|
||||||
|
{/* <ol >
|
||||||
|
{chapters.map((chapter) => ())}
|
||||||
|
</ol> */}
|
||||||
|
<Virtuoso
|
||||||
|
style={{ // override Virtuoso default values and set them with class
|
||||||
|
height: 'undefined',
|
||||||
|
}}
|
||||||
|
className={classes.chapters}
|
||||||
|
totalCount={chapters.length}
|
||||||
|
itemContent={itemContent}
|
||||||
|
useWindowScroll={window.innerWidth < 960}
|
||||||
|
overscan={window.innerHeight * 0.5}
|
||||||
|
/>
|
||||||
|
</LoadingPlaceholder>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ export default function Reader() {
|
|||||||
|
|
||||||
const [serverAddress] = useLocalStorage<String>('serverBaseURL', '');
|
const [serverAddress] = useLocalStorage<String>('serverBaseURL', '');
|
||||||
|
|
||||||
const { chapterIndex, mangaId } = useParams<{chapterIndex: string, mangaId: string}>();
|
const { chapterIndex, mangaId } = useParams<{ chapterIndex: string, mangaId: string }>();
|
||||||
const [manga, setManga] = useState<IMangaCard | IManga>({ id: +mangaId, title: '', thumbnailUrl: '' });
|
const [manga, setManga] = useState<IMangaCard | IManga>({ id: +mangaId, title: '', thumbnailUrl: '' });
|
||||||
const [chapter, setChapter] = useState<IChapter | IPartialChpter>(initialChapter());
|
const [chapter, setChapter] = useState<IChapter | IPartialChpter>(initialChapter());
|
||||||
const [curPage, setCurPage] = useState<number>(0);
|
const [curPage, setCurPage] = useState<number>(0);
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ export default function SearchSingle() {
|
|||||||
const { setTitle, setAction } = useContext(NavbarContext);
|
const { setTitle, setAction } = useContext(NavbarContext);
|
||||||
useEffect(() => { setTitle('Search'); setAction(<></>); }, []);
|
useEffect(() => { setTitle('Search'); setAction(<></>); }, []);
|
||||||
|
|
||||||
const { sourceId } = useParams<{sourceId: string}>();
|
const { sourceId } = useParams<{ sourceId: string }>();
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
const [error, setError] = useState<boolean>(false);
|
const [error, setError] = useState<boolean>(false);
|
||||||
const [mangas, setMangas] = useState<IMangaCard[]>([]);
|
const [mangas, setMangas] = useState<IMangaCard[]>([]);
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ export default function SourceMangas(props: { popular: boolean }) {
|
|||||||
const { setTitle, setAction } = useContext(NavbarContext);
|
const { setTitle, setAction } = useContext(NavbarContext);
|
||||||
useEffect(() => { setTitle('Source'); setAction(<></>); }, []);
|
useEffect(() => { setTitle('Source'); setAction(<></>); }, []);
|
||||||
|
|
||||||
const { sourceId } = useParams<{sourceId: string}>();
|
const { sourceId } = useParams<{ sourceId: string }>();
|
||||||
const [mangas, setMangas] = useState<IMangaCard[]>([]);
|
const [mangas, setMangas] = useState<IMangaCard[]>([]);
|
||||||
const [hasNextPage, setHasNextPage] = useState<boolean>(false);
|
const [hasNextPage, setHasNextPage] = useState<boolean>(false);
|
||||||
const [lastPageNum, setLastPageNum] = useState<number>(1);
|
const [lastPageNum, setLastPageNum] = useState<number>(1);
|
||||||
|
|||||||
7
webUI/react/src/typings.d.ts
vendored
7
webUI/react/src/typings.d.ts
vendored
@@ -56,10 +56,13 @@ interface IChapter {
|
|||||||
id: number
|
id: number
|
||||||
url: string
|
url: string
|
||||||
name: string
|
name: string
|
||||||
date_upload: number
|
uploadDate: number
|
||||||
chapter_number: number
|
chapterNumber: number
|
||||||
scanlator: String
|
scanlator: String
|
||||||
mangaId: number
|
mangaId: number
|
||||||
|
read: boolean
|
||||||
|
bookmarked: boolean
|
||||||
|
lastPageRead: number
|
||||||
chapterIndex: number
|
chapterIndex: number
|
||||||
chapterCount: number
|
chapterCount: number
|
||||||
pageCount: number
|
pageCount: number
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user