Move history logic into redux

This commit is contained in:
Rajarshee Chatterjee
2021-03-21 15:39:10 +05:30
parent 5ec08b3add
commit 195fcaf9b2
16 changed files with 179 additions and 256 deletions
-57
View File
@@ -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);
};
+38
View File
@@ -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 },
});
};
+4 -4
View File
@@ -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
);
};
+8
View File
@@ -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";
-41
View File
@@ -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;
+41
View File
@@ -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;
-1
View File
@@ -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,
+2
View File
@@ -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,
})
);
+15 -77
View File
@@ -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 }) => {
)}
<Portal>
<BottomSheet
bottomSheetRef={(c) => (_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: {
+26 -28
View File
@@ -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 }) => (
<HistoryCard
item={item}
deleteHistory={deleteHistory}
deleteHistory={deleteChapterFromHistory}
navigation={navigation}
/>
);
@@ -59,7 +48,7 @@ const History = ({ navigation }) => {
<FlatList
contentContainerStyle={{ flex: 1 }}
data={history}
keyExtractor={(item) => 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: {
+1 -1
View File
@@ -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"
/>
<List.Item
titleStyle={{ color: theme.textColorPrimary }}
+2 -1
View File
@@ -176,8 +176,9 @@ const SettingsScreen = ({
borderRadius: 6,
}}
>
{themes.map((item) => (
{themes.map((item, index) => (
<ThemeCheckbox
key={index}
label={themes[item.themeCode].label}
checked={
themeCode === item.themeCode
+2 -1
View File
@@ -108,12 +108,13 @@ const Novel = ({
showsVerticalScrollIndicator={false}
keyExtractor={(item) => item.chapterUrl}
removeClippedSubviews={true}
maxToRenderPerBatch={10}
maxToRenderPerBatch={5}
windowSize={15}
initialNumToRender={7}
renderItem={renderChapterCard}
ListHeaderComponent={() => (
<NovelInfoHeader
theme={theme}
item={{ novelName, novelCover }}
novel={novel}
noOfChapters={chapters.length}
+3 -12
View File
@@ -15,7 +15,6 @@ import * as WebBrowser from "expo-web-browser";
import { LinearGradient } from "expo-linear-gradient";
import { MaterialCommunityIcons } from "@expo/vector-icons";
import { connect } from "react-redux";
const NovelInfoHeader = ({
item,
novel,
@@ -26,8 +25,6 @@ const NovelInfoHeader = ({
bottomSheetRef,
theme,
}) => {
const navigation = useNavigation();
const [more, setMore] = useState(navigatingFrom === 2 ? true : false);
const renderGenreChip = ({ item }) => (
@@ -46,7 +43,7 @@ const NovelInfoHeader = ({
);
return (
<>
<View style={{ flexGrow: 1 }}>
<ImageBackground
source={{
uri: item.novelCover,
@@ -125,7 +122,6 @@ const NovelInfoHeader = ({
<>
<View
style={{
flex: 1,
flexDirection: "row",
alignItems: "center",
}}
@@ -288,7 +284,6 @@ const NovelInfoHeader = ({
<TouchableRipple
style={{
flex: 1,
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
@@ -320,15 +315,11 @@ const NovelInfoHeader = ({
</TouchableRipple>
</>
)}
</>
</View>
);
};
const mapStateToProps = (state) => ({
theme: state.themeReducer.theme,
});
export default connect(mapStateToProps)(NovelInfoHeader);
export default NovelInfoHeader;
const styles = StyleSheet.create({
nameContainer: {
@@ -53,8 +53,9 @@ export const BottomSheet = ({ bottomSheetRef, setSort, sort, setLoading }) => {
}}
expanded
>
{sorting.map((item) => (
{sorting.map((item, index) => (
<List.Item
key={index}
right={() =>
sort === item.sortFlag && (
<List.Icon
+35 -32
View File
@@ -71,7 +71,7 @@ export const createIndexes = async () => {
});
};
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]
);
});
};