diff --git a/src/database/queries/ChapterQueries.ts b/src/database/queries/ChapterQueries.ts index 02473768..7d2b9ce7 100644 --- a/src/database/queries/ChapterQueries.ts +++ b/src/database/queries/ChapterQueries.ts @@ -311,6 +311,26 @@ export const getDownloadedChapters = () => WHERE Chapter.isDownloaded = 1 `); +export const getNovelDownloadedChapters = ( + novelId: number, + startPosition?: number, + endPosition?: number, +) => { + if (startPosition !== undefined && endPosition !== undefined) { + return db.getAllAsync( + 'SELECT * FROM Chapter WHERE novelId = ? AND isDownloaded = 1 AND position >= ? AND position <= ? ORDER BY position ASC', + novelId, + startPosition - 1, + endPosition - 1, + ); + } + + return db.getAllAsync( + 'SELECT * FROM Chapter WHERE novelId = ? AND isDownloaded = 1 ORDER BY position ASC', + novelId, + ); +}; + export const getUpdatedOverviewFromDb = () => db.getAllAsync(`SELECT Novel.id AS novelId, diff --git a/src/screens/novel/NovelScreen.tsx b/src/screens/novel/NovelScreen.tsx index c6898102..94ca3b8d 100644 --- a/src/screens/novel/NovelScreen.tsx +++ b/src/screens/novel/NovelScreen.tsx @@ -250,7 +250,6 @@ const Novel = ({ route, navigation }: NovelScreenProps) => { {selected.length === 0 ? ( void; + onSubmit?: (uri: string, startChapter?: number, endChapter?: number) => void; hideModal: () => void; } @@ -34,13 +34,39 @@ const ExportEpubModal: React.FC = ({ const useAppTheme = useBoolean(epubUseAppTheme); const useCustomCSS = useBoolean(epubUseCustomCSS); const useCustomJS = useBoolean(epubUseCustomJS); + const exportAll = useBoolean(true); + const [startChapter, setStartChapter] = useState(''); + const [endChapter, setEndChapter] = useState(''); const onDismiss = () => { hideModal(); setUri(epubLocation); + exportAll.setTrue(); + setStartChapter(''); + setEndChapter(''); }; const onSubmit = () => { + if (!exportAll.value) { + const start = parseInt(startChapter, 10); + const end = parseInt(endChapter, 10); + + if (isNaN(start) || isNaN(end)) { + showToast(getString('novelScreen.exportEpubModal.invalidRange')); + return; + } + + if (start < 1 || end < 1) { + showToast(getString('novelScreen.exportEpubModal.invalidRange')); + return; + } + + if (start > end) { + showToast(getString('novelScreen.exportEpubModal.startGreaterThanEnd')); + return; + } + } + setChapterReaderSettings({ epubLocation: uri, epubUseAppTheme: useAppTheme.value, @@ -48,7 +74,10 @@ const ExportEpubModal: React.FC = ({ epubUseCustomJS: useCustomJS.value, }); - onSubmitProp?.(uri); + const start = exportAll.value ? undefined : parseInt(startChapter, 10); + const end = exportAll.value ? undefined : parseInt(endChapter, 10); + + onSubmitProp?.(uri, start, end); hideModal(); }; @@ -87,6 +116,38 @@ const ExportEpubModal: React.FC = ({ /> + + {!exportAll.value && ( + + + + + )} void; @@ -28,7 +28,6 @@ interface ExportNovelAsEpubButtonProps { const ExportNovelAsEpubButton: React.FC = ({ novel, - chapters, iconComponent: IconComponent, }) => { const theme = useTheme(); @@ -111,7 +110,11 @@ const ExportNovelAsEpubButton: React.FC = ({ `; }, [novel, readerSettings]); - const exportNovelAsEpub = async (destinationUri: string) => { + const exportNovelAsEpub = async ( + destinationUri: string, + startChapter?: number, + endChapter?: number, + ) => { if (!novel) { showToast(getString('novelScreen.epub.noNovelSelected')); return; @@ -120,6 +123,17 @@ const ExportNovelAsEpubButton: React.FC = ({ let epub: EpubBuilder | undefined; try { + const chapters = await getNovelDownloadedChapters( + novel.id, + startChapter, + endChapter, + ); + + if (chapters.length === 0) { + showToast(getString('novelScreen.epub.noDownloadedChapters')); + return; + } + epub = new EpubBuilder( { title: novel.name, diff --git a/src/screens/novel/components/NovelAppbar.tsx b/src/screens/novel/components/NovelAppbar.tsx index 5df78154..beece940 100644 --- a/src/screens/novel/components/NovelAppbar.tsx +++ b/src/screens/novel/components/NovelAppbar.tsx @@ -57,7 +57,6 @@ const Menu = React.memo( const NovelAppbar = ({ novel, - chapters, theme, isLocal, downloadChapters, @@ -71,7 +70,6 @@ const NovelAppbar = ({ headerOpacity, }: { novel: NovelInfo | undefined; - chapters: ChapterInfo[]; theme: ThemeColors; isLocal: boolean | undefined; downloadChapters: (amount: number | 'all' | 'unread') => void; @@ -165,11 +163,7 @@ const NovelAppbar = ({ - +