Add chapter screen

This commit is contained in:
Rajarshee Chatterjee
2020-12-24 10:03:21 +05:30
parent 23dcc74e22
commit 22f9533d20
6 changed files with 384 additions and 38 deletions
+18
View File
@@ -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",
+2
View File
@@ -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",
+8
View File
@@ -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,
}}
/>
<Stack.Screen
name="ChapterItem"
component={ChapterItem}
options={{
headerShown: false,
}}
/>
</Stack.Navigator>
);
};
+119
View File
@@ -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 (
<>
<Appbar.Header style={{ backgroundColor: theme.colorDarkPrimary }}>
<Appbar.BackAction
onPress={() => {
navigation.goBack();
}}
color={"white"}
size={26}
style={{ marginRight: 0 }}
/>
<Appbar.Content
title={loading ? "Chapter" : chapter.chapterName}
titleStyle={{ color: theme.textColorPrimaryDark }}
/>
{!loading && (
<>
<Appbar.Action
icon="chevron-left"
size={26}
disabled={!chapter.prevChapter}
onPress={() => {
navigation.navigate("ChapterItem", {
chapterUrl: chapter.prevChapter,
});
}}
color={"white"}
/>
<Appbar.Action
icon="chevron-right"
size={26}
disabled={!chapter.nextChapter}
onPress={() => {
navigation.navigate("ChapterItem", {
chapterUrl: chapter.nextChapter,
});
}}
color={"white"}
/>
</>
)}
</Appbar.Header>
<ScrollView
style={styles.container}
refreshControl={
<RefreshControl
refreshing={refreshing}
onRefresh={onRefresh}
colors={["white"]}
progressBackgroundColor={theme.colorAccentDark}
/>
}
>
{!loading && (
<Text
style={{
color: theme.textColorPrimaryDark,
lineHeight: 20,
}}
>
{chapter.chapterText.trim()}
</Text>
)}
</ScrollView>
</>
);
};
export default ChapterItem;
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#202125",
paddingHorizontal: 10,
paddingVertical: 10,
},
});
+228 -38
View File
@@ -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 (
<>
<Appbar.Header style={{ backgroundColor: "#242529" }}>
<Appbar.Header style={{ backgroundColor: theme.colorDarkPrimary }}>
<Appbar.BackAction
onPress={() => {
navigation.goBack();
@@ -40,10 +56,20 @@ const NovelItem = ({ route, navigation }) => {
/>
<Appbar.Content
title={item.novelName}
titleStyle={{ color: "white" }}
titleStyle={{ color: theme.textColorPrimaryDark }}
/>
</Appbar.Header>
<ScrollView style={styles.container}>
<ScrollView
style={styles.container}
refreshControl={
<RefreshControl
refreshing={refreshing}
onRefresh={onRefresh}
colors={["white"]}
progressBackgroundColor={theme.colorAccentDark}
/>
}
>
<ImageBackground
source={{
uri: item.novelCover,
@@ -61,44 +87,188 @@ const NovelItem = ({ route, navigation }) => {
}}
style={styles.logo}
/>
<View style={styles.nameContainer}>
<Text
numberOfLines={4}
style={[
styles.name,
{ color: theme.textColorPrimaryDark },
]}
>
{item.novelName}
</Text>
{!loading && (
<>
<Text
style={{
color:
theme.textColorSecondaryDark,
marginVertical: 3,
fontSize: 16,
}}
>
{novel.novelDetails[
"Alternative"
].replace(",", ", ")}
</Text>
<Text
style={{
color:
theme.textColorSecondaryDark,
marginVertical: 3,
fontSize: 16,
}}
>
{novel.novelDetails[
"Author(s)"
].replace(",", ", ")}
</Text>
<Text
style={{
color:
theme.textColorSecondaryDark,
marginVertical: 3,
fontSize: 16,
}}
>
{novel.novelDetails["Release"]}
</Text>
<Text
style={{
color:
theme.textColorSecondaryDark,
marginVertical: 3,
fontSize: 16,
}}
>
{novel.novelDetails["Status"] +
" • " +
novel.novelDetails["Type"]}
</Text>
</>
)}
</View>
</View>
</LinearGradient>
</ImageBackground>
{loading ? (
<View style={{ flex: 1, justifyContent: "center" }}>
<ActivityIndicator size="large" color="white" />
</View>
) : (
{!loading && (
<>
<View
style={{ paddingHorizontal: 15, marginBottom: 10 }}
>
<Text
style={{
color: theme.textColorPrimaryDark,
marginTop: 5,
paddingVertical: 5,
fontSize: 15,
}}
>
About
</Text>
<Text
style={{
color: theme.textColorSecondaryDark,
lineHeight: 20,
}}
numberOfLines={more ? 100 : 2}
onPress={() => setMore(!more)}
ellipsizeMode="clip"
>
{novel.novelSummary}
</Text>
<Text
style={{
color: theme.colorAccentDark,
fontWeight: "bold",
position: "absolute",
bottom: 0,
right: 15,
}}
onPress={() => setMore(!more)}
>
{more ? "Less" : "More"}
</Text>
</View>
<FlatList
contentContainerStyle={{
paddingHorizontal: 15,
marginBottom: 10,
}}
horizontal
data={novel.novelDetails["Genre(s)"].split(",")}
keyExtractor={(item) => item}
renderItem={({ item }) => (
<Text
style={[
styles.genre,
{
color: theme.colorAccentDark,
borderColor: theme.colorAccentDark,
},
]}
>
{item}
</Text>
)}
/>
<Text
style={{
color: theme.textColorPrimaryDark,
paddingHorizontal: 15,
marginTop: 5,
paddingVertical: 5,
fontSize: 15,
}}
>
{novel.novelChapters.length + " Chapters"}
</Text>
<FlatList
data={novel.novelChapters}
showsVerticalScrollIndicator={false}
keyExtractor={(item) => item.chapterUrl}
removeClippedSubviews={true}
maxToRenderPerBatch={10}
initialNumToRender={10}
renderItem={({ item }) => (
<>
<Text
style={{
color: "white",
paddingLeft: 7,
paddingRight: 7,
paddingTop: 15,
}}
numberOfLines={1}
>
{item.chapterName}
</Text>
<Text
style={{
color: "grey",
paddingLeft: 7,
paddingBottom: 7,
fontSize: 13,
}}
numberOfLines={1}
>
{item.releaseDate}
</Text>
</>
<TouchableRipple
style={{
paddingHorizontal: 15,
paddingVertical: 12,
}}
onPress={() =>
navigation.navigate("ChapterItem", {
chapterName: item.chapterName,
chapterUrl: item.chapterUrl,
})
}
rippleColor={theme.rippleColorDark}
>
<>
<Text
style={{
color:
theme.textColorPrimaryDark,
}}
numberOfLines={1}
>
{item.chapterName}
</Text>
<Text
style={{
color:
theme.textColorSecondaryDark,
marginTop: 5,
fontSize: 13,
}}
numberOfLines={1}
>
{item.releaseDate}
</Text>
</>
</TouchableRipple>
)}
/>
</>
@@ -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,
},
});
+9
View File
@@ -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)",
};