From 195fcaf9b28bf46d65f9acc1f10e1cdbe50213bc Mon Sep 17 00:00:00 2001 From: Rajarshee Chatterjee Date: Sun, 21 Mar 2021 15:39:10 +0530 Subject: [PATCH] Move history logic into redux --- src/redux/actions/chapters.js | 57 ------------ src/redux/actions/history.js | 38 ++++++++ src/redux/actions/novel.js | 8 +- src/redux/actions/types.js | 8 ++ src/redux/reducers/chapters.js | 41 --------- src/redux/reducers/history.js | 41 +++++++++ src/redux/reducers/novel.js | 1 - src/redux/store/configureStore.js | 2 + src/screens/Chapter/Chapter.js | 92 +++---------------- src/screens/History/History.js | 54 ++++++----- src/screens/More/About.js | 2 +- src/screens/More/Settings.js | 3 +- src/screens/Novel/Novel.js | 3 +- src/screens/Novel/components/NovelHeader.js | 15 +-- .../boxnovel/filters/BottomSheet.js | 3 +- src/services/db.js | 67 +++++++------- 16 files changed, 179 insertions(+), 256 deletions(-) delete mode 100644 src/redux/actions/chapters.js create mode 100644 src/redux/actions/history.js delete mode 100644 src/redux/reducers/chapters.js create mode 100644 src/redux/reducers/history.js diff --git a/src/redux/actions/chapters.js b/src/redux/actions/chapters.js deleted file mode 100644 index 61fdc30a..00000000 --- a/src/redux/actions/chapters.js +++ /dev/null @@ -1,57 +0,0 @@ -import { - LOADING_CHAPTERS, - GET_CHAPTERS, - CHAPTER_DOWNLOADED, - CHAPTER_DELETED, - CHAPTER_DOWNLOADING, -} from "./types"; - -import { - deleteChapterFromDb, - downloadChapterFromSource, -} from "../../services/db"; - -import { ToastAndroid } from "react-native"; - -export const downloadChapter = ( - extensionId, - novelUrl, - chapterUrl, - chapterName -) => async (dispatch) => { - dispatch({ - type: CHAPTER_DOWNLOADING, - payload: { - extensionId, - novelUrl, - chapterUrl, - downloading: true, - downloaded: false, - }, - }); - - await downloadChapterFromSource(extensionId, novelUrl, chapterUrl); - - dispatch({ - type: CHAPTER_DOWNLOADED, - payload: { extensionId, novelUrl, chapterUrl }, - }); - - ToastAndroid.show(`Downloaded ${chapterName}`, ToastAndroid.SHORT); -}; - -export const deleteChapter = ( - extensionId, - novelUrl, - chapterUrl, - chapterName -) => (dispatch) => { - deleteChapterFromDb(extensionId, novelUrl, chapterUrl); - - dispatch({ - type: CHAPTER_DELETED, - payload: { extensionId, novelUrl, chapterUrl }, - }); - - ToastAndroid.show(`Deleted ${chapterName}`, ToastAndroid.SHORT); -}; diff --git a/src/redux/actions/history.js b/src/redux/actions/history.js new file mode 100644 index 00000000..27568beb --- /dev/null +++ b/src/redux/actions/history.js @@ -0,0 +1,38 @@ +import { + UPDATE_NOVEL_HISTORY, + CLEAR_NOVEL_HISTORY, + GET_HISTORY, + LOAD_HISTORY, +} from "./types"; +import { + getHistoryFromDb, + insertIntoHistory, + deleteChapterHistory, +} from "../../services/db"; + +export const getHistory = () => async (dispatch) => { + dispatch({ type: LOAD_HISTORY }); + + const history = await getHistoryFromDb(); + + dispatch({ type: GET_HISTORY, payload: history }); +}; + +export const updateNovelHistory = (chapterUrl, chapterName, novelUrl) => async ( + dispatch +) => { + await insertIntoHistory(chapterUrl, chapterName, novelUrl); + + dispatch({ + type: UPDATE_NOVEL_HISTORY, + }); +}; + +export const deleteChapterFromHistory = (novelUrl) => async (dispatch) => { + await deleteChapterHistory(novelUrl); + + dispatch({ + type: CLEAR_NOVEL_HISTORY, + payload: { novelUrl }, + }); +}; diff --git a/src/redux/actions/novel.js b/src/redux/actions/novel.js index b6acfcee..98b83258 100644 --- a/src/redux/actions/novel.js +++ b/src/redux/actions/novel.js @@ -82,18 +82,18 @@ export const sortAndFilterChapters = (novelUrl, filter, sort) => async ( }); }; -export const insertNovelInLibrary = (libraryStatus, novelUrl) => async ( +export const insertNovelInLibrary = (inLibrary, novelUrl) => async ( dispatch ) => { - const inLibrary = await toggleFavourite(libraryStatus, novelUrl); + toggleFavourite(inLibrary, novelUrl); dispatch({ type: UPDATE_IN_LIBRARY, - payload: inLibrary, + payload: !inLibrary, }); ToastAndroid.show( - inLibrary ? "Added to library" : "Removed from library", + !inLibrary ? "Added to library" : "Removed from library", ToastAndroid.SHORT ); }; diff --git a/src/redux/actions/types.js b/src/redux/actions/types.js index 308e3802..fd518fc8 100644 --- a/src/redux/actions/types.js +++ b/src/redux/actions/types.js @@ -27,3 +27,11 @@ export const CHAPTER_DOWNLOADED = "CHAPTER_DOWNLOADED"; export const CHAPTER_DELETED = "CHAPTER_DELETED"; export const CHAPTER_DOWNLOADING = "CHAPTER_DOWNLOADING"; + +export const LOAD_HISTORY = "LOAD_HISTORY"; + +export const UPDATE_NOVEL_HISTORY = "UPDATE_NOVEL_HISTORY"; + +export const CLEAR_NOVEL_HISTORY = "CLEAR_NOVEL_HISTORY"; + +export const GET_HISTORY = "GET_HISTORY"; diff --git a/src/redux/reducers/chapters.js b/src/redux/reducers/chapters.js deleted file mode 100644 index f2f44833..00000000 --- a/src/redux/reducers/chapters.js +++ /dev/null @@ -1,41 +0,0 @@ -import { - CHAPTER_DOWNLOADING, - CHAPTER_DOWNLOADED, - CHAPTER_DELETED, -} from "../actions/types"; - -const initialState = { - chapters: [], - loading: true, -}; - -const downloadsReducer = (state = initialState, action) => { - const { type, payload } = action; - - switch (type) { - case CHAPTER_DOWNLOADING: - return { ...state, downloads: [...state.downloads, payload] }; - case CHAPTER_DOWNLOADED: - return { - ...state, - downloads: state.downloads.map((chapter) => - chapter.chapterUrl === payload.chapterUrl && - chapter.extensionId === payload.extensionId - ? { ...chapter, downloading: false, downloaded: true } - : chapter - ), - }; - case CHAPTER_DELETED: - return { - downloads: state.downloads.filter( - (chapter) => - chapter.chapterUrl === payload.chapterUrl && - chapter.extensionId === payload.extensionId - ), - }; - default: - return state; - } -}; - -export default downloadsReducer; diff --git a/src/redux/reducers/history.js b/src/redux/reducers/history.js new file mode 100644 index 00000000..432b3b29 --- /dev/null +++ b/src/redux/reducers/history.js @@ -0,0 +1,41 @@ +import { + CLEAR_NOVEL_HISTORY, + GET_HISTORY, + LOAD_HISTORY, + UPDATE_NOVEL_HISTORY, +} from "../actions/types"; + +const initialState = { + history: [], + loading: true, +}; + +const historyReducer = (state = initialState, action) => { + const { type, payload } = action; + + switch (type) { + case LOAD_HISTORY: + return { ...state, loading: true }; + case GET_HISTORY: + return { ...state, history: payload, loading: false }; + case UPDATE_NOVEL_HISTORY: + return state; + case CLEAR_NOVEL_HISTORY: + return { + ...state, + history: state.history.filter( + (item) => item.novelUrl !== payload.novelUrl + ), + }; + // return { + // ...state, + // history: state.history.map((novel) => + // novel.novelUrl === payload.novelUrl ? payload : novel + // ), + // }; + default: + return state; + } +}; + +export default historyReducer; diff --git a/src/redux/reducers/novel.js b/src/redux/reducers/novel.js index a4f85c41..8c82e2cb 100644 --- a/src/redux/reducers/novel.js +++ b/src/redux/reducers/novel.js @@ -29,7 +29,6 @@ const novelReducer = (state = initialState, action) => { return { ...state, novel: payload }; case GET_NOVEL: return { - ...state, novel: payload.novel, chapters: payload.chapters, loading: false, diff --git a/src/redux/store/configureStore.js b/src/redux/store/configureStore.js index 62a3be98..bbc557f7 100644 --- a/src/redux/store/configureStore.js +++ b/src/redux/store/configureStore.js @@ -8,6 +8,7 @@ import settingsReducer from "../reducers/settings"; import libraryReducer from "../reducers/library"; import extensionReducer from "../reducers/extension"; import novelReducer from "../reducers/novel"; +import historyReducer from "../reducers/history"; const persistConfig = { key: "root", @@ -23,6 +24,7 @@ const persistedReducer = persistReducer( libraryReducer, extensionReducer, novelReducer, + historyReducer, }) ); diff --git a/src/screens/Chapter/Chapter.js b/src/screens/Chapter/Chapter.js index 8f781677..3d7d65e2 100644 --- a/src/screens/Chapter/Chapter.js +++ b/src/screens/Chapter/Chapter.js @@ -1,4 +1,4 @@ -import React, { useState, useEffect } from "react"; +import React, { useState, useEffect, useRef } from "react"; import { StyleSheet, View, Text, ActivityIndicator } from "react-native"; import { Appbar, Provider, Portal } from "react-native-paper"; @@ -14,7 +14,11 @@ import { fetchChapterFromSource } from "../../services/api"; import { getReaderTheme } from "../../services/asyncStorage"; -const ChapterItem = ({ route, navigation }) => { +import { updateNovelHistory } from "../../redux/actions/history"; + +import { connect } from "react-redux"; + +const ChapterItem = ({ route, navigation, theme, updateNovelHistory }) => { const { extensionId, chapterUrl, novelUrl, chapterName } = route.params; const [loading, setLoading] = useState(true); @@ -25,48 +29,10 @@ const ChapterItem = ({ route, navigation }) => { const [readerTheme, setReaderTheme] = useState(1); + let _panel = useRef(null); // Bottomsheet ref + getReaderTheme().then((value) => setReaderTheme(value)); - const setHistory = () => { - db.transaction((tx) => { - tx.executeSql( - "INSERT INTO HistoryTable (chapterUrl, novelUrl, chapterName, lastRead) VALUES ( ?, ?, ?, (datetime('now','localtime')))", - [chapterUrl, novelUrl, chapterName], - (tx, res) => - console.log( - "Inserted into history table: " + novelUrl + chapterUrl - ), - (tx, error) => console.log(error) - ); - tx.executeSql( - "UPDATE LibraryTable SET lastRead = ?, lastReadName = ?, unread = 0 WHERE novelUrl = ?", - [chapterUrl, chapterName, novelUrl], - (tx, res) => - console.log("Set Last Read " + novelUrl + chapterUrl), - (tx, error) => console.log(error) - ); - }); - }; - - const updateHistory = () => { - db.transaction((tx) => { - tx.executeSql( - "UPDATE HistoryTable SET lastRead = (datetime('now','localtime')), chapterName=?, chapterUrl=? WHERE novelUrl = ?", - [chapterName, chapterUrl, novelUrl], - (tx, res) => - console.log("Updated into history table: " + novelUrl), - (tx, error) => console.log(error) - ); - tx.executeSql( - "UPDATE LibraryTable SET lastRead = ?, lastReadName = ?, unread = 0 WHERE novelUrl = ?", - [chapterUrl, chapterName, novelUrl], - (tx, res) => - console.log("Set Last read" + novelUrl + chapterUrl), - (tx, error) => console.log(error) - ); - }); - }; - const setRead = () => { db.transaction((tx) => { tx.executeSql( @@ -78,38 +44,6 @@ const ChapterItem = ({ route, navigation }) => { }); }; - const checkIfInHistory = () => { - db.transaction((tx) => { - tx.executeSql( - "SELECT * FROM HistoryTable WHERE novelUrl=?", - [novelUrl], - (txObj, res) => { - if (res.rows.length === 0) { - console.log("Not In History"); - setHistory(); - } else { - console.log("In History"); - updateHistory(); - } - }, - (txObj, error) => console.log("Error ", error) - ); - }); - }; - - // const updateLastRead = () => { - // db.transaction((tx) => { - - // tx.executeSql( - // "UPDATE LibraryTable SET lastRead = ?, lastReadName = ?, unread = 0 WHERE novelUrl = ?", - // [chapter.nextChapter, chapterName, novelUrl], - // (tx, res) => - // console.log("Set Last Read " + novelUrl + chapterUrl), - // (tx, error) => console.log(error) - // ); - // }); - // }; - const checkIfDownloaded = () => { db.transaction((tx) => { tx.executeSql( @@ -130,11 +64,11 @@ const ChapterItem = ({ route, navigation }) => { // console.log("Already Downloaded"); getChapterFromDB(); } - checkIfInHistory(); }, (txObj, error) => console.log("Error ", error) ); }); + updateNovelHistory(chapterUrl, chapterName, novelUrl); }; const getChapterFromDB = () => { @@ -292,7 +226,7 @@ const ChapterItem = ({ route, navigation }) => { )} (_panel = c)} + bottomSheetRef={_panel} setSize={setSize} size={size} setReaderTheme={setReaderTheme} @@ -304,7 +238,11 @@ const ChapterItem = ({ route, navigation }) => { ); }; -export default ChapterItem; +const mapStateToProps = (state) => ({ + theme: state.themeReducer.theme, +}); + +export default connect(mapStateToProps, { updateNovelHistory })(ChapterItem); const styles = StyleSheet.create({ container: { diff --git a/src/screens/History/History.js b/src/screens/History/History.js index 70bc999a..049c725b 100644 --- a/src/screens/History/History.js +++ b/src/screens/History/History.js @@ -1,38 +1,27 @@ import React, { useState, useCallback } from "react"; import { useFocusEffect } from "@react-navigation/native"; -import { - StyleSheet, - View, - Text, - FlatList, - ActivityIndicator, -} from "react-native"; +import { StyleSheet, View, FlatList, ActivityIndicator } from "react-native"; import { Appbar } from "../../components/common/Appbar"; import HistoryCard from "./components/HistoryCard"; -import { getHistoryFromDb, deleteChapterHistory } from "../../services/db"; - -import { useSelector } from "react-redux"; +import { connect } from "react-redux"; import EmptyView from "../../components/common/EmptyView"; -const History = ({ navigation }) => { - const [loading, setLoading] = useState(true); - const [history, setHistory] = useState([]); - - const theme = useSelector((state) => state.themeReducer.theme); - - const getHistory = async () => { - await getHistoryFromDb().then((res) => setHistory(res)); - setLoading(false); - }; - - const deleteHistory = (novelId) => { - deleteChapterHistory(novelId); - getHistory(); - }; +import { + getHistory, + deleteChapterFromHistory, +} from "../../redux/actions/history"; +const History = ({ + navigation, + theme, + history, + loading, + getHistory, + deleteChapterFromHistory, +}) => { useFocusEffect( useCallback(() => { getHistory(); @@ -42,7 +31,7 @@ const History = ({ navigation }) => { const renderHistoryCard = ({ item }) => ( ); @@ -59,7 +48,7 @@ const History = ({ navigation }) => { item.historyId.toString()} + keyExtractor={(item) => item.novelUrl.toString()} renderItem={renderHistoryCard} ListFooterComponent={ loading && ( @@ -83,7 +72,16 @@ const History = ({ navigation }) => { ); }; -export default History; +const mapStateToProps = (state) => ({ + theme: state.themeReducer.theme, + history: state.historyReducer.history, + loading: state.historyReducer.loading, +}); + +export default connect(mapStateToProps, { + getHistory, + deleteChapterFromHistory, +})(History); const styles = StyleSheet.create({ container: { diff --git a/src/screens/More/About.js b/src/screens/More/About.js index e5664bd1..f0ffb381 100644 --- a/src/screens/More/About.js +++ b/src/screens/More/About.js @@ -24,7 +24,7 @@ const AboutScreen = ({ navigation }) => { titleStyle={{ color: theme.textColorPrimary }} title="Version" descriptionStyle={{ color: theme.textColorSecondary }} - description="Stable 1.0.4" + description="Stable 1.0.5" /> - {themes.map((item) => ( + {themes.map((item, index) => ( item.chapterUrl} removeClippedSubviews={true} - maxToRenderPerBatch={10} + maxToRenderPerBatch={5} windowSize={15} initialNumToRender={7} renderItem={renderChapterCard} ListHeaderComponent={() => ( { - const navigation = useNavigation(); - const [more, setMore] = useState(navigatingFrom === 2 ? true : false); const renderGenreChip = ({ item }) => ( @@ -46,7 +43,7 @@ const NovelInfoHeader = ({ ); return ( - <> + )} - + ); }; -const mapStateToProps = (state) => ({ - theme: state.themeReducer.theme, -}); - -export default connect(mapStateToProps)(NovelInfoHeader); +export default NovelInfoHeader; const styles = StyleSheet.create({ nameContainer: { diff --git a/src/screens/extensions/boxnovel/filters/BottomSheet.js b/src/screens/extensions/boxnovel/filters/BottomSheet.js index 2688a7a3..02c53f86 100644 --- a/src/screens/extensions/boxnovel/filters/BottomSheet.js +++ b/src/screens/extensions/boxnovel/filters/BottomSheet.js @@ -53,8 +53,9 @@ export const BottomSheet = ({ bottomSheetRef, setSort, sort, setLoading }) => { }} expanded > - {sorting.map((item) => ( + {sorting.map((item, index) => ( sort === item.sortFlag && ( { }); }; -export const insertNovelInfoInDb = (novel) => { +export const insertNovelInfoInDb = async (novel) => { db.transaction((tx) => { tx.executeSql( "INSERT INTO LibraryTable (novelUrl, novelName, novelCover, novelSummary, `Author(s)`, `Genre(s)`, Status, extensionId, lastRead, lastReadName, sourceUrl, source) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", @@ -89,15 +89,13 @@ export const insertNovelInfoInDb = (novel) => { novel.sourceUrl, novel.source, ], - (txObj, res) => { - console.log("Inserted Novel Info in Db"); - }, + (txObj, res) => {}, (txObj, error) => console.log("Error ", error) ); }); }; -export const insertChaptersInDb = (novelUrl, chapters) => { +export const insertChaptersInDb = async (novelUrl, chapters) => { db.transaction((tx) => { chapters.map((chapter) => tx.executeSql( @@ -107,11 +105,12 @@ export const insertChaptersInDb = (novelUrl, chapters) => { chapter.chapterName, chapter.releaseDate, novelUrl, - ] + ], + (txObj, res) => {}, + (txObj, error) => console.log("Error ", error) ) ); }); - console.log("Inserted Chapters in Db"); }; /** @@ -180,18 +179,14 @@ export const checkNovelInDb = (novelUrl) => { */ export const toggleFavourite = async (libraryStatus, novelUrl) => { - return new Promise((resolve, reject) => - db.transaction((tx) => { - tx.executeSql( - "UPDATE LibraryTable SET libraryStatus = ? WHERE novelUrl=?", - [!libraryStatus, novelUrl], - (tx, res) => { - resolve(!libraryStatus); - }, - (txObj, error) => console.log("Error ", error) - ); - }) - ); + db.transaction((tx) => { + tx.executeSql( + "UPDATE LibraryTable SET libraryStatus = ? WHERE novelUrl=?", + [!libraryStatus, novelUrl], + (tx, res) => {}, + (txObj, error) => console.log("Error ", error) + ); + }); }; /** @@ -213,8 +208,8 @@ export const downloadOrDeleteChapter = async ( db.transaction((tx) => { tx.executeSql( - `UPDATE ChapterTable SET downloaded = 1 WHERE chapterUrl = ?`, - [chapterUrl] + `UPDATE ChapterTable SET downloaded = 1 WHERE chapterUrl = ? AND novelUrl = ?`, + [chapterUrl, novelUrl] ); tx.executeSql( `INSERT INTO DownloadsTable (chapterUrl, novelUrl, chapterName, chapterText, prevChapter, nextChapter) VALUES (?, ?, ?, ?, ?, ?)`, @@ -233,12 +228,12 @@ export const downloadOrDeleteChapter = async ( } else { db.transaction((tx) => { tx.executeSql( - `UPDATE ChapterTable SET downloaded = 0 WHERE chapterUrl = ?`, - [chapterUrl] + `UPDATE ChapterTable SET downloaded = 0 WHERE chapterUrl = ? AND novelUrl= ?`, + [chapterUrl, novelUrl] ); tx.executeSql( - `DELETE FROM DownloadsTable WHERE chapterUrl = ?`, - [chapterUrl], + `DELETE FROM DownloadsTable WHERE chapterUrl = ? AND novelUrl = ?`, + [chapterUrl, novelUrl], (tx, res) => console.log(`Chapter deleted`), (txObj, error) => console.log("Error ", error) ); @@ -265,14 +260,9 @@ export const getHistoryFromDb = async () => { }); }; -export const deleteChapterHistory = (novelId) => { +export const deleteChapterHistory = async (novelId) => { db.transaction((tx) => { - tx.executeSql( - "DELETE FROM HistoryTable WHERE novelUrl = ?", - [novelId], - (txObj, res) => {}, - (txObj, error) => console.log("Error ", error) - ); + tx.executeSql("DELETE FROM HistoryTable WHERE novelUrl = ?", [novelId]); }); }; @@ -423,3 +413,16 @@ export const deleteChapterFromDb = (extensionId, novelUrl, chapterUrl) => { ); }); }; + +export const insertIntoHistory = async (chapterUrl, chapterName, novelUrl) => { + db.transaction((tx) => { + tx.executeSql( + "INSERT OR REPLACE INTO HistoryTable (chapterUrl, novelUrl, chapterName, lastRead) VALUES ( ?, ?, ?, (datetime('now','localtime')))", + [chapterUrl, novelUrl, chapterName] + ); + tx.executeSql( + "UPDATE LibraryTable SET lastRead = ?, lastReadName = ?, unread = 0 WHERE novelUrl = ?", + [chapterUrl, chapterName, novelUrl] + ); + }); +};