Add screens, custom font, navigation

This commit is contained in:
Rajarshee Chatterjee
2020-12-23 21:21:29 +05:30
parent dd7727a218
commit 0ca0d79968
12 changed files with 1582 additions and 51 deletions
+29 -6
View File
@@ -1,11 +1,34 @@
import React from "react";
import React, { useState } from "react";
import Router from "./src/navigation/Router";
import { NavigationContainer } from "@react-navigation/native";
import { StatusBar } from "expo-status-bar";
import * as Font from "expo-font";
import AppLoading from "expo-app-loading";
const getFonts = () =>
Font.loadAsync({
"pt-sans-bold": require("./assets/fonts/PTSansNarrow-Bold.ttf"),
});
export default function App() {
return (
<NavigationContainer>
<Router />
</NavigationContainer>
);
const [fontsLoaded, setFontsLoaded] = useState(false);
if (fontsLoaded) {
return (
<>
<StatusBar style="light" />
<NavigationContainer>
<Router />
</NavigationContainer>
</>
);
} else {
return (
<AppLoading
startAsync={getFonts}
onError={() => warn(error)}
onFinish={() => setFontsLoaded(true)}
/>
);
}
}
Binary file not shown.
+1042
View File
File diff suppressed because it is too large Load Diff
+35 -30
View File
@@ -1,32 +1,37 @@
{
"main": "node_modules/expo/AppEntry.js",
"scripts": {
"start": "expo start",
"android": "expo start --android",
"ios": "expo start --ios",
"web": "expo start --web",
"eject": "expo eject"
},
"dependencies": {
"@react-native-community/masked-view": "0.1.10",
"@react-navigation/material-bottom-tabs": "^5.3.10",
"@react-navigation/native": "^5.8.10",
"@react-navigation/stack": "^5.12.8",
"expo": "~40.0.0",
"expo-status-bar": "~1.0.3",
"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-gesture-handler": "~1.8.0",
"react-native-paper": "^4.5.0",
"react-native-reanimated": "~1.13.0",
"react-native-safe-area-context": "3.1.9",
"react-native-screens": "~2.15.0",
"react-native-vector-icons": "^7.1.0",
"react-native-web": "~0.13.12"
},
"devDependencies": {
"@babel/core": "~7.9.0"
},
"private": true
"main": "node_modules/expo/AppEntry.js",
"scripts": {
"start": "expo start",
"android": "expo start --android",
"ios": "expo start --ios",
"web": "expo start --web",
"eject": "expo eject"
},
"dependencies": {
"@react-native-community/masked-view": "0.1.10",
"@react-navigation/material-bottom-tabs": "^5.3.10",
"@react-navigation/native": "^5.8.10",
"@react-navigation/stack": "^5.12.8",
"cheerio-without-node-native": "^0.20.2",
"expo": "~40.0.0",
"expo-app-loading": "^1.0.1",
"expo-font": "^8.4.0",
"expo-linear-gradient": "^8.4.0",
"expo-status-bar": "~1.0.3",
"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-gesture-handler": "~1.8.0",
"react-native-paper": "^4.5.0",
"react-native-reanimated": "~1.13.0",
"react-native-safe-area-context": "3.1.9",
"react-native-screens": "~2.15.0",
"react-native-vector-icons": "^7.1.0",
"react-native-web": "~0.13.12"
},
"devDependencies": {
"@babel/core": "~7.9.0"
},
"private": true,
"proxy": "http://192.168.1.38:5000"
}
+52
View File
@@ -0,0 +1,52 @@
import React from "react";
import { StyleSheet, View, Text, ImageBackground } from "react-native";
import { LinearGradient } from "expo-linear-gradient";
const NovelCover = ({ item }) => {
return (
<ImageBackground
source={{
uri: item.novelCover,
}}
style={styles.logo}
imageStyle={{ borderRadius: 6 }}
>
<View style={styles.titleContainer}>
<LinearGradient
colors={["transparent", "black"]}
style={styles.linearGradient}
>
<Text numberOfLines={2} style={styles.title}>
{item.novelName}
</Text>
</LinearGradient>
</View>
</ImageBackground>
);
};
export default NovelCover;
const styles = StyleSheet.create({
logo: {
height: "100%",
borderRadius: 6,
},
titleContainer: {
position: "absolute",
bottom: 0,
left: 0,
width: "100%",
borderRadius: 6,
},
title: {
fontFamily: "pt-sans-bold",
fontSize: 15,
color: "white",
padding: 5,
width: "100%",
},
linearGradient: {
borderRadius: 6,
},
});
+108 -4
View File
@@ -1,15 +1,106 @@
import React from "react";
import { createStackNavigator } from "@react-navigation/stack";
import { createMaterialBottomTabNavigator } from "@react-navigation/material-bottom-tabs";
import MaterialCommunityIcons from "react-native-vector-icons/MaterialCommunityIcons";
import Library from "../screens/Library";
import Updates from "../screens/Updates";
import Browse from "../screens/Browse";
import More from "../screens/More";
import Search from "../screens/Search";
import NovelItem from "../screens/NovelItem";
import { CardStyleInterpolators } from "@react-navigation/stack";
const Stack = createStackNavigator();
const Tab = createMaterialBottomTabNavigator();
const LibraryStack = () => {
return (
<Stack.Navigator
screenOptions={{
headerTintColor: "white",
headerStyle: { backgroundColor: "#242529" },
}}
>
<Stack.Screen name="Library" component={Library} />
</Stack.Navigator>
);
};
const BrowseStack = () => {
return (
<Stack.Navigator
screenOptions={{
headerTintColor: "white",
headerStyle: { backgroundColor: "#242529" },
}}
>
<Stack.Screen name="Browse" component={Browse} />
<Stack.Screen
name="NovelItem"
component={NovelItem}
options={{
headerShown: false,
}}
/>
</Stack.Navigator>
);
};
const SearchStack = () => {
return (
<Stack.Navigator
screenOptions={{
headerTintColor: "white",
headerStyle: { backgroundColor: "#242529" },
}}
>
<Stack.Screen
name="Search"
component={Search}
options={{
headerShown: false,
}}
/>
<Stack.Screen
name="NovelItem"
component={NovelItem}
options={{
headerShown: false,
}}
/>
</Stack.Navigator>
);
};
const UpdatesStack = () => {
return (
<Stack.Navigator
screenOptions={{
headerTintColor: "white",
headerStyle: { backgroundColor: "#242529" },
}}
>
<Stack.Screen name="Updates" component={Updates} />
</Stack.Navigator>
);
};
const MoreStack = () => {
return (
<Stack.Navigator
screenOptions={{
headerTintColor: "white",
headerStyle: { backgroundColor: "#242529" },
}}
>
<Stack.Screen name="More" component={More} />
</Stack.Navigator>
);
};
const Router = () => {
return (
<Tab.Navigator
@@ -19,7 +110,7 @@ const Router = () => {
>
<Tab.Screen
name="Library"
component={Library}
component={LibraryStack}
options={{
tabBarIcon: ({ color }) => (
<MaterialCommunityIcons
@@ -32,7 +123,7 @@ const Router = () => {
/>
<Tab.Screen
name="Updates"
component={Updates}
component={UpdatesStack}
options={{
tabBarIcon: ({ color }) => (
<MaterialCommunityIcons
@@ -43,9 +134,22 @@ const Router = () => {
),
}}
/>
<Tab.Screen
name="Search"
component={SearchStack}
options={{
tabBarIcon: ({ color }) => (
<MaterialCommunityIcons
name="magnify"
color={color}
size={24}
/>
),
}}
/>
<Tab.Screen
name="Browse"
component={Browse}
component={BrowseStack}
options={{
tabBarIcon: ({ color }) => (
<MaterialCommunityIcons
@@ -58,7 +162,7 @@ const Router = () => {
/>
<Tab.Screen
name="More"
component={More}
component={MoreStack}
options={{
tabBarIcon: ({ color }) => (
<MaterialCommunityIcons
+60 -5
View File
@@ -1,8 +1,63 @@
import React from "react";
import { Text } from "react-native";
import React, { useEffect, useState } from "react";
import { StyleSheet, View, FlatList, ActivityIndicator } from "react-native";
import { TouchableRipple } from "react-native-paper";
import NovelCover from "../components/NovelCover";
const MoreScreen = () => {
return <Text>Browse</Text>;
const BrowseScreen = ({ navigation }) => {
const [loading, setLoading] = useState(true);
const [novels, setNovels] = useState();
useEffect(() => {
fetch("http://192.168.1.38:5000/api/latest")
.then((response) => response.json())
.then((json) => setNovels(json))
.catch((error) => console.error(error))
.finally(() => {
setLoading(false);
});
}, []);
return (
<View style={styles.container}>
{loading ? (
<View style={{ flex: 1, justifyContent: "center" }}>
<ActivityIndicator size="large" color="white" />
</View>
) : (
<FlatList
contentContainerStyle={styles.list}
numColumns={3}
data={novels}
showsVerticalScrollIndicator={false}
renderItem={({ item }) => (
<TouchableRipple
borderless
centered
rippleColor="rgba(256,256,256,0.3)"
style={styles.opac}
onPress={() =>
navigation.navigate("NovelItem", item)
}
>
<NovelCover item={item} />
</TouchableRipple>
)}
/>
)}
</View>
);
};
export default MoreScreen;
export default BrowseScreen;
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#202125",
},
opac: {
height: 190,
flex: 1 / 3,
margin: 3.2,
},
});
+13 -2
View File
@@ -1,8 +1,19 @@
import React from "react";
import { Text } from "react-native";
import { StyleSheet, Text, View } from "react-native";
const MoreScreen = () => {
return <Text>More</Text>;
return (
<View style={styles.container}>
<Text style={{ color: "#FFFFFF" }}>More</Text>
</View>
);
};
export default MoreScreen;
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#202125",
},
});
+102
View File
@@ -0,0 +1,102 @@
import React, { useState, useEffect } from "react";
import {
StyleSheet,
View,
Image,
ActivityIndicator,
ImageBackground,
} from "react-native";
import { Appbar } from "react-native-paper";
import { LinearGradient } from "expo-linear-gradient";
const NovelItem = ({ route, navigation }) => {
const item = route.params;
const [loading, setLoading] = useState(true);
const [novel, setNovel] = useState();
useEffect(() => {
fetch("http://192.168.1.38:5000/api/" + item.novelUrl)
.then((response) => response.json())
.then((json) => setNovel(json))
.catch((error) => console.error(error))
.finally(() => {
setLoading(false);
});
}, []);
return (
<>
<Appbar.Header style={{ backgroundColor: "#242529" }}>
<Appbar.BackAction
onPress={() => {
navigation.goBack();
}}
color={"white"}
size={26}
style={{ marginRight: 0 }}
/>
<Appbar.Content
title={item.novelName}
titleStyle={{ color: "white" }}
/>
</Appbar.Header>
<View style={styles.container}>
{loading ? (
<View style={{ flex: 1, justifyContent: "center" }}>
<ActivityIndicator size="large" color="white" />
</View>
) : (
<>
<ImageBackground
source={{
uri: item.novelCover,
}}
style={styles.background}
>
<LinearGradient
colors={["transparent", "#202125"]}
style={styles.linearGradient}
>
<View style={styles.detailsContainer}>
<Image
source={{
uri: item.novelCover,
}}
style={styles.logo}
/>
</View>
</LinearGradient>
</ImageBackground>
</>
)}
</View>
</>
);
};
export default NovelItem;
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#202125",
},
background: {
height: 240,
},
linearGradient: {
height: "100%",
backgroundColor: "rgba(256, 256, 256, 0.5)",
},
detailsContainer: {
flex: 1,
flexDirection: "row",
margin: 17,
},
logo: {
height: 180,
width: 120,
margin: 3.2,
borderRadius: 6,
},
});
+114
View File
@@ -0,0 +1,114 @@
import React, { useState } from "react";
import {
StyleSheet,
Text,
View,
TextInput,
FlatList,
ActivityIndicator,
} from "react-native";
import { Appbar, TouchableRipple } from "react-native-paper";
import NovelCover from "../components/NovelCover";
const SearchScreen = ({ navigation }) => {
const [loading, setLoading] = useState(false);
const [novels, setNovels] = useState([]);
const [searchText, setSearchText] = useState("");
const getNovels = (searchText) => {
setLoading(true);
setNovels([]);
fetch(`http://192.168.1.38:5000/api/search/?s=${searchText}&?o=rating`)
.then((response) => response.json())
.then((json) => setNovels(json))
.catch((error) => console.error(error))
.finally(() => setLoading(false));
};
return (
<>
<Appbar.Header style={{ backgroundColor: "#202125" }}>
<Appbar.BackAction
onPress={() => {
navigation.goBack();
setNovels([]);
}}
color={"white"}
size={26}
/>
<TextInput
placeholder="Search Light Novels..."
defaultValue={searchText}
style={{ fontSize: 17, flex: 1, color: "white" }}
placeholderTextColor="#e0e0e0"
blurOnSubmit={true}
onChangeText={(text) => {
setSearchText(text);
getNovels(searchText);
}}
/>
{searchText !== "" && (
<Appbar.Action
icon="close"
onPress={() => {
setSearchText("");
}}
color={"white"}
/>
)}
</Appbar.Header>
<View style={styles.container}>
{loading ? (
<View style={{ flex: 1, justifyContent: "center" }}>
<ActivityIndicator size="large" color="white" />
</View>
) : (
<FlatList
contentContainerStyle={styles.list}
numColumns={3}
data={novels}
showsVerticalScrollIndicator={false}
renderItem={({ item }) => (
<TouchableRipple
borderless
centered
rippleColor="rgba(256,256,256,0.3)"
style={styles.opac}
onPress={() =>
navigation.navigate("NovelItem", item)
}
>
<NovelCover item={item} />
</TouchableRipple>
)}
/>
)}
</View>
</>
);
};
export default SearchScreen;
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#202125",
},
textInput: {
alignItems: "center",
backgroundColor: "#E6E8E9",
borderRadius: 10,
color: "#8E8E93",
flexDirection: "row",
fontSize: 17,
height: 43,
margin: 8,
marginVertical: 10,
paddingHorizontal: 10,
},
opac: {
height: 190,
flex: 1 / 3,
margin: 3.2,
},
});
+15 -4
View File
@@ -1,8 +1,19 @@
import React from "react";
import { Text } from "react-native";
import { StyleSheet, Text, View } from "react-native";
const MoreScreen = () => {
return <Text>Updates</Text>;
const UpdatesScreen = () => {
return (
<View style={styles.container}>
<Text style={{ color: "#FFFFFF" }}>Update</Text>
</View>
);
};
export default MoreScreen;
export default UpdatesScreen;
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#202125",
},
});
+12
View File
@@ -0,0 +1,12 @@
import cheerio from "cheerio-without-node-native";
const baseUrl = "https://boxnovel.com/";
export const getLatest = async () => {
const response = await fetch(baseUrl); // fetch page
const htmlString = await response.text(); // get response text
const $ = cheerio.load(htmlString); // parse HTML string
let title = $("title");
console.log(title.text());
};