diff --git a/src/components/common/Appbar.js b/src/components/common/Appbar.js
index e7f618c2..4d3cdca0 100644
--- a/src/components/common/Appbar.js
+++ b/src/components/common/Appbar.js
@@ -123,12 +123,12 @@ export const SearchAppbar = ({
const styles = StyleSheet.create({
searchAppbarContainer: {
- marginTop: Constants.statusBarHeight + 4,
+ marginTop: Constants.statusBarHeight + 8,
height: 48,
flexDirection: "row",
alignItems: "center",
paddingHorizontal: 16,
- marginBottom: 8,
+ marginBottom: 12,
borderRadius: 8,
marginHorizontal: 12,
elevation: 2,
diff --git a/src/redux/actions/novel.js b/src/redux/actions/novel.js
index 1630bb08..b6acfcee 100644
--- a/src/redux/actions/novel.js
+++ b/src/redux/actions/novel.js
@@ -1,16 +1,35 @@
-import { LOADING_NOVEL, GET_NOVEL, GET_CHAPTERS } from "./types";
+import { ToastAndroid } from "react-native";
+
+import {
+ LOADING_NOVEL,
+ GET_NOVEL,
+ GET_CHAPTERS,
+ FETCHING_NOVEL,
+ SET_NOVEL,
+ UPDATE_IN_LIBRARY,
+ CHAPTER_DOWNLOADING,
+ CHAPTER_DOWNLOADED,
+ CHAPTER_DELETED,
+} from "./types";
import {
checkNovelInDb,
getChaptersFromDb,
getNovelInfoFromDb,
insertChaptersInDb,
insertNovelInfoInDb,
+ toggleFavourite,
+ downloadChapterFromSource,
+ deleteChapterFromDb,
} from "../../services/db";
import {
fetchChaptersFromSource,
fetchNovelFromSource,
} from "../../services/api";
+export const setNovel = (novel) => async (dispatch) => {
+ dispatch({ type: SET_NOVEL, payload: novel });
+};
+
export const getNovel = (navigatingFrom, extensionId, novelUrl) => async (
dispatch
) => {
@@ -23,6 +42,8 @@ export const getNovel = (navigatingFrom, extensionId, novelUrl) => async (
payload: chapters,
});
} else {
+ dispatch({ type: FETCHING_NOVEL });
+
const inCache = await checkNovelInDb(novelUrl);
if (inCache) {
@@ -50,3 +71,70 @@ export const getNovel = (navigatingFrom, extensionId, novelUrl) => async (
}
}
};
+
+export const sortAndFilterChapters = (novelUrl, filter, sort) => async (
+ dispatch
+) => {
+ const chapters = await getChaptersFromDb(novelUrl, filter, sort);
+ dispatch({
+ type: GET_CHAPTERS,
+ payload: chapters,
+ });
+};
+
+export const insertNovelInLibrary = (libraryStatus, novelUrl) => async (
+ dispatch
+) => {
+ const inLibrary = await toggleFavourite(libraryStatus, novelUrl);
+
+ dispatch({
+ type: UPDATE_IN_LIBRARY,
+ payload: inLibrary,
+ });
+
+ ToastAndroid.show(
+ inLibrary ? "Added to library" : "Removed from library",
+ ToastAndroid.SHORT
+ );
+};
+
+// export const downloadChapter = (
+// extensionId,
+// novelUrl,
+// chapterUrl,
+// chapterName
+// ) => async (dispatch) => {
+// dispatch({
+// type: CHAPTER_DOWNLOADING,
+// payload: {
+// extensionId,
+// novelUrl,
+// chapterUrl,
+// },
+// });
+
+// 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/types.js b/src/redux/actions/types.js
index ef28b4f5..308e3802 100644
--- a/src/redux/actions/types.js
+++ b/src/redux/actions/types.js
@@ -10,10 +10,16 @@ export const GET_EXTENSIONS = "GET_EXTENSIONS";
export const LOADING_NOVEL = "LOADING_NOVEL";
+export const FETCHING_NOVEL = "FETCHING_NOVEL";
+
export const LOADING_CHAPTERS = "LOADING_CHAPTERS";
+export const SET_NOVEL = "SET_NOVEL";
+
export const GET_NOVEL = "GET_NOVEL";
+export const UPDATE_IN_LIBRARY = "UPDATE_IN_LIBRARY";
+
export const GET_CHAPTERS = "GET_CHAPTERS";
export const CHAPTER_DOWNLOADED = "CHAPTER_DOWNLOADED";
diff --git a/src/redux/reducers/novel.js b/src/redux/reducers/novel.js
index 8be74c67..a4f85c41 100644
--- a/src/redux/reducers/novel.js
+++ b/src/redux/reducers/novel.js
@@ -5,12 +5,16 @@ import {
GET_CHAPTERS,
LOADING_NOVEL,
GET_NOVEL,
+ FETCHING_NOVEL,
+ SET_NOVEL,
+ UPDATE_IN_LIBRARY,
} from "../actions/types";
const initialState = {
novel: null,
chapters: [],
loading: true,
+ fetching: false,
};
const novelReducer = (state = initialState, action) => {
@@ -19,39 +23,60 @@ const novelReducer = (state = initialState, action) => {
switch (type) {
case LOADING_NOVEL:
return { ...state, loading: true };
+ case FETCHING_NOVEL:
+ return { ...state, loading: true, fetching: true };
+ case SET_NOVEL:
+ return { ...state, novel: payload };
case GET_NOVEL:
return {
...state,
novel: payload.novel,
chapters: payload.chapters,
loading: false,
+ fetching: false,
};
case GET_CHAPTERS:
return {
...state,
chapters: payload,
loading: false,
+ fetching: false,
};
- case CHAPTER_DOWNLOADING:
- return { ...state, downloads: [...state.downloads, payload] };
- case CHAPTER_DOWNLOADED:
+ case UPDATE_IN_LIBRARY:
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
- ),
+ novel: { ...state.novel, libraryStatus: payload },
};
+ // case CHAPTER_DOWNLOADING:
+ // return {
+ // ...state,
+ // chapters: [
+ // state.chapters.map((chap) =>
+ // chap.novelUrl === payload.novelUrl &&
+ // chap.chapterUrl === payload.novelUrl
+ // ? { ...chap, downloading: true, downloaded: false }
+ // : chap
+ // ),
+ // ],
+ // };
+ // case CHAPTER_DOWNLOADED:
+ // return {
+ // ...state,
+ // downloads: state.downloads.map((chap) =>
+ // chap.chapterUrl === payload.chapterUrl &&
+ // chap.novelUrl === payload.novelUrl
+ // ? { ...chap, downloading: false, downloaded: true }
+ // : chap
+ // ),
+ // };
+ // case CHAPTER_DELETED:
+ // return {
+ // downloads: state.downloads.filter(
+ // (chapter) =>
+ // chapter.chapterUrl === payload.chapterUrl &&
+ // chapter.novelUrl === payload.novelUrl
+ // ),
+ // };
default:
return state;
}
diff --git a/src/screens/Library/Library.js b/src/screens/Library/Library.js
index dfd8e1e7..1a12269a 100644
--- a/src/screens/Library/Library.js
+++ b/src/screens/Library/Library.js
@@ -19,6 +19,7 @@ import {
searchLibraryNovels,
} from "../../redux/actions/library";
import { SearchAppbar } from "../../components/common/Appbar";
+import { setNovel } from "../../redux/actions/novel";
const LibraryScreen = ({
navigation,
@@ -27,6 +28,7 @@ const LibraryScreen = ({
loading,
getLibraryNovels,
searchLibraryNovels,
+ setNovel,
}) => {
const [refreshing, setRefreshing] = useState(false);
@@ -49,11 +51,13 @@ const LibraryScreen = ({
setRefreshing(false);
};
- const redirectToNovel = (item) =>
+ const redirectToNovel = (item) => {
navigation.navigate("NovelItem", {
...item,
navigatingFrom: 1,
});
+ setNovel(item);
+ };
return (
<>
@@ -129,6 +133,7 @@ const mapStateToProps = (state) => ({
export default connect(mapStateToProps, {
getLibraryNovels,
searchLibraryNovels,
+ setNovel,
})(LibraryScreen);
const styles = StyleSheet.create({
diff --git a/src/screens/More/About.js b/src/screens/More/About.js
index 1b0cb888..e5664bd1 100644
--- a/src/screens/More/About.js
+++ b/src/screens/More/About.js
@@ -24,13 +24,13 @@ const AboutScreen = ({ navigation }) => {
titleStyle={{ color: theme.textColorPrimary }}
title="Version"
descriptionStyle={{ color: theme.textColorSecondary }}
- description="Stable 1.0.3"
+ description="Stable 1.0.4"
/>
{
- const item = route.params;
-
const {
extensionId,
novelUrl,
@@ -38,13 +42,6 @@ const Novel = ({
novelCover,
} = route.params;
- // const [refreshing, setRefreshing] = useState(false);
-
- const [libraryStatus, setlibraryStatus] = useState(item.libraryStatus);
-
- const [sort, setSort] = useState("");
- const [filter, setFilter] = useState("");
-
const [downloading, setDownloading] = useState({
downloading: false,
chapterUrl: "",
@@ -52,20 +49,6 @@ const Novel = ({
let _panel = useRef(null); // Bottomsheet ref
- /**
- * Insert or remove novel from library
- */
-
- const insertNovelInLib = async () => {
- toggleFavourite(libraryStatus, novelUrl).then((res) => {
- setlibraryStatus(res);
- ToastAndroid.show(
- res ? "Added to library" : "Removed from library",
- ToastAndroid.SHORT
- );
- });
- };
-
/**
* Download chapter from source
*
@@ -96,27 +79,21 @@ const Novel = ({
});
};
- useFocusEffect(
- useCallback(() => {
- getNovel(navigatingFrom, extensionId, novelUrl);
- }, [sort, filter])
- );
+ useEffect(() => {
+ getNovel(navigatingFrom, extensionId, novelUrl);
+ }, []);
- const onRefresh = async () => {
- // setRefreshing(true);
- // checkIfExistsInDb();
- };
-
- const renderChapterCard = ({ item }) => (
-
- );
+ const renderChapterCard = ({ item }) =>
+ !loading && (
+
+ );
return (
@@ -128,7 +105,6 @@ const Novel = ({
>
item.chapterUrl}
removeClippedSubviews={true}
@@ -138,14 +114,10 @@ const Novel = ({
renderItem={renderChapterCard}
ListHeaderComponent={() => (
@@ -178,9 +148,14 @@ const mapStateToProps = (state) => ({
novel: state.novelReducer.novel,
chapters: state.novelReducer.chapters,
loading: state.novelReducer.loading,
+ fetching: state.novelReducer.fetching,
});
-export default connect(mapStateToProps, { getNovel })(Novel);
+export default connect(mapStateToProps, {
+ getNovel,
+ insertNovelInLibrary,
+ sortAndFilterChapters,
+})(Novel);
const styles = StyleSheet.create({
container: {
diff --git a/src/screens/Novel/components/BottomSheet.js b/src/screens/Novel/components/BottomSheet.js
index 6c7c26e9..451514b7 100644
--- a/src/screens/Novel/components/BottomSheet.js
+++ b/src/screens/Novel/components/BottomSheet.js
@@ -1,32 +1,29 @@
-import React from "react";
+import React, { useState } from "react";
import { StyleSheet, View, Text } from "react-native";
import { List, RadioButton, Checkbox } from "react-native-paper";
import Bottomsheet from "rn-sliding-up-panel";
import { useSelector } from "react-redux";
-const BottomSheetHandle = () => (
-
-);
-
export const BottomSheet = ({
bottomSheetRef,
- sort,
- filter,
- sortChapters,
- filterChapters,
+ sortAndFilterChapters,
+ novelUrl,
}) => {
const checkBoxStyle = { flexDirection: "row", alignItems: "center" };
+ const [chapterFlags, setChapterFlags] = useState({ sort: "", filter: "" });
+
+ const sortChapters = (sort) => {
+ setChapterFlags({ ...chapterFlags, sort: sort });
+ sortAndFilterChapters(novelUrl, chapterFlags.filter, chapterFlags.sort);
+ };
+
+ const filterChapters = (filter) => {
+ setChapterFlags({ ...chapterFlags, filter: filter });
+ sortAndFilterChapters(novelUrl, chapterFlags.filter, chapterFlags.sort);
+ };
+
const theme = useSelector((state) => state.themeReducer.theme);
return (
@@ -43,7 +40,7 @@ export const BottomSheet = ({
},
]}
>
-
+
sortChapters(newValue)}
- value={sort}
+ value={chapterFlags.sort}
c
>
filterChapters("")}
@@ -129,7 +128,9 @@ export const BottomSheet = ({
{
@@ -136,7 +135,7 @@ const NovelInfoHeader = ({
icon={() => (
)}
- onPress={() => insertNovelInLib()}
+ onPress={() =>
+ insertNovelInLibrary(
+ novel.libraryStatus,
+ novel.novelUrl
+ )
+ }
style={[
{
backgroundColor: theme.colorPrimaryDark,
@@ -168,7 +172,9 @@ const NovelInfoHeader = ({
color: theme.textColorPrimary,
}}
>
- {libraryStatus ? "In Library" : "Add to library"}
+ {novel.libraryStatus
+ ? "In Library"
+ : "Add to library"}
{
sourceUrl: res.sourceUrl,
source: res.sourceName,
unread: 1,
+ libraryStatus: 0,
lastRead: res.novelChapters[0].chapterUrl,
lastReadName: res.novelChapters[0].chapterName,
extensionId: res.extensionId,
diff --git a/src/services/db.js b/src/services/db.js
index f21e6d06..87b1eb86 100644
--- a/src/services/db.js
+++ b/src/services/db.js
@@ -386,8 +386,8 @@ export const downloadChapterFromSource = 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 (?, ?, ?, ?, ?, ?)`,