REF: Animated scroll Header

This commit is contained in:
Marcos Rodriguez Velez 2024-06-16 11:44:55 -04:00
parent 247967b099
commit 30e6b3baa3
No known key found for this signature in database
GPG key ID: 6030B2F48CCE86D7
5 changed files with 77 additions and 43 deletions

View file

@ -1,6 +1,5 @@
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import { StyleSheet, Text, Animated } from 'react-native';
import loc from '../loc';
import PlusIcon from './icons/PlusIcon';
import { useTheme } from './themes';
@ -9,9 +8,11 @@ interface HeaderProps {
leftText: string;
isDrawerList?: boolean;
onNewWalletPress?: () => void;
scrollY?: Animated.Value;
staticText?: boolean;
}
export const Header: React.FC<HeaderProps> = ({ leftText, isDrawerList, onNewWalletPress }) => {
export const Header: React.FC<HeaderProps> = ({ leftText, isDrawerList, onNewWalletPress, scrollY, staticText = false }) => {
const { colors } = useTheme();
const styleWithProps = StyleSheet.create({
root: {
@ -24,11 +25,31 @@ export const Header: React.FC<HeaderProps> = ({ leftText, isDrawerList, onNewWal
},
});
const HEADER_MAX_HEIGHT = 70;
const HEADER_MIN_HEIGHT = 0;
const HEADER_SCROLL_DISTANCE = HEADER_MAX_HEIGHT - HEADER_MIN_HEIGHT;
const headerHeightAnimated = scrollY?.interpolate({
inputRange: [0, HEADER_SCROLL_DISTANCE],
outputRange: [HEADER_MAX_HEIGHT, HEADER_MIN_HEIGHT],
extrapolate: 'clamp',
});
const headerOpacity = scrollY?.interpolate({
inputRange: [0, HEADER_SCROLL_DISTANCE / 2, HEADER_SCROLL_DISTANCE],
outputRange: [1, 0.5, 0],
extrapolate: 'clamp',
});
return (
<View style={[styles.root, styleWithProps.root]}>
<Text style={[styles.text, styleWithProps.text]}>{leftText}</Text>
<Animated.View style={[styles.root, styleWithProps.root, !staticText && { height: headerHeightAnimated, opacity: headerOpacity }]}>
{staticText ? (
<Text style={[styles.text, styleWithProps.text, styles.title]}>{leftText}</Text>
) : (
<Animated.Text style={[styles.text, styleWithProps.text, styles.title]}>{leftText}</Animated.Text>
)}
{onNewWalletPress && <PlusIcon accessibilityRole="button" accessibilityLabel={loc.wallets.add_title} onPress={onNewWalletPress} />}
</View>
</Animated.View>
);
};
@ -45,4 +66,8 @@ const styles = StyleSheet.create({
fontWeight: 'bold',
fontSize: 34,
},
title: {
fontSize: 34,
fontWeight: '600',
},
});

View file

@ -1,11 +1,10 @@
import React, { useCallback, useMemo } from 'react';
import React, { useMemo } from 'react';
import { NativeStackNavigationOptions } from '@react-navigation/native-stack';
import { I18nManager, View } from 'react-native';
import { I18nManager } from 'react-native';
import { isDesktop } from '../blue_modules/environment';
import HeaderRightButton from '../components/HeaderRightButton';
import navigationStyle, { CloseButtonPosition } from '../components/navigationStyle';
import { useTheme } from '../components/themes';
import { useExtendedNavigation } from '../hooks/useExtendedNavigation';
import loc from '../loc';
import LdkInfo from '../screen/lnd/ldkInfo';
import LNDViewAdditionalInvoiceInformation from '../screen/lnd/lndViewAdditionalInvoiceInformation';
@ -64,41 +63,26 @@ import SignVerifyStackRoot from './SignVerifyStack';
import ViewEditMultisigCosignersStackRoot from './ViewEditMultisigCosignersStack';
import WalletExportStack from './WalletExportStack';
import WalletXpubStackRoot from './WalletXpubStack';
import PlusIcon from '../components/icons/PlusIcon';
import SettingsButton from '../components/icons/SettingsButton';
const DetailViewStackScreensStack = () => {
const theme = useTheme();
const navigation = useExtendedNavigation();
const SaveButton = useMemo(() => <HeaderRightButton testID="SaveButton" disabled={true} title={loc.wallets.details_save} />, []);
const DetailButton = useMemo(() => <HeaderRightButton testID="DetailButton" disabled={true} title={loc.send.create_details} />, []);
const navigateToAddWallet = useCallback(() => {
navigation.navigate('AddWalletRoot');
}, [navigation]);
const useWalletListScreenOptions = useMemo<NativeStackNavigationOptions>(() => {
const RightBarButtons = (
<>
<PlusIcon accessibilityRole="button" accessibilityLabel={loc.wallets.add_title} onPress={navigateToAddWallet} />
<View style={styles.width24} />
<SettingsButton />
</>
);
return {
title: loc.wallets.wallets,
navigationBarColor: theme.colors.navigationBarColor,
headerShown: !isDesktop,
headerLargeTitle: true,
headerStyle: {
backgroundColor: theme.colors.customHeader,
},
headerRight: I18nManager.isRTL ? undefined : () => RightBarButtons,
headerLeft: I18nManager.isRTL ? () => RightBarButtons : undefined,
headerRight: I18nManager.isRTL ? undefined : () => <SettingsButton />,
headerLeft: I18nManager.isRTL ? () => <SettingsButton /> : undefined,
};
}, [navigateToAddWallet, theme.colors.customHeader, theme.colors.navigationBarColor]);
}, [theme.colors.customHeader, theme.colors.navigationBarColor]);
const walletListScreenOptions = useWalletListScreenOptions;
return (
@ -161,8 +145,6 @@ const DetailViewStackScreensStack = () => {
backgroundColor: theme.colors.customHeader,
},
headerRight: () => DetailButton,
headerBackTitleStyle: { fontSize: 0 },
headerBackTitleVisible: true,
})(theme)}
/>
<DetailViewStack.Screen name="CPFP" component={CPFP} options={CPFP.navigationOptions(theme)} />
@ -268,9 +250,6 @@ const DetailViewStackScreensStack = () => {
options={navigationStyle({
headerTransparent: true,
title: loc.settings.header,
// workaround to deal with the flicker when headerBackTitleVisible is false
headerBackTitleStyle: { fontSize: 0 },
headerBackTitleVisible: true,
headerShadowVisible: false,
headerLargeTitle: true,
animationTypeForReplace: 'push',
@ -388,9 +367,3 @@ const DetailViewStackScreensStack = () => {
};
export default DetailViewStackScreensStack;
const styles = {
width24: {
width: 24,
},
};

View file

@ -102,7 +102,7 @@ const SettingsPrivacy: React.FC = () => {
<ScrollView style={[styles.root, styleHooks.root]} contentInsetAdjustmentBehavior="automatic" automaticallyAdjustContentInsets>
{Platform.OS === 'android' ? (
<View style={styles.headerContainer}>
<Header leftText={loc.settings.general} />
<Header leftText={loc.settings.general} staticText />
</View>
) : null}

View file

@ -142,7 +142,7 @@ const DrawerList: React.FC<DrawerListProps> = memo(({ navigation }) => {
showsHorizontalScrollIndicator={false}
showsVerticalScrollIndicator={false}
>
<Header leftText={loc.wallets.list_title} onNewWalletPress={onNewWalletPress} isDrawerList />
<Header leftText={loc.wallets.list_title} onNewWalletPress={onNewWalletPress} isDrawerList staticText />
<WalletsCarousel
// @ts-ignore: refactor later
data={state.wallets.concat(false as any)}

View file

@ -1,6 +1,16 @@
import React, { useCallback, useEffect, useReducer, useRef } from 'react';
import React, { useCallback, useEffect, useMemo, useReducer, useRef } from 'react';
import { useFocusEffect, useIsFocused, useRoute } from '@react-navigation/native';
import { findNodeHandle, Image, InteractionManager, SectionList, StyleSheet, Text, useWindowDimensions, View } from 'react-native';
import {
findNodeHandle,
Image,
InteractionManager,
SectionList,
StyleSheet,
Text,
useWindowDimensions,
View,
Animated,
} from 'react-native';
import A from '../../blue_modules/analytics';
import BlueClipboard from '../../blue_modules/clipboard';
import { isDesktop } from '../../blue_modules/environment';
@ -21,6 +31,7 @@ import { NativeStackNavigationProp } from '@react-navigation/native-stack';
import { DetailViewStackParamList } from '../../navigation/DetailViewStackParamList';
import { useExtendedNavigation } from '../../hooks/useExtendedNavigation';
import { useStorage } from '../../hooks/context/useStorage';
import { Header } from '../../components/Header';
const WalletsListSections = { CAROUSEL: 'CAROUSEL', TRANSACTIONS: 'TRANSACTIONS' };
@ -106,13 +117,15 @@ const WalletsList: React.FC = () => {
} = useStorage();
const { width } = useWindowDimensions();
const { colors, scanImage } = useTheme();
const { navigate } = useExtendedNavigation<NavigationProps>();
const { navigate, setOptions } = useExtendedNavigation<NavigationProps>();
const isFocused = useIsFocused();
const routeName = useRoute().name;
const dataSource = getTransactions(undefined, 10);
const walletsCount = useRef<number>(wallets.length);
const walletActionButtonsRef = useRef<any>();
const scrollY = useRef(new Animated.Value(0)).current;
const stylesHook = StyleSheet.create({
walletsListWrapper: {
backgroundColor: colors.brandingColor,
@ -149,6 +162,21 @@ const WalletsList: React.FC = () => {
walletsCount.current = wallets.length;
}, [wallets]);
const HeaderTitle = useMemo(() => {
const titleOpacity = scrollY.interpolate({
inputRange: [0, 200],
outputRange: [0, 1],
extrapolate: 'clamp',
});
return <Animated.Text style={[styles.nativeHeaderTitle, { opacity: titleOpacity }]}>{loc.wallets.list_title}</Animated.Text>;
}, [scrollY]);
useEffect(() => {
setOptions({
headerTitle: () => HeaderTitle,
});
}, [HeaderTitle, scrollY, setOptions]);
const verifyBalance = useCallback(() => {
if (getBalance() !== 0) {
A(A.ENUM.GOT_NONZERO_BALANCE);
@ -405,6 +433,7 @@ const WalletsList: React.FC = () => {
return (
<View style={styles.root}>
<Header leftText={loc.wallets.list_title} onNewWalletPress={() => navigate('AddWalletRoot')} scrollY={scrollY} />
<View style={[styles.walletsListWrapper, stylesHook.walletsListWrapper]}>
<SectionList<any | string, SectionData>
removeClippedSubviews
@ -421,6 +450,8 @@ const WalletsList: React.FC = () => {
windowSize={21}
maxToRenderPerBatch={10}
updateCellsBatchingPeriod={50}
onScroll={Animated.event([{ nativeEvent: { contentOffset: { y: scrollY } } }], { useNativeDriver: false })}
scrollEventThrottle={16}
/>
{renderScanButton()}
</View>
@ -473,4 +504,9 @@ const styles = StyleSheet.create({
transaction: {
marginHorizontal: 0,
},
nativeHeaderTitle: {
fontSize: 17,
fontWeight: '600',
color: 'black', // adjust color if necessary
},
});