Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a870442022 | |||
| a9a176297e | |||
| f4c0a647fb | |||
| 06e7e45df0 | |||
| c538bf4956 | |||
| e1679a41f1 | |||
| 3c2f4a59b7 | |||
| 8c13b1ff12 | |||
| 45083e5fd1 | |||
| 3b37c1cb33 | |||
| 48187d7d54 |
Binary file not shown.
|
Before Width: | Height: | Size: 55 KiB |
@@ -15,13 +15,18 @@ import { createDB, deleteDb } from "./src/database/DBHelper";
|
||||
const getFonts = () =>
|
||||
Font.loadAsync({
|
||||
"pt-sans-bold": require("./assets/fonts/PTSansNarrow-Bold.ttf"),
|
||||
"arbutus-slab": require("./assets/fonts/ArbutusSlab-Regular.ttf"),
|
||||
domine: require("./assets/fonts/Domine-VariableFont_wght.ttf"),
|
||||
lato: require("./assets/fonts/Lato-Regular.ttf"),
|
||||
"noto-sans": require("./assets/fonts/NotoSans-Regular.ttf"),
|
||||
"open-sans": require("./assets/fonts/OpenSans-Regular.ttf"),
|
||||
"pt-serif": require("./assets/fonts/PTSerif-Regular.ttf"),
|
||||
});
|
||||
|
||||
const App = () => {
|
||||
const [fontsLoaded, setFontsLoaded] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
// deleteDb();
|
||||
createDB();
|
||||
}, []);
|
||||
|
||||
|
||||
@@ -11,7 +11,8 @@
|
||||
"backgroundColor": "#000000"
|
||||
},
|
||||
"updates": {
|
||||
"fallbackToCacheTimeout": 0
|
||||
"fallbackToCacheTimeout": 0,
|
||||
"enabled": false
|
||||
},
|
||||
"assetBundlePatterns": ["**/*"],
|
||||
"ios": {
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 6.7 KiB |
Generated
-778
File diff suppressed because it is too large
Load Diff
+51
-54
@@ -1,56 +1,53 @@
|
||||
{
|
||||
"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-async-storage/async-storage": "^1.13.2",
|
||||
"@react-native-community/masked-view": "0.1.10",
|
||||
"@react-native-community/netinfo": "^5.9.7",
|
||||
"@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",
|
||||
"expo": "~40.0.0",
|
||||
"expo-app-loading": "^1.0.1",
|
||||
"expo-font": "^8.4.0",
|
||||
"expo-linear-gradient": "^8.4.0",
|
||||
"expo-sharing": "~8.5.0",
|
||||
"expo-sqlite": "~8.5.0",
|
||||
"expo-status-bar": "~1.0.3",
|
||||
"expo-web-browser": "~8.6.0",
|
||||
"moment": "^2.29.1",
|
||||
"react": "16.13.1",
|
||||
"react-color-extractor": "^1.1.2",
|
||||
"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-input-spinner": "^1.7.7",
|
||||
"react-native-offline": "^5.7.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",
|
||||
"react-native-webview": "11.0.0",
|
||||
"react-redux": "^7.2.2",
|
||||
"redux": "^4.0.5",
|
||||
"redux-devtools-extension": "^2.13.9",
|
||||
"redux-persist": "^6.0.0",
|
||||
"redux-thunk": "^2.3.0",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"rn-sliding-up-panel": "^2.4.4",
|
||||
"typeorm": "^0.2.31"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "~7.9.0",
|
||||
"@types/node": "^14.14.35"
|
||||
},
|
||||
"private": true
|
||||
"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-async-storage/async-storage": "^1.13.2",
|
||||
"@react-native-community/masked-view": "0.1.10",
|
||||
"@react-native-community/netinfo": "^5.9.7",
|
||||
"@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",
|
||||
"expo": "~40.0.0",
|
||||
"expo-app-loading": "^1.0.1",
|
||||
"expo-font": "^8.4.0",
|
||||
"expo-linear-gradient": "^8.4.0",
|
||||
"expo-sharing": "~8.5.0",
|
||||
"expo-sqlite": "~8.5.0",
|
||||
"expo-status-bar": "~1.0.3",
|
||||
"expo-web-browser": "~8.6.0",
|
||||
"moment": "^2.29.1",
|
||||
"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-offline": "^5.7.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",
|
||||
"react-native-webview": "11.0.0",
|
||||
"react-redux": "^7.2.2",
|
||||
"redux": "^4.0.5",
|
||||
"redux-devtools-extension": "^2.13.9",
|
||||
"redux-persist": "^6.0.0",
|
||||
"redux-thunk": "^2.3.0",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"rn-sliding-up-panel": "^2.4.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "~7.9.0",
|
||||
"@types/node": "^14.14.35"
|
||||
},
|
||||
"private": true
|
||||
}
|
||||
|
||||
@@ -10,11 +10,13 @@ import Constants from "expo-constants";
|
||||
import { useNavigation } from "@react-navigation/native";
|
||||
import { useSelector } from "react-redux";
|
||||
|
||||
export const Appbar = ({ title, onBackAction }) => {
|
||||
export const Appbar = ({ title, onBackAction, style }) => {
|
||||
const theme = useSelector((state) => state.themeReducer.theme);
|
||||
|
||||
return (
|
||||
<MaterialAppbar.Header style={{ backgroundColor: theme.colorPrimary }}>
|
||||
<MaterialAppbar.Header
|
||||
style={[{ backgroundColor: theme.colorPrimary }, style]}
|
||||
>
|
||||
{onBackAction && (
|
||||
<MaterialAppbar.BackAction onPress={onBackAction} />
|
||||
)}
|
||||
@@ -34,7 +36,7 @@ export const SearchAppbar = ({
|
||||
getNovels,
|
||||
setLoading,
|
||||
screen,
|
||||
onFilter,
|
||||
openWebView,
|
||||
}) => {
|
||||
const searchRef = useRef(null);
|
||||
|
||||
@@ -110,17 +112,15 @@ export const SearchAppbar = ({
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<IconButton
|
||||
icon="filter-variant"
|
||||
color={theme.textColorSecondary}
|
||||
style={{ marginRight: 0 }}
|
||||
size={23}
|
||||
disabled={typeof onFilter === "function" ? false : true}
|
||||
/**
|
||||
* TODO
|
||||
*/
|
||||
onPress={() => onFilter?.()}
|
||||
/>
|
||||
{openWebView && (
|
||||
<IconButton
|
||||
icon="earth"
|
||||
color={theme.textColorSecondary}
|
||||
style={{ marginRight: 0 }}
|
||||
size={23}
|
||||
onPress={openWebView}
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
</TouchableRipple>
|
||||
);
|
||||
@@ -10,9 +10,7 @@ const EmptyView = ({ icon, description }) => {
|
||||
<Text
|
||||
style={[
|
||||
styles.emptyViewIcon,
|
||||
{
|
||||
color: theme.textColorSecondary,
|
||||
},
|
||||
{ color: theme.textColorSecondary },
|
||||
]}
|
||||
>
|
||||
{icon}
|
||||
@@ -20,9 +18,7 @@ const EmptyView = ({ icon, description }) => {
|
||||
<Text
|
||||
style={[
|
||||
styles.emptyViewText,
|
||||
{
|
||||
color: theme.textColorSecondary,
|
||||
},
|
||||
{ color: theme.textColorSecondary },
|
||||
]}
|
||||
>
|
||||
{description}
|
||||
@@ -0,0 +1,57 @@
|
||||
import React from "react";
|
||||
import { StyleSheet } from "react-native";
|
||||
import { List, Divider as PaperDivider } from "react-native-paper";
|
||||
|
||||
const ListSection = ({ children }) => (
|
||||
<List.Section style={styles.listSection}>{children}</List.Section>
|
||||
);
|
||||
|
||||
const ListSubHeader = ({ children, theme }) => (
|
||||
<List.Subheader
|
||||
style={[styles.listSubHeader, { color: theme.colorAccentDark }]}
|
||||
>
|
||||
{children}
|
||||
</List.Subheader>
|
||||
);
|
||||
|
||||
const ListItem = ({ title, description, icon, onPress, theme }) => (
|
||||
<List.Item
|
||||
title={title}
|
||||
titleStyle={{ color: theme.textColorPrimary }}
|
||||
description={description}
|
||||
descriptionStyle={{ color: theme.textColorSecondary }}
|
||||
descriptionNumberOfLines={1}
|
||||
left={() =>
|
||||
icon && (
|
||||
<List.Icon
|
||||
color={theme.colorAccentDark}
|
||||
icon={icon}
|
||||
style={{ marginVertical: 0 }}
|
||||
/>
|
||||
)
|
||||
}
|
||||
onPress={onPress}
|
||||
rippleColor={theme.rippleColor}
|
||||
/>
|
||||
);
|
||||
|
||||
const Divider = ({ theme }) => (
|
||||
<PaperDivider
|
||||
style={{
|
||||
backgroundColor: theme.dividerColor,
|
||||
height: 1,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
export { ListSection, ListSubHeader, ListItem, Divider };
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
listSection: {
|
||||
flex: 1,
|
||||
marginVertical: 0,
|
||||
},
|
||||
listSubHeader: {
|
||||
paddingBottom: 5,
|
||||
},
|
||||
});
|
||||
@@ -1,41 +0,0 @@
|
||||
import React from "react";
|
||||
import { Checkbox } from "react-native-paper";
|
||||
import { useSelector } from "react-redux";
|
||||
|
||||
export const DisplayCheckbox = ({ displayMode, onPress, value }) => {
|
||||
const theme = useSelector((state) => state.themeReducer.theme);
|
||||
|
||||
const label = {
|
||||
0: "Compact Grid",
|
||||
1: "Comfortable Grid",
|
||||
2: "List",
|
||||
};
|
||||
|
||||
return (
|
||||
<Checkbox.Item
|
||||
label={label[value]}
|
||||
labelStyle={{ color: theme.textColorPrimary }}
|
||||
status={displayMode === value ? "checked" : "unchecked"}
|
||||
mode="ios"
|
||||
uncheckedColor={theme.textColorSecondary}
|
||||
color={theme.colorAccentDark}
|
||||
onPress={onPress}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const ThemeCheckbox = ({ onPress, label, checked }) => {
|
||||
const theme = useSelector((state) => state.themeReducer.theme);
|
||||
|
||||
return (
|
||||
<Checkbox.Item
|
||||
label={label}
|
||||
labelStyle={{ color: theme.textColorPrimary }}
|
||||
status={checked ? "checked" : "unchecked"}
|
||||
mode="ios"
|
||||
uncheckedColor={theme.textColorSecondary}
|
||||
color={theme.colorAccentDark}
|
||||
onPress={onPress}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -21,11 +21,7 @@ import Settings from "../screens/More/Settings";
|
||||
import NovelItem from "../screens/Novel/Novel";
|
||||
import ChapterItem from "../screens/Chapter/Chapter";
|
||||
|
||||
// Extensions
|
||||
import BoxNovel from "../screens/extensions/boxnovel/BoxNovel";
|
||||
import ReadLightNovel from "../screens/extensions/readlightnovel/ReadLightNovel";
|
||||
import FastNovel from "../screens/extensions/fastnovel/FastNovel";
|
||||
import ReadNovelFull from "../screens/extensions/readnovelfull/ReadNovelFull";
|
||||
import Extension from "../screens/Extension/Extension";
|
||||
|
||||
const Stack = createStackNavigator();
|
||||
|
||||
@@ -45,17 +41,6 @@ const SettingsStack = () => {
|
||||
);
|
||||
};
|
||||
|
||||
const ExtensionStack = () => {
|
||||
return (
|
||||
<Stack.Navigator screenOptions={stackNavigatorConfig}>
|
||||
<Stack.Screen name="BoxNovel" component={BoxNovel} />
|
||||
<Stack.Screen name="ReadLightNovel" component={ReadLightNovel} />
|
||||
<Stack.Screen name="FastNovel" component={FastNovel} />
|
||||
<Stack.Screen name="ReadNovelFull" component={ReadNovelFull} />
|
||||
</Stack.Navigator>
|
||||
);
|
||||
};
|
||||
|
||||
import { useSelector } from "react-redux";
|
||||
|
||||
const BottomNavigator = () => {
|
||||
@@ -138,9 +123,9 @@ const BottomNavigator = () => {
|
||||
};
|
||||
|
||||
const Router = () => {
|
||||
const themeCode = useSelector((state) => state.themeReducer.themeCode);
|
||||
const theme = useSelector((state) => state.themeReducer.theme);
|
||||
|
||||
useEffect(() => setStatusBarStyle(themeCode === 1 ? "dark" : "light"), []);
|
||||
useEffect(() => setStatusBarStyle(theme.id === 1 ? "dark" : "light"), []);
|
||||
|
||||
return (
|
||||
<Provider>
|
||||
@@ -162,10 +147,11 @@ const Router = () => {
|
||||
}}
|
||||
/>
|
||||
<Stack.Screen name="SettingsStack" component={SettingsStack} />
|
||||
<Stack.Screen
|
||||
<Stack.Screen name="Extension" component={Extension} />
|
||||
{/* <Stack.Screen
|
||||
name="ExtensionStack"
|
||||
component={ExtensionStack}
|
||||
/>
|
||||
/> */}
|
||||
</Stack.Navigator>
|
||||
</Provider>
|
||||
);
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
UPDATE_READER_THEME,
|
||||
UPDATE_READER_TEXT_ALIGN,
|
||||
UPDATE_READER_PADDING,
|
||||
SET_READER_FONT,
|
||||
} from "./settings.types";
|
||||
|
||||
export const setDisplayMode = (val) => (dispatch) => {
|
||||
@@ -48,3 +49,10 @@ export const updateReaderPadding = (val) => (dispatch) => {
|
||||
payload: val,
|
||||
});
|
||||
};
|
||||
|
||||
export const setReaderFont = (val) => (dispatch) => {
|
||||
dispatch({
|
||||
type: SET_READER_FONT,
|
||||
payload: val,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import {
|
||||
SET_DISPLAY_MODE,
|
||||
SET_ITEMS_PER_ROW,
|
||||
SET_READER_FONT,
|
||||
UPDATE_READER_PADDING,
|
||||
UPDATE_READER_TEXT_ALIGN,
|
||||
UPDATE_READER_TEXT_SIZE,
|
||||
@@ -14,7 +15,8 @@ const initialState = {
|
||||
theme: 1,
|
||||
textSize: 16,
|
||||
textAlign: "left",
|
||||
padding: "5",
|
||||
padding: 5,
|
||||
fontFamily: null,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -62,6 +64,11 @@ const settingsReducer = (state = initialState, action) => {
|
||||
...state,
|
||||
reader: { ...state.reader, padding: payload },
|
||||
};
|
||||
case SET_READER_FONT:
|
||||
return {
|
||||
...state,
|
||||
reader: { ...state.reader, fontFamily: payload },
|
||||
};
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
||||
@@ -4,3 +4,4 @@ export const UPDATE_READER_THEME = "UPDATE_READER_THEME";
|
||||
export const UPDATE_READER_TEXT_SIZE = "UPDATE_READER_TEXT_SIZE";
|
||||
export const UPDATE_READER_TEXT_ALIGN = "UPDATE_READER_TEXT_ALIGN";
|
||||
export const UPDATE_READER_PADDING = "UPDATE_READER_PADDING";
|
||||
export const SET_READER_FONT = "SET_READER_FONT";
|
||||
|
||||
@@ -1,12 +1,5 @@
|
||||
import { SWITCH_THEME } from "./theme.types";
|
||||
|
||||
/**
|
||||
* 0 -> Amoled Dark Theme
|
||||
* 1 -> Light Theme
|
||||
* 2 -> Dark Theme
|
||||
* 3 -> Midnight Dusk Theme
|
||||
*/
|
||||
|
||||
export const switchTheme = (val) => (dispatch) => {
|
||||
dispatch({
|
||||
type: SWITCH_THEME,
|
||||
|
||||
@@ -13,7 +13,6 @@ const themes = {
|
||||
};
|
||||
|
||||
const initialState = {
|
||||
themeCode: 0,
|
||||
theme: themes[0],
|
||||
};
|
||||
|
||||
@@ -22,7 +21,7 @@ const themeReducer = (state = initialState, action) => {
|
||||
|
||||
switch (type) {
|
||||
case "SWITCH_THEME":
|
||||
return { ...state, themeCode: payload, theme: themes[payload] };
|
||||
return { ...state, theme: themes[payload] };
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { useEffect } from "react";
|
||||
import { StyleSheet, View, FlatList, ActivityIndicator } from "react-native";
|
||||
import { Appbar } from "../../components/common/Appbar";
|
||||
import { Appbar } from "../../components/Appbar";
|
||||
import { connect } from "react-redux";
|
||||
|
||||
import { getSourcesAction } from "../../redux/source/source.actions";
|
||||
@@ -51,6 +51,5 @@ export default connect(mapStateToProps, { getSourcesAction })(Browse);
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
paddingHorizontal: 4,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -6,7 +6,7 @@ import { useNavigation } from "@react-navigation/native";
|
||||
import { useSelector } from "react-redux";
|
||||
|
||||
const ExtensionCard = ({ item }) => {
|
||||
const { sourceId, sourceName, sourceCover, sourceLanguage } = item;
|
||||
const { sourceName, sourceCover, sourceLanguage, status } = item;
|
||||
|
||||
const navigation = useNavigation();
|
||||
|
||||
@@ -16,8 +16,10 @@ const ExtensionCard = ({ item }) => {
|
||||
<TouchableRipple
|
||||
style={styles.extensionCard}
|
||||
onPress={() =>
|
||||
navigation.navigate("ExtensionStack", {
|
||||
screen: sourceName,
|
||||
navigation.navigate("Extension", {
|
||||
sourceId: item.sourceId,
|
||||
sourceName: item.sourceName,
|
||||
sourceUrl: item.sourceUrl,
|
||||
})
|
||||
}
|
||||
rippleColor={theme.rippleColor}
|
||||
@@ -25,9 +27,7 @@ const ExtensionCard = ({ item }) => {
|
||||
>
|
||||
<>
|
||||
<Image
|
||||
source={{
|
||||
uri: sourceCover,
|
||||
}}
|
||||
source={{ uri: sourceCover }}
|
||||
style={styles.extensionIcon}
|
||||
resizeMode="contain"
|
||||
/>
|
||||
@@ -57,7 +57,7 @@ const ExtensionCard = ({ item }) => {
|
||||
marginLeft: 5,
|
||||
}}
|
||||
>
|
||||
{sourceId === 3 && "(Not Working)"}
|
||||
{status === 0 && "(Not Working)"}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
@@ -69,8 +69,10 @@ const ExtensionCard = ({ item }) => {
|
||||
uppercase={false}
|
||||
color={theme.colorAccentDark}
|
||||
onPress={() =>
|
||||
navigation.navigate("ExtensionStack", {
|
||||
screen: sourceName,
|
||||
navigation.navigate("Extension", {
|
||||
sourceId: item.sourceId,
|
||||
sourceName: item.sourceName,
|
||||
sourceUrl: item.sourceUrl,
|
||||
})
|
||||
}
|
||||
>
|
||||
@@ -92,7 +94,6 @@ const styles = StyleSheet.create({
|
||||
marginVertical: 4,
|
||||
paddingVertical: 8,
|
||||
paddingHorizontal: 20,
|
||||
borderRadius: 4,
|
||||
},
|
||||
extensionIcon: {
|
||||
width: 40,
|
||||
|
||||
@@ -59,7 +59,9 @@ const ChapterItem = ({
|
||||
const readerLineHeight = (val) => {
|
||||
const lineHeight = {
|
||||
12: 20,
|
||||
14: 22,
|
||||
16: 25,
|
||||
18: 26,
|
||||
20: 28,
|
||||
};
|
||||
return lineHeight[val];
|
||||
@@ -173,6 +175,9 @@ const ChapterItem = ({
|
||||
textAlign: reader.textAlign,
|
||||
paddingHorizontal: `${reader.padding}%`,
|
||||
},
|
||||
reader.fontFamily && {
|
||||
fontFamily: reader.fontFamily,
|
||||
},
|
||||
]}
|
||||
>
|
||||
{chapter.chapterText.trim()}
|
||||
|
||||
@@ -1,19 +1,20 @@
|
||||
import React from "react";
|
||||
|
||||
import { Animated, StyleSheet, View, Text, Dimensions } from "react-native";
|
||||
import { ToggleButton, IconButton } from "react-native-paper";
|
||||
import { ToggleButton, IconButton, Chip } from "react-native-paper";
|
||||
import Slider from "@react-native-community/slider";
|
||||
import Bottomsheet from "rn-sliding-up-panel";
|
||||
import { fonts } from "../../../utils/constants";
|
||||
|
||||
import { connect } from "react-redux";
|
||||
|
||||
import {
|
||||
setReaderFont,
|
||||
updateReaderPadding,
|
||||
updateReaderTextAlign,
|
||||
updateReaderTextSize,
|
||||
updateReaderTheme,
|
||||
} from "../../../redux/settings/settings.actions";
|
||||
import BottomSheetHandle from "../../../components/common/BottomSheetHandle";
|
||||
import BottomSheetHandle from "../../../components/BottomSheetHandle";
|
||||
|
||||
const ChapterBottomSheet = ({
|
||||
bottomSheetRef,
|
||||
@@ -23,13 +24,14 @@ const ChapterBottomSheet = ({
|
||||
updateReaderTheme,
|
||||
updateReaderTextAlign,
|
||||
updateReaderPadding,
|
||||
setReaderFont,
|
||||
}) => {
|
||||
return (
|
||||
<Bottomsheet
|
||||
animatedValue={new Animated.Value(0)}
|
||||
ref={bottomSheetRef}
|
||||
draggableRange={{ top: 360, bottom: 0 }}
|
||||
snappingPoints={[0, 360]}
|
||||
draggableRange={{ top: 400, bottom: 0 }}
|
||||
snappingPoints={[0, 400]}
|
||||
showBackdrop={false}
|
||||
>
|
||||
<View style={styles.contentContainer}>
|
||||
@@ -37,7 +39,7 @@ const ChapterBottomSheet = ({
|
||||
<View style={styles.readerSettingsContainer}>
|
||||
<Text
|
||||
style={{
|
||||
color: theme.textColorPrimary,
|
||||
color: "#FFFFFF",
|
||||
fontWeight: "bold",
|
||||
}}
|
||||
>
|
||||
@@ -57,94 +59,116 @@ const ChapterBottomSheet = ({
|
||||
thumbTintColor={theme.colorAccentDark}
|
||||
onValueChange={(value) => updateReaderTextSize(value)}
|
||||
/>
|
||||
<Text
|
||||
<View
|
||||
style={{
|
||||
color: theme.textColorPrimary,
|
||||
fontWeight: "bold",
|
||||
flexDirection: "row",
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
Reader Theme
|
||||
</Text>
|
||||
<ToggleButton.Row
|
||||
onValueChange={(value) => updateReaderTheme(value)}
|
||||
value={reader.theme}
|
||||
style={{ marginTop: 10 }}
|
||||
>
|
||||
<ToggleButton
|
||||
icon="format-text"
|
||||
color="#FFFFFF"
|
||||
value={1}
|
||||
<View
|
||||
style={{
|
||||
backgroundColor: "#000000",
|
||||
marginHorizontal: 10,
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
}}
|
||||
/>
|
||||
<ToggleButton
|
||||
icon="format-text"
|
||||
color="#000000"
|
||||
value={2}
|
||||
>
|
||||
<Text
|
||||
style={{
|
||||
color: "#FFFFFF",
|
||||
fontWeight: "bold",
|
||||
}}
|
||||
>
|
||||
Reader Theme
|
||||
</Text>
|
||||
<ToggleButton.Row
|
||||
onValueChange={(value) =>
|
||||
updateReaderTheme(value)
|
||||
}
|
||||
value={reader.theme}
|
||||
style={{ marginTop: 10 }}
|
||||
>
|
||||
<ToggleButton
|
||||
icon="format-text"
|
||||
color="#FFFFFF"
|
||||
value={1}
|
||||
style={{
|
||||
backgroundColor: "#000000",
|
||||
marginHorizontal: 10,
|
||||
}}
|
||||
/>
|
||||
<ToggleButton
|
||||
icon="format-text"
|
||||
color="#000000"
|
||||
value={2}
|
||||
style={{
|
||||
backgroundColor: "#FFFFFF",
|
||||
marginHorizontal: 10,
|
||||
}}
|
||||
/>
|
||||
<ToggleButton
|
||||
icon="format-text"
|
||||
color="#000000"
|
||||
value={3}
|
||||
style={{
|
||||
backgroundColor: "#F4ECD8",
|
||||
marginHorizontal: 10,
|
||||
}}
|
||||
/>
|
||||
</ToggleButton.Row>
|
||||
</View>
|
||||
<View
|
||||
style={{
|
||||
backgroundColor: "#FFFFFF",
|
||||
marginHorizontal: 10,
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
}}
|
||||
/>
|
||||
<ToggleButton
|
||||
icon="format-text"
|
||||
color="#000000"
|
||||
value={3}
|
||||
style={{
|
||||
backgroundColor: "#F4ECD8",
|
||||
marginHorizontal: 10,
|
||||
}}
|
||||
/>
|
||||
</ToggleButton.Row>
|
||||
>
|
||||
<Text
|
||||
style={{
|
||||
color: "#FFFFFF",
|
||||
fontWeight: "bold",
|
||||
}}
|
||||
>
|
||||
Text Align
|
||||
</Text>
|
||||
<ToggleButton.Row
|
||||
onValueChange={(value) =>
|
||||
updateReaderTextAlign(value ?? "left")
|
||||
}
|
||||
value={reader.textAlign}
|
||||
style={{ marginTop: 10 }}
|
||||
>
|
||||
<ToggleButton
|
||||
icon="format-align-left"
|
||||
color="#000000"
|
||||
value="left"
|
||||
style={{
|
||||
backgroundColor: "#FFFFFF",
|
||||
marginHorizontal: 10,
|
||||
}}
|
||||
/>
|
||||
<ToggleButton
|
||||
icon="format-align-justify"
|
||||
color="#000000"
|
||||
value="justify"
|
||||
style={{
|
||||
backgroundColor: "#FFFFFF",
|
||||
marginHorizontal: 10,
|
||||
}}
|
||||
/>
|
||||
<ToggleButton
|
||||
icon="format-align-right"
|
||||
color="#000000"
|
||||
value="right"
|
||||
style={{
|
||||
backgroundColor: "#FFFFFF",
|
||||
marginHorizontal: 10,
|
||||
}}
|
||||
/>
|
||||
</ToggleButton.Row>
|
||||
</View>
|
||||
</View>
|
||||
<Text
|
||||
style={{
|
||||
color: theme.textColorPrimary,
|
||||
fontWeight: "bold",
|
||||
marginTop: 10,
|
||||
}}
|
||||
>
|
||||
Text Align
|
||||
</Text>
|
||||
<ToggleButton.Row
|
||||
onValueChange={(value) =>
|
||||
updateReaderTextAlign(value ?? "left")
|
||||
}
|
||||
value={reader.textAlign}
|
||||
style={{ marginTop: 10 }}
|
||||
>
|
||||
<ToggleButton
|
||||
icon="format-align-left"
|
||||
color="#000000"
|
||||
value="left"
|
||||
style={{
|
||||
backgroundColor: "#FFFFFF",
|
||||
marginHorizontal: 10,
|
||||
}}
|
||||
/>
|
||||
<ToggleButton
|
||||
icon="format-align-justify"
|
||||
color="#000000"
|
||||
value="justify"
|
||||
style={{
|
||||
backgroundColor: "#FFFFFF",
|
||||
marginHorizontal: 10,
|
||||
}}
|
||||
/>
|
||||
<ToggleButton
|
||||
icon="format-align-right"
|
||||
color="#000000"
|
||||
value="right"
|
||||
style={{
|
||||
backgroundColor: "#FFFFFF",
|
||||
marginHorizontal: 10,
|
||||
}}
|
||||
/>
|
||||
</ToggleButton.Row>
|
||||
<Text
|
||||
style={{
|
||||
color: theme.textColorPrimary,
|
||||
color: "#FFFFFF",
|
||||
fontWeight: "bold",
|
||||
marginTop: 10,
|
||||
}}
|
||||
@@ -170,7 +194,7 @@ const ChapterBottomSheet = ({
|
||||
/>
|
||||
<Text
|
||||
style={{
|
||||
color: theme.textColorPrimary,
|
||||
color: "#FFFFFF",
|
||||
paddingHorizontal: 50,
|
||||
}}
|
||||
>
|
||||
@@ -186,6 +210,42 @@ const ChapterBottomSheet = ({
|
||||
}
|
||||
/>
|
||||
</View>
|
||||
<Text
|
||||
style={{
|
||||
color: "#FFFFFF",
|
||||
fontWeight: "bold",
|
||||
marginTop: 10,
|
||||
}}
|
||||
>
|
||||
Font Style
|
||||
</Text>
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
flexWrap: "wrap",
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
{fonts.map((font, index) => (
|
||||
<Chip
|
||||
key={index}
|
||||
onPress={() => setReaderFont(font.fontFamily)}
|
||||
textStyle={{ fontFamily: font.fontFamily }}
|
||||
style={{
|
||||
borderWidth: 0,
|
||||
marginHorizontal: 5,
|
||||
marginVertical: 5,
|
||||
}}
|
||||
selected={
|
||||
reader.fontFamily === font.fontFamily
|
||||
? true
|
||||
: false
|
||||
}
|
||||
>
|
||||
{font.name}
|
||||
</Chip>
|
||||
))}
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</Bottomsheet>
|
||||
@@ -202,6 +262,7 @@ export default connect(mapStateToProps, {
|
||||
updateReaderTheme,
|
||||
updateReaderTextAlign,
|
||||
updateReaderPadding,
|
||||
setReaderFont,
|
||||
})(ChapterBottomSheet);
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
|
||||
+28
-12
@@ -1,14 +1,17 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { StyleSheet, View, FlatList, ActivityIndicator } from "react-native";
|
||||
import { Provider } from "react-native-paper";
|
||||
import * as WebBrowser from "expo-web-browser";
|
||||
|
||||
import NovelCover from "../../../components/common/NovelCover";
|
||||
import EmptyView from "../../../components/common/EmptyView";
|
||||
import { SearchAppbar } from "../../../components/common/Appbar";
|
||||
import NovelCover from "../../components/NovelCover";
|
||||
import EmptyView from "../../components/EmptyView";
|
||||
import { SearchAppbar } from "../../components/Appbar";
|
||||
|
||||
import { useSelector } from "react-redux";
|
||||
|
||||
const ReadLightNovel = ({ navigation }) => {
|
||||
const Extension = ({ navigation, route }) => {
|
||||
const { sourceId, sourceName, sourceUrl } = route.params;
|
||||
|
||||
const theme = useSelector((state) => state.themeReducer.theme);
|
||||
const library = useSelector((state) => state.libraryReducer.novels);
|
||||
const itemsPerRow = useSelector(
|
||||
@@ -16,13 +19,28 @@ const ReadLightNovel = ({ navigation }) => {
|
||||
);
|
||||
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
const [novels, setNovels] = useState();
|
||||
|
||||
const [searchText, setSearchText] = useState("");
|
||||
|
||||
const getSourceUrl = () => {
|
||||
if (sourceId === 1) {
|
||||
return `https://lnreader-extensions.herokuapp.com/api/1/novels/1/?o=rating`;
|
||||
} else {
|
||||
return `https://lnreader-extensions.herokuapp.com/api/${sourceId}/novels/`;
|
||||
}
|
||||
};
|
||||
|
||||
const getSearchUrl = () => {
|
||||
if (sourceId === 1) {
|
||||
return `https://lnreader-extensions.herokuapp.com/api/1/search/?s=${searchText}&?o=rating`;
|
||||
} else {
|
||||
return `https://lnreader-extensions.herokuapp.com/api/${sourceId}/search/?s=${searchText}`;
|
||||
}
|
||||
};
|
||||
|
||||
const getNovels = () => {
|
||||
fetch(`https://lnreader-extensions.herokuapp.com/api/2/novels/`)
|
||||
fetch(getSourceUrl())
|
||||
.then((response) => response.json())
|
||||
.then((json) => {
|
||||
setNovels(json);
|
||||
@@ -32,9 +50,7 @@ const ReadLightNovel = ({ navigation }) => {
|
||||
|
||||
const getSearchResults = (searchText) => {
|
||||
setLoading(true);
|
||||
fetch(
|
||||
`https://lnreader-extensions.herokuapp.com/api/2/search/?s=${searchText}`
|
||||
)
|
||||
fetch(getSearchUrl())
|
||||
.then((response) => response.json())
|
||||
.then((json) => {
|
||||
setNovels(json);
|
||||
@@ -60,12 +76,13 @@ const ReadLightNovel = ({ navigation }) => {
|
||||
>
|
||||
<SearchAppbar
|
||||
screen="Extension"
|
||||
placeholder="Search ReadLightNovel"
|
||||
placeholder={`Search ${sourceName}`}
|
||||
searchText={searchText}
|
||||
setSearchText={setSearchText}
|
||||
getSearchResults={getSearchResults}
|
||||
getNovels={getNovels}
|
||||
setLoading={setLoading}
|
||||
openWebView={() => WebBrowser.openBrowserAsync(sourceUrl)}
|
||||
/>
|
||||
|
||||
{loading ? (
|
||||
@@ -98,7 +115,6 @@ const ReadLightNovel = ({ navigation }) => {
|
||||
/>
|
||||
)}
|
||||
ListEmptyComponent={
|
||||
searchText !== "" &&
|
||||
novels.length === 0 && (
|
||||
<EmptyView
|
||||
icon="(; ̄Д ̄)"
|
||||
@@ -113,7 +129,7 @@ const ReadLightNovel = ({ navigation }) => {
|
||||
);
|
||||
};
|
||||
|
||||
export default ReadLightNovel;
|
||||
export default Extension;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
@@ -3,11 +3,11 @@ import { useFocusEffect } from "@react-navigation/native";
|
||||
|
||||
import { StyleSheet, View, FlatList, ActivityIndicator } from "react-native";
|
||||
|
||||
import { Appbar } from "../../components/common/Appbar";
|
||||
import { Appbar } from "../../components/Appbar";
|
||||
import HistoryCard from "./components/HistoryCard";
|
||||
|
||||
import { connect } from "react-redux";
|
||||
import EmptyView from "../../components/common/EmptyView";
|
||||
import EmptyView from "../../components/EmptyView";
|
||||
|
||||
import {
|
||||
getHistoryAction,
|
||||
|
||||
@@ -75,11 +75,11 @@ const HistoryCard = ({ item, deleteHistoryAction, navigation }) => {
|
||||
style={{ marginRight: 10 }}
|
||||
onPress={() =>
|
||||
navigation.navigate("ChapterItem", {
|
||||
chapterId: item.historyChapterId,
|
||||
chapterUrl: item.chapterUrl,
|
||||
extensionId: item.extensionId,
|
||||
extensionId: item.sourceId,
|
||||
novelUrl: item.novelUrl,
|
||||
novelName: item.novelName,
|
||||
novelCover: item.novelCover,
|
||||
novelId: item.novelId,
|
||||
chapterName: item.chapterName,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -11,14 +11,14 @@ import { FlatList } from "react-native-gesture-handler";
|
||||
import { useFocusEffect } from "@react-navigation/native";
|
||||
import { connect } from "react-redux";
|
||||
|
||||
import NovelCover from "../../components/common/NovelCover";
|
||||
import EmptyView from "../../components/common/EmptyView";
|
||||
import NovelCover from "../../components/NovelCover";
|
||||
import EmptyView from "../../components/EmptyView";
|
||||
|
||||
import {
|
||||
getLibraryAction,
|
||||
searchLibraryAction,
|
||||
} from "../../redux/library/library.actions";
|
||||
import { SearchAppbar } from "../../components/common/Appbar";
|
||||
import { SearchAppbar } from "../../components/Appbar";
|
||||
import { setNovel } from "../../redux/novel/novel.actions";
|
||||
import { updateAllNovels } from "../../services/updates";
|
||||
|
||||
|
||||
+55
-61
@@ -1,10 +1,11 @@
|
||||
import React from "react";
|
||||
import { View } from "react-native";
|
||||
import * as Linking from "expo-linking";
|
||||
import { List, Divider } from "react-native-paper";
|
||||
|
||||
import { Appbar } from "../../components/common/Appbar";
|
||||
import { Appbar } from "../../components/Appbar";
|
||||
|
||||
import { useSelector } from "react-redux";
|
||||
import { Divider, ListItem, ListSection } from "../../components/List";
|
||||
|
||||
const AboutScreen = ({ navigation }) => {
|
||||
const theme = useSelector((state) => state.themeReducer.theme);
|
||||
@@ -12,65 +13,58 @@ const AboutScreen = ({ navigation }) => {
|
||||
return (
|
||||
<>
|
||||
<Appbar title="About" onBackAction={() => navigation.goBack()} />
|
||||
<List.Section
|
||||
style={{
|
||||
flex: 1,
|
||||
marginTop: 0,
|
||||
backgroundColor: theme.colorPrimaryDark,
|
||||
marginBottom: 0,
|
||||
}}
|
||||
>
|
||||
<List.Item
|
||||
titleStyle={{ color: theme.textColorPrimary }}
|
||||
title="Version"
|
||||
descriptionStyle={{ color: theme.textColorSecondary }}
|
||||
description="Stable 1.0.12"
|
||||
/>
|
||||
<List.Item
|
||||
titleStyle={{ color: theme.textColorPrimary }}
|
||||
title="Build Time"
|
||||
descriptionStyle={{ color: theme.textColorSecondary }}
|
||||
description="08-04-21 08:00 AM"
|
||||
/>
|
||||
|
||||
<List.Item
|
||||
titleStyle={{ color: theme.textColorPrimary }}
|
||||
title="What's new"
|
||||
onPress={() =>
|
||||
Linking.openURL(
|
||||
"https://github.com/rajarsheechatterjee/lnreader/commits/main"
|
||||
)
|
||||
}
|
||||
rippleColor={theme.rippleColor}
|
||||
/>
|
||||
<Divider />
|
||||
|
||||
<List.Item
|
||||
titleStyle={{ color: theme.textColorPrimary }}
|
||||
descriptionStyle={{ color: theme.textColorSecondary }}
|
||||
title="Github"
|
||||
description="https://github.com/rajarsheechatterjee/lnreader"
|
||||
onPress={() =>
|
||||
Linking.openURL(
|
||||
"https://github.com/rajarsheechatterjee/lnreader"
|
||||
)
|
||||
}
|
||||
rippleColor={theme.rippleColor}
|
||||
/>
|
||||
<List.Item
|
||||
titleStyle={{ color: theme.textColorPrimary }}
|
||||
descriptionStyle={{ color: theme.textColorSecondary }}
|
||||
title="Extensions"
|
||||
description="https://github.com/rajarsheechatterjee/lnreader-extensions"
|
||||
descriptionNumberOfLines={1}
|
||||
onPress={() =>
|
||||
Linking.openURL(
|
||||
"https://github.com/rajarsheechatterjee/lnreader-extensions"
|
||||
)
|
||||
}
|
||||
rippleColor={theme.rippleColor}
|
||||
/>
|
||||
</List.Section>
|
||||
<View style={{ flex: 1, backgroundColor: theme.colorPrimaryDark }}>
|
||||
<ListSection>
|
||||
<ListItem
|
||||
title="Version"
|
||||
description="Stable 1.0.13"
|
||||
theme={theme}
|
||||
/>
|
||||
<ListItem
|
||||
title="Build Time"
|
||||
description="24-04-21 21:00 PM"
|
||||
theme={theme}
|
||||
/>
|
||||
<ListItem
|
||||
title="What's new"
|
||||
onPress={() =>
|
||||
Linking.openURL(
|
||||
"https://github.com/rajarsheechatterjee/lnreader/commits/main"
|
||||
)
|
||||
}
|
||||
theme={theme}
|
||||
/>
|
||||
<Divider theme={theme} />
|
||||
<ListItem
|
||||
title="Discord"
|
||||
description="https://discord.gg/QdcWN4MD63"
|
||||
onPress={() =>
|
||||
Linking.openURL("https://discord.gg/QdcWN4MD63")
|
||||
}
|
||||
theme={theme}
|
||||
/>
|
||||
<ListItem
|
||||
title="Github"
|
||||
description="https://github.com/rajarsheechatterjee/lnreader"
|
||||
onPress={() =>
|
||||
Linking.openURL(
|
||||
"https://github.com/rajarsheechatterjee/lnreader"
|
||||
)
|
||||
}
|
||||
theme={theme}
|
||||
/>
|
||||
<ListItem
|
||||
title="Extensions"
|
||||
description="https://github.com/rajarsheechatterjee/lnreader-extensions"
|
||||
onPress={() =>
|
||||
Linking.openURL(
|
||||
"https://github.com/rajarsheechatterjee/lnreader-extensions"
|
||||
)
|
||||
}
|
||||
theme={theme}
|
||||
/>
|
||||
</ListSection>
|
||||
</View>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
+48
-45
@@ -1,57 +1,60 @@
|
||||
import React from "react";
|
||||
|
||||
import { StyleSheet } from "react-native";
|
||||
import { List } from "react-native-paper";
|
||||
|
||||
import { Appbar } from "../../components/common/Appbar";
|
||||
|
||||
import { StyleSheet, View, Image } from "react-native";
|
||||
import { useSelector } from "react-redux";
|
||||
|
||||
import { Appbar } from "../../components/Appbar";
|
||||
import { ListItem, ListSection } from "../../components/List";
|
||||
|
||||
const MoreScreen = ({ navigation }) => {
|
||||
const theme = useSelector((state) => state.themeReducer.theme);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Appbar title="More" />
|
||||
<List.Section
|
||||
style={{
|
||||
flex: 1,
|
||||
backgroundColor: theme.colorPrimaryDark,
|
||||
marginTop: 0,
|
||||
marginBottom: 0,
|
||||
}}
|
||||
>
|
||||
<List.Item
|
||||
titleStyle={{ color: theme.textColorPrimary }}
|
||||
title="Settings"
|
||||
left={() => (
|
||||
<List.Icon
|
||||
color={theme.colorAccentDark}
|
||||
icon="cog-outline"
|
||||
<Appbar title="More" style={{ elevation: 0 }} />
|
||||
<View style={{ flex: 1, backgroundColor: theme.colorPrimaryDark }}>
|
||||
<View style={{ overflow: "hidden", paddingBottom: 4 }}>
|
||||
<View
|
||||
style={{
|
||||
paddingTop: 20,
|
||||
paddingBottom: 30,
|
||||
alignItems: "center",
|
||||
backgroundColor: theme.colorPrimary,
|
||||
elevation: 4,
|
||||
}}
|
||||
>
|
||||
<Image
|
||||
source={require("../../../assets/logo.png")}
|
||||
style={{
|
||||
height: 60,
|
||||
width: 60,
|
||||
tintColor: theme.textColorPrimary,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
onPress={() =>
|
||||
navigation.navigate("SettingsStack", {
|
||||
screen: "Settings",
|
||||
})
|
||||
}
|
||||
/>
|
||||
<List.Item
|
||||
titleStyle={{ color: theme.textColorPrimary }}
|
||||
title="About"
|
||||
left={() => (
|
||||
<List.Icon
|
||||
color={theme.colorAccentDark}
|
||||
icon="information-outline"
|
||||
/>
|
||||
)}
|
||||
onPress={() =>
|
||||
navigation.navigate("SettingsStack", {
|
||||
screen: "About",
|
||||
})
|
||||
}
|
||||
/>
|
||||
</List.Section>
|
||||
</View>
|
||||
</View>
|
||||
<ListSection>
|
||||
<ListItem
|
||||
title="Settings"
|
||||
icon="cog-outline"
|
||||
onPress={() =>
|
||||
navigation.navigate("SettingsStack", {
|
||||
screen: "Settings",
|
||||
})
|
||||
}
|
||||
theme={theme}
|
||||
/>
|
||||
<ListItem
|
||||
title="About"
|
||||
icon="information-outline"
|
||||
onPress={() =>
|
||||
navigation.navigate("SettingsStack", {
|
||||
screen: "About",
|
||||
})
|
||||
}
|
||||
theme={theme}
|
||||
/>
|
||||
</ListSection>
|
||||
</View>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
+75
-238
@@ -1,26 +1,25 @@
|
||||
import React, { useState } from "react";
|
||||
import { View, Text, Dimensions } from "react-native";
|
||||
import { setStatusBarStyle } from "expo-status-bar";
|
||||
import { List, Modal, Portal } from "react-native-paper";
|
||||
import Slider from "@react-native-community/slider";
|
||||
import InputSpinner from "react-native-input-spinner";
|
||||
|
||||
import { View } from "react-native";
|
||||
import { connect } from "react-redux";
|
||||
|
||||
import { switchTheme } from "../../redux/theme/theme.actions";
|
||||
import {
|
||||
setDisplayMode,
|
||||
setItemsPerRow,
|
||||
} from "../../redux/settings/settings.actions";
|
||||
|
||||
import { Appbar } from "../../components/common/Appbar";
|
||||
import {
|
||||
DisplayCheckbox,
|
||||
ThemeCheckbox,
|
||||
} from "../../components/settings/Checkbox";
|
||||
|
||||
import { deleteAllHistory } from "../../database/queries/HistoryQueries";
|
||||
import { deleteNovelCache } from "../../database/queries/NovelQueries";
|
||||
// import { deleteDb } from "../../database/DBHelper";
|
||||
|
||||
import { Appbar } from "../../components/Appbar";
|
||||
import {
|
||||
Divider,
|
||||
ListItem,
|
||||
ListSection,
|
||||
ListSubHeader,
|
||||
} from "../../components/List";
|
||||
import DisplayModeModal from "./components/DisplayModeModal";
|
||||
import GridSizeModal from "./components/GridSizeModal";
|
||||
import ThemeModal from "./components/ThemeModal";
|
||||
|
||||
const SettingsScreen = ({
|
||||
navigation,
|
||||
@@ -32,266 +31,104 @@ const SettingsScreen = ({
|
||||
setDisplayMode,
|
||||
setItemsPerRow,
|
||||
}) => {
|
||||
const display = {
|
||||
0: "Compact Grid",
|
||||
1: "Comfortable Grid",
|
||||
2: "List",
|
||||
const displayModeLabel = (displayMode) => {
|
||||
const label = {
|
||||
0: "Compact Grid",
|
||||
1: "Comfortable Grid",
|
||||
2: "List",
|
||||
};
|
||||
|
||||
return label[displayMode];
|
||||
};
|
||||
|
||||
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.textColorSecondary,
|
||||
};
|
||||
|
||||
const titleStyles = { color: theme.textColorPrimary };
|
||||
|
||||
/**
|
||||
* Display Mode Modal
|
||||
*/
|
||||
// Display Mode Modal
|
||||
const [displayModalVisible, setDisplayModalVisible] = useState(false);
|
||||
const showDisplayModal = () => setDisplayModalVisible(true);
|
||||
const hideDisplayModal = () => setDisplayModalVisible(false);
|
||||
|
||||
/**
|
||||
* Change Theme Modal
|
||||
*/
|
||||
// Theme Modal
|
||||
const [themeModalVisible, setthemeModalVisible] = useState(false);
|
||||
const showthemeModal = () => setthemeModalVisible(true);
|
||||
const hidethemeModal = () => setthemeModalVisible(false);
|
||||
|
||||
const [itemsModalVisible, setitemsModalVisible] = useState(false);
|
||||
const showitemsModal = () => setitemsModalVisible(true);
|
||||
const hideitemsModal = () => setitemsModalVisible(false);
|
||||
// Grid Size Modal
|
||||
const [gridSizeModalVisible, setGridSizeModalVisible] = useState(false);
|
||||
const showGridSizeModal = () => setGridSizeModalVisible(true);
|
||||
const hideGridSizeModal = () => setGridSizeModalVisible(false);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Appbar title="Settings" onBackAction={() => navigation.goBack()} />
|
||||
<View style={{ flex: 1, backgroundColor: theme.colorPrimaryDark }}>
|
||||
<List.Section
|
||||
style={{
|
||||
flex: 1,
|
||||
backgroundColor: theme.colorPrimaryDark,
|
||||
}}
|
||||
>
|
||||
<List.Subheader
|
||||
style={{
|
||||
color: theme.colorAccentDark,
|
||||
paddingBottom: 5,
|
||||
}}
|
||||
>
|
||||
Data
|
||||
</List.Subheader>
|
||||
<List.Item
|
||||
titleStyle={titleStyles}
|
||||
<View
|
||||
style={{
|
||||
flex: 1,
|
||||
backgroundColor: theme.colorPrimaryDark,
|
||||
paddingVertical: 8,
|
||||
}}
|
||||
>
|
||||
<ListSection>
|
||||
<ListSubHeader theme={theme}>Data</ListSubHeader>
|
||||
<ListItem
|
||||
title="Clear database"
|
||||
descriptionStyle={desciptionStyles}
|
||||
description="Delete history for novels not in your library"
|
||||
onPress={() => deleteNovelCache()}
|
||||
rippleColor={theme.rippleColor}
|
||||
theme={theme}
|
||||
/>
|
||||
<List.Item
|
||||
titleStyle={titleStyles}
|
||||
<ListItem
|
||||
title="Clear history"
|
||||
descriptionStyle={desciptionStyles}
|
||||
description="Delete reading history for all novels"
|
||||
onPress={() => deleteAllHistory()}
|
||||
rippleColor={theme.rippleColor}
|
||||
theme={theme}
|
||||
/>
|
||||
<List.Subheader
|
||||
style={{
|
||||
color: theme.colorAccentDark,
|
||||
paddingBottom: 5,
|
||||
}}
|
||||
>
|
||||
Display
|
||||
</List.Subheader>
|
||||
<List.Item
|
||||
titleStyle={titleStyles}
|
||||
<Divider theme={theme} />
|
||||
<ListSubHeader theme={theme}>Display</ListSubHeader>
|
||||
<ListItem
|
||||
title="Display Mode"
|
||||
descriptionStyle={desciptionStyles}
|
||||
description={display[displayMode]}
|
||||
description={displayModeLabel(displayMode)}
|
||||
onPress={showDisplayModal}
|
||||
rippleColor={theme.rippleColor}
|
||||
theme={theme}
|
||||
/>
|
||||
<Portal>
|
||||
<Modal
|
||||
visible={displayModalVisible}
|
||||
onDismiss={hideDisplayModal}
|
||||
contentContainerStyle={{
|
||||
backgroundColor: theme.colorPrimaryDark,
|
||||
padding: 20,
|
||||
margin: 20,
|
||||
borderRadius: 6,
|
||||
}}
|
||||
>
|
||||
<DisplayCheckbox
|
||||
value={1}
|
||||
displayMode={displayMode}
|
||||
onPress={() => setDisplayMode(1)}
|
||||
/>
|
||||
<DisplayCheckbox
|
||||
value={0}
|
||||
displayMode={displayMode}
|
||||
onPress={() => setDisplayMode(0)}
|
||||
/>
|
||||
<DisplayCheckbox
|
||||
value={2}
|
||||
displayMode={displayMode}
|
||||
onPress={() => setDisplayMode(2)}
|
||||
/>
|
||||
</Modal>
|
||||
</Portal>
|
||||
<List.Item
|
||||
titleStyle={titleStyles}
|
||||
<ListItem
|
||||
title="Items per row in library"
|
||||
descriptionStyle={desciptionStyles}
|
||||
description={itemsPerRow}
|
||||
onPress={showitemsModal}
|
||||
rippleColor={theme.rippleColor}
|
||||
description={`${itemsPerRow} items per row`}
|
||||
onPress={showGridSizeModal}
|
||||
theme={theme}
|
||||
/>
|
||||
<Portal>
|
||||
<Modal
|
||||
visible={itemsModalVisible}
|
||||
onDismiss={hideitemsModal}
|
||||
contentContainerStyle={{
|
||||
backgroundColor: theme.colorPrimaryDark,
|
||||
padding: 20,
|
||||
margin: 20,
|
||||
borderRadius: 6,
|
||||
}}
|
||||
>
|
||||
<Text
|
||||
style={{
|
||||
color: theme.textColorPrimary,
|
||||
fontSize: 18,
|
||||
marginBottom: 10,
|
||||
}}
|
||||
>
|
||||
Grid size
|
||||
</Text>
|
||||
<Text
|
||||
style={{
|
||||
color: theme.textColorSecondary,
|
||||
marginBottom: 4,
|
||||
}}
|
||||
>
|
||||
{itemsPerRow} per row
|
||||
</Text>
|
||||
{/* <InputSpinner
|
||||
style={{
|
||||
paddingHorizontal: 16,
|
||||
paddingVertical: 16,
|
||||
elevation: 0,
|
||||
}}
|
||||
max={10}
|
||||
min={1}
|
||||
skin="paper"
|
||||
background={theme.colorPrimaryDark}
|
||||
colorMax={theme.colorAccentDark}
|
||||
colorLeft={theme.colorAccentDark}
|
||||
colorRight={theme.colorAccentDark}
|
||||
buttonTextColor={theme.textColorPrimary}
|
||||
colorPress={"white"}
|
||||
colorMin={theme.colorAccentDark}
|
||||
value={itemsPerRow}
|
||||
onChange={(num) => setItemsPerRow(num)}
|
||||
inputStyle={{
|
||||
color: theme.textColorPrimary,
|
||||
}}
|
||||
/> */}
|
||||
|
||||
<Slider
|
||||
style={{
|
||||
width: "100%",
|
||||
height: 40,
|
||||
// backgroundColor: "red",
|
||||
}}
|
||||
value={itemsPerRow}
|
||||
minimumValue={1}
|
||||
maximumValue={5}
|
||||
step={1}
|
||||
minimumTrackTintColor={theme.colorAccentDark}
|
||||
maximumTrackTintColor="#000000"
|
||||
thumbTintColor={theme.colorAccentDark}
|
||||
onValueChange={(value) => setItemsPerRow(value)}
|
||||
/>
|
||||
</Modal>
|
||||
</Portal>
|
||||
|
||||
{/* <List.Subheader
|
||||
style={{
|
||||
color: theme.colorAccentDark,
|
||||
paddingBottom: 5,
|
||||
}}
|
||||
>
|
||||
Devloper options
|
||||
</List.Subheader>
|
||||
<List.Item
|
||||
titleStyle={titleStyles}
|
||||
title="Delete database"
|
||||
descriptionStyle={desciptionStyles}
|
||||
description="Delete entire database"
|
||||
rippleColor={theme.rippleColor}
|
||||
onPress={() => deleteDb()}
|
||||
/> */}
|
||||
<List.Subheader
|
||||
style={{
|
||||
color: theme.colorAccentDark,
|
||||
paddingBottom: 5,
|
||||
}}
|
||||
>
|
||||
Theme
|
||||
</List.Subheader>
|
||||
<List.Item
|
||||
titleStyle={titleStyles}
|
||||
<Divider theme={theme} />
|
||||
<ListSubHeader theme={theme}>Theme</ListSubHeader>
|
||||
<ListItem
|
||||
title="Theme"
|
||||
descriptionStyle={desciptionStyles}
|
||||
description={themes[themeCode].label}
|
||||
description={theme.name}
|
||||
onPress={showthemeModal}
|
||||
rippleColor={theme.rippleColor}
|
||||
theme={theme}
|
||||
/>
|
||||
<Portal>
|
||||
<Modal
|
||||
visible={themeModalVisible}
|
||||
onDismiss={hidethemeModal}
|
||||
contentContainerStyle={{
|
||||
backgroundColor: theme.colorPrimaryDark,
|
||||
padding: 20,
|
||||
margin: 20,
|
||||
borderRadius: 6,
|
||||
}}
|
||||
>
|
||||
{themes.map((item, index) => (
|
||||
<ThemeCheckbox
|
||||
key={index}
|
||||
label={themes[item.themeCode].label}
|
||||
checked={
|
||||
themeCode === item.themeCode
|
||||
? true
|
||||
: false
|
||||
}
|
||||
onPress={() => {
|
||||
switchTheme(item.themeCode);
|
||||
setStatusBarStyle(item.statusBar);
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</Modal>
|
||||
</Portal>
|
||||
</List.Section>
|
||||
</ListSection>
|
||||
<DisplayModeModal
|
||||
displayMode={displayMode}
|
||||
displayModalVisible={displayModalVisible}
|
||||
hideDisplayModal={hideDisplayModal}
|
||||
setDisplayMode={setDisplayMode}
|
||||
theme={theme}
|
||||
/>
|
||||
<GridSizeModal
|
||||
itemsPerRow={itemsPerRow}
|
||||
gridSizeModalVisible={gridSizeModalVisible}
|
||||
hideGridSizeModal={hideGridSizeModal}
|
||||
setItemsPerRow={setItemsPerRow}
|
||||
theme={theme}
|
||||
/>
|
||||
<ThemeModal
|
||||
themeModalVisible={themeModalVisible}
|
||||
hidethemeModal={hidethemeModal}
|
||||
switchTheme={switchTheme}
|
||||
theme={theme}
|
||||
/>
|
||||
</View>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const mapStateToProps = (state) => ({
|
||||
themeCode: state.themeReducer.themeCode,
|
||||
theme: state.themeReducer.theme,
|
||||
displayMode: state.settingsReducer.displayMode,
|
||||
itemsPerRow: state.settingsReducer.itemsPerRow,
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
import React from "react";
|
||||
import { StyleSheet } from "react-native";
|
||||
import { Portal, Modal, Checkbox } from "react-native-paper";
|
||||
|
||||
const DisplayModeModal = ({
|
||||
displayMode,
|
||||
displayModalVisible,
|
||||
setDisplayMode,
|
||||
hideDisplayModal,
|
||||
theme,
|
||||
}) => {
|
||||
const displayModes = [
|
||||
{ displayMode: 0, label: "Compact Grid" },
|
||||
{ displayMode: 1, label: "Comfortable Grid" },
|
||||
{ displayMode: 2, label: "List" },
|
||||
];
|
||||
|
||||
const renderCheckboxes = () => {
|
||||
return displayModes.map((mode) => (
|
||||
<Checkbox.Item
|
||||
key={mode.displayMode}
|
||||
label={mode.label}
|
||||
labelStyle={{ color: theme.textColorPrimary }}
|
||||
status={
|
||||
displayMode === mode.displayMode ? "checked" : "unchecked"
|
||||
}
|
||||
mode="ios"
|
||||
uncheckedColor={theme.textColorSecondary}
|
||||
color={theme.colorAccentDark}
|
||||
onPress={() => setDisplayMode(mode.displayMode)}
|
||||
/>
|
||||
));
|
||||
};
|
||||
|
||||
return (
|
||||
<Portal>
|
||||
<Modal
|
||||
visible={displayModalVisible}
|
||||
onDismiss={hideDisplayModal}
|
||||
contentContainerStyle={[
|
||||
styles.containerStyle,
|
||||
{ backgroundColor: theme.colorPrimaryDark },
|
||||
]}
|
||||
>
|
||||
{renderCheckboxes()}
|
||||
</Modal>
|
||||
</Portal>
|
||||
);
|
||||
};
|
||||
|
||||
export default DisplayModeModal;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
containerStyle: {
|
||||
padding: 20,
|
||||
margin: 20,
|
||||
borderRadius: 6,
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,74 @@
|
||||
import React from "react";
|
||||
import { Text, StyleSheet } from "react-native";
|
||||
import { Portal, Modal } from "react-native-paper";
|
||||
import Slider from "@react-native-community/slider";
|
||||
|
||||
const GridSizeModal = ({
|
||||
itemsPerRow,
|
||||
gridSizeModalVisible,
|
||||
hideGridSizeModal,
|
||||
setItemsPerRow,
|
||||
theme,
|
||||
}) => {
|
||||
return (
|
||||
<Portal>
|
||||
<Modal
|
||||
visible={gridSizeModalVisible}
|
||||
onDismiss={hideGridSizeModal}
|
||||
contentContainerStyle={[
|
||||
styles.containerStyle,
|
||||
{ backgroundColor: theme.colorPrimaryDark },
|
||||
]}
|
||||
>
|
||||
<Text
|
||||
style={[
|
||||
styles.modalHeader,
|
||||
{ color: theme.textColorPrimary },
|
||||
]}
|
||||
>
|
||||
Grid size
|
||||
</Text>
|
||||
<Text
|
||||
style={[
|
||||
styles.modalDescription,
|
||||
{ color: theme.textColorSecondary },
|
||||
]}
|
||||
>
|
||||
{`${itemsPerRow} per row`}
|
||||
</Text>
|
||||
<Slider
|
||||
style={styles.slider}
|
||||
value={itemsPerRow}
|
||||
minimumValue={1}
|
||||
maximumValue={5}
|
||||
step={1}
|
||||
minimumTrackTintColor={theme.colorAccentDark}
|
||||
maximumTrackTintColor="#000000"
|
||||
thumbTintColor={theme.colorAccentDark}
|
||||
onValueChange={(value) => setItemsPerRow(value)}
|
||||
/>
|
||||
</Modal>
|
||||
</Portal>
|
||||
);
|
||||
};
|
||||
|
||||
export default GridSizeModal;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
containerStyle: {
|
||||
padding: 20,
|
||||
margin: 20,
|
||||
borderRadius: 6,
|
||||
},
|
||||
modalHeader: {
|
||||
fontSize: 18,
|
||||
marginBottom: 10,
|
||||
},
|
||||
modalDescription: {
|
||||
marginBottom: 4,
|
||||
},
|
||||
slider: {
|
||||
width: "100%",
|
||||
height: 40,
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,60 @@
|
||||
import React from "react";
|
||||
import { StyleSheet } from "react-native";
|
||||
import { Portal, Modal, Checkbox } from "react-native-paper";
|
||||
|
||||
import { setStatusBarStyle } from "expo-status-bar";
|
||||
|
||||
const ThemeModal = ({
|
||||
themeModalVisible,
|
||||
hidethemeModal,
|
||||
switchTheme,
|
||||
theme,
|
||||
}) => {
|
||||
const themes = [
|
||||
{ id: 0, name: "AMOLED Dark", statusBar: "light" },
|
||||
{ id: 1, name: "Light", statusBar: "dark" },
|
||||
{ id: 2, name: "Dark", statusBar: "light" },
|
||||
{ id: 3, name: "Midnight Dusk", statusBar: "light" },
|
||||
];
|
||||
|
||||
const renderThemeCheckboxes = () =>
|
||||
themes.map((item) => (
|
||||
<Checkbox.Item
|
||||
key={item.id}
|
||||
label={item.name}
|
||||
labelStyle={{ color: theme.textColorPrimary }}
|
||||
status={theme.id === item.id ? "checked" : "unchecked"}
|
||||
mode="ios"
|
||||
color={theme.colorAccentDark}
|
||||
onPress={() => {
|
||||
switchTheme(item.id);
|
||||
setStatusBarStyle(item.statusBar);
|
||||
}}
|
||||
/>
|
||||
));
|
||||
|
||||
return (
|
||||
<Portal>
|
||||
<Modal
|
||||
visible={themeModalVisible}
|
||||
onDismiss={hidethemeModal}
|
||||
contentContainerStyle={[
|
||||
styles.containerStyle,
|
||||
{ backgroundColor: theme.colorPrimaryDark },
|
||||
]}
|
||||
>
|
||||
{renderThemeCheckboxes()}
|
||||
</Modal>
|
||||
</Portal>
|
||||
);
|
||||
};
|
||||
|
||||
export default ThemeModal;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
containerStyle: {
|
||||
padding: 20,
|
||||
margin: 20,
|
||||
borderRadius: 6,
|
||||
},
|
||||
});
|
||||
@@ -48,7 +48,7 @@ const ChapterCard = ({
|
||||
style={{ margin: 2 }}
|
||||
/>
|
||||
}
|
||||
contentStyle={{ backgroundColor: "#242529" }}
|
||||
contentStyle={{ backgroundColor: theme.menuColor }}
|
||||
>
|
||||
<Menu.Item
|
||||
onPress={() =>
|
||||
|
||||
@@ -155,9 +155,7 @@ const NovelInfoHeader = ({
|
||||
|
||||
<IconButton
|
||||
onPress={() =>
|
||||
WebBrowser.openBrowserAsync(
|
||||
novel.sourceUrl && novel.sourceUrl
|
||||
)
|
||||
WebBrowser.openBrowserAsync(novel.sourceUrl)
|
||||
}
|
||||
icon="earth"
|
||||
color={theme.colorAccentDark}
|
||||
@@ -165,9 +163,7 @@ const NovelInfoHeader = ({
|
||||
/>
|
||||
<IconButton
|
||||
onPress={() =>
|
||||
Share.share({
|
||||
message: novel.sourceUrl,
|
||||
})
|
||||
Share.share({ message: novel.sourceUrl })
|
||||
}
|
||||
icon="share-variant"
|
||||
color={theme.colorAccentDark}
|
||||
@@ -185,17 +181,17 @@ const NovelInfoHeader = ({
|
||||
onPress={openMenu}
|
||||
/>
|
||||
}
|
||||
contentStyle={{ backgroundColor: "#242529" }}
|
||||
contentStyle={{ backgroundColor: theme.menuColor }}
|
||||
>
|
||||
<Menu.Item
|
||||
title="Download all"
|
||||
style={{ backgroundColor: "#242529" }}
|
||||
style={{ backgroundColor: theme.menuColor }}
|
||||
titleStyle={{ color: theme.textColorPrimary }}
|
||||
onPress={downloadAllChapters}
|
||||
/>
|
||||
<Menu.Item
|
||||
title="Delete downloads"
|
||||
style={{ backgroundColor: "#242529" }}
|
||||
style={{ backgroundColor: theme.menuColor }}
|
||||
titleStyle={{ color: theme.textColorPrimary }}
|
||||
onPress={deleteAllChapters}
|
||||
/>
|
||||
|
||||
@@ -3,7 +3,7 @@ import { useFocusEffect } from "@react-navigation/native";
|
||||
import { StyleSheet, View, FlatList, ActivityIndicator } from "react-native";
|
||||
|
||||
import { connect } from "react-redux";
|
||||
import EmptyView from "../../components/common/EmptyView";
|
||||
import EmptyView from "../../components/EmptyView";
|
||||
import { getUpdatesAction } from "../../redux/updates/updates.actions";
|
||||
import { Appbar } from "./components/Appbar";
|
||||
import UpdateCard from "./components/UpdateCard";
|
||||
|
||||
@@ -1,146 +0,0 @@
|
||||
import React, { useEffect, useState, useRef } from "react";
|
||||
import { StyleSheet, View, FlatList, ActivityIndicator } from "react-native";
|
||||
import { Provider, Portal } from "react-native-paper";
|
||||
|
||||
import NovelCover from "../../../components/common/NovelCover";
|
||||
import { SearchAppbar } from "../../../components/common/Appbar";
|
||||
import { BottomSheet } from "./filters/BottomSheet";
|
||||
|
||||
import { useSelector } from "react-redux";
|
||||
|
||||
const BoxNovel = ({ navigation }) => {
|
||||
const theme = useSelector((state) => state.themeReducer.theme);
|
||||
const itemsPerRow = useSelector(
|
||||
(state) => state.settingsReducer.itemsPerRow
|
||||
);
|
||||
|
||||
const library = useSelector((state) => state.libraryReducer.novels);
|
||||
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
const [novels, setNovels] = useState([]);
|
||||
const [sort, setSort] = useState("rating");
|
||||
|
||||
const [searchText, setSearchText] = useState("");
|
||||
|
||||
let bottomSheetRef = useRef(null);
|
||||
|
||||
const getNovels = () => {
|
||||
fetch(
|
||||
`https://lnreader-extensions.herokuapp.com/api/1/novels/1/?o=${sort}`
|
||||
)
|
||||
.then((response) => response.json())
|
||||
.then((json) => {
|
||||
setNovels(json);
|
||||
setLoading(false);
|
||||
});
|
||||
};
|
||||
|
||||
const getSearchResults = (searchText) => {
|
||||
setLoading(true);
|
||||
fetch(
|
||||
`https://lnreader-extensions.herokuapp.com/api/1/search/?s=${searchText}&?o=${sort}`
|
||||
)
|
||||
.then((response) => response.json())
|
||||
.then((json) => {
|
||||
setNovels(json);
|
||||
setLoading(false);
|
||||
});
|
||||
};
|
||||
|
||||
const checkIFInLibrary = (id) => {
|
||||
return library.some((obj) => obj.novelUrl === id);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
getNovels();
|
||||
}, [sort]);
|
||||
|
||||
return (
|
||||
<Provider>
|
||||
<View
|
||||
style={[
|
||||
styles.container,
|
||||
{ backgroundColor: theme.colorPrimaryDark },
|
||||
]}
|
||||
>
|
||||
<SearchAppbar
|
||||
screen="Extension"
|
||||
placeholder="Search BoxNovel"
|
||||
searchText={searchText}
|
||||
setSearchText={setSearchText}
|
||||
getSearchResults={getSearchResults}
|
||||
getNovels={getNovels}
|
||||
setLoading={setLoading}
|
||||
onFilter={() =>
|
||||
bottomSheetRef.current.show({ velocity: -1.5 })
|
||||
}
|
||||
/>
|
||||
{loading ? (
|
||||
<View style={{ flex: 1, justifyContent: "center" }}>
|
||||
<ActivityIndicator
|
||||
size={60}
|
||||
color={theme.colorAccentDark}
|
||||
/>
|
||||
</View>
|
||||
) : (
|
||||
<FlatList
|
||||
contentContainerStyle={styles.list}
|
||||
numColumns={itemsPerRow}
|
||||
key={itemsPerRow}
|
||||
data={novels}
|
||||
showsVerticalScrollIndicator={false}
|
||||
keyExtractor={(item) => item.novelUrl}
|
||||
renderItem={({ item }) => (
|
||||
<NovelCover
|
||||
item={item}
|
||||
onPress={() => {
|
||||
navigation.navigate("NovelItem", {
|
||||
novelName: item.novelName,
|
||||
novelCover: item.novelCover,
|
||||
novelUrl: item.novelUrl,
|
||||
sourceId: item.extensionId,
|
||||
});
|
||||
}}
|
||||
libraryStatus={
|
||||
checkIFInLibrary(item.novelUrl)
|
||||
? true
|
||||
: false
|
||||
}
|
||||
/>
|
||||
)}
|
||||
ListEmptyComponent={
|
||||
novels.length === 0 && (
|
||||
<EmptyView
|
||||
icon="(; ̄Д ̄)"
|
||||
description="No results found"
|
||||
/>
|
||||
)
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
<Portal>
|
||||
<BottomSheet
|
||||
bottomSheetRef={bottomSheetRef}
|
||||
setSort={setSort}
|
||||
sort={sort}
|
||||
setLoading={setLoading}
|
||||
/>
|
||||
</Portal>
|
||||
</Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export default BoxNovel;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
padding: 4,
|
||||
},
|
||||
|
||||
contentContainer: {
|
||||
flex: 1,
|
||||
},
|
||||
});
|
||||
@@ -1,94 +0,0 @@
|
||||
import React from "react";
|
||||
import { StyleSheet, View } from "react-native";
|
||||
import { List } from "react-native-paper";
|
||||
import Bottomsheet from "rn-sliding-up-panel";
|
||||
|
||||
import { useSelector } from "react-redux";
|
||||
|
||||
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 (
|
||||
<Bottomsheet
|
||||
ref={bottomSheetRef}
|
||||
draggableRange={{ top: 370, bottom: 0 }}
|
||||
snappingPoints={[0, 370]}
|
||||
>
|
||||
<View
|
||||
style={[
|
||||
styles.contentContainer,
|
||||
{ backgroundColor: theme.colorPrimary },
|
||||
]}
|
||||
>
|
||||
<View
|
||||
style={[
|
||||
styles.bottomSheetHandle,
|
||||
{ backgroundColor: theme.textColorPrimary },
|
||||
]}
|
||||
/>
|
||||
<List.Section
|
||||
title="Sort"
|
||||
titleStyle={{
|
||||
color: theme.colorAccentDark,
|
||||
fontWeight: "bold",
|
||||
}}
|
||||
style={{ color: theme.colorAccentDark }}
|
||||
expanded
|
||||
>
|
||||
{sorting.map((item, index) => (
|
||||
<List.Item
|
||||
key={index}
|
||||
right={() =>
|
||||
sort === item.sortFlag && (
|
||||
<List.Icon
|
||||
icon="arrow-up"
|
||||
color={theme.colorAccentDark}
|
||||
style={styles.sortArrow}
|
||||
/>
|
||||
)
|
||||
}
|
||||
title={item.label}
|
||||
titleStyle={{
|
||||
fontSize: 15,
|
||||
color: theme.textColorPrimary,
|
||||
}}
|
||||
onPress={() => {
|
||||
setLoading(true);
|
||||
setSort(item.sortFlag);
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</List.Section>
|
||||
</View>
|
||||
</Bottomsheet>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
contentContainer: {
|
||||
flex: 1,
|
||||
borderTopRightRadius: 8,
|
||||
borderTopLeftRadius: 8,
|
||||
},
|
||||
bottomSheetHandle: {
|
||||
opacity: 0.5,
|
||||
height: 4,
|
||||
width: 32,
|
||||
borderRadius: 50,
|
||||
top: 8,
|
||||
alignSelf: "center",
|
||||
},
|
||||
sortArrow: {
|
||||
marginVertical: 0,
|
||||
paddingVertical: 0,
|
||||
},
|
||||
});
|
||||
@@ -1,129 +0,0 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { StyleSheet, View, FlatList, ActivityIndicator } from "react-native";
|
||||
import { Provider } from "react-native-paper";
|
||||
|
||||
import NovelCover from "../../../components/common/NovelCover";
|
||||
import { SearchAppbar } from "../../../components/common/Appbar";
|
||||
|
||||
import { useSelector } from "react-redux";
|
||||
import EmptyView from "../../../components/common/EmptyView";
|
||||
|
||||
const FastNovel = ({ navigation }) => {
|
||||
const theme = useSelector((state) => state.themeReducer.theme);
|
||||
const library = useSelector((state) => state.libraryReducer.novels);
|
||||
const itemsPerRow = useSelector(
|
||||
(state) => state.settingsReducer.itemsPerRow
|
||||
);
|
||||
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
const [novels, setNovels] = useState();
|
||||
|
||||
const [searchText, setSearchText] = useState("");
|
||||
|
||||
const getNovels = () => {
|
||||
fetch(`https://lnreader-extensions.herokuapp.com/api/3/novels/`)
|
||||
.then((response) => response.json())
|
||||
.then((json) => {
|
||||
setNovels(json);
|
||||
setLoading(false);
|
||||
});
|
||||
};
|
||||
|
||||
const getSearchResults = (searchText) => {
|
||||
setLoading(true);
|
||||
fetch(
|
||||
`https://lnreader-extensions.herokuapp.com/api/3/search/?s=${searchText}`
|
||||
)
|
||||
.then((response) => response.json())
|
||||
.then((json) => {
|
||||
setNovels(json);
|
||||
setLoading(false);
|
||||
});
|
||||
};
|
||||
|
||||
const checkIFInLibrary = (id) => {
|
||||
return library.some((obj) => obj.novelUrl === id);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
getNovels();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Provider>
|
||||
<View
|
||||
style={[
|
||||
styles.container,
|
||||
{ backgroundColor: theme.colorPrimaryDark },
|
||||
]}
|
||||
>
|
||||
<SearchAppbar
|
||||
screen="Extension"
|
||||
placeholder="Search FastNovel"
|
||||
searchText={searchText}
|
||||
setSearchText={setSearchText}
|
||||
getSearchResults={getSearchResults}
|
||||
getNovels={getNovels}
|
||||
setLoading={setLoading}
|
||||
/>
|
||||
|
||||
{loading ? (
|
||||
<View style={{ flex: 1, justifyContent: "center" }}>
|
||||
<ActivityIndicator
|
||||
size={60}
|
||||
color={theme.colorAccentDark}
|
||||
/>
|
||||
</View>
|
||||
) : (
|
||||
<FlatList
|
||||
contentContainerStyle={{ flexGrow: 1 }}
|
||||
numColumns={itemsPerRow}
|
||||
key={itemsPerRow}
|
||||
data={novels}
|
||||
showsVerticalScrollIndicator={false}
|
||||
keyExtractor={(item) => item.novelUrl}
|
||||
renderItem={({ item }) => (
|
||||
<NovelCover
|
||||
item={item}
|
||||
onPress={() =>
|
||||
navigation.navigate("NovelItem", {
|
||||
novelName: item.novelName,
|
||||
novelCover: item.novelCover,
|
||||
novelUrl: item.novelUrl,
|
||||
sourceId: item.extensionId,
|
||||
})
|
||||
}
|
||||
libraryStatus={
|
||||
checkIFInLibrary(item.novelUrl)
|
||||
? true
|
||||
: false
|
||||
}
|
||||
/>
|
||||
)}
|
||||
ListEmptyComponent={
|
||||
novels.length === 0 && (
|
||||
<EmptyView
|
||||
icon="(; ̄Д ̄)"
|
||||
description="No results found"
|
||||
/>
|
||||
)
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
</Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export default FastNovel;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
padding: 4,
|
||||
},
|
||||
contentContainer: {
|
||||
flex: 1,
|
||||
},
|
||||
});
|
||||
@@ -1,129 +0,0 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { StyleSheet, View, FlatList, ActivityIndicator } from "react-native";
|
||||
import { Provider } from "react-native-paper";
|
||||
|
||||
import NovelCover from "../../../components/common/NovelCover";
|
||||
import { SearchAppbar } from "../../../components/common/Appbar";
|
||||
|
||||
import { useSelector } from "react-redux";
|
||||
import EmptyView from "../../../components/common/EmptyView";
|
||||
|
||||
const FastNovel = ({ navigation }) => {
|
||||
const theme = useSelector((state) => state.themeReducer.theme);
|
||||
const library = useSelector((state) => state.libraryReducer.novels);
|
||||
const itemsPerRow = useSelector(
|
||||
(state) => state.settingsReducer.itemsPerRow
|
||||
);
|
||||
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
const [novels, setNovels] = useState();
|
||||
|
||||
const [searchText, setSearchText] = useState("");
|
||||
|
||||
const getNovels = () => {
|
||||
fetch(`https://lnreader-extensions.herokuapp.com/api/4/novels/`)
|
||||
.then((response) => response.json())
|
||||
.then((json) => {
|
||||
setNovels(json);
|
||||
setLoading(false);
|
||||
});
|
||||
};
|
||||
|
||||
const getSearchResults = (searchText) => {
|
||||
setLoading(true);
|
||||
fetch(
|
||||
`https://lnreader-extensions.herokuapp.com/api/4/search/?s=${searchText}`
|
||||
)
|
||||
.then((response) => response.json())
|
||||
.then((json) => {
|
||||
setNovels(json);
|
||||
setLoading(false);
|
||||
});
|
||||
};
|
||||
|
||||
const checkIFInLibrary = (id) => {
|
||||
return library.some((obj) => obj.novelUrl === id);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
getNovels();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Provider>
|
||||
<View
|
||||
style={[
|
||||
styles.container,
|
||||
{ backgroundColor: theme.colorPrimaryDark },
|
||||
]}
|
||||
>
|
||||
<SearchAppbar
|
||||
screen="Extension"
|
||||
placeholder="Search ReadNovelFull"
|
||||
searchText={searchText}
|
||||
setSearchText={setSearchText}
|
||||
getSearchResults={getSearchResults}
|
||||
getNovels={getNovels}
|
||||
setLoading={setLoading}
|
||||
/>
|
||||
|
||||
{loading ? (
|
||||
<View style={{ flex: 1, justifyContent: "center" }}>
|
||||
<ActivityIndicator
|
||||
size={60}
|
||||
color={theme.colorAccentDark}
|
||||
/>
|
||||
</View>
|
||||
) : (
|
||||
<FlatList
|
||||
contentContainerStyle={{ flexGrow: 1 }}
|
||||
numColumns={itemsPerRow}
|
||||
key={itemsPerRow}
|
||||
data={novels}
|
||||
showsVerticalScrollIndicator={false}
|
||||
keyExtractor={(item) => item.novelUrl}
|
||||
renderItem={({ item }) => (
|
||||
<NovelCover
|
||||
item={item}
|
||||
onPress={() =>
|
||||
navigation.navigate("NovelItem", {
|
||||
novelName: item.novelName,
|
||||
novelCover: item.novelCover,
|
||||
novelUrl: item.novelUrl,
|
||||
sourceId: item.extensionId,
|
||||
})
|
||||
}
|
||||
libraryStatus={
|
||||
checkIFInLibrary(item.novelUrl)
|
||||
? true
|
||||
: false
|
||||
}
|
||||
/>
|
||||
)}
|
||||
ListEmptyComponent={
|
||||
novels.length === 0 && (
|
||||
<EmptyView
|
||||
icon="(; ̄Д ̄)"
|
||||
description="No results found"
|
||||
/>
|
||||
)
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
</Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export default FastNovel;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
padding: 4,
|
||||
},
|
||||
contentContainer: {
|
||||
flex: 1,
|
||||
},
|
||||
});
|
||||
@@ -15,6 +15,8 @@ export const theme = {
|
||||
* Light Theme
|
||||
*/
|
||||
export const lightTheme = {
|
||||
id: 1,
|
||||
name: "Light",
|
||||
colorPrimary: "#FFFFFF",
|
||||
colorPrimaryDark: "#FAFAFA",
|
||||
colorAccentDark: "#2979FF",
|
||||
@@ -23,12 +25,17 @@ export const lightTheme = {
|
||||
textColorHintDark: "rgba(0,0,0,0.38)",
|
||||
rippleColor: "rgba(0,0,0,0.12)",
|
||||
searchBarColor: "#FFFFFF",
|
||||
menuColor: "#FFFFFF",
|
||||
dividerColor: "rgba(0,0,0,0.1)",
|
||||
statusBar: "dark",
|
||||
};
|
||||
|
||||
/**
|
||||
* Dark Theme
|
||||
*/
|
||||
export const darkTheme = {
|
||||
id: 2,
|
||||
name: "Dark",
|
||||
colorPrimary: "#242529",
|
||||
colorPrimaryDark: "#202125",
|
||||
colorAccentDark: "#3399FF",
|
||||
@@ -37,12 +44,17 @@ export const darkTheme = {
|
||||
textColorHintDark: "rgba(255,255,255,0.5)",
|
||||
rippleColor: "rgba(255,255,255,0.2)",
|
||||
searchBarColor: "#303135",
|
||||
menuColor: "#242529",
|
||||
dividerColor: "rgba(255,255,255,0.1)",
|
||||
statusBar: "light",
|
||||
};
|
||||
|
||||
/**
|
||||
* Amoled Dark Theme
|
||||
*/
|
||||
export const amoledDarkTheme = {
|
||||
id: 0,
|
||||
name: "AMOLED Dark",
|
||||
colorPrimary: "#000000",
|
||||
colorPrimaryDark: "#000000",
|
||||
colorAccentDark: "#3399FF",
|
||||
@@ -51,12 +63,17 @@ export const amoledDarkTheme = {
|
||||
textColorHintDark: "rgba(255,255,255,0.5)",
|
||||
rippleColor: "rgba(255,255,255,0.2)",
|
||||
searchBarColor: "#1F1F1F",
|
||||
menuColor: "#242529",
|
||||
dividerColor: "rgba(255,255,255,0.15)",
|
||||
statusBar: "light",
|
||||
};
|
||||
|
||||
/**
|
||||
* Midnight Dusk Theme
|
||||
*/
|
||||
export const midnightDuskTheme = {
|
||||
id: 3,
|
||||
name: "Midnight Dusk",
|
||||
colorPrimary: "#201F27",
|
||||
colorPrimaryDark: "#16151D",
|
||||
colorAccentDark: "#F02475",
|
||||
@@ -65,4 +82,7 @@ export const midnightDuskTheme = {
|
||||
textColorHintDark: "rgba(255,255,255,0.5)",
|
||||
rippleColor: "rgba(255,255,255,0.2)",
|
||||
searchBarColor: "#201F27",
|
||||
menuColor: "#201F27",
|
||||
dividerColor: "rgba(255,255,255,0.1)",
|
||||
statusBar: "light",
|
||||
};
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
const fonts = [
|
||||
{ fontFamily: "", name: "Original" },
|
||||
{ fontFamily: "arbutus-slab", name: "Arbutus Slab" },
|
||||
{ fontFamily: "domine", name: "Domine" },
|
||||
{ fontFamily: "lato", name: "Lato" },
|
||||
{ fontFamily: "noto-sans", name: "Noto Sans" },
|
||||
{ fontFamily: "open-sans", name: "Open Sans" },
|
||||
{ fontFamily: "pt-serif", name: "PT Serif" },
|
||||
];
|
||||
|
||||
export { fonts };
|
||||
Reference in New Issue
Block a user