Make further screens immersive

This commit is contained in:
minibits-cash
2026-07-10 14:50:16 +02:00
parent 51414feda7
commit fb0126b122
9 changed files with 131 additions and 94 deletions

View File

@@ -1 +0,0 @@
<EFBFBD><EFBFBD>

View File

@@ -1,6 +1,8 @@
import {observer} from 'mobx-react-lite'
import React, {FC, useEffect, useState} from 'react'
import {Alert, Platform, ScrollView, TextStyle, View, ViewStyle} from 'react-native'
import React, {FC, useEffect, useLayoutEffect, useState} from 'react'
import {Alert, Platform, TextStyle, View, ViewStyle} from 'react-native'
import Animated, {useSharedValue} from 'react-native-reanimated'
import {useTabBarInset, useTabBarScrollHandler} from '../navigation/tabBarVisibility'
import {colors, spacing, useThemeColor} from '../theme'
import {
APP_ENV,
@@ -20,8 +22,9 @@ import {
InfoModal,
BottomModal,
Button,
Header,
AnimatedHeader,
} from '../components'
import {useHeader} from '../utils/useHeader'
import {rootStoreInstance, useStores} from '../models'
import {translate} from '../i18n'
import AppError from '../utils/AppError'
@@ -41,10 +44,23 @@ type Props = StaticScreenProps<undefined>
export const DeveloperScreen = observer(function DeveloperScreen({ route }: Props) {
const navigation = useNavigation()
useHeader({
leftIcon: 'faArrowLeft',
onLeftPress: () => navigation.goBack(),
})
const scrollY = useSharedValue(0)
const HEADER_SCROLL_DISTANCE = spacing.screenHeight * 0.15
useLayoutEffect(() => {
navigation.setOptions({
headerShown: true,
header: () => (
<Header
titleTx="developerScreen_title"
leftIcon="faArrowLeft"
onLeftPress={() => navigation.goBack()}
scrollY={scrollY}
scrollDistance={HEADER_SCROLL_DISTANCE}
/>
),
})
}, [])
const {transactionsStore, userSettingsStore, proofsStore, walletProfileStore, authStore} = useStores()
const rootStore = useStores()
@@ -286,23 +302,26 @@ export const DeveloperScreen = observer(function DeveloperScreen({ route }: Prop
setError(e)
}
const headerBg = useThemeColor('header')
const iconSelectedColor = useThemeColor('button')
const iconColor = useThemeColor('textDim')
const headerTitle = useThemeColor('headerTitle')
const scrollHandler = useTabBarScrollHandler(scrollY)
const tabBarInset = useTabBarInset()
return (
<Screen style={$screen} preset='fixed'>
<View style={[$headerContainer, {backgroundColor: headerBg}]}>
<Text
preset="heading"
tx="developerScreen_title"
style={{color: headerTitle}}
<Screen style={$screen} preset='fixed' contentUnderTabBar>
<Animated.ScrollView
style={$contentContainer}
contentContainerStyle={{paddingBottom: tabBarInset}}
onScroll={scrollHandler}
scrollEventThrottle={16}
>
<AnimatedHeader
titleTx="developerScreen_title"
scrollY={scrollY}
/>
</View>
<ScrollView style={$contentContainer}>
<Card
style={[$card]}
style={[$card, {marginTop: -spacing.extraLarge * 1.5}]}
HeadingComponent={
<ListItem
tx="developerScreen_info"
@@ -423,7 +442,7 @@ Sentry id: ${walletProfileStore.walletId}
</>
}
/>
</ScrollView>
</Animated.ScrollView>
<BottomModal
isVisible={isLogLevelSelectorVisible ? true : false}
style={{alignItems: 'stretch'}}
@@ -477,24 +496,18 @@ Sentry id: ${walletProfileStore.walletId}
})
const $screen: ViewStyle = {
flex: 1,
}
const $headerContainer: TextStyle = {
alignItems: 'center',
paddingBottom: spacing.medium,
height: spacing.screenHeight * 0.15,
}
const $contentContainer: TextStyle = {
flex: 1,
marginTop: -spacing.extraLarge * 2,
padding: spacing.extraSmall,
// alignItems: 'center',
}
// The horizontal inset used to come from $contentContainer's padding, which now has
// to stay clear so the AnimatedHeader's background spans the full width.
const $card: ViewStyle = {
marginBottom: 0,
marginHorizontal: spacing.extraSmall,
}
const $item: ViewStyle = {

View File

@@ -7,7 +7,6 @@ import {
} from 'react-native'
import Animated, {
useSharedValue,
useAnimatedScrollHandler,
} from 'react-native-reanimated'
import notifee from '@notifee/react-native'
import {useThemeColor, spacing, colors} from '../theme'
@@ -34,6 +33,7 @@ import {StaticScreenProps, useNavigation} from '@react-navigation/native'
import {MintBalanceSelector} from './Mints/MintBalanceSelector'
import {MintBalance} from '../models/Mint'
import {MintUnit} from '../services/wallet/currency'
import { useTabBarInset, useTabBarScrollHandler } from '../navigation/tabBarVisibility'
const OPTIMIZE_DENOMINATION_THRESHOLD = 5
@@ -182,16 +182,14 @@ export const OptimizeEcashScreen = function OptimizeEcash(_props: Props) {
const hint = useThemeColor('textDim')
const scrollHandler = useAnimatedScrollHandler({
onScroll: (event) => {
scrollY.value = event.contentOffset.y
},
})
const scrollHandler = useTabBarScrollHandler(scrollY)
const tabBarInset = useTabBarInset()
return (
<Screen contentContainerStyle={$screen} preset="fixed">
<Screen contentContainerStyle={$screen} contentUnderTabBar>
<Animated.ScrollView
style={$contentContainer}
contentContainerStyle={{paddingBottom: tabBarInset}}
onScroll={scrollHandler}
scrollEventThrottle={16}
>
@@ -313,11 +311,11 @@ export const OptimizeEcashScreen = function OptimizeEcash(_props: Props) {
}
const $screen: ViewStyle = {
// flex: 1,
//flex: 1,
}
const $contentContainer: TextStyle = {
//flex: 1,
//flex: 1,
}
const $card: ViewStyle = {

View File

@@ -3,8 +3,8 @@ import React, {FC, useEffect, useState, useLayoutEffect} from 'react'
import {Switch, TextStyle, View, ViewStyle} from 'react-native'
import Animated, {
useSharedValue,
useAnimatedScrollHandler,
} from 'react-native-reanimated'
import {useTabBarInset, useTabBarScrollHandler} from '../navigation/tabBarVisibility'
import {colors, spacing, useThemeColor} from '../theme'
import {
ListItem,
@@ -197,16 +197,14 @@ export const PrivacyScreen = observer(function PrivacyScreen({ route }: Props) {
const iconColor = useThemeColor('textDim')
const scrollHandler = useAnimatedScrollHandler({
onScroll: (event) => {
scrollY.value = event.contentOffset.y
},
})
const scrollHandler = useTabBarScrollHandler(scrollY)
const tabBarInset = useTabBarInset()
return (
<Screen style={$screen} preset='fixed'>
<Screen style={$screen} preset='fixed' contentUnderTabBar>
<Animated.ScrollView
style={$contentContainer}
contentContainerStyle={{paddingBottom: tabBarInset}}
onScroll={scrollHandler}
scrollEventThrottle={16}
>
@@ -287,7 +285,7 @@ export const PrivacyScreen = observer(function PrivacyScreen({ route }: Props) {
}
/>*/}
<Card
style={[$card, {marginTop: -spacing.extraLarge * 2}]}
style={[$card, {marginTop: -spacing.extraLarge * 1.5}]}
ContentComponent={
<>
<ListItem
@@ -422,11 +420,7 @@ export const PrivacyScreen = observer(function PrivacyScreen({ route }: Props) {
const $screen: ViewStyle = {}
const $contentContainer: TextStyle = {
flex: 1,
// marginTop: -spacing.extraLarge * 2,
// padding: spacing.extraSmall,
// alignItems: 'center',
const $contentContainer: TextStyle = {
}
const $card: ViewStyle = {

View File

@@ -3,7 +3,6 @@ import React, {useState, useEffect, useRef, useLayoutEffect} from 'react'
import {Platform, TextInput, TextStyle, View, ViewStyle} from 'react-native'
import Animated, {
useSharedValue,
useAnimatedScrollHandler,
} from 'react-native-reanimated'
import notifee, { AndroidImportance } from '@notifee/react-native'
import {spacing, useThemeColor, colors} from '../theme'
@@ -33,6 +32,7 @@ import { MintBalanceSelector } from './Mints/MintBalanceSelector'
import { MintBalance } from '../models/Mint'
import { MintUnit } from '../services/wallet/currency'
import Clipboard from '@react-native-clipboard/clipboard'
import { useTabBarInset, useTabBarScrollHandler } from '../navigation/tabBarVisibility'
type Props = StaticScreenProps<undefined>
@@ -315,17 +315,15 @@ export const RecoveryOptionsScreen = observer(function RecoveryOptionsScreen(_:
const mintsModalBg = useThemeColor('background')
const inputText = useThemeColor('text')
const scrollHandler = useAnimatedScrollHandler({
onScroll: (event) => {
scrollY.value = event.contentOffset.y
},
})
const scrollHandler = useTabBarScrollHandler(scrollY)
const tabBarInset = useTabBarInset()
return (
<Screen preset="fixed" contentContainerStyle={$screen}>
<Screen contentContainerStyle={$screen} contentUnderTabBar>
<Animated.ScrollView
style={$contentContainer}
//contentContainerStyle={{ paddingBottom: HEADER_SCROLL_DISTANCE }}
contentContainerStyle={{paddingBottom: tabBarInset}}
onScroll={scrollHandler}
scrollEventThrottle={16}
>
@@ -334,7 +332,7 @@ export const RecoveryOptionsScreen = observer(function RecoveryOptionsScreen(_:
scrollY={scrollY}
/>
<Card
style={[$card, {marginTop: -spacing.extraLarge * 2}]}
style={[$card, {marginTop: -spacing.extraLarge * 1.5}]}
HeadingComponent={
<ListItem
tx="seedRecoveryOptions"
@@ -592,14 +590,11 @@ export const RecoveryOptionsScreen = observer(function RecoveryOptionsScreen(_:
)
const $screen: ViewStyle = {
// flex: 1,
}
const $contentContainer: TextStyle = {
//flex: 1,
// marginTop: -spacing.extraLarge * 2,
// padding: spacing.extraSmall,
// alignItems: 'center',
}
const $mintsContainer: TextStyle = {

View File

@@ -214,14 +214,14 @@ export const RelaysScreen = observer(function RelaysScreen({ route }: Props) {
LeftAccessory={() => (
<Icon
icon='faPlus'
size={spacing.large}
size={spacing.medium}
color={mainButtonIcon}
/>
)}
onPress={gotoAdd}
style={[{backgroundColor: mainButtonColor, borderWidth: 1, borderColor: screenBg}, $buttonNew]}
//style={[{backgroundColor: mainButtonColor, borderWidth: 1, borderColor: screenBg}, $buttonNew]}
preset='tertiary'
text='Add'
tx='buttonAdd'
/>
</View>
</View>

View File

@@ -307,7 +307,7 @@ export const SettingsScreen = observer(function SettingsScreen({ route }: Props)
const tabBarInset = useTabBarInset()
return (
<Screen contentContainerStyle={$screen} preset='fixed' contentUnderTabBar>
<Screen contentContainerStyle={$screen} contentUnderTabBar>
<Animated.ScrollView
style={$contentContainer}
contentContainerStyle={{paddingBottom: tabBarInset}}

View File

@@ -6,8 +6,7 @@ import {
LayoutAnimation,
Linking,
Platform,
Pressable,
ScrollView,
Pressable,
TextInput,
TextStyle,
UIManager,
@@ -16,6 +15,13 @@ import {
} from 'react-native'
import Clipboard from '@react-native-clipboard/clipboard'
import JSONTree from 'react-native-json-tree'
import Animated, {
Extrapolation,
interpolate,
useAnimatedStyle,
useSharedValue,
} from 'react-native-reanimated'
import {useTabBarInset, useTabBarScrollHandler} from '../navigation/tabBarVisibility'
import {colors, spacing, typography, useThemeColor} from '../theme'
import EventEmitter from '../utils/eventEmitter'
import {
@@ -76,7 +82,10 @@ export const TranDetailScreen = observer(function TranDetailScreen({ route }: Pr
const navigation = useNavigation()
const {id, prevScreen} = route.params
const {transactionsStore, mintsStore} = useStores()
const scrollY = useSharedValue(0)
const HEADER_SCROLL_DISTANCE = spacing.screenHeight * 0.15
const noteInputRef = useRef<TextInput>(null)
const [transaction, setTransaction] = useState<Transaction>()
@@ -233,8 +242,22 @@ export const TranDetailScreen = observer(function TranDetailScreen({ route }: Pr
const inputText = useThemeColor('text')
const statusColor = useThemeColor('header')
const scrollHandler = useTabBarScrollHandler(scrollY)
const tabBarInset = useTabBarInset()
// Mirrors AnimatedHeader: the amount fades over the first half of the header's
// height while the block itself scrolls away, so there is no layout jitter.
const animatedAmount = useAnimatedStyle(() => ({
opacity: interpolate(
scrollY.value,
[0, HEADER_SCROLL_DISTANCE * 0.5],
[1, 0],
Extrapolation.CLAMP,
),
}))
return (
<Screen contentContainerStyle={$screen} preset="fixed">
<Screen contentContainerStyle={$screen} preset="fixed" contentUnderTabBar>
{transaction && (
<>
<MintHeader
@@ -243,9 +266,15 @@ export const TranDetailScreen = observer(function TranDetailScreen({ route }: Pr
hideBalance={true}
onBackPress={onBack}
/>
<View style={[$headerContainer, {
backgroundColor: headerBg,
justifyContent: 'space-around',
<Animated.ScrollView
style={$contentContainer}
contentContainerStyle={{paddingBottom: tabBarInset}}
onScroll={scrollHandler}
scrollEventThrottle={16}
>
<Animated.View style={[$headerContainer, animatedAmount, {
backgroundColor: headerBg,
justifyContent: 'space-around',
paddingBottom: spacing.huge
}]}
>
@@ -278,11 +307,10 @@ export const TranDetailScreen = observer(function TranDetailScreen({ route }: Pr
]}
/>
</View>
)}
</View>
<ScrollView style={$contentContainer}>
)}
</Animated.View>
<Card
style={$actionCard}
style={[$actionCard, {marginTop: -spacing.extraLarge * 1.5}]}
ContentComponent={
<View style={$noteContainer}>
<TextInput
@@ -480,7 +508,7 @@ export const TranDetailScreen = observer(function TranDetailScreen({ route }: Pr
}
/>
)}
</ScrollView>
</Animated.ScrollView>
</>
)}
{error && <ErrorModal error={error} />}
@@ -1974,12 +2002,16 @@ const $headerContainer: TextStyle = {
alignItems: 'center',
paddingBottom: spacing.medium,
height: spacing.screenHeight * 0.15,
// Cancels $contentContainer's padding so the header's background still meets the
// MintHeader above it and spans the full width, now that it scrolls inside the
// scroll view rather than sitting above it.
marginHorizontal: -spacing.extraSmall,
marginTop: -spacing.extraSmall,
}
const $contentContainer: TextStyle = {
// flex: 1,
flex: 1,
padding: spacing.extraSmall,
marginTop: -spacing.extraLarge * 1.5,
paddingBottom: spacing.medium,
}

View File

@@ -755,7 +755,8 @@ export const WalletScreen = observer(function WalletScreen({ route }: Props) {
/>
</>
}
style={isNwcCompact ? [$nwcCard, $nwcCardCompact] : $nwcCard}
//style={isNwcCompact ? [$nwcCard, $nwcCardCompact] : $nwcCard}
style={$nwcCardCompact}
/>
)
@@ -1241,8 +1242,8 @@ const $headerContainer: TextStyle = {
const $tabContainer: TextStyle = {
marginTop: -spacing.extraLarge * 1.5,
paddingTop: spacing.small,
//borderWidth: 1,
//borderColor: 'green',
// borderWidth: 1,
// borderColor: 'green',
}
@@ -1253,7 +1254,7 @@ const $rightContainer: ViewStyle = {
}
const $card: ViewStyle = {
marginBottom: spacing.small,
//marginBottom: spacing.small,
marginHorizontal: spacing.extraSmall,
}
@@ -1285,26 +1286,29 @@ const CARD_SHADOW_ALLOWANCE = 20
const $tabView: ViewStyle = {
flexGrow: 0,
flexShrink: 0,
//borderWidth: 1,
//borderColor: 'red',
// borderWidth: 1,
// borderColor: 'red',
marginBottom: 0,
paddingBottom: 0,
}
// Flexible band that takes the space left between the TabView and the buttons.
// The top gap must clear the transactions card's drop shadow (offset 10 +
// radius 8 ≈ 18px), otherwise on shorter/wider screens the NWC card gets pushed
// up under the shadow. The bottom gap keeps the card off the Scan button.
const NWC_BAND_TOP_GAP = spacing.large
const NWC_BAND_TOP_GAP = 0
const NWC_BAND_BOTTOM_GAP = spacing.small
const $middleContainer: ViewStyle = {
flex: 1,
justifyContent: 'flex-end',
paddingTop: NWC_BAND_TOP_GAP,
//justifyContent: 'flex-start',
//paddingTop: NWC_BAND_TOP_GAP,
paddingBottom: NWC_BAND_BOTTOM_GAP,
//borderWidth: 1,
}
const $nwcContainer: ViewStyle = {
//flexShrink: 1,
flexShrink: 1,
paddingHorizontal: spacing.extraSmall,
//borderWidth: 1,
//borderColor: 'red',
@@ -1324,6 +1328,8 @@ const NWC_CARD_FULL_HEIGHT = verticalScale(84)
// card can shrink when the band is squeezed on shorter/wider screens. Combined
// with the collapsed label→amount gap in renderNwcCard.
const $nwcCardCompact: ViewStyle = {
width: spacing.screenWidth * 0.28,
marginRight: spacing.small,
minHeight: verticalScale(48),
paddingVertical: spacing.tiny,
}