diff --git a/src/components/hideableHeader.tsx b/src/components/hideableHeader.tsx new file mode 100644 index 0000000..fe341f9 --- /dev/null +++ b/src/components/hideableHeader.tsx @@ -0,0 +1,63 @@ +import React, { useEffect, useRef } from 'react'; +import { Animated, StyleSheet } from 'react-native'; +import { useDimensions } from '../contexts'; +import styles from '../styles'; +import { useTheme } from 'react-native-paper'; + +const hideableHeaderStyles = StyleSheet.create({ + headerView: { + position: 'absolute', + top: 0, + left: 0, + right: 0, + zIndex: 100, + }, +}); + +const HideableHeader = ({ + visible = true, + children, +}: { + visible?: boolean; + children: React.ReactNode; +}) => { + const { colors } = useTheme(); + const { orientation } = useDimensions(); + + const headerAnim = useRef(new Animated.Value(visible ? 1 : 0)).current; + + useEffect(() => { + Animated.timing(headerAnim, { + toValue: visible ? 1 : 0, + duration: visible ? 200 : 150, + useNativeDriver: true, + }).start(); + }, [headerAnim, visible]); + + return ( + + {children} + + ); +}; + +export default HideableHeader; diff --git a/src/components/index.ts b/src/components/index.ts index 3d9cf86..455a959 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -1,5 +1,6 @@ export { default as FloatingActionButton } from './floatingActionButton'; export { default as HideableBottomNavigationBar } from './hideableBottomNavigationBar'; +export { default as HideableHeader } from './hideableHeader'; export { default as LoadingView } from './loadingView'; -export { default as TagChip } from './tagChip'; -export { default as TagPreview } from './tagPreview'; +export { default as TagChip } from './tags/tagChip'; +export { default as TagPreview } from './tags/tagPreview'; diff --git a/src/components/tagChip.tsx b/src/components/tags/tagChip.tsx similarity index 86% rename from src/components/tagChip.tsx rename to src/components/tags/tagChip.tsx index f3e6d36..dfb801a 100644 --- a/src/components/tagChip.tsx +++ b/src/components/tags/tagChip.tsx @@ -1,7 +1,7 @@ import React from 'react'; -import { getContrastColor } from '../utilities'; +import { getContrastColor } from '../../utilities'; import { Chip } from 'react-native-paper'; -import { Tag } from '../database'; +import { Tag } from '../../database'; import FontAwesome5 from 'react-native-vector-icons/FontAwesome5'; const TagChip = ({ tag }: { tag: Tag }) => { diff --git a/src/components/tagPreview.tsx b/src/components/tags/tagPreview.tsx similarity index 88% rename from src/components/tagPreview.tsx rename to src/components/tags/tagPreview.tsx index 89bb11d..8e9e329 100644 --- a/src/components/tagPreview.tsx +++ b/src/components/tags/tagPreview.tsx @@ -2,9 +2,9 @@ import React from 'react'; import { StyleSheet, View } from 'react-native'; import FontAwesome5 from 'react-native-vector-icons/FontAwesome5'; import { Chip } from 'react-native-paper'; -import styles from '../styles'; -import { useDimensions } from '../contexts'; -import { getContrastColor } from '../utilities'; +import styles from '../../styles'; +import { useDimensions } from '../../contexts'; +import { getContrastColor } from '../../utilities'; const tagPreviewStyles = StyleSheet.create({ chip: { diff --git a/src/screens/tags.tsx b/src/screens/tags.tsx index 86e696e..af56bbc 100644 --- a/src/screens/tags.tsx +++ b/src/screens/tags.tsx @@ -1,11 +1,11 @@ -import React, { useEffect, useRef, useState } from 'react'; +import React, { useCallback, useRef, useState } from 'react'; import { StyleSheet, View, Text, NativeSyntheticEvent, NativeScrollEvent, - Animated, + BackHandler, } from 'react-native'; import { Button, @@ -19,7 +19,12 @@ import { import { useQuery } from '@realm/react'; import { useDispatch, useSelector } from 'react-redux'; import { FlashList } from '@shopify/flash-list'; -import { TagChip } from '../components'; +import { + NavigationProp, + useFocusEffect, + useNavigation, +} from '@react-navigation/native'; +import { HideableHeader, TagChip } from '../components'; import { Tag } from '../database'; import styles from '../styles'; import { @@ -37,17 +42,8 @@ import { tagSortQuery, } from '../types'; import { getSortIcon } from '../utilities'; -import { useDimensions } from '../contexts'; -import { NavigationProp, useNavigation } from '@react-navigation/native'; const tagsStyles = StyleSheet.create({ - headerView: { - position: 'absolute', - top: 0, - left: 0, - right: 0, - zIndex: 100, - }, headerButtonView: { height: 50, }, @@ -74,8 +70,7 @@ const tagsStyles = StyleSheet.create({ const Tags = () => { const { colors } = useTheme(); - const { orientation } = useDimensions(); - const navigation = useNavigation>(); + const { navigate } = useNavigation>(); const sort = useSelector((state: RootState) => state.tags.sort); const sortDirection = useSelector( (state: RootState) => state.tags.sortDirection, @@ -101,16 +96,6 @@ const Tags = () => { setSortMenuVisible(false); }; - const sortMenuAnim = useRef(new Animated.Value(navVisisble ? 1 : 0)).current; - - useEffect(() => { - Animated.timing(sortMenuAnim, { - toValue: navVisisble ? 1 : 0, - duration: navVisisble ? 200 : 150, - useNativeDriver: true, - }).start(); - }, [navVisisble, sortMenuAnim]); - const [search, setSearch] = useState(''); const tags = useQuery( @@ -132,17 +117,33 @@ const Tags = () => { if (currentOffset <= 150) { dispatch(setNavVisible(true)); - setScrollOffset(0); - return; + } else { + const diff = currentOffset - scrollOffset; + if (Math.abs(diff) > 50) dispatch(setNavVisible(diff < 0)); } - const diff = currentOffset - scrollOffset; - if (Math.abs(diff) < 50) return; - - dispatch(setNavVisible(diff < 0)); setScrollOffset(currentOffset); }; + const flashListRef = useRef>(null); + + useFocusEffect( + useCallback(() => { + const handleBackPress = () => { + if (scrollOffset > 0) { + flashListRef.current?.scrollToOffset({ offset: 0, animated: true }); + return true; + } + return false; + }; + + BackHandler.addEventListener('hardwareBackPress', handleBackPress); + + return () => + BackHandler.removeEventListener('hardwareBackPress', handleBackPress); + }, [flashListRef, scrollOffset]), + ); + return ( { styles.fullSize, { backgroundColor: colors.background }, ]}> - + { - + ( - navigation.navigate(ROUTE.EDIT_TAG, { id: tag.id.toHexString() }) + navigate(ROUTE.EDIT_TAG, { id: tag.id.toHexString() }) }> diff --git a/src/styles.tsx b/src/styles.tsx index 7f6deb0..82a33bc 100644 --- a/src/styles.tsx +++ b/src/styles.tsx @@ -14,16 +14,16 @@ const styles = StyleSheet.create({ paddingTop: '2%', }, padding: { - padding: '5%', + padding: '4%', }, paddingHorizontal: { - paddingHorizontal: '5%', + paddingHorizontal: '4%', }, paddingVertical: { - paddingVertical: '5%', + paddingVertical: '4%', }, paddingTop: { - paddingTop: '5%', + paddingTop: '4%', }, centered: { justifyContent: 'center',