Add library screen
This commit is contained in:
Generated
+14
-5
@@ -2681,6 +2681,11 @@
|
||||
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz",
|
||||
"integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ=="
|
||||
},
|
||||
"clamp": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/clamp/-/clamp-1.0.1.tgz",
|
||||
"integrity": "sha1-ZqDmQBGBbjcZaCj9yMjBRzEshjQ="
|
||||
},
|
||||
"class-utils": {
|
||||
"version": "0.3.6",
|
||||
"resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz",
|
||||
@@ -7163,11 +7168,6 @@
|
||||
"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",
|
||||
@@ -7435,6 +7435,15 @@
|
||||
"glob": "^7.1.3"
|
||||
}
|
||||
},
|
||||
"rn-sliding-up-panel": {
|
||||
"version": "2.4.4",
|
||||
"resolved": "https://registry.npmjs.org/rn-sliding-up-panel/-/rn-sliding-up-panel-2.4.4.tgz",
|
||||
"integrity": "sha512-NbvDiDVsRosno1t7BXMnw+ZmusznqNC0R7px9JcJNNLLfIdGmfwpJI+RCFz5t/pDSO2Jql4093W2On+mYLrX8Q==",
|
||||
"requires": {
|
||||
"clamp": "^1.0.1",
|
||||
"prop-types": "^15.7.2"
|
||||
}
|
||||
},
|
||||
"rsvp": {
|
||||
"version": "4.8.5",
|
||||
"resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz",
|
||||
|
||||
+4
-4
@@ -22,14 +22,14 @@
|
||||
"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-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-reanimated": "^1.13.2",
|
||||
"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"
|
||||
"react-native-web": "~0.13.12",
|
||||
"rn-sliding-up-panel": "^2.4.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "~7.9.0"
|
||||
|
||||
@@ -0,0 +1,172 @@
|
||||
import React from "react";
|
||||
import { StyleSheet, View } from "react-native";
|
||||
import { List } from "react-native-paper";
|
||||
import Bottomsheet from "rn-sliding-up-panel";
|
||||
import { theme } from "../theming/theme";
|
||||
|
||||
export const BottomSheet = ({
|
||||
bottomSheetRef,
|
||||
setSort,
|
||||
sort,
|
||||
setRefreshing,
|
||||
}) => (
|
||||
<Bottomsheet
|
||||
ref={bottomSheetRef}
|
||||
draggableRange={{ top: 370, bottom: 0 }}
|
||||
snappingPoints={[0, 370]}
|
||||
>
|
||||
<View
|
||||
style={[
|
||||
styles.contentContainer,
|
||||
{
|
||||
backgroundColor: theme.colorDarkPrimary,
|
||||
},
|
||||
]}
|
||||
>
|
||||
<List.Section
|
||||
title="Sort"
|
||||
titleStyle={{
|
||||
color: theme.colorAccentDark,
|
||||
fontWeight: "bold",
|
||||
}}
|
||||
style={{
|
||||
color: theme.colorAccentDark,
|
||||
// backgroundColor: theme.colorAccentDark,
|
||||
}}
|
||||
expanded
|
||||
>
|
||||
<List.Item
|
||||
right={(props) =>
|
||||
sort === "latest" && (
|
||||
<List.Icon
|
||||
{...props}
|
||||
size
|
||||
icon="arrow-up"
|
||||
color={theme.colorAccentDark}
|
||||
/>
|
||||
)
|
||||
}
|
||||
title="Latest"
|
||||
titleStyle={{
|
||||
fontSize: 15,
|
||||
color: theme.textColorPrimaryDark,
|
||||
}}
|
||||
onPress={() => setSort("latest")}
|
||||
/>
|
||||
<List.Item
|
||||
right={(props) =>
|
||||
sort === "alphabet" && (
|
||||
<List.Icon
|
||||
{...props}
|
||||
size
|
||||
icon="arrow-up"
|
||||
color={theme.colorAccentDark}
|
||||
/>
|
||||
)
|
||||
}
|
||||
title="A-Z"
|
||||
titleStyle={{
|
||||
fontSize: 15,
|
||||
color: theme.textColorPrimaryDark,
|
||||
}}
|
||||
onPress={() => {
|
||||
setSort("alphabet");
|
||||
setRefreshing(true);
|
||||
}}
|
||||
/>
|
||||
<List.Item
|
||||
right={(props) =>
|
||||
sort === "rating" && (
|
||||
<List.Icon
|
||||
{...props}
|
||||
size
|
||||
icon="arrow-up"
|
||||
color={theme.colorAccentDark}
|
||||
/>
|
||||
)
|
||||
}
|
||||
title="Rating"
|
||||
titleStyle={{
|
||||
fontSize: 15,
|
||||
color: theme.textColorPrimaryDark,
|
||||
}}
|
||||
onPress={() => {
|
||||
setSort("rating");
|
||||
setRefreshing(true);
|
||||
}}
|
||||
/>
|
||||
<List.Item
|
||||
right={(props) =>
|
||||
sort === "trending" && (
|
||||
<List.Icon
|
||||
{...props}
|
||||
size
|
||||
icon="arrow-up"
|
||||
color={theme.colorAccentDark}
|
||||
/>
|
||||
)
|
||||
}
|
||||
title="Trending"
|
||||
titleStyle={{
|
||||
fontSize: 15,
|
||||
color: theme.textColorPrimaryDark,
|
||||
}}
|
||||
onPress={() => {
|
||||
setSort("trending");
|
||||
setRefreshing(true);
|
||||
}}
|
||||
/>
|
||||
<List.Item
|
||||
right={(props) =>
|
||||
sort === "views" && (
|
||||
<List.Icon
|
||||
{...props}
|
||||
size
|
||||
icon="arrow-up"
|
||||
color={theme.colorAccentDark}
|
||||
/>
|
||||
)
|
||||
}
|
||||
title="Most Views"
|
||||
titleStyle={{
|
||||
fontSize: 15,
|
||||
color: theme.textColorPrimaryDark,
|
||||
}}
|
||||
onPress={() => {
|
||||
setSort("views");
|
||||
setRefreshing(true);
|
||||
}}
|
||||
/>
|
||||
<List.Item
|
||||
right={(props) =>
|
||||
sort === "new-manga" && (
|
||||
<List.Icon
|
||||
{...props}
|
||||
size
|
||||
icon="arrow-up"
|
||||
color={theme.colorAccentDark}
|
||||
/>
|
||||
)
|
||||
}
|
||||
title="New"
|
||||
titleStyle={{
|
||||
fontSize: 15,
|
||||
color: theme.textColorPrimaryDark,
|
||||
}}
|
||||
onPress={() => {
|
||||
setSort("new-manga");
|
||||
setRefreshing(true);
|
||||
}}
|
||||
/>
|
||||
</List.Section>
|
||||
</View>
|
||||
</Bottomsheet>
|
||||
);
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
contentContainer: {
|
||||
flex: 1,
|
||||
// paddingTop: ,
|
||||
// alignItems: "center",
|
||||
},
|
||||
});
|
||||
@@ -10,6 +10,7 @@ const NovelCover = ({ item }) => {
|
||||
}}
|
||||
style={styles.logo}
|
||||
imageStyle={{ borderRadius: 6 }}
|
||||
progressiveRenderingEnabled={true}
|
||||
>
|
||||
<View style={styles.titleContainer}>
|
||||
<LinearGradient
|
||||
|
||||
+44
-35
@@ -1,6 +1,7 @@
|
||||
import React from "react";
|
||||
import { createStackNavigator } from "@react-navigation/stack";
|
||||
import { createMaterialBottomTabNavigator } from "@react-navigation/material-bottom-tabs";
|
||||
import { theme } from "../theming/theme";
|
||||
|
||||
import MaterialCommunityIcons from "react-native-vector-icons/MaterialCommunityIcons";
|
||||
|
||||
@@ -11,6 +12,7 @@ import More from "../screens/More";
|
||||
import Search from "../screens/Search";
|
||||
import NovelItem from "../screens/NovelItem";
|
||||
import ChapterItem from "../screens/ChapterItem";
|
||||
import About from "../screens/About";
|
||||
|
||||
const Stack = createStackNavigator();
|
||||
|
||||
@@ -20,11 +22,15 @@ const LibraryStack = () => {
|
||||
return (
|
||||
<Stack.Navigator
|
||||
screenOptions={{
|
||||
headerTintColor: "white",
|
||||
headerStyle: { backgroundColor: "#242529" },
|
||||
headerTintColor: theme.textColorPrimaryDark,
|
||||
headerStyle: { backgroundColor: theme.colorDarkPrimary },
|
||||
}}
|
||||
>
|
||||
<Stack.Screen name="Library" component={Library} />
|
||||
<Stack.Screen
|
||||
name="Library"
|
||||
component={Library}
|
||||
options={{ headerShown: false }}
|
||||
/>
|
||||
</Stack.Navigator>
|
||||
);
|
||||
};
|
||||
@@ -33,18 +39,11 @@ const LatestStack = () => {
|
||||
return (
|
||||
<Stack.Navigator
|
||||
screenOptions={{
|
||||
headerTintColor: "white",
|
||||
headerStyle: { backgroundColor: "#242529" },
|
||||
headerTintColor: theme.textColorPrimaryDark,
|
||||
headerStyle: { backgroundColor: theme.colorDarkPrimary },
|
||||
}}
|
||||
>
|
||||
<Stack.Screen name="Latest" component={Latest} />
|
||||
<Stack.Screen
|
||||
name="NovelItem"
|
||||
component={NovelItem}
|
||||
options={{
|
||||
headerShown: false,
|
||||
}}
|
||||
/>
|
||||
</Stack.Navigator>
|
||||
);
|
||||
};
|
||||
@@ -53,8 +52,8 @@ const SearchStack = () => {
|
||||
return (
|
||||
<Stack.Navigator
|
||||
screenOptions={{
|
||||
headerTintColor: "white",
|
||||
headerStyle: { backgroundColor: "#242529" },
|
||||
headerTintColor: theme.textColorPrimaryDark,
|
||||
headerStyle: { backgroundColor: theme.colorDarkPrimary },
|
||||
}}
|
||||
>
|
||||
<Stack.Screen
|
||||
@@ -64,20 +63,6 @@ const SearchStack = () => {
|
||||
headerShown: false,
|
||||
}}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name="NovelItem"
|
||||
component={NovelItem}
|
||||
options={{
|
||||
headerShown: false,
|
||||
}}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name="ChapterItem"
|
||||
component={ChapterItem}
|
||||
options={{
|
||||
headerShown: false,
|
||||
}}
|
||||
/>
|
||||
</Stack.Navigator>
|
||||
);
|
||||
};
|
||||
@@ -86,8 +71,8 @@ const UpdatesStack = () => {
|
||||
return (
|
||||
<Stack.Navigator
|
||||
screenOptions={{
|
||||
headerTintColor: "white",
|
||||
headerStyle: { backgroundColor: "#242529" },
|
||||
headerTintColor: theme.textColorPrimaryDark,
|
||||
headerStyle: { backgroundColor: theme.colorDarkPrimary },
|
||||
}}
|
||||
>
|
||||
<Stack.Screen name="Updates" component={Updates} />
|
||||
@@ -98,8 +83,8 @@ const MoreStack = () => {
|
||||
return (
|
||||
<Stack.Navigator
|
||||
screenOptions={{
|
||||
headerTintColor: "white",
|
||||
headerStyle: { backgroundColor: "#242529" },
|
||||
headerTintColor: theme.textColorPrimaryDark,
|
||||
headerStyle: { backgroundColor: theme.colorDarkPrimary },
|
||||
}}
|
||||
>
|
||||
<Stack.Screen name="More" component={More} />
|
||||
@@ -111,11 +96,11 @@ const Router = () => {
|
||||
return (
|
||||
<Tab.Navigator
|
||||
shifting={false}
|
||||
barStyle={{ backgroundColor: "#242529" }}
|
||||
barStyle={{ backgroundColor: theme.colorDarkPrimary }}
|
||||
activeColor="#3399FF"
|
||||
>
|
||||
<Tab.Screen
|
||||
name="Library"
|
||||
name="All Novels"
|
||||
component={LibraryStack}
|
||||
options={{
|
||||
tabBarIcon: ({ color }) => (
|
||||
@@ -182,4 +167,28 @@ const Router = () => {
|
||||
</Tab.Navigator>
|
||||
);
|
||||
};
|
||||
export default Router;
|
||||
|
||||
const MainStack = () => {
|
||||
return (
|
||||
<Stack.Navigator
|
||||
screenOptions={{
|
||||
headerShown: false,
|
||||
}}
|
||||
>
|
||||
<Stack.Screen name="MainStack" component={Router} />
|
||||
<Stack.Screen name="ChapterItem" component={ChapterItem} />
|
||||
<Stack.Screen name="NovelItem" component={NovelItem} />
|
||||
<Stack.Screen
|
||||
name="About"
|
||||
component={About}
|
||||
options={{
|
||||
headerShown: true,
|
||||
headerTintColor: theme.textColorPrimaryDark,
|
||||
headerStyle: { backgroundColor: theme.colorDarkPrimary },
|
||||
}}
|
||||
/>
|
||||
</Stack.Navigator>
|
||||
);
|
||||
};
|
||||
|
||||
export default MainStack;
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
import React from "react";
|
||||
import { List, Divider } from "react-native-paper";
|
||||
import * as Linking from "expo-linking";
|
||||
import { theme } from "../theming/theme";
|
||||
|
||||
const AboutScreen = ({ navigation }) => {
|
||||
return (
|
||||
<>
|
||||
<List.Section
|
||||
style={{
|
||||
flex: 1,
|
||||
marginTop: 0,
|
||||
backgroundColor: theme.colorDarkPrimaryDark,
|
||||
marginBottom: 0,
|
||||
}}
|
||||
>
|
||||
<List.Item
|
||||
titleStyle={{ color: theme.textColorPrimaryDark }}
|
||||
title="Version"
|
||||
descriptionStyle={{ color: theme.textColorSecondaryDark }}
|
||||
description="Stable 1.0.0"
|
||||
/>
|
||||
<List.Item
|
||||
titleStyle={{ color: theme.textColorPrimaryDark }}
|
||||
title="Build Time"
|
||||
descriptionStyle={{ color: theme.textColorSecondaryDark }}
|
||||
description="24-12-20 12:00 PM"
|
||||
/>
|
||||
|
||||
<List.Item
|
||||
titleStyle={{ color: theme.textColorPrimaryDark }}
|
||||
title="What's new"
|
||||
onPress={() =>
|
||||
Linking.openURL(
|
||||
"https://github.com/rajarsheechatterjee/LNReader/commits/master"
|
||||
)
|
||||
}
|
||||
/>
|
||||
<Divider />
|
||||
|
||||
<List.Item
|
||||
titleStyle={{ color: theme.textColorPrimaryDark }}
|
||||
descriptionStyle={{ color: theme.textColorSecondaryDark }}
|
||||
title="Github"
|
||||
description="https://github.com/rajarsheechatterjee/LNReader"
|
||||
onPress={() =>
|
||||
Linking.openURL(
|
||||
"https://github.com/rajarsheechatterjee/LNReader"
|
||||
)
|
||||
}
|
||||
/>
|
||||
<List.Item
|
||||
titleStyle={{ color: theme.textColorPrimaryDark }}
|
||||
descriptionStyle={{ color: theme.textColorSecondaryDark }}
|
||||
title="Backend"
|
||||
description="https://github.com/rajarsheechatterjee/LNReader-backend"
|
||||
onPress={() =>
|
||||
Linking.openURL(
|
||||
"https://github.com/rajarsheechatterjee/LNReader-backend"
|
||||
)
|
||||
}
|
||||
/>
|
||||
</List.Section>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default AboutScreen;
|
||||
+58
-53
@@ -7,16 +7,20 @@ import {
|
||||
Text,
|
||||
FlatList,
|
||||
ScrollView,
|
||||
Platform,
|
||||
RefreshControl,
|
||||
StatusBar,
|
||||
ActivityIndicator,
|
||||
} from "react-native";
|
||||
|
||||
import { Appbar } from "react-native-paper";
|
||||
import { theme } from "../theming/theme";
|
||||
import { CollapsibleHeaderScrollView } from "react-native-collapsible-header-views";
|
||||
|
||||
const ChapterItem = ({ route, navigation }) => {
|
||||
const { chapterName, chapterUrl } = route.params;
|
||||
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [refreshing, setRefreshing] = useState(true);
|
||||
|
||||
const [chapter, setChapter] = useState();
|
||||
|
||||
@@ -30,79 +34,80 @@ const ChapterItem = ({ route, navigation }) => {
|
||||
.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}
|
||||
<CollapsibleHeaderScrollView
|
||||
headerContainerBackgroundColor={theme.colorDarkPrimary}
|
||||
CollapsibleHeaderComponent={
|
||||
<Appbar.Header
|
||||
style={{ backgroundColor: theme.colorDarkPrimary }}
|
||||
>
|
||||
<Appbar.BackAction
|
||||
onPress={() => {
|
||||
navigation.navigate("ChapterItem", {
|
||||
chapterUrl: chapter.prevChapter,
|
||||
});
|
||||
navigation.goBack();
|
||||
}}
|
||||
color={"white"}
|
||||
/>
|
||||
<Appbar.Action
|
||||
icon="chevron-right"
|
||||
size={26}
|
||||
disabled={!chapter.nextChapter}
|
||||
onPress={() => {
|
||||
navigation.navigate("ChapterItem", {
|
||||
chapterUrl: chapter.nextChapter,
|
||||
});
|
||||
}}
|
||||
color={"white"}
|
||||
style={{ marginRight: 0 }}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</Appbar.Header>
|
||||
<ScrollView
|
||||
style={styles.container}
|
||||
refreshControl={
|
||||
<RefreshControl
|
||||
refreshing={refreshing}
|
||||
onRefresh={onRefresh}
|
||||
colors={["white"]}
|
||||
progressBackgroundColor={theme.colorAccentDark}
|
||||
/>
|
||||
<Appbar.Content
|
||||
title={loading ? "Chapter" : chapter.chapterName}
|
||||
titleStyle={{ color: theme.textColorPrimaryDark }}
|
||||
/>
|
||||
{!loading && (
|
||||
<>
|
||||
<Appbar.Action
|
||||
icon="chevron-left"
|
||||
size={26}
|
||||
disabled={!chapter.prevChapter}
|
||||
onPress={() => {
|
||||
navigation.push("ChapterItem", {
|
||||
chapterUrl: chapter.prevChapter,
|
||||
});
|
||||
}}
|
||||
color={"white"}
|
||||
/>
|
||||
<Appbar.Action
|
||||
icon="chevron-right"
|
||||
size={26}
|
||||
disabled={!chapter.nextChapter}
|
||||
onPress={() => {
|
||||
navigation.push("ChapterItem", {
|
||||
chapterUrl: chapter.nextChapter,
|
||||
});
|
||||
}}
|
||||
color={"white"}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</Appbar.Header>
|
||||
}
|
||||
headerHeight={100}
|
||||
contentContainerStyle={styles.container}
|
||||
>
|
||||
{!loading && (
|
||||
{loading ? (
|
||||
<View style={{ flex: 1, justifyContent: "center" }}>
|
||||
<ActivityIndicator
|
||||
size="large"
|
||||
color={theme.colorAccentDark}
|
||||
/>
|
||||
</View>
|
||||
) : (
|
||||
<Text
|
||||
style={{
|
||||
color: theme.textColorPrimaryDark,
|
||||
lineHeight: 20,
|
||||
paddingVertical: 15,
|
||||
}}
|
||||
>
|
||||
{chapter.chapterText.trim()}
|
||||
</Text>
|
||||
)}
|
||||
</ScrollView>
|
||||
</CollapsibleHeaderScrollView>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -111,7 +116,7 @@ export default ChapterItem;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
flexGrow: 1,
|
||||
backgroundColor: "#202125",
|
||||
paddingHorizontal: 10,
|
||||
paddingVertical: 10,
|
||||
|
||||
+32
-3
@@ -1,27 +1,48 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { StyleSheet, View, FlatList, ActivityIndicator } from "react-native";
|
||||
import {
|
||||
StyleSheet,
|
||||
View,
|
||||
FlatList,
|
||||
ActivityIndicator,
|
||||
RefreshControl,
|
||||
} from "react-native";
|
||||
import { TouchableRipple } from "react-native-paper";
|
||||
import NovelCover from "../components/NovelCover";
|
||||
import { theme } from "../theming/theme";
|
||||
|
||||
const LatestScreen = ({ navigation }) => {
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [refreshing, setRefreshing] = useState(true);
|
||||
const [novels, setNovels] = useState();
|
||||
|
||||
useEffect(() => {
|
||||
const getNovels = () => {
|
||||
fetch("http://192.168.1.38:5000/api/latest")
|
||||
.then((response) => response.json())
|
||||
.then((json) => setNovels(json))
|
||||
.catch((error) => console.error(error))
|
||||
.finally(() => {
|
||||
setRefreshing(false);
|
||||
setLoading(false);
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
getNovels();
|
||||
}, []);
|
||||
|
||||
const onRefresh = () => {
|
||||
setRefreshing(true);
|
||||
getNovels();
|
||||
};
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
{loading ? (
|
||||
<View style={{ flex: 1, justifyContent: "center" }}>
|
||||
<ActivityIndicator size="large" color="white" />
|
||||
<ActivityIndicator
|
||||
size="large"
|
||||
color={theme.colorAccentDark}
|
||||
/>
|
||||
</View>
|
||||
) : (
|
||||
<FlatList
|
||||
@@ -43,6 +64,14 @@ const LatestScreen = ({ navigation }) => {
|
||||
<NovelCover item={item} />
|
||||
</TouchableRipple>
|
||||
)}
|
||||
refreshControl={
|
||||
<RefreshControl
|
||||
refreshing={refreshing}
|
||||
onRefresh={onRefresh}
|
||||
colors={["white"]}
|
||||
progressBackgroundColor={theme.colorAccentDark}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
|
||||
+158
-7
@@ -1,19 +1,170 @@
|
||||
import React from "react";
|
||||
import { StyleSheet, Text, View } from "react-native";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import {
|
||||
StyleSheet,
|
||||
View,
|
||||
FlatList,
|
||||
ActivityIndicator,
|
||||
RefreshControl,
|
||||
} from "react-native";
|
||||
import {
|
||||
TouchableRipple,
|
||||
Appbar,
|
||||
Provider,
|
||||
Portal,
|
||||
Button,
|
||||
} from "react-native-paper";
|
||||
import NovelCover from "../components/NovelCover";
|
||||
import { theme } from "../theming/theme";
|
||||
import { BottomSheet } from "../components/BottomSheet";
|
||||
|
||||
const AllNovels = ({ navigation }) => {
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [refreshing, setRefreshing] = useState(true);
|
||||
const [novels, setNovels] = useState();
|
||||
const [sort, setSort] = useState("rating");
|
||||
const [pageNo, setPageNo] = useState(2);
|
||||
|
||||
const getNovels = () => {
|
||||
fetch(`http://192.168.1.38:5000/api/novels/1/?o=${sort}`)
|
||||
.then((response) => response.json())
|
||||
.then((json) => setNovels(json))
|
||||
.catch((error) => console.error(error))
|
||||
.finally(() => {
|
||||
setPageNo(2);
|
||||
setRefreshing(false);
|
||||
setLoading(false);
|
||||
});
|
||||
};
|
||||
|
||||
const loadMore = () => {
|
||||
setRefreshing(true);
|
||||
fetch(`http://192.168.1.38:5000/api/novels/${pageNo}/?o=${sort}`)
|
||||
.then((response) => response.json())
|
||||
.then((json) => setNovels((novels) => novels.concat(json)))
|
||||
.catch((error) => console.error(error))
|
||||
.finally(() => {
|
||||
setRefreshing(false);
|
||||
setLoading(false);
|
||||
setPageNo(pageNo + 1);
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
getNovels();
|
||||
}, [sort]);
|
||||
|
||||
const onRefresh = () => {
|
||||
setRefreshing(true);
|
||||
setPageNo(2);
|
||||
getNovels();
|
||||
};
|
||||
|
||||
const MoreScreen = () => {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Text style={{ color: "#FFFFFF" }}>Library</Text>
|
||||
</View>
|
||||
<Provider>
|
||||
<Appbar.Header style={{ backgroundColor: theme.colorDarkPrimary }}>
|
||||
<Appbar.Content
|
||||
title="All Novels"
|
||||
titleStyle={{ color: theme.textColorPrimaryDark }}
|
||||
/>
|
||||
<Appbar.Action
|
||||
icon="filter-variant"
|
||||
onPress={() => {
|
||||
_panel.show({ velocity: -1.5 });
|
||||
}}
|
||||
/>
|
||||
</Appbar.Header>
|
||||
<View style={styles.container}>
|
||||
{loading ? (
|
||||
<View style={{ flex: 1, justifyContent: "center" }}>
|
||||
<ActivityIndicator
|
||||
size="large"
|
||||
color={theme.colorAccentDark}
|
||||
/>
|
||||
</View>
|
||||
) : (
|
||||
<FlatList
|
||||
contentContainerStyle={styles.list}
|
||||
numColumns={3}
|
||||
data={novels}
|
||||
showsVerticalScrollIndicator={false}
|
||||
keyExtractor={(item) => item.novelUrl}
|
||||
ListFooterComponent={() => (
|
||||
<View
|
||||
style={{
|
||||
width: 120,
|
||||
alignSelf: "center",
|
||||
marginVertical: 10,
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
mode="contained"
|
||||
color={theme.colorAccentDark}
|
||||
uppercase={false}
|
||||
labelStyle={{
|
||||
color: theme.textColorPrimaryDark,
|
||||
letterSpacing: 0,
|
||||
}}
|
||||
onPress={() => loadMore()}
|
||||
>
|
||||
Load More
|
||||
</Button>
|
||||
</View>
|
||||
)}
|
||||
renderItem={({ item }) => (
|
||||
<TouchableRipple
|
||||
borderless
|
||||
centered
|
||||
rippleColor="rgba(256,256,256,0.3)"
|
||||
style={styles.opac}
|
||||
onPress={() =>
|
||||
navigation.navigate("NovelItem", item)
|
||||
}
|
||||
>
|
||||
<NovelCover item={item} />
|
||||
</TouchableRipple>
|
||||
)}
|
||||
refreshControl={
|
||||
<RefreshControl
|
||||
refreshing={refreshing}
|
||||
onRefresh={onRefresh}
|
||||
colors={["white"]}
|
||||
progressBackgroundColor={theme.colorAccentDark}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
<Portal>
|
||||
<BottomSheet
|
||||
bottomSheetRef={(c) => (_panel = c)}
|
||||
setSort={setSort}
|
||||
sort={sort}
|
||||
setRefreshing={setRefreshing}
|
||||
/>
|
||||
</Portal>
|
||||
</Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export default MoreScreen;
|
||||
export default AllNovels;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: "#202125",
|
||||
},
|
||||
opac: {
|
||||
height: 190,
|
||||
flex: 1 / 3,
|
||||
margin: 3.2,
|
||||
},
|
||||
contentContainer: {
|
||||
flex: 1,
|
||||
},
|
||||
fab: {
|
||||
position: "absolute",
|
||||
margin: 16,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
},
|
||||
});
|
||||
|
||||
+24
-5
@@ -1,11 +1,30 @@
|
||||
import React from "react";
|
||||
import { StyleSheet, Text, View } from "react-native";
|
||||
import { StyleSheet } from "react-native";
|
||||
import { List } from "react-native-paper";
|
||||
import { theme } from "../theming/theme";
|
||||
|
||||
const MoreScreen = () => {
|
||||
const MoreScreen = ({ navigation }) => {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Text style={{ color: "#FFFFFF" }}>More</Text>
|
||||
</View>
|
||||
<List.Section
|
||||
style={{
|
||||
flex: 1,
|
||||
backgroundColor: theme.colorDarkPrimaryDark,
|
||||
marginTop: 0,
|
||||
marginBottom: 0,
|
||||
}}
|
||||
>
|
||||
<List.Item
|
||||
titleStyle={{ color: theme.textColorPrimaryDark }}
|
||||
title="About"
|
||||
left={() => (
|
||||
<List.Icon
|
||||
color={theme.colorAccentDark}
|
||||
icon="information-outline"
|
||||
/>
|
||||
)}
|
||||
onPress={() => navigation.navigate("About")}
|
||||
/>
|
||||
</List.Section>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
+81
-47
@@ -9,7 +9,7 @@ import {
|
||||
ScrollView,
|
||||
RefreshControl,
|
||||
} from "react-native";
|
||||
import { Appbar, TouchableRipple } from "react-native-paper";
|
||||
import { Appbar, TouchableRipple, IconButton } from "react-native-paper";
|
||||
import { LinearGradient } from "expo-linear-gradient";
|
||||
|
||||
import { theme } from "../theming/theme";
|
||||
@@ -21,12 +21,16 @@ const NovelItem = ({ route, navigation }) => {
|
||||
const [refreshing, setRefreshing] = useState(true);
|
||||
|
||||
const [novel, setNovel] = useState();
|
||||
const [chapters, setChapters] = 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))
|
||||
.then((json) => {
|
||||
setNovel(json);
|
||||
setChapters(json.novelChapters);
|
||||
})
|
||||
.catch((error) => console.error(error))
|
||||
.finally(() => {
|
||||
setRefreshing(false);
|
||||
@@ -59,6 +63,7 @@ const NovelItem = ({ route, navigation }) => {
|
||||
titleStyle={{ color: theme.textColorPrimaryDark }}
|
||||
/>
|
||||
</Appbar.Header>
|
||||
|
||||
<ScrollView
|
||||
style={styles.container}
|
||||
refreshControl={
|
||||
@@ -153,48 +158,52 @@ const NovelItem = ({ route, navigation }) => {
|
||||
</ImageBackground>
|
||||
{!loading && (
|
||||
<>
|
||||
<View
|
||||
style={{ paddingHorizontal: 15, marginBottom: 10 }}
|
||||
>
|
||||
<Text
|
||||
{novel.novelSummary.length > 0 && (
|
||||
<View
|
||||
style={{
|
||||
color: theme.textColorPrimaryDark,
|
||||
marginTop: 5,
|
||||
paddingVertical: 5,
|
||||
fontSize: 15,
|
||||
paddingHorizontal: 15,
|
||||
marginBottom: 10,
|
||||
}}
|
||||
>
|
||||
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>
|
||||
|
||||
<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,
|
||||
marginBottom: 15,
|
||||
}}
|
||||
horizontal
|
||||
data={novel.novelDetails["Genre(s)"].split(",")}
|
||||
@@ -214,19 +223,44 @@ const NovelItem = ({ route, navigation }) => {
|
||||
)}
|
||||
/>
|
||||
|
||||
<Text
|
||||
<TouchableRipple
|
||||
style={{
|
||||
color: theme.textColorPrimaryDark,
|
||||
paddingHorizontal: 15,
|
||||
marginTop: 5,
|
||||
paddingVertical: 5,
|
||||
fontSize: 15,
|
||||
flex: 1,
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
}}
|
||||
onPress={() =>
|
||||
setChapters((chapters) => chapters.reverse())
|
||||
}
|
||||
rippleColor={theme.rippleColorDark}
|
||||
>
|
||||
{novel.novelChapters.length + " Chapters"}
|
||||
</Text>
|
||||
<>
|
||||
<Text
|
||||
style={{
|
||||
color: theme.textColorPrimaryDark,
|
||||
paddingHorizontal: 15,
|
||||
paddingVertical: 5,
|
||||
fontSize: 15,
|
||||
}}
|
||||
>
|
||||
{chapters.length + " Chapters"}
|
||||
</Text>
|
||||
<IconButton
|
||||
icon="filter-variant"
|
||||
color={theme.textColorPrimaryDark}
|
||||
size={20}
|
||||
onPress={() =>
|
||||
setChapters((chapters) =>
|
||||
chapters.reverse()
|
||||
)
|
||||
}
|
||||
/>
|
||||
</>
|
||||
</TouchableRipple>
|
||||
<FlatList
|
||||
data={novel.novelChapters}
|
||||
data={chapters}
|
||||
extraData={chapters}
|
||||
showsVerticalScrollIndicator={false}
|
||||
keyExtractor={(item) => item.chapterUrl}
|
||||
removeClippedSubviews={true}
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
} from "react-native";
|
||||
import { Appbar, TouchableRipple } from "react-native-paper";
|
||||
import NovelCover from "../components/NovelCover";
|
||||
import { theme } from "../theming/theme";
|
||||
|
||||
const SearchScreen = ({ navigation }) => {
|
||||
const [loading, setLoading] = useState(false);
|
||||
@@ -25,10 +26,11 @@ const SearchScreen = ({ navigation }) => {
|
||||
};
|
||||
return (
|
||||
<>
|
||||
<Appbar.Header style={{ backgroundColor: "#202125" }}>
|
||||
<Appbar.Header style={{ backgroundColor: theme.colorDarkPrimary }}>
|
||||
<Appbar.BackAction
|
||||
onPress={() => {
|
||||
navigation.goBack();
|
||||
setSearchText("");
|
||||
setNovels([]);
|
||||
}}
|
||||
color={"white"}
|
||||
@@ -60,7 +62,10 @@ const SearchScreen = ({ navigation }) => {
|
||||
<View style={styles.container}>
|
||||
{loading ? (
|
||||
<View style={{ flex: 1, justifyContent: "center" }}>
|
||||
<ActivityIndicator size="large" color="white" />
|
||||
<ActivityIndicator
|
||||
size="large"
|
||||
color={theme.colorAccentDark}
|
||||
/>
|
||||
</View>
|
||||
) : (
|
||||
<FlatList
|
||||
|
||||
Reference in New Issue
Block a user