diff --git a/apps/readest-app/src/app/library/components/Bookshelf.tsx b/apps/readest-app/src/app/library/components/Bookshelf.tsx index cf83091a..b86981ca 100644 --- a/apps/readest-app/src/app/library/components/Bookshelf.tsx +++ b/apps/readest-app/src/app/library/components/Bookshelf.tsx @@ -25,6 +25,7 @@ import { isTauriAppPlatform, isWebAppPlatform } from '@/services/environment'; import Alert from '@/components/Alert'; import Spinner from '@/components/Spinner'; import BookDetailModal from '@/components/BookDetailModal'; +import ReadingProgress from './ReadingProgress'; type BookshelfItem = Book | BooksGroup; @@ -242,17 +243,50 @@ const Bookshelf: React.FC = ({ libraryBooks, isSelectMode, onImp )} -
-

- {(item as Book).title} -

- {isWebAppPlatform() && ( -
- +
+
+

+ {(item as Book).title} +

+
+ {item.progress && ( +
+ + {isWebAppPlatform() && ( + + )} +
+ )} + {!item.progress && isWebAppPlatform() && ( +
+
)}
@@ -270,6 +304,11 @@ const Bookshelf: React.FC = ({ libraryBooks, isSelectMode, onImp className='h-48 w-full object-cover' /> +
+

{book.title}

+

{book.author}

+ +
))}

{(item as BooksGroup).name}

diff --git a/apps/readest-app/src/app/library/components/ReadingProgress.tsx b/apps/readest-app/src/app/library/components/ReadingProgress.tsx new file mode 100644 index 00000000..567abdd8 --- /dev/null +++ b/apps/readest-app/src/app/library/components/ReadingProgress.tsx @@ -0,0 +1,43 @@ +import type React from 'react'; +import { memo, useMemo } from 'react'; +import type { Book } from '@/types/book'; + +interface ReadingProgressProps { + book: Book; +} + +const getProgressPercentage = (book: Book) => { + if (!book.progress || !book.progress[1]) { + return null; + } + if (book.progress && book.progress[1] === 1) { + return 100; + } + return Math.round((book.progress[0] / book.progress[1]) * 100); +}; + +const ReadingProgress: React.FC = memo( + ({ book }) => { + const progressPercentage = useMemo(() => getProgressPercentage(book), [book]); + + if (!progressPercentage) { + return null; + } + + return ( +
+ {progressPercentage}% +
+ ); + }, + (prevProps, nextProps) => { + return ( + prevProps.book.hash === nextProps.book.hash && + prevProps.book.updatedAt === nextProps.book.updatedAt + ); + }, +); + +ReadingProgress.displayName = 'ReadingProgress'; + +export default ReadingProgress; diff --git a/apps/readest-app/src/store/readerStore.ts b/apps/readest-app/src/store/readerStore.ts index 5a296a62..b06db3a0 100644 --- a/apps/readest-app/src/store/readerStore.ts +++ b/apps/readest-app/src/store/readerStore.ts @@ -64,7 +64,10 @@ export const useReaderStore = create((set, get) => ({ getView: (key: string | null) => (key && get().viewStates[key]?.view) || null, setView: (key: string, view) => set((state) => ({ - viewStates: { ...state.viewStates, [key]: { ...state.viewStates[key]!, view } }, + viewStates: { + ...state.viewStates, + [key]: { ...state.viewStates[key]!, view }, + }, })), getViews: () => Object.values(get().viewStates).map((state) => state.view!), getViewsById: (id: string) => { @@ -213,13 +216,31 @@ export const useReaderStore = create((set, get) => ({ const bookData = useBookDataStore.getState().booksData[id]; const viewState = state.viewStates[key]; if (!viewState || !bookData) return state; + + const progress: [number, number] = [pageinfo.current, pageinfo.total]; + + // Update library book progress + const { library, setLibrary } = useLibraryStore.getState(); + const bookIndex = library.findIndex((b) => b.hash === id); + if (bookIndex !== -1) { + const updatedLibrary = [...library]; + const existingBook = updatedLibrary[bookIndex]!; + updatedLibrary[bookIndex] = { + ...existingBook, + progress, + updatedAt: Date.now(), + }; + setLibrary(updatedLibrary); + } + const oldConfig = bookData.config; const newConfig = { ...bookData.config, updatedAt: Date.now(), - progress: [pageinfo.current, pageinfo.total] as [number, number], + progress, location, }; + useBookDataStore.setState((state) => ({ booksData: { ...state.booksData, @@ -229,6 +250,7 @@ export const useReaderStore = create((set, get) => ({ }, }, })); + return { viewStates: { ...state.viewStates, @@ -248,7 +270,6 @@ export const useReaderStore = create((set, get) => ({ }, }; }), - setBookmarkRibbonVisibility: (key: string, visible: boolean) => set((state) => ({ viewStates: { diff --git a/apps/readest-app/src/types/book.ts b/apps/readest-app/src/types/book.ts index a11d43ce..2f740f4f 100644 --- a/apps/readest-app/src/types/book.ts +++ b/apps/readest-app/src/types/book.ts @@ -19,6 +19,7 @@ export interface Book { deletedAt?: number | null; lastUpdated?: number; // deprecated in favor of updatedAt + progress?: [number, number]; // Add progress field: [current, total] } export interface PageInfo {