diff --git a/App.js b/App.js index fffb58c9..6b8e80eb 100644 --- a/App.js +++ b/App.js @@ -1,4 +1,4 @@ -import React, { useState } from "react"; +import React, { useState, useEffect } from "react"; import Router from "./src/navigation/Router"; import { NavigationContainer } from "@react-navigation/native"; import { StatusBar } from "expo-status-bar"; diff --git a/debug.log b/debug.log new file mode 100644 index 00000000..5457bfb3 --- /dev/null +++ b/debug.log @@ -0,0 +1 @@ +[1225/135759.273:ERROR:directory_reader_win.cc(43)] FindFirstFile: The system cannot find the path specified. (0x3) diff --git a/package-lock.json b/package-lock.json index 0860aded..9790eabc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7191,6 +7191,11 @@ "resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-2.15.0.tgz", "integrity": "sha512-qTSQPy0WKHtlb8xt5gY0Gt6sdvfQUQAnFSqgsggW9UEvySbkHzpqOrOYNA79Ca8oXO0dCFwp6X8buIiDefa7+Q==" }, + "react-native-sqlite-storage": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/react-native-sqlite-storage/-/react-native-sqlite-storage-5.0.0.tgz", + "integrity": "sha512-c1Joq3/tO1nmIcP8SkRZNolPSbfvY8uZg5lXse0TmjIPC0qHVbk96IMvWGyly1TmYCIpxpuDRc0/xCffDbYIvg==" + }, "react-native-vector-icons": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/react-native-vector-icons/-/react-native-vector-icons-7.1.0.tgz", diff --git a/package.json b/package.json index 700efe7a..1809a08c 100644 --- a/package.json +++ b/package.json @@ -1,40 +1,42 @@ { - "main": "node_modules/expo/AppEntry.js", - "scripts": { - "start": "expo start", - "android": "expo start --android", - "ios": "expo start --ios", - "web": "expo start --web", - "eject": "expo eject" - }, - "dependencies": { - "@react-native-community/masked-view": "0.1.10", - "@react-native-community/slider": "^3.0.3", - "@react-navigation/material-bottom-tabs": "^5.3.10", - "@react-navigation/native": "^5.8.10", - "@react-navigation/stack": "^5.12.8", - "cheerio-without-node-native": "^0.20.2", - "expo": "~40.0.0", - "expo-app-loading": "^1.0.1", - "expo-font": "^8.4.0", - "expo-linear-gradient": "^8.4.0", - "expo-status-bar": "~1.0.3", - "react": "16.13.1", - "react-dom": "16.13.1", - "react-native": "https://github.com/expo/react-native/archive/sdk-40.0.1.tar.gz", - "react-native-collapsible-header-views": "^1.1.2", - "react-native-gesture-handler": "^1.8.0", - "react-native-paper": "^4.5.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", - "rn-sliding-up-panel": "^2.4.4" - }, - "devDependencies": { - "@babel/core": "~7.9.0" - }, - "private": true, - "proxy": "http://192.168.1.38:5000" + "main": "node_modules/expo/AppEntry.js", + "scripts": { + "start": "expo start", + "android": "expo start --android", + "ios": "expo start --ios", + "web": "expo start --web", + "eject": "expo eject" + }, + "dependencies": { + "@react-native-community/masked-view": "0.1.10", + "@react-native-community/slider": "^3.0.3", + "@react-navigation/material-bottom-tabs": "^5.3.10", + "@react-navigation/native": "^5.8.10", + "@react-navigation/stack": "^5.12.8", + "cheerio-without-node-native": "^0.20.2", + "expo": "~40.0.0", + "expo-app-loading": "^1.0.1", + "expo-font": "^8.4.0", + "expo-linear-gradient": "^8.4.0", + "expo-status-bar": "~1.0.3", + "react": "16.13.1", + "react-dom": "16.13.1", + "react-native": "https://github.com/expo/react-native/archive/sdk-40.0.1.tar.gz", + "react-native-collapsible-header-views": "^1.1.2", + "react-native-gesture-handler": "^1.8.0", + "react-native-paper": "^4.5.0", + "react-native-reanimated": "^1.13.2", + "react-native-safe-area-context": "3.1.9", + "react-native-screens": "~2.15.0", + "react-native-sqlite-storage": "^5.0.0", + "react-native-vector-icons": "^7.1.0", + "react-native-web": "~0.13.12", + "rn-sliding-up-panel": "^2.4.4", + "expo-sqlite": "~8.5.0" + }, + "devDependencies": { + "@babel/core": "~7.9.0" + }, + "private": true, + "proxy": "http://192.168.1.38:5000" } diff --git a/src/navigation/Router.js b/src/navigation/Router.js index c9dddd2f..77b4d54f 100644 --- a/src/navigation/Router.js +++ b/src/navigation/Router.js @@ -13,7 +13,7 @@ import Search from "../screens/Search"; import NovelItem from "../screens/NovelItem"; import ChapterItem from "../screens/ChapterItem"; import About from "../screens/About"; - +import LibraryNovelItem from "../screens/LibraryNovelItem"; import { theme } from "../theming/theme"; const Stack = createStackNavigator(); @@ -182,6 +182,10 @@ const MainStack = () => { + { - const { chapterName, chapterUrl } = route.params; + const { chapterUrl } = route.params; const [loading, setLoading] = useState(true); @@ -115,24 +115,18 @@ const ChapterItem = ({ route, navigation }) => { diff --git a/src/screens/Library.js b/src/screens/Library.js index 64313246..2e8fb413 100644 --- a/src/screens/Library.js +++ b/src/screens/Library.js @@ -162,10 +162,4 @@ const styles = StyleSheet.create({ contentContainer: { flex: 1, }, - fab: { - position: "absolute", - margin: 16, - right: 0, - bottom: 0, - }, }); diff --git a/src/screens/LibraryNovelItem.js b/src/screens/LibraryNovelItem.js new file mode 100644 index 00000000..13a3da9d --- /dev/null +++ b/src/screens/LibraryNovelItem.js @@ -0,0 +1,387 @@ +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(); + const [chapters, setChapters] = useState(); + const [more, setMore] = useState(false); + + const fetchNovel = () => { + db.transaction((tx) => { + tx.executeSql( + "SELECT * FROM LibraryTable WHERE novelId=?", + [item.novelId], + (txObj, { rows: { _array } }) => { + setNovel(_array); + setRefreshing(false); + }, + (txObj, error) => console.log("Error ", error) + ); + tx.executeSql( + "SELECT * FROM ChapterTable WHERE novelId=?", + [item.novelId], + (txObj, { rows: { _array } }) => { + setChapters(_array); + setLoading(false); + }, + (txObj, error) => console.log("Error ", error) + ); + }); + }; + + useEffect(() => { + fetchNovel(); + }, []); + + const onRefresh = async () => { + setRefreshing(true); + fetchNovel(); + }; + + return ( + <> + + { + navigation.goBack(); + }} + color={"white"} + size={26} + style={{ marginRight: 0 }} + /> + + + + + } + > + + + + + + + {item.novelName} + + {!loading && ( + <> + + {item.alternative.replace( + ",", + ", " + )} + + + {item.author.replace(",", ", ")} + + + {item.releaseDate} + + + {item.status + " • " + item.type} + + + )} + + + + + {!loading && ( + <> + {/* */} + {item.novelSummary.length > 0 && ( + + + About + + setMore(!more)} + ellipsizeMode="clip" + > + {item.novelSummary} + + setMore(!more)} + > + {more ? "Less" : "More"} + + + )} + item} + renderItem={({ item }) => ( + + {item} + + )} + /> + + + setChapters((chapters) => chapters.reverse()) + } + rippleColor={theme.rippleColorDark} + > + <> + + {chapters.length + " Chapters"} + + + setChapters((chapters) => + chapters.reverse() + ) + } + /> + + + item.chapterId} + removeClippedSubviews={true} + maxToRenderPerBatch={10} + initialNumToRender={10} + renderItem={({ item }) => ( + + navigation.navigate("ChapterItem", { + chapterUrl: item.chapterId, + }) + } + rippleColor={theme.rippleColorDark} + > + <> + + {item.chapterName} + + + {item.releaseDate} + + + + )} + /> + + )} + + + ); +}; + +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, + }, +}); diff --git a/src/screens/NovelItem.js b/src/screens/NovelItem.js index c2b77406..4df5e9cf 100644 --- a/src/screens/NovelItem.js +++ b/src/screens/NovelItem.js @@ -9,11 +9,19 @@ import { ScrollView, RefreshControl, } from "react-native"; -import { Appbar, TouchableRipple, IconButton } from "react-native-paper"; +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; @@ -38,6 +46,52 @@ const NovelItem = ({ route, navigation }) => { }); }; + const insertToLibrary = () => { + createTables(); + db.transaction((tx) => { + tx.executeSql( + "INSERT INTO LibraryTable (novelId, novelName, novelCover, novelSummary, alternative, author, genre, type, releaseDate, status) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", + [ + novel.novelUrl, + novel.novelName, + novel.novelCover, + novel.novelSummary, + novel.novelDetails.Alternative, + novel.novelDetails["Author(s)"], + novel.novelDetails["Genre(s)"], + novel.novelDetails.Type, + novel.novelDetails.Release, + novel.novelDetails.Status, + ] + ); + console.log("Inserted Novel"); + + novel.novelChapters.map((chap) => + tx.executeSql( + "INSERT INTO ChapterTable (chapterId, chapterName, releaseDate, novelId) values (?, ?, ?, ?)", + [ + chap.chapterUrl, + chap.chapterName, + chap.releaseDate, + novel.novelUrl, + ] + ) + ); + }); + }; + + 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)" + ); + }); + useEffect(() => { getNovel(); }, []); @@ -159,6 +213,18 @@ const NovelItem = ({ route, navigation }) => { {!loading && ( <> + {novel.novelSummary.length > 0 && ( { }} onPress={() => navigation.navigate("ChapterItem", { - chapterName: item.chapterName, chapterUrl: item.chapterUrl, }) } diff --git a/src/screens/Updates.js b/src/screens/Updates.js index 708194f8..dfd7b308 100644 --- a/src/screens/Updates.js +++ b/src/screens/Updates.js @@ -1,12 +1,78 @@ -import React from "react"; +import React, { useState, useCallback } from "react"; import { StyleSheet, Text, View } from "react-native"; +import { FlatList } from "react-native-gesture-handler"; +import { theme } from "../theming/theme"; +import { useFocusEffect } from "@react-navigation/native"; + +import { Button } from "react-native-paper"; + +import * as SQLite from "expo-sqlite"; + +const db = SQLite.openDatabase("lnreader.db"); + +const UpdatesScreen = ({ navigation }) => { + const [novels, setNovels] = useState(); + + const getLibraryNovels = () => { + db.transaction((tx) => { + tx.executeSql( + "SELECT * FROM LibraryTable", + null, + (txObj, { rows: { _array } }) => { + setNovels(_array); + // console.log(_array); + }, + (txObj, error) => console.log("Error ", error) + ); + // tx.executeSql( + // "SELECT * FROM Chaptertable", + // null, + // (txObj, { rows: { _array } }) => { + // console.log(_array); + // }, + // (txObj, error) => console.log("Error ", error) + // ); + }); + }; + + // const deleted = () => { + // db.transaction((tx) => { + // tx.executeSql( + // "DROP TABLE LibraryTable", + // null, + // (txObj) => { + // console.log("Deleted"); + // }, + // (txObj, error) => console.log("Error ", error) + // ); + // }); + // }; + + useFocusEffect( + useCallback(() => { + getLibraryNovels(); + }, []) + ); -const UpdatesScreen = () => { return ( - - Updates Screen - + item.novelId} + renderItem={({ item }) => ( + + navigation.navigate("LibraryNovelItem", item) + } + > + {item.novelId} + + )} + /> + {/* */} ); };