diff --git a/src/components/Common/CrossFadeView.js b/src/components/Common/CrossFadeView.js
new file mode 100644
index 00000000..c75f5271
--- /dev/null
+++ b/src/components/Common/CrossFadeView.js
@@ -0,0 +1,110 @@
+import PropTypes from "prop-types";
+import React, { PureComponent, Children } from "react";
+import { View, Animated, StyleSheet } from "react-native";
+
+export default class FadeView extends PureComponent {
+ static defaultProps = {
+ animationDuration: 225,
+
+ active: false,
+ removeHiddenSubviews: true,
+ };
+
+ static propTypes = {
+ animationDuration: PropTypes.number,
+
+ active: PropTypes.bool,
+ removeHiddenSubviews: PropTypes.bool,
+
+ children: PropTypes.oneOfType([
+ PropTypes.arrayOf(PropTypes.node),
+ PropTypes.node,
+ ]),
+ };
+
+ constructor(props) {
+ super(props);
+
+ this.renderChild = this.renderChild.bind(this);
+ this.mounted = false;
+
+ let { active } = this.props;
+
+ this.state = {
+ progress: new Animated.Value(Number(active)),
+ animating: false,
+ };
+ }
+
+ componentDidMount() {
+ this.mounted = true;
+ }
+
+ componentWillUnmount() {
+ this.mounted = false;
+ }
+
+ componentWillReceiveProps({ active, animationDuration }) {
+ let { progress } = this.state;
+
+ if (active ^ this.props.active) {
+ this.setState({ animating: true });
+
+ Animated.timing(progress, {
+ toValue: Number(active),
+ duration: animationDuration,
+ useNativeDriver: true,
+ }).start(() => {
+ if (this.mounted) {
+ this.setState({ animating: false });
+ }
+ });
+ }
+ }
+
+ renderChild(child, index) {
+ let { active, removeHiddenSubviews } = this.props;
+ let { animating, progress } = this.state;
+
+ let opacity = progress.interpolate({
+ inputRange: [0, 1],
+ outputRange: index ? [0, 1] : [1, 0],
+ });
+
+ let hidden = active ^ !!index;
+
+ if (removeHiddenSubviews) {
+ if (!animating && hidden) {
+ return null;
+ }
+ }
+
+ let pointerEvents = hidden ? "none" : "box-none";
+
+ return (
+
+ {child}
+
+ );
+ }
+
+ render() {
+ let { children, ...props } = this.props;
+
+ return (
+ {Children.map(children, this.renderChild)}
+ );
+ }
+}
+
+const styles = StyleSheet.create({
+ container: {
+ // ...StyleSheet.absoluteFillObject,
+ flexDirection: "row",
+ justifyContent: "center",
+ alignItems: "center",
+ },
+});
diff --git a/src/screens/Chapter/components/ChapterAppbar.js b/src/screens/Chapter/components/ChapterAppbar.js
index 4b4c4b79..f2ca0b42 100644
--- a/src/screens/Chapter/components/ChapterAppbar.js
+++ b/src/screens/Chapter/components/ChapterAppbar.js
@@ -2,6 +2,7 @@ import React, { useState } from "react";
import { View } from "react-native";
import { Appbar } from "react-native-paper";
+import FadeView from "../../../components/Common/CrossFadeView";
import { bookmarkChapterAction } from "../../../redux/novel/novel.actions";
const ChapterAppbar = ({
@@ -16,19 +17,20 @@ const ChapterAppbar = ({
}) => {
const [bookmarked, setBookmarked] = useState(bookmark);
- if (hide) {
- return null;
- } else {
- return (
+ return (
+
- );
- }
+
+ );
};
export default ChapterAppbar;
diff --git a/src/screens/Chapter/components/ChapterFooter.js b/src/screens/Chapter/components/ChapterFooter.js
index fa94e840..fefc27ec 100644
--- a/src/screens/Chapter/components/ChapterFooter.js
+++ b/src/screens/Chapter/components/ChapterFooter.js
@@ -1,6 +1,7 @@
import React from "react";
import { Pressable, StyleSheet, View } from "react-native";
import { IconButton } from "react-native-paper";
+import FadeView from "../../../components/Common/CrossFadeView";
const ChapterFooter = ({
hide,
@@ -22,10 +23,8 @@ const ChapterFooter = ({
radius: 50,
};
- if (hide) {
- return null;
- } else {
- return (
+ return (
+
- );
- }
+
+ );
};
export default ChapterFooter;
diff --git a/src/screens/Chapter/components/VerticalScrollbar.js b/src/screens/Chapter/components/VerticalScrollbar.js
index 3d8fd5b0..621d4b4a 100644
--- a/src/screens/Chapter/components/VerticalScrollbar.js
+++ b/src/screens/Chapter/components/VerticalScrollbar.js
@@ -3,6 +3,7 @@ import { Dimensions, View, Text, StyleSheet } from "react-native";
import Slider from "@react-native-community/slider";
import { getDeviceOrientation } from "../../../services/utils/helpers";
+import FadeView from "../../../components/Common/CrossFadeView";
const VerticalScrollbar = ({
theme,
@@ -22,84 +23,95 @@ const VerticalScrollbar = ({
setLoading(false);
};
- if (hide) {
- return null;
- } else if (getDeviceOrientation() === "potrait") {
+ if (getDeviceOrientation() === "potrait") {
return (
-
-
- {scrollPercentage}
-
-
-
- 100
-
-
+
+ {scrollPercentage}
+
+
+
+ 100
+
+
+
);
} else {
return (
-
-
- {scrollPercentage}
-
-
-
- 100
-
-
+
+
+
+ {scrollPercentage}
+
+
+
+ 100
+
+
+
);
}
};
@@ -108,11 +120,6 @@ export default VerticalScrollbar;
const styles = StyleSheet.create({
verticalSliderContainer: {
- position: "absolute",
- zIndex: 2,
- right: -(Dimensions.get("window").width / 2) + 40,
- bottom: 300,
- backgroundColor: "rgba(0,0,0,0.7)",
flexDirection: "row",
justifyContent: "flex-end",
alignItems: "center",
@@ -124,7 +131,6 @@ const styles = StyleSheet.create({
position: "absolute",
zIndex: 2,
bottom: 100,
- backgroundColor: "rgba(0,0,0,0.7)",
flexDirection: "row",
justifyContent: "flex-end",
alignItems: "center",
diff --git a/src/screens/Novel/Novel.js b/src/screens/Novel/Novel.js
index 0df48c96..33e45c77 100644
--- a/src/screens/Novel/Novel.js
+++ b/src/screens/Novel/Novel.js
@@ -44,6 +44,7 @@ import JumpToChapterModal from "./components/JumpToChapterModal";
import { Actionbar } from "../../components/Actionbar/Actionbar";
import EditInfoModal from "./components/EditInfoModal";
import { setCustomNovelCover } from "../../database/queries/NovelQueries";
+import FadeView from "../../components/Common/CrossFadeView";
const Novel = ({ route, navigation }) => {
const item = route.params;
@@ -198,26 +199,29 @@ const Novel = ({ route, navigation }) => {
{ backgroundColor: theme.colorPrimaryDark },
]}
>
- {selected.length > 0 ? (
+
{
- setSelected([]);
- }}
+ onPress={() => setSelected([])}
/>
{
}}
/>
- ) : (
+
+ {selected.length == 0 && (