Fix animated header, fix pending filter, fix QRShareModal

This commit is contained in:
minibits-cash
2026-03-11 22:13:16 +01:00
parent c1b03ac4a8
commit 5ddc3de9e0
8 changed files with 46 additions and 79 deletions
+1 -1
View File
@@ -196,7 +196,7 @@ function App() {
? require('../android/app/src/main/res/mipmap-xxhdpi/ic_launcher_golden.png') ? require('../android/app/src/main/res/mipmap-xxhdpi/ic_launcher_golden.png')
: require('../android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png')} /> : require('../android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png')} />
</View> </View>
<Text text={displayName} style={[$title]} /> <Text text={displayName} style={[$title, {paddingBottom: isAppLocked ? spacing.tiny : spacing.extraLarge}]} />
<View style={{ <View style={{
paddingHorizontal: spacing.large, paddingHorizontal: spacing.large,
paddingBottom: spacing.extraLarge, paddingBottom: spacing.extraLarge,
+12 -46
View File
@@ -1,5 +1,5 @@
import React from 'react' import React from 'react'
import { TextStyle, ViewStyle } from 'react-native' import { TextStyle, View, ViewStyle } from 'react-native'
import Animated, { import Animated, {
SharedValue, SharedValue,
useAnimatedStyle, useAnimatedStyle,
@@ -24,91 +24,57 @@ export interface AnimatedHeaderProps {
*/ */
scrollY: SharedValue<number> scrollY: SharedValue<number>
/** /**
* The scroll distance over which the animation occurs. * Header height. Title fades out over the first half of this distance.
* Defaults to spacing.screenHeight * 0.07
*/
scrollDistance?: number
/**
* Maximum header height when not scrolled.
* Defaults to spacing.screenHeight * 0.15 * Defaults to spacing.screenHeight * 0.15
*/ */
maxHeight?: number maxHeight?: number
/**
* Minimum header height when fully scrolled.
* Defaults to spacing.screenHeight * 0.08
*/
minHeight?: number
} }
/** /**
* AnimatedHeader component that provides a collapsible header with animated title. * AnimatedHeader component with a large title that fades as the user scrolls.
* Use with Animated.ScrollView and useAnimatedScrollHandler to track scroll position. * Place this as the first child inside an Animated.ScrollView so that it scrolls
* away naturally — no height animation means no layout jitter.
*/ */
export function AnimatedHeader(props: AnimatedHeaderProps) { export function AnimatedHeader(props: AnimatedHeaderProps) {
const { const {
title, title,
titleTx, titleTx,
scrollY, scrollY,
scrollDistance = spacing.screenHeight * 0.07,
maxHeight = spacing.screenHeight * 0.15, maxHeight = spacing.screenHeight * 0.15,
minHeight = spacing.screenHeight * 0.08,
} = props } = props
const headerBg = useThemeColor('header') const headerBg = useThemeColor('header')
const headerTitleColor = useThemeColor('headerTitle') const headerTitleColor = useThemeColor('headerTitle')
const animatedHeaderStyle = useAnimatedStyle(() => {
const height = interpolate(
scrollY.value,
[0, scrollDistance],
[maxHeight, minHeight],
Extrapolation.CLAMP
)
return { height }
})
const animatedTitleStyle = useAnimatedStyle(() => { const animatedTitleStyle = useAnimatedStyle(() => {
const scale = interpolate(
scrollY.value,
[0, scrollDistance],
[1, 0.75],
Extrapolation.CLAMP
)
const translateY = interpolate(
scrollY.value,
[0, scrollDistance],
[0, -spacing.extraLarge * 1.5],
Extrapolation.CLAMP
)
const opacity = interpolate( const opacity = interpolate(
scrollY.value, scrollY.value,
[0, scrollDistance * 0.8], [0, maxHeight * 0.5],
[1, 0], [1, 0],
Extrapolation.CLAMP Extrapolation.CLAMP
) )
return { return { opacity }
transform: [{ scale }, { translateY }],
opacity,
}
}) })
const titleContent = titleTx ? translate(titleTx) : title const titleContent = titleTx ? translate(titleTx) : title
return ( return (
<Animated.View style={[animatedHeaderStyle, $headerContainer, { backgroundColor: headerBg }]}> <View style={[$headerContainer, { height: maxHeight, backgroundColor: headerBg }]}>
<Animated.Text style={[animatedTitleStyle, $headerTitle, { color: headerTitleColor }]}> <Animated.Text style={[animatedTitleStyle, $headerTitle, { color: headerTitleColor }]}>
{titleContent} {titleContent}
</Animated.Text> </Animated.Text>
</Animated.View> </View>
) )
} }
const $headerContainer: ViewStyle = { const $headerContainer: ViewStyle = {
alignItems: 'center', alignItems: 'center',
justifyContent: 'center',
} }
const $headerTitle: TextStyle = { const $headerTitle: TextStyle = {
fontSize: verticalScale(32), fontSize: verticalScale(32),
lineHeight: verticalScale(44), lineHeight: verticalScale(44),
fontFamily: typography.primary?.medium, fontFamily: typography.primary?.medium,
marginBottom: spacing.extraLarge * 2,
} }
+1 -1
View File
@@ -228,7 +228,7 @@ export function Header(props: HeaderProps) {
} }
const opacity = interpolate( const opacity = interpolate(
scrollY.value, scrollY.value,
[0, scrollDistance], [scrollDistance * 0.5, scrollDistance],
[0, 1], [0, 1],
Extrapolation.CLAMP Extrapolation.CLAMP
) )
+1 -1
View File
@@ -47,7 +47,7 @@ export const QRShareModal = (props: QRShareModalProps) => {
isVisible={isVisible} isVisible={isVisible}
ContentComponent={ ContentComponent={
<> <>
{shareModalTx || shareModalTitle && ( {(shareModalTx || shareModalTitle) && (
<Text <Text
tx={shareModalTx} tx={shareModalTx}
text={shareModalTitle} text={shareModalTitle}
+9 -9
View File
@@ -31,7 +31,7 @@ type Props = StaticScreenProps<undefined>
export const PrivacyScreen = observer(function PrivacyScreen({ route }: Props) { export const PrivacyScreen = observer(function PrivacyScreen({ route }: Props) {
const navigation = useNavigation() const navigation = useNavigation()
const scrollY = useSharedValue(0) const scrollY = useSharedValue(0)
const HEADER_SCROLL_DISTANCE = spacing.screenHeight * 0.07 const HEADER_SCROLL_DISTANCE = spacing.screenHeight * 0.15
useLayoutEffect(() => { useLayoutEffect(() => {
navigation.setOptions({ navigation.setOptions({
@@ -205,16 +205,15 @@ export const PrivacyScreen = observer(function PrivacyScreen({ route }: Props) {
return ( return (
<Screen style={$screen} preset='fixed'> <Screen style={$screen} preset='fixed'>
<AnimatedHeader
titleTx="privacyScreen_title"
scrollY={scrollY}
scrollDistance={HEADER_SCROLL_DISTANCE}
/>
<Animated.ScrollView <Animated.ScrollView
style={$contentContainer} style={$contentContainer}
onScroll={scrollHandler} onScroll={scrollHandler}
scrollEventThrottle={16} scrollEventThrottle={16}
> >
<AnimatedHeader
titleTx="privacyScreen_title"
scrollY={scrollY}
/>
{/*<Card {/*<Card
style={[$card, {marginTop: spacing.medium}]} style={[$card, {marginTop: spacing.medium}]}
ContentComponent={ ContentComponent={
@@ -288,7 +287,7 @@ export const PrivacyScreen = observer(function PrivacyScreen({ route }: Props) {
} }
/>*/} />*/}
<Card <Card
style={[$card, {marginTop: spacing.medium}]} style={[$card, {marginTop: -spacing.extraLarge * 2}]}
ContentComponent={ ContentComponent={
<> <>
<ListItem <ListItem
@@ -425,13 +424,14 @@ const $screen: ViewStyle = {}
const $contentContainer: TextStyle = { const $contentContainer: TextStyle = {
flex: 1, flex: 1,
marginTop: -spacing.extraLarge * 2, // marginTop: -spacing.extraLarge * 2,
padding: spacing.extraSmall, // padding: spacing.extraSmall,
// alignItems: 'center', // alignItems: 'center',
} }
const $card: ViewStyle = { const $card: ViewStyle = {
marginBottom: 0, marginBottom: 0,
marginHorizontal: spacing.small,
} }
const $bottomModal: ViewStyle = { const $bottomModal: ViewStyle = {
+10 -9
View File
@@ -39,7 +39,7 @@ type Props = StaticScreenProps<undefined>
export const RecoveryOptionsScreen = observer(function RecoveryOptionsScreen(_: Props) { export const RecoveryOptionsScreen = observer(function RecoveryOptionsScreen(_: Props) {
const navigation = useNavigation() const navigation = useNavigation()
const scrollY = useSharedValue(0) const scrollY = useSharedValue(0)
const HEADER_SCROLL_DISTANCE = spacing.screenHeight * 0.07 const HEADER_SCROLL_DISTANCE = spacing.screenHeight * 0.15
useLayoutEffect(() => { useLayoutEffect(() => {
navigation.setOptions({ navigation.setOptions({
@@ -327,18 +327,18 @@ export const RecoveryOptionsScreen = observer(function RecoveryOptionsScreen(_:
return ( return (
<Screen preset="fixed" contentContainerStyle={$screen}> <Screen preset="fixed" contentContainerStyle={$screen}>
<AnimatedHeader
titleTx="recoveryOptionsTitle"
scrollY={scrollY}
scrollDistance={HEADER_SCROLL_DISTANCE}
/>
<Animated.ScrollView <Animated.ScrollView
style={$contentContainer} style={$contentContainer}
//contentContainerStyle={{ paddingBottom: HEADER_SCROLL_DISTANCE }}
onScroll={scrollHandler} onScroll={scrollHandler}
scrollEventThrottle={16} scrollEventThrottle={16}
> >
<AnimatedHeader
titleTx="recoveryOptionsTitle"
scrollY={scrollY}
/>
<Card <Card
style={$card} style={[$card, {marginTop: -spacing.extraLarge * 2}]}
HeadingComponent={ HeadingComponent={
<ListItem <ListItem
tx="seedRecoveryOptions" tx="seedRecoveryOptions"
@@ -601,8 +601,8 @@ const $screen: ViewStyle = {
const $contentContainer: TextStyle = { const $contentContainer: TextStyle = {
//flex: 1, //flex: 1,
marginTop: -spacing.extraLarge * 2, // marginTop: -spacing.extraLarge * 2,
padding: spacing.extraSmall, // padding: spacing.extraSmall,
// alignItems: 'center', // alignItems: 'center',
} }
@@ -641,6 +641,7 @@ const $quoteInput: TextStyle = {
const $card: ViewStyle = { const $card: ViewStyle = {
marginBottom: spacing.small, marginBottom: spacing.small,
marginHorizontal: spacing.small,
} }
const $rightContainer: ViewStyle = { const $rightContainer: ViewStyle = {
+9 -9
View File
@@ -31,7 +31,7 @@ type Props = StaticScreenProps<undefined>
export const SettingsScreen = observer(function SettingsScreen({ route }: Props) { export const SettingsScreen = observer(function SettingsScreen({ route }: Props) {
const navigation = useNavigation() const navigation = useNavigation()
const scrollY = useSharedValue(0) const scrollY = useSharedValue(0)
const HEADER_SCROLL_DISTANCE = spacing.screenHeight * 0.07 const HEADER_SCROLL_DISTANCE = spacing.screenHeight * 0.15
useLayoutEffect(() => { useLayoutEffect(() => {
navigation.setOptions({ navigation.setOptions({
@@ -315,18 +315,17 @@ export const SettingsScreen = observer(function SettingsScreen({ route }: Props)
return ( return (
<Screen contentContainerStyle={$screen} preset='fixed'> <Screen contentContainerStyle={$screen} preset='fixed'>
<AnimatedHeader
titleTx="settingsScreen_title"
scrollY={scrollY}
scrollDistance={HEADER_SCROLL_DISTANCE}
/>
<Animated.ScrollView <Animated.ScrollView
style={$contentContainer} style={$contentContainer}
onScroll={scrollHandler} onScroll={scrollHandler}
scrollEventThrottle={16} scrollEventThrottle={16}
> >
<AnimatedHeader
titleTx="settingsScreen_title"
scrollY={scrollY}
/>
<Card <Card
style={$card} style={[$card, {marginTop: -spacing.extraLarge * 2}]}
ContentComponent={ ContentComponent={
<> <>
<ListItem <ListItem
@@ -595,12 +594,13 @@ const $screen: ViewStyle = {
} }
const $contentContainer: TextStyle = { const $contentContainer: TextStyle = {
marginTop: -spacing.extraLarge * 2, //marginTop: -spacing.extraLarge * 2,
padding: spacing.extraSmall, //padding: spacing.extraSmall,
} }
const $card: ViewStyle = { const $card: ViewStyle = {
marginHorizontal: spacing.small,
//paddingVertical: 0, //paddingVertical: 0,
} }
+3 -3
View File
@@ -120,9 +120,9 @@ export const TranHistoryScreen = observer(function TranHistoryScreen({ route }:
log.trace('[initFilter] toggleShowPendingOnly ') log.trace('[initFilter] toggleShowPendingOnly ')
toggleShowPendingOnly() toggleShowPendingOnly()
//@ts-ignore //@ts-ignore
/* navigation.setParams({ navigation.setParams({
showPending: undefined, showPending: undefined,
})*/ })
} }
}, []) }, [])
@@ -349,7 +349,7 @@ export const TranHistoryScreen = observer(function TranHistoryScreen({ route }:
) : ( ) : (
<Button <Button
preset="secondary" preset="secondary"
onPress={addTransactionsToList} onPress={showPendingOnly ? addPendingTransactionsToList : addTransactionsToList}
tx="tranHistory_viewMore" tx="tranHistory_viewMore"
style={{minHeight: 25, paddingVertical: spacing.tiny}} style={{minHeight: 25, paddingVertical: spacing.tiny}}
textStyle={{fontSize: 14}} textStyle={{fontSize: 14}}