diff --git a/package-lock.json b/package-lock.json
index ec85fe4e..75fdc685 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -3766,6 +3766,11 @@
"integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
"optional": true
},
+ "fast-memoize": {
+ "version": "2.5.2",
+ "resolved": "https://registry.npmjs.org/fast-memoize/-/fast-memoize-2.5.2.tgz",
+ "integrity": "sha512-Ue0LwpDYErFbmNnZSF0UH6eImUwDmogUO1jyE+JbN2gsQz/jICm1Ve7t9QT0rNSsfJt+Hs4/S3GnsDVjL4HVrw=="
+ },
"fb-watchman": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz",
@@ -7124,6 +7129,14 @@
}
}
},
+ "react-native-collapsible-header-views": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/react-native-collapsible-header-views/-/react-native-collapsible-header-views-1.1.2.tgz",
+ "integrity": "sha512-HjhIKkJa3tkPC6i1G9hh9IdjiG4Df2aB3jU1z1RbNIWBqrCa83BfkstwtbzeAADJVkTBkLTldDd6EbMybbm0DA==",
+ "requires": {
+ "fast-memoize": "^2.5.1"
+ }
+ },
"react-native-gesture-handler": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-1.8.0.tgz",
@@ -7150,6 +7163,11 @@
"react-native-iphone-x-helper": "^1.3.1"
}
},
+ "react-native-read-more-text": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/react-native-read-more-text/-/react-native-read-more-text-1.1.2.tgz",
+ "integrity": "sha512-FIQhOpvikUanwPRl9QVBYmx6Wx7IXxXH/jlzElOLcP+NSgFLw2fRzSekQUq0yicymZsi7cAWW5TtIj8FHWtNDw=="
+ },
"react-native-reanimated": {
"version": "1.13.2",
"resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-1.13.2.tgz",
diff --git a/package.json b/package.json
index 851b59f1..cac01181 100644
--- a/package.json
+++ b/package.json
@@ -21,8 +21,10 @@
"react": "16.13.1",
"react-dom": "16.13.1",
"react-native": "https://github.com/expo/react-native/archive/sdk-40.0.1.tar.gz",
+ "react-native-collapsible-header-views": "^1.1.2",
"react-native-gesture-handler": "~1.8.0",
"react-native-paper": "^4.5.0",
+ "react-native-read-more-text": "^1.1.2",
"react-native-reanimated": "~1.13.0",
"react-native-safe-area-context": "3.1.9",
"react-native-screens": "~2.15.0",
diff --git a/src/navigation/Router.js b/src/navigation/Router.js
index 9f1920b8..3f88a363 100644
--- a/src/navigation/Router.js
+++ b/src/navigation/Router.js
@@ -10,6 +10,7 @@ import Latest from "../screens/Latest";
import More from "../screens/More";
import Search from "../screens/Search";
import NovelItem from "../screens/NovelItem";
+import ChapterItem from "../screens/ChapterItem";
const Stack = createStackNavigator();
@@ -70,6 +71,13 @@ const SearchStack = () => {
headerShown: false,
}}
/>
+
);
};
diff --git a/src/screens/ChapterItem.js b/src/screens/ChapterItem.js
new file mode 100644
index 00000000..204d1211
--- /dev/null
+++ b/src/screens/ChapterItem.js
@@ -0,0 +1,119 @@
+import React, { useState, useEffect } from "react";
+import {
+ StyleSheet,
+ View,
+ Image,
+ ImageBackground,
+ Text,
+ FlatList,
+ ScrollView,
+ RefreshControl,
+} from "react-native";
+import { Appbar } from "react-native-paper";
+import { theme } from "../theming/theme";
+
+const ChapterItem = ({ route, navigation }) => {
+ const { chapterName, chapterUrl } = route.params;
+
+ const [loading, setLoading] = useState(true);
+ const [refreshing, setRefreshing] = useState(true);
+
+ const [chapter, setChapter] = useState();
+
+ useEffect(() => {
+ getChapter();
+ }, []);
+
+ const getChapter = () => {
+ fetch(`http://192.168.1.38:5000/api/${chapterUrl}`)
+ .then((response) => response.json())
+ .then((json) => setChapter(json))
+ .catch((error) => console.error(error))
+ .finally(() => {
+ setRefreshing(false);
+ setLoading(false);
+ });
+ };
+
+ const onRefresh = async () => {
+ setRefreshing(true);
+ getChapter();
+ };
+ return (
+ <>
+
+ {
+ navigation.goBack();
+ }}
+ color={"white"}
+ size={26}
+ style={{ marginRight: 0 }}
+ />
+
+ {!loading && (
+ <>
+ {
+ navigation.navigate("ChapterItem", {
+ chapterUrl: chapter.prevChapter,
+ });
+ }}
+ color={"white"}
+ />
+ {
+ navigation.navigate("ChapterItem", {
+ chapterUrl: chapter.nextChapter,
+ });
+ }}
+ color={"white"}
+ />
+ >
+ )}
+
+
+ }
+ >
+ {!loading && (
+
+ {chapter.chapterText.trim()}
+
+ )}
+
+ >
+ );
+};
+
+export default ChapterItem;
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ backgroundColor: "#202125",
+ paddingHorizontal: 10,
+ paddingVertical: 10,
+ },
+});
diff --git a/src/screens/NovelItem.js b/src/screens/NovelItem.js
index 42770238..4fb2419d 100644
--- a/src/screens/NovelItem.js
+++ b/src/screens/NovelItem.js
@@ -3,33 +3,49 @@ import {
StyleSheet,
View,
Image,
- ActivityIndicator,
ImageBackground,
Text,
FlatList,
+ ScrollView,
+ RefreshControl,
} from "react-native";
-import { Appbar } from "react-native-paper";
+import { Appbar, TouchableRipple } from "react-native-paper";
import { LinearGradient } from "expo-linear-gradient";
-import { ScrollView } from "react-native-gesture-handler";
+
+import { theme } from "../theming/theme";
const NovelItem = ({ route, navigation }) => {
const item = route.params;
const [loading, setLoading] = useState(true);
- const [novel, setNovel] = useState();
+ const [refreshing, setRefreshing] = useState(true);
- useEffect(() => {
+ const [novel, setNovel] = useState();
+ const [more, setMore] = useState(false);
+
+ const getNovel = () => {
fetch(`http://192.168.1.38:5000/api/novel/${item.novelUrl}`)
.then((response) => response.json())
.then((json) => setNovel(json))
.catch((error) => console.error(error))
.finally(() => {
+ setRefreshing(false);
setLoading(false);
});
+ };
+
+ useEffect(() => {
+ getNovel();
}, []);
+
+ const onRefresh = async () => {
+ setRefreshing(true);
+ getNovel();
+ };
+
return (
<>
-
+
{
navigation.goBack();
@@ -40,10 +56,20 @@ const NovelItem = ({ route, navigation }) => {
/>
-
+
+ }
+ >
{
}}
style={styles.logo}
/>
+
+
+ {item.novelName}
+
+ {!loading && (
+ <>
+
+ {novel.novelDetails[
+ "Alternative"
+ ].replace(",", ", ")}
+
+
+ {novel.novelDetails[
+ "Author(s)"
+ ].replace(",", ", ")}
+
+
+ {novel.novelDetails["Release"]}
+
+
+ {novel.novelDetails["Status"] +
+ " • " +
+ novel.novelDetails["Type"]}
+
+ >
+ )}
+
- {loading ? (
-
-
-
- ) : (
+ {!loading && (
<>
+
+
+ About
+
+ setMore(!more)}
+ ellipsizeMode="clip"
+ >
+ {novel.novelSummary}
+
+ setMore(!more)}
+ >
+ {more ? "Less" : "More"}
+
+
+
+ item}
+ renderItem={({ item }) => (
+
+ {item}
+
+ )}
+ />
+
+
+ {novel.novelChapters.length + " Chapters"}
+
item.chapterUrl}
+ removeClippedSubviews={true}
+ maxToRenderPerBatch={10}
+ initialNumToRender={10}
renderItem={({ item }) => (
- <>
-
- {item.chapterName}
-
-
- {item.releaseDate}
-
- >
+
+ navigation.navigate("ChapterItem", {
+ chapterName: item.chapterName,
+ chapterUrl: item.chapterUrl,
+ })
+ }
+ rippleColor={theme.rippleColorDark}
+ >
+ <>
+
+ {item.chapterName}
+
+
+ {item.releaseDate}
+
+ >
+
)}
/>
>
@@ -115,6 +285,12 @@ const styles = StyleSheet.create({
flex: 1,
backgroundColor: "#202125",
},
+ nameContainer: {
+ flex: 1,
+ width: "100%",
+ marginHorizontal: 15,
+ // justifyContent: "center",
+ },
background: {
height: 240,
},
@@ -125,7 +301,7 @@ const styles = StyleSheet.create({
detailsContainer: {
flex: 1,
flexDirection: "row",
- margin: 17,
+ margin: 15,
},
logo: {
height: 180,
@@ -133,4 +309,18 @@ const styles = StyleSheet.create({
margin: 3.2,
borderRadius: 6,
},
+ genre: {
+ borderRadius: 24,
+ borderWidth: 1,
+ paddingHorizontal: 10,
+ marginHorizontal: 2,
+ fontSize: 13,
+ paddingVertical: 1,
+ justifyContent: "center",
+ flex: 1,
+ },
+ name: {
+ fontWeight: "bold",
+ fontSize: 20,
+ },
});
diff --git a/src/theming/theme.js b/src/theming/theme.js
new file mode 100644
index 00000000..c41af600
--- /dev/null
+++ b/src/theming/theme.js
@@ -0,0 +1,9 @@
+export const theme = {
+ colorDarkPrimary: "#242529",
+ colorDarkPrimaryDark: "#202125",
+ colorAccentDark: "#3399FF",
+ textColorPrimaryDark: "#FFFFFF",
+ textColorSecondaryDark: "rgba(265,265,265,0.7)",
+ textColorHintDark: "rgba(265,265,265,0.5)",
+ rippleColorDark: "rgba(265,265,265,0.2)",
+};