Reorganize novel details
This commit is contained in:
@@ -2,7 +2,7 @@ import React from "react";
|
||||
import { StyleSheet, Text, View } from "react-native";
|
||||
import { useSelector } from "react-redux";
|
||||
|
||||
const EmptyView = ({ icon, description }) => {
|
||||
const EmptyView = ({ icon, description, style, children }) => {
|
||||
const theme = useSelector((state) => state.settingsReducer.theme);
|
||||
|
||||
return (
|
||||
@@ -11,6 +11,7 @@ const EmptyView = ({ icon, description }) => {
|
||||
style={[
|
||||
styles.emptyViewIcon,
|
||||
{ color: theme.textColorSecondary },
|
||||
style,
|
||||
]}
|
||||
>
|
||||
{icon}
|
||||
@@ -19,10 +20,12 @@ const EmptyView = ({ icon, description }) => {
|
||||
style={[
|
||||
styles.emptyViewText,
|
||||
{ color: theme.textColorSecondary },
|
||||
style,
|
||||
]}
|
||||
>
|
||||
{description}
|
||||
</Text>
|
||||
{children}
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
|
||||
import { useDispatch } from "react-redux";
|
||||
import Constants from "expo-constants";
|
||||
import { Portal } from "react-native-paper";
|
||||
import { IconButton, Portal } from "react-native-paper";
|
||||
import { CollapsibleHeaderScrollView } from "react-native-collapsible-header-views";
|
||||
|
||||
import { getChapterFromDB } from "../../Database/queries/ChapterQueries";
|
||||
@@ -26,6 +26,7 @@ import {
|
||||
import { updateChaptersRead } from "../../redux/tracker/tracker.actions";
|
||||
import { insertHistoryAction } from "../../redux/history/history.actions";
|
||||
import {
|
||||
errorTextColor,
|
||||
readerBackground,
|
||||
readerLineHeight,
|
||||
readerTextColor,
|
||||
@@ -36,6 +37,7 @@ import { parseChapterNumber } from "../../Services/updates";
|
||||
|
||||
import ChapterAppbar from "./components/ChapterAppbar";
|
||||
import ReaderSheet from "./components/ReaderSheet";
|
||||
import EmptyView from "../../Components/EmptyView";
|
||||
|
||||
const Chapter = ({ route, navigation }) => {
|
||||
const {
|
||||
@@ -60,6 +62,7 @@ const Chapter = ({ route, navigation }) => {
|
||||
|
||||
const [chapter, setChapter] = useState({});
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState();
|
||||
|
||||
const [scrollPercentage, setScrollPercentage] = useState(0);
|
||||
const [firstLayout, setFirstLayout] = useState(true);
|
||||
@@ -91,6 +94,8 @@ const Chapter = ({ route, navigation }) => {
|
||||
|
||||
setLoading(false);
|
||||
} catch (error) {
|
||||
setError(error.message);
|
||||
setLoading(false);
|
||||
showToast(error.message);
|
||||
}
|
||||
};
|
||||
@@ -216,7 +221,7 @@ const Chapter = ({ route, navigation }) => {
|
||||
color={theme.colorAccent}
|
||||
/>
|
||||
</View>
|
||||
) : (
|
||||
) : !error ? (
|
||||
<View style={{ flex: 1 }}>
|
||||
{images.length > 0 &&
|
||||
images.map((image) => (
|
||||
@@ -242,6 +247,31 @@ const Chapter = ({ route, navigation }) => {
|
||||
{chapter.chapterText.trim()}
|
||||
</Text>
|
||||
</View>
|
||||
) : (
|
||||
<View style={{ flex: 1, justifyContent: "center" }}>
|
||||
<EmptyView
|
||||
icon="(-_-;)・・・"
|
||||
description={error}
|
||||
style={{ color: errorTextColor(reader.theme) }}
|
||||
>
|
||||
<IconButton
|
||||
icon="reload"
|
||||
size={25}
|
||||
style={{ margin: 0, marginTop: 16 }}
|
||||
color={errorTextColor(reader.theme)}
|
||||
onPress={() => {
|
||||
getChapter(chapterId);
|
||||
setLoading(true);
|
||||
setError();
|
||||
}}
|
||||
/>
|
||||
<Text
|
||||
style={{ color: errorTextColor(reader.theme) }}
|
||||
>
|
||||
Retry
|
||||
</Text>
|
||||
</EmptyView>
|
||||
</View>
|
||||
)}
|
||||
<Portal>
|
||||
<ReaderSheet
|
||||
|
||||
@@ -302,9 +302,8 @@ const ReaderSheet = ({ theme, reader, dispatch, bottomSheetRef }) => {
|
||||
{fonts.find(
|
||||
(font) =>
|
||||
font.fontFamily ===
|
||||
reader.fontFamily ||
|
||||
font.fontFamily === ""
|
||||
).name || "Original"}
|
||||
reader.fontFamily
|
||||
).name || "Default"}
|
||||
</Text>
|
||||
}
|
||||
>
|
||||
|
||||
@@ -21,3 +21,9 @@ export const readerLineHeight = (fontSize, lineHeightMultiplier) => {
|
||||
|
||||
return lineHeight;
|
||||
};
|
||||
|
||||
export const errorTextColor = (val) => {
|
||||
const textColor = val === 1 ? "rgba(255,255,255,0.7)" : "rgba(0,0,0,0.54)";
|
||||
|
||||
return textColor;
|
||||
};
|
||||
|
||||
+92
-25
@@ -6,14 +6,10 @@ import {
|
||||
RefreshControl,
|
||||
StatusBar,
|
||||
Dimensions,
|
||||
Share,
|
||||
} from "react-native";
|
||||
|
||||
import {
|
||||
Provider,
|
||||
Portal,
|
||||
Appbar as MaterialAppbar,
|
||||
IconButton,
|
||||
} from "react-native-paper";
|
||||
import { Provider, Portal, Appbar, IconButton, Menu } from "react-native-paper";
|
||||
import { useDispatch } from "react-redux";
|
||||
|
||||
import {
|
||||
@@ -41,7 +37,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";
|
||||
import { Row } from "../../Components/Common";
|
||||
|
||||
const Novel = ({ route, navigation }) => {
|
||||
const item = route.params;
|
||||
@@ -52,6 +48,7 @@ const Novel = ({ route, navigation }) => {
|
||||
const { novel, chapters, loading, updating, downloading } = useNovel();
|
||||
|
||||
const [selected, setSelected] = useState([]);
|
||||
const [downloadMenu, showDownloadMenu] = useState(false);
|
||||
|
||||
let chaptersSettingsSheetRef = useRef(null);
|
||||
let trackerSheetRef = useRef(null);
|
||||
@@ -130,18 +127,18 @@ const Novel = ({ route, navigation }) => {
|
||||
paddingBottom: 8,
|
||||
}}
|
||||
>
|
||||
<MaterialAppbar.Action
|
||||
<Appbar.Action
|
||||
icon="close"
|
||||
color={theme.textColorPrimary}
|
||||
onPress={() => {
|
||||
setSelected([]);
|
||||
}}
|
||||
/>
|
||||
<MaterialAppbar.Content
|
||||
<Appbar.Content
|
||||
title={selected.length}
|
||||
titleStyle={{ color: theme.textColorPrimary }}
|
||||
/>
|
||||
<MaterialAppbar.Action
|
||||
<Appbar.Action
|
||||
icon="bookmark-outline"
|
||||
color={theme.textColorPrimary}
|
||||
onPress={() => {
|
||||
@@ -151,7 +148,7 @@ const Novel = ({ route, navigation }) => {
|
||||
/>
|
||||
|
||||
{selected.some((obj) => obj.read === 0) && (
|
||||
<MaterialAppbar.Action
|
||||
<Appbar.Action
|
||||
icon="check"
|
||||
color={theme.textColorPrimary}
|
||||
onPress={() => {
|
||||
@@ -161,7 +158,7 @@ const Novel = ({ route, navigation }) => {
|
||||
/>
|
||||
)}
|
||||
{selected.some((obj) => obj.read === 1) && (
|
||||
<MaterialAppbar.Action
|
||||
<Appbar.Action
|
||||
icon="check-outline"
|
||||
color={theme.textColorPrimary}
|
||||
onPress={() => {
|
||||
@@ -171,8 +168,8 @@ const Novel = ({ route, navigation }) => {
|
||||
/>
|
||||
)}
|
||||
{selected.length === 1 && (
|
||||
<MaterialAppbar.Action
|
||||
icon="eye-check"
|
||||
<Appbar.Action
|
||||
icon="playlist-check"
|
||||
color={theme.textColorPrimary}
|
||||
onPress={() => {
|
||||
dispatch(
|
||||
@@ -186,7 +183,7 @@ const Novel = ({ route, navigation }) => {
|
||||
/>
|
||||
)}
|
||||
{selected.some((obj) => obj.downloaded === 1) && (
|
||||
<MaterialAppbar.Action
|
||||
<Appbar.Action
|
||||
icon="trash-can-outline"
|
||||
color={theme.textColorPrimary}
|
||||
onPress={() => {
|
||||
@@ -197,7 +194,7 @@ const Novel = ({ route, navigation }) => {
|
||||
)}
|
||||
|
||||
{selected.some((obj) => obj.downloaded === 0) && (
|
||||
<MaterialAppbar.Action
|
||||
<Appbar.Action
|
||||
icon="download-outline"
|
||||
color={theme.textColorPrimary}
|
||||
onPress={() => {
|
||||
@@ -212,7 +209,7 @@ const Novel = ({ route, navigation }) => {
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<MaterialAppbar.Action
|
||||
<Appbar.Action
|
||||
icon="select-all"
|
||||
color={theme.textColorPrimary}
|
||||
onPress={() => {
|
||||
@@ -221,18 +218,88 @@ const Novel = ({ route, navigation }) => {
|
||||
/>
|
||||
</View>
|
||||
) : (
|
||||
<IconButton
|
||||
icon="arrow-left"
|
||||
color="white"
|
||||
size={24}
|
||||
onPress={() => navigation.goBack()}
|
||||
<View
|
||||
style={{
|
||||
position: "absolute",
|
||||
zIndex: 1,
|
||||
top: StatusBar.currentHeight + 8,
|
||||
left: 8,
|
||||
height: StatusBar.currentHeight + 54,
|
||||
width: "100%",
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
}}
|
||||
/>
|
||||
>
|
||||
<IconButton
|
||||
icon="arrow-left"
|
||||
color="white"
|
||||
size={24}
|
||||
style={{ marginTop: StatusBar.currentHeight + 8 }}
|
||||
onPress={() => navigation.goBack()}
|
||||
/>
|
||||
<Row>
|
||||
<Menu
|
||||
visible={downloadMenu}
|
||||
onDismiss={() => showDownloadMenu(false)}
|
||||
anchor={
|
||||
<IconButton
|
||||
icon="download"
|
||||
color="white"
|
||||
size={24}
|
||||
style={{
|
||||
marginTop:
|
||||
StatusBar.currentHeight + 8,
|
||||
}}
|
||||
onPress={() => showDownloadMenu(true)}
|
||||
/>
|
||||
}
|
||||
contentStyle={{
|
||||
backgroundColor: theme.menuColor,
|
||||
}}
|
||||
>
|
||||
<Menu.Item
|
||||
title="Download all"
|
||||
style={{ backgroundColor: theme.menuColor }}
|
||||
titleStyle={{
|
||||
color: theme.textColorPrimary,
|
||||
}}
|
||||
onPress={() =>
|
||||
dispatch(
|
||||
downloadAllChaptersAction(
|
||||
novel.sourceId,
|
||||
novel.novelUrl,
|
||||
chapters
|
||||
)
|
||||
)
|
||||
}
|
||||
/>
|
||||
<Menu.Item
|
||||
title="Delete downloads"
|
||||
style={{ backgroundColor: theme.menuColor }}
|
||||
titleStyle={{
|
||||
color: theme.textColorPrimary,
|
||||
}}
|
||||
onPress={() =>
|
||||
dispatch(
|
||||
deleteAllChaptersAction(chapters)
|
||||
)
|
||||
}
|
||||
/>
|
||||
</Menu>
|
||||
<IconButton
|
||||
icon="share-variant"
|
||||
color="white"
|
||||
size={21}
|
||||
style={{
|
||||
marginTop: StatusBar.currentHeight + 8,
|
||||
marginRight: 16,
|
||||
}}
|
||||
onPress={() =>
|
||||
Share.share({
|
||||
message: novel.sourceUrl,
|
||||
})
|
||||
}
|
||||
/>
|
||||
</Row>
|
||||
</View>
|
||||
)}
|
||||
<FlatList
|
||||
data={!loading && chapters}
|
||||
|
||||
@@ -228,7 +228,8 @@ const ChapterItem = ({
|
||||
]}
|
||||
numberOfLines={1}
|
||||
>
|
||||
{"• Progress " +
|
||||
{chapter.releaseDate && "• "}
|
||||
{"Progress " +
|
||||
position[chapter.chapterId]
|
||||
.percentage +
|
||||
"%"}
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
View,
|
||||
} from "react-native";
|
||||
|
||||
import { Chip } from "react-native-paper";
|
||||
import { Chip, IconButton } from "react-native-paper";
|
||||
import { MaterialCommunityIcons } from "@expo/vector-icons";
|
||||
import { LinearGradient } from "expo-linear-gradient";
|
||||
import easeGradient from "react-native-easing-gradient";
|
||||
@@ -70,51 +70,43 @@ const NovelInfo = ({ theme, children }) => (
|
||||
);
|
||||
|
||||
const FollowButton = ({ theme, onPress, followed }) => (
|
||||
<Chip
|
||||
mode="outlined"
|
||||
icon={() => (
|
||||
<MaterialCommunityIcons
|
||||
name={followed ? "heart" : "heart-outline"}
|
||||
size={21}
|
||||
color={theme.colorAccent}
|
||||
/>
|
||||
)}
|
||||
onPress={onPress}
|
||||
style={[
|
||||
{ backgroundColor: theme.colorPrimaryDark },
|
||||
styles.followButton,
|
||||
]}
|
||||
textStyle={{
|
||||
fontWeight: "bold",
|
||||
color: theme.textColorPrimary,
|
||||
}}
|
||||
>
|
||||
{followed ? "In Library" : "Add to library"}
|
||||
</Chip>
|
||||
<View style={{ alignItems: "center" }}>
|
||||
<IconButton
|
||||
icon={followed ? "heart" : "heart-outline"}
|
||||
color={followed ? theme.colorAccent : theme.textColorSecondary}
|
||||
size={24}
|
||||
style={{ margin: 0 }}
|
||||
onPress={onPress}
|
||||
/>
|
||||
<Text
|
||||
style={{
|
||||
fontSize: 12,
|
||||
color: followed ? theme.colorAccent : theme.textColorSecondary,
|
||||
}}
|
||||
>
|
||||
{followed ? "In Library" : "Add to library"}
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
|
||||
const TrackerButton = ({ theme, isTracked, onPress }) => (
|
||||
<Chip
|
||||
mode="outlined"
|
||||
icon={() => (
|
||||
<MaterialCommunityIcons
|
||||
name={isTracked ? "check" : "sync"}
|
||||
size={21}
|
||||
color={theme.colorAccent}
|
||||
/>
|
||||
)}
|
||||
onPress={onPress}
|
||||
style={[
|
||||
styles.followButton,
|
||||
{ backgroundColor: theme.colorPrimaryDark, marginLeft: 0 },
|
||||
]}
|
||||
textStyle={{
|
||||
fontWeight: "bold",
|
||||
color: theme.textColorPrimary,
|
||||
}}
|
||||
>
|
||||
{isTracked ? "Tracked" : "Tracking"}
|
||||
</Chip>
|
||||
<View style={{ alignItems: "center" }}>
|
||||
<IconButton
|
||||
icon={isTracked ? "check" : "sync"}
|
||||
color={followed ? theme.colorAccent : theme.textColorSecondary}
|
||||
size={24}
|
||||
style={{ margin: 0 }}
|
||||
onPress={onPress}
|
||||
/>
|
||||
<Text
|
||||
style={{
|
||||
fontSize: 12,
|
||||
color: followed ? theme.colorAccent : theme.textColorSecondary,
|
||||
}}
|
||||
>
|
||||
{isTracked ? "Tracked" : "Tracking"}
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
|
||||
const GenreChip = ({ children, theme }) => (
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
import React, { useState } from "react";
|
||||
import { View, Text, StyleSheet, Share } from "react-native";
|
||||
import React from "react";
|
||||
import { View, Text, StyleSheet } from "react-native";
|
||||
|
||||
import * as WebBrowser from "expo-web-browser";
|
||||
import { TouchableRipple, IconButton, Menu } from "react-native-paper";
|
||||
import { TouchableRipple, IconButton } from "react-native-paper";
|
||||
|
||||
import {
|
||||
downloadAllChaptersAction,
|
||||
deleteAllChaptersAction,
|
||||
followNovelAction,
|
||||
} from "../../../redux/novel/novel.actions";
|
||||
import { followNovelAction } from "../../../redux/novel/novel.actions";
|
||||
import { useTrackingStatus } from "../../../Hooks/reduxHooks";
|
||||
|
||||
import {
|
||||
@@ -39,8 +35,6 @@ const NovelInfoHeader = ({
|
||||
trackerSheetRef,
|
||||
chaptersSettingsSheetRef,
|
||||
}) => {
|
||||
const [downloadMenu, showDownloadMenu] = useState(false);
|
||||
|
||||
const { tracker, trackedNovels } = useTrackingStatus();
|
||||
|
||||
let isTracked = false;
|
||||
@@ -74,7 +68,7 @@ const NovelInfoHeader = ({
|
||||
</CoverImage>
|
||||
{!loading && (
|
||||
<>
|
||||
<Row>
|
||||
<Row style={{ justifyContent: "space-around" }}>
|
||||
<FollowButton
|
||||
theme={theme}
|
||||
followed={novel.followed}
|
||||
@@ -87,58 +81,47 @@ const NovelInfoHeader = ({
|
||||
onPress={() => trackerSheetRef.current.show()}
|
||||
/>
|
||||
)}
|
||||
<IconButton
|
||||
onPress={() =>
|
||||
WebBrowser.openBrowserAsync(novel.sourceUrl)
|
||||
}
|
||||
icon="earth"
|
||||
color={theme.colorAccent}
|
||||
size={21}
|
||||
/>
|
||||
<IconButton
|
||||
onPress={() =>
|
||||
Share.share({ message: novel.sourceUrl })
|
||||
}
|
||||
icon="share-variant"
|
||||
color={theme.colorAccent}
|
||||
size={21}
|
||||
/>
|
||||
<Menu
|
||||
visible={downloadMenu}
|
||||
onDismiss={() => showDownloadMenu(false)}
|
||||
anchor={
|
||||
<IconButton
|
||||
icon="download"
|
||||
color={theme.colorAccent}
|
||||
size={21}
|
||||
onPress={() => showDownloadMenu(true)}
|
||||
/>
|
||||
}
|
||||
contentStyle={{ backgroundColor: theme.menuColor }}
|
||||
>
|
||||
<Menu.Item
|
||||
title="Download all"
|
||||
style={{ backgroundColor: theme.menuColor }}
|
||||
titleStyle={{ color: theme.textColorPrimary }}
|
||||
<View style={{ alignItems: "center" }}>
|
||||
<IconButton
|
||||
icon="swap-vertical-variant"
|
||||
color={theme.textColorSecondary}
|
||||
size={24}
|
||||
style={{ margin: 0 }}
|
||||
onPress={() =>
|
||||
dispatch(
|
||||
downloadAllChaptersAction(
|
||||
novel.sourceId,
|
||||
novel.novelUrl,
|
||||
chapters
|
||||
)
|
||||
)
|
||||
navigation.navigate("MigrateNovel", {
|
||||
sourceId: novel.sourceId,
|
||||
novelName: novel.novelName,
|
||||
})
|
||||
}
|
||||
/>
|
||||
<Menu.Item
|
||||
title="Delete downloads"
|
||||
style={{ backgroundColor: theme.menuColor }}
|
||||
titleStyle={{ color: theme.textColorPrimary }}
|
||||
<Text
|
||||
style={{
|
||||
fontSize: 12,
|
||||
color: theme.textColorSecondary,
|
||||
}}
|
||||
>
|
||||
Migrate
|
||||
</Text>
|
||||
</View>
|
||||
<View style={{ alignItems: "center" }}>
|
||||
<IconButton
|
||||
icon="earth"
|
||||
color={theme.textColorSecondary}
|
||||
size={24}
|
||||
style={{ margin: 0 }}
|
||||
onPress={() =>
|
||||
dispatch(deleteAllChaptersAction(chapters))
|
||||
WebBrowser.openBrowserAsync(novel.sourceUrl)
|
||||
}
|
||||
/>
|
||||
</Menu>
|
||||
<Text
|
||||
style={{
|
||||
fontSize: 12,
|
||||
color: theme.textColorSecondary,
|
||||
}}
|
||||
>
|
||||
WebView
|
||||
</Text>
|
||||
</View>
|
||||
</Row>
|
||||
<NovelSummary
|
||||
summary={novel.novelSummary}
|
||||
|
||||
Reference in New Issue
Block a user