Rewrite NovelItem Screen

This commit is contained in:
Rajarshee Chatterjee
2020-12-26 17:19:30 +05:30
parent 3c53e5a53d
commit 99376b1fc4
7 changed files with 633 additions and 77 deletions
+21
View File
@@ -1,3 +1,5 @@
console.disableYellowBox = true;
import React, { useState, useEffect } from "react";
import Router from "./src/navigation/Router";
import { NavigationContainer } from "@react-navigation/native";
@@ -5,6 +7,9 @@ import { StatusBar } from "expo-status-bar";
import * as Font from "expo-font";
import AppLoading from "expo-app-loading";
import * as SQLite from "expo-sqlite";
const db = SQLite.openDatabase("lnreader.db");
const getFonts = () =>
Font.loadAsync({
"pt-sans-bold": require("./assets/fonts/PTSansNarrow-Bold.ttf"),
@@ -13,6 +18,22 @@ const getFonts = () =>
export default function App() {
const [fontsLoaded, setFontsLoaded] = useState(false);
const createTables = () =>
db.transaction((tx) => {
tx.executeSql(
"CREATE TABLE IF NOT EXISTS LibraryTable (novelUrl VARCHAR(255) NOT NULL PRIMARY KEY, novelName VARCHAR(255), novelCover VARCHAR(255), novelSummary TEXT, Alternative VARCHAR(255), `Author(s)` VARCHAR(255), `Genre(s)` VARCHAR(255), Type VARCHAR(255), `Release` VARCHAR(255), Status VARCHAR(255))"
);
console.log("Library Table Created");
tx.executeSql(
"CREATE TABLE IF NOT EXISTS ChapterTable (chapterUrl VARCHAR(255), chapterName VARCHAR(255), releaseDate VARCHAR(255), novelUrl VARCHAR(255), FOREIGN KEY (novelUrl) REFERENCES LibraryTable(novelUrl) ON DELETE CASCADE)"
);
});
useEffect(() => {
createTables();
});
if (fontsLoaded) {
return (
<>
+6
View File
@@ -15,6 +15,7 @@ import ChapterItem from "../screens/ChapterItem";
import About from "../screens/About";
import LibraryNovelItem from "../screens/LibraryNovelItem";
import { theme } from "../theming/theme";
import NovelItemRewrite from "../screens/NovelItemRewrite";
const Stack = createStackNavigator();
@@ -172,6 +173,11 @@ const MainStack = () => {
<Stack.Screen name="MainStack" component={Router} />
<Stack.Screen name="ChapterItem" component={ChapterItem} />
<Stack.Screen name="NovelItem" component={NovelItem} />
<Stack.Screen
name="NovelItemRewrite"
component={NovelItemRewrite}
/>
<Stack.Screen
name="LibraryNovelItem"
component={LibraryNovelItem}
+18 -18
View File
@@ -38,19 +38,19 @@ const UpdatesScreen = ({ navigation }) => {
});
};
// const deleted = () => {
// db.transaction((tx) => {
// tx.executeSql(
// "DROP TABLE LibraryTable",
// null,
// (txObj, { rows: { _array } }) => {
// console.log("DELETED TABLE");
// },
// (txObj, error) => console.log("Error ", error)
// );
// });
// setNovels([]);
// };
const deleted = () => {
db.transaction((tx) => {
tx.executeSql(
"DROP TABLE LibraryTable",
null,
(txObj, { rows: { _array } }) => {
console.log("DELETED TABLE");
},
(txObj, error) => console.log("Error ", error)
);
});
setNovels([]);
};
useFocusEffect(
useCallback(() => {
@@ -110,7 +110,7 @@ const UpdatesScreen = ({ navigation }) => {
numColumns={3}
data={novels}
showsVerticalScrollIndicator={false}
keyExtractor={(item) => item.novelId}
keyExtractor={(item) => item.novelUrl}
renderItem={({ item }) => (
<TouchableRipple
borderless
@@ -119,7 +119,7 @@ const UpdatesScreen = ({ navigation }) => {
style={styles.opac}
onPress={() =>
navigation.navigate(
"LibraryNovelItem",
"NovelItemRewrite",
item
)
}
@@ -139,9 +139,9 @@ const UpdatesScreen = ({ navigation }) => {
}
/>
)}
{/* <Button mode="contained" onPress={() => deleted()}>
Delete Table
</Button> */}
<Button mode="contained" onPress={() => deleted()}>
Delete Library Table
</Button>
</>
)}
</View>
+77 -45
View File
@@ -8,6 +8,7 @@ import {
FlatList,
ScrollView,
RefreshControl,
ToastAndroid,
} from "react-native";
import {
Appbar,
@@ -36,19 +37,20 @@ const NovelItem = ({ route, navigation }) => {
const fetchNovel = () => {
db.transaction((tx) => {
tx.executeSql(
"SELECT * FROM LibraryTable WHERE novelId=?",
[item.novelId],
"SELECT * FROM LibraryTable WHERE novelUrl=?",
[item.novelUrl],
(txObj, { rows: { _array } }) => {
setNovel(_array);
setRefreshing(false);
},
(txObj, error) => console.log("Error ", error)
);
tx.executeSql(
"SELECT * FROM ChapterTable WHERE novelId=?",
[item.novelId],
"SELECT * FROM ChapterTable WHERE novelUrl=?",
[item.novelUrl],
(txObj, { rows: { _array } }) => {
setChapters(_array);
// !_array.length && getChapters();
setRefreshing(false);
setLoading(false);
},
(txObj, error) => console.log("Error ", error)
@@ -56,18 +58,27 @@ const NovelItem = ({ route, navigation }) => {
});
};
// const getChapters = () => {
// fetch(`http://192.168.1.39:5000/api/novel/${item.novelUrl}`)
// .then((response) => response.json())
// .then((json) => {
// setChapters(json.novelChapters);
// })
// .catch((error) => console.error(error));
// };
const checkIfExistsInLibrary = (id) => {
db.transaction((tx) => {
tx.executeSql(
"SELECT * FROM LibraryTable WHERE novelId=?",
"SELECT * FROM LibraryTable WHERE novelUrl=?",
[id],
(txObj, res) => {
console.log(res.rows.length);
// console.log(res.rows.length);
if (res.rows.length === 0) {
console.log("Not In Library");
// console.log("Not In Library");
setlibraryStatus(0);
} else {
console.log("In Library");
// console.log("In Library");
setlibraryStatus(1);
}
},
@@ -79,8 +90,8 @@ const NovelItem = ({ route, navigation }) => {
const sortChapters = () => {
db.transaction((tx) => {
tx.executeSql(
"SELECT * FROM ChapterTable WHERE novelId=? ORDER BY chapterName ASC",
[item.novelId],
"SELECT * FROM ChapterTable WHERE novelUrl=? ORDER BY chapterName ASC",
[item.novelUrl],
(txObj, { rows: { _array } }) => {
setChapters(_array);
setLoading(false);
@@ -94,57 +105,71 @@ const NovelItem = ({ route, navigation }) => {
if (libraryStatus === 0) {
db.transaction((tx) => {
tx.executeSql(
"INSERT INTO LibraryTable (novelId, novelName, novelCover, novelSummary, alternative, author, genre, type, releaseDate, status) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
"INSERT INTO LibraryTable (novelUrl, novelName, novelCover, novelSummary, alternative, author, genre, type, releaseDate, status) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
[
item.novelId,
item.novelUrl,
item.novelName,
item.novelCover,
item.novelSummary,
item.alternative,
item.author,
item.genre,
item.type,
item.releaseDate,
item.status,
]
item.Alternative,
item["Author(s)"],
item["Genres(s)"],
item.Type,
item.Release,
item.Status,
],
(txObj, res) => {
console.log("Novel Inserted");
},
(txObj, error) => console.log("Error ", error)
);
console.log("Inserted Novel");
// chapters.map((chap) =>
// tx.executeSql(
// "INSERT INTO ChapterTable (chapterId, chapterName, releaseDate, novelId) values (?, ?, ?, ?)",
// [
// chap.chapterId,
// chap.chapterName,
// chap.releaseDate,
// item.novelId,
// ]
// )
// );
chapters.map((chap) =>
tx.executeSql(
"INSERT INTO ChapterTable (chapterUrl, chapterName, releaseDate, novelUrl) values (?, ?, ?, ?)",
[
chap.chapterUrl,
chap.chapterName,
chap.releaseDate,
item.novelUrl,
],
(txObj, res) => {
// console.log("Chapters Inserted");
},
(txObj, error) => console.log("Error ", error)
)
);
setlibraryStatus(1);
ToastAndroid.show("Added to library", ToastAndroid.SHORT);
});
} else {
db.transaction((tx) => {
tx.executeSql(
"DELETE FROM LibraryTable WHERE novelId=?",
[item.novelId],
"DELETE FROM LibraryTable WHERE novelUrl=?",
[item.novelUrl],
(txObj, res) => {
console.log("DELETED NOVEL FROM TABLE");
},
(txObj, error) => console.log("Error ", error)
);
// tx.executeSql("DELETE FROM ChapterTable WHERE novelId=?", [
// item.novelId,
// ]);
tx.executeSql(
"DELETE FROM ChapterTable WHERE novelUrl=?",
[item.novelUrl],
(txObj, res) => {
console.log("DELETED Chapters FROM TABLE");
},
(txObj, error) => console.log("Error ", error)
);
console.log("Removed Novel");
setlibraryStatus(0);
ToastAndroid.show("Removed from library", ToastAndroid.SHORT);
});
}
};
useEffect(() => {
fetchNovel();
checkIfExistsInLibrary(item.novelId);
checkIfExistsInLibrary(item.novelUrl);
}, []);
const onRefresh = async () => {
@@ -218,7 +243,7 @@ const NovelItem = ({ route, navigation }) => {
}}
numberOfLines={1}
>
{item.alternative.replace(
{item.Alternative.replace(
",",
", "
)}
@@ -231,7 +256,10 @@ const NovelItem = ({ route, navigation }) => {
fontSize: 15,
}}
>
{item.author.replace(",", ", ")}
{item["Author(s)"].replace(
",",
", "
)}
</Text>
<Text
style={{
@@ -241,7 +269,7 @@ const NovelItem = ({ route, navigation }) => {
fontSize: 15,
}}
>
{item.releaseDate}
{item.Release}
</Text>
<Text
style={{
@@ -251,7 +279,7 @@ const NovelItem = ({ route, navigation }) => {
fontSize: 15,
}}
>
{item.status + " • " + item.type}
{item.Status + " • " + item.Type}
</Text>
</>
)}
@@ -328,7 +356,7 @@ const NovelItem = ({ route, navigation }) => {
marginBottom: 15,
}}
horizontal
data={item.genre.split(",")}
data={item["Genre(s)"].split(",")}
keyExtractor={(item) => item}
renderItem={({ item }) => (
<Text
@@ -380,7 +408,11 @@ const NovelItem = ({ route, navigation }) => {
data={chapters}
extraData={chapters}
showsVerticalScrollIndicator={false}
keyExtractor={(item) => item.chapterId}
keyExtractor={(item) =>
item.chapterUrl
? item.chapterUrl
: item.chapterUrl
}
removeClippedSubviews={true}
maxToRenderPerBatch={10}
initialNumToRender={10}
@@ -392,7 +424,7 @@ const NovelItem = ({ route, navigation }) => {
}}
onPress={() =>
navigation.navigate("ChapterItem", {
chapterUrl: item.chapterId,
chapterUrl: item.chapterUrl,
})
}
rippleColor={theme.rippleColorDark}
-13
View File
@@ -101,18 +101,6 @@ const NovelItem = ({ route, navigation }) => {
}
};
const createTables = () =>
db.transaction((tx) => {
tx.executeSql(
"CREATE TABLE IF NOT EXISTS LibraryTable (novelId VARCHAR(255) NOT NULL PRIMARY KEY, novelName VARCHAR(255), novelCover VARCHAR(255), novelSummary TEXT, alternative VARCHAR(255), author VARCHAR(255), genre VARCHAR(255), type VARCHAR(255), releaseDate VARCHAR(255), status VARCHAR(255))"
);
console.log("Library Table Created");
tx.executeSql(
"CREATE TABLE IF NOT EXISTS ChapterTable (chapterId VARCHAR(255), chapterName VARCHAR(255), releaseDate VARCHAR(255), novelId VARCHAR(255), FOREIGN KEY (novelId) REFERENCES LibraryTable(novelId) ON DELETE CASCADE)"
);
});
const checkIfExistsInLibrary = (id) => {
db.transaction((tx) => {
tx.executeSql(
@@ -134,7 +122,6 @@ const NovelItem = ({ route, navigation }) => {
};
useEffect(() => {
createTables();
getNovel();
}, []);
+507
View File
@@ -0,0 +1,507 @@
import React, { useState, useEffect } from "react";
import {
StyleSheet,
View,
Image,
ImageBackground,
Text,
FlatList,
ScrollView,
RefreshControl,
} from "react-native";
import {
Appbar,
TouchableRipple,
IconButton,
Button,
} from "react-native-paper";
import { LinearGradient } from "expo-linear-gradient";
import { theme } from "../theming/theme";
import * as SQLite from "expo-sqlite";
const db = SQLite.openDatabase("lnreader.db");
const NovelItem = ({ route, navigation }) => {
const item = route.params;
const [loading, setLoading] = useState(true);
const [refreshing, setRefreshing] = useState(false);
const [novel, setNovel] = useState(item);
const [chapters, setChapters] = useState();
const [more, setMore] = useState(false);
const [libraryStatus, setlibraryStatus] = useState();
// const [dbFlag, setDbFlag] = useState(0);
const getNovel = () => {
fetch(`http://192.168.1.39:5000/api/novel/${item.novelUrl}`)
.then((response) => response.json())
.then((json) => {
setNovel(json);
setChapters(json.novelChapters);
})
.catch((error) => console.error(error))
.finally(() => {
setRefreshing(false);
setLoading(false);
});
};
const getNovelFromDb = () => {
db.transaction((tx) => {
// tx.executeSql(
// "SELECT * FROM LibraryTable WHERE novelUrl=?",
// [item.novelUrl],
// (txObj, { rows: _array }) => {
// // setNovel(_array);
// // console.log(_array);
// },
// (txObj, error) => console.log("Error ", error)
// );
tx.executeSql(
"SELECT * FROM ChapterTable WHERE novelUrl=?",
[item.novelUrl],
(txObj, { rows: { _array } }) => {
setChapters(_array);
// console.log(_array);
setRefreshing(false);
setLoading(false);
},
(txObj, error) => console.log("Error ", error)
);
});
};
const insertToLibrary = () => {
if (libraryStatus === 0) {
db.transaction((tx) => {
tx.executeSql(
"INSERT INTO LibraryTable (novelUrl, novelName, novelCover, novelSummary, Alternative, `Author(s)`, `Genre(s)`, Type, `Release`, Status) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
[
item.novelUrl,
novel.novelName,
novel.novelCover,
novel.novelSummary,
novel.Alternative,
novel["Author(s)"],
novel["Genre(s)"],
novel.Type,
novel.Release,
novel.Status,
],
(tx, res) => console.log("Inserted Novel"),
(txObj, error) => console.log("Error ", error)
);
chapters.map((chap) =>
tx.executeSql(
"INSERT INTO ChapterTable (chapterUrl, chapterName, releaseDate, novelUrl) values (?, ?, ?, ?)",
[
chap.chapterUrl,
chap.chapterName,
chap.releaseDate,
item.novelUrl,
]
)
);
setlibraryStatus(1);
});
} else {
db.transaction((tx) => {
tx.executeSql(
"DELETE FROM LibraryTable WHERE novelUrl=?",
[item.novelUrl],
(txObj, res) => {
console.log("DELETED NOVEL FROM TABLE");
},
(txObj, error) => console.log("Error ", error)
);
tx.executeSql("DELETE FROM ChapterTable WHERE novelUrl=?", [
item.novelUrl,
]);
console.log("Removed Novel");
setlibraryStatus(0);
});
}
};
const checkIfExistsInLibrary = (id) => {
db.transaction((tx) => {
tx.executeSql(
"SELECT * FROM LibraryTable WHERE novelUrl=?",
[id],
(txObj, res) => {
console.log(res.rows.length);
if (res.rows.length === 0) {
console.log("Not In Library");
getNovel();
setlibraryStatus(0);
} else {
console.log("In Library");
getNovelFromDb();
setlibraryStatus(1);
}
},
(txObj, error) => console.log("Error ", error)
);
});
};
useEffect(() => {
checkIfExistsInLibrary(item.novelUrl);
}, []);
const onRefresh = async () => {
setRefreshing(true);
checkIfExistsInLibrary(item.novelUrl);
};
return (
<>
<Appbar.Header style={{ backgroundColor: theme.colorDarkPrimary }}>
<Appbar.BackAction
onPress={() => {
navigation.goBack();
}}
color={"white"}
size={26}
style={{ marginRight: 0 }}
/>
<Appbar.Content
title={item.novelName}
titleStyle={{ color: theme.textColorPrimaryDark }}
/>
</Appbar.Header>
<ScrollView
style={styles.container}
refreshControl={
<RefreshControl
refreshing={refreshing}
onRefresh={onRefresh}
colors={["white"]}
progressBackgroundColor={theme.colorAccentDark}
/>
}
>
<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.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,
},
]}
uppercase={false}
labelStyle={{ letterSpacing: 0 }}
onPress={() => insertToLibrary()}
>
{libraryStatus === 0
? "Add to library"
: "In Library"}
</Button>
{/* <Button
color={theme.textColorPrimaryDark}
style={{
backgroundColor: theme.colorAccentDark,
marginHorizontal: 15,
}}
uppercase={false}
labelStyle={{ letterSpacing: 0 }}
onPress={() =>
checkIfExistsInLibrary(novel.novelUrl)
}
>
Check
</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,
}}
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",
}}
// onPress={() =>
// setChapters((chapters) => chapters.reverse())
// }
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={20}
// onPress={() =>
// setChapters((chapters) =>
// chapters.reverse()
// )
// }
/>
</>
</TouchableRipple>
<FlatList
data={chapters}
extraData={chapters}
showsVerticalScrollIndicator={false}
keyExtractor={(item) => novel.chapterUrl}
removeClippedSubviews={true}
maxToRenderPerBatch={10}
initialNumToRender={10}
renderItem={({ item }) => (
<TouchableRipple
style={{
paddingHorizontal: 15,
paddingVertical: 12,
}}
onPress={() =>
navigation.navigate("ChapterItem", {
chapterUrl: item.chapterUrl,
})
}
rippleColor={theme.rippleColorDark}
>
<>
<Text
style={{
color:
theme.textColorPrimaryDark,
}}
numberOfLines={1}
>
{item.chapterName}
</Text>
<Text
style={{
color:
theme.textColorSecondaryDark,
marginTop: 5,
fontSize: 13,
}}
numberOfLines={1}
>
{item.releaseDate}
</Text>
</>
</TouchableRipple>
)}
/>
</>
)}
</ScrollView>
</>
);
};
export default NovelItem;
const styles = StyleSheet.create({
container: {
flex: 1,
// backgroundColor: "#202125",
backgroundColor: "#000000",
},
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,
},
});
+4 -1
View File
@@ -116,7 +116,10 @@ const AllNovels = ({ navigation }) => {
rippleColor="rgba(256,256,256,0.3)"
style={styles.opac}
onPress={() =>
navigation.navigate("NovelItem", item)
navigation.navigate(
"NovelItemRewrite",
item
)
}
>
<NovelCover item={item} />