Break into components
This commit is contained in:
@@ -32,14 +32,14 @@ export default function App() {
|
||||
(tx, error) => console.log(error)
|
||||
);
|
||||
tx.executeSql(
|
||||
"CREATE TABLE IF NOT EXISTS HistoryTable (historyId INTEGER PRIMARY KEY AUTOINCREMENT, chapterUrl VARCHAR(255) UNIQUE, novelUrl VARCHAR(255), chapterName VARCHAR(255), lastRead DATETIME DEFAULT CURRENT_TIMESTAMP)",
|
||||
"CREATE TABLE IF NOT EXISTS HistoryTable (historyId INTEGER PRIMARY KEY AUTOINCREMENT, chapterUrl VARCHAR(255) UNIQUE, novelUrl VARCHAR(255) UNIQUE, chapterName VARCHAR(255), lastRead DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (novelUrl) REFERENCES LibraryTable(novelUrl) ON DELETE CASCADE)",
|
||||
null,
|
||||
(tx, results) => console.log("History Table Created"),
|
||||
(tx, error) => console.log(error)
|
||||
);
|
||||
|
||||
tx.executeSql(
|
||||
"CREATE TABLE IF NOT EXISTS DownloadsTable (downloadId INTEGER PRIMARY KEY AUTOINCREMENT, chapterUrl VARCHAR(255) UNIQUE, novelUrl VARCHAR(255), chapterName VARCHAR(255), chapterText VARCHAR(255), nextChapter VARCHAR(255), prevChapter VARCHAR(255))",
|
||||
"CREATE TABLE IF NOT EXISTS DownloadsTable (downloadId INTEGER PRIMARY KEY AUTOINCREMENT, chapterUrl VARCHAR(255) UNIQUE, novelUrl VARCHAR(255), chapterName VARCHAR(255), chapterText VARCHAR(255), nextChapter VARCHAR(255), prevChapter VARCHAR(255), FOREIGN KEY (novelUrl) REFERENCES LibraryTable(novelUrl) ON DELETE CASCADE)",
|
||||
null,
|
||||
(tx, results) => console.log("Downloads Table Created"),
|
||||
(tx, error) => console.log(error)
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 32 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
@@ -0,0 +1,13 @@
|
||||
import React from "react";
|
||||
import { Appbar } from "react-native-paper";
|
||||
import { theme } from "../theming/theme";
|
||||
|
||||
export const CustomAppbar = ({ title, onBackAction }) => (
|
||||
<Appbar.Header style={{ backgroundColor: theme.colorDarkPrimary }}>
|
||||
{onBackAction && <Appbar.BackAction onPress={onBackAction} />}
|
||||
<Appbar.Content
|
||||
title={title}
|
||||
titleStyle={{ color: theme.textColorPrimaryDark }}
|
||||
/>
|
||||
</Appbar.Header>
|
||||
);
|
||||
@@ -0,0 +1,88 @@
|
||||
import React from "react";
|
||||
import { View, Text } from "react-native";
|
||||
import { TouchableRipple, IconButton } from "react-native-paper";
|
||||
import { theme } from "../theming/theme";
|
||||
|
||||
const ChapterCard = ({
|
||||
navigation,
|
||||
novelUrl,
|
||||
chapter,
|
||||
downloadChapter,
|
||||
extensionId,
|
||||
}) => (
|
||||
<TouchableRipple
|
||||
style={{
|
||||
paddingHorizontal: 15,
|
||||
paddingVertical: 12,
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
}}
|
||||
onPress={() =>
|
||||
navigation.navigate("ChapterItem", {
|
||||
chapterUrl: chapter.chapterUrl,
|
||||
extensionId,
|
||||
novelUrl: novelUrl,
|
||||
chapterName: chapter.chapterName,
|
||||
})
|
||||
}
|
||||
rippleColor={theme.rippleColorDark}
|
||||
>
|
||||
<>
|
||||
<View>
|
||||
<Text
|
||||
style={[
|
||||
{
|
||||
color: theme.textColorPrimaryDark,
|
||||
},
|
||||
chapter.read === 1 && {
|
||||
color: theme.textColorHintDark,
|
||||
},
|
||||
]}
|
||||
numberOfLines={1}
|
||||
>
|
||||
{chapter.chapterName.substring(0, 50) + "..."}
|
||||
</Text>
|
||||
<Text
|
||||
style={[
|
||||
{
|
||||
color: theme.textColorSecondaryDark,
|
||||
marginTop: 5,
|
||||
fontSize: 13,
|
||||
},
|
||||
chapter.read === 1 && {
|
||||
color: theme.textColorHintDark,
|
||||
},
|
||||
]}
|
||||
numberOfLines={1}
|
||||
>
|
||||
{chapter.releaseDate ? chapter.releaseDate : "release-date"}
|
||||
</Text>
|
||||
</View>
|
||||
<View>
|
||||
<IconButton
|
||||
icon={
|
||||
chapter.downloaded
|
||||
? "check-circle"
|
||||
: "arrow-down-circle-outline"
|
||||
}
|
||||
animated
|
||||
color={
|
||||
chapter.downloaded
|
||||
? "#47a84a"
|
||||
: theme.textColorSecondaryDark
|
||||
}
|
||||
size={24}
|
||||
onPress={() => {
|
||||
downloadChapter(
|
||||
chapter.downloaded ? chapter.downloaded : 0,
|
||||
chapter.chapterUrl
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
</>
|
||||
</TouchableRipple>
|
||||
);
|
||||
|
||||
export default ChapterCard;
|
||||
@@ -0,0 +1,118 @@
|
||||
import React from "react";
|
||||
import { theme } from "../theming/theme";
|
||||
import moment from "moment";
|
||||
import { StyleSheet, View, Text, FlatList, Image } from "react-native";
|
||||
import { TouchableRipple, IconButton, Appbar } from "react-native-paper";
|
||||
|
||||
const HistoryCard = ({ item, deleteHistory, navigation }) => (
|
||||
<TouchableRipple
|
||||
style={styles.historyCard}
|
||||
rippleColor={theme.rippleColorDark}
|
||||
borderless
|
||||
onPress={() =>
|
||||
navigation.navigate("NovelItem", {
|
||||
novelName: item.novelName,
|
||||
novelCover: item.novelCover,
|
||||
extensionId: item.extensionId,
|
||||
novelUrl: item.novelUrl,
|
||||
})
|
||||
}
|
||||
>
|
||||
<>
|
||||
<Image
|
||||
source={{ uri: item.novelCover }}
|
||||
style={{
|
||||
height: 80,
|
||||
width: 57,
|
||||
borderTopLeftRadius: 4,
|
||||
borderBottomLeftRadius: 4,
|
||||
}}
|
||||
/>
|
||||
<View
|
||||
style={{
|
||||
marginLeft: 15,
|
||||
flex: 1,
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
}}
|
||||
>
|
||||
<View>
|
||||
<Text
|
||||
style={{
|
||||
color: "white",
|
||||
fontWeight: "bold",
|
||||
fontSize: 16,
|
||||
}}
|
||||
>
|
||||
{item.novelName}
|
||||
</Text>
|
||||
<Text
|
||||
style={{
|
||||
color: theme.textColorSecondaryDark,
|
||||
marginTop: 2,
|
||||
}}
|
||||
numberOfLines={1}
|
||||
>
|
||||
{`Ch. ${item.chapterName
|
||||
.replace(/^\D+/g, "")
|
||||
.substring(0, 4)} - ${moment(
|
||||
item.lastRead
|
||||
).calendar()}`}
|
||||
</Text>
|
||||
</View>
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
}}
|
||||
>
|
||||
<IconButton
|
||||
icon="delete-outline"
|
||||
size={24}
|
||||
color={theme.textColorPrimaryDark}
|
||||
style={{
|
||||
marginRight: 0,
|
||||
}}
|
||||
onPress={() => deleteHistory(item.novelUrl)}
|
||||
/>
|
||||
<IconButton
|
||||
icon="play"
|
||||
size={24}
|
||||
color={theme.textColorPrimaryDark}
|
||||
style={{ marginRight: 10 }}
|
||||
onPress={() =>
|
||||
navigation.navigate("ChapterItem", {
|
||||
chapterUrl: item.chapterUrl,
|
||||
extensionId: item.extensionId,
|
||||
novelUrl: item.novelUrl,
|
||||
novelName: item.novelName,
|
||||
novelCover: item.novelCover,
|
||||
chapterName: item.chapterName,
|
||||
})
|
||||
}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
</>
|
||||
</TouchableRipple>
|
||||
);
|
||||
|
||||
export default HistoryCard;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: "#202125",
|
||||
backgroundColor: "#000000",
|
||||
padding: 10,
|
||||
},
|
||||
historyCard: {
|
||||
// backgroundColor: "pink",
|
||||
// paddingVertical: 10,
|
||||
// marginVertical: 5,
|
||||
// paddingHorizontal: 20,
|
||||
marginTop: 10,
|
||||
borderRadius: 4,
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,423 @@
|
||||
import React, { useState } from "react";
|
||||
import {
|
||||
View,
|
||||
Text,
|
||||
ImageBackground,
|
||||
StyleSheet,
|
||||
Image,
|
||||
FlatList,
|
||||
} from "react-native";
|
||||
import { TouchableRipple, IconButton, Button } from "react-native-paper";
|
||||
import { LinearGradient } from "expo-linear-gradient";
|
||||
|
||||
import { theme } from "../theming/theme";
|
||||
|
||||
const NovelInfoHeader = ({
|
||||
item,
|
||||
novel,
|
||||
loading,
|
||||
libraryStatus,
|
||||
noOfChapters,
|
||||
insertToLibrary,
|
||||
sortChapters,
|
||||
}) => {
|
||||
const [more, setMore] = useState(false);
|
||||
|
||||
const renderGenreChip = ({ item }) => (
|
||||
<Text
|
||||
style={[
|
||||
styles.genre,
|
||||
{
|
||||
color: theme.colorAccentDark,
|
||||
borderColor: theme.colorAccentDark,
|
||||
},
|
||||
]}
|
||||
>
|
||||
{item}
|
||||
</Text>
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<ImageBackground
|
||||
source={{
|
||||
uri: item.novelCover,
|
||||
}}
|
||||
style={styles.background}
|
||||
>
|
||||
<LinearGradient
|
||||
colors={["transparent", "#000000"]}
|
||||
style={styles.linearGradient}
|
||||
>
|
||||
<View style={styles.detailsContainer}>
|
||||
<Image
|
||||
source={{
|
||||
uri: item.novelCover,
|
||||
}}
|
||||
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: 15,
|
||||
}}
|
||||
numberOfLines={1}
|
||||
>
|
||||
{novel.Alternative &&
|
||||
novel.Alternative.replace(
|
||||
",",
|
||||
", "
|
||||
)}
|
||||
</Text>
|
||||
<Text
|
||||
style={{
|
||||
color: theme.textColorSecondaryDark,
|
||||
marginVertical: 3,
|
||||
fontSize: 15,
|
||||
}}
|
||||
>
|
||||
{novel["Author(s)"].replace(",", ", ")}
|
||||
</Text>
|
||||
<Text
|
||||
style={{
|
||||
color: theme.textColorSecondaryDark,
|
||||
marginVertical: 3,
|
||||
fontSize: 15,
|
||||
}}
|
||||
>
|
||||
{novel["Release"]}
|
||||
</Text>
|
||||
<Text
|
||||
style={{
|
||||
color: theme.textColorSecondaryDark,
|
||||
marginVertical: 3,
|
||||
fontSize: 15,
|
||||
}}
|
||||
>
|
||||
{novel["Status"] +
|
||||
" • " +
|
||||
novel["Type"]}
|
||||
</Text>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Text
|
||||
style={{
|
||||
color: theme.textColorSecondaryDark,
|
||||
marginVertical: 3,
|
||||
fontSize: 15,
|
||||
}}
|
||||
numberOfLines={1}
|
||||
>
|
||||
{item.Alternative &&
|
||||
item.Alternative.replace(",", ", ")}
|
||||
</Text>
|
||||
<Text
|
||||
style={{
|
||||
color: theme.textColorSecondaryDark,
|
||||
marginVertical: 3,
|
||||
fontSize: 15,
|
||||
}}
|
||||
>
|
||||
{item["Author(s)"] &&
|
||||
item["Author(s)"].replace(
|
||||
",",
|
||||
", "
|
||||
)}
|
||||
</Text>
|
||||
<Text
|
||||
style={{
|
||||
color: theme.textColorSecondaryDark,
|
||||
marginVertical: 3,
|
||||
fontSize: 15,
|
||||
}}
|
||||
>
|
||||
{item["Release"] && item["Release"]}
|
||||
</Text>
|
||||
<Text
|
||||
style={{
|
||||
color: theme.textColorSecondaryDark,
|
||||
marginVertical: 3,
|
||||
fontSize: 15,
|
||||
}}
|
||||
>
|
||||
{item["Status"] &&
|
||||
item["Type"] &&
|
||||
item["Status"] +
|
||||
" • " +
|
||||
item["Type"]}
|
||||
</Text>
|
||||
</>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
</LinearGradient>
|
||||
</ImageBackground>
|
||||
|
||||
{!loading ? (
|
||||
<>
|
||||
<Button
|
||||
color={theme.textColorPrimaryDark}
|
||||
style={[
|
||||
{
|
||||
backgroundColor: theme.colorAccentDark,
|
||||
marginHorizontal: 15,
|
||||
},
|
||||
novel.novelSummary.length === 0 && {
|
||||
marginBottom: 20,
|
||||
},
|
||||
]}
|
||||
icon={
|
||||
libraryStatus === 0
|
||||
? "bookmark-outline"
|
||||
: "bookmark"
|
||||
}
|
||||
uppercase={false}
|
||||
labelStyle={{ letterSpacing: 0 }}
|
||||
onPress={() => insertToLibrary()}
|
||||
>
|
||||
{libraryStatus === 0 ? "Add to library" : "In Library"}
|
||||
</Button>
|
||||
{novel.novelSummary.length > 0 && (
|
||||
<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,
|
||||
backgroundColor: "black",
|
||||
paddingLeft: 5,
|
||||
}}
|
||||
onPress={() => setMore(!more)}
|
||||
>
|
||||
{more ? "Less" : "More"}
|
||||
</Text>
|
||||
</View>
|
||||
)}
|
||||
<FlatList
|
||||
contentContainerStyle={{
|
||||
paddingHorizontal: 15,
|
||||
marginBottom: 15,
|
||||
}}
|
||||
horizontal
|
||||
data={novel["Genre(s)"].split(",")}
|
||||
keyExtractor={(item) => item}
|
||||
renderItem={renderGenreChip}
|
||||
/>
|
||||
<TouchableRipple
|
||||
style={{
|
||||
flex: 1,
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
paddingRight: 15,
|
||||
}}
|
||||
onPress={() => sortChapters()}
|
||||
rippleColor={theme.rippleColorDark}
|
||||
>
|
||||
<>
|
||||
<Text
|
||||
style={{
|
||||
color: theme.textColorPrimaryDark,
|
||||
paddingHorizontal: 15,
|
||||
paddingVertical: 5,
|
||||
fontSize: 15,
|
||||
}}
|
||||
>
|
||||
{noOfChapters + " Chapters"}
|
||||
</Text>
|
||||
<IconButton
|
||||
icon="filter-variant"
|
||||
color={theme.textColorPrimaryDark}
|
||||
size={24}
|
||||
onPress={() => sortChapters()}
|
||||
/>
|
||||
</>
|
||||
</TouchableRipple>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
{item.libraryStatus && (
|
||||
<Button
|
||||
color={theme.textColorPrimaryDark}
|
||||
style={[
|
||||
{
|
||||
backgroundColor: theme.colorAccentDark,
|
||||
marginHorizontal: 15,
|
||||
},
|
||||
item.novelSummary &&
|
||||
item.novelSummary.length === 0 && {
|
||||
marginBottom: 20,
|
||||
},
|
||||
]}
|
||||
icon={
|
||||
item.libraryStatus === 0
|
||||
? "bookmark-outline"
|
||||
: "bookmark"
|
||||
}
|
||||
uppercase={false}
|
||||
labelStyle={{ letterSpacing: 0 }}
|
||||
onPress={() => insertToLibrary()}
|
||||
>
|
||||
{item.libraryStatus === 0
|
||||
? "Add to library"
|
||||
: "In Library"}
|
||||
</Button>
|
||||
)}
|
||||
{item.novelSummary && item.novelSummary.length > 0 && (
|
||||
<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"
|
||||
>
|
||||
{item.novelSummary}
|
||||
</Text>
|
||||
<Text
|
||||
style={{
|
||||
color: theme.colorAccentDark,
|
||||
fontWeight: "bold",
|
||||
position: "absolute",
|
||||
bottom: 0,
|
||||
right: 15,
|
||||
backgroundColor: "black",
|
||||
paddingLeft: 5,
|
||||
}}
|
||||
onPress={() => setMore(!more)}
|
||||
>
|
||||
{more ? "Less" : "More"}
|
||||
</Text>
|
||||
</View>
|
||||
)}
|
||||
<FlatList
|
||||
contentContainerStyle={{
|
||||
paddingHorizontal: 15,
|
||||
marginBottom: 15,
|
||||
}}
|
||||
horizontal
|
||||
data={item["Genre(s)"] && item["Genre(s)"].split(",")}
|
||||
keyExtractor={(item) => item}
|
||||
renderItem={({ item }) => (
|
||||
<Text
|
||||
style={[
|
||||
styles.genre,
|
||||
{
|
||||
color: theme.colorAccentDark,
|
||||
borderColor: theme.colorAccentDark,
|
||||
},
|
||||
]}
|
||||
>
|
||||
{item}
|
||||
</Text>
|
||||
)}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default NovelInfoHeader;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
nameContainer: {
|
||||
flex: 1,
|
||||
width: "100%",
|
||||
marginHorizontal: 15,
|
||||
// justifyContent: "center",
|
||||
},
|
||||
background: {
|
||||
height: 240,
|
||||
},
|
||||
linearGradient: {
|
||||
height: "100%",
|
||||
backgroundColor: "rgba(256, 256, 256, 0.5)",
|
||||
},
|
||||
detailsContainer: {
|
||||
flex: 1,
|
||||
flexDirection: "row",
|
||||
margin: 15,
|
||||
},
|
||||
logo: {
|
||||
height: 180,
|
||||
width: 120,
|
||||
margin: 3.2,
|
||||
borderRadius: 6,
|
||||
},
|
||||
genre: {
|
||||
borderRadius: 24,
|
||||
borderWidth: 1,
|
||||
paddingHorizontal: 10,
|
||||
marginHorizontal: 2,
|
||||
fontSize: 13,
|
||||
paddingVertical: 2,
|
||||
justifyContent: "center",
|
||||
flex: 1,
|
||||
},
|
||||
name: {
|
||||
fontWeight: "bold",
|
||||
fontSize: 20,
|
||||
},
|
||||
});
|
||||
+31
-105
@@ -1,108 +1,53 @@
|
||||
import React from "react";
|
||||
import { createStackNavigator } from "@react-navigation/stack";
|
||||
|
||||
import {
|
||||
createStackNavigator,
|
||||
TransitionPresets,
|
||||
} from "@react-navigation/stack";
|
||||
import { createMaterialBottomTabNavigator } from "@react-navigation/material-bottom-tabs";
|
||||
import { TransitionPresets } from "@react-navigation/stack";
|
||||
|
||||
import MaterialCommunityIcons from "react-native-vector-icons/MaterialCommunityIcons";
|
||||
|
||||
import Library from "../screens/Library";
|
||||
import History from "../screens/History/History";
|
||||
import Browse from "../screens/Browse";
|
||||
import Latest from "../screens/Latest";
|
||||
import More from "../screens/More";
|
||||
import BoxNovelSearch from "../screens/Sources/BoxNovel/BoxNovelSearch";
|
||||
|
||||
import More from "../screens/More/More";
|
||||
import About from "../screens/More/About";
|
||||
|
||||
import NovelItem from "../screens/NovelItem";
|
||||
import ChapterItem from "../screens/ChapterItem";
|
||||
import About from "../screens/About";
|
||||
import HistoryScreen from "../screens/History/History";
|
||||
import Updates from "../screens/Updates/Updates";
|
||||
import BoxNovel from "../screens/Sources/BoxNovel/BoxNovel";
|
||||
|
||||
import { theme } from "../theming/theme";
|
||||
// Sources
|
||||
import BoxNovel from "../screens/Sources/BoxNovel/BoxNovel";
|
||||
import BoxNovelSearch from "../screens/Sources/BoxNovel/BoxNovelSearch";
|
||||
|
||||
import ReadLightNovel from "../screens/Sources/ReadLightNovel/ReadLightNovel";
|
||||
import ReadLightNovelSearch from "../screens/Sources/ReadLightNovel/ReadLightNovelSearch";
|
||||
|
||||
import { theme } from "../theming/theme";
|
||||
|
||||
const Stack = createStackNavigator();
|
||||
|
||||
const Tab = createMaterialBottomTabNavigator();
|
||||
|
||||
const LibraryStack = () => {
|
||||
return (
|
||||
<Stack.Navigator
|
||||
screenOptions={{
|
||||
headerTintColor: theme.textColorPrimaryDark,
|
||||
headerStyle: { backgroundColor: theme.colorDarkPrimary },
|
||||
}}
|
||||
>
|
||||
<Stack.Screen name="Library" component={Library} />
|
||||
</Stack.Navigator>
|
||||
);
|
||||
const stackNavigatorConfig = {
|
||||
headerShown: false,
|
||||
...TransitionPresets.RevealFromBottomAndroid,
|
||||
};
|
||||
|
||||
// const UpdatesStack = () => {
|
||||
// return (
|
||||
// <Stack.Navigator
|
||||
// screenOptions={{
|
||||
// headerTintColor: theme.textColorPrimaryDark,
|
||||
// headerStyle: { backgroundColor: theme.colorDarkPrimary },
|
||||
// }}
|
||||
// >
|
||||
// <Stack.Screen name="Updates" component={Updates} />
|
||||
// </Stack.Navigator>
|
||||
// );
|
||||
// };
|
||||
|
||||
const SearchStack = () => {
|
||||
return (
|
||||
<Stack.Navigator>
|
||||
<Stack.Screen
|
||||
name="Search"
|
||||
component={Search}
|
||||
options={{
|
||||
headerShown: false,
|
||||
}}
|
||||
/>
|
||||
</Stack.Navigator>
|
||||
);
|
||||
};
|
||||
|
||||
const BrowseStack = () => {
|
||||
return (
|
||||
<Stack.Navigator
|
||||
screenOptions={{
|
||||
headerTintColor: theme.textColorPrimaryDark,
|
||||
headerStyle: { backgroundColor: theme.colorDarkPrimary },
|
||||
}}
|
||||
>
|
||||
<Stack.Screen
|
||||
name="Browse"
|
||||
component={Browse}
|
||||
// options={{ headerShown: false }}
|
||||
/>
|
||||
</Stack.Navigator>
|
||||
);
|
||||
};
|
||||
const MoreStack = () => {
|
||||
return (
|
||||
<Stack.Navigator
|
||||
screenOptions={{
|
||||
headerTintColor: theme.textColorPrimaryDark,
|
||||
headerStyle: { backgroundColor: theme.colorDarkPrimary },
|
||||
}}
|
||||
>
|
||||
<Stack.Navigator screenOptions={stackNavigatorConfig}>
|
||||
<Stack.Screen name="More" component={More} />
|
||||
<Stack.Screen name="About" component={About} />
|
||||
</Stack.Navigator>
|
||||
);
|
||||
};
|
||||
|
||||
const BoxNovelStack = () => {
|
||||
return (
|
||||
<Stack.Navigator
|
||||
screenOptions={{
|
||||
headerShown: false,
|
||||
...TransitionPresets.RevealFromBottomAndroid,
|
||||
}}
|
||||
>
|
||||
<Stack.Navigator screenOptions={stackNavigatorConfig}>
|
||||
<Stack.Screen name="BoxNovel" component={BoxNovel} />
|
||||
<Stack.Screen name="BoxNovelSearch" component={BoxNovelSearch} />
|
||||
</Stack.Navigator>
|
||||
@@ -111,12 +56,7 @@ const BoxNovelStack = () => {
|
||||
|
||||
const ReadLightNovelStack = () => {
|
||||
return (
|
||||
<Stack.Navigator
|
||||
screenOptions={{
|
||||
headerShown: false,
|
||||
...TransitionPresets.RevealFromBottomAndroid,
|
||||
}}
|
||||
>
|
||||
<Stack.Navigator screenOptions={stackNavigatorConfig}>
|
||||
<Stack.Screen name="ReadLightNovel" component={ReadLightNovel} />
|
||||
<Stack.Screen
|
||||
name="ReadLightNovelSearch"
|
||||
@@ -126,16 +66,16 @@ const ReadLightNovelStack = () => {
|
||||
);
|
||||
};
|
||||
|
||||
const Router = () => {
|
||||
const BottomNavigator = () => {
|
||||
return (
|
||||
<Tab.Navigator
|
||||
shifting={false}
|
||||
barStyle={{ backgroundColor: theme.colorDarkPrimary }}
|
||||
activeColor="#3399FF"
|
||||
activeColor={theme.colorAccentDark}
|
||||
>
|
||||
<Tab.Screen
|
||||
name="My Library"
|
||||
component={LibraryStack}
|
||||
component={Library}
|
||||
options={{
|
||||
tabBarIcon: ({ color }) => (
|
||||
<MaterialCommunityIcons
|
||||
@@ -162,7 +102,7 @@ const Router = () => {
|
||||
/> */}
|
||||
<Tab.Screen
|
||||
name="History"
|
||||
component={HistoryScreen}
|
||||
component={History}
|
||||
options={{
|
||||
tabBarIcon: ({ color }) => (
|
||||
<MaterialCommunityIcons
|
||||
@@ -175,7 +115,7 @@ const Router = () => {
|
||||
/>
|
||||
<Tab.Screen
|
||||
name="Browse"
|
||||
component={BrowseStack}
|
||||
component={Browse}
|
||||
options={{
|
||||
tabBarIcon: ({ color }) => (
|
||||
<MaterialCommunityIcons
|
||||
@@ -203,26 +143,12 @@ const Router = () => {
|
||||
);
|
||||
};
|
||||
|
||||
const MainStack = () => {
|
||||
const Router = () => {
|
||||
return (
|
||||
<Stack.Navigator
|
||||
screenOptions={{
|
||||
headerShown: false,
|
||||
...TransitionPresets.RevealFromBottomAndroid,
|
||||
}}
|
||||
>
|
||||
<Stack.Screen name="MainStack" component={Router} />
|
||||
<Stack.Navigator screenOptions={stackNavigatorConfig}>
|
||||
<Stack.Screen name="Router" component={BottomNavigator} />
|
||||
<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.Screen name="BoxNovelStack" component={BoxNovelStack} />
|
||||
<Stack.Screen
|
||||
name="ReadLightNovelStack"
|
||||
@@ -232,4 +158,4 @@ const MainStack = () => {
|
||||
);
|
||||
};
|
||||
|
||||
export default MainStack;
|
||||
export default Router;
|
||||
|
||||
+78
-72
@@ -1,84 +1,90 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { StyleSheet, View, Text, FlatList, Image } from "react-native";
|
||||
import { TouchableRipple, IconButton } from "react-native-paper";
|
||||
import { CustomAppbar } from "../components/Appbar";
|
||||
import { theme } from "../theming/theme";
|
||||
import { sources } from "../utils/sources";
|
||||
|
||||
const Browse = ({ navigation }) => {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<FlatList
|
||||
data={sources}
|
||||
keyExtractor={(item) => item.sourceId.toString()}
|
||||
renderItem={({ item }) => (
|
||||
<TouchableRipple
|
||||
style={styles.sourceCard}
|
||||
onPress={() =>
|
||||
navigation.navigate(item.sourceName + "Stack")
|
||||
}
|
||||
rippleColor={theme.rippleColorDark}
|
||||
>
|
||||
<>
|
||||
<Image
|
||||
source={{
|
||||
uri: item.sourceCover,
|
||||
}}
|
||||
style={{
|
||||
width: 60,
|
||||
height: 60,
|
||||
borderRadius: 6,
|
||||
}}
|
||||
resizeMode="contain"
|
||||
/>
|
||||
<View
|
||||
style={{
|
||||
marginLeft: 15,
|
||||
flex: 1,
|
||||
justifyContent: "space-between",
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<View>
|
||||
<Text
|
||||
style={{
|
||||
color: theme.textColorPrimaryDark,
|
||||
fontSize: 16,
|
||||
}}
|
||||
>
|
||||
{item.sourceName}
|
||||
</Text>
|
||||
<Text
|
||||
style={{
|
||||
color: theme.textColorSecondaryDark,
|
||||
}}
|
||||
>
|
||||
{item.sourceLanguage}
|
||||
</Text>
|
||||
<>
|
||||
<CustomAppbar title="Browse" />
|
||||
<View style={styles.container}>
|
||||
<FlatList
|
||||
data={sources}
|
||||
keyExtractor={(item) => item.sourceId.toString()}
|
||||
renderItem={({ item }) => (
|
||||
<TouchableRipple
|
||||
style={styles.sourceCard}
|
||||
onPress={() =>
|
||||
navigation.navigate(item.sourceName + "Stack")
|
||||
}
|
||||
rippleColor={theme.rippleColorDark}
|
||||
>
|
||||
<>
|
||||
<Image
|
||||
source={{
|
||||
uri: item.sourceCover,
|
||||
}}
|
||||
style={{
|
||||
width: 60,
|
||||
height: 60,
|
||||
borderRadius: 6,
|
||||
}}
|
||||
resizeMode="contain"
|
||||
/>
|
||||
<View
|
||||
style={{
|
||||
marginLeft: 15,
|
||||
flex: 1,
|
||||
justifyContent: "space-between",
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<View>
|
||||
<Text
|
||||
style={{
|
||||
color:
|
||||
theme.textColorPrimaryDark,
|
||||
fontSize: 16,
|
||||
}}
|
||||
>
|
||||
{item.sourceName}
|
||||
</Text>
|
||||
<Text
|
||||
style={{
|
||||
color:
|
||||
theme.textColorSecondaryDark,
|
||||
}}
|
||||
>
|
||||
{item.sourceLanguage}
|
||||
</Text>
|
||||
</View>
|
||||
<View>
|
||||
<IconButton
|
||||
icon="magnify"
|
||||
color={theme.textColorSecondaryDark}
|
||||
size={24}
|
||||
onPress={() =>
|
||||
navigation.navigate(
|
||||
item.sourceName + "Stack",
|
||||
{
|
||||
screen:
|
||||
item.sourceName +
|
||||
"Search",
|
||||
}
|
||||
)
|
||||
}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
<View>
|
||||
<IconButton
|
||||
icon="magnify"
|
||||
color={theme.textColorSecondaryDark}
|
||||
size={24}
|
||||
onPress={() =>
|
||||
navigation.navigate(
|
||||
item.sourceName + "Stack",
|
||||
{
|
||||
screen:
|
||||
item.sourceName +
|
||||
"Search",
|
||||
}
|
||||
)
|
||||
}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
</>
|
||||
</TouchableRipple>
|
||||
)}
|
||||
/>
|
||||
</View>
|
||||
</>
|
||||
</TouchableRipple>
|
||||
)}
|
||||
/>
|
||||
</View>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
+17
-119
@@ -1,16 +1,16 @@
|
||||
import React, { useEffect, useState, useCallback } from "react";
|
||||
import { StyleSheet, View, Text, FlatList, Image } from "react-native";
|
||||
import { TouchableRipple, IconButton, Appbar } from "react-native-paper";
|
||||
import React, { useState, useCallback, useEffect } from "react";
|
||||
import { StyleSheet, View, Text, FlatList } from "react-native";
|
||||
import { theme } from "../../theming/theme";
|
||||
import moment from "moment";
|
||||
import { useFocusEffect } from "@react-navigation/native";
|
||||
|
||||
import { CustomAppbar } from "../../components/Appbar";
|
||||
import HistoryCard from "../../components/HistoryCard";
|
||||
|
||||
import * as SQLite from "expo-sqlite";
|
||||
const db = SQLite.openDatabase("lnreader.db");
|
||||
|
||||
const History = ({ navigation }) => {
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [novels, setNovels] = useState();
|
||||
const [history, setHistory] = useState();
|
||||
|
||||
const getHistory = () => {
|
||||
db.transaction((tx) => {
|
||||
@@ -18,21 +18,19 @@ const History = ({ navigation }) => {
|
||||
"SELECT HistoryTable.chapterUrl, HistoryTable.historyId, HistoryTable.chapterName, HistoryTable.lastRead, LibraryTable.novelName, LibraryTable.novelCover, LibraryTable.novelUrl, LibraryTable.extensionId FROM HistoryTable INNER JOIN LibraryTable ON HistoryTable.novelUrl = LibraryTable.novelUrl ORDER BY HistoryTable.lastRead DESC",
|
||||
null,
|
||||
(txObj, { rows: { _array } }) => {
|
||||
setNovels(_array);
|
||||
// console.log(_array);
|
||||
setLoading(false);
|
||||
setHistory(_array);
|
||||
},
|
||||
(txObj, error) => console.log("Error ", error)
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
const deleteHistory = (name) => {
|
||||
const deleteHistory = (novelId) => {
|
||||
db.transaction((tx) => {
|
||||
tx.executeSql(
|
||||
"DELETE FROM HistoryTable WHERE novelUrl = ?",
|
||||
[name],
|
||||
(txObj, { rows: { _array } }) => {
|
||||
[novelId],
|
||||
(txObj, res) => {
|
||||
getHistory();
|
||||
},
|
||||
(txObj, error) => console.log("Error ", error)
|
||||
@@ -48,118 +46,18 @@ const History = ({ navigation }) => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<Appbar.Header style={{ backgroundColor: theme.colorDarkPrimary }}>
|
||||
<Appbar.Content
|
||||
title="History"
|
||||
titleStyle={{ color: theme.textColorPrimaryDark }}
|
||||
/>
|
||||
</Appbar.Header>
|
||||
<CustomAppbar title="History" />
|
||||
<View style={styles.container}>
|
||||
<FlatList
|
||||
contentContainerStyle={{ flex: 1 }}
|
||||
data={novels}
|
||||
data={history}
|
||||
keyExtractor={(item) => item.historyId.toString()}
|
||||
renderItem={({ item }) => (
|
||||
<TouchableRipple
|
||||
style={styles.historyCard}
|
||||
rippleColor={theme.rippleColorDark}
|
||||
borderless
|
||||
onPress={() =>
|
||||
navigation.navigate("NovelItem", {
|
||||
novelName: item.novelName,
|
||||
novelCover: item.novelCover,
|
||||
extensionId: item.extensionId,
|
||||
novelUrl: item.novelUrl,
|
||||
})
|
||||
}
|
||||
>
|
||||
<>
|
||||
<Image
|
||||
source={{ uri: item.novelCover }}
|
||||
style={{
|
||||
height: 80,
|
||||
width: 57,
|
||||
borderTopLeftRadius: 4,
|
||||
borderBottomLeftRadius: 4,
|
||||
}}
|
||||
/>
|
||||
<View
|
||||
style={{
|
||||
marginLeft: 15,
|
||||
flex: 1,
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
}}
|
||||
>
|
||||
<View>
|
||||
<Text
|
||||
style={{
|
||||
color: "white",
|
||||
fontWeight: "bold",
|
||||
fontSize: 16,
|
||||
}}
|
||||
>
|
||||
{item.novelName}
|
||||
</Text>
|
||||
<Text
|
||||
style={{
|
||||
color:
|
||||
theme.textColorSecondaryDark,
|
||||
marginTop: 2,
|
||||
}}
|
||||
numberOfLines={1}
|
||||
>
|
||||
{`Ch. ${item.chapterName
|
||||
.replace(/^\D+/g, "")
|
||||
.substring(0, 4)} - ${moment(
|
||||
item.lastRead
|
||||
).calendar()}`}
|
||||
</Text>
|
||||
</View>
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
}}
|
||||
>
|
||||
<IconButton
|
||||
icon="delete-outline"
|
||||
size={24}
|
||||
color={theme.textColorPrimaryDark}
|
||||
style={{
|
||||
marginRight: 0,
|
||||
}}
|
||||
onPress={() =>
|
||||
deleteHistory(item.novelUrl)
|
||||
}
|
||||
/>
|
||||
<IconButton
|
||||
icon="play"
|
||||
size={24}
|
||||
color={theme.textColorPrimaryDark}
|
||||
style={{ marginRight: 10 }}
|
||||
onPress={() =>
|
||||
navigation.navigate(
|
||||
"ChapterItem",
|
||||
{
|
||||
chapterUrl:
|
||||
item.chapterUrl,
|
||||
extensionId:
|
||||
item.extensionId,
|
||||
novelUrl: item.novelUrl,
|
||||
novelName:
|
||||
item.novelName,
|
||||
novelCover:
|
||||
item.novelCover,
|
||||
chapterName:
|
||||
item.chapterName,
|
||||
}
|
||||
)
|
||||
}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
</>
|
||||
</TouchableRipple>
|
||||
<HistoryCard
|
||||
item={item}
|
||||
deleteHistory={deleteHistory}
|
||||
navigation={navigation}
|
||||
/>
|
||||
)}
|
||||
ListEmptyComponent={
|
||||
<View
|
||||
|
||||
+63
-55
@@ -10,9 +10,11 @@ import { FlatList } from "react-native-gesture-handler";
|
||||
import { theme } from "../theming/theme";
|
||||
import { useFocusEffect } from "@react-navigation/native";
|
||||
|
||||
import { TouchableRipple, Button } from "react-native-paper";
|
||||
import { Button } from "react-native-paper";
|
||||
import NovelCover from "../components/NovelCover";
|
||||
|
||||
import { CustomAppbar } from "../components/Appbar";
|
||||
|
||||
import * as SQLite from "expo-sqlite";
|
||||
|
||||
const db = SQLite.openDatabase("lnreader.db");
|
||||
@@ -88,63 +90,69 @@ const UpdatesScreen = ({ navigation }) => {
|
||||
};
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<FlatList
|
||||
contentContainerStyle={{ flex: 1 }}
|
||||
numColumns={3}
|
||||
data={novels}
|
||||
showsVerticalScrollIndicator={false}
|
||||
keyExtractor={(item) => item.novelUrl}
|
||||
renderItem={({ item }) => (
|
||||
<NovelCover
|
||||
item={item}
|
||||
onPress={() => navigation.navigate("NovelItem", item)}
|
||||
/>
|
||||
)}
|
||||
refreshControl={
|
||||
<RefreshControl
|
||||
refreshing={refreshing}
|
||||
onRefresh={onRefresh}
|
||||
colors={["white"]}
|
||||
progressBackgroundColor={theme.colorAccentDark}
|
||||
/>
|
||||
}
|
||||
ListEmptyComponent={
|
||||
<View
|
||||
style={{
|
||||
flex: 1,
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<Text
|
||||
<>
|
||||
<CustomAppbar title="Library" />
|
||||
|
||||
<View style={styles.container}>
|
||||
<FlatList
|
||||
contentContainerStyle={{ flex: 1 }}
|
||||
numColumns={3}
|
||||
data={novels}
|
||||
showsVerticalScrollIndicator={false}
|
||||
keyExtractor={(item) => item.novelUrl}
|
||||
renderItem={({ item }) => (
|
||||
<NovelCover
|
||||
item={item}
|
||||
onPress={() =>
|
||||
navigation.navigate("NovelItem", item)
|
||||
}
|
||||
/>
|
||||
)}
|
||||
refreshControl={
|
||||
<RefreshControl
|
||||
refreshing={refreshing}
|
||||
onRefresh={onRefresh}
|
||||
colors={["white"]}
|
||||
progressBackgroundColor={theme.colorAccentDark}
|
||||
/>
|
||||
}
|
||||
ListEmptyComponent={
|
||||
<View
|
||||
style={{
|
||||
color: theme.textColorSecondaryDark,
|
||||
fontSize: 45,
|
||||
fontWeight: "bold",
|
||||
flex: 1,
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
Σ(ಠ_ಠ)
|
||||
</Text>
|
||||
<Text
|
||||
style={{
|
||||
color: theme.textColorSecondaryDark,
|
||||
fontWeight: "bold",
|
||||
marginTop: 10,
|
||||
textAlign: "center",
|
||||
paddingHorizontal: 30,
|
||||
}}
|
||||
>
|
||||
Your library is empty. Add series to your library
|
||||
from Browse.
|
||||
</Text>
|
||||
</View>
|
||||
}
|
||||
/>
|
||||
{/* <Button mode="contained" onPress={() => deleted()}>
|
||||
Delete Library Table
|
||||
</Button> */}
|
||||
</View>
|
||||
<Text
|
||||
style={{
|
||||
color: theme.textColorSecondaryDark,
|
||||
fontSize: 45,
|
||||
fontWeight: "bold",
|
||||
}}
|
||||
>
|
||||
Σ(ಠ_ಠ)
|
||||
</Text>
|
||||
<Text
|
||||
style={{
|
||||
color: theme.textColorSecondaryDark,
|
||||
fontWeight: "bold",
|
||||
marginTop: 10,
|
||||
textAlign: "center",
|
||||
paddingHorizontal: 30,
|
||||
}}
|
||||
>
|
||||
Your library is empty. Add series to your
|
||||
library from Browse.
|
||||
</Text>
|
||||
</View>
|
||||
}
|
||||
/>
|
||||
{/* <Button mode="contained" onPress={() => deleted()}>
|
||||
Delete Library Table
|
||||
</Button> */}
|
||||
</View>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
import React from "react";
|
||||
import { StyleSheet } from "react-native";
|
||||
import { List } from "react-native-paper";
|
||||
import { theme } from "../theming/theme";
|
||||
|
||||
const MoreScreen = ({ navigation }) => {
|
||||
return (
|
||||
<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>
|
||||
);
|
||||
};
|
||||
|
||||
export default MoreScreen;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
// backgroundColor: "#202125",
|
||||
backgroundColor: "#000000",
|
||||
},
|
||||
});
|
||||
@@ -1,11 +1,16 @@
|
||||
import React from "react";
|
||||
import { List, Divider } from "react-native-paper";
|
||||
import * as Linking from "expo-linking";
|
||||
import { theme } from "../theming/theme";
|
||||
import { theme } from "../../theming/theme";
|
||||
import { CustomAppbar } from "../../components/Appbar";
|
||||
|
||||
const AboutScreen = ({ navigation }) => {
|
||||
return (
|
||||
<>
|
||||
<CustomAppbar
|
||||
title="About"
|
||||
onBackAction={() => navigation.goBack()}
|
||||
/>
|
||||
<List.Section
|
||||
style={{
|
||||
flex: 1,
|
||||
@@ -35,6 +40,7 @@ const AboutScreen = ({ navigation }) => {
|
||||
"https://github.com/rajarsheechatterjee/LNReader/commits/master"
|
||||
)
|
||||
}
|
||||
rippleColor={theme.rippleColorDark}
|
||||
/>
|
||||
<Divider />
|
||||
|
||||
@@ -48,6 +54,7 @@ const AboutScreen = ({ navigation }) => {
|
||||
"https://github.com/rajarsheechatterjee/lnreader"
|
||||
)
|
||||
}
|
||||
rippleColor={theme.rippleColorDark}
|
||||
/>
|
||||
<List.Item
|
||||
titleStyle={{ color: theme.textColorPrimaryDark }}
|
||||
@@ -60,6 +67,7 @@ const AboutScreen = ({ navigation }) => {
|
||||
"https://github.com/rajarsheechatterjee/lnreader-extensions"
|
||||
)
|
||||
}
|
||||
rippleColor={theme.rippleColorDark}
|
||||
/>
|
||||
</List.Section>
|
||||
</>
|
||||
@@ -0,0 +1,54 @@
|
||||
import React from "react";
|
||||
import { StyleSheet } from "react-native";
|
||||
import { List } from "react-native-paper";
|
||||
import { CustomAppbar } from "../../components/Appbar";
|
||||
import { theme } from "../../theming/theme";
|
||||
|
||||
const MoreScreen = ({ navigation }) => {
|
||||
return (
|
||||
<>
|
||||
<CustomAppbar title="More" />
|
||||
<List.Section
|
||||
style={{
|
||||
flex: 1,
|
||||
backgroundColor: theme.colorDarkPrimaryDark,
|
||||
marginTop: 0,
|
||||
marginBottom: 0,
|
||||
}}
|
||||
>
|
||||
<List.Item
|
||||
titleStyle={{ color: theme.textColorPrimaryDark }}
|
||||
title="Settings"
|
||||
left={() => (
|
||||
<List.Icon
|
||||
color={theme.colorAccentDark}
|
||||
icon="code-tags"
|
||||
/>
|
||||
)}
|
||||
onPress={() => navigation.navigate("About")}
|
||||
/>
|
||||
<List.Item
|
||||
titleStyle={{ color: theme.textColorPrimaryDark }}
|
||||
title="About"
|
||||
left={() => (
|
||||
<List.Icon
|
||||
color={theme.colorAccentDark}
|
||||
icon="information-outline"
|
||||
/>
|
||||
)}
|
||||
onPress={() => navigation.navigate("About")}
|
||||
/>
|
||||
</List.Section>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default MoreScreen;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
// backgroundColor: "#202125",
|
||||
backgroundColor: "#000000",
|
||||
},
|
||||
});
|
||||
+54
-358
@@ -1,27 +1,21 @@
|
||||
import React, { useState, useCallback, useEffect } from "react";
|
||||
import React, { useState, useCallback } from "react";
|
||||
import { useFocusEffect } from "@react-navigation/native";
|
||||
|
||||
import {
|
||||
StyleSheet,
|
||||
View,
|
||||
Image,
|
||||
ImageBackground,
|
||||
Text,
|
||||
FlatList,
|
||||
RefreshControl,
|
||||
ToastAndroid,
|
||||
ActivityIndicator,
|
||||
} from "react-native";
|
||||
import {
|
||||
Appbar,
|
||||
TouchableRipple,
|
||||
IconButton,
|
||||
Button,
|
||||
FAB,
|
||||
ProgressBar,
|
||||
} from "react-native-paper";
|
||||
import { LinearGradient } from "expo-linear-gradient";
|
||||
import { useFocusEffect } from "@react-navigation/native";
|
||||
import { Appbar, FAB, ProgressBar } from "react-native-paper";
|
||||
|
||||
import { theme } from "../theming/theme";
|
||||
|
||||
import ChapterCard from "../components/ChapterCard";
|
||||
import NovelInfoHeader from "../components/NovelInfoHeader";
|
||||
|
||||
import * as SQLite from "expo-sqlite";
|
||||
const db = SQLite.openDatabase("lnreader.db");
|
||||
|
||||
@@ -35,9 +29,8 @@ const NovelItem = ({ route, navigation }) => {
|
||||
|
||||
const [novel, setNovel] = useState(item);
|
||||
const [chapters, setChapters] = useState();
|
||||
const [more, setMore] = useState(false);
|
||||
|
||||
const [libraryStatus, setlibraryStatus] = useState(0);
|
||||
const [libraryStatus, setlibraryStatus] = useState(item.libraryStatus);
|
||||
const [sort, setSort] = useState("ASC");
|
||||
|
||||
const [readingStatus, setReadingStatus] = useState();
|
||||
@@ -63,21 +56,8 @@ const NovelItem = ({ route, navigation }) => {
|
||||
});
|
||||
};
|
||||
|
||||
const getNovelFromDb = () => {
|
||||
const getChaptersFromDb = () => {
|
||||
db.transaction((tx) => {
|
||||
tx.executeSql(
|
||||
"SELECT * FROM LibraryTable WHERE novelUrl=?",
|
||||
[item.novelUrl],
|
||||
(txObj, results) => {
|
||||
let len = results.rows.length;
|
||||
for (let i = 0; i < len; i++) {
|
||||
let row = results.rows.item(i);
|
||||
setNovel(row);
|
||||
setlibraryStatus(row.libraryStatus);
|
||||
}
|
||||
},
|
||||
(txObj, error) => console.log("Error ", error)
|
||||
);
|
||||
tx.executeSql(
|
||||
`SELECT * FROM ChapterTable WHERE novelUrl=? ORDER BY chapterId ${sort}`,
|
||||
[item.novelUrl],
|
||||
@@ -109,14 +89,12 @@ const NovelItem = ({ route, navigation }) => {
|
||||
(txObj, results) => {
|
||||
let len = results.rows.length;
|
||||
if (len > 0) {
|
||||
for (let i = 0; i < len; i++) {
|
||||
let row = results.rows.item(i);
|
||||
setReadingStatus({
|
||||
chapterUrl: row.chapterUrl,
|
||||
chapterName: row.chapterName,
|
||||
fabLabel: "Resume",
|
||||
});
|
||||
}
|
||||
let row = results.rows.item(0);
|
||||
setReadingStatus({
|
||||
chapterUrl: row.chapterUrl,
|
||||
chapterName: row.chapterName,
|
||||
fabLabel: "Resume",
|
||||
});
|
||||
} else {
|
||||
setReadingStatus({
|
||||
chapterUrl: chapUrl,
|
||||
@@ -149,7 +127,7 @@ const NovelItem = ({ route, navigation }) => {
|
||||
0,
|
||||
],
|
||||
(tx, res) => {
|
||||
console.log("Inserted into DB");
|
||||
// console.log("Inserted into DB");
|
||||
},
|
||||
(txObj, error) => console.log("Error ", error)
|
||||
);
|
||||
@@ -181,9 +159,9 @@ const NovelItem = ({ route, navigation }) => {
|
||||
`UPDATE ChapterTable SET downloaded = 1 WHERE chapterUrl = ?`,
|
||||
[cdUrl],
|
||||
(tx, res) => {
|
||||
console.log(
|
||||
"Updated Download Status to downloaded"
|
||||
);
|
||||
// console.log(
|
||||
// "Updated Download Status to downloaded"
|
||||
// );
|
||||
},
|
||||
(txObj, error) => console.log("Error ", error)
|
||||
);
|
||||
@@ -202,7 +180,7 @@ const NovelItem = ({ route, navigation }) => {
|
||||
`Downloaded ${json.chapterName}`,
|
||||
ToastAndroid.SHORT
|
||||
);
|
||||
console.log("Inserted into Downloads Table");
|
||||
// console.log("Inserted into Downloads Table");
|
||||
},
|
||||
(txObj, error) => console.log("Error ", error)
|
||||
);
|
||||
@@ -218,7 +196,7 @@ const NovelItem = ({ route, navigation }) => {
|
||||
`UPDATE ChapterTable SET downloaded = 0 WHERE chapterUrl = ?`,
|
||||
[cdUrl],
|
||||
(tx, res) => {
|
||||
console.log("Updated Download Status to downloaded");
|
||||
// console.log("Updated Download Status to downloaded");
|
||||
},
|
||||
(txObj, error) => console.log("Error ", error)
|
||||
);
|
||||
@@ -226,7 +204,7 @@ const NovelItem = ({ route, navigation }) => {
|
||||
`DELETE FROM DownloadsTable WHERE chapterUrl = ?`,
|
||||
[cdUrl],
|
||||
(tx, res) => {
|
||||
console.log("Deleted Download");
|
||||
// console.log("Deleted Download");
|
||||
checkIfExistsInDB();
|
||||
ToastAndroid.show(
|
||||
`Chapter deleted`,
|
||||
@@ -250,7 +228,7 @@ const NovelItem = ({ route, navigation }) => {
|
||||
"Added to library",
|
||||
ToastAndroid.SHORT
|
||||
);
|
||||
console.log("Inserted into Library");
|
||||
// console.log("Inserted into Library");
|
||||
|
||||
setlibraryStatus(1);
|
||||
},
|
||||
@@ -267,7 +245,7 @@ const NovelItem = ({ route, navigation }) => {
|
||||
"Removed from library",
|
||||
ToastAndroid.SHORT
|
||||
);
|
||||
console.log("Removed From Library");
|
||||
// console.log("Removed From Library");
|
||||
setlibraryStatus(0);
|
||||
},
|
||||
(txObj, error) => console.log("Error ", error)
|
||||
@@ -284,12 +262,15 @@ const NovelItem = ({ route, navigation }) => {
|
||||
(txObj, res) => {
|
||||
if (res.rows.length === 0) {
|
||||
setRefreshing(true);
|
||||
console.log("Not In Database");
|
||||
setlibraryStatus(0);
|
||||
// console.log("Not In Database");
|
||||
getNovel();
|
||||
} else {
|
||||
// setRefreshing(true);
|
||||
console.log("In Database");
|
||||
getNovelFromDb();
|
||||
// console.log("In Database");
|
||||
setlibraryStatus(res.rows.item(0).libraryStatus);
|
||||
setNovel(res.rows.item(0));
|
||||
getChaptersFromDb();
|
||||
}
|
||||
},
|
||||
(txObj, error) => console.log("Error ", error)
|
||||
@@ -313,6 +294,16 @@ const NovelItem = ({ route, navigation }) => {
|
||||
checkIfExistsInDB();
|
||||
};
|
||||
|
||||
const renderChapterCard = ({ item }) => (
|
||||
<ChapterCard
|
||||
navigation={navigation}
|
||||
novelUrl={novelUrl}
|
||||
extensionId={extensionId}
|
||||
chapter={item}
|
||||
downloadChapter={downloadChapter}
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Appbar.Header style={{ backgroundColor: theme.colorDarkPrimary }}>
|
||||
@@ -324,10 +315,10 @@ const NovelItem = ({ route, navigation }) => {
|
||||
size={26}
|
||||
style={{ marginRight: 0 }}
|
||||
/>
|
||||
{/* <Appbar.Content
|
||||
<Appbar.Content
|
||||
title={item.novelName}
|
||||
titleStyle={{ color: theme.textColorPrimaryDark }}
|
||||
/> */}
|
||||
/>
|
||||
</Appbar.Header>
|
||||
|
||||
<View style={styles.container}>
|
||||
@@ -344,312 +335,18 @@ const NovelItem = ({ route, navigation }) => {
|
||||
removeClippedSubviews={true}
|
||||
maxToRenderPerBatch={10}
|
||||
initialNumToRender={10}
|
||||
renderItem={({ item }) => (
|
||||
<TouchableRipple
|
||||
style={{
|
||||
paddingHorizontal: 15,
|
||||
paddingVertical: 12,
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
}}
|
||||
onPress={() =>
|
||||
navigation.navigate("ChapterItem", {
|
||||
chapterUrl: item.chapterUrl,
|
||||
extensionId,
|
||||
novelUrl: novelUrl,
|
||||
chapterName: item.chapterName,
|
||||
})
|
||||
}
|
||||
rippleColor={theme.rippleColorDark}
|
||||
>
|
||||
<>
|
||||
<View>
|
||||
<Text
|
||||
style={[
|
||||
{
|
||||
color:
|
||||
theme.textColorPrimaryDark,
|
||||
},
|
||||
item.read === 1 && {
|
||||
color: theme.textColorHintDark,
|
||||
},
|
||||
]}
|
||||
numberOfLines={1}
|
||||
>
|
||||
{item.chapterName}
|
||||
</Text>
|
||||
<Text
|
||||
style={[
|
||||
{
|
||||
color:
|
||||
theme.textColorSecondaryDark,
|
||||
marginTop: 5,
|
||||
fontSize: 13,
|
||||
},
|
||||
item.read === 1 && {
|
||||
color: theme.textColorHintDark,
|
||||
},
|
||||
]}
|
||||
numberOfLines={1}
|
||||
>
|
||||
{item.releaseDate
|
||||
? item.releaseDate
|
||||
: "release-date"}
|
||||
</Text>
|
||||
</View>
|
||||
<View>
|
||||
<IconButton
|
||||
icon={
|
||||
item.downloaded
|
||||
? "check-circle"
|
||||
: "arrow-down-circle-outline"
|
||||
}
|
||||
animated
|
||||
color={
|
||||
item.downloaded
|
||||
? "#47a84a"
|
||||
: theme.textColorSecondaryDark
|
||||
}
|
||||
size={24}
|
||||
onPress={() => {
|
||||
downloadChapter(
|
||||
item.downloaded
|
||||
? item.downloaded
|
||||
: 0,
|
||||
item.chapterUrl
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
</>
|
||||
</TouchableRipple>
|
||||
renderItem={renderChapterCard}
|
||||
ListHeaderComponent={() => (
|
||||
<NovelInfoHeader
|
||||
item={item}
|
||||
novel={novel}
|
||||
noOfChapters={!loading && chapters.length}
|
||||
loading={loading}
|
||||
libraryStatus={libraryStatus}
|
||||
insertToLibrary={insertToLibrary}
|
||||
sortChapters={sortChapters}
|
||||
/>
|
||||
)}
|
||||
ListHeaderComponent={
|
||||
<>
|
||||
<ImageBackground
|
||||
source={{
|
||||
uri: item.novelCover,
|
||||
}}
|
||||
style={styles.background}
|
||||
>
|
||||
<LinearGradient
|
||||
colors={["transparent", "#000000"]}
|
||||
style={styles.linearGradient}
|
||||
>
|
||||
<View style={styles.detailsContainer}>
|
||||
<Image
|
||||
source={{
|
||||
uri: item.novelCover,
|
||||
}}
|
||||
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: 15,
|
||||
}}
|
||||
numberOfLines={1}
|
||||
>
|
||||
{novel.Alternative &&
|
||||
novel.Alternative.replace(
|
||||
",",
|
||||
", "
|
||||
)}
|
||||
</Text>
|
||||
<Text
|
||||
style={{
|
||||
color:
|
||||
theme.textColorSecondaryDark,
|
||||
marginVertical: 3,
|
||||
fontSize: 15,
|
||||
}}
|
||||
>
|
||||
{novel[
|
||||
"Author(s)"
|
||||
].replace(",", ", ")}
|
||||
</Text>
|
||||
<Text
|
||||
style={{
|
||||
color:
|
||||
theme.textColorSecondaryDark,
|
||||
marginVertical: 3,
|
||||
fontSize: 15,
|
||||
}}
|
||||
>
|
||||
{novel["Release"]}
|
||||
</Text>
|
||||
<Text
|
||||
style={{
|
||||
color:
|
||||
theme.textColorSecondaryDark,
|
||||
marginVertical: 3,
|
||||
fontSize: 15,
|
||||
}}
|
||||
>
|
||||
{novel["Status"] +
|
||||
" • " +
|
||||
novel["Type"]}
|
||||
</Text>
|
||||
</>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
</LinearGradient>
|
||||
</ImageBackground>
|
||||
|
||||
{!loading && (
|
||||
<>
|
||||
<Button
|
||||
color={theme.textColorPrimaryDark}
|
||||
style={[
|
||||
{
|
||||
backgroundColor:
|
||||
theme.colorAccentDark,
|
||||
marginHorizontal: 15,
|
||||
},
|
||||
novel.novelSummary.length === 0 && {
|
||||
marginBottom: 20,
|
||||
},
|
||||
]}
|
||||
icon={
|
||||
libraryStatus === 0
|
||||
? "bookmark-outline"
|
||||
: "bookmark"
|
||||
}
|
||||
uppercase={false}
|
||||
labelStyle={{ letterSpacing: 0 }}
|
||||
onPress={() => insertToLibrary()}
|
||||
>
|
||||
{libraryStatus === 0
|
||||
? "Add to library"
|
||||
: "In Library"}
|
||||
</Button>
|
||||
{novel.novelSummary.length > 0 && (
|
||||
<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,
|
||||
backgroundColor: "black",
|
||||
paddingLeft: 5,
|
||||
}}
|
||||
onPress={() => setMore(!more)}
|
||||
>
|
||||
{more ? "Less" : "More"}
|
||||
</Text>
|
||||
</View>
|
||||
)}
|
||||
<FlatList
|
||||
contentContainerStyle={{
|
||||
paddingHorizontal: 15,
|
||||
marginBottom: 15,
|
||||
}}
|
||||
horizontal
|
||||
data={novel["Genre(s)"].split(",")}
|
||||
keyExtractor={(item) => item}
|
||||
renderItem={({ item }) => (
|
||||
<Text
|
||||
style={[
|
||||
styles.genre,
|
||||
{
|
||||
color:
|
||||
theme.colorAccentDark,
|
||||
borderColor:
|
||||
theme.colorAccentDark,
|
||||
},
|
||||
]}
|
||||
>
|
||||
{item}
|
||||
</Text>
|
||||
)}
|
||||
/>
|
||||
<TouchableRipple
|
||||
style={{
|
||||
flex: 1,
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
paddingRight: 15,
|
||||
}}
|
||||
onPress={() => sortChapters()}
|
||||
rippleColor={theme.rippleColorDark}
|
||||
>
|
||||
<>
|
||||
<Text
|
||||
style={{
|
||||
color:
|
||||
theme.textColorPrimaryDark,
|
||||
paddingHorizontal: 15,
|
||||
paddingVertical: 5,
|
||||
fontSize: 15,
|
||||
}}
|
||||
>
|
||||
{chapters.length + " Chapters"}
|
||||
</Text>
|
||||
<IconButton
|
||||
icon="filter-variant"
|
||||
color={
|
||||
theme.textColorPrimaryDark
|
||||
}
|
||||
size={24}
|
||||
onPress={() => sortChapters()}
|
||||
/>
|
||||
</>
|
||||
</TouchableRipple>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
}
|
||||
refreshControl={
|
||||
<RefreshControl
|
||||
refreshing={refreshing}
|
||||
@@ -667,7 +364,6 @@ const NovelItem = ({ route, navigation }) => {
|
||||
label={readingStatus.fabLabel}
|
||||
color={theme.textColorPrimaryDark}
|
||||
onPress={() => {
|
||||
// console.log(readingStatus);
|
||||
navigation.navigate("ChapterItem", {
|
||||
chapterUrl: readingStatus.chapterUrl,
|
||||
extensionId,
|
||||
|
||||
Reference in New Issue
Block a user