Add selecting chapters logic
This commit is contained in:
Binary file not shown.
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 28 KiB |
Generated
+99
@@ -2840,6 +2840,11 @@
|
||||
"resolved": "https://registry.npmjs.org/bmp-js/-/bmp-js-0.1.0.tgz",
|
||||
"integrity": "sha1-4Fpj95amwf8l9Hcex62twUjAcjM="
|
||||
},
|
||||
"boolbase": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
|
||||
"integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24="
|
||||
},
|
||||
"bplist-creator": {
|
||||
"version": "0.0.8",
|
||||
"resolved": "https://registry.npmjs.org/bplist-creator/-/bplist-creator-0.0.8.tgz",
|
||||
@@ -3420,6 +3425,38 @@
|
||||
"isobject": "^3.0.1"
|
||||
}
|
||||
},
|
||||
"css-select": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/css-select/-/css-select-2.1.0.tgz",
|
||||
"integrity": "sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ==",
|
||||
"requires": {
|
||||
"boolbase": "^1.0.0",
|
||||
"css-what": "^3.2.1",
|
||||
"domutils": "^1.7.0",
|
||||
"nth-check": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"css-tree": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz",
|
||||
"integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==",
|
||||
"requires": {
|
||||
"mdn-data": "2.0.14",
|
||||
"source-map": "^0.6.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"source-map": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"css-what": {
|
||||
"version": "3.4.2",
|
||||
"resolved": "https://registry.npmjs.org/css-what/-/css-what-3.4.2.tgz",
|
||||
"integrity": "sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ=="
|
||||
},
|
||||
"csstype": {
|
||||
"version": "3.0.8",
|
||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.8.tgz",
|
||||
@@ -3551,11 +3588,41 @@
|
||||
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
|
||||
"integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
|
||||
},
|
||||
"dom-serializer": {
|
||||
"version": "0.2.2",
|
||||
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz",
|
||||
"integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==",
|
||||
"requires": {
|
||||
"domelementtype": "^2.0.1",
|
||||
"entities": "^2.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"domelementtype": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz",
|
||||
"integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"dom-walk": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz",
|
||||
"integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w=="
|
||||
},
|
||||
"domelementtype": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz",
|
||||
"integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w=="
|
||||
},
|
||||
"domutils": {
|
||||
"version": "1.7.0",
|
||||
"resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz",
|
||||
"integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==",
|
||||
"requires": {
|
||||
"dom-serializer": "0",
|
||||
"domelementtype": "1"
|
||||
}
|
||||
},
|
||||
"ee-first": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
|
||||
@@ -3592,6 +3659,11 @@
|
||||
"once": "^1.4.0"
|
||||
}
|
||||
},
|
||||
"entities": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz",
|
||||
"integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A=="
|
||||
},
|
||||
"envinfo": {
|
||||
"version": "7.8.1",
|
||||
"resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz",
|
||||
@@ -3893,6 +3965,11 @@
|
||||
"fontfaceobserver": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"expo-haptics": {
|
||||
"version": "10.0.0",
|
||||
"resolved": "https://registry.npmjs.org/expo-haptics/-/expo-haptics-10.0.0.tgz",
|
||||
"integrity": "sha512-dfl4Fef22B8O49x5JEzILmAhathT14bkN0kic2FpuwssJDX/yZ/R2lD12Iu9XqxdgHAFQRjOSq3dFjrxDGkP6g=="
|
||||
},
|
||||
"expo-keep-awake": {
|
||||
"version": "9.1.2",
|
||||
"resolved": "https://registry.npmjs.org/expo-keep-awake/-/expo-keep-awake-9.1.2.tgz",
|
||||
@@ -5617,6 +5694,11 @@
|
||||
"buffer-alloc": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"mdn-data": {
|
||||
"version": "2.0.14",
|
||||
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz",
|
||||
"integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow=="
|
||||
},
|
||||
"merge-stream": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-1.0.1.tgz",
|
||||
@@ -6460,6 +6542,14 @@
|
||||
"path-key": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"nth-check": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz",
|
||||
"integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==",
|
||||
"requires": {
|
||||
"boolbase": "~1.0.0"
|
||||
}
|
||||
},
|
||||
"nullthrows": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/nullthrows/-/nullthrows-1.1.1.tgz",
|
||||
@@ -7535,6 +7625,15 @@
|
||||
"resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-3.0.0.tgz",
|
||||
"integrity": "sha512-35II5oxTaVp3OP8y0eLPOPpQkxG4fRKQ+dL1YSE1we5kCZFOU0l/Rn0T79HbyUu1LPwUZr6lZupPs0ULnRyMuQ=="
|
||||
},
|
||||
"react-native-svg": {
|
||||
"version": "12.1.0",
|
||||
"resolved": "https://registry.npmjs.org/react-native-svg/-/react-native-svg-12.1.0.tgz",
|
||||
"integrity": "sha512-1g9qBRci7man8QsHoXn6tP3DhCDiypGgc6+AOWq+Sy+PmP6yiyf8VmvKuoqrPam/tf5x+ZaBT2KI0gl7bptZ7w==",
|
||||
"requires": {
|
||||
"css-select": "^2.1.0",
|
||||
"css-tree": "^1.0.0-alpha.39"
|
||||
}
|
||||
},
|
||||
"react-native-swipe-list-view": {
|
||||
"version": "3.2.7",
|
||||
"resolved": "https://registry.npmjs.org/react-native-swipe-list-view/-/react-native-swipe-list-view-3.2.7.tgz",
|
||||
|
||||
+3
-1
@@ -55,7 +55,9 @@
|
||||
"redux-persist": "^6.0.0",
|
||||
"redux-thunk": "^2.3.0",
|
||||
"rn-sliding-up-panel": "^2.4.4",
|
||||
"expo-speech": "~9.1.0"
|
||||
"expo-speech": "~9.1.0",
|
||||
"react-native-svg": "12.1.0",
|
||||
"expo-haptics": "~10.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "~7.9.0"
|
||||
|
||||
@@ -10,7 +10,7 @@ import Constants from "expo-constants";
|
||||
import { useNavigation } from "@react-navigation/native";
|
||||
import { useSelector } from "react-redux";
|
||||
|
||||
export const Appbar = ({ title, onBackAction, style }) => {
|
||||
export const Appbar = ({ title, onBackAction, style, children }) => {
|
||||
const theme = useSelector((state) => state.settingsReducer.theme);
|
||||
|
||||
return (
|
||||
@@ -24,6 +24,7 @@ export const Appbar = ({ title, onBackAction, style }) => {
|
||||
title={title}
|
||||
titleStyle={{ color: theme.textColorPrimary }}
|
||||
/>
|
||||
{children}
|
||||
</MaterialAppbar.Header>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -45,10 +45,6 @@ const MainNavigator = () => {
|
||||
name="Novel"
|
||||
component={Novel}
|
||||
options={{
|
||||
headerTitle: "",
|
||||
headerShown: true,
|
||||
headerTransparent: true,
|
||||
headerTintColor: "white",
|
||||
...TransitionPresets.RevealFromBottomAndroid,
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -81,7 +81,7 @@ const Browse = ({ navigation }) => {
|
||||
clearSearchbar={clearSearchbar}
|
||||
right="book-search"
|
||||
onPressRight={() => navigation.navigate("GlobalSearch")}
|
||||
migrate="weather-cloudy-arrow-right"
|
||||
migrate="swap-vertical-variant"
|
||||
onPressMigrate={() => navigation.navigate("Migration")}
|
||||
/>
|
||||
|
||||
|
||||
@@ -40,18 +40,18 @@ const ChapterAppbar = ({
|
||||
novelUrl,
|
||||
novelId,
|
||||
chapterName: prevChapter.chapterName,
|
||||
novelName: novelName,
|
||||
novelName,
|
||||
});
|
||||
|
||||
const navigateToNextChapter = () =>
|
||||
navigation.replace("Chapter", {
|
||||
chapterUrl: nextChapter.nextChapter,
|
||||
chapterUrl: nextChapter.chapterUrl,
|
||||
sourceId,
|
||||
novelUrl,
|
||||
novelId,
|
||||
chapterId: nextChapter.chapterId,
|
||||
chapterName: nextChapter.chapterName,
|
||||
novelName: novelName,
|
||||
novelName,
|
||||
});
|
||||
|
||||
return (
|
||||
@@ -64,9 +64,9 @@ const ChapterAppbar = ({
|
||||
/>
|
||||
<Appbar.Content
|
||||
title={novelName}
|
||||
titleStyle={{ color: theme.textColorPrimary }}
|
||||
titleStyle={{ color: "#FFFFFF" }}
|
||||
subtitle={chapterName}
|
||||
subtitleStyle={{ color: theme.textColorSecondary }}
|
||||
subtitleStyle={{ color: "rgba(255, 255, 255, 0.7)" }}
|
||||
/>
|
||||
<Appbar.Action
|
||||
icon="chevron-left"
|
||||
|
||||
@@ -9,6 +9,17 @@ import { setReaderSettings } from "../../../redux/settings/settings.actions";
|
||||
import BottomSheetHandle from "../../../Components/BottomSheetHandle";
|
||||
|
||||
const ReaderSheet = ({ theme, reader, dispatch, bottomSheetRef }) => {
|
||||
const ReaderSettingTitle = ({ title }) => (
|
||||
<Text
|
||||
style={{
|
||||
color: "#FFFFFF",
|
||||
fontWeight: "bold",
|
||||
}}
|
||||
>
|
||||
{title}
|
||||
</Text>
|
||||
);
|
||||
|
||||
return (
|
||||
<Bottomsheet
|
||||
ref={bottomSheetRef}
|
||||
@@ -20,14 +31,7 @@ const ReaderSheet = ({ theme, reader, dispatch, bottomSheetRef }) => {
|
||||
<View style={styles.contentContainer}>
|
||||
<BottomSheetHandle theme={theme} />
|
||||
<View style={styles.readerSettingsContainer}>
|
||||
<Text
|
||||
style={{
|
||||
color: "#FFFFFF",
|
||||
fontWeight: "bold",
|
||||
}}
|
||||
>
|
||||
Text Size
|
||||
</Text>
|
||||
<ReaderSettingTitle title="Text Size" />
|
||||
<Slider
|
||||
style={{
|
||||
width: Dimensions.get("window").width,
|
||||
@@ -56,14 +60,7 @@ const ReaderSheet = ({ theme, reader, dispatch, bottomSheetRef }) => {
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<Text
|
||||
style={{
|
||||
color: "#FFFFFF",
|
||||
fontWeight: "bold",
|
||||
}}
|
||||
>
|
||||
Reader Theme
|
||||
</Text>
|
||||
<ReaderSettingTitle title="Reader Theme" />
|
||||
<ToggleButton.Row
|
||||
onValueChange={(value) => {
|
||||
dispatch(
|
||||
@@ -118,14 +115,7 @@ const ReaderSheet = ({ theme, reader, dispatch, bottomSheetRef }) => {
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<Text
|
||||
style={{
|
||||
color: "#FFFFFF",
|
||||
fontWeight: "bold",
|
||||
}}
|
||||
>
|
||||
Text Align
|
||||
</Text>
|
||||
<ReaderSettingTitle title="Text Align" />
|
||||
<ToggleButton.Row
|
||||
onValueChange={(value) =>
|
||||
dispatch(
|
||||
@@ -150,6 +140,8 @@ const ReaderSheet = ({ theme, reader, dispatch, bottomSheetRef }) => {
|
||||
backgroundColor: "#FFFFFF",
|
||||
marginHorizontal: 10,
|
||||
borderWidth: 0,
|
||||
borderTopRightRadius: 4,
|
||||
borderBottomRightRadius: 4,
|
||||
}}
|
||||
/>
|
||||
<ToggleButton
|
||||
@@ -164,6 +156,7 @@ const ReaderSheet = ({ theme, reader, dispatch, bottomSheetRef }) => {
|
||||
backgroundColor: "#FFFFFF",
|
||||
marginHorizontal: 10,
|
||||
borderWidth: 0,
|
||||
borderRadius: 4,
|
||||
}}
|
||||
/>
|
||||
<ToggleButton
|
||||
@@ -178,6 +171,8 @@ const ReaderSheet = ({ theme, reader, dispatch, bottomSheetRef }) => {
|
||||
backgroundColor: "#FFFFFF",
|
||||
marginHorizontal: 10,
|
||||
borderWidth: 0,
|
||||
borderTopLeftRadius: 4,
|
||||
borderBottomLeftRadius: 4,
|
||||
}}
|
||||
/>
|
||||
</ToggleButton.Row>
|
||||
@@ -241,7 +236,7 @@ const ReaderSheet = ({ theme, reader, dispatch, bottomSheetRef }) => {
|
||||
style={{
|
||||
color: "#FFFFFF",
|
||||
fontWeight: "bold",
|
||||
marginTop: 10,
|
||||
marginVertical: 10,
|
||||
}}
|
||||
>
|
||||
Font Style
|
||||
|
||||
+132
-5
@@ -1,14 +1,29 @@
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { StyleSheet, View, FlatList, RefreshControl } from "react-native";
|
||||
import {
|
||||
StyleSheet,
|
||||
View,
|
||||
FlatList,
|
||||
RefreshControl,
|
||||
StatusBar,
|
||||
} from "react-native";
|
||||
|
||||
import { Provider, Portal } from "react-native-paper";
|
||||
import {
|
||||
Provider,
|
||||
Portal,
|
||||
Appbar as MaterialAppbar,
|
||||
IconButton,
|
||||
} from "react-native-paper";
|
||||
import { useDispatch } from "react-redux";
|
||||
|
||||
import {
|
||||
bookmarkChapterAction,
|
||||
deleteAllChaptersAction,
|
||||
downloadAllChaptersAction,
|
||||
getNovelAction,
|
||||
markChapterReadAction,
|
||||
markChaptersRead,
|
||||
markChapterUnreadAction,
|
||||
markPreviousChaptersReadAction,
|
||||
sortAndFilterChapters,
|
||||
updateNovelAction,
|
||||
} from "../../redux/novel/novel.actions";
|
||||
@@ -25,6 +40,7 @@ import NovelInfoHeader from "./components/NovelHeader";
|
||||
import ChaptersSettingsSheet from "./components/ChaptersSettingsSheet";
|
||||
import TrackSheet from "./components/Tracker/TrackSheet";
|
||||
import ChapterActionsSheet from "./components/ChapterActionsSheet";
|
||||
import { Appbar } from "../../Components/Appbar";
|
||||
|
||||
const Novel = ({ route, navigation }) => {
|
||||
const item = route.params;
|
||||
@@ -34,7 +50,7 @@ const Novel = ({ route, navigation }) => {
|
||||
const dispatch = useDispatch();
|
||||
const { novel, chapters, loading, updating, downloading } = useNovel();
|
||||
|
||||
const [selected, setSelected] = useState();
|
||||
const [selected, setSelected] = useState([]);
|
||||
|
||||
let chaptersSettingsSheetRef = useRef(null);
|
||||
let trackerSheetRef = useRef(null);
|
||||
@@ -82,6 +98,7 @@ const Novel = ({ route, navigation }) => {
|
||||
downloading={downloading}
|
||||
selected={selected}
|
||||
novelName={novelName}
|
||||
selected={selected}
|
||||
setSelected={setSelected}
|
||||
chapterActionsSheetRef={chapterActionsSheetRef}
|
||||
/>
|
||||
@@ -95,6 +112,116 @@ const Novel = ({ route, navigation }) => {
|
||||
{ backgroundColor: theme.colorPrimaryDark },
|
||||
]}
|
||||
>
|
||||
{selected.length > 0 ? (
|
||||
<MaterialAppbar.Header
|
||||
style={{
|
||||
backgroundColor: theme.colorPrimary,
|
||||
}}
|
||||
>
|
||||
<MaterialAppbar.Action
|
||||
icon="close"
|
||||
color={theme.textColorPrimary}
|
||||
onPress={() => {
|
||||
setSelected([]);
|
||||
}}
|
||||
/>
|
||||
<MaterialAppbar.Content
|
||||
title={selected.length}
|
||||
titleStyle={{ color: theme.textColorPrimary }}
|
||||
/>
|
||||
<MaterialAppbar.Action
|
||||
icon="bookmark-outline"
|
||||
color={theme.textColorPrimary}
|
||||
onPress={() => {
|
||||
dispatch(bookmarkChapterAction(selected));
|
||||
setSelected([]);
|
||||
}}
|
||||
/>
|
||||
|
||||
{selected.some((obj) => obj.read === 0) && (
|
||||
<MaterialAppbar.Action
|
||||
icon="check"
|
||||
color={theme.textColorPrimary}
|
||||
onPress={() => {
|
||||
dispatch(markChaptersRead(selected));
|
||||
setSelected([]);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{selected.some((obj) => obj.read === 1) && (
|
||||
<MaterialAppbar.Action
|
||||
icon="check-outline"
|
||||
color={theme.textColorPrimary}
|
||||
onPress={() => {
|
||||
dispatch(markChapterUnreadAction(selected));
|
||||
setSelected([]);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{selected.length === 1 && (
|
||||
<MaterialAppbar.Action
|
||||
icon="eye-check"
|
||||
color={theme.textColorPrimary}
|
||||
onPress={() => {
|
||||
dispatch(
|
||||
markPreviousChaptersReadAction(
|
||||
selected[0].chapterId,
|
||||
selected[0].novelId
|
||||
)
|
||||
);
|
||||
setSelected([]);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{selected.some((obj) => obj.downloaded === 1) && (
|
||||
<MaterialAppbar.Action
|
||||
icon="trash-can-outline"
|
||||
color={theme.textColorPrimary}
|
||||
onPress={() => {
|
||||
dispatch(deleteAllChaptersAction(selected));
|
||||
setSelected([]);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
{selected.some((obj) => obj.downloaded === 0) && (
|
||||
<MaterialAppbar.Action
|
||||
icon="download-outline"
|
||||
color={theme.textColorPrimary}
|
||||
onPress={() => {
|
||||
dispatch(
|
||||
downloadAllChaptersAction(
|
||||
novel.sourceId,
|
||||
novel.novelUrl,
|
||||
selected
|
||||
)
|
||||
);
|
||||
setSelected([]);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<MaterialAppbar.Action
|
||||
icon="select-all"
|
||||
color={theme.textColorPrimary}
|
||||
onPress={() => {
|
||||
setSelected(chapters);
|
||||
}}
|
||||
/>
|
||||
</MaterialAppbar.Header>
|
||||
) : (
|
||||
<IconButton
|
||||
icon="arrow-left"
|
||||
color="white"
|
||||
size={24}
|
||||
onPress={() => navigation.goBack()}
|
||||
style={{
|
||||
position: "absolute",
|
||||
zIndex: 1,
|
||||
top: StatusBar.currentHeight + 8,
|
||||
left: 8,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<FlatList
|
||||
data={!loading && chapters}
|
||||
keyExtractor={(item) => item.chapterId.toString()}
|
||||
@@ -138,7 +265,7 @@ const Novel = ({ route, navigation }) => {
|
||||
novelName={novel.novelName}
|
||||
theme={theme}
|
||||
/>
|
||||
<ChapterActionsSheet
|
||||
{/* <ChapterActionsSheet
|
||||
theme={theme}
|
||||
selected={selected}
|
||||
chapters={chapters}
|
||||
@@ -148,7 +275,7 @@ const Novel = ({ route, navigation }) => {
|
||||
markChapterReadAction={markChapterReadAction}
|
||||
markChapterUnreadAction={markChapterUnreadAction}
|
||||
bookmarkChapterAction={bookmarkChapterAction}
|
||||
/>
|
||||
/> */}
|
||||
</Portal>
|
||||
)}
|
||||
</View>
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import React, { useState } from "react";
|
||||
import { View, Text, ActivityIndicator, StyleSheet } from "react-native";
|
||||
|
||||
import { TouchableRipple, IconButton, Menu } from "react-native-paper";
|
||||
import * as Haptics from "expo-haptics";
|
||||
|
||||
import {
|
||||
deleteChapterAction,
|
||||
@@ -17,6 +19,7 @@ const ChapterItem = ({
|
||||
navigation,
|
||||
downloading,
|
||||
position,
|
||||
selected,
|
||||
setSelected,
|
||||
chapterActionsSheetRef,
|
||||
}) => {
|
||||
@@ -112,16 +115,44 @@ const ChapterItem = ({
|
||||
}
|
||||
};
|
||||
|
||||
const isSelected = (chapterId) => {
|
||||
return selected.some((obj) => obj.chapterId === chapterId);
|
||||
};
|
||||
|
||||
return (
|
||||
<TouchableRipple
|
||||
style={[
|
||||
styles.chapterCardContainer,
|
||||
{ backgroundColor: theme.colorPrimaryDark },
|
||||
isSelected(chapter.chapterId) && {
|
||||
backgroundColor: theme.rippleColor,
|
||||
},
|
||||
]}
|
||||
onPress={navigateToChapter}
|
||||
onPress={() => {
|
||||
if (selected.length === 0) {
|
||||
navigateToChapter();
|
||||
} else {
|
||||
if (isSelected(chapter.chapterId)) {
|
||||
setSelected((selected) =>
|
||||
selected.filter(
|
||||
(item) => item.chapterId !== chapter.chapterId
|
||||
)
|
||||
);
|
||||
} else {
|
||||
setSelected((selected) => [...selected, chapter]);
|
||||
}
|
||||
}
|
||||
}}
|
||||
onLongPress={() => {
|
||||
setSelected(chapter);
|
||||
chapterActionsSheetRef.current.show();
|
||||
if (isSelected(chapter.chapterId)) {
|
||||
setSelected((selected) =>
|
||||
selected.filter(
|
||||
(item) => item.chapterId !== chapter.chapterId
|
||||
)
|
||||
);
|
||||
} else {
|
||||
setSelected((selected) => [...selected, chapter]);
|
||||
}
|
||||
// chapterActionsSheetRef.current.show();
|
||||
}}
|
||||
rippleColor={theme.rippleColor}
|
||||
>
|
||||
|
||||
@@ -36,6 +36,7 @@ import {
|
||||
bookmarkChapter,
|
||||
markPreviuschaptersRead,
|
||||
markPreviousChaptersUnread,
|
||||
getNextChapterFromDB,
|
||||
} from "../../Database/queries/ChapterQueries";
|
||||
import { deleteNovelUpdates } from "../../Database/queries/UpdateQueries";
|
||||
import {
|
||||
@@ -54,58 +55,66 @@ export const setNovel = (novel) => async (dispatch) => {
|
||||
export const getNovelAction =
|
||||
(followed, sourceId, novelUrl, novelId, sort, filter) =>
|
||||
async (dispatch) => {
|
||||
dispatch({ type: LOADING_NOVEL });
|
||||
try {
|
||||
dispatch({ type: LOADING_NOVEL });
|
||||
|
||||
if (followed === 1) {
|
||||
/**
|
||||
* If novel is followed directly get the chapters from db.
|
||||
*/
|
||||
const chapters = await getChapters(novelId, sort, filter);
|
||||
|
||||
dispatch({
|
||||
type: GET_CHAPTERS,
|
||||
payload: chapters,
|
||||
});
|
||||
} else {
|
||||
dispatch({ type: FETCHING_NOVEL });
|
||||
|
||||
/**
|
||||
* Check if novel is cached.
|
||||
*/
|
||||
const novel = await getNovel(sourceId, novelUrl);
|
||||
|
||||
if (novel) {
|
||||
if (followed === 1) {
|
||||
/**
|
||||
* Get chapters from db.
|
||||
* If novel is followed directly get the chapters from db.
|
||||
*/
|
||||
novel.chapters = await getChapters(novel.novelId, sort, filter);
|
||||
const chapters = await getChapters(novelId, sort, filter);
|
||||
|
||||
dispatch({
|
||||
type: GET_NOVEL,
|
||||
payload: novel,
|
||||
type: GET_CHAPTERS,
|
||||
payload: chapters,
|
||||
});
|
||||
} else {
|
||||
/**
|
||||
* Fetch novel from source.
|
||||
*/
|
||||
const fetchedNovel = await fetchNovel(sourceId, novelUrl);
|
||||
dispatch({ type: FETCHING_NOVEL });
|
||||
|
||||
/**
|
||||
* Insert novel in db.
|
||||
*/
|
||||
const fetchedNovelId = await insertNovel(fetchedNovel);
|
||||
await insertChapters(fetchedNovelId, fetchedNovel.chapters);
|
||||
|
||||
/**
|
||||
* Get novel from db.
|
||||
* Check if novel is cached.
|
||||
*/
|
||||
const novel = await getNovel(sourceId, novelUrl);
|
||||
novel.chapters = await getChapters(novel.novelId);
|
||||
|
||||
dispatch({
|
||||
type: GET_NOVEL,
|
||||
payload: novel,
|
||||
});
|
||||
if (novel) {
|
||||
/**
|
||||
* Get chapters from db.
|
||||
*/
|
||||
novel.chapters = await getChapters(
|
||||
novel.novelId,
|
||||
sort,
|
||||
filter
|
||||
);
|
||||
dispatch({
|
||||
type: GET_NOVEL,
|
||||
payload: novel,
|
||||
});
|
||||
} else {
|
||||
/**
|
||||
* Fetch novel from source.
|
||||
*/
|
||||
const fetchedNovel = await fetchNovel(sourceId, novelUrl);
|
||||
|
||||
/**
|
||||
* Insert novel in db.
|
||||
*/
|
||||
const fetchedNovelId = await insertNovel(fetchedNovel);
|
||||
await insertChapters(fetchedNovelId, fetchedNovel.chapters);
|
||||
|
||||
/**
|
||||
* Get novel from db.
|
||||
*/
|
||||
const novel = await getNovel(sourceId, novelUrl);
|
||||
novel.chapters = await getChapters(novel.novelId);
|
||||
|
||||
dispatch({
|
||||
type: GET_NOVEL,
|
||||
payload: novel,
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
showToast(error.message);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -146,15 +155,19 @@ export const followNovelAction = (novel) => async (dispatch) => {
|
||||
showToast(!novel.followed ? "Added to library" : "Removed from library");
|
||||
};
|
||||
|
||||
export const bookmarkChapterAction =
|
||||
(bookmark, chapterId) => async (dispatch) => {
|
||||
await bookmarkChapter(bookmark, chapterId);
|
||||
export const bookmarkChapterAction = (chapters) => async (dispatch) => {
|
||||
chapters.map((chapter) => {
|
||||
bookmarkChapter(chapter.bookmark, chapter.chapterId);
|
||||
|
||||
dispatch({
|
||||
type: BOOKMARK_CHAPTER,
|
||||
payload: { bookmark, chapterId },
|
||||
payload: {
|
||||
bookmark: chapter.bookmark,
|
||||
chapterId: chapter.chapterId,
|
||||
},
|
||||
});
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
export const markChapterReadAction =
|
||||
(chapterId, novelId) => async (dispatch) => {
|
||||
@@ -165,9 +178,11 @@ export const markChapterReadAction =
|
||||
payload: { chapterId },
|
||||
});
|
||||
|
||||
const nextChapter = await getNextChapterFromDB(novelId, chapterId);
|
||||
|
||||
dispatch({
|
||||
type: SET_LAST_READ,
|
||||
payload: { novelId, chapterId: chapterId + 1 },
|
||||
payload: { novelId, chapterId: nextChapter.chapterId },
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -192,8 +207,51 @@ export const markPreviousChaptersReadAction =
|
||||
type: MARK_PREVIOUS_CHAPTERS_READ,
|
||||
payload: chapterId,
|
||||
});
|
||||
|
||||
showToast("Marked previous chapters read");
|
||||
};
|
||||
|
||||
export const markChaptersRead = (chapters) => async (dispatch) => {
|
||||
try {
|
||||
chapters.map(async (chapter) => {
|
||||
await markChapterRead(chapter.chapterId);
|
||||
|
||||
dispatch({
|
||||
type: CHAPTER_READ,
|
||||
payload: { chapterId: chapter.chapterId },
|
||||
});
|
||||
|
||||
const nextChapter = await getNextChapterFromDB(
|
||||
chapter.novelId,
|
||||
chapter.chapterId
|
||||
);
|
||||
|
||||
dispatch({
|
||||
type: SET_LAST_READ,
|
||||
payload: {
|
||||
novelId: chapter.novelId,
|
||||
chapterId: nextChapter.chapterId,
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Reset progress on marked read
|
||||
*/
|
||||
dispatch({
|
||||
type: SAVE_SCROLL_POSITION,
|
||||
payload: {
|
||||
position: 0,
|
||||
percentage: 0,
|
||||
chapterId: chapter.chapterId,
|
||||
novelId: chapter.novelId,
|
||||
},
|
||||
});
|
||||
});
|
||||
} catch (error) {
|
||||
showToast(error.message);
|
||||
}
|
||||
};
|
||||
|
||||
export const markPreviousChaptersUnreadAction =
|
||||
(chapterId, novelId) => async (dispatch) => {
|
||||
await markPreviousChaptersUnread(chapterId, novelId);
|
||||
@@ -204,12 +262,14 @@ export const markPreviousChaptersUnreadAction =
|
||||
});
|
||||
};
|
||||
|
||||
export const markChapterUnreadAction = (chapterId) => async (dispatch) => {
|
||||
await markChapterUnread(chapterId);
|
||||
export const markChapterUnreadAction = (chapters) => async (dispatch) => {
|
||||
await chapters.map((chapter) => {
|
||||
markChapterUnread(chapter.chapterId);
|
||||
|
||||
dispatch({
|
||||
type: CHAPTER_UNREAD,
|
||||
payload: { chapterId },
|
||||
dispatch({
|
||||
type: CHAPTER_UNREAD,
|
||||
payload: { chapterId: chapter.chapterId },
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
@@ -233,30 +293,36 @@ export const downloadChapterAction =
|
||||
|
||||
export const downloadAllChaptersAction =
|
||||
(extensionId, novelUrl, chapters) => async (dispatch) => {
|
||||
await chapters.map((chapter, index) => {
|
||||
setTimeout(async () => {
|
||||
dispatch({
|
||||
type: CHAPTER_DOWNLOADING,
|
||||
payload: chapter.chapterId,
|
||||
});
|
||||
try {
|
||||
await chapters.map((chapter, index) => {
|
||||
setTimeout(async () => {
|
||||
dispatch({
|
||||
type: CHAPTER_DOWNLOADING,
|
||||
payload: chapter.chapterId,
|
||||
});
|
||||
|
||||
if (!chapter.downloaded) {
|
||||
await downloadChapter(
|
||||
extensionId,
|
||||
novelUrl,
|
||||
chapter.chapterUrl,
|
||||
chapter.chapterId
|
||||
);
|
||||
}
|
||||
if (!chapter.downloaded) {
|
||||
await downloadChapter(
|
||||
extensionId,
|
||||
novelUrl,
|
||||
chapter.chapterUrl,
|
||||
chapter.chapterId
|
||||
);
|
||||
}
|
||||
|
||||
dispatch({
|
||||
type: CHAPTER_DOWNLOADED,
|
||||
payload: chapter.chapterId,
|
||||
});
|
||||
}, 1000 * index);
|
||||
});
|
||||
dispatch({
|
||||
type: CHAPTER_DOWNLOADED,
|
||||
payload: chapter.chapterId,
|
||||
});
|
||||
|
||||
showToast(`All chapters downloaded`);
|
||||
if (index + 1 === chapters.length) {
|
||||
showToast(`Download completed `);
|
||||
}
|
||||
}, 1000 * index);
|
||||
});
|
||||
} catch (error) {
|
||||
showToast(error.message);
|
||||
}
|
||||
};
|
||||
|
||||
export const deleteChapterAction =
|
||||
@@ -281,7 +347,7 @@ export const deleteAllChaptersAction = (chapters) => async (dispatch) => {
|
||||
});
|
||||
});
|
||||
|
||||
showToast("Deleted all chapters");
|
||||
showToast("Chapters deleted");
|
||||
};
|
||||
|
||||
export const updateNovelAction =
|
||||
|
||||
@@ -1,13 +1,18 @@
|
||||
import { GET_SOURCES, PIN_SOURCES, SEARCH_SOURCES } from "./source.types";
|
||||
import { fetchSources } from "../../Services/Source/source";
|
||||
import { showToast } from "../../Hooks/showToast";
|
||||
|
||||
export const getSourcesAction = () => async (dispatch) => {
|
||||
const res = await fetchSources();
|
||||
try {
|
||||
const res = await fetchSources();
|
||||
|
||||
dispatch({
|
||||
type: GET_SOURCES,
|
||||
payload: res,
|
||||
});
|
||||
dispatch({
|
||||
type: GET_SOURCES,
|
||||
payload: res,
|
||||
});
|
||||
} catch (error) {
|
||||
showToast(error.message);
|
||||
}
|
||||
};
|
||||
|
||||
export const searchSourcesAction = (searchText) => async (dispatch) => {
|
||||
|
||||
+1
-3
@@ -6,7 +6,6 @@ import thunk from "redux-thunk";
|
||||
import settingsReducer from "./settings/settings.reducer";
|
||||
import libraryReducer from "./library/library.reducer";
|
||||
import sourceReducer from "./source/source.reducers";
|
||||
import chapterReducer from "./chapter/chapter.reducer";
|
||||
import novelReducer from "./novel/novel.reducer";
|
||||
import historyReducer from "./history/history.reducer";
|
||||
import updatesReducer from "./updates/updates.reducer";
|
||||
@@ -16,7 +15,7 @@ import preferenceReducer from "./preferences/preference.reducer";
|
||||
const persistConfig = {
|
||||
key: "root",
|
||||
storage: AsyncStorage,
|
||||
blacklist: ["novelReducer", "chapterReducer"],
|
||||
blacklist: ["novelReducer"],
|
||||
};
|
||||
|
||||
const persistedReducer = persistReducer(
|
||||
@@ -27,7 +26,6 @@ const persistedReducer = persistReducer(
|
||||
sourceReducer,
|
||||
novelReducer,
|
||||
historyReducer,
|
||||
chapterReducer,
|
||||
updatesReducer,
|
||||
trackerReducer,
|
||||
preferenceReducer,
|
||||
|
||||
Reference in New Issue
Block a user