From 00ba0fa44fbdc25d92525a3db6708e5d2e5954c8 Mon Sep 17 00:00:00 2001 From: yanas Date: Mon, 10 Feb 2025 10:55:56 +0100 Subject: [PATCH] fix(suite-native): use react-native-keyboard-controller for keyboard handling --- .../mobile-dependencies.txt | 2 +- suite-native/app/package.json | 2 +- suite-native/app/src/App.tsx | 17 ++--- .../AccountImportConfirmFormScreen.tsx | 40 ++++++------ .../components/AccountImportSummaryScreen.tsx | 63 +++++++++++-------- .../src/components/XpubHint.tsx | 22 +++---- .../src/screens/XpubScanScreen.tsx | 5 +- .../PassphraseContentScreenWrapper.tsx | 7 +-- .../components/passphrase/PassphraseForm.tsx | 28 +-------- .../passphrase/PassphraseFormScreen.tsx | 31 ++++----- .../PassphraseVerifyEmptyWalletScreen.tsx | 27 ++++---- .../src/components/AmountInputs.tsx | 29 +-------- .../src/components/DestinationTagInput.tsx | 30 +-------- .../module-send/src/components/SendScreen.tsx | 15 ----- .../src/screens/SendAccountsScreen.tsx | 9 ++- .../src/screens/SendAddressReviewScreen.tsx | 8 +-- .../SendDestinationTagReviewScreen.tsx | 8 +-- .../src/screens/SendFeesScreen.tsx | 9 ++- .../src/screens/SendOutputsReviewScreen.tsx | 8 +-- .../src/screens/SendOutputsScreen.tsx | 21 +++++-- suite-native/navigation/package.json | 2 +- .../navigation/src/components/Screen.tsx | 18 +++--- .../src/components/ScreenContentWrapper.tsx | 20 +++--- .../src/hooks/useIsKeyboardShown.ts | 22 +++++++ suite-native/test-utils/package.json | 1 + suite-native/test-utils/src/expoMock.js | 4 ++ yarn.lock | 31 ++++----- 27 files changed, 214 insertions(+), 265 deletions(-) delete mode 100644 suite-native/module-send/src/components/SendScreen.tsx create mode 100644 suite-native/navigation/src/hooks/useIsKeyboardShown.ts diff --git a/scripts/list-outdated-dependencies/mobile-dependencies.txt b/scripts/list-outdated-dependencies/mobile-dependencies.txt index 9790db953fa..db2f584deba 100644 --- a/scripts/list-outdated-dependencies/mobile-dependencies.txt +++ b/scripts/list-outdated-dependencies/mobile-dependencies.txt @@ -53,7 +53,7 @@ expo-updates jotai lottie-react-native react-native-gesture-handler -react-native-keyboard-aware-scroll-view +react-native-keyboard-controller react-native-mmkv react-native-quick-crypto react-native-restart diff --git a/suite-native/app/package.json b/suite-native/app/package.json index 67d8252b45b..46e888328ca 100644 --- a/suite-native/app/package.json +++ b/suite-native/app/package.json @@ -114,7 +114,7 @@ "react-native": "0.76.1", "react-native-edge-to-edge": "^1.3.1", "react-native-gesture-handler": "^2.21.0", - "react-native-keyboard-aware-scroll-view": "0.9.5", + "react-native-keyboard-controller": "1.16.5", "react-native-mmkv": "2.12.2", "react-native-quick-crypto": "^0.7.6", "react-native-reanimated": "^3.16.7", diff --git a/suite-native/app/src/App.tsx b/suite-native/app/src/App.tsx index 426572bab43..b9944c68fdc 100644 --- a/suite-native/app/src/App.tsx +++ b/suite-native/app/src/App.tsx @@ -1,5 +1,6 @@ import { useEffect } from 'react'; import { GestureHandlerRootView } from 'react-native-gesture-handler'; +import { KeyboardProvider } from 'react-native-keyboard-controller'; import { SafeAreaProvider } from 'react-native-safe-area-context'; import { useDispatch, useSelector } from 'react-redux'; @@ -80,13 +81,15 @@ const PureApp = () => ( - - - - - - - + + + + + + + + + diff --git a/suite-native/module-accounts-import/src/components/AccountImportConfirmFormScreen.tsx b/suite-native/module-accounts-import/src/components/AccountImportConfirmFormScreen.tsx index 39d6d73e27c..8d30a442c9a 100644 --- a/suite-native/module-accounts-import/src/components/AccountImportConfirmFormScreen.tsx +++ b/suite-native/module-accounts-import/src/components/AccountImportConfirmFormScreen.tsx @@ -127,28 +127,26 @@ export const AccountImportConfirmFormScreen = ({ } > - - - {knownTokens.length > 0 && ( - - - - - - )} - - } - estimatedItemSize={115} + + {knownTokens.length > 0 && ( + + + + + + } + estimatedItemSize={115} + /> + )} ); diff --git a/suite-native/module-accounts-import/src/components/AccountImportSummaryScreen.tsx b/suite-native/module-accounts-import/src/components/AccountImportSummaryScreen.tsx index 7c9049604bc..44a7f009566 100644 --- a/suite-native/module-accounts-import/src/components/AccountImportSummaryScreen.tsx +++ b/suite-native/module-accounts-import/src/components/AccountImportSummaryScreen.tsx @@ -1,8 +1,8 @@ import { ReactNode } from 'react'; -import { KeyboardAvoidingView, Platform } from 'react-native'; import { Box, PictogramTitleHeader, VStack } from '@suite-native/atoms'; import { Screen, ScreenFooterGradient } from '@suite-native/navigation'; +import { prepareNativeStyle, useNativeStyles } from '@trezor/styles'; import { AccountImportScreenHeader } from './AccountImportScreenHeader'; @@ -14,36 +14,45 @@ type AccountImportSummaryScreenProps = { testID?: string; }; +const screenFooterStyle = prepareNativeStyle(utils => ({ + paddingHorizontal: utils.spacings.sp16, + paddingBottom: utils.spacings.sp16, + backgroundColor: utils.colors.backgroundSurfaceElevation0, +})); + export const AccountImportSummaryScreen = ({ children, title, subtitle, footer, testID, -}: AccountImportSummaryScreenProps) => ( - } - footer={ - - - - {footer} +}: AccountImportSummaryScreenProps) => { + const { applyStyle } = useNativeStyles(); + + return ( + } + footer={ + <> + + {footer} + + } + focusedInputBottomOffset={114} // space below the label input + button height with vertical margin + > + + + - - } - > - - - - - - {children} - - - -); + + {children} + + + + ); +}; diff --git a/suite-native/module-accounts-import/src/components/XpubHint.tsx b/suite-native/module-accounts-import/src/components/XpubHint.tsx index 2910830718c..afb75c0bdca 100644 --- a/suite-native/module-accounts-import/src/components/XpubHint.tsx +++ b/suite-native/module-accounts-import/src/components/XpubHint.tsx @@ -1,5 +1,3 @@ -import { KeyboardAvoidingView, Platform } from 'react-native'; - import { NetworkType } from '@suite-common/wallet-config'; import { isAddressBasedNetwork } from '@suite-common/wallet-utils'; import { Box, TextButton } from '@suite-native/atoms'; @@ -36,16 +34,14 @@ export const XpubHint = ({ networkType, handleOpen }: XpubScanHintSheet) => { ); return ( - - - - {buttonTitle} - - - + + + {buttonTitle} + + ); }; diff --git a/suite-native/module-accounts-import/src/screens/XpubScanScreen.tsx b/suite-native/module-accounts-import/src/screens/XpubScanScreen.tsx index aa3115b1f27..866f089845a 100644 --- a/suite-native/module-accounts-import/src/screens/XpubScanScreen.tsx +++ b/suite-native/module-accounts-import/src/screens/XpubScanScreen.tsx @@ -36,9 +36,6 @@ import { XpubImportSection, networkTypeToTitleMap } from '../components/XpubImpo const FORM_BUTTON_FADE_IN_DURATION = 200; -// Extra padding needed to make multiline xpub input form visible even with the sticky footer. -const EXTRA_KEYBOARD_AVOIDING_VIEW_HEIGHT = 350; - const cameraStyle = prepareNativeStyle(_ => ({ alignItems: 'center', marginTop: 20, @@ -176,7 +173,7 @@ export const XpubScanScreen = ({ } footer={} - extraKeyboardAvoidingViewHeight={EXTRA_KEYBOARD_AVOIDING_VIEW_HEIGHT} + focusedInputBottomOffset={163} // button height with vertical margin + footer height > diff --git a/suite-native/module-authorize-device/src/components/passphrase/PassphraseContentScreenWrapper.tsx b/suite-native/module-authorize-device/src/components/passphrase/PassphraseContentScreenWrapper.tsx index 9bf9b233df2..a167e8d1136 100644 --- a/suite-native/module-authorize-device/src/components/passphrase/PassphraseContentScreenWrapper.tsx +++ b/suite-native/module-authorize-device/src/components/passphrase/PassphraseContentScreenWrapper.tsx @@ -1,6 +1,6 @@ import { ReactNode } from 'react'; -import { Text, VStack } from '@suite-native/atoms'; +import { TitleHeader, VStack } from '@suite-native/atoms'; import { Screen } from '@suite-native/navigation'; import { PassphraseScreenHeader } from './PassphraseScreenHeader'; @@ -18,10 +18,7 @@ export const PassphraseContentScreenWrapper = ({ }: PassphraseContentScreenWrapperProps) => ( }> - - {title} - {subtitle && {subtitle}} - + {children} diff --git a/suite-native/module-authorize-device/src/components/passphrase/PassphraseForm.tsx b/suite-native/module-authorize-device/src/components/passphrase/PassphraseForm.tsx index a7540a30ddf..7f044376181 100644 --- a/suite-native/module-authorize-device/src/components/passphrase/PassphraseForm.tsx +++ b/suite-native/module-authorize-device/src/components/passphrase/PassphraseForm.tsx @@ -1,5 +1,5 @@ -import { useCallback, useEffect, useRef, useState } from 'react'; -import { Platform, View } from 'react-native'; +import { useRef, useState } from 'react'; +import { View } from 'react-native'; import Animated, { FadeIn, FadeOut } from 'react-native-reanimated'; import { useDispatch, useSelector } from 'react-redux'; @@ -23,7 +23,6 @@ import { AuthorizeDeviceStackRoutes, RootStackParamList, StackToStackCompositeNavigationProps, - useScrollView, } from '@suite-native/navigation'; import { prepareNativeStyle, useNativeStyles } from '@trezor/styles'; @@ -32,10 +31,6 @@ import { NoPassphraseButton } from './NoPassphraseButton'; const FORM_CARD_PADDING = 12; -// iOS scroll needs to calculate also with the keyboard height. -const SCROLL_OFFSET = Platform.OS === 'android' ? 0 : 250; -const SCROLL_DELAY = 100; - type PassphraseFormProps = { onFocus?: () => void; inputLabel: string; @@ -58,7 +53,6 @@ export const PassphraseForm = ({ noPassphraseEnabled, }: PassphraseFormProps) => { const dispatch = useDispatch(); - const scrollView = useScrollView(); const formWrapperView = useRef(null); const [isInputFocused, setIsInputFocused] = useState(false); @@ -85,24 +79,6 @@ export const PassphraseForm = ({ reset, } = form; - const handleScrollToButton = useCallback(() => { - if (scrollView && formWrapperView.current) { - // Scroll so the whole form including submit button is visible.The delay is needed, because the scroll can not start before the button animation finishes. - formWrapperView.current.measureLayout(scrollView.getInnerViewNode(), (_, y) => { - setTimeout( - () => scrollView.scrollTo({ y: y - SCROLL_OFFSET, animated: true }), - SCROLL_DELAY, - ); - }); - } - }, [scrollView]); - - useEffect(() => { - if (isDirty) { - handleScrollToButton(); - } - }, [isDirty, handleScrollToButton]); - const handleCreateHiddenWallet = handleSubmit(({ passphrase }) => { dispatch(onPassphraseSubmit({ value: passphrase, passphraseOnDevice: false })); navigation.push(AuthorizeDeviceStackRoutes.PassphraseConfirmOnTrezor); diff --git a/suite-native/module-authorize-device/src/screens/passphrase/PassphraseFormScreen.tsx b/suite-native/module-authorize-device/src/screens/passphrase/PassphraseFormScreen.tsx index 0f688ebe13c..fcbdcc470bd 100644 --- a/suite-native/module-authorize-device/src/screens/passphrase/PassphraseFormScreen.tsx +++ b/suite-native/module-authorize-device/src/screens/passphrase/PassphraseFormScreen.tsx @@ -2,14 +2,15 @@ import { LayoutChangeEvent, View } from 'react-native'; import Animated, { useAnimatedStyle, useSharedValue, withTiming } from 'react-native-reanimated'; import { EventType, analytics } from '@suite-native/analytics'; -import { Box, Button, HStack, Text, VStack } from '@suite-native/atoms'; +import { Box, Button, HStack, Text, TitleHeader, VStack } from '@suite-native/atoms'; import { Icon } from '@suite-native/icons'; import { Translation, useTranslate } from '@suite-native/intl'; import { useOpenLink } from '@suite-native/link'; +import { Screen } from '@suite-native/navigation'; import { prepareNativeStyle, useNativeStyles } from '@trezor/styles'; -import { PassphraseContentScreenWrapper } from '../../components/passphrase/PassphraseContentScreenWrapper'; import { PassphraseForm } from '../../components/passphrase/PassphraseForm'; +import { PassphraseScreenHeader } from '../../components/passphrase/PassphraseScreenHeader'; const ANIMATION_DURATION = 300; @@ -70,18 +71,20 @@ export const PassphraseFormScreen = () => { }; return ( - } - subtitle={ - {chunks}, - }} + }> + + } + subtitle={ + {chunks}, + }} + /> + } + titleVariant="titleMedium" /> - } - > - @@ -158,6 +161,6 @@ export const PassphraseFormScreen = () => { inputLabel={translate('modulePassphrase.form.createWalletInputLabel')} /> - + ); }; diff --git a/suite-native/module-authorize-device/src/screens/passphrase/PassphraseVerifyEmptyWalletScreen.tsx b/suite-native/module-authorize-device/src/screens/passphrase/PassphraseVerifyEmptyWalletScreen.tsx index b21969338e4..10738863088 100644 --- a/suite-native/module-authorize-device/src/screens/passphrase/PassphraseVerifyEmptyWalletScreen.tsx +++ b/suite-native/module-authorize-device/src/screens/passphrase/PassphraseVerifyEmptyWalletScreen.tsx @@ -4,15 +4,16 @@ import { useDispatch } from 'react-redux'; import { isFulfilled } from '@reduxjs/toolkit'; import { EventType, analytics } from '@suite-native/analytics'; -import { AlertBox, Text, VStack } from '@suite-native/atoms'; +import { AlertBox, Text, TitleHeader, VStack } from '@suite-native/atoms'; import { finishPassphraseFlow, verifyPassphraseOnEmptyWalletThunk, } from '@suite-native/device-authorization'; import { Translation, useTranslate } from '@suite-native/intl'; +import { Screen } from '@suite-native/navigation'; -import { PassphraseContentScreenWrapper } from '../../components/passphrase/PassphraseContentScreenWrapper'; import { PassphraseForm } from '../../components/passphrase/PassphraseForm'; +import { PassphraseScreenHeader } from '../../components/passphrase/PassphraseScreenHeader'; export const PassphraseVerifyEmptyWalletScreen = () => { const dispatch = useDispatch(); @@ -34,15 +35,17 @@ export const PassphraseVerifyEmptyWalletScreen = () => { }, [dispatch]); return ( - - } - subtitle={ - - } - > - + }> + + + } + subtitle={ + + } + titleVariant="titleMedium" + /> { inputLabel={translate('modulePassphrase.form.verifyPassphraseInputLabel')} /> - + ); }; diff --git a/suite-native/module-send/src/components/AmountInputs.tsx b/suite-native/module-send/src/components/AmountInputs.tsx index a34a8ccd044..1b0e0bca581 100644 --- a/suite-native/module-send/src/components/AmountInputs.tsx +++ b/suite-native/module-send/src/components/AmountInputs.tsx @@ -1,5 +1,5 @@ import { useRef, useState } from 'react'; -import { TextInput, View, findNodeHandle } from 'react-native'; +import { TextInput, View } from 'react-native'; import Animated, { LinearTransition, useSharedValue, withTiming } from 'react-native-reanimated'; import { useSelector } from 'react-redux'; @@ -13,12 +13,7 @@ import { import { EventType, analytics } from '@suite-native/analytics'; import { HStack, Text, VStack } from '@suite-native/atoms'; import { Translation } from '@suite-native/intl'; -import { - SendStackParamList, - SendStackRoutes, - StackProps, - useScrollView, -} from '@suite-native/navigation'; +import { SendStackParamList, SendStackRoutes, StackProps } from '@suite-native/navigation'; import { prepareNativeStyle, useNativeStyles } from '@trezor/styles'; import { AmountErrorMessage } from './AmountErrorMessage'; @@ -66,7 +61,6 @@ export const AmountInputs = ({ index }: AmountInputProps) => { ); const [isCryptoSelected, setIsCryptoSelected] = useState(true); - const scrollView = useScrollView(); const amountInputsWrapperRef = useRef(null); const cryptoRef = useRef(null); @@ -102,23 +96,6 @@ export const AmountInputs = ({ index }: AmountInputProps) => { setIsCryptoSelected(!isCryptoSelected); }; - const handleInputFocus = () => { - const amountInputsWrapper = amountInputsWrapperRef.current; - const scrollViewNodeHandle = findNodeHandle(scrollView); - - if (!amountInputsWrapper || !scrollViewNodeHandle) return; - - // Timeout is needed so the position is calculated after keyboard and footer animations are finished. - setTimeout( - () => - // Scroll so the whole amount inputs section is visible. - amountInputsWrapper.measureLayout(scrollViewNodeHandle, (_, y) => { - scrollView?.scrollTo({ y, animated: true }); - }), - 400, - ); - }; - if (!symbol) return null; return ( @@ -149,7 +126,6 @@ export const AmountInputs = ({ index }: AmountInputProps) => { isDisabled={!isCryptoSelected} symbol={symbol} onPress={!isCryptoSelected ? handleSwitchInputs : undefined} - onFocus={handleInputFocus} tokenContract={tokenContract} /> {isFiatDisplayed && ( @@ -164,7 +140,6 @@ export const AmountInputs = ({ index }: AmountInputProps) => { symbol={symbol} tokenContract={tokenContract} onPress={isCryptoSelected ? handleSwitchInputs : undefined} - onFocus={handleInputFocus} /> )} diff --git a/suite-native/module-send/src/components/DestinationTagInput.tsx b/suite-native/module-send/src/components/DestinationTagInput.tsx index 84d7a7be25a..be5201b7b8c 100644 --- a/suite-native/module-send/src/components/DestinationTagInput.tsx +++ b/suite-native/module-send/src/components/DestinationTagInput.tsx @@ -1,13 +1,12 @@ import { useRef, useState } from 'react'; -import { TextInput, View, findNodeHandle } from 'react-native'; -import Animated, { FadeIn, FadeOut, useSharedValue } from 'react-native-reanimated'; +import { TextInput } from 'react-native'; +import Animated, { FadeIn, FadeOut } from 'react-native-reanimated'; import { AlertBox, AnimatedVStack, HStack, Switch, Text, VStack } from '@suite-native/atoms'; import { TextInputField, useFormContext } from '@suite-native/forms'; import { Icon } from '@suite-native/icons'; import { Translation } from '@suite-native/intl'; import { Link } from '@suite-native/link'; -import { useScrollView } from '@suite-native/navigation'; import { useDebounce } from '@trezor/react-utils'; import { prepareNativeStyle, useNativeStyles } from '@trezor/styles'; @@ -25,13 +24,8 @@ const inputWrapperStyle = prepareNativeStyle(utils => ({ gap: utils.spacings.sp12, })); -const SCROLL_TO_DELAY = 200; - export const DestinationTagInput = () => { - const inputWrapperRef = useRef(null); const inputRef = useRef(null); - const inputHeight = useSharedValue(null); - const scrollView = useScrollView(); const { applyStyle } = useNativeStyles(); const [isInputDisplayed, setIsInputDisplayed] = useState(true); @@ -56,28 +50,9 @@ export const DestinationTagInput = () => { setIsInputDisplayed(!isInputDisplayed); }; - const handleInputFocus = () => { - const inputWrapper = inputWrapperRef.current; - const scrollViewNodeHandle = findNodeHandle(scrollView); - - if (!inputWrapper || !scrollViewNodeHandle) return; - - // Timeout is needed so the position is calculated after keyboard and footer animations are finished. - setTimeout( - () => - // Scroll so the whole amount inputs section is visible. - inputWrapper.measureLayout(scrollViewNodeHandle, (_x, y, _w, h) => { - inputHeight.value = h; - scrollView?.scrollTo({ y, animated: true }); - }), - SCROLL_TO_DELAY, - ); - }; - const handleChangeValue = () => { debounce(() => { trigger(destinationTagFieldName); - handleInputFocus(); }); }; @@ -116,7 +91,6 @@ export const DestinationTagInput = () => { onChangeText={handleChangeValue} name={destinationTagFieldName} testID={destinationTagFieldName} - onFocus={handleInputFocus} accessibilityLabel="address input" /> diff --git a/suite-native/module-send/src/components/SendScreen.tsx b/suite-native/module-send/src/components/SendScreen.tsx deleted file mode 100644 index 42e99c2108f..00000000000 --- a/suite-native/module-send/src/components/SendScreen.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { ReactNode } from 'react'; - -import { Screen } from '@suite-native/navigation'; - -type SendScreenProps = { - children: ReactNode; - screenHeader: ReactNode; - footer?: ReactNode; -}; - -export const SendScreen = ({ children, footer, screenHeader }: SendScreenProps) => ( - - {children} - -); diff --git a/suite-native/module-send/src/screens/SendAccountsScreen.tsx b/suite-native/module-send/src/screens/SendAccountsScreen.tsx index 79d4540479d..170e737f540 100644 --- a/suite-native/module-send/src/screens/SendAccountsScreen.tsx +++ b/suite-native/module-send/src/screens/SendAccountsScreen.tsx @@ -1,14 +1,13 @@ import { AccountsList, OnSelectAccount } from '@suite-native/accounts'; import { useTranslate } from '@suite-native/intl'; import { + Screen, ScreenHeader, SendStackParamList, SendStackRoutes, StackProps, } from '@suite-native/navigation'; -import { SendScreen } from '../components/SendScreen'; - export const SendAccountsScreen = ({ navigation, }: StackProps) => { @@ -21,8 +20,8 @@ export const SendAccountsScreen = ({ }); return ( - - + ); }; diff --git a/suite-native/module-send/src/screens/SendAddressReviewScreen.tsx b/suite-native/module-send/src/screens/SendAddressReviewScreen.tsx index 20ccd999040..3e8e9af94ac 100644 --- a/suite-native/module-send/src/screens/SendAddressReviewScreen.tsx +++ b/suite-native/module-send/src/screens/SendAddressReviewScreen.tsx @@ -5,6 +5,7 @@ import { AccountsRootState, DeviceRootState, SendRootState } from '@suite-common import { Box, Text, VStack } from '@suite-native/atoms'; import { Translation, useTranslate } from '@suite-native/intl'; import { + Screen, ScreenHeader, SendStackParamList, SendStackRoutes, @@ -13,7 +14,6 @@ import { import { AddressReviewStepList } from '../components/AddressReviewStepList'; import { SendConfirmOnDeviceImage } from '../components/SendConfirmOnDeviceImage'; -import { SendScreen } from '../components/SendScreen'; import { selectIsReceiveAddressOutputConfirmed, selectIsTransactionReviewInProgress, @@ -43,8 +43,8 @@ export const SendAddressReviewScreen = ({ }, [isAddressConfirmed, accountKey, navigation, tokenContract]); return ( - - + ); }; diff --git a/suite-native/module-send/src/screens/SendDestinationTagReviewScreen.tsx b/suite-native/module-send/src/screens/SendDestinationTagReviewScreen.tsx index 834475aadeb..be2e5191fc4 100644 --- a/suite-native/module-send/src/screens/SendDestinationTagReviewScreen.tsx +++ b/suite-native/module-send/src/screens/SendDestinationTagReviewScreen.tsx @@ -7,6 +7,7 @@ import { AccountsRootState, DeviceRootState, SendRootState } from '@suite-common import { Text, VStack } from '@suite-native/atoms'; import { Translation, useTranslate } from '@suite-native/intl'; import { + Screen, ScreenHeader, SendStackParamList, SendStackRoutes, @@ -15,7 +16,6 @@ import { import { ReviewDestinationTagCard } from '../components/ReviewDestinationTagCard'; import { SendConfirmOnDeviceImage } from '../components/SendConfirmOnDeviceImage'; -import { SendScreen } from '../components/SendScreen'; import { useHandleOnDeviceTransactionReview } from '../hooks/useHandleOnDeviceTransactionReview'; import { selectIsDestinationTagOutputConfirmed, @@ -65,8 +65,8 @@ export const SendDestinationTagReviewScreen = ({ }, [isDestinationTagConfirmed, accountKey, navigation, tokenContract, transaction]); return ( - - + ); }; diff --git a/suite-native/module-send/src/screens/SendFeesScreen.tsx b/suite-native/module-send/src/screens/SendFeesScreen.tsx index dedf53a0456..f3f54450f29 100644 --- a/suite-native/module-send/src/screens/SendFeesScreen.tsx +++ b/suite-native/module-send/src/screens/SendFeesScreen.tsx @@ -1,11 +1,10 @@ import { useSelector } from 'react-redux'; import { AccountsRootState, selectAccountByKey } from '@suite-common/wallet-core'; -import { SendStackParamList, SendStackRoutes, StackProps } from '@suite-native/navigation'; +import { Screen, SendStackParamList, SendStackRoutes, StackProps } from '@suite-native/navigation'; import { AccountBalanceScreenHeader } from '../components/AccountBalanceScreenHeader'; import { SendFeesForm } from '../components/SendFeesForm'; -import { SendScreen } from '../components/SendScreen'; export const SendFeesScreen = ({ route: { params }, @@ -18,12 +17,12 @@ export const SendFeesScreen = ({ if (!account) return; return ( - } > - + ); }; diff --git a/suite-native/module-send/src/screens/SendOutputsReviewScreen.tsx b/suite-native/module-send/src/screens/SendOutputsReviewScreen.tsx index c9ec16b1130..9c62a57535e 100644 --- a/suite-native/module-send/src/screens/SendOutputsReviewScreen.tsx +++ b/suite-native/module-send/src/screens/SendOutputsReviewScreen.tsx @@ -8,6 +8,7 @@ import { useTranslate } from '@suite-native/intl'; import { RootStackParamList, RootStackRoutes, + Screen, ScreenHeader, SendStackParamList, SendStackRoutes, @@ -17,7 +18,6 @@ import { import { OutputsReviewFooter } from '../components/OutputsReviewFooter'; import { ReviewOutputItemList } from '../components/ReviewOutputItemList'; -import { SendScreen } from '../components/SendScreen'; import { useShowReviewCancellationAlert } from '../hooks/useShowReviewCancellationAlert'; import { cleanupSendFormThunk } from '../sendFormThunks'; @@ -59,8 +59,8 @@ export const SendOutputsReviewScreen = ({ }); return ( - - + ); }; diff --git a/suite-native/module-send/src/screens/SendOutputsScreen.tsx b/suite-native/module-send/src/screens/SendOutputsScreen.tsx index 7b3b6b252b3..392651e80e5 100644 --- a/suite-native/module-send/src/screens/SendOutputsScreen.tsx +++ b/suite-native/module-send/src/screens/SendOutputsScreen.tsx @@ -27,6 +27,7 @@ import { Box, Button } from '@suite-native/atoms'; import { Form, useForm } from '@suite-native/forms'; import { Translation } from '@suite-native/intl'; import { + Screen, ScreenFooterGradient, SendStackParamList, SendStackRoutes, @@ -36,10 +37,10 @@ import { import { SettingsSliceRootState, selectIsAmountInSats } from '@suite-native/settings'; import { TokensRootState, selectAccountTokenInfo } from '@suite-native/tokens'; import { useDebounce } from '@trezor/react-utils'; +import { prepareNativeStyle, useNativeStyles } from '@trezor/styles'; import { AccountBalanceScreenHeader } from '../components/AccountBalanceScreenHeader'; import { SendOutputFields } from '../components/SendOutputFields'; -import { SendScreen } from '../components/SendScreen'; import { useSubscribeForSolanaBlockUpdates } from '../hooks/useSubscribeForSolanaBlockUpdates'; import { storeFeeLevels } from '../sendFormSlice'; import { calculateFeeLevelsMaxAmountThunk } from '../sendFormThunks'; @@ -66,6 +67,12 @@ const getDefaultValues = ({ ], }) as const; +const screenFooterStyle = prepareNativeStyle(utils => ({ + paddingHorizontal: utils.spacings.sp16, + paddingBottom: utils.spacings.sp16, + backgroundColor: utils.colors.backgroundSurfaceElevation0, +})); + export const SendOutputsScreen = ({ route: { params }, }: StackProps) => { @@ -74,6 +81,7 @@ export const SendOutputsScreen = ({ const debounce = useDebounce(); const navigation = useNavigation>(); + const { applyStyle } = useNativeStyles(); const [feeLevelsMaxAmount, setFeeLevelsMaxAmount] = useState(); @@ -270,15 +278,15 @@ export const SendOutputsScreen = ({ }); return ( - } footer={ isValid && ( - +