diff --git a/src/database/queries/ChapterQueries.js b/src/database/queries/ChapterQueries.js index 5f39f3d6..a8fcdff7 100644 --- a/src/database/queries/ChapterQueries.js +++ b/src/database/queries/ChapterQueries.js @@ -35,7 +35,7 @@ export const insertChapters = async (novelId, chapters) => { }; const getChaptersQuery = (sort, filter) => - `SELECT * FROM chapters WHERE novelId = ? ${filter} ${sort}`; + `SELECT * FROM chapters WHERE novelId = ? ${filter ?? ""} ${sort ?? ""}`; export const getChapters = (novelId, sort, filter) => { return new Promise((resolve, reject) => @@ -113,6 +113,8 @@ export const downloadChapter = async ( ) => { const downloadUrl = `https://lnreader-extensions.herokuapp.com/api/${extensionId}/novel/${novelUrl}${chapterUrl}`; + // console.log(downloadUrl); + const response = await fetch(downloadUrl); const chapter = await response.json(); @@ -157,6 +159,26 @@ export const deleteChapter = async (chapterId) => { }); }; +// export const deleteAllChapters = async (novelId) => { +// const updateIsDownloadedQuery = `UPDATE chapters SET downloaded = 0 WHERE novelId=?`; +// const deleteChapterQuery = `DELETE FROM downloads WHERE downloadChapterId=?`; + +// db.transaction((tx) => { +// tx.executeSql( +// updateIsDownloadedQuery, +// [chapterId], +// (tx, res) => console.log(`Chaptermarked not downapdeod deleted`), +// (txObj, error) => console.log("Error ", error) +// ); +// tx.executeSql( +// deleteChapterQuery, +// [chapterId], +// (tx, res) => console.log(`Chapter deleted`), +// (txObj, error) => console.log("Error ", error) +// ); +// }); +// }; + const getLastReadChapterQuery = ` SELECT chapters.* FROM history diff --git a/src/navigation/Router.js b/src/navigation/Router.js index dcc57938..df3fdb64 100644 --- a/src/navigation/Router.js +++ b/src/navigation/Router.js @@ -22,10 +22,10 @@ import NovelItem from "../screens/Novel/Novel"; import ChapterItem from "../screens/Chapter/Chapter"; // Extensions -import BoxNovel from "../screens/Extensions/boxnovel/BoxNovel"; -import ReadLightNovel from "../screens/Extensions/readlightnovel/ReadLightNovel"; -import FastNovel from "../screens/Extensions/fastnovel/FastNovel"; -import ReadNovelFull from "../screens/Extensions/readnovelfull/ReadNovelFull"; +import BoxNovel from "../screens/extensions/boxnovel/BoxNovel"; +import ReadLightNovel from "../screens/extensions/readlightnovel/ReadLightNovel"; +import FastNovel from "../screens/extensions/fastnovel/FastNovel"; +import ReadNovelFull from "../screens/extensions/readnovelfull/ReadNovelFull"; const Stack = createStackNavigator(); diff --git a/src/redux/chapter/chapter.actions.js b/src/redux/chapter/chapter.actions.js index addd02e5..208d0101 100644 --- a/src/redux/chapter/chapter.actions.js +++ b/src/redux/chapter/chapter.actions.js @@ -35,6 +35,7 @@ export const getChapterAction = ( } else { chapter = await fetchChapter(extensionId, novelUrl, chapterUrl); } + console.log(isDownloaded); dispatch({ type: GET_CHAPTER, payload: chapter }); }; diff --git a/src/redux/novel/novel.actions.js b/src/redux/novel/novel.actions.js index ddd6b070..4eed5d23 100644 --- a/src/redux/novel/novel.actions.js +++ b/src/redux/novel/novel.actions.js @@ -161,6 +161,37 @@ export const downloadChapterAction = ( ToastAndroid.show(`Downloaded ${chapterName}`, ToastAndroid.SHORT); }; +export const downloadAllChaptersAction = ( + extensionId, + novelUrl, + chapters +) => async (dispatch) => { + await chapters.map((chapter, index) => { + setTimeout(async () => { + dispatch({ + type: CHAPTER_DOWNLOADING, + payload: chapter.chapterId, + }); + + if (!chapter.downloaded) { + await downloadChapter( + extensionId, + novelUrl, + chapter.chapterUrl, + chapter.chapterId + ); + } + + dispatch({ + type: CHAPTER_DOWNLOADED, + payload: chapter.chapterId, + }); + }, 1000 * index); + }); + + ToastAndroid.show(`All chapters downloaded`, ToastAndroid.SHORT); +}; + export const deleteChapterAction = (chapterId, chapterName) => async ( dispatch ) => { @@ -174,6 +205,19 @@ export const deleteChapterAction = (chapterId, chapterName) => async ( ToastAndroid.show(`Deleted ${chapterName}`, ToastAndroid.SHORT); }; +export const deleteAllChaptersAction = (chapters) => async (dispatch) => { + await chapters.map((chapter) => { + deleteChapter(chapter.chapterId); + + dispatch({ + type: CHAPTER_DELETED, + payload: chapter.chapterId, + }); + }); + + ToastAndroid.show(`Deleted all chapters`, ToastAndroid.SHORT); +}; + export const updateNovelAction = (extensionId, novelUrl, novelId) => async ( dispatch ) => { diff --git a/src/redux/novel/novel.reducer.js b/src/redux/novel/novel.reducer.js index 05cfbdcc..a94174af 100644 --- a/src/redux/novel/novel.reducer.js +++ b/src/redux/novel/novel.reducer.js @@ -82,12 +82,16 @@ const novelReducer = (state = initialState, action) => { case CHAPTER_DOWNLOADING: return { ...state, - downloading: payload, + chapters: state.chapters.map((chapter) => + chapter.chapterId === payload + ? { ...chapter, downloaded: 3 } + : chapter + ), }; case CHAPTER_DOWNLOADED: return { ...state, - downloading: null, + // downloading: state.downloading.filter((id) => id === payload), chapters: state.chapters.map((chapter) => chapter.chapterId === payload ? { ...chapter, downloaded: 1 } diff --git a/src/screens/Novel/Novel.js b/src/screens/Novel/Novel.js index 8f8709e9..f0ee20db 100644 --- a/src/screens/Novel/Novel.js +++ b/src/screens/Novel/Novel.js @@ -19,6 +19,8 @@ import { followNovelAction, sortAndFilterChapters, updateNovelAction, + downloadAllChaptersAction, + deleteAllChaptersAction, } from "../../redux/novel/novel.actions"; const Novel = ({ @@ -32,6 +34,8 @@ const Novel = ({ followNovelAction, sortAndFilterChapters, updateNovelAction, + downloadAllChaptersAction, + deleteAllChaptersAction, }) => { const { sourceId, @@ -92,6 +96,16 @@ const Novel = ({ loading={loading} lastRead={lastRead} bottomSheetRef={_panel} + downloadAllChapters={() => + downloadAllChaptersAction( + sourceId, + novelUrl, + chapters + ) + } + deleteAllChapters={() => + deleteAllChaptersAction(chapters) + } /> } refreshControl={ @@ -131,6 +145,8 @@ export default connect(mapStateToProps, { followNovelAction, sortAndFilterChapters, updateNovelAction, + downloadAllChaptersAction, + deleteAllChaptersAction, })(Novel); const styles = StyleSheet.create({ diff --git a/src/screens/Novel/components/ChapterCard.js b/src/screens/Novel/components/ChapterCard.js index 376e4f9f..b7bd29b1 100644 --- a/src/screens/Novel/components/ChapterCard.js +++ b/src/screens/Novel/components/ChapterCard.js @@ -1,6 +1,6 @@ -import React from "react"; +import React, { useState } from "react"; import { View, Text, ActivityIndicator, StyleSheet } from "react-native"; -import { TouchableRipple, IconButton } from "react-native-paper"; +import { TouchableRipple, IconButton, Menu } from "react-native-paper"; import { useNavigation } from "@react-navigation/native"; import { @@ -14,12 +14,77 @@ const ChapterCard = ({ chapter, extensionId, theme, - downloading, + // downloading, downloadChapterAction, deleteChapterAction, }) => { const navigation = useNavigation(); + const [visible, setVisible] = useState(false); + const openMenu = () => setVisible(true); + const closeMenu = () => setVisible(false); + + const displayDownloadButton = () => { + if (chapter.downloaded === 3) { + return ( + + ); + } else if (chapter.downloaded === 1) { + return ( + + } + contentStyle={{ backgroundColor: "#242529" }} + > + + deleteChapterAction( + chapter.chapterId, + chapter.chapterName + ) + } + title="Delete" + titleStyle={{ color: theme.textColorPrimary }} + /> + + ); + } else { + return ( + { + downloadChapterAction( + extensionId, + novelUrl, + chapter.chapterUrl, + chapter.chapterName, + chapter.chapterId + ); + // console.log(downloading); + }} + style={{ margin: 2 }} + /> + ); + } + }; + return ( )} - - {downloading === chapter.chapterId ? ( - - ) : ( - { - if (!chapter.downloaded) { - downloadChapterAction( - extensionId, - novelUrl, - chapter.chapterUrl, - chapter.chapterName, - chapter.chapterId - ); - } else { - deleteChapterAction( - chapter.chapterId, - chapter.chapterName - ); - } - }} - style={{ margin: 2 }} - /> - )} - + {displayDownloadButton()} ); @@ -116,7 +141,7 @@ const ChapterCard = ({ const mapStateToProps = (state) => ({ theme: state.themeReducer.theme, - downloading: state.novelReducer.downloading, + // downloading: state.novelReducer.downloading, }); export default connect(mapStateToProps, { diff --git a/src/screens/Novel/components/NovelHeader.js b/src/screens/Novel/components/NovelHeader.js index b095d91f..3f1bf0c4 100644 --- a/src/screens/Novel/components/NovelHeader.js +++ b/src/screens/Novel/components/NovelHeader.js @@ -8,7 +8,13 @@ import { FlatList, Share, } from "react-native"; -import { TouchableRipple, IconButton, Button, Chip } from "react-native-paper"; +import { + TouchableRipple, + IconButton, + Button, + Chip, + Menu, +} from "react-native-paper"; import { useNavigation } from "@react-navigation/native"; import * as WebBrowser from "expo-web-browser"; @@ -24,6 +30,8 @@ const NovelInfoHeader = ({ bottomSheetRef, theme, lastRead, + downloadAllChapters, + deleteAllChapters, }) => { const navigation = useNavigation(); @@ -31,6 +39,10 @@ const NovelInfoHeader = ({ !loading && novel.followed !== 1 ? true : false ); + const [visible, setVisible] = useState(false); + const openMenu = () => setVisible(true); + const closeMenu = () => setVisible(false); + const renderGenreChip = ({ item }) => ( + + + } + contentStyle={{ backgroundColor: "#242529" }} + > + + + {novel.novelSummary !== "" && (