diff --git a/server/src/main/kotlin/ir/armor/tachidesk/Main.kt b/server/src/main/kotlin/ir/armor/tachidesk/Main.kt index fbc29c4..d0e1d1a 100644 --- a/server/src/main/kotlin/ir/armor/tachidesk/Main.kt +++ b/server/src/main/kotlin/ir/armor/tachidesk/Main.kt @@ -119,10 +119,11 @@ class Main { } // single source search - app.get("/api/v1/source/:sourceId/search/:searchTerm") { ctx -> + app.get("/api/v1/source/:sourceId/search/:searchTerm/:pageNum") { ctx -> val sourceId = ctx.pathParam("sourceId").toLong() val searchTerm = ctx.pathParam("searchTerm") - ctx.json(sourceSearch(sourceId, searchTerm)) + val pageNum = ctx.pathParam("pageNum").toInt() + ctx.json(sourceSearch(sourceId, searchTerm, pageNum)) } // source filter list diff --git a/server/src/main/kotlin/ir/armor/tachidesk/database/dataclass/MangaDataClass.kt b/server/src/main/kotlin/ir/armor/tachidesk/database/dataclass/MangaDataClass.kt index 2d921c6..0ef9b40 100644 --- a/server/src/main/kotlin/ir/armor/tachidesk/database/dataclass/MangaDataClass.kt +++ b/server/src/main/kotlin/ir/armor/tachidesk/database/dataclass/MangaDataClass.kt @@ -8,7 +8,7 @@ data class MangaDataClass( val url: String, val title: String, - val thumbnail_url: String? = null, + val thumbnailUrl: String? = null, val initialized: Boolean = false, diff --git a/server/src/main/kotlin/ir/armor/tachidesk/util/MangaList.kt b/server/src/main/kotlin/ir/armor/tachidesk/util/MangaList.kt index 1ec874d..d881a35 100644 --- a/server/src/main/kotlin/ir/armor/tachidesk/util/MangaList.kt +++ b/server/src/main/kotlin/ir/armor/tachidesk/util/MangaList.kt @@ -1,5 +1,6 @@ package ir.armor.tachidesk.util +import eu.kanade.tachiyomi.source.model.MangasPage import ir.armor.tachidesk.database.dataclass.MangaDataClass import ir.armor.tachidesk.database.table.MangaStatus import ir.armor.tachidesk.database.table.MangaTable @@ -17,6 +18,11 @@ fun getMangaList(sourceId: Long, pageNum: Int = 1, popular: Boolean): List { + val mangasPage = this return transaction { return@transaction mangasPage.mangas.map { manga -> var mangaEntry = MangaTable.select { MangaTable.url eq manga.url }.firstOrNull() diff --git a/server/src/main/kotlin/ir/armor/tachidesk/util/Search.kt b/server/src/main/kotlin/ir/armor/tachidesk/util/Search.kt index 906dbba..4947f97 100644 --- a/server/src/main/kotlin/ir/armor/tachidesk/util/Search.kt +++ b/server/src/main/kotlin/ir/armor/tachidesk/util/Search.kt @@ -1,13 +1,16 @@ package ir.armor.tachidesk.util +import ir.armor.tachidesk.database.dataclass.MangaDataClass + fun sourceFilters(sourceId: Long) { val source = getHttpSource(sourceId) // source.getFilterList().toItems() } -fun sourceSearch(sourceId: Long, searchTerm: String) { +fun sourceSearch(sourceId: Long, searchTerm: String, pageNum: Int): List { val source = getHttpSource(sourceId) - // source.fetchSearchManga() + val searchManga = source.fetchSearchManga(pageNum, searchTerm, source.getFilterList()).toBlocking().first() + return searchManga.processEntries(sourceId) } fun sourceGlobalSearch(searchTerm: String) { @@ -18,7 +21,7 @@ data class FilterWrapper( val filter: Any ) -// private fun FilterList.toItems(): List { +// private fun FilterList.toFilterWrapper(): List { // return mapNotNull { filter -> // when (filter) { // is Filter.Header -> FilterWrapper("Header",filter) diff --git a/webUI/react/src/App.tsx b/webUI/react/src/App.tsx index ffe4465..81da291 100644 --- a/webUI/react/src/App.tsx +++ b/webUI/react/src/App.tsx @@ -9,7 +9,7 @@ import Extensions from './screens/Extensions'; import MangaList from './screens/MangaList'; import Manga from './screens/Manga'; import Reader from './screens/Reader'; -import Search from './screens/Search'; +import Search from './screens/SearchSingle'; import NavBarTitle from './context/NavbarTitle'; export default function App() { @@ -22,7 +22,7 @@ export default function App() { - + diff --git a/webUI/react/src/components/SourceCard.tsx b/webUI/react/src/components/SourceCard.tsx index cc534e7..ceb139d 100644 --- a/webUI/react/src/components/SourceCard.tsx +++ b/webUI/react/src/components/SourceCard.tsx @@ -65,8 +65,9 @@ export default function SourceCard(props: IProps) {
- {supportsLatest && } - + + {supportsLatest && } +
diff --git a/webUI/react/src/components/TemporaryDrawer.tsx b/webUI/react/src/components/TemporaryDrawer.tsx index 6895d4b..93b9244 100644 --- a/webUI/react/src/components/TemporaryDrawer.tsx +++ b/webUI/react/src/components/TemporaryDrawer.tsx @@ -48,14 +48,14 @@ export default function TemporaryDrawer({ drawerOpen, setDrawerOpen }: IProps) { - + {/* - + */} ); diff --git a/webUI/react/src/screens/MangaList.tsx b/webUI/react/src/screens/MangaList.tsx index 4a547c1..fd44c62 100644 --- a/webUI/react/src/screens/MangaList.tsx +++ b/webUI/react/src/screens/MangaList.tsx @@ -19,8 +19,8 @@ export default function MangaList(props: { popular: boolean }) { const sourceType = props.popular ? 'popular' : 'latest'; fetch(`http://127.0.0.1:4567/api/v1/source/${sourceId}/${sourceType}/${lastPageNum}`) .then((response) => response.json()) - .then((data: { title: string, thumbnail_url: string, id:number }[]) => setMangas( - data.map((it) => ({ title: it.title, thumbnailUrl: it.thumbnail_url, id: it.id })), + .then((data: IManga[]) => setMangas( + data.map((it) => ({ title: it.title, thumbnailUrl: it.thumbnailUrl, id: it.id })), )); }, []); diff --git a/webUI/react/src/screens/Search.tsx b/webUI/react/src/screens/Search.tsx deleted file mode 100644 index e40c581..0000000 --- a/webUI/react/src/screens/Search.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import React, { useContext, useState } from 'react'; -import { makeStyles } from '@material-ui/core/styles'; -import TextField from '@material-ui/core/TextField'; -import Button from '@material-ui/core/Button'; -import MangaGrid from '../components/MangaGrid'; -import NavBarTitle from '../context/NavbarTitle'; - -const useStyles = makeStyles((theme) => ({ - root: { - TextField: { - margin: theme.spacing(1), - width: '25ch', - }, - }, -})); - -export default function Search() { - const { setTitle } = useContext(NavBarTitle); - setTitle('Search'); - const classes = useStyles(); - const [error, setError] = useState(false); - const [mangas, setMangas] = useState([]); - const [message, setMessage] = useState(''); - - const textInput = React.createRef(); - - function doSearch() { - if (textInput.current) { - const { value } = textInput.current; - if (value === '') { setError(true); } else { - setError(false); - setMangas([]); - setMessage('button pressed'); - } - } - } - - const mangaGrid = ; - - return ( - <> -
- - - - {mangaGrid} - - ); -} diff --git a/webUI/react/src/screens/SearchSingle.tsx b/webUI/react/src/screens/SearchSingle.tsx new file mode 100644 index 0000000..a0f9b02 --- /dev/null +++ b/webUI/react/src/screens/SearchSingle.tsx @@ -0,0 +1,81 @@ +import React, { useContext, useEffect, useState } from 'react'; +import { makeStyles } from '@material-ui/core/styles'; +import TextField from '@material-ui/core/TextField'; +import Button from '@material-ui/core/Button'; +import { useParams } from 'react-router-dom'; +import MangaGrid from '../components/MangaGrid'; +import NavBarTitle from '../context/NavbarTitle'; + +const useStyles = makeStyles((theme) => ({ + root: { + TextField: { + margin: theme.spacing(1), + width: '25ch', + }, + }, +})); + +export default function SearchSingle() { + const { setTitle } = useContext(NavBarTitle); + const { sourceId } = useParams<{sourceId: string}>(); + const classes = useStyles(); + const [error, setError] = useState(false); + const [mangas, setMangas] = useState([]); + const [message, setMessage] = useState(''); + const [lastPageNum] = useState(1); + const [searchTerm, setSearchTerm] = useState(''); + + const textInput = React.createRef(); + + useEffect(() => { + fetch(`http://127.0.0.1:4567/api/v1/source/${sourceId}`) + .then((response) => response.json()) + .then((data: { name: string }) => setTitle(`Search: ${data.name}`)); + }, []); + + function processInput() { + if (textInput.current) { + const { value } = textInput.current; + if (value === '') { + setError(true); + setMessage('Type something to search'); + } else { + setError(false); + setSearchTerm(value); + setMessage(''); + } + } + } + + useEffect(() => { + if (searchTerm.length > 0) { + fetch(`http://127.0.0.1:4567/api/v1/source/${sourceId}/search/${searchTerm}/${lastPageNum}`) + .then((response) => response.json()) + .then((data: IManga[]) => { + if (data.length > 0) { + setMangas( + data.map((it) => ( + { title: it.title, thumbnailUrl: it.thumbnailUrl, id: it.id } + )), + ); + } else { + setMessage('search qeury returned nothing.'); + } + }); + } + }, [searchTerm]); + + const mangaGrid = ; + + return ( + <> +
+ + + + {mangaGrid} + + ); +}