diff --git a/apps/readest-app/src-tauri/Cargo.toml b/apps/readest-app/src-tauri/Cargo.toml index 0fe839f6..10f0b08c 100644 --- a/apps/readest-app/src-tauri/Cargo.toml +++ b/apps/readest-app/src-tauri/Cargo.toml @@ -11,7 +11,7 @@ rust-version = "1.71" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [lib] -name = "readest" +name = "readestlib" crate-type = ["staticlib", "cdylib", "lib"] [build-dependencies] diff --git a/apps/readest-app/src-tauri/src/main.rs b/apps/readest-app/src-tauri/src/main.rs index af4ef67a..2e464ec2 100644 --- a/apps/readest-app/src-tauri/src/main.rs +++ b/apps/readest-app/src-tauri/src/main.rs @@ -2,5 +2,5 @@ #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] fn main() { - readest::run(); + readestlib::run(); } diff --git a/apps/readest-app/src/app/library/components/Bookshelf.tsx b/apps/readest-app/src/app/library/components/Bookshelf.tsx index 182fa3a4..2568d2fa 100644 --- a/apps/readest-app/src/app/library/components/Bookshelf.tsx +++ b/apps/readest-app/src/app/library/components/Bookshelf.tsx @@ -1,4 +1,5 @@ import * as React from 'react'; +import { useState } from 'react'; import { PiPlus } from 'react-icons/pi'; import { MdDelete, MdOpenInNew } from 'react-icons/md'; import { MdCheckCircle, MdCheckCircleOutline } from 'react-icons/md'; @@ -11,6 +12,7 @@ import Alert from '@/components/Alert'; import { useReaderStore } from '@/store/readerStore'; import { useEnv } from '@/context/EnvContext'; import clsx from 'clsx'; +import Spinner from '@/components/Spinner'; type BookshelfItem = Book | BooksGroup; @@ -48,9 +50,10 @@ const Bookshelf: React.FC = ({ libraryBooks, isSelectMode, onImp const router = useRouter(); const { envConfig } = useEnv(); const { deleteBook } = useReaderStore(); - const [selectedBooks, setSelectedBooks] = React.useState([]); - const [showDeleteAlert, setShowDeleteAlert] = React.useState(false); - const [clickedImage, setClickedImage] = React.useState(null); + const [loading, setLoading] = useState(false); + const [selectedBooks, setSelectedBooks] = useState([]); + const [showDeleteAlert, setShowDeleteAlert] = useState(false); + const [clickedImage, setClickedImage] = useState(null); React.useEffect(() => { setSelectedBooks([]); @@ -64,6 +67,7 @@ const Bookshelf: React.FC = ({ libraryBooks, isSelectMode, onImp } else { setClickedImage(id); setTimeout(() => setClickedImage(null), 300); + setTimeout(() => setLoading(true), 200); router.push(`/reader?ids=${id}`); } }; @@ -75,6 +79,7 @@ const Bookshelf: React.FC = ({ libraryBooks, isSelectMode, onImp }; const openSelectedBooks = () => { + setTimeout(() => setLoading(true), 200); router.push(`/reader?ids=${selectedBooks.join(',')}`); }; @@ -123,8 +128,8 @@ const Bookshelf: React.FC = ({ libraryBooks, isSelectMode, onImp />
{item.title} @@ -196,6 +201,11 @@ const Bookshelf: React.FC = ({ libraryBooks, isSelectMode, onImp
)} + {loading && ( +
+ +
+ )} {showDeleteAlert && ( { const { envConfig, appService } = useEnv(); const { library: libraryBooks, setLibrary } = useReaderStore(); - const [loading, setLoading] = useState(true); + const [loading, setLoading] = useState(false); const isInitiating = useRef(false); const [isSelectMode, setIsSelectMode] = useState(false); React.useEffect(() => { if (isInitiating.current) return; isInitiating.current = true; - setLoading(true); + + const loadingTimeout = setTimeout(() => setLoading(true), 200); envConfig.getAppService().then(async (appService) => { console.log('Loading library books...'); setLibrary(await appService.loadLibraryBooks()); + if (loadingTimeout) clearTimeout(loadingTimeout); setLoading(false); }); }, []); @@ -73,7 +75,7 @@ const LibraryPage = () => { }; if (!appService) { - return ; + return null; } return ( @@ -90,29 +92,29 @@ const LibraryPage = () => { )} -
- {libraryBooks.length > 0 ? ( + {libraryBooks.length > 0 ? ( +
- ) : ( -
-
-
-

Your Library

-

- Welcome to your library. You can upload your books here and read them anytime. -

- -
+
+ ) : ( +
+
+
+

Your Library

+

+ Welcome to your library. You can import your books here and read them anytime. +

+
- )} -
+
+ )}
); }; diff --git a/apps/readest-app/src/app/reader/components/FoliateViewer.tsx b/apps/readest-app/src/app/reader/components/FoliateViewer.tsx index c1b82738..11250088 100644 --- a/apps/readest-app/src/app/reader/components/FoliateViewer.tsx +++ b/apps/readest-app/src/app/reader/components/FoliateViewer.tsx @@ -116,6 +116,8 @@ const FoliateViewer: React.FC<{ useEffect(() => { if (isViewCreated.current) return; + isViewCreated.current = true; + const openBook = async () => { console.log('Opening book', bookKey); await import('foliate-js/view.js'); @@ -161,13 +163,6 @@ const FoliateViewer: React.FC<{ }; openBook(); - isViewCreated.current = true; - - return () => { - console.log('Closing book', bookKey); - viewRef.current?.close(); - viewRef.current?.remove(); - }; }, []); const initAnnotations = () => { diff --git a/apps/readest-app/src/app/reader/components/ReaderContent.tsx b/apps/readest-app/src/app/reader/components/ReaderContent.tsx index 3258ec7f..832ba1e4 100644 --- a/apps/readest-app/src/app/reader/components/ReaderContent.tsx +++ b/apps/readest-app/src/app/reader/components/ReaderContent.tsx @@ -1,6 +1,7 @@ 'use client'; import * as React from 'react'; +import { useState, useRef } from 'react'; import { useRouter, useSearchParams } from 'next/navigation'; import { useEnv } from '@/context/EnvContext'; @@ -24,10 +25,15 @@ const ReaderContent: React.FC<{ settings: SystemSettings }> = ({ settings }) => useReaderStore(); const { setBookKeys, getBookData, initViewState, getViewState, clearViewState } = useReaderStore(); + const isInitiating = useRef(false); + const [loading, setLoading] = useState(false); useBookShortcuts({ sideBarBookKey, bookKeys }); React.useEffect(() => { + if (isInitiating.current) return; + isInitiating.current = true; + const initialIds = (searchParams.get('ids') || '').split(',').filter(Boolean); const initialBookKeys = initialIds.map((id) => `${id}-${uniqueId()}`); setBookKeys(initialBookKeys); @@ -45,6 +51,7 @@ const ReaderContent: React.FC<{ settings: SystemSettings }> = ({ settings }) => }, []); const saveConfigAndCloseBook = (bookKey: string) => { + console.log('Closing book', bookKey); getView(bookKey)?.close(); getView(bookKey)?.remove(); const config = getConfig(bookKey); @@ -82,10 +89,13 @@ const ReaderContent: React.FC<{ settings: SystemSettings }> = ({ settings }) => if (!bookKeys || bookKeys.length === 0) return null; const bookData = getBookData(bookKeys[0]!); if (!bookData || !bookData.book || !bookData.bookDoc) { + setTimeout(() => setLoading(true), 200); return ( -
- -
+ loading && ( +
+ +
+ ) ); } diff --git a/apps/readest-app/src/app/reader/components/sidebar/BookCard.tsx b/apps/readest-app/src/app/reader/components/sidebar/BookCard.tsx index c8a27b27..e86874ac 100644 --- a/apps/readest-app/src/app/reader/components/sidebar/BookCard.tsx +++ b/apps/readest-app/src/app/reader/components/sidebar/BookCard.tsx @@ -18,10 +18,13 @@ const BookCard: React.FC = ({ cover, title, author }) => { width={56} height={80} className='mr-4 aspect-auto max-h-20 w-[15%] max-w-14 rounded-sm object-cover shadow-md' + onError={(e) => { + (e.target as HTMLImageElement).style.display = 'none'; + }} />

{title}

-

{formatAuthors(author)}

+

{formatAuthors(author)}