diff --git a/src/components/common/Appbar.js b/src/components/common/Appbar.js index f9f23edf3..e7f618c22 100644 --- a/src/components/common/Appbar.js +++ b/src/components/common/Appbar.js @@ -1,19 +1,136 @@ -import React from "react"; - -import { Appbar } from "react-native-paper"; +import React, { useRef } from "react"; +import { View, TextInput, StyleSheet } from "react-native"; +import { + TouchableRipple, + IconButton, + Appbar as MaterialAppbar, +} from "react-native-paper"; +import Constants from "expo-constants"; +import { useNavigation } from "@react-navigation/native"; import { useSelector } from "react-redux"; -export const CustomAppbar = ({ title, onBackAction }) => { +export const Appbar = ({ title, onBackAction }) => { const theme = useSelector((state) => state.themeReducer.theme); return ( - - {onBackAction && } - + {onBackAction && ( + + )} + - + + ); +}; + +export const SearchAppbar = ({ + placeholder, + getSearchResults, + setSearchText, + searchText, + getNovels, + setLoading, + screen, + onFilter, +}) => { + const searchRef = useRef(null); + + const navigation = useNavigation(); + + const theme = useSelector((state) => state.themeReducer.theme); + + return ( + searchRef.current.focus()} + style={[ + styles.searchAppbarContainer, + { backgroundColor: theme.searchBarColor }, + ]} + > + + + { + if (screen === "Extension") { + navigation.goBack(); + } + }} + /> + { + setSearchText(text); + if (screen === "Library") { + getSearchResults(text); + } + }} + onSubmitEditing={() => { + if (screen === "Extension") { + getSearchResults(searchText); + } + }} + defaultValue={searchText} + /> + + {searchText !== "" && ( + { + setLoading?.(true); + getNovels(); + setSearchText(""); + }} + /> + )} + onFilter?.()} + /> + + ); }; + +const styles = StyleSheet.create({ + searchAppbarContainer: { + marginTop: Constants.statusBarHeight + 4, + height: 48, + flexDirection: "row", + alignItems: "center", + paddingHorizontal: 16, + marginBottom: 8, + borderRadius: 8, + marginHorizontal: 12, + elevation: 2, + }, +}); diff --git a/src/screens/History/components/EmptyView.js b/src/components/common/EmptyView.js similarity index 82% rename from src/screens/History/components/EmptyView.js rename to src/components/common/EmptyView.js index 4c27be870..73b4252f8 100644 --- a/src/screens/History/components/EmptyView.js +++ b/src/components/common/EmptyView.js @@ -2,7 +2,7 @@ import React from "react"; import { StyleSheet, Text, View } from "react-native"; import { useSelector } from "react-redux"; -const EmptyView = () => { +const EmptyView = ({ icon, description }) => { const theme = useSelector((state) => state.themeReducer.theme); return ( @@ -11,21 +11,21 @@ const EmptyView = () => { style={[ styles.emptyViewIcon, { - color: theme.textColorSecondaryDark, + color: theme.textColorSecondary, }, ]} > - (˘・_・˘) + {icon} - Nothing read recently. + {description} ); diff --git a/src/components/common/NovelCover.js b/src/components/common/NovelCover.js index 42612ae55..e02c035d8 100644 --- a/src/components/common/NovelCover.js +++ b/src/components/common/NovelCover.js @@ -21,20 +21,18 @@ const NovelCover = ({ item, onPress, libraryStatus }) => { <> - {item.novelCover ? ( + {item.novelCover && ( @@ -53,7 +51,7 @@ const NovelCover = ({ item, onPress, libraryStatus }) => { styles.title, { color: - theme.textColorPrimaryDark, + "rgba(255,255,255,1)", }, ]} > @@ -63,19 +61,16 @@ const NovelCover = ({ item, onPress, libraryStatus }) => { )} - ) : ( - - - Novel Cover Doesn't Exist - - )} {displayMode === 1 && ( {item.novelName} @@ -91,8 +86,7 @@ export default NovelCover; const styles = StyleSheet.create({ logo: { - height: 183, - borderRadius: 4, + height: 180, }, titleContainer: { flex: 1, diff --git a/src/components/settings/Checkbox.js b/src/components/settings/Checkbox.js index ea8ba16d0..835d3d2ec 100644 --- a/src/components/settings/Checkbox.js +++ b/src/components/settings/Checkbox.js @@ -13,10 +13,10 @@ export const DisplayCheckbox = ({ displayMode, onPress, value }) => { return ( @@ -29,10 +29,10 @@ export const ThemeCheckbox = ({ onPress, label, checked }) => { return ( diff --git a/src/navigation/Router.js b/src/navigation/Router.js index 937eb73ea..f12d8a559 100644 --- a/src/navigation/Router.js +++ b/src/navigation/Router.js @@ -4,6 +4,7 @@ import { TransitionPresets, } from "@react-navigation/stack"; import { createMaterialBottomTabNavigator } from "@react-navigation/material-bottom-tabs"; +import { Provider } from "react-native-paper"; import MaterialCommunityIcons from "react-native-vector-icons/MaterialCommunityIcons"; @@ -64,7 +65,7 @@ const BottomNavigator = () => { return ( { const Router = () => { return ( - - - - - - - + + + + + + + + + ); }; diff --git a/src/redux/actions/extension.js b/src/redux/actions/extension.js new file mode 100644 index 000000000..f85981bff --- /dev/null +++ b/src/redux/actions/extension.js @@ -0,0 +1,11 @@ +import { GET_EXTENSIONS } from "./types"; +import { fetchExtensionList } from "../../services/api"; + +export const getExtensions = () => async (dispatch) => { + const res = await fetchExtensionList(); + + dispatch({ + type: GET_EXTENSIONS, + payload: res, + }); +}; diff --git a/src/redux/actions/types.js b/src/redux/actions/types.js index 05ddb2977..25425fefa 100644 --- a/src/redux/actions/types.js +++ b/src/redux/actions/types.js @@ -5,3 +5,5 @@ export const GET_LIBRARY_NOVELS = "GET_LIBRARY_NOVELS"; export const SET_DISPLAY_MODE = "SET_DISPLAY_MODE"; export const SET_ITEMS_PER_ROW = "SET_ITEMS_PER_ROW"; + +export const GET_EXTENSIONS = "GET_EXTENSIONS"; diff --git a/src/redux/reducers/extension.js b/src/redux/reducers/extension.js new file mode 100644 index 000000000..49feeee35 --- /dev/null +++ b/src/redux/reducers/extension.js @@ -0,0 +1,19 @@ +import { GET_EXTENSIONS } from "../actions/types"; + +const initialState = { + extensions: [], + loading: true, +}; + +const libraryReducer = (state = initialState, action) => { + const { type, payload } = action; + + switch (type) { + case GET_EXTENSIONS: + return { extensions: payload, loading: false }; + default: + return state; + } +}; + +export default libraryReducer; diff --git a/src/redux/store/configureStore.js b/src/redux/store/configureStore.js index 0643b8609..12d7f82e6 100644 --- a/src/redux/store/configureStore.js +++ b/src/redux/store/configureStore.js @@ -6,6 +6,7 @@ import thunk from "redux-thunk"; import themeReducer from "../reducers/theme"; import settingsReducer from "../reducers/settings"; import libraryReducer from "../reducers/library"; +import extensionReducer from "../reducers/extension"; const persistConfig = { key: "root", @@ -14,7 +15,12 @@ const persistConfig = { const persistedReducer = persistReducer( persistConfig, - combineReducers({ themeReducer, settingsReducer, libraryReducer }) + combineReducers({ + themeReducer, + settingsReducer, + libraryReducer, + extensionReducer, + }) ); export const store = createStore(persistedReducer, applyMiddleware(thunk)); diff --git a/src/screens/Browse/Browse.js b/src/screens/Browse/Browse.js index 58e6e59d0..159ce3b40 100644 --- a/src/screens/Browse/Browse.js +++ b/src/screens/Browse/Browse.js @@ -1,144 +1,56 @@ -import React, { useEffect, useState } from "react"; +import React, { useEffect } from "react"; +import { StyleSheet, View, FlatList, ActivityIndicator } from "react-native"; +import { Appbar } from "../../components/common/Appbar"; +import { connect } from "react-redux"; -import { - StyleSheet, - View, - Text, - FlatList, - Image, - ActivityIndicator, -} from "react-native"; -import { TouchableRipple, Button } from "react-native-paper"; -import { CustomAppbar } from "../../components/common/Appbar"; +import { getExtensions } from "../../redux/actions/extension"; -import { useSelector } from "react-redux"; - -const Browse = ({ navigation }) => { - const theme = useSelector((state) => state.themeReducer.theme); - - const [loading, setLoading] = useState(true); - const [extensions, setExtensions] = useState(); +import ExtensionCard from "./components/ExtensionCard"; +const Browse = ({ theme, extensions, loading, getExtensions }) => { useEffect(() => { - fetch(`https://lnreader-extensions.herokuapp.com/api/`) - .then((response) => response.json()) - .then((json) => { - setExtensions(json); - setLoading(false); - }); + getExtensions(); }, []); return ( <> - + - {!loading ? ( - item.sourceId.toString()} - renderItem={({ item }) => ( - - navigation.navigate( - item.sourceName + "Stack" - ) - } - rippleColor={theme.rippleColorDark} - > - <> - - - - - {item.sourceName} - - - {item.sourceLanguage} - - - - - - - - - )} - /> - ) : ( - - - - )} + item.sourceId.toString()} + renderItem={({ item }) => } + ListEmptyComponent={ + loading && ( + + ) + } + /> ); }; -export default Browse; +const mapStateToProps = (state) => ({ + theme: state.themeReducer.theme, + extensions: state.extensionReducer.extensions, + loading: state.extensionReducer.loading, +}); + +export default connect(mapStateToProps, { getExtensions })(Browse); const styles = StyleSheet.create({ container: { flex: 1, - }, - sourceCard: { - paddingVertical: 10, - marginVertical: 5, - paddingHorizontal: 20, - borderRadius: 6, - flexDirection: "row", - alignItems: "center", + paddingHorizontal: 4, }, }); diff --git a/src/screens/Browse/components/ExtensionCard.js b/src/screens/Browse/components/ExtensionCard.js new file mode 100644 index 000000000..527be6477 --- /dev/null +++ b/src/screens/Browse/components/ExtensionCard.js @@ -0,0 +1,91 @@ +import React from "react"; +import { View, Text, Image, StyleSheet } from "react-native"; +import { TouchableRipple, Button } from "react-native-paper"; + +import { useNavigation } from "@react-navigation/native"; +import { useSelector } from "react-redux"; + +const ExtensionCard = ({ item }) => { + const { sourceName, sourceCover, sourceLanguage } = item; + + const navigation = useNavigation(); + + const theme = useSelector((state) => state.themeReducer.theme); + + return ( + navigation.navigate(sourceName + "Stack")} + rippleColor={theme.rippleColor} + > + <> + + + + + {sourceName} + + + {sourceLanguage} + + + + + + + + + ); +}; + +export default ExtensionCard; + +const styles = StyleSheet.create({ + extensionCard: { + flexDirection: "row", + alignItems: "center", + marginVertical: 4, + paddingVertical: 8, + paddingHorizontal: 20, + borderRadius: 6, + }, + extensionIcon: { + width: 40, + height: 40, + borderRadius: 8, + }, + extensionDetails: { + flex: 1, + flexDirection: "row", + justifyContent: "space-between", + alignItems: "center", + marginLeft: 16, + }, +}); diff --git a/src/screens/Chapter/Chapter.js b/src/screens/Chapter/Chapter.js index 919d51525..8f7816774 100644 --- a/src/screens/Chapter/Chapter.js +++ b/src/screens/Chapter/Chapter.js @@ -193,7 +193,7 @@ const ChapterItem = ({ route, navigation }) => { /> {!loading && ( <> @@ -241,7 +241,7 @@ const ChapterItem = ({ route, navigation }) => { contentContainerStyle={[ styles.container, readerTheme === 1 && { - backgroundColor: theme.colorDarkPrimary, + backgroundColor: theme.colorPrimary, }, readerTheme === 2 && { backgroundColor: "white", @@ -277,7 +277,7 @@ const ChapterItem = ({ route, navigation }) => { fontSize: size, }, readerTheme === 1 - ? { color: theme.textColorSecondaryDark } + ? { color: theme.textColorSecondary } : { color: "black" }, size === 16 ? { lineHeight: 25 } diff --git a/src/screens/Chapter/components/BottomSheet.js b/src/screens/Chapter/components/BottomSheet.js index 4965911f0..7718c4132 100644 --- a/src/screens/Chapter/components/BottomSheet.js +++ b/src/screens/Chapter/components/BottomSheet.js @@ -48,7 +48,7 @@ const ChapterBottomSheet = ({ @@ -70,7 +70,7 @@ const ChapterBottomSheet = ({ /> diff --git a/src/screens/History/History.js b/src/screens/History/History.js index a55093ee5..f88264bc6 100644 --- a/src/screens/History/History.js +++ b/src/screens/History/History.js @@ -9,13 +9,13 @@ import { ActivityIndicator, } from "react-native"; -import { CustomAppbar } from "../../components/common/Appbar"; +import { Appbar } from "../../components/common/Appbar"; import HistoryCard from "./components/HistoryCard"; import { getHistoryFromDb, deleteChapterHistory } from "../../services/db"; import { useSelector } from "react-redux"; -import EmptyView from "./components/EmptyView"; +import EmptyView from "../../components/common/EmptyView"; const History = ({ navigation }) => { const [loading, setLoading] = useState(true); @@ -49,15 +49,14 @@ const History = ({ navigation }) => { return ( <> - + item.historyId.toString()} renderItem={renderHistoryCard} @@ -69,7 +68,14 @@ const History = ({ navigation }) => { /> ) } - ListEmptyComponent={!loading && } + ListEmptyComponent={ + !loading && ( + + ) + } /> diff --git a/src/screens/History/components/HistoryCard.js b/src/screens/History/components/HistoryCard.js index c77fac432..1d8f01768 100644 --- a/src/screens/History/components/HistoryCard.js +++ b/src/screens/History/components/HistoryCard.js @@ -13,7 +13,7 @@ const HistoryCard = ({ item, deleteHistory, navigation }) => { return ( navigation.navigate("NovelItem", { @@ -34,7 +34,7 @@ const HistoryCard = ({ item, deleteHistory, navigation }) => { { { { navigation.navigate("ChapterItem", { diff --git a/src/screens/Library/Library.js b/src/screens/Library/Library.js index 2b33fa6df..daa60aa3d 100644 --- a/src/screens/Library/Library.js +++ b/src/screens/Library/Library.js @@ -11,14 +11,14 @@ import { FlatList } from "react-native-gesture-handler"; import { useFocusEffect } from "@react-navigation/native"; import { connect } from "react-redux"; -import Appbar from "./components/Appbar"; import NovelCover from "../../components/common/NovelCover"; -import EmptyView from "./components/EmptyView"; +import EmptyView from "../../components/common/EmptyView"; import { getLibraryNovels, searchLibraryNovels, } from "../../redux/actions/library"; +import { SearchAppbar } from "../../components/common/Appbar"; const LibraryScreen = ({ navigation, @@ -30,13 +30,11 @@ const LibraryScreen = ({ }) => { const [refreshing, setRefreshing] = useState(false); - const [search, setSearch] = useState({ searching: false, searchText: "" }); - - const resetSearch = () => setSearch({ searching: false, searchText: "" }); + const [searchText, setSearchText] = useState(""); useFocusEffect( useCallback(() => { - resetSearch(); + setSearchText(""); getLibraryNovels(); }, []) ); @@ -59,61 +57,62 @@ const LibraryScreen = ({ return ( <> - + {loading ? ( ) : ( - <> - item.novelUrl} - renderItem={({ item }) => ( - redirectToNovel(item)} - /> - )} - refreshControl={ - item.novelUrl} + renderItem={({ item }) => ( + redirectToNovel(item)} + /> + )} + refreshControl={ + + } + ListEmptyComponent={ + searchText !== "" ? ( + + {`"${searchText}" not in library`} + + ) : ( + - } - ListEmptyComponent={ - search.searchText === "" ? ( - - ) : ( - - {`"${search.searchText}" not in library`} - - ) - } - /> - + ) + } + /> )} @@ -137,9 +136,8 @@ const styles = StyleSheet.create({ padding: 4, }, emptySearch: { - fontWeight: "bold", - marginTop: 10, + marginTop: 8, textAlign: "center", - paddingHorizontal: 30, + paddingHorizontal: 16, }, }); diff --git a/src/screens/Library/components/Appbar.js b/src/screens/Library/components/Appbar.js index 18941827c..1102d3344 100644 --- a/src/screens/Library/components/Appbar.js +++ b/src/screens/Library/components/Appbar.js @@ -15,22 +15,22 @@ const LibraryAppbar = ({ const { searching, searchText } = search; return ( - + {!searching ? ( <> setSearch({ ...search, searching: true }) } - color={theme.textColorPrimaryDark} + color={theme.textColorPrimary} /> _panel.show({ velocity: -1.5 })} @@ -43,7 +43,7 @@ const LibraryAppbar = ({ setSearch({ searching: false, searchText: "" }); getLibraryNovels(); }} - color={theme.textColorPrimaryDark} + color={theme.textColorPrimary} size={24} /> )} diff --git a/src/screens/Library/components/EmptyView.js b/src/screens/Library/components/EmptyView.js deleted file mode 100644 index 4ee24872f..000000000 --- a/src/screens/Library/components/EmptyView.js +++ /dev/null @@ -1,52 +0,0 @@ -import React from "react"; -import { StyleSheet, Text, View } from "react-native"; -import { useSelector } from "react-redux"; - -const EmptyView = () => { - const theme = useSelector((state) => state.themeReducer.theme); - - return ( - - - Σ(ಠ_ಠ) - - - Your library is empty. Add series to your library from Browse. - - - ); -}; - -export default EmptyView; - -const styles = StyleSheet.create({ - emptyViewContainer: { - flex: 1, - justifyContent: "center", - alignItems: "center", - }, - emptyViewIcon: { - fontSize: 45, - fontWeight: "bold", - }, - emptyViewText: { - fontWeight: "bold", - marginTop: 10, - textAlign: "center", - paddingHorizontal: 30, - }, -}); diff --git a/src/screens/More/About.js b/src/screens/More/About.js index 74892b4df..1b0cb8888 100644 --- a/src/screens/More/About.js +++ b/src/screens/More/About.js @@ -2,7 +2,7 @@ import React from "react"; import * as Linking from "expo-linking"; import { List, Divider } from "react-native-paper"; -import { CustomAppbar } from "../../components/common/Appbar"; +import { Appbar } from "../../components/common/Appbar"; import { useSelector } from "react-redux"; @@ -11,46 +11,43 @@ const AboutScreen = ({ navigation }) => { return ( <> - navigation.goBack()} - /> + navigation.goBack()} /> Linking.openURL( "https://github.com/rajarsheechatterjee/lnreader/commits/main" ) } - rippleColor={theme.rippleColorDark} + rippleColor={theme.rippleColor} /> @@ -58,11 +55,11 @@ const AboutScreen = ({ navigation }) => { "https://github.com/rajarsheechatterjee/lnreader" ) } - rippleColor={theme.rippleColorDark} + rippleColor={theme.rippleColor} /> { "https://github.com/rajarsheechatterjee/lnreader-extensions" ) } - rippleColor={theme.rippleColorDark} + rippleColor={theme.rippleColor} /> diff --git a/src/screens/More/More.js b/src/screens/More/More.js index 4e7d0deaa..28765351e 100644 --- a/src/screens/More/More.js +++ b/src/screens/More/More.js @@ -3,7 +3,7 @@ import React from "react"; import { StyleSheet } from "react-native"; import { List } from "react-native-paper"; -import { CustomAppbar } from "../../components/common/Appbar"; +import { Appbar } from "../../components/common/Appbar"; import { useSelector } from "react-redux"; @@ -12,17 +12,17 @@ const MoreScreen = ({ navigation }) => { return ( <> - + ( { onPress={() => navigation.navigate("Settings")} /> ( { - const label = { + const display = { 0: "Compact", 1: "Comfortable", }; - const themes = { - 0: "AMOLED Dark Theme", - 1: "Light Theme", - 2: "Dark Theme", - 3: "Midnight Dusk Theme", - }; + const themes = [ + { themeCode: 0, label: "AMOLED Dark Theme", statusBar: "light" }, + { themeCode: 1, label: "Light Theme", statusBar: "dark" }, + { themeCode: 2, label: "Dark Theme", statusBar: "light" }, + { themeCode: 3, label: "Midnight Dusk Theme", statusBar: "light" }, + ]; const desciptionStyles = { - color: theme.textColorSecondaryDark, + color: theme.textColorSecondary, }; - const titleStyles = { color: theme.textColorPrimaryDark }; + const titleStyles = { color: theme.textColorPrimary }; - // Display Mode Modal + /** + * Display Mode Modal + */ const [displayModalVisible, setDisplayModalVisible] = useState(false); const showDisplayModal = () => setDisplayModalVisible(true); const hideDisplayModal = () => setDisplayModalVisible(false); - // Theme Modal + /** + * Change Theme Modal + */ const [themeModalVisible, setthemeModalVisible] = useState(false); const showthemeModal = () => setthemeModalVisible(true); const hidethemeModal = () => setthemeModalVisible(false); - // Items Modal - const [itemsModalVisible, setitemsModalVisible] = useState(false); - const showitemsModal = () => setitemsModalVisible(true); - const hideitemsModal = () => setitemsModalVisible(false); - return ( - - navigation.goBack()} - /> - + <> + navigation.goBack()} /> + deleteNovelsNotInLibrary()} - rippleColor={theme.rippleColorDark} + rippleColor={theme.rippleColor} /> deleteHistory()} - rippleColor={theme.rippleColorDark} + rippleColor={theme.rippleColor} /> - - setDisplayMode(1)} - /> - - - setDisplayMode(0)} - /> - + setDisplayMode(1)} + /> + setDisplayMode(0)} + /> - {/* - - - setItemsPerRow(1)} - > - 1 - - setItemsPerRow(2)} - > - 2 - - setItemsPerRow(3)} - > - 3 - - setItemsPerRow(4)} - > - 4 - - - */} {/* deleteDatabase()} /> */} @@ -229,58 +161,40 @@ const SettingsScreen = ({ titleStyle={titleStyles} title="Theme" descriptionStyle={desciptionStyles} - description={themes[themeCode]} + description={themes[themeCode].label} onPress={showthemeModal} - rippleColor={theme.rippleColorDark} + rippleColor={theme.rippleColor} /> - { - switchTheme(1); - setStatusBarStyle("dark"); - }} - /> - { - switchTheme(2); - setStatusBarStyle("light"); - }} - /> - { - switchTheme(0); - setStatusBarStyle("light"); - }} - /> - { - switchTheme(3); - setStatusBarStyle("light"); - }} - /> + {themes.map((item) => ( + { + switchTheme(item.themeCode); + setStatusBarStyle(item.statusBar); + }} + /> + ))} - + ); }; diff --git a/src/screens/Novel/Novel.js b/src/screens/Novel/Novel.js index de4497288..628fefadd 100644 --- a/src/screens/Novel/Novel.js +++ b/src/screens/Novel/Novel.js @@ -195,7 +195,7 @@ const NovelItem = ({ route, navigation }) => { { } /> diff --git a/src/screens/Novel/components/BottomSheet.js b/src/screens/Novel/components/BottomSheet.js index 72b8b685b..6c7c26e96 100644 --- a/src/screens/Novel/components/BottomSheet.js +++ b/src/screens/Novel/components/BottomSheet.js @@ -39,14 +39,14 @@ export const BottomSheet = ({ style={[ styles.contentContainer, { - backgroundColor: theme.colorDarkPrimary, + backgroundColor: theme.colorPrimary, }, ]} > @@ -77,7 +77,7 @@ export const BottomSheet = ({ /> Newest to oldest @@ -96,7 +96,7 @@ export const BottomSheet = ({ /> Oldest to newest @@ -108,7 +108,7 @@ export const BottomSheet = ({ filterChapters("")} /> - + Show all @@ -135,7 +135,7 @@ export const BottomSheet = ({ color={theme.colorAccentDark} onPress={() => filterChapters("AND `read`=1")} /> - + Show read chapters @@ -148,7 +148,7 @@ export const BottomSheet = ({ color={theme.colorAccentDark} onPress={() => filterChapters("AND `read`=0")} /> - + Show unread chapters @@ -163,7 +163,7 @@ export const BottomSheet = ({ color={theme.colorAccentDark} onPress={() => filterChapters("AND downloaded=1")} /> - + Show downloaded chapters @@ -175,5 +175,7 @@ export const BottomSheet = ({ const styles = StyleSheet.create({ contentContainer: { flex: 1, + borderTopRightRadius: 8, + borderTopLeftRadius: 8, }, }); diff --git a/src/screens/Novel/components/ChapterCard.js b/src/screens/Novel/components/ChapterCard.js index c494469a4..1f405d2c4 100644 --- a/src/screens/Novel/components/ChapterCard.js +++ b/src/screens/Novel/components/ChapterCard.js @@ -36,14 +36,14 @@ const ChapterCard = ({ chapterName: chapter.chapterName, }) } - rippleColor={theme.rippleColorDark} + rippleColor={theme.rippleColor} > <> @@ -55,7 +55,7 @@ const NovelInfoHeader = ({ style={styles.background} > @@ -73,7 +73,7 @@ const NovelInfoHeader = ({ style={[ styles.name, { - color: theme.textColorPrimaryDark, + color: theme.textColorPrimary, }, ]} > @@ -83,7 +83,7 @@ const NovelInfoHeader = ({ <> insertNovelInLib()} style={[ { - backgroundColor: theme.colorDarkPrimaryDark, + backgroundColor: theme.colorPrimaryDark, marginRight: 2, // borderColor: "rgba(255,255,255,0.121)", - // borderWidth: 1, + borderWidth: 0, justifyContent: "center", height: 30, alignItems: "center", @@ -165,7 +165,7 @@ const NovelInfoHeader = ({ ]} textStyle={{ fontWeight: "bold", - color: theme.textColorPrimaryDark, + color: theme.textColorPrimary, }} > {libraryStatus ? "In Library" : "Add to library"} @@ -202,7 +202,7 @@ const NovelInfoHeader = ({ > setMore(!more)} @@ -291,12 +291,12 @@ const NovelInfoHeader = ({ onPress={() => bottomSheetRef.current.show({ velocity: -1.5 }) } - rippleColor={theme.rippleColorDark} + rippleColor={theme.rippleColor} > <> @@ -332,7 +332,7 @@ const styles = StyleSheet.create({ }, background: { height: 285, - // backgroundColor: theme.colorDarkPrimaryDark, + // backgroundColor: theme.colorPrimaryDark, }, linearGradient: { // flex: 1, diff --git a/src/screens/extensions/boxnovel/BoxNovel.js b/src/screens/extensions/boxnovel/BoxNovel.js index 3f0adb006..2572f54a1 100644 --- a/src/screens/extensions/boxnovel/BoxNovel.js +++ b/src/screens/extensions/boxnovel/BoxNovel.js @@ -1,70 +1,38 @@ -import React, { useEffect, useState } from "react"; +import React, { useEffect, useState, useRef } from "react"; import { StyleSheet, View, FlatList, ActivityIndicator } from "react-native"; -import { Appbar, Provider, Portal } from "react-native-paper"; +import { Provider, Portal } from "react-native-paper"; import NovelCover from "../../../components/common/NovelCover"; -import SearchBar from "../../../components/common/SearchBar"; +import { SearchAppbar } from "../../../components/common/Appbar"; import { BottomSheet } from "./filters/BottomSheet"; import { useSelector } from "react-redux"; -import * as SQLite from "expo-sqlite"; -const db = SQLite.openDatabase("lnreader.db"); +const BoxNovel = ({ navigation }) => { + const theme = useSelector((state) => state.themeReducer.theme); + + const library = useSelector((state) => state.libraryReducer.novels); -const AllNovels = ({ navigation }) => { const [loading, setLoading] = useState(true); - const [loadingMore, setLoadingMore] = useState(false); const [novels, setNovels] = useState([]); - const [libraryNovels, setlibraryNovels] = useState([]); - const [sort, setSort] = useState("rating"); - const [pageNo, setPageNo] = useState(1); - const [searchBar, setSearchBar] = useState(false); const [searchText, setSearchText] = useState(""); - const [searched, setSearched] = useState(0); - - const theme = useSelector((state) => state.themeReducer.theme); + let bottomSheetRef = useRef(null); const getNovels = () => { fetch( - `https://lnreader-extensions.herokuapp.com/api/1/novels/${pageNo}/?o=${sort}` + `https://lnreader-extensions.herokuapp.com/api/1/novels/1/?o=${sort}` ) .then((response) => response.json()) .then((json) => { - setPageNo(pageNo + 1); - setNovels((novels) => novels.concat(json)); + setNovels(json); setLoading(false); }); }; - const getLibraryNovels = () => { - db.transaction((tx) => { - tx.executeSql( - "SELECT novelUrl FROM LibraryTable WHERE libraryStatus = 1 AND extensionId = 1", - null, - (tx, { rows: { _array } }) => { - setlibraryNovels(_array); - }, - (tx, error) => console.log(error) - ); - }); - }; - - const onEndReached = ({ - layoutMeasurement, - contentOffset, - contentSize, - }) => { - const paddingToBottom = 5; - return ( - layoutMeasurement.height + contentOffset.y >= - contentSize.height - paddingToBottom - ); - }; - const getSearchResults = (searchText) => { setLoading(true); fetch( @@ -78,92 +46,33 @@ const AllNovels = ({ navigation }) => { }; const checkIFInLibrary = (id) => { - return libraryNovels.some((obj) => obj.novelUrl === id); + return library.some((obj) => obj.novelUrl === id); }; useEffect(() => { - getLibraryNovels(); getNovels(); }, [sort]); - const sortNovels = () => { - setLoading(true); - if (searched) { - getSearchResults(); - } else { - getNovels(); - } - }; - return ( - - {!searchBar ? ( - <> - navigation.goBack()} - color={theme.textColorPrimaryDark} - /> - - - setSearchBar(true)} - color={theme.textColorPrimaryDark} - /> - _panel.show({ velocity: -1.5 })} - color={theme.textColorPrimaryDark} - /> - - ) : ( - <> - { - if (searched) { - setLoading(true); - setPageNo(1); - setNovels([]); - getNovels(); - } - setSearchBar(false); - setSearchText(""); - }} - color={theme.textColorPrimaryDark} - /> - setSearchText(text)} - onSubmitEditing={() => { - if (searchText !== "") { - setSort("rating"); - getSearchResults(searchText); - setSearched(true); - } - }} - /> - {searchText !== "" && ( - { - setSearchText(""); - }} - color={theme.textColorPrimaryDark} - /> - )} - - )} - + + bottomSheetRef.current.show({ velocity: -1.5 }) + } + /> {loading ? ( { data={novels} showsVerticalScrollIndicator={false} keyExtractor={(item) => item.novelUrl} - ListFooterComponent={() => - loadingMore && ( - - ) - } renderItem={({ item }) => ( { } /> )} - onScroll={({ nativeEvent }) => { - if (onEndReached(nativeEvent)) { - setLoadingMore(true); - getNovels(); - console.log("End Reached"); - } - }} /> )} (_panel = c)} + bottomSheetRef={bottomSheetRef} setSort={setSort} sort={sort} + setLoading={setLoading} /> ); }; -export default AllNovels; +export default BoxNovel; const styles = StyleSheet.create({ container: { flex: 1, - padding: 3, + padding: 4, }, contentContainer: { diff --git a/src/screens/extensions/boxnovel/filters/BottomSheet.js b/src/screens/extensions/boxnovel/filters/BottomSheet.js index fd83dd27c..2688a7a31 100644 --- a/src/screens/extensions/boxnovel/filters/BottomSheet.js +++ b/src/screens/extensions/boxnovel/filters/BottomSheet.js @@ -5,14 +5,18 @@ import Bottomsheet from "rn-sliding-up-panel"; import { useSelector } from "react-redux"; -export const BottomSheet = ({ - bottomSheetRef, - setSort, - sort, - setRefreshing, -}) => { +export const BottomSheet = ({ bottomSheetRef, setSort, sort, setLoading }) => { const theme = useSelector((state) => state.themeReducer.theme); + const sorting = [ + { label: "Latest", sortFlag: "latest" }, + { label: "A-Z", sortFlag: "aplhabet" }, + { label: "Rating", sortFlag: "rating" }, + { label: "Trending", sortFlag: "trending" }, + { label: "Most Views", sortFlag: "views" }, + { label: "New", sortFlag: "new-manga" }, + ]; + return ( @@ -49,129 +53,31 @@ export const BottomSheet = ({ }} expanded > - - sort === "latest" && ( - - ) - } - title="Latest" - titleStyle={{ - fontSize: 15, - color: theme.textColorPrimaryDark, - }} - onPress={() => setSort("latest")} - /> - - sort === "alphabet" && ( - - ) - } - title="A-Z" - titleStyle={{ - fontSize: 15, - color: theme.textColorPrimaryDark, - }} - onPress={() => { - setSort("alphabet"); - setRefreshing(true); - }} - /> - - sort === "rating" && ( - - ) - } - title="Rating" - titleStyle={{ - fontSize: 15, - color: theme.textColorPrimaryDark, - }} - onPress={() => { - setSort("rating"); - setRefreshing(true); - }} - /> - - sort === "trending" && ( - - ) - } - title="Trending" - titleStyle={{ - fontSize: 15, - color: theme.textColorPrimaryDark, - }} - onPress={() => { - setSort("trending"); - setRefreshing(true); - }} - /> - - sort === "views" && ( - - ) - } - title="Most Views" - titleStyle={{ - fontSize: 15, - color: theme.textColorPrimaryDark, - }} - onPress={() => { - setSort("views"); - setRefreshing(true); - }} - /> - - sort === "new-manga" && ( - - ) - } - title="New" - titleStyle={{ - fontSize: 15, - color: theme.textColorPrimaryDark, - }} - onPress={() => { - setSort("new-manga"); - setRefreshing(true); - }} - /> + {sorting.map((item) => ( + + sort === item.sortFlag && ( + + ) + } + title={item.label} + titleStyle={{ + fontSize: 15, + color: theme.textColorPrimary, + }} + onPress={() => { + setLoading(true); + setSort(item.sortFlag); + }} + /> + ))} diff --git a/src/screens/extensions/readlightnovel/ReadLightNovel.js b/src/screens/extensions/readlightnovel/ReadLightNovel.js index ef5632f2d..7c930bf42 100644 --- a/src/screens/extensions/readlightnovel/ReadLightNovel.js +++ b/src/screens/extensions/readlightnovel/ReadLightNovel.js @@ -1,28 +1,23 @@ import React, { useEffect, useState } from "react"; import { StyleSheet, View, FlatList, ActivityIndicator } from "react-native"; -import { Appbar, Provider } from "react-native-paper"; +import { Provider } from "react-native-paper"; import NovelCover from "../../../components/common/NovelCover"; -import SearchBar from "../../../components/common/SearchBar"; +import { SearchAppbar } from "../../../components/common/Appbar"; import { useSelector } from "react-redux"; - -import * as SQLite from "expo-sqlite"; -const db = SQLite.openDatabase("lnreader.db"); +import EmptyView from "../../../components/common/EmptyView"; const ReadLightNovel = ({ navigation }) => { const theme = useSelector((state) => state.themeReducer.theme); + const library = useSelector((state) => state.libraryReducer.novels); const [loading, setLoading] = useState(true); const [novels, setNovels] = useState(); - const [libraryNovels, setlibraryNovels] = useState([]); - const [searchBar, setSearchBar] = useState(false); const [searchText, setSearchText] = useState(""); - const [searched, setSearched] = useState(false); - const getNovels = () => { fetch(`https://lnreader-extensions.herokuapp.com/api/2/novels/`) .then((response) => response.json()) @@ -44,95 +39,32 @@ const ReadLightNovel = ({ navigation }) => { }); }; - const getLibraryNovels = () => { - db.transaction((tx) => { - tx.executeSql( - "SELECT novelUrl FROM LibraryTable WHERE libraryStatus = 1 AND extensionId = 2", - null, - (tx, { rows: { _array } }) => { - setlibraryNovels(_array); - }, - (tx, error) => console.log(error) - ); - }); - }; - const checkIFInLibrary = (id) => { - return libraryNovels.some((obj) => obj.novelUrl === id); + return library.some((obj) => obj.novelUrl === id); }; useEffect(() => { getNovels(); - getLibraryNovels(); }, []); return ( - - {!searchBar ? ( - <> - navigation.goBack()} - /> - - - setSearchBar(true)} - /> - - - ) : ( - <> - { - if (searched) { - setLoading(true); - getNovels(); - } - setSearchBar(false); - setSearchText(""); - }} - color={theme.textColorPrimaryDark} - /> - setSearchText(text)} - onSubmitEditing={() => { - if (searchText !== "") { - getSearchResults(searchText); - setSearched(true); - } - }} - /> - {searchText !== "" && ( - { - setSearchText(""); - }} - color={theme.textColorPrimaryDark} - /> - )} - - )} - + + {loading ? ( { ) : ( { } /> )} + ListEmptyComponent={ + searchText !== "" && + novels.length === 0 && ( + + ) + } /> )} diff --git a/src/services/api.js b/src/services/api.js index a63036a42..70ca9730e 100644 --- a/src/services/api.js +++ b/src/services/api.js @@ -53,12 +53,22 @@ export const fetchChapterFromSource = async ( chapterUrl ) => { const url = `https://lnreader-extensions.herokuapp.com/api/${extensionId}/novel/${novelUrl}${chapterUrl}`; - console.log( - `https://lnreader-extensions.herokuapp.com/api/${extensionId}/novel/${novelUrl}${chapterUrl}` - ); let res = await fetch(url); let chapter = await res.json(); return chapter; }; + +/** + * Fetch list of extensions + */ + +export const fetchExtensionList = async () => { + const url = `https://lnreader-extensions.herokuapp.com/api/`; + + let res = await fetch(url); + let extensions = await res.json(); + + return extensions; +}; diff --git a/src/theme/theme.js b/src/theme/theme.js index 9d6279a69..ea943e6a8 100644 --- a/src/theme/theme.js +++ b/src/theme/theme.js @@ -2,63 +2,67 @@ * Application Colors */ export const theme = { - colorDarkPrimary: "#000000", - colorDarkPrimaryDark: "#000000", + colorPrimary: "#000000", + colorPrimaryDark: "#000000", colorAccentDark: "#3399FF", - textColorPrimaryDark: "#FFFFFF", - textColorSecondaryDark: "rgba(255,255,255,0.7)", + textColorPrimary: "#FFFFFF", + textColorSecondary: "rgba(255,255,255,0.7)", textColorHintDark: "rgba(255,255,255,0.5)", - rippleColorDark: "rgba(255,255,255,0.2)", + rippleColor: "rgba(255,255,255,0.2)", }; /** * Light Theme */ export const lightTheme = { - colorDarkPrimary: "#FFFFFF", - colorDarkPrimaryDark: "#FAFAFA", + colorPrimary: "#FFFFFF", + colorPrimaryDark: "#FAFAFA", colorAccentDark: "#2979FF", - textColorPrimaryDark: "#000000", - textColorSecondaryDark: "rgba(0,0,0,0.54)", + textColorPrimary: "#000000", + textColorSecondary: "rgba(0,0,0,0.54)", textColorHintDark: "rgba(0,0,0,0.38)", - rippleColorDark: "#C2C2C2", + rippleColor: "#C2C2C2", + searchBarColor: "#FFFFFF", }; /** * Dark Theme */ export const darkTheme = { - colorDarkPrimary: "#242529", - colorDarkPrimaryDark: "#202125", + colorPrimary: "#242529", + colorPrimaryDark: "#202125", colorAccentDark: "#3399FF", - textColorPrimaryDark: "#FFFFFF", - textColorSecondaryDark: "rgba(255,255,255,0.7)", + textColorPrimary: "#FFFFFF", + textColorSecondary: "rgba(255,255,255,0.7)", textColorHintDark: "rgba(255,255,255,0.5)", - rippleColorDark: "rgba(255,255,255,0.2)", + rippleColor: "rgba(255,255,255,0.2)", + searchBarColor: "#303135", }; /** * Amoled Dark Theme */ export const amoledDarkTheme = { - colorDarkPrimary: "#000000", - colorDarkPrimaryDark: "#000000", + colorPrimary: "#000000", + colorPrimaryDark: "#000000", colorAccentDark: "#3399FF", - textColorPrimaryDark: "#FFFFFF", - textColorSecondaryDark: "rgba(255,255,255,0.7)", + textColorPrimary: "#FFFFFF", + textColorSecondary: "rgba(255,255,255,0.7)", textColorHintDark: "rgba(255,255,255,0.5)", - rippleColorDark: "rgba(255,255,255,0.2)", + rippleColor: "rgba(255,255,255,0.2)", + searchBarColor: "#1F1F1F", }; /** * Midnight Dusk Theme */ export const midnightDuskTheme = { - colorDarkPrimary: "#201F27", - colorDarkPrimaryDark: "#16151D", + colorPrimary: "#201F27", + colorPrimaryDark: "#16151D", colorAccentDark: "#F02475", - textColorPrimaryDark: "#FFFFFF", - textColorSecondaryDark: "rgba(255,255,255,0.7)", + textColorPrimary: "#FFFFFF", + textColorSecondary: "rgba(255,255,255,0.7)", textColorHintDark: "rgba(255,255,255,0.5)", - rippleColorDark: "rgba(255,255,255,0.2)", + rippleColor: "rgba(255,255,255,0.2)", + searchBarColor: "#201F27", };